]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.106 2.1.106
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:42 +0000 (15:15 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:42 +0000 (15:15 -0500)
286 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/MultiSound [deleted file]
Documentation/filesystems/isofs.txt
Documentation/paride.txt
Documentation/sound/ALS007 [new file with mode: 0644]
Documentation/sound/AWE32
Documentation/sound/MultiSound [new file with mode: 0644]
Documentation/sound/Multisound [new file with mode: 0644]
Documentation/sound/Soundblaster
MAINTAINERS
Makefile
README
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/process.c
arch/alpha/mm/init.c
arch/arm/kernel/sys_arm.c
arch/i386/boot/setup.S
arch/i386/kernel/head.S
arch/i386/kernel/process.c
arch/i386/kernel/setup.c
arch/i386/kernel/smp.c
arch/i386/kernel/sys_i386.c
arch/i386/lib/checksum.c
arch/i386/mm/init.c
arch/m68k/Makefile
arch/m68k/atari/ataints.c
arch/m68k/atari/atakeyb.c
arch/m68k/atari/atasound.c
arch/m68k/atari/config.c
arch/m68k/atari/joystick.c
arch/m68k/atari/stram.c
arch/m68k/atari/time.c
arch/m68k/bvme6000/Makefile [new file with mode: 0644]
arch/m68k/bvme6000/bvmeints.c [new file with mode: 0644]
arch/m68k/bvme6000/config.c [new file with mode: 0644]
arch/m68k/bvme6000/rtc.c [new file with mode: 0644]
arch/m68k/config.in
arch/m68k/defconfig
arch/m68k/hp300/Makefile [new file with mode: 0644]
arch/m68k/hp300/README.hp300 [new file with mode: 0644]
arch/m68k/hp300/config.c [new file with mode: 0644]
arch/m68k/hp300/hil.c [new file with mode: 0644]
arch/m68k/hp300/ints.c [new file with mode: 0644]
arch/m68k/hp300/ints.h [new file with mode: 0644]
arch/m68k/hp300/ksyms.c [new file with mode: 0644]
arch/m68k/hp300/reboot.S [new file with mode: 0644]
arch/m68k/hp300/time.c [new file with mode: 0644]
arch/m68k/hp300/time.h [new file with mode: 0644]
arch/m68k/kernel/bios32.c
arch/m68k/kernel/entry.S
arch/m68k/kernel/head.S
arch/m68k/kernel/ints.c
arch/m68k/kernel/m68k_ksyms.c
arch/m68k/kernel/ptrace.c
arch/m68k/kernel/setup.c
arch/m68k/kernel/signal.c
arch/m68k/kernel/sys_m68k.c
arch/m68k/mac/Makefile
arch/m68k/mac/adb-bus.c
arch/m68k/mac/config.c
arch/m68k/mac/debug.c
arch/m68k/mac/ksyms.c [deleted file]
arch/m68k/mac/mac_ksyms.c [new file with mode: 0644]
arch/m68k/mac/macints.c
arch/m68k/mac/mackeyb.c
arch/m68k/mac/psc.h [new file with mode: 0644]
arch/m68k/mac/via6522.c
arch/m68k/mm/Makefile
arch/m68k/mm/fault.c
arch/m68k/mm/hwtest.c [new file with mode: 0644]
arch/m68k/mm/init.c
arch/m68k/mm/memory.c
arch/m68k/mvme16x/16xints.c
arch/m68k/mvme16x/Makefile
arch/m68k/mvme16x/config.c
arch/m68k/mvme16x/rtc.c [new file with mode: 0644]
arch/sparc/kernel/sys_sparc.c
drivers/block/ll_rw_blk.c
drivers/block/paride/Config.in
drivers/block/paride/Makefile
drivers/block/paride/fit3.c [new file with mode: 0644]
drivers/block/paride/mkd
drivers/block/paride/paride.c
drivers/block/paride/paride.h
drivers/block/paride/pg.c [new file with mode: 0644]
drivers/block/paride/pseudo.h
drivers/char/adbmouse.c [new file with mode: 0644]
drivers/char/bttv.c
drivers/char/console.c
drivers/char/lp_intern.c
drivers/char/mac_SCC.c [new file with mode: 0644]
drivers/char/mac_SCC.h [new file with mode: 0644]
drivers/char/mem.c
drivers/char/misc.c
drivers/char/nvram.c
drivers/char/pc_keyb.c
drivers/char/radio-aimslab.c
drivers/char/random.c
drivers/char/tty_io.c
drivers/dio/Makefile [new file with mode: 0644]
drivers/dio/dio.c [new file with mode: 0644]
drivers/misc/parport_arc.c
drivers/misc/parport_ax.c
drivers/misc/parport_pc.c
drivers/net/7990.c [new file with mode: 0644]
drivers/net/7990.h [new file with mode: 0644]
drivers/net/8390.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/atari_bionet.c
drivers/net/hamradio/dmascc.c
drivers/net/hplance.c [new file with mode: 0644]
drivers/net/hplance.h [new file with mode: 0644]
drivers/net/loopback.c
drivers/net/ppp.c
drivers/net/wavelan.c
drivers/scsi/Config.in
drivers/scsi/NCR53C9x.c
drivers/scsi/NCR53C9x.h
drivers/scsi/blz1230.c
drivers/scsi/blz1230.h
drivers/scsi/blz2060.c
drivers/scsi/blz2060.h
drivers/scsi/cyberstorm.c
drivers/scsi/cyberstorm.h
drivers/scsi/cyberstormII.c
drivers/scsi/cyberstormII.h
drivers/scsi/fastlane.c
drivers/scsi/fastlane.h
drivers/scsi/hosts.c
drivers/scsi/scsi_obsolete.c
drivers/scsi/scsi_proc.c
drivers/scsi/sr_ioctl.c
drivers/sound/Config.in
drivers/sound/Makefile
drivers/sound/dmasound.c
drivers/sound/gus_wave.c
drivers/sound/msnd.c [new file with mode: 0644]
drivers/sound/msnd.h [new file with mode: 0644]
drivers/sound/msnd_classic.c [new file with mode: 0644]
drivers/sound/msnd_classic.h [new file with mode: 0644]
drivers/sound/msnd_pinnacle.c [new file with mode: 0644]
drivers/sound/msnd_pinnacle.h [new file with mode: 0644]
drivers/sound/soundcard.c
drivers/sound/v_midi.c
fs/binfmt_aout.c
fs/devpts/inode.c
fs/filesystems.c
fs/isofs/dir.c
fs/isofs/inode.c
fs/isofs/namei.c
fs/minix/bitmap.c
fs/minix/inode.c
fs/minix/namei.c
fs/nfsd/nfsproc.c
fs/nfsd/vfs.c
fs/proc/array.c
fs/romfs/inode.c
include/asm-alpha/bitops.h
include/asm-alpha/pgtable.h
include/asm-alpha/smp.h
include/asm-arm/arch-a5k/a.out.h [deleted file]
include/asm-arm/arch-a5k/dma.h [deleted file]
include/asm-arm/arch-a5k/hardware.h [deleted file]
include/asm-arm/arch-a5k/ide.h [deleted file]
include/asm-arm/arch-a5k/io.h [deleted file]
include/asm-arm/arch-a5k/irq.h [deleted file]
include/asm-arm/arch-a5k/irqs.h [deleted file]
include/asm-arm/arch-a5k/mmu.h [deleted file]
include/asm-arm/arch-a5k/oldlatches.h [deleted file]
include/asm-arm/arch-a5k/processor.h [deleted file]
include/asm-arm/arch-a5k/serial.h [deleted file]
include/asm-arm/arch-a5k/shmparam.h [deleted file]
include/asm-arm/arch-a5k/system.h [deleted file]
include/asm-arm/arch-a5k/time.h [deleted file]
include/asm-arm/arch-a5k/timex.h [deleted file]
include/asm-arm/arch-a5k/uncompress.h [deleted file]
include/asm-arm/arch-ebsa110/mmap.h [deleted file]
include/asm-arm/arch-ebsa285/io.h
include/asm-arm/arch-ebsa285/processor.h
include/asm-arm/arch-nexuspci/mmap.h [deleted file]
include/asm-arm/arch-nexuspci/serial.h [deleted file]
include/asm-arm/arch-rpc/mmap.h [deleted file]
include/asm-arm/bitops.h
include/asm-arm/fiq.h [new file with mode: 0644]
include/asm-arm/floppy.h
include/asm-arm/hardirq.h
include/asm-arm/io.h
include/asm-arm/ioctl.h
include/asm-arm/irq-no.h [deleted file]
include/asm-arm/namei.h
include/asm-generic/bitops.h
include/asm-i386/bitops.h
include/asm-i386/pgtable.h
include/asm-i386/processor.h
include/asm-m68k/amigahw.h
include/asm-m68k/atari_SCCserial.h
include/asm-m68k/atari_mouse.h [deleted file]
include/asm-m68k/bitops.h
include/asm-m68k/blinken.h [new file with mode: 0644]
include/asm-m68k/bootinfo.h
include/asm-m68k/bvme6000hw.h [new file with mode: 0644]
include/asm-m68k/checksum.h
include/asm-m68k/entry.h
include/asm-m68k/hardirq.h
include/asm-m68k/hwtest.h [new file with mode: 0644]
include/asm-m68k/ide.h
include/asm-m68k/io.h
include/asm-m68k/machw.h
include/asm-m68k/macintosh.h
include/asm-m68k/macints.h
include/asm-m68k/mvme16xhw.h
include/asm-m68k/pgtable.h
include/asm-m68k/processor.h
include/asm-m68k/serial.h
include/asm-m68k/setup.h
include/asm-m68k/signal.h
include/asm-m68k/stat.h
include/asm-m68k/system.h
include/asm-m68k/unistd.h
include/asm-mips/bitops.h
include/asm-ppc/bitops.h
include/asm-sparc/bitops.h
include/asm-sparc64/bitops.h
include/linux/adfs_fs.h
include/linux/bitops.h [new file with mode: 0644]
include/linux/blk.h
include/linux/dio.h [new file with mode: 0644]
include/linux/in_route.h
include/linux/iso_fs.h
include/linux/iso_fs_sb.h
include/linux/minix_fs.h
include/linux/minix_fs_sb.h
include/linux/mm.h
include/linux/netdevice.h
include/linux/nfsd/nfsd.h
include/linux/parport.h
include/linux/parport_pc.h
include/linux/pg.h [new file with mode: 0644]
include/linux/poll.h
include/linux/proc_fs.h
include/linux/rtnetlink.h
include/linux/signal.h
include/linux/swap.h
include/linux/sysctl.h
include/linux/timer.h
include/linux/utsname.h
include/linux/vmalloc.h
include/net/tcp.h
init/main.c
kernel/kmod.c
kernel/ksyms.c
kernel/sched.c
kernel/sysctl.c
mm/memory.c
mm/mmap.c
mm/swapfile.c
mm/vmalloc.c
net/802/psnap.c
net/core/dev.c
net/core/profile.c
net/core/sock.c
net/ipv4/fib_frontend.c
net/ipv4/fib_semantics.c
net/ipv4/icmp.c
net/ipv4/ip_fragment.c
net/ipv4/ip_fw.c
net/ipv4/ip_input.c
net/ipv4/ip_output.c
net/ipv4/ipconfig.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/af_inet6.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/sched/cls_rsvp.h
net/sched/sch_cbq.c
net/sched/sch_teql.c
scripts/mkdep.c

diff --git a/CREDITS b/CREDITS
index 43d2fded33d9a2c895dddb3e9499e38c15dcfb70..d442fef70bd1887752fb1a0aeac4d3280cb19b03 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1492,6 +1492,12 @@ N: Alessandro Rubini
 E: rubini@ipvvis.unipv.it
 D: the gpm mouse server and kernel support for it
 
+N: Paul Russell
+E: Paul.Russell@rustcorp.com.au
+W: http://www.adelaide.net.au/~rustcorp
+D: Ruggedly handsome.
+D: Developed Generic IP Firewalling Chains with Michael Neuling.
+
 N: Thomas Sailer
 E: sailer@ife.ee.ethz.ch
 E: HB9JNX@HB9W.CHE.EU (packet radio)
@@ -1787,6 +1793,11 @@ S: Chudenicka 8
 S: 10200 Prague 10, Hostivar
 S: Czech Republic
 
+N: Andrew Veliath
+E: andrewtv@usa.net
+D: Turtle Beach MultiSound sound driver
+S: USA
+
 N: Dirk Verworner
 D: Co-author of german book ``Linux-Kernel-Programmierung''
 D: Co-founder of Berlin Linux User Group
index e508af1879b1023c9e888fff39a8b45eb45e542f..2dfc18c928760b97e858a64e982a0a96da86e47a 100644 (file)
@@ -33,7 +33,7 @@ http://cyberbuzz.gatech.edu/kaboom/linux/ as well.
    Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
 needs.
 
-Last updated: May 12, 1998
+Last updated: May 31, 1998
 Current Author: Chris Ricker (kaboom@gatech.edu).
 
 Current Minimal Requirements
@@ -47,10 +47,10 @@ running, the suggested command should tell you.
 - Gnu C                 2.7.2.3                 ; gcc --version
 - Binutils              2.8.1.0.23              ; ld -v
 - Linux C Library       5.4.44                  ; ls -l /lib/libc.so.*
-- Dynamic Linker (ld.so) 1.9.5                   ; ldd --version
+- 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.7                   ; ps --version
-- Procinfo               13                      ; procinfo -v
+- Procinfo               14                      ; procinfo -v
 - Mount                  2.7l                    ; mount --version
 - Net-tools              1.45                    ; hostname -V
 - Loadlin                1.6a
@@ -190,6 +190,17 @@ net-tools.  This will also fix other problems.  For example, the format
 of /proc/net/dev changed; as a result, an older ifconfig will
 incorrectly report errors.
 
+   As of 2.1.102, the firewalling code has been replaced with
+firewalling chains.  See
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html for
+more information.  Among other things, you'll now need to use ipchains
+instead of ipfwadm to configure your filters.
+
+   The IP firewalling code has been replaced: ipfwadm will no longer
+work.  You need to obtain `ipchains', available from
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
+which includes an ipfwadm wrapper.
+
 Memory
 ======
 
@@ -209,8 +220,8 @@ use autofs as well as the new NFS utils.
 RPM
 ===
 
-   If you run Red Hat Linux or any other distribution that uses RPM, you
-need to upgrade RPM to version 2.2.7 or later.
+   If you run Red Hat Linux or any other distribution that uses RPM,
+you need to upgrade RPM to version 2.2.7 or later.
 
 DOSEMU
 ======
@@ -344,9 +355,9 @@ ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.8
 Dynamic Linker
 ==============
 
-The 1.9.5 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ld.so-1.9.5.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.9.5.tar.gz
+The 1.9.9 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ld.so-1.9.9.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.9.9.tar.gz
 
 Modules utilities
 =================
@@ -364,21 +375,21 @@ ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.7.tgz
 Procinfo utilities
 ==================
 
-The 13 release:
-ftp://ftp.cistron.nl/pub/people/svm/procinfo-13.tar.gz
+The 14 release:
+ftp://ftp.cistron.nl/pub/people/svm/procinfo-14.tar.gz
 
 RPM utilities
 =============
 
 The 2.2.7 release for Intel:
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-2.2.7-1.i386.rpm
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.i386.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/i386/rpm-2.2.7-1.i386.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.i386.rpm
 The 2.2.7 release for Alpha:
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/axp/rpm-2.2.7-1.axp.rpm
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/axp/rpm-devel-2.2.7-1.axp.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/axp/rpm-2.2.7-1.axp.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/axp/rpm-devel-2.2.7-1.axp.rpm
 The 2.2.7 release for SPARC:
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-2.2.7-1.sparc.rpm
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.sparc.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/sparc/rpm-2.2.7-1.sparc.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/sparc/rpm-devel-2.2.7-1.sparc.rpm
 
 DOSEMU
 ======
@@ -456,6 +467,13 @@ PPP
 The 2.3.5 release:
 ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.5.tar.gz
 
+IP Chains
+=========
+
+The 1.3.3 release:
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.gz
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.bz2
+
 Other Info
 ==========
 
index d0096ef01798638fce4e82ffdbc12b11116addca..6d6e625dd70c2a7e384de4b08436148cfaa77619 100644 (file)
@@ -154,14 +154,22 @@ Loop device support
 CONFIG_BLK_DEV_LOOP
   Saying Y here will allow you to mount a file as a file system. This
   is useful if you want to check an ISO9660 file system before burning
-  the CD, or want to use floppy images without first writing them to
-  floppy. This option also allows you to mount a filesystem with
-  encryption. To use these features, you need a recent version of
-  mount (available via FTP (user: anonymous) from
-  ftp://ftp.win.tue.nl/pub/linux/util/). Note that this loop device
-  has nothing to do with the loopback device used for network
-  connections from the machine to itself. Most users will answer N
-  here.
+  the CD, or if you want to use floppy images without first writing
+  them to floppy.
+
+  This option also allows you to mount a filesystem with encryption.
+  (Note that an alternative way to encrypt filesystems is provided by
+  the cfs package, which can be gotten via FTP (user: anonymous) from
+  ftp://ftp.replay.com/pub/crypto/disk).
+
+  To use the loop device, you need a recent version of mount
+  (available via FTP (user: anonymous) from
+  ftp://ftp.win.tue.nl/pub/linux/util/).
+
+  Note that this loop device has nothing to do with the loopback
+  device used for network connections from the machine to itself.
+
+  Most users will answer N here.
 
 Network Block Device support
 CONFIG_BLK_DEV_NBD
@@ -314,12 +322,21 @@ SCSI emulation support
 CONFIG_BLK_DEV_IDESCSI
   This will provide SCSI host adapter emulation for IDE ATAPI devices,
   and will allow you to use a SCSI device driver instead of a native
-  ATAPI driver. This is useful if you have an ATAPI device for which
-  no native driver has been written (for example, an ATAPI PD-CD or
-  CDR drive); you can then use this emulation together with an
-  appropriate SCSI device driver. If both this SCSI emulation and
-  native ATAPI support are compiled into the kernel, the native
-  support will be used.  Normally, say N.
+  ATAPI driver.
+
+  This is useful if you have an ATAPI device for which no native
+  driver has been written (for example, an ATAPI PD-CD or CDR drive);
+  you can then use this emulation together with an appropriate SCSI
+  device driver. In order to do this, say Y here and to "SCSI support"
+  and "SCSI generic support", below.
+
+  Note that this option does NOT allow you to attach SCSI devices to a
+  box that doesn't have a SCSI host adapter installed.
+
+  If both this SCSI emulation and native ATAPI support are compiled
+  into the kernel, the native support will be used.
+
+  If unsure, say N.
 
 CMD640 chipset bugfix/support
 CONFIG_BLK_DEV_CMD640
@@ -451,46 +468,51 @@ NS87415 support (EXPERIMENTAL)
 CONFIG_BLK_DEV_NS87415
   This driver adds detection and support for the NS87415 chip
   (used in SPARC64, among others).
+
   Please read the comments at the top of drivers/block/ns87415.c.
 
 QDI QD6580 support
 CONFIG_BLK_DEV_QD6580
   This driver is enabled at runtime using the "ide0=qd6580" kernel
   boot parameter.  It permits faster I/O speeds to be set.  See the
-  Documentation/ide.txt and qd6580.c files for more info.
+  files Documentation/ide.txt and qd6580.c for more info.
 
 UMC 8672 support
 CONFIG_BLK_DEV_UMC8672
   This driver is enabled at runtime using the "ide0=umc8672" kernel
   boot parameter.  It enables support for the secondary IDE interface
   of the UMC-8672, and permits faster I/O speeds to be set as well.
-  See the Documentation/ide.txt and umc8672.c files for more info.
+  See the files Documentation/ide.txt and umc8672.c for more info.
 
 ALI M14xx support
 CONFIG_BLK_DEV_ALI14XX
   This driver is enabled at runtime using the "ide0=ali14xx" kernel
   boot parameter.  It enables support for the secondary IDE interface
   of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
-  I/O speeds to be set as well.  See the Documentation/ide.txt and
-  ali14xx.c files for more info.
+  I/O speeds to be set as well. See the files Documentation/ide.txt
+  and ali14xx.c for more info.
 
 Apple Macintosh builtin IDE interface support (EXPERIMENTAL)
 CONFIG_BLK_DEV_MAC_IDE
   This is the IDE driver for the builtin IDE interface on some Apple
   Macintosh models.  It supports both the Quadra/Performa/LC 630 and
   the PowerBook 190 IDE interface.
+
   Say Y if you have such a Macintosh model and want to use IDE devices
   (hard disks, CD-ROM drives, etc.) that are connected to the builtin
   IDE interface.
 
 XT hard disk support
 CONFIG_BLK_DEV_XD
-  Very old 8 bit hard disk controllers used in the IBM XT computer. To
-  include a driver for these, say Y. If you want to compile the driver
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt. The module will be called xd.o. It's
-  pretty unlikely that you have one of these: say N.
+  Very old 8 bit hard disk controllers used in the IBM XT computer
+  will be supported if you say Y here. 
+
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called xd.o. 
+
+  It's pretty unlikely that you have one of these: say N.
 
 Parallel port IDE device support
 CONFIG_PARIDE
@@ -560,12 +582,27 @@ CONFIG_PARIDE_PT
   This option enables the high-level driver for ATAPI tape devices
   connected through a parallel port.  If you chose to build PARIDE
   support into your kernel, you may answer Y here to build in the
-  parallel port ATAPI disk driver, otherwise you should answer M
+  parallel port ATAPI tape driver, otherwise you should answer M
   to build it as a loadable module.  The module will be called pt.o.
   You must also have at least one parallel port protocol driver in
   your system.  Among the devices supported by this driver is the
   parallel port version of the HP 5GB drive.
 
+Parallel port generic ATAPI devices
+CONFIG_PARIDE_PG
+  This option enables a special high-level driver for generic ATAPI
+  devices connected through a parallel port. The driver allows user
+  programs, such as cdrecord, to send ATAPI commands directly to a
+  device. If you chose to build PARIDE support into your kernel, you 
+  may answer Y here to build in the parallel port generic ATAPI driver, 
+  otherwise you should answer M to build it as a loadable module.
+  The module will be called pg.o.  You must also have at least one 
+  parallel port protocol driver in your system.  This driver 
+  implements an API loosely related to the generic SCSI driver.  
+  See /usr/include/linux/pg.h for details, or visit 
+  http://www.torque.net/parport/cdr.html for more information and
+  the required patches to cdrecord.
+
 ATEN EH-100 protocol
 CONFIG_PARIDE_ATEN 
   This option enables support for the ATEN EH-100 parallel port IDE
@@ -633,10 +670,21 @@ CONFIG_PARIDE_FIT2
   adapter that is used in some portable hard drives.  If you chose to 
   build PARIDE support into your kernel, you may answer Y here to 
   build in the protocol driver, otherwise you should answer M to 
-  build it as a loadable module.  The module will be called ktti.o.  
+  build it as a loadable module.  The module will be called fit2.o.
   You must also have a high-level driver for the type of device 
   that you want to support.
 
+FIT TD-3000 protocol
+CONFIG_PARIDE_FIT3
+  This option enables support for the TD-3000 parallel port IDE protocol
+  from Fidelity International Technology. This protocol is used in newer
+  models of their portable disk, CD-ROM and PD/CD devices.   If you chose
+  to build PARIDE support into your kernel, you may answer Y here to
+  build in the protocol driver, otherwise you should answer M to
+  build it as a loadable module.  The module will be called fit3.o.
+  You must also have a high-level driver for the type of device
+  that you want to support.
+
 FreeCom power protocol
 CONFIG_PARIDE_FRPW 
   This option enables support for the Freecom power parallel port IDE 
@@ -764,6 +812,24 @@ CONFIG_MD_RAID5
   want to compile it as a module, say M here and read
   Documentation/modules.txt. If unsure, say Y.
 
+IDE card support
+CONFIG_BLK_DEV_IDE_CARDS
+  On Acorn systems, say Y here if you wish to use an IDE interface
+  expansion card. If you do not or are unsure, say N.
+
+ICS IDE interface
+CONFIG_BLK_DEV_IDE_ICS
+  On Acorn systems, say Y here if you wish to use the ICS IDE
+  interface card. This is not required for ICS partition support. If
+  you are unsure, say.
+
+ADFS partition support
+CONFIG_BLK_DEV_PART
+  This allows Linux on Acorn systems to determine its partitions in
+  the 'non-ADFS' partition area of the hard disk - usually located
+  after the ADFS partition.  You are probably using this system, so
+  you should say Y here.
+
 IDE card support
 CONFIG_BLK_DEV_IDE_CARDS
   On Acorn systems, enable this if you wish to use an IDE interface
@@ -920,11 +986,10 @@ CONFIG_FIREWALL
   is talking to the firewall box -- makes the local network completely
   invisible to the outside world and avoids the need to allocate
   globally valid IP host addresses for the machines on the local net)
-  and IP packet accounting (keeping track of what is using up all your
-  network bandwidth) and IP transparent proxying (makes the computers
-  on the local network think they're talking to a remote computer,
-  while in reality the traffic is redirected by your Linux firewall to
-  a local proxy server).
+  and IP transparent proxying (makes the computers on the local
+  network think they're talking to a remote computer, while in reality
+  the traffic is redirected by your Linux firewall to a local proxy
+  server).
   
   Make sure to say N to "Fast switching" below if you intend to say Y
   here.
@@ -948,6 +1013,11 @@ CONFIG_SYN_COOKIES
   about SYN cookies, check out
   ftp://koobera.math.uic.edu/pub/docs/syncookies-archive.
 
+  If you are SYN flooded, the source address reported by the kernel is
+  likely to have been forged by the attacker; it is only reported as
+  an aid in tracing the packets to their actual source and should not
+  be taken as absolute truth.
+
   If you say Y here, note that SYN cookies aren't enabled by default;
   you can enable them by saying Y to "/proc filesystem support" and
   "Sysctl support" below and executing the command
@@ -1060,18 +1130,15 @@ CONFIG_SERIAL_SHARE_IRQ
   serial ports on the same board to share a single IRQ.  To enable
   support for this in the serial driver, say Y here.
 
-Autodetect IRQ on standard ports (unsafe)
+Auto detect IRQ on standard ports (unsafe)
 CONFIG_SERIAL_DETECT_IRQ
-  Enable this option if you want the kernel to try to guess which IRQ
-  is configured during the boot sequence and you're too lazy to edit
-  the boot scripts to use the setserial command.  This option can be
-  unsafe and should not be enabled on most machines.  It is far
-  better to dynamically request autoconfiguration during the boot-time
-  scripts using the setserial command.  You can change the IRQ and/or 
-  request automatic IRQ configuration at any time by using the 
-  "setserial" program.  I wouldn't include this config option at all except
-  people keep bellyaching about it.  I guess they are really are too lazy 
-  to edit their boot scripts.  :-)   If unsure, say No.
+  Say Y here if you want the kernel to try to guess which IRQ
+  to use for your serial port. 
+
+  This is considered unsafe; it is far better to configure the IRQ in
+  a boot script using the setserial command.
+
+  If unsure, say N.
 
 Support special multiport boards
 CONFIG_SERIAL_MULTIPORT
@@ -1099,9 +1166,10 @@ CONFIG_PCI
   bus system, i.e. the way the CPU talks to the other stuff inside
   your box. Other bus systems are ISA, EISA, Microchannel (MCA) or
   VESA. If you have PCI, say Y, otherwise N. The PCI-HOWTO, available
-  via FTP (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO,
-  contains valuable information about which PCI hardware does work
-  under Linux and which doesn't.
+  via FTP (user: anonymous) in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, contains valuable
+  information about which PCI hardware does work under Linux and which
+  doesn't.
 
   If some of your PCI devices don't work and you get a warning during
   boot time ("man dmesg"), please follow the instructions at the top
@@ -1131,8 +1199,9 @@ CONFIG_PCI_DIRECT
 PCI quirks
 CONFIG_PCI_QUIRKS
   If you have a broken BIOS, it may fail to set up the PCI bus in a
-  correct or optimal fashion. If your BIOS is fine you can say N here
-  for a very slightly smaller kernel. If unsure, say Y.
+  correct or optimal fashion. Saying Y here will correct that problem.
+  If your BIOS is fine you can say N here for a very slightly smaller
+  kernel. If unsure, say Y.
 
 PCI bridge optimization (experimental)
 CONFIG_PCI_OPTIMIZE
@@ -1588,10 +1657,10 @@ IP: use TOS value as routing key
 CONFIG_IP_ROUTE_TOS
   The header of every IP packet carries a TOS (Type of Service) value
   with which the packet requests a certain treatment, e.g. low latency
-  (for interactive traffic), high throughput, or high
-  reliability. Normally, these values are ignored, but if you say Y
-  here, you will be able to specify different routes for packets with
-  different TOS values.
+  (for interactive traffic), high throughput, or high reliability.
+  Normally, these values are ignored, but if you say Y here, you will
+  be able to specify different routes for packets with different TOS
+  values.
 
 IP: verbose route monitoring
 CONFIG_IP_ROUTE_VERBOSE
@@ -1641,22 +1710,19 @@ CONFIG_IP_FIREWALL
   More powerful than the old IP firewalling but also provides similar
   structure to original firewalling for experienced users.  IP
   accounting and packet logging are automatically included with firewall
-  chains, so you don't need them them if you say Y here.  See
+  chains.  See
   http://www.adelaide.net.au/~rustcorp for new ipfwadm (called ipchains).
   If in doubt, say N here.
 
 IP: firewall packet netlink device
 CONFIG_IP_FIREWALL_NETLINK
-  If you say Y here and then packets hit your Linux firewall and are
-  blocked, the first 128 bytes of each such packet are passed on to
-  optional user space monitoring software that can then look for
-  attacks and take actions such as paging the administrator of the
-  site. To use this, you need to create a character special file under
-  /dev with major number 36 and minor number 3 using mknod ("man
-  mknod"), and you need (to write) a program that reads from that
-  device and takes appropriate action.
-  With the current generic firewalling chains you can specify which
-  packets go to this device, as well as how many bytes.
+  If you say Y here, then packets which hit your Linux firewall can
+  be copied to optional user space monitoring software that can then
+  respond accordingly: see the ipchains source distributions for an
+  example if this.  To use this, you need to create a character
+  special file under /dev with major number 36 and minor number 3
+  using mknod ("man mknod"), and you need (to write) a program that
+  reads from that device and takes appropriate action.
 
 IP: kernel level autoconfiguration
 CONFIG_IP_PNP
@@ -1728,12 +1794,6 @@ CONFIG_NET_IPGRE_BROADCAST
   Network), but can be distributed all over the Internet. If you want
   to do that, say Y here and to "IP: multicast routing" below.
 
-IP: firewall packet logging
-CONFIG_IP_FIREWALL_VERBOSE
-  This gives you information about what your firewall did with
-  packets it received. The information is handled by the klogd daemon
-  which is responsible for kernel messages ("man klogd").
-
 IP: transparent proxying
 CONFIG_IP_TRANSPARENT_PROXY
   This enables your Linux firewall to transparently redirect any
@@ -1775,7 +1835,9 @@ CONFIG_IP_MASQUERADE
 
   Details on how to set things up are contained in the IP Masquerade
   mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini.
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini; there's also some
+  information on the WWW at
+  http://www.tor.shaw.wave.ca/~ambrose/kernel21.html. 
 
   If you say Y here, you should also say Y to "IP: always defragment",
   below. If you say Y here, then the modules ip_masq_ftp.o (for ftp
@@ -1814,13 +1876,23 @@ CONFIG_IP_MASQUERADE_IPAUTOFW
 
 IP: ipportfw masquerade support
 CONFIG_IP_MASQUERADE_IPPORTFW
-  ipportfw is an addition to IP Masquerading written by Steven Clarke
-  to allow some forwarding of packets from outside to inside a
-  firewall on given ports. Information and source for ipportfw is
-  available from
+  Port Forwarding is an addition to IP Masquerading written by Steven
+  Clarke to allow some forwarding of packets from outside to inside a
+  firewall on given ports. This could be useful if, for example, you
+  want to run a web server behind the firewall or masquerading host
+  and this web server should be visible to the outside world. An
+  external client connects to port 80 of the firewall, the firewall
+  forwards requests to this port to the web server, the web server
+  handles the request and the results are sent through the firewall to
+  the original client. The client thinks that the firewall machine
+  itself is running the web server.
+
+  Information about it is available from
   http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html (to
   browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape).
+  that has a program like lynx or netscape). You will need the user
+  space program ipportfw which can be downloaded from
+  ftp://ftp.compsoc.net/users/steve/ipportfw/linux21/
 
   The portfw code is still under development and so is currently
   marked EXPERIMENTAL. If you want to try it, say Y.
@@ -2005,18 +2077,20 @@ CONFIG_SKB_LARGE
 Unix domain sockets
 CONFIG_UNIX
   This includes Unix domain sockets, the standard Unix mechanism for
-  establishing and accessing network connections. Unless you are
-  working on an embedded system or something, you definitely want to
-  say Y here.
+  establishing and accessing network connections. Many commonly used
+  programs such as the X Window system and syslog use these sockets
+  even if your machine is not connected to any network. Unless you are
+  working on an embedded system or something similar, you therefore
+  definitely want to say Y here.
 
   The socket support is also available as a module ( = code which can
   be inserted in and removed from the running kernel whenever you
   want). The module will be called unix.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt. If you
   try building this as a module and you are running kerneld, be sure
-  to add 'alias net-pf-1 unix' to your /etc/conf.module file. If
-  unsure, say Y.  (NOTE: X Windows and syslog probably won't work
-  if you say N to this or fail to configure it correctly)
+  to add 'alias net-pf-1 unix' to your /etc/conf.module file. 
+
+  If unsure, say Y.
 
 The IPv6 protocol
 CONFIG_IPV6
@@ -2056,26 +2130,45 @@ CONFIG_IPV6_NO_PB
   some problems caused by the presence of two link-local addresses on
   an interface.
 
+IPv6: routing messages via old netlink
+CONFIG_IPV6_NETLINK
+  You can say Y here to receive routing messages from the IPv6 code
+  through the old netlink interface. However, a better option is to
+  say Y to "Kernel/User network link driver" and to "Routing
+  messages" instead.
+  
 IPX networking
 CONFIG_IPX
   This is support for the Novell networking protocol, IPX, commonly
   used for local networks of Windows machines. You need it if you want
   to access Novell NetWare file or print servers using the Linux
   Novell client ncpfs (available via FTP (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/system/filesystems/) or from within the
-  Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO). In order to do the former,
-  you'll also have to say Y to "NCP filesystem support", below. To
-  turn your Linux box into a fully featured NetWare file server and
+  ftp://sunsite.unc.edu/pub/Linux/system/filesystems/) or from within
+  the Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). In order to do the
+  former, you'll also have to say Y to "NCP filesystem support",
+  below.
+
+  IPX is similar in scope to IP, while SPX, which runs on top of IPX,
+  is similar to TCP. There is also experimental support for SPX in
+  Linux (see "SPX networking", below).
+
+  To turn your Linux box into a fully featured NetWare file server and
   IPX router, say Y here and fetch either lwared from
-  sunsite.unc.edu:/pub/Linux/system/network/daemons/ or mars_nwe from
-  ftp.gwdg.de:/pub/linux/misc/ncpfs. For more information, read the
-  IPX-HOWTO in sunsite.unc.edu:/pub/Linux/docs/howto. The IPX driver
-  would enlarge your kernel by about 5 kB. This driver is also
-  available as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want). The module will be
-  called ipx.o. If you want to compile it as a module, say M here
-  and read Documentation/modules.txt.  Unless you want to integrate
+  ftp://sunsite.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe from
+  ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information, read the
+  IPX-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+  General information about how to connect Linux, Windows machines and
+  Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
+  browse the WWW, you need to have access to a machine on the Internet
+  that has a program like lynx or netscape). 
+
+  The IPX driver would enlarge your kernel by about 5 kB. This driver
+  is also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module will
+  be called ipx.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt. Unless you want to integrate
   your Linux box with a local Novell network, say N.
 
 IPX: Full internal IPX network
@@ -2083,11 +2176,12 @@ CONFIG_IPX_INTERN
   Every IPX network has an address that identifies it. Sometimes it is
   useful to give an IPX "network" address to your Linux box as well
   (for example if your box is acting as a fileserver for different IPX
-  networks: it will then be accessible form everywhere using the same
+  networks: it will then be accessible from everywhere using the same
   address).  The way this is done is to create a virtual internal
   "network" inside your box and to assign an IPX address to this
   network. Say Y here if you want to do this; read the IPX-HOWTO at
-  sunsite.unc.edu:/pub/Linux/docs/howto for details.  
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO for details.  
+
   The full internal IPX network enables you to allocate sockets on
   different virtual nodes of the internal network. This is done by
   evaluating the field sipx_node of the socket address given to the
@@ -2099,14 +2193,28 @@ CONFIG_IPX_INTERN
   'special' sockets to sockets listening on the primary network is
   disabled. This might break existing applications, especially RIP/SAP
   daemons. A RIP/SAP daemon that works well with the full internal net
-  can be found on ftp.gwdg.de:/pub/linux/misc/ncpfs.  If you don't
+  can be found on ftp://ftp.gwdg.de/pub/linux/misc/ncpfs.  If you don't
   know what you are doing, say N.
 
 IPX: SPX networking (EXPERIMENTAL)
 CONFIG_SPX
-  The (SPP-derived) Sequenced Packet eXchange (SPX) protocol. Novell's
-  networking protocol which monitors transmissions to guarantee
-  successful delivery. It is safe to say Y/M here.
+  The Sequenced Packet eXchange protocol is a transport layer protocol
+  built on top of IPX. It is used in Novell NetWare systems for
+  client-server applications and is similar to TCP (which runs on top
+  of IP).
+
+  Note that Novell NetWare file sharing does not use SPX; it uses a
+  protocol called NCP, for which separate Linux support is available
+  ("NCP filesystem support" below for the client side, and the user
+  space programs lwared or mars_nwe for the server side).
+
+  Say Y here if you have use for SPX; read the IPX-HOWTO at
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO for details.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called af_spx.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 Appletalk DDP
 CONFIG_ATALK
@@ -2115,36 +2223,42 @@ CONFIG_ATALK
   want to join the conversation, say Y. You will need to use the
   netatalk package so that your Linux box can act as a print and file
   server for Macs as well as access Appletalk printers. Check out
-  http://artoo.hitchcock.org/~flowerpt/projects/linux-netatalk/ on the
-  WWW for details (to browse the WWW, you need to have access to a
-  machine on the Internet that has a program like lynx or
-  netscape). EtherTalk is the name used for Appletalk over Ethernet
-  and the cheaper and slower LocalTalk is appletalk over a proprietary
-  apple network using serial links. Ethertalk and Localtalk are fully 
-  supported by Linux. The NET-2-HOWTO, available via FTP (user: anonymous)
-  in sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information
-  as well. This driver is also available as a module ( = code which
-  can be inserted in and removed from the running kernel whenever you
-  want). The module is called appletalk.o. If you want to compile
-  it as a module, say M here and read Documentation/modules.txt. I
-  hear that the GNU boycott of Apple is over, so even politically
-  correct people are allowed to say Y here.
+  http://threepio.hitchcock.org/cgi-bin/faq/netatalk/faq.pl on the WWW
+  for details (to browse the WWW, you need to have access to a machine
+  on the Internet that has a program like lynx or netscape). EtherTalk
+  is the name used for Appletalk over Ethernet and the cheaper and
+  slower LocalTalk is appletalk over a proprietary apple network using
+  serial links. Ethertalk and Localtalk are fully supported by Linux.
+  The NET-2-HOWTO, available via FTP (user: anonymous) in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO contains valuable
+  information as well.
+
+  General information about how to connect Linux, Windows machines and
+  Macs is on the WWW at http://www.eats.com/linux_mac_win.html
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called appletalk.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. I hear that
+  the GNU boycott of Apple is over, so even politically correct people
+  are allowed to say Y here.
 
 Appletalk-IP driver support
 CONFIG_IPDDP
   This allows IP networking for users who only have Appletalk
   networking available.  This feature is experimental. With this
   driver, you can either encapsulate IP inside Appletalk (e.g. if your
-  Linux box is stuck on an appletalk only network) or decapsulate
-  (e.g. if you want your Linux box to act as a Internet gateway for a
+  Linux box is stuck on an Appletalk only network) or decapsulate
+  (e.g. if you want your Linux box to act as an Internet gateway for a
   zoo of appletalk connected Macs). You decide which one of the two
   you want in the following two questions; you can say Y to only one
   of them. Please see Documentation/networking/ipddp.txt for more
-  information.  This driver is also available as a module ( = code
-  which can be inserted in and removed from the running kernel
-  whenever you want). The module is called ipddp.o. If you want to
-  compile it as a module, say M here and read
-  Documentation/modules.txt.
+  information.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module is called ipddp.o. If you want to compile it as a module,
+  say M here and read Documentation/modules.txt.
 
 IP to Appletalk-IP Encapsulation support
 CONFIG_IPDDP_ENCAP
@@ -2406,6 +2520,21 @@ CONFIG_BAYCOM_PAR
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called baycom_par.o.
 
+BAYCOM epp driver for AX.25
+CONFIG_BAYCOM_EPP
+  This is a driver for Baycom style simple amateur radio modems that
+  connect to a parallel interface. The driver supports the epp
+  designs. To configure the driver, use the sethdlc utility available
+  in the standard ax25 utilities package. For information on the
+  modems, see http://www.baycom.de (to browse the WWW, you need to
+  have access to a machine on the Internet that has a program like
+  lynx or netscape) and Documentation/networking/baycom.txt.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called baycom_par.o.
+
 BAYCOM ser12 full duplex driver for AX.25
 CONFIG_BAYCOM_SER_FDX
   This is one of two drivers for Baycom style simple amateur radio
@@ -2915,7 +3044,7 @@ CONFIG_AIC7XXX_RESET_DELAY
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
   This is support for BusLogic MultiMaster and FlashPoint SCSI Host
-  Adapters.  Consult the SCSI-HOWTO, available via anonymous ftp from
+  Adapters.  Consult the SCSI-HOWTO, available via anonymous FTP from
   ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, and the files
   README.BusLogic and README.FlashPoint in drivers/scsi for more
   information.  If this driver does not work correctly without
@@ -3197,7 +3326,7 @@ CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
   interface.
 
   If all the boards of your system are genuine SYMBIOS boards or use
-  BIOS and drivers from SYMBIOS, you would want to enable this option.
+  BIOS and drivers from SYMBIOS, you would want to say Y here.
   The driver behaves correctly on my system with this option enabled.
   (SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev
   0x12).  This option must be set to N if your system has at least one
@@ -3205,10 +3334,10 @@ CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
   DC-390/U/W/F). 
 
   However, if all your non Symbios compatible boards have NVRAM,
-  setting option "detect and read serial NVRAMs"
+  saying Y to "detect and read serial NVRAMs"
   (CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT) above allows the driver to
-  distinguish Symbios compatible boards from other ones.  So, you can
-  answer Y if all non Symbios compatible boards have NVRAM.
+  distinguish Symbios compatible boards from other ones; you can then
+  also answer Y here.
 
   If unsure, say N.
 
@@ -3428,7 +3557,7 @@ CONFIG_SCSI_EATA
   This driver supports all the EATA/DMA-compliant SCSI host adapters
   and does not need any BIOS32 service.  DPT ISA and all EISA i/o
   addresses are probed looking for the "EATA" signature. If you said Y
-  to "PCI bios support", the addresses of all the PCI SCSI controllers
+  to "PCI BIOS support", the addresses of all the PCI SCSI controllers
   reported by BIOS32 are probed as well.  You want to read
   the start of drivers/scsi/eata.c and the SCSI-HOWTO, available via
   FTP (user: anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.  
@@ -3556,6 +3685,59 @@ CONFIG_SCSI_ACORNSCSI_3
   This enables support for the Acorn SCSI card (aka30).  If you have an
   Acorn system with one of these, say Y.  If unsure, say N.
 
+Acorn SCSI tagged queue support
+CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+  Say Y here to enable tagged queuing support on the Acorn SCSI card.
+
+  This is a feature of SCSI-2 which improves performance: the host
+  adapter can send several SCSI commands to a device's queue even if
+  previous commands haven't finished yet. Some SCSI devices don't
+  implement this properly, so the safe answer is N.
+
+Acorn SCSI Synchronous transfers support
+CONFIG_SCSI_ACORNSCSI_SYNC
+  Say Y here to enable synchronous transfer negotiation with all targets
+  on the Acorn SCSI card.
+
+  In general, this improves performance; however some SCSI devices
+  don't implement it properly, so the safe answer is N.
+
+Oak SCSI support
+CONFIG_SCSI_OAK1
+  This enables support for the Oak SCSI card.  If you have an Acorn system
+  with one of these, say Y.  If unsure, say N.
+
+Cumana SCSI I support
+CONFIG_SCSI_CUMANA_1
+  This enables support for the Cumana SCSI I card.  If you have an Acorn
+  system with one of these, say Y.  If unsure, say N.
+
+Cumana SCSI II support
+CONFIG_SCSI_CUMANA_2
+  This enables support for the Cumana SCSI II card.  If you have an Acorn
+  system with one of these, say Y.  If unsure, say N.
+
+EcoSCSI support
+CONFIG_SCSI_ECOSCSI
+  This enables support for the EcoSCSI card - a small card that sits in
+  the Econet socket.  If you have an Acorn system with one of these,
+  say Y.  If unsure, say N.
+
+EESOX SCSI support
+CONFIG_SCSI_EESOXSCSI
+  This enables support for the EESOX SCSI card.  If you have an Acorn
+  system with one of these, say Y, otherwise say N.
+
+Powertec SCSI support
+CONFIG_SCSI_POWERTECSCSI
+  This enables support for the Powertec SCSI card on Acorn systems.  If
+  you have one of these, say Y.  If unsure, say N.  
+
+AcornSCSI support
+CONFIG_SCSI_ACORNSCSI_3
+  This enables support for the Acorn SCSI card (aka30).  If you have an
+  Acorn system with one of these, say Y.  If unsure, say N.
+
 Acorn SCSI tagged queue support
 CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
   Say Y here to enable tagged queuing support on the Acorn SCSI card.
@@ -3788,18 +3970,23 @@ CONFIG_STRIP
 
 AT&T WaveLAN & DEC RoamAbout DS support
 CONFIG_WAVELAN
-  The Lucent Wavelan (formerly NCR and AT&T ; or DEC RoamAbout DS) is
+  The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is
   a Radio LAN (wireless Ethernet-like Local Area Network) using the
   radio frequencies 900 MHz and 2.4 GHz.
   
   This driver support the ISA version of the Wavelan card. A separate
-  driver for the pcmcia hardware is available in David Hinds's pcmcia
-  package. If you want to use an ISA Wavelan card under Linux, say Y
-  and read the Ethernet-HOWTO, available via FTP (user: anonymous) in
+  driver for the pcmcia hardware is available in David Hinds's
+  pcmcia-cs package (see the file Documentation/Changes for location).
+
+  If you want to use an ISA Wavelan card under Linux, say Y and read
+  the Ethernet-HOWTO, available via FTP (user: anonymous) in
   ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Some more specific
-  information is contained in Documentation/networking/wavelan.txt.
+  information is contained in Documentation/networking/wavelan.txt and
+  in the source code drivers/net/wavelan.p.h.
+
   You will also need the wireless tools package available from
   ftp://ftp.inka.de/pub/comp/Linux/networking/NetTools/contrib/.
+  Please read the man pages contained therein.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -3817,10 +4004,21 @@ CONFIG_MISC_RADIO
   something at ftp://ftp.lmh.ox.ac.uk/users/weejock/linux/, but I haven't
   written anything too useful yet...)
 
-AIMSlab RadioTrack card
+AIMSlab RadioTrack (aka RadioReveal) support
 CONFIG_RADIO_RTRACK
-  Choose Y here if you have one of these, and then fill in the port
-  address below.
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address below.
+  
+  In order to control your radio card under the X window system, you
+  may use the program X-Tuner, available on the WWW at
+  http://gatekeeper.dec.com/pub/X11/R6-contrib/applications/; to
+  browse the WWW, you need to have access to a machine on the Internet
+  that has a program like lynx or netscape.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called radio-aimslab.o.
 
 RadioTrack i/o port
 CONFIG_RADIO_RTRACK_PORT
@@ -3829,8 +4027,13 @@ CONFIG_RADIO_RTRACK_PORT
 
 Aztech/Packard Bell Radio
 CONFIG_RADIO_AZTECH
-  Choose Y here if you have one of these, and then fill in the port
-  address below.
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address below.
+  
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called radio-aztech.o.
 
 Aztech/Packard Bell radio card i/o port
 CONFIG_RADIO_AZTECH_PORT
@@ -3838,6 +4041,20 @@ CONFIG_RADIO_AZTECH_PORT
   haven't changed the setting of jumper JP3 on the card.  Removing the
   jumper sets the card to 0x358.
 
+SF16FMI Radio
+CONFIG_RADIO_SF16FMI
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address below.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called radio-sf16fmi.o
+
+SF16FMI I/O port (0x284 or 0x384)
+CONFIG_RADIO_SF16FMI_PORT
+  Enter the I/O port of your SF16FMI radio card.
+
 LAPB over Ethernet driver
 CONFIG_LAPBETHER
   This is a driver for a pseudo device (typically called /dev/lapb0)
@@ -4005,6 +4222,35 @@ CONFIG_SDLA
   The module will be called sdla.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+Acorn Econet/AUN protocols (EXPERIMENTAL)
+CONFIG_ECONET
+  Econet is a fairly old and slow networking protocol mainly used by
+  Acorn computers to access file and print servers. It uses native
+  Econet network cards. AUN is an implementation of the higher level
+  parts of Econet that runs over ordinary Ethernet connections, on
+  top of the UDP packet protocol, which in turn runs on top of the
+  Internet protocol IP.
+
+  If you say Y here, you can choose with the next two options whether
+  to send Econet/AUN traffic over a UDP Ethernet connection or over
+  a native Econet network card.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called econet.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+AUN over UDP
+CONFIG_ECONET_AUNUDP
+  Say Y here if you want to send Econet/AUN traffic over a a UDP
+  connection (UDP is a packet based protocol that runs on top of the
+  Internet protocol IP) using an ordinary Ethernet network card.
+
+Native Econet
+CONFIG_ECONET_NATIVE
+  Say Y here if you have a native Econet network card installed in
+  your computer.
+
 WAN Router
 CONFIG_WAN_ROUTER
   Wide Area Networks (WANs), such as X.25, frame relay and leased
@@ -4074,14 +4320,18 @@ CONFIG_NET_SCHED
   called packet schedulers. You can attach different schedulers to
   different network devices. If you want to stick to the default
   scheduling algorithm, say N here. If you want to experiment with a
-  couple of different algorithms, say Y. 
+  couple of different algorithms, say Y. Currently, this is only
+  recommended for experts.
 
   To administer these schedulers, you'll need the user-level utilities
   from the package iproute2+tc at ftp://ftp.inr.ac.ru/ip-routing/
 
-  The available schedulers are
-  listed in the following questions; you can say Y to as many as you
-  like.  If unsure, say N now.
+  If you say Y here and to "/proc filesystem" below, you will be able
+  to read status information about priority schedulers from
+  the file /proc/net/psched.
+  
+  The available schedulers are listed in the following questions; you
+  can say Y to as many as you like. If unsure, say N now.
 
 CBQ packet scheduler
 CONFIG_NET_SCH_CBQ
@@ -4090,8 +4340,8 @@ CONFIG_NET_SCH_CBQ
   algorithm classifies the waiting packets into a tree-like hierarchy
   of classes; the leaves of this tree are in turn scheduled by
   separate algorithms (called "disciplines" in this context) which you
-  can choose below from among the "auxiliary disciplines".  See the top
-  of net/sched/sch_cbq.c for references about the CBQ algorithm.
+  can choose below from among the various queueing algorithms. See the
+  top of net/sched/sch_cbq.c for references about the CBQ algorithm.
 
   This code is also available as a module called sch_cbq.o ( = code
   which can be inserted in and removed from the running kernel
@@ -4113,7 +4363,18 @@ CONFIG_NET_SCH_CSZ
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-RED queueing discipline
+The simplest PRIO pseudo scheduler
+CONFIG_NET_SCH_PRIO
+  Say Y here if you want to use an n-band priority queue packet
+  "scheduler" for some of your network devices or as a leaf discipline
+  for the CBQ scheduling algorithm. 
+
+  This code is also available as a module called sch_prio.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+RED queue
 CONFIG_NET_SCH_RED
   Say Y here if you want to use the Random Early Detection (RED)
   packet scheduling algorithm for some of your network devices (see
@@ -4125,7 +4386,7 @@ CONFIG_NET_SCH_RED
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-SFQ queueing discipline
+SFQ queue
 CONFIG_NET_SCH_SFQ
   Say Y here if you want to use the Stochastic Fairness Queueing (SFQ)
   packet scheduling algorithm for some of your network devices or as a
@@ -4138,7 +4399,21 @@ CONFIG_NET_SCH_SFQ
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-auxiliary TBF queue
+TEQL queue
+CONFIG_NET_SCH_TEQL
+  Say Y here if you want to use the True Link Equalizer (TLE) packet
+  scheduling algorithm for some of your network devices or as a leaf
+  discipline for the CBQ scheduling algorithm. This queueing
+  discipline allows the combination of several physical devices into
+  one virtual device. (see the top of net/sched/sch_teql.c for
+  details).
+
+  This code is also available as a module called sch_teql.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
+TBF queue
 CONFIG_NET_SCH_TBF
   Say Y here if you want to use the Simple Token Bucket Filter (TBF)
   packet scheduling algorithm for some of your network devices or as a
@@ -4150,27 +4425,49 @@ CONFIG_NET_SCH_TBF
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-auxiliary FIFO queue
-CONFIG_NET_SCH_PFIFO
-  Say Y here if you want to use a simple FIFO (first in - first out)
-  packet "scheduler" for some of your network devices or as a leaf
-  discipline for the CBQ scheduling algorithm. 
+QoS support
+CONFIG_NET_QOS
+  Say Y here if you want to include Quality Of Service scheduling
+  features, which means that you will be able to request certain
+  rate-of-flow limits for your net devices.
 
-  This code is also available as a module called sch_fifo.o ( = code
-  which can be inserted in and removed from the running kernel
-  whenever you want). If you want to compile it as a module, say M
-  here and read Documentation/modules.txt.
-
-auxiliary PRIO queue
-CONFIG_NET_SCH_PRIO
-  Say Y here if you want to use an n-band priority queue packet
-  "scheduler" for some of your network devices or as a leaf discipline
-  for the CBQ scheduling algorithm. 
-
-  This code is also available as a module called sch_prio.o ( = code
-  which can be inserted in and removed from the running kernel
-  whenever you want). If you want to compile it as a module, say M
-  here and read Documentation/modules.txt.
+  Note that the answer to this question won't directly affect the
+  kernel: saying N will just cause this configure script to skip all
+  the questions about QoS support.
+
+Rate estimator
+CONFIG_NET_ESTIMATOR
+  In order for Quality of Service scheduling to work, the current
+  rate-of-flow for a network device has to be estimated; if you say Y
+  here, the kernel will do just that.
+
+Packet classifier API
+CONFIG_NET_CLS
+  The CBQ scheduling algorithm requires that network packets which are
+  scheduled to be sent out over a network device be classified in some
+  way. If you say Y here, you will get a choice of several different
+  packet classifiers with the following questions. 
+#
+# Routing tables based classifier
+# CONFIG_NET_CLS_ROUTE
+#
+# Firewall based classifier
+# CONFIG_NET_CLS_FW
+#
+# U32 classifier
+# CONFIG_NET_CLS_U32
+#
+# Special RSVP classifier
+# CONFIG_NET_CLS_RSVP
+#
+# Special RSVP classifier for IPv6
+# CONFIG_NET_CLS_RSVP6
+#
+# Ingres traffic policing
+# CONFIG_NET_CLS_POLICE
+###
+### Some expert please fill these in
+###
 
 Network code profiler
 CONFIG_NET_PROFILE
@@ -4245,9 +4542,9 @@ CONFIG_WANPIPE_PPP
 Ethernet (10 or 100Mbit)
 CONFIG_NET_ETHERNET
   Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
-  type of Local Area Networks (LANs) in universities or
-  companies. 10-base-2 or Thinnet (10 Mbps over coaxial cable, linking
-  computers in a chain), 10-base-T (10 Mbps over twisted pair
+  type of Local Area Networks (LANs) in universities or companies.
+  10-base-2 or Thinnet (10 Mbps over coaxial cable, linking computers
+  in a chain), 10-base-T or TwistedPair (10 Mbps over twisted pair
   telephone cable, linking computers to a central hub) and
   100-base-<whatever> (100 Mbps) are common types of Ethernet. 
 
@@ -4359,6 +4656,18 @@ CONFIG_SMC9194
   it as a module, say M here and read Documentation/modules.txt as
   well as Documentation/networking/net-modules.txt.
 
+PCI NE2000 support
+CONFIG_NE2K_PCI
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via FTP (user: anonymous) in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ne2k-pci.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
+
 Racal-Interlan (Micom) NI cards
 CONFIG_NET_VENDOR_RACAL
   If you have a network (Ethernet) card belonging to this class, such
@@ -4408,6 +4717,32 @@ CONFIG_NI65
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
+RealTek 8129/8139 (not 8019/8029!) support
+CONFIG_RTL8139
+  This is a driver for the Fast Ethernet PCI network cards based on
+  the RTL8129 and RTL8139 chips. If you have one of those, say Y and
+  read the Ethernet-HOWTO, available via FTP (user: anonymous) in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called rtl8139.o.
+
+Packet Engines Yellowfin Gigabit-NIC support
+CONFIG_YELLOWFIN
+  Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
+  adapter. This adapter is used by the Beowulf Linux cluster project.
+  See http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html for
+  more information about this driver in particular and Beowulf in
+  general (to browse the WWW, you need to have access to a machine on
+  the Internet that has a program like lynx or netscape).
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called yellowfin.o.
+
 AMD LANCE and PCnet (AT1500 and NE2100) support
 CONFIG_LANCE
   If you have a network (Ethernet) card of this type, say Y and read
@@ -4509,10 +4844,10 @@ CONFIG_EL3
 
 3c590 series (592/595/597) "Vortex" support
 CONFIG_VORTEX
-  If you have a 3Com "Vortex" or "Boomerang" series network (Ethernet)
-  card (Fast EtherLink 3c590/3c592/3c595/3c597 or the EtherLink XL
-  3c900 or 3c905), say Y and read the Ethernet-HOWTO, available via
-  FTP (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  If you have a 3Com "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597)
+  or "Boomerang" series (EtherLink XL 3c900 or 3c905) network
+  (Ethernet) card, say Y and read the Ethernet-HOWTO, available via FTP
+  (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
   More specific information is in Documentation/networking/vortex.txt
   and in the comments at the beginning of drivers/net/3c59x.c.
 
@@ -4820,6 +5155,12 @@ CONFIG_PCNET32
   Y here and read the Ethernet-HOWTO, available via FTP (user:
   anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pcnet32.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
+
 Ansel Communications EISA 3200 support
 CONFIG_AC3200
   If you have a network (Ethernet) card of this type, say Y and read
@@ -5001,7 +5342,7 @@ CONFIG_NET_POCKET
 
   If you want to plug a network card into the PCMCIA slot of your
   laptop instead (PCMCIA is the standard for credit card size
-  extension cards used by all modern laptops), look on the ftp site
+  extension cards used by all modern laptops), look on the FTP site
   (user: anonymous) ftp://cb-iris.stanford.edu/pub/pcmcia and say N
   here.
 
@@ -5129,6 +5470,26 @@ CONFIG_AM79C961A
   If you wish to compile a kernel for the EBSA-110, then you should
   always answer Y to this.
 
+Acorn Ether1 card
+CONFIG_ARM_ETHER1
+  If you have an Acorn system with one of these (AKA25) network cards,
+  you should say Y to this option if you wish to use it with Linux.
+
+Acorn/ANT Ether3 card
+CONFIG_ARM_ETHER3
+  If you have an Acorn system with one of these network cards, you
+  should say Y to this option if you wish to use it with Linux.
+
+I Cubed EtherH card
+CONFIG_ARM_ETHERH
+  If you have an Acorn system with one of these network cards, you
+  should say Y to this option if you wish to use it with Linux.
+
+EBSA-110 ethernet interface
+CONFIG_AM79C961A
+  If you wish to compile a kernel for the EBSA-110, then you should
+  always answer Y to this.
+
 Support CDROM drives that are not SCSI or IDE/ATAPI
 CONFIG_CD_NO_IDESCSI
   If you have a CDROM drive that is neither SCSI nor IDE/ATAPI, say Y
@@ -5591,28 +5952,35 @@ CONFIG_MINIX_FS
 Second extended fs support
 CONFIG_EXT2_FS
   This is the de facto standard Linux filesystem (= method to organize
-  files on a storage device) for hard disks. You want to say Y, unless
-  you intend to use Linux exclusively from inside a DOS partition
-  using the umsdos filesystem. The advantage of the latter is that you
-  can get away without repartitioning your hard drive (which often
-  implies backing everything up and restoring afterwards); the
-  disadvantage is that Linux becomes susceptible to DOS viruses and
-  that umsdos is somewhat slower than ext2fs. Even if you want to run
-  Linux in this fashion, it might be a good idea to have ext2fs
-  around: it enables you to read more floppy disks and facilitates the
-  transition to a *real* Linux partition later. Another (rare) case
-  which doesn't require ext2fs is a diskless Linux box which mounts
-  all files over the network using NFS (in this case it's sufficient
-  to say Y to "NFS filesystem support" below). Saying Y here will
-  enlarge your kernel by about 41 kB.
+  files on a storage device) for hard disks. 
+
+  You want to say Y here, unless you intend to use Linux exclusively
+  from inside a DOS partition using the umsdos filesystem. The
+  advantage of the latter is that you can get away without
+  repartitioning your hard drive (which often implies backing
+  everything up and restoring afterwards); the disadvantage is that
+  Linux becomes susceptible to DOS viruses and that umsdos is somewhat
+  slower than ext2fs. Even if you want to run Linux in this fashion,
+  it might be a good idea to have ext2fs around: it enables you to
+  read more floppy disks and facilitates the transition to a *real*
+  Linux partition later. Another (rare) case which doesn't require
+  ext2fs is a diskless Linux box which mounts all files over the
+  network using NFS (in this case it's sufficient to say Y to "NFS
+  filesystem support" below). Saying Y here will enlarge your kernel
+  by about 41 kB.
 
   The Ext2fs-Undeletion mini-HOWTO, available via FTP (user:
   anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini,
   gives information about how to retrieve deleted files on ext2fs
   filesystems.
 
-  To change the behavior of ext2fs filesystems, you can use the
-  tune2fs utility ("man tune2fs"). 
+  To change the behavior of ext2 filesystems, you can use the tune2fs
+  utility ("man tune2fs"). To modify attributes of files and
+  directories on ext2 filesystems, use chattr ("man chattr").
+  
+  Ext2fs partitions can be read from within DOS using the ext2tool
+  package available via FTP (user: anonymous) from
+  ftp://sunsite.unc.edu/pub/Linux/system/filesystems/ext2.
 
   If you want to compile this filesystem as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
@@ -5944,7 +6312,7 @@ CONFIG_AUTOFS_FS
   The automounter is a tool to automatically mount remote filesystems
   on demand.  This implementation is partially kernel-based to reduce
   overhead in the already-mounted case; this is unlike the BSD
-  automounter (amd), which is only in user space.  
+  automounter (amd), which is a pure user space daemon.
 
   To use the automounter you need the user-space tools from
   ftp://ftp.kernel.org/pub/linux/daemons/autofs; you also want to say Y to
@@ -6019,13 +6387,15 @@ CONFIG_SOLARIS_X86_PARTITION
 
 ADFS filesystem support (read only) (EXPERIMENTAL)
 CONFIG_ADFS_FS
-  The Acorn Disc Filing System is the standard filesystem of the RiscOS
-  operating system which runs on Acorn's ARM based Risc PC systems and
-  the Acorn Archimedes range of machines. These should be the first
-  partition (ie, /dev/[hs]d?1) on each of your drives. If you say Y
+  The Acorn Disc Filing System is the standard filesystem of the
+  RiscOS operating system which runs on Acorn's ARM based Risc PC
+  systems and the Acorn Archimedes range of machines. If you say Y
   here, Linux will be able to read from ADFS partitions on hard drives
   and from ADFS-formatted floppy discs.
 
+  The ADFS partition should be the first partition (i.e.,
+  /dev/[hs]d?1) on each of your drives.
+
   This code is also available as a module called adfs.o ( = code which
   can be inserted in and removed from the running kernel whenever you
   want). If you want to compile it as a module, say M here and read
@@ -6037,7 +6407,7 @@ CONFIG_ADFS_FS
 CONFIG_DEVPTS_FS
   If you say Y here, you'll get a virtual filesystem which can be
   mounted on /dev/pts with "mount -t devpts". This, together with the
-  pseudo terminal master multiplexer /dev/ptmx is used for pseudo
+  pseudo terminal master multiplexer /dev/ptmx, is used for pseudo
   terminal support as described in the Open Group's Unix98 standard:
   in order to acquire a pseudo terminal, a process opens /dev/ptmx;
   the number of the pseudo terminal is then made available to the
@@ -6513,6 +6883,13 @@ CONFIG_SOFTCURSOR
   or change their color depending on the virtual console you're on.
   See Documentation/VGA-softcursor.txt for more information.
 
+Acorn's ADFS filesystem support (read only) (EXPERIMENTAL)
+CONFIG_ADFS_FS
+  The Advanced Disk File System is the filesystem used on floppy and
+  hard disks by Acorn Systems.  Currently in development, as a read-
+  only driver for hard disks.  These should be the first partition
+  (eg. /dev/[sh]d?1) on each of your drives.  If unsure, say N.
+
 Standard/generic serial support
 CONFIG_SERIAL
   This selects whether you want to include the driver for the standard
@@ -6530,8 +6907,12 @@ CONFIG_SERIAL
   be lost when kerneld automatically unloads the driver. This
   limitation may be lifted in the future.] 
 
-  BTW: If you have a mouseman serial mouse which is not recognized by
+  BTW1: If you have a mouseman serial mouse which is not recognized by
   the X window system, try running gpm first. 
+  
+  BTW2: If you intend to connect a so-called Winmodem to your
+  machine's serial port, forget it. These modems require proprietary
+  drivers which are only available under Windows.
 
   Most people will say Y or M here, so that they can use serial mice,
   modems and similar devices connecting to the standard serial ports.
@@ -6600,7 +6981,7 @@ CONFIG_RISCOM8
 
 Specialix IO8+ card support
 CONFIG_SPECIALIX
-  This is a driver for the Specialix IO8+ multiport card, that give 
+  This is a driver for the Specialix IO8+ multiport card which gives
   you many serial ports. You would need something like this to 
   connect more than two modems to your Linux box, for instance in
   order to become a BBS. 
@@ -6612,9 +6993,9 @@ CONFIG_SPECIALIX
 
 Specialix DTR/RTS pin is RTS
 CONFIG_SPECIALIX_RTSCTS
-  The Specialix card can only support either RTS or DTR. When you say
+  The Specialix card can only support either RTS or DTR. If you say
   N here, the driver will use the pin as "DTR" when the tty is in
-  software handshake mode. When you say Y here or hardware handshake
+  software handshake mode. If you say Y here or hardware handshake
   is on, it will always be RTS. Read the file
   Documentation/specialix.txt for more information.
 
@@ -7182,7 +7563,7 @@ CONFIG_FT_FDC_MAX_RATE
 
 MTRR control and configuration
 CONFIG_MTRR
-  On Intel Pentium Pro/Pentium II systems the Memory Type Range
+  On Intel Pentium Pro and Pentium II systems the Memory Type Range
   Registers (MTRRs) may be used to control processor access to memory
   ranges. This is most useful when you have a video (VGA) card on a
   PCI or AGP bus. Enabling write-combining allows bus write transfers
@@ -7193,12 +7574,16 @@ CONFIG_MTRR
   your MTRRs. Typically the X server should use this. This should have
   a reasonably generic interface so that similar control registers on
   other processors can be easily supported.
-  This option also fixes a problem with buggy SMP BIOSes which only
+
+  Saying Y here also fixes a problem with buggy SMP BIOSes which only
   set the MTRRs for the boot CPU and not the secondary CPUs. This can
   lead to all sorts of problems.
-  Compiling this as a module is not available because the BIOS fix
-  needs to be done early in the boot sequence, otherwise your machine
-  could lock up.
+
+  In general you should compile this into the kernel, rather than as a
+  loadable module, because the BIOS fix needs to be done early in the
+  boot sequence. If you compile this as a module, the BIOS fix will be
+  delayed until when you load the module. You do this at your own risk.
+
   See Documentation/mtrr.txt for more information.
 
 Main CPU frequency, only for DEC alpha machine
@@ -7256,11 +7641,12 @@ CONFIG_APM
    3) passing the "floppy=nodma" option to the kernel
    4) passing the "mem=4M" option to the kernel (thereby disabling 
       all but the first 4M of RAM)
-   5) reading the sig11 FAQ at http://www.bitwizard.nl/sig11/
-   6) disabling the cache from your BIOS settings
-   7) installing a better fan
-   8) exchanging RAM chips 
-   9) exchanging the motherboard.
+   5) making sure that the CPU is not over clocked.
+   6) reading the sig11 FAQ at http://www.bitwizard.nl/sig11/
+   7) disabling the cache from your BIOS settings
+   8) installing a better fan
+   9) exchanging RAM chips 
+   10) exchanging the motherboard.
 
 Ignore USER SUSPEND
 CONFIG_APM_IGNORE_USER_SUSPEND
@@ -7471,6 +7857,17 @@ CONFIG_NVRAM
   The module will be called nvram.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+Atomwide Serial Support
+CONFIG_ATOMWIDE_SERIAL
+  If you have an Atomwide Serial card for an Acorn system, say Y to
+  this option.  The driver can handle 1, 2, or 3 port cards.
+  If unsure, say N
+
+The Serial Port Dual Serial Port
+CONFIG_DUALSP_SERIAL
+  If you have the Serial Port's dual serial card for an Acorn system,
+  say Y to this option.  If unsure, say N
+
 PC joystick support
 CONFIG_JOYSTICK
   If you have a PC compatible analog or digital joystick, you can say
@@ -7523,11 +7920,12 @@ CONFIG_SOUND
   I'm told that even without a sound card, you can make your computer
   say more than an occasional beep, by programming the PC speaker.
   Kernel patches and programs to do that are in the pcsndrv package on
-  sunsite.unc.edu:/pub/Linux/kernel/patches/console/.
+  ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console/ and in the
+  pcsp patch at ftp://dwmw2.robinson.cam.ac.uk/pub/kernel/ .
 
 Support for Aztech Sound Galaxy (non-Pnp) cards
 CONFIG_SOUND_SGALAXY
-  This module initialises the older non Plug and Play sound galaxy cards
+  This module initializes the older non Plug and Play sound galaxy cards
   from Aztech. It supports the Waverider Pro 32 - 3D and the Galaxy
   Washington 16.
 
@@ -7562,12 +7960,12 @@ CONFIG_SOUND_ADLIB
   these cards may cause trouble (I don't currently know of any such
   cards, however). If unsure, say Y.
 
-Loopback MIDI device support
-CONFIG_VMIDI
+#Loopback MIDI device support
+#CONFIG_SOUND_VMIDI
 ###
 ### somebody please fill this in.
 ###
-
+#
 Gravis Ultrasound support
 CONFIG_SOUND_GUS
   Say Y here for any type of Gravis Ultrasound card, including
@@ -7597,6 +7995,12 @@ CONFIG_SOUND_PSS
   card based on the PSS chipset (AD1848 codec + ADSP-2115 DSP chip +
   Echo ESC614 ASIC CHIP).
 
+#Enable PSS mixer (Beethoven ADSP-16 and other compatible)
+#CONFIG_PSS_MIXER
+###
+### Don't know what this is
+###
+#
 Have DSPxxx.LD firmware file
 CONFIG_PSS_HAVE_BOOT
   If you want to emulate the Sound Blaster card and you have a DSPxxx.LD
@@ -7685,8 +8089,9 @@ CONFIG_MAD16_OLDCARD
 Support for Crystal CS4232 based (PnP) cards
 CONFIG_SOUND_CS4232
   Say Y here if you have a card based on the Crystal CS4232 chip set,
-  which use its own Plug and Play protocol. See Documentation/sound/CS4232
-  for more information on configuring this card.
+  which uses its own Plug and Play protocol. See
+  Documentation/sound/CS4232 for more information on configuring this
+  card.
 
 Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers
 CONFIG_SOUND_MAUI
@@ -7703,6 +8108,43 @@ Full pathname of OSWF.MOT firmware file
 CONFIG_MAUI_BOOT_FILE
   Enter the full pathname of your OSWF.MOT file, starting from /.
 
+Support for Turtle Beach MultiSound Classic, Tahiti, Monterey
+CONFIG_SOUND_MSNDCLAS
+  Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
+  Monterey (not for the Pinnacle or Fiji).  See
+  Documentation/sound/MultiSound for important information about this
+  driver.
+
+Full pathname of MSNDINIT.BIN firmware file
+CONFIG_MSNDCLAS_INIT_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included.  These files can be
+  obtained from Turtle Beach.
+
+Full pathname of MSNDPERM.BIN firmware file
+CONFIG_MSNDCLAS_PERM_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included.  These files can be
+  obtained from Turtle Beach.
+
+Support for Turtle Beach MultiSound Pinnacle, Fiji
+CONFIG_SOUND_MSNDPIN
+  Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji.
+  See Documentation/sound/MultiSound for important information about
+  this driver.
+
+Full pathname of PNDSPINI.BIN firmware file
+CONFIG_MSNDPIN_INIT_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included.  These files can be
+  obtained from Turtle Beach.
+
+Full pathname of PNDSPERM.BIN firmware file
+CONFIG_MSNDPIN_PERM_FILE
+  The MultiSound cards have two firmware files which are required for
+  operation, and are not currently included.  These files can be
+  obtained from Turtle Beach.
+
 /dev/dsp and /dev/audio support
 CONFIG_SOUND_AUDIO
   Answering N disables /dev/dsp and /dev/audio, the A/D and D/A
@@ -7731,11 +8173,6 @@ CONFIG_LOWLEVEL_SOUND
   affect the kernel; saying Y will simply cause this configure script
   to present you with more options. If unsure, say Y.
 
-SB32/AWE support
-CONFIG_AWE32_SYNTH
-  Say Y here if you have a SB32 or SB AWE soundcard. See
-  drivers/sound/lowlevel/README.awe for more info.
-
 ACI mixer (miroPCM12)
 CONFIG_ACI_MIXER
   Audio Command Interface (ACI) driver.  ACI is a protocol used to
@@ -8181,9 +8618,12 @@ CONFIG_ATARI
 
 Macintosh support
 CONFIG_MAC
-  This option enables support for the Apple Macintosh series of computers
-  (yes, there is experimental support now, at least for part of the series).  
-  Say N unless you're willing to code the remaining necessary support. ;)
+  This option enables support for the Apple Macintosh series of
+  computers (yes, there is experimental support now, at least for part
+  of the series).
+  
+  Say N unless you're willing to code the remaining necessary support.
+  ;)
 
 # CONFIG_APOLLO, etc. coming soon (?)
 
@@ -8743,11 +9183,43 @@ CONFIG_VIDEO_PMS
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+CPU Optimisation
+CONFIG_CPU_ARM2
+  This selects the processor type of your CPU.  This is only used to
+  determine C compiler optimisation options, and can affect the
+  compatability of the kernel on other processors.  If you specify
+  ARM6, the kernel should work on all 32-bit processors.  If you
+  specify ARM2, ARM250 or ARM3, it should work on all 26-bit
+  processors.  If you're not sure, set it to "None".
+
+ARM System type
+CONFIG_ARCH_ARC
+  This selects what ARM system you wish to build the kernel for.  It
+  also selects to some extent the CPU type.  If you are unsure what
+  to set this option to, please consult any information supplied with
+  your system.
+
+Build Tools Selection
+CONFIG_BINUTILS_NEW
+  Say Y here if you're using GCC 2.8.1/EGCS with a binutils version >= 2.8.1
+  to compile the kernel.  Otherwise, say N.
+
+Compile kernel with frame pointer
+CONFIG_FRAME_POINTER
+  In order to give useful debugging/error results, say Y here, otherwise
+  say N.
+
+VIDC Sound
+CONFIG_VIDC_SOUND
+  Say 'Y' here for ARM systems with the VIDC video controller and 16-bit
+  Linear sound DACs.  If unsure, say N.
+
 #
 # A couple of things I keep forgetting:
-#   capitalize: DMA, Internet, Intel, IRQ, Linux, NetWare, NFS, PCI, SCSI
-#   two words: hard drive, hard disk, sound card
-#   other: it's safe to save; daemon
+#   capitalize: Appletalk, Ethernet, DMA, FTP, Internet, Intel, IRQ, 
+#               Linux, NetWare, NFS, PCI, SCSI
+#   two words:  hard drive, hard disk, sound card
+#   other:      it's safe to save; daemon
 #
 # This is used by Emacs' spell checker ispell.el:
 #
@@ -8767,7 +9239,7 @@ CONFIG_VIDEO_PMS
 # LocalWords:  buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext
 # LocalWords:  QLOGIC qlogic TMC seagate Trantor ultrastor FASST wd NETDEVICES
 # LocalWords:  unix BBS linux nullmodem CSLIP PLIP Kirch's LDP CSlip SL SCC IRQ
-# LocalWords:  Turbo Laplink plip NCSA ReQuest IRQs EQL SMC AMD PCnet NE
+# LocalWords:  Turbo Laplink plip NCSA port's ReQuest IRQs EQL SMC AMD PCnet NE
 # LocalWords:  COM ELPLUS Com EtherLinkIII VLB Arcnet arcnet Cabletron DEPCA DE
 # LocalWords:  depca EtherWorks EWRK ewrk SEEQ EtherExpressPro EEXPRESS NI xxx
 # LocalWords:  EtherExpress WaveLAN wavelan PCLAN HPLAN VG SK Ansel Xen de ZNET
@@ -8788,7 +9260,7 @@ CONFIG_VIDEO_PMS
 # LocalWords:  chipset FB multicast MROUTE appletalk ifconfig IBMTR multiport
 # LocalWords:  Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard
 # LocalWords:  Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem
-# LocalWords:  carleton Deskstation DECstation SUNFD JENSEN Noname SLiRP
+# LocalWords:  carleton Deskstation DECstation SUNFD JENSEN Noname XXXM SLiRP
 # LocalWords:  pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd
 # LocalWords:  RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff
 # LocalWords:  dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
@@ -8810,10 +9282,10 @@ CONFIG_VIDEO_PMS
 # LocalWords:  ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr
 # LocalWords:  ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
 # LocalWords:  initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS
-# LocalWords:  FC DC dc PPA ppa RNFS FMV Fujitsu ARPD arpd loran layes
+# LocalWords:  FC DC dc PPA IOMEGA's ppa RNFS FMV Fujitsu ARPD arpd loran layes
 # LocalWords:  FRAD indiana framerelay DLCI DCLIs Sangoma SDLA mrouted sync sec
 # LocalWords:  Starmode Metricom MosquitoNet mosquitonet kbit nfsroot Digiboard
-# LocalWords:  DIGI Xe Xeve digiboard UMISC touchscreens mtu HBAs MEX
+# LocalWords:  DIGI Xe Xeve digiboard UMISC touchscreens mtu ethernets HBAs MEX
 # LocalWords:  Shifflett netcom js jshiffle WIC DECchip ELCP EtherPower dst RTC
 # LocalWords:  rtc SMP lp Digi Intl RightSwitch DGRS dgrs AFFS Amiga UFS SDL AP
 # LocalWords:  Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au artoo ufs
@@ -8822,7 +9294,7 @@ CONFIG_VIDEO_PMS
 # LocalWords:  Bernd informatik rwth aachen uae affs multihosting bytecode java
 # LocalWords:  applets applet JDK ncsa cabi SNI Alphatronix readme LANs scarab
 # LocalWords:  winsock RNIS caltech OSPF honour Honouring Mbit Localtalk DEFRAG
-# LocalWords:  download Packetwin Baycom baycom interwork ascii JNT
+# LocalWords:  localtalk download Packetwin Baycom baycom interwork ascii JNT
 # LocalWords:  Camtec proxying indyramp defragment defragmented UDP FAS FASXX
 # LocalWords:  FastSCSI SIO FDC qlogicfas QLogic qlogicisp setbaycom ife ee LJ
 # LocalWords:  ethz ch Travelmates ProAudioSpectrum ProAudio SoundMan SB SBPro
@@ -8865,7 +9337,7 @@ CONFIG_VIDEO_PMS
 # LocalWords:  smp HiSax SiemensChipSet Siemens AVM Elsa ITK hisax PCC MICROR
 # LocalWords:  Mircolink EURO DSS Spellcaster BRI sc spellcast Digiboards GPIO
 # LocalWords:  SYMBIOS COMPAT SDMS rev ASUS Tekram HX VX API ibmmcascsi ASY asy
-# LocalWords:  loader's PCnetPCI automounter AUTOFS amd autofs VT Gallant's PnP
+# LocalWords:  loader's PCnetPCI automounter AUTOFS amd autofs VT Gallant's Pnp
 # LocalWords:  AEDSP aedsp enskip tik Sysctl sysctl PARPORT parport pnp IDs EPP
 # LocalWords:  Autoprobe bart patrickr HDLS READBACK AB usr DAMA DS SparQ aten
 # LocalWords:  Symbios PCscsi tmscsim RoamAbout GHz Hinds' contrib mathematik
@@ -8918,4 +9390,12 @@ CONFIG_VIDEO_PMS
 # LocalWords:  mwave OLDCARD isdnloop linklevel loopctrl Eicon Diehl DIEHLDIVA
 # LocalWords:  ASUSCOM AsusCom TELEINT semiactiv Sedlbauer Sportster TA MIC ITH
 # LocalWords:  NETjet NetJet Niccy Neuhaus sparcs AOC AOCD AOCE Microlink SAA
-# LocalWords:  teletext WinTV saa iproute tc
+# LocalWords:  teletext WinTV saa iproute tc Quadra Performa PowerBook tor AUN
+# LocalWords:  setserial compsoc steve Econet econet AUNUDP psched TEQL TLE CLS
+# LocalWords:  teql FW Ingres TwistedPair MTRR MTRRs mtrr cfs crypto TD ktti KT
+# LocalWords:  PHd ICS ipchains adelaide rustcorp syslog epp Cumana
+# LocalWords:  AcornSCSI EcoSCSI EESOX EESOXSCSI Powertec POWERTECSCSI dec SF
+# LocalWords:  RadioReveal gatekeeper aimslab aztech FMI sf fmi RTL rtl cesdis
+# LocalWords:  Yellowfin gsfc nasa gov yellowfin pcnet Mylex LNE lne EtherH hs
+# LocalWords:  EBSA chattr RiscOS Winmodem AGP Atomwide DUALSP pcsp robinson
+# LocalWords:  SGALAXY Waverider DSPxxx TRXPRO AudioTrix OSWF MOT
diff --git a/Documentation/MultiSound b/Documentation/MultiSound
deleted file mode 100644 (file)
index 2e104c1..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Turtle Beach Multisound support is not yet integrated. If you'd like
-to test it or help out in finishing the module please see
-
-       http://www.rpi.edu/~veliaa/pinlinux.html
index 2f0a4249e4a3c6c5e7a565628d71e7e28ff321fa..20f984687c90c4405f0be4f92da0939add783d58 100644 (file)
@@ -21,7 +21,8 @@ Mount options that are unique to the isofs filesystem.
   check=strict  Matches only filenames with the exact same case
   cruft         Try to handle badly formatted CDs.
   map=off       Do not map non-rockridge filenames to lowercase
-  map=normal    Map rockridge filenames to lowercase
+  map=normal    Map non-rockridge filenames to lowecase
+  map=acorn     As map=normal but also apply Acorn extensions if present
   mode=xxx      Sets the permissions on files to xxx
   nojoliet      Ignore Joliet extensions if they are present.
   norock        Ignore rockridge extensions if they are present.
index 0a5183b58fb961c66c820b0a5efa1791ad10b20b..47141f7a391b96ad929bddd6e1b63f16305bf7cd 100644 (file)
@@ -44,6 +44,7 @@ parallel port IDE subsystem, including:
        Imation Superdisk LS-120
        FreeCom Power CD
        Hewlett-Packard 5GB tape drive
+       Hewlett-Packard 7100 and 7200 CD-RW drives
 
 as well as most of the clone and no-name products on the market.
 
@@ -57,8 +58,9 @@ high-level drivers for each of the different type of supported device:
        pcd     ATAPI CD-ROM
        pf      ATAPI disk
        pt      ATAPI tape
+       pg      ATAPI generic
 
-(Support for ATAPI CD-R and CD-RW drives is in the design phase.)
+(Currently, the pg driver is only used with CD-R drives).
 
 The high-level drivers function according to the relevant standards.
 The third component of PARIDE is a set of low-level protocol drivers
@@ -72,7 +74,8 @@ support is available for almost all known adapter protocols:
         dstr    DataStor EP-2000                       (TW)
         epat    Shuttle EPAT                           (UK)
         epia    Shuttle EPIA                           (UK)
-       fit2    FIT TD-2000
+       fit2    FIT TD-2000                            (US)
+       fit3    FIT TD-3000                            (US)
         frpw    Freecom Power                          (DE)
         kbic    KingByte KBIC-951A and KBIC-971A       (TW)
        ktti    KT Technology PHd adapter              (SG)
@@ -111,6 +114,7 @@ and high-level drivers that you would use:
        Avatar                  Shark           pd      epat
        FreeCom                 CD-ROM          pcd     frpw
        Hewlett-Packard         5GB Tape        pt      epat
+       Hewlett-Packard         7100/7200       pg      epat
 
 2.1  Configuring built-in drivers
 
@@ -258,6 +262,7 @@ for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done
 for u in 0 1 2 3 ; do mkdev pf$u  b 47 $u ; done 
 for u in 0 1 2 3 ; do mkdev pt$u  c 96 $u ; done 
 for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done 
+for u in 0 1 2 3 ; do mkdev pg$u  c 97 $u ; done 
 #
 # end of mkd
 
@@ -285,6 +290,11 @@ floppy that you could share with a DOS system:
        mkdosfs /dev/pf0
        mount /dev/pf0 /mnt
 
+2.4  Using the pg driver
+
+The pg driver can be used in conjunction with the cdrecord program
+to create CD-ROMs.  For more information, and the required patches 
+to cdrecord, please visit http://www.torque.net/parport/cdr.html .
 
 3. Troubleshooting
 
@@ -333,6 +343,6 @@ have in your mail headers, when sending mail to the list server.
 You might also find some useful information on the linux-parport
 web pages (although they are not always up to date) at
 
-       http://www.torque.net/linux-pp.html
+       http://www.torque.net/parport/
 
 
diff --git a/Documentation/sound/ALS007 b/Documentation/sound/ALS007
new file mode 100644 (file)
index 0000000..7ec31d5
--- /dev/null
@@ -0,0 +1,40 @@
+ALS-007 based soundcards
+========================
+
+Support for soundcards based around the Avance Logic ALS-007 chip is
+included.  The ALS-007 is a single chip PnP sound solution which is mostly
+hardware compatible with the Sound Blaster 16 card, with most differences
+occuring in the use of the mixer registers.  For this reason the ALS-007 
+code is integrated as part of the Sound Blaster 16 driver (adding only 800
+bytes to the SB16 driver).
+
+To use an ALS-007 soundcard under Linux, enable the following options in the
+sound configuration section of the kernel config:
+  - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
+  - FM synthesizer (YM3812/OPL-3) support 
+Since the ALS-007 is a PnP card, the sound driver probably should be
+compiled as a module, with the isapnptools used to wake up the soundcard.
+Set the "I/O base for SB", "Sound Blaster IRQ" and "Sound Blaster DMA" (8 bit -
+either 0, 1 or 3) to the values used in your particular installation (they
+should match the values used to configure the card using isapnp).  The
+ALS-007 does NOT implement 16 bit DMA, so the "Sound Blaster 16 bit DMA"
+should be set to -1.  If you wish to use the externel MPU-401 interface on
+the card, "MPU401 I/O base of SB16" and "SB MPU401 IRQ" should be set to
+the appropriate values for your installation.  (Note that the ALS-007
+requires a separate IRQ for the MPU-401, so don't specify -1 here).  (Note
+that the base port of the internal FM synth is fixed at 0x388 on the ALS007; 
+in any case the FM synth location is not setable in the kernel config).
+
+The resulting sound driver will provide the following capabilities:
+  - 8 and 16 bit audio playback
+  - 8 and 16 bit audio recording
+  - Software selection of record source (line in, CD, FM, mic, master)
+  - Record and playback of midi data via the external MPU-401
+  - Playback of midi data using inbuilt FM synthesizer
+  - Control of the ALS-007 mixer via any OSS-compatible mixer programs. 
+    Controls available are Master (L&R), Line in (L&R), CD (L&R), 
+    DSP/PCM/audio out (L&R), FM (L&R) and Mic in (mono).
+
+Jonathan Woithe
+jwoithe@physics.adelaide.edu.au
+30 March 1998
index 351f88a3855d4fe6ef487b6bd1514666925422ff..7c9c4f41916bf16510975956cf37f9ca52759055 100644 (file)
@@ -5,7 +5,7 @@ with 2.1.86 and 2.1.88) with modularized sound support these lines can
 be issued (of course with the suitable values for the parameters)
 after PNP setup:
 
-insmod  sound.o
+modprobe  sound.o
 insmod  uart401.o
 insmod  sb.o io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
 insmod  awe_wave.o
@@ -59,5 +59,6 @@ rmmod opl3
 rmmod sb
 rmmod uart401
 rmmod sound
+rmmod soundcore
  -----
 
diff --git a/Documentation/sound/MultiSound b/Documentation/sound/MultiSound
new file mode 100644 (file)
index 0000000..6bdecb3
--- /dev/null
@@ -0,0 +1,146 @@
+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).  MultiSound support is
+fully modularized, and can only be used as 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 assember.
+
+* 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).
+
+
+Creating and Obtaining Firmware
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+       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.
+
+
+       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.
diff --git a/Documentation/sound/Multisound b/Documentation/sound/Multisound
new file mode 100644 (file)
index 0000000..2e104c1
--- /dev/null
@@ -0,0 +1,4 @@
+Turtle Beach Multisound support is not yet integrated. If you'd like
+to test it or help out in finishing the module please see
+
+       http://www.rpi.edu/~veliaa/pinlinux.html
index 21f685a0fb20c33d939551fdc6b76ffb8524dfd3..b314d6f99e1b061d2c82ab3f108e5ce1bf71d827 100644 (file)
@@ -32,7 +32,11 @@ To make this driver work with Mwave you must set mwave_bug. You also need
 to warm boot from DOS/Windows with the required firmware loaded under this
 OS. IBM are being difficult about documenting how to load this firmware.
 
-Advance Logic ALS007
+Avance Logic ALS007
 
-This card isn't currently supported. I have patches to merge however that
-add limited support.
+This card is supported; see the separate file ALS007 for full details.
+
+Avance Logic ALS100
+
+This card is supported; setup should be as for a standard Sound Blaster 16.
+The driver will identify the audio device as a "Sound Blaster 16 (ALS-100)".
index f12bade7752bc81d34931d3196e3f411cd931b58..f77b3e3107d595e7dfc71fe91bf7bf336c3ea78b 100644 (file)
@@ -277,7 +277,7 @@ S:  Maintainted
 
 HIGH-SPEED SCC DRIVER FOR AX.25
 P:     Klaus Kudielka
-M:     oe1kib@oe1xtu.ampr.org
+M:     oe1kib@oe1kib.ampr.org
 L:     linux-hams@vger.rutgers.edu
 S:     Maintained
 
@@ -304,6 +304,12 @@ M: Gadi Oxman <gadio@netvision.net.il>
 L:     linux-kernel@vger.rutgers.edu
 S:     Maintained
 
+IP FIREWALL
+P:     Paul Russell
+M:     Paul.Russell@rustcorp.com.au
+W:     http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
+S:     Maintained
+
 IPX/SPX NETWORK LAYER
 P:     Jay Schulist
 M:     Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
@@ -379,6 +385,11 @@ M: rubini@ipvvis.unipv.it
 L:     linux-kernel@vger.rutgers.edu
 S:     Maintained
 
+MULTISOUND SOUND DRIVER
+P:     Andrew Veliath
+M:     andrewtv@usa.net
+S:     Maintained
+
 NCP FILESYSTEM:
 P:     Petr Vandrovec
 M:     vandrove@vc.cvut.cz
@@ -539,6 +550,12 @@ M: io8-linux@specialix.co.uk
 L:     linux-kernel@vger.rutgers.edu ?
 S:     Supported
 
+SPX NETWORK LAYER
+P:     Jay Schulist
+M:     Jay.Schulist@spacs.k12.wi.us
+L:     linux-net@vger.rutgers.edu
+S:     Supported
+
 STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS
 P:     Greg Ungerer
 M:     support@stallion.oz.au
@@ -571,8 +588,9 @@ S:  Supported
 
 TOKEN-RING NETWORK DRIVER
 P:     Paul Norton
-M:     pnorton@cts.com
+M:     p.norton@computer.org
 L:     linux-net@vger.rutgers.edu
+L:     linux-tr@emissary.aus-etc.com
 S:     Maintained
 
 U14-34F SCSI DRIVER
@@ -631,6 +649,19 @@ W: http://qsl.net/dl1bke/
 L:     linux-hams@vger.rutgers.edu
 S:     Maintained
 
+ARM PORT
+P:     Russell King
+M:     linux@arm.uk.linux.org
+L:     linux-arm@vger.rutgers.edu
+L:     arm-linux@tardis.ed.ac.uk
+W:     http://www.arm.uk.linux.org/~rmk/armlinux.html
+S:     Maintained
+
+ARM MFM AND FLOPPY DRIVERS
+P:     Dave Gilbert
+M:     linux@treblig.org
+S:     Maintained
+
 REST:
 P:     Linus Torvalds
 S:     Buried alive in diapers
index 9c16f05a0d29fd16d544ef8b98f462d2c46850e3..69ed8f5252878d34b892f269f55e7332c2ae31d7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ VERSION = 2
 PATCHLEVEL = 1
 SUBLEVEL = 106
 
-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
+ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm*/arm/ -e s/sa110/arm/)
 
 #
 # For SMP kernels, set this. We don't want to have this in the config file
diff --git a/README b/README
index 9c4b5bd7df34d9c7fa77f79ed496d893cf419c6f..e26de3a585af2bb489d39d17ba6797b271e53e3b 100644 (file)
--- a/README
+++ b/README
@@ -39,8 +39,8 @@ WHAT IS LINUX?
 ON WHAT HARDWARE DOES IT RUN?
 
   Linux was first developed for 386/486-based PCs.  These days it also
-  runs on DEC Alphas, SUN Sparcs, M68000 machines (like Atari and Amiga),
-  MIPS, PowerPC, and others.
+  runs on ARMs, DEC Alphas, SUN Sparcs, M68000 machines (like Atari and
+  Amiga), MIPS and PowerPC, and others.
 
 DOCUMENTATION:
 
index e0eafa2323f89dff51233f7ff3ca8366c0b663f8..eb923b416003220b5d47d9d49bb331b928da3a08 100644 (file)
@@ -537,11 +537,15 @@ asmlinkage int osf_utsname(char *name)
        error = verify_area(VERIFY_WRITE, name, 5 * 32);
        if (error)
                goto out;
+               
+       down(&uts_sem);
        copy_to_user(name + 0, system_utsname.sysname, 32);
        copy_to_user(name + 32, system_utsname.nodename, 32);
        copy_to_user(name + 64, system_utsname.release, 32);
        copy_to_user(name + 96, system_utsname.version, 32);
        copy_to_user(name + 128, system_utsname.machine, 32);
+       up(&uts_sem);
+       
 out:
        unlock_kernel();
        return error;
@@ -602,11 +606,13 @@ asmlinkage int osf_getdomainname(char *name, int namelen)
        if (namelen > 32)
                len = 32;
 
+       down(&uts_sem);
        for (i = 0; i < len; ++i) {
-               put_user(system_utsname.domainname[i], name + i);
+               __put_user(system_utsname.domainname[i], name + i);
                if (system_utsname.domainname[i] == '\0')
                        break;
        }
+       up(&uts_sem);
 out:
        unlock_kernel();
        return error;
@@ -843,6 +849,8 @@ asmlinkage long osf_sysinfo(int command, char *buf, long count)
                printk("sysinfo(%d)", command);
                goto out;
        }
+       
+       down(&uts_sem);
        res = sysinfo_table[offset];
        len = strlen(res)+1;
        if (len > count)
@@ -851,6 +859,7 @@ asmlinkage long osf_sysinfo(int command, char *buf, long count)
                err = -EFAULT;
        else
                err = 0;
+       up(&uts_sem);
 out:
        unlock_kernel();
        return err;
index 401a7af4643819cf1db410eda14c6b421bfee0bd..f318e87cc1d4a6ab65b15eb5a9d3f9a8574a43ea 100644 (file)
@@ -120,6 +120,7 @@ asmlinkage int sys_idle(void)
        /* endless idle loop with no priority at all */
        current->counter = -100;
        for (;;) {
+               check_pgt_cache();
                schedule();
        }
        ret = 0;
index 7562f6709bdb8c9a7ca2767a2737feec1cf2f5aa..7e0a2f070c04c8df8922fcb56838fb64d27dd5e6 100644 (file)
@@ -28,6 +28,67 @@ extern void show_net_buffers(void);
 
 struct thread_struct * original_pcb_ptr;
 
+#ifndef __SMP__
+struct pgtable_cache_struct quicklists;
+#endif
+
+void __bad_pmd(pgd_t *pgd)
+{
+       printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+       pgd_set(pgd, BAD_PAGETABLE);
+}
+
+void __bad_pte(pmd_t *pmd)
+{
+       printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+       pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+}
+
+pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
+{
+       pmd_t *pmd;
+
+       pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+       if (pgd_none(*pgd)) {
+               if (pmd) {
+                       clear_page((unsigned long)pmd);
+                       pgd_set(pgd, pmd);
+                       return pmd + offset;
+               }
+               pgd_set(pgd, BAD_PAGETABLE);
+               return NULL;
+       }
+       free_page((unsigned long)pmd);
+       if (pgd_bad(*pgd)) {
+               __bad_pmd(pgd);
+               return NULL;
+       }
+       return (pmd_t *) pgd_page(*pgd) + offset;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+       pte_t *pte;
+
+       pte = (pte_t *) __get_free_page(GFP_KERNEL);
+       if (pmd_none(*pmd)) {
+               if (pte) {
+                       clear_page((unsigned long)pte);
+                       pmd_set(pmd, pte);
+                       return pte + offset;
+               }
+               pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+               return NULL;
+       }
+       free_page((unsigned long)pte);
+       if (pmd_bad(*pmd)) {
+               __bad_pte(pmd);
+               return NULL;
+       }
+       return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -56,7 +117,7 @@ pte_t __bad_page(void)
 void show_mem(void)
 {
        int i,free = 0,total = 0,reserved = 0;
-       int shared = 0;
+       int shared = 0, cached = 0;
 
        printk("\nMem-info:\n");
        show_free_areas();
@@ -66,6 +127,8 @@ void show_mem(void)
                total++;
                if (PageReserved(mem_map+i))
                        reserved++;
+               else if (PageSwapCache(mem_map+i))
+                       cached++;
                else if (!atomic_read(&mem_map[i].count))
                        free++;
                else
@@ -75,6 +138,8 @@ void show_mem(void)
        printk("%d free pages\n",free);
        printk("%d reserved pages\n",reserved);
        printk("%d pages shared\n",shared);
+       printk("%d pages swap cached\n",cached);
+       printk("%d pages in page table cache\n",pgtable_cache_size);
        show_buffers();
 #ifdef CONFIG_NET
        show_net_buffers();
@@ -213,16 +278,16 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
 
 void free_initmem (void)
 {
-        extern char __init_begin, __init_end;
-        unsigned long addr;
-
-        addr = (unsigned long)(&__init_begin);
-        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-                mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-                atomic_set(&mem_map[MAP_NR(addr)].count, 1);
-                free_page(addr);
-        }
-        printk ("Freeing unused kernel memory: %ldk freed\n",
+       extern char __init_begin, __init_end;
+       unsigned long addr;
+
+       addr = (unsigned long)(&__init_begin);
+       for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+               mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+               atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+               free_page(addr);
+       }
+       printk ("Freeing unused kernel memory: %ldk freed\n",
                (&__init_end - &__init_begin) >> 10);
 }
 
index 66d18c8e49939b0c321454570cc22096c2b3b5c3..6c13eaaf130c07c615822506ab649216317ccff0 100644 (file)
@@ -309,16 +309,20 @@ sys_compat_mount (char *devname, char *dirname, char *type, unsigned long flags,
 asmlinkage int sys_uname (struct old_utsname * name)
 {
        static int warned = 0;
-
+       int err;
+       
        if (warned == 0) {
                warned ++;
                printk (KERN_NOTICE "%s (%d): obsolete uname call\n",
                        current->comm, current->pid);
        }
 
-       if (name && !copy_to_user (name, &system_utsname, sizeof (*name)))
-               return 0;
-       return -EFAULT;
+       if(!name)
+               return -EFAULT;
+       down(&uts_sem);
+       err=copy_to_user (name, &system_utsname, sizeof (*name));
+       up(&uts_sem);
+       return err?-EFAULT:0;
 }
 
 asmlinkage int sys_olduname(struct oldold_utsname * name)
@@ -338,6 +342,8 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
        if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
                return -EFAULT;
 
+       down(&uts_sem);
+       
        error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
        error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
        error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
@@ -348,6 +354,9 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
        error -= __put_user(0,name->version+__OLD_UTS_LEN);
        error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
        error -= __put_user(0,name->machine+__OLD_UTS_LEN);
+       
+       up(&uts_sem);
+       
        error = error ? -EFAULT : 0;
 
        return error;
index 60261b83679c06f48c7979f6b4bad613b9a7d46a..4bbcbd1ef7253b0d0659b8b3f2bb86323ae42487 100644 (file)
@@ -531,6 +531,24 @@ end_move_self:
        out     #0x60,al
        call    empty_8042
 
+! wait until a20 really *is* enabled; it can take a fair amount of
+! time on any
+       
+       push    ds
+       push    es
+       xor     ax,ax                   ! segment 0x0000
+       mov     ds,ax
+       dec     ax                      ! segment 0xffff (HMA)
+       mov     es,ax
+a20_wait:
+       inc     ax
+       mov     [0x7c00],ax             ! any unused memory location < 64K
+       seg     es
+       cmp     ax,[0x7c10]             ! corresponding HMA address
+       je      a20_wait                ! loop until no longer aliased
+       pop     es
+       pop     ds
+               
 ! make sure any possible coprocessor is properly reset..
 
        xor     ax,ax
index 7c640aeb9830dc0cf922cb0e2a8fc7bed0de7811..92b23a058ec6f2eb1daaea8309547ba1ca6e135e 100644 (file)
@@ -104,11 +104,6 @@ startup_32:
  * in 16-bit mode for the "real" operations.
  */
        call setup_idt
-       xorl %eax,%eax
-1:     incl %eax               # check that A20 really IS enabled
-       movl %eax,0x000000      # loop forever if it isn't
-       cmpl %eax,0x100000
-       je 1b
 /*
  * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
  * confuse the debugger if this code is traced.
index 2c5de4f2a44b8ee90c2054d3b4ac203c451778d5..ddeeb898a6ce7cdec0b0c9ef573cab0a5310be2a 100644 (file)
@@ -125,8 +125,10 @@ asmlinkage int sys_idle(void)
                 *      the APM bios knowing only one CPU at a time will do
                 *      so.
                 */
-               if (!start_idle) 
+               if (!start_idle) {
+                       check_pgt_cache();
                        start_idle = jiffies;
+               }
                if (jiffies - start_idle > HARD_IDLE_TIMEOUT) 
                        hard_idle();
                else  {
@@ -158,6 +160,7 @@ int cpu_idle(void *unused)
                if(current_cpu_data.hlt_works_ok &&
                                !hlt_counter && !need_resched)
                        __asm("hlt");
+               check_pgt_cache();
                /*
                 * tq_scheduler currently assumes we're running in a process
                 * context (ie that we hold the kernel lock..)
@@ -551,9 +554,9 @@ int dump_fpu (struct pt_regs * regs, struct user_i387_struct* fpu)
 
        if ((fpvalid = current->used_math) != 0) {
                if (boot_cpu_data.hard_math) {
-                 if (last_task_used_math == current) {
-                         __asm__("clts ; fsave %0; fwait": :"m" (*fpu));
-                 }
+                       if (last_task_used_math == current) {
+                               __asm__("clts ; fsave %0; fwait": :"m" (*fpu));
+                       }
                        else
                                memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
                } else {
index 90a51bd1cd99245c9f8a58df1d43a3e5fd62977e..7b4c86192be1550bbaedf30252dba44552f60bc2 100644 (file)
@@ -361,7 +361,7 @@ static struct cpu_model_info cpu_models[] __initdata = {
        { X86_VENDOR_AMD,       5,
          { "K5/SSA5 (PR-75, PR-90, PR-100)", "K5 (PR-120, PR-133)",
            "K5 (PR-166)", "K5 (PR-200)", NULL, NULL,
-           "K6 (166 - 266)", "K6 (166 - 300)", "K6-3D (200 - 450)",
+           "K6 (166 - 266)", "K6 (166 - 300)", "K6-2 (200 - 450)",
            "K6-3D-Plus (200 - 450)", NULL, NULL, NULL, NULL, NULL, NULL }},
        { X86_VENDOR_UMC,       4,
          { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -442,11 +442,11 @@ int get_cpuinfo(char * buffer)
 {
        char *p = buffer;
        int sep_bug;
-        static const char *x86_cap_flags[] = {
-                "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-                "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
-                "fcmov", "17", "18", "19", "20", "21", "22", "mmx",
-                "osfxsr", "25", "26", "27", "28", "29", "30", "amd3d"
+        static char *x86_cap_flags[] = {
+                "fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce",
+                "cx8", "9", "10", "sep", "12", "pge", "14", "cmov",
+                "16", "17", "18", "19", "20", "21", "22", "mmx",
+                "24", "25", "26", "27", "28", "29", "30", "31"
         };
        struct cpuinfo_x86 *c = cpu_data;
        int i, n;
@@ -474,6 +474,24 @@ int get_cpuinfo(char * buffer)
                } else
                        p += sprintf(p, "stepping\t: unknown\n");
 
+               /* Modify the capabilities according to chip type */
+               if (c->x86_mask) {
+                       if (c->x86_vendor == X86_VENDOR_CYRIX) {
+                               x86_cap_flags[24] = "cxmmx";
+                       } else if (c->x86_vendor == X86_VENDOR_AMD) {
+                               x86_cap_flags[16] = "fcmov";
+                               x86_cap_flags[31] = "amd3d";
+                       } else if (c->x86_vendor == X86_VENDOR_INTEL) {
+                               x86_cap_flags[6] = "pae";
+                               x86_cap_flags[9] = "apic";
+                               x86_cap_flags[12] = "mtrr";
+                               x86_cap_flags[14] = "mca";
+                               x86_cap_flags[16] = "pat";
+                               x86_cap_flags[17] = "pse";
+                               x86_cap_flags[24] = "osfxsr";
+                       }
+               }
+
                sep_bug = c->x86_vendor == X86_VENDOR_INTEL &&
                          c->x86 == 0x06 &&
                          c->cpuid_level >= 0 &&
index 2403da1727c2eecfe966273c4c0d163d8c33db5a..8e740000369b2bff6a22308bebf744aced001d75 100644 (file)
@@ -597,6 +597,9 @@ __initfunc(void smp_store_cpu_info(int id))
        struct cpuinfo_x86 *c=&cpu_data[id];
 
        *c = boot_cpu_data;
+       c->pte_quick = 0;
+       c->pgd_quick = 0;
+       c->pgtable_cache_sz = 0;
        identify_cpu(c);
        /*
         *      Mask B, Pentium, but not Pentium MMX
index ba968fb9000106dce32c0dcb6854d45bd3133515..2d864633312a7aac2bfd2d305547119483549502 100644 (file)
@@ -216,9 +216,13 @@ out:
  */
 asmlinkage int sys_uname(struct old_utsname * name)
 {
-       if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
-               return 0;
-       return -EFAULT;
+       int err;
+       if (!name)
+               return -EFAULT;
+       down(&uts_sem);
+       err=copy_to_user(name, &system_utsname, sizeof (*name));
+       up(&uts_sem);
+       return err?-EFAULT:0;
 }
 
 asmlinkage int sys_olduname(struct oldold_utsname * name)
@@ -230,6 +234,8 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
        if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
                return -EFAULT;
   
+       down(&uts_sem);
+       
        error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
        error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
        error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
@@ -240,7 +246,9 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
        error |= __put_user(0,name->version+__OLD_UTS_LEN);
        error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
        error |= __put_user(0,name->machine+__OLD_UTS_LEN);
-
+       
+       up(&uts_sem);
+       
        error = error ? -EFAULT : 0;
 
        return error;
index c246421a950658eba784b7dacaa4e11554254f34..e743b5d1b6865e2c8ab9519016f2299a9f33c4a1 100644 (file)
@@ -8,6 +8,9 @@
  * Authors:    Jorge Cwik, <jorge@laser.satlink.net>
  *             Arnt Gulbrandsen, <agulbra@nvg.unit.no>
  *             Tom May, <ftom@netcom.com>
+ *              Pentium Pro/II routines:
+ *              Alexander Kjeldaas <astor@guardian.no>
+ *              Finn Arne Gangstad <finnag@guardian.no>
  *             Lots of code moved from tcp.c and ip.c; see those files
  *             for more names.
  *
@@ -26,6 +29,8 @@
  * computes a partial checksum, e.g. for TCP/UDP fragments
  */
 
+#if CPU!=686
+
 unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) {
          /*
           * Experiments with ethernet and slip connections show that buff
@@ -97,6 +102,101 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
        return(sum);
 }
 
+#else  /* 686 */
+
+unsigned int csum_partial(const unsigned char * buf, int len, unsigned int sum) {
+         __asm__ ("
+            testl $2, %%esi         
+            jnz 30f                 
+10:
+            movl %%ecx, %%edx
+            movl %%ecx, %%ebx
+            andl $0x7c, %%ebx
+            shrl $7, %%ecx
+            addl %%ebx,%%esi
+            shrl $2, %%ebx  
+            negl %%ebx
+            lea 45f(%%ebx,%%ebx,2), %%ebx
+            testl %%esi, %%esi
+            jmp %%ebx
+
+            # Handle 2-byte-aligned regions
+20:         addw (%%esi), %%ax
+            lea 2(%%esi), %%esi
+            adcl $0, %%eax
+            jmp 10b
+
+30:         subl $2, %%ecx          
+            ja 20b                 
+            je 32f
+            movzbl (%%esi),%%ebx # csumming 1 byte, 2-aligned
+            addl %%ebx, %%eax
+            adcl $0, %%eax
+            jmp 80f
+32:
+            addw (%%esi), %%ax # csumming 2 bytes, 2-aligned
+            adcl $0, %%eax
+            jmp 80f
+
+40: 
+           addl -128(%%esi), %%eax
+            adcl -124(%%esi), %%eax
+            adcl -120(%%esi), %%eax
+            adcl -116(%%esi), %%eax   
+           adcl -112(%%esi), %%eax   
+            adcl -108(%%esi), %%eax
+            adcl -104(%%esi), %%eax
+            adcl -100(%%esi), %%eax
+            adcl -96(%%esi), %%eax
+            adcl -92(%%esi), %%eax
+            adcl -88(%%esi), %%eax
+            adcl -84(%%esi), %%eax
+            adcl -80(%%esi), %%eax
+            adcl -76(%%esi), %%eax
+            adcl -72(%%esi), %%eax
+            adcl -68(%%esi), %%eax
+           adcl -64(%%esi), %%eax     
+            adcl -60(%%esi), %%eax     
+            adcl -56(%%esi), %%eax     
+            adcl -52(%%esi), %%eax   
+            adcl -48(%%esi), %%eax   
+            adcl -44(%%esi), %%eax
+            adcl -40(%%esi), %%eax
+            adcl -36(%%esi), %%eax
+            adcl -32(%%esi), %%eax
+            adcl -28(%%esi), %%eax
+            adcl -24(%%esi), %%eax
+            adcl -20(%%esi), %%eax
+            adcl -16(%%esi), %%eax
+            adcl -12(%%esi), %%eax
+            adcl -8(%%esi), %%eax
+            adcl -4(%%esi), %%eax
+45:
+            lea 128(%%esi), %%esi
+            adcl $0, %%eax
+            dec %%ecx
+            jge 40b
+            movl %%edx, %%ecx
+50:         andl $3, %%ecx
+            jz 80f
+
+            # Handle the last 1-3 bytes without jumping
+            notl %%ecx            # 1->2, 2->1, 3->0, higher bits are masked
+           movl $0xffffff,%%ebx  # by the shll and shrl instructions
+           shll $3,%%ecx
+           shrl %%cl,%%ebx
+           andl -128(%%esi),%%ebx # esi is 4-aligned so should be ok
+           addl %%ebx,%%eax
+           adcl $0,%%eax
+80:          "
+        : "=a"(sum)
+        : "0"(sum), "c"(len), "S"(buf)
+        : "bx", "cx", "dx", "si");
+        return(sum);
+}
+
+#endif
+
 /*
  * Copy from ds while checksumming, otherwise like csum_partial
  *
@@ -112,13 +212,15 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
 "      9999: "#y";                     \n \
        .section __ex_table, \"a\";     \n \
        .long 9999b, 6001f              \n \
-       .previous"
+       .previous\n"
 
 #define DST(y...)                      \
 "      9999: "#y";                     \n \
        .section __ex_table, \"a\";     \n \
        .long 9999b, 6002f              \n \
-       .previous"
+       .previous\n"
+
+#if CPU!=686
 
 unsigned int csum_partial_copy_generic (const char *src, char *dst,
                                  int len, int sum, int *src_err_ptr, int *dst_err_ptr)
@@ -242,6 +344,79 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
     return(sum);
 }
 
+#else /* CPU == 686 */
+
+#define ROUND1(x) \
+        SRC(movl x(%%esi), %%ebx         ) \
+        "addl %%ebx, %%eax\n" \
+        DST(movl %%ebx, x(%%edi)         )
+
+#define ROUND(x) \
+        SRC(movl x(%%esi), %%ebx         ) \
+        "adcl %%ebx, %%eax\n" \
+        DST(movl %%ebx, x(%%edi)         )
+
+unsigned int csum_partial_copy_generic (const char *src, char *dst,
+                                 int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+{
+       __asm__ __volatile__ ("
+        movl %%ecx, %%edx  
+        movl %%ecx, %%ebx  
+        shrl $6, %%ecx     
+        andl $0x3c, %%ebx  
+        negl %%ebx
+        subl %%ebx, %%esi  
+        subl %%ebx, %%edi  
+        lea 3f(%%ebx,%%ebx), %%ebx
+        testl %%esi, %%esi 
+        jmp %%ebx         
+1:      addl $64,%%esi
+        addl $64,%%edi\n" 
+ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
+ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
+ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
+ROUND (-16) ROUND(-12) ROUND(-8)  ROUND(-4)
+"3:     adcl $0,%%eax
+        dec %%ecx
+        jge 1b
+4:      andl $3, %%edx
+        jz 7f
+        cmpl $2, %%edx
+        jb 5f
+  " SRC(movw (%%esi), %%dx         )"
+        leal 2(%%esi), %%esi
+  " DST(movw %%dx, (%%edi)         )"
+        leal 2(%%edi), %%edi
+        je 6f
+        shll $16,%%edx
+5:" SRC(movb (%%esi), %%dl         )"
+  " DST(movb %%dl, (%%edi)         )"
+6:      addl %%edx, %%eax
+        adcl $0, %%eax
+7:
+.section .fixup, \"ax\"
+6000:  movl    %7, (%%ebx)
+# FIXME: do zeroing of rest of the buffer here.
+       jmp     7b
+6001:  movl    %1, %%ebx       
+       jmp     6000b   
+6002:  movl    %2, %%ebx
+       jmp     6000b
+.previous
+        "
+       : "=a"(sum), "=m"(src_err_ptr), "=m"(dst_err_ptr)
+        : "0"(sum), "c"(len), "S"(src), "D" (dst),
+               "i" (-EFAULT)
+        : "bx", "cx", "dx", "si", "di" );
+       return(sum);
+}
+
+#undef ROUND
+#undef ROUND1
+
+#endif
+
+
 #undef SRC
 #undef DST
 
index df8590e5f4947580d32bfebc300490009a11b3b2..ba36ad0025a31a88b59d1f822ad88da907d6765f 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/dma.h>
 
-const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
-
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
 
+void __bad_pte_kernel(pmd_t *pmd)
+{
+       printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+       pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
+}
+
+void __bad_pte(pmd_t *pmd)
+{
+       printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+       pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+}
+
+pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
+{
+       pte_t *pte;
+
+       pte = (pte_t *) __get_free_page(GFP_KERNEL);
+       if (pmd_none(*pmd)) {
+               if (pte) {
+                       clear_page((unsigned long)pte);
+                       pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte);
+                       return pte + offset;
+               }
+               pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
+               return NULL;
+       }
+       free_page((unsigned long)pte);
+       if (pmd_bad(*pmd)) {
+               __bad_pte_kernel(pmd);
+               return NULL;
+       }
+       return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+       unsigned long pte;
+
+       pte = (unsigned long) __get_free_page(GFP_KERNEL);
+       if (pmd_none(*pmd)) {
+               if (pte) {
+                       clear_page(pte);
+                       pmd_val(*pmd) = _PAGE_TABLE + __pa(pte);
+                       return (pte_t *)(pte + offset);
+               }
+               pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+               return NULL;
+       }
+       free_page(pte);
+       if (pmd_bad(*pmd)) {
+               __bad_pte(pmd);
+               return NULL;
+       }
+       return (pte_t *) (pmd_page(*pmd) + offset);
+}
+
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -82,7 +137,7 @@ void show_mem(void)
                total++;
                if (PageReserved(mem_map+i))
                        reserved++;
-               if (PageSwapCache(mem_map+i))
+               else if (PageSwapCache(mem_map+i))
                        cached++;
                else if (!atomic_read(&mem_map[i].count))
                        free++;
@@ -93,6 +148,7 @@ void show_mem(void)
        printk("%d reserved pages\n",reserved);
        printk("%d pages shared\n",shared);
        printk("%d pages swap cached\n",cached);
+       printk("%ld pages in page table cache\n",pgtable_cache_size);
        show_buffers();
 #ifdef CONFIG_NET
        show_net_buffers();
index 0e945744eaed823a204d4f412bde039afa7679af..9cd2d1838dd79292c74375c9201eccc1adfbb3e4 100644 (file)
@@ -64,6 +64,11 @@ CORE_FILES := $(CORE_FILES) arch/m68k/mac/mac.o
 SUBDIRS := $(SUBDIRS) arch/m68k/mac
 endif
 
+ifdef CONFIG_HP300
+CORE_FILES := $(CORE_FILES) arch/m68k/hp300/hp300.o
+SUBDIRS := $(SUBDIRS) arch/m68k/hp300
+endif
+
 ifdef CONFIG_APOLLO
 CORE_FILES := $(CORE_FILES) arch/m68k/apollo/apollo.o
 SUBDIRS := $(SUBDIRS) arch/m68k/apollo
@@ -74,6 +79,11 @@ CORE_FILES := $(CORE_FILES) arch/m68k/mvme16x/mvme16x.o
 SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x
 endif
 
+ifdef CONFIG_BVME6000
+CORE_FILES := $(CORE_FILES) arch/m68k/bvme6000/bvme6000.o
+SUBDIRS := $(SUBDIRS) arch/m68k/bvme6000
+endif
+
 ifdef CONFIG_M68040
 CORE_FILES := $(CORE_FILES) arch/m68k/fpsp040/fpsp.o
 SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040
index 61afbb50b9b3c5fe4256efc87b1988b9750b02b2..15e4c2d09f8f8a42101aa976a92cf94baf104c36 100644 (file)
@@ -294,7 +294,7 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ":
        addql   #8,%%sp
        addql   #4,%%sp
        jbra    "SYMBOL_NAME_STR(ret_from_interrupt)
-        : : "i" (&kstat.irqs), "n" (PT_OFF_FORMATVEC)
+        : : "i" (&kstat.irqs[0]), "n" (PT_OFF_FORMATVEC)
 );
 }
 
index 8c512a714cb70c108048932b175eb6a1c799110a..68e244087b19125cc964e2806db4b5996fa86232 100644 (file)
@@ -28,7 +28,6 @@
 #include <asm/atariints.h>
 #include <asm/atarihw.h>
 #include <asm/atarikb.h>
-#include <asm/atari_mouse.h>
 #include <asm/atari_joystick.h>
 #include <asm/irq.h>
 
@@ -193,7 +192,7 @@ static u_short ataalt_map[NR_KEYS] __initdata = {
        0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
 };
 
-static u_short atashift_alt_map[NR_KEYS] = {
+static u_short atashift_alt_map[NR_KEYS] __initdata = {
        0xf200, 0xf81b, 0xf821, 0xf840, 0xf823, 0xf824, 0xf825, 0xf85e,
        0xf826, 0xf82a, 0xf828, 0xf829, 0xf85f, 0xf82b, 0xf808, 0xf809,
        0xf851, 0xf857, 0xf845, 0xf852, 0xf854, 0xf859, 0xf855, 0xf849,
@@ -767,14 +766,17 @@ void atari_kbd_leds (unsigned int leds)
 __initfunc(int atari_keyb_init(void))
 {
     /* setup key map */
-    memcpy(plain_map, ataplain_map, sizeof(plain_map));
-    memcpy(shift_map, atashift_map, sizeof(shift_map));
+    memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
+    memcpy(key_maps[1], atashift_map, sizeof(plain_map));
+    memcpy(key_maps[4], atactrl_map, sizeof(plain_map));
+    memcpy(key_maps[5], atashift_ctrl_map, sizeof(plain_map));
+    memcpy(key_maps[8], ataalt_map, sizeof(plain_map));
+    /* Atari doesn't have an altgr_map, so we can reuse its memory for
+       atashift_alt_map */
+    memcpy(key_maps[2], atashift_alt_map, sizeof(plain_map));
+    key_maps[9]  = key_maps[2];
     key_maps[2]  = 0; /* ataaltgr_map */
-    memcpy(ctrl_map, atactrl_map, sizeof(ctrl_map));
-    memcpy(shift_ctrl_map, atashift_ctrl_map, sizeof(shift_ctrl_map));
-    memcpy(alt_map, ataalt_map, sizeof(alt_map));
-    key_maps[9]  = atashift_alt_map;
-    memcpy(ctrl_alt_map, atactrl_alt_map, sizeof(ctrl_alt_map));
+    memcpy(key_maps[12], atactrl_alt_map, sizeof(plain_map));
     key_maps[13] = atashift_ctrl_alt_map;
     keymap_count = 8;
 
@@ -860,3 +862,8 @@ int atari_kbdrate( struct kbd_repeat *k )
        
        return( 0 );
 }
+
+/* for "kbd-reset" cmdline param */
+__initfunc(void kbd_reset_setup(char *str, int *ints))
+{
+}
index 6b03b96fd136584e0b93fcc74f7b57fb73aa883b..8223ce95ce21761725873ebe9dcc85c66ec0dc92 100644 (file)
@@ -10,6 +10,9 @@
  * License.  See the file COPYING in the main directory of this archive
  * for more details.
  *
+ * 1998-05-31 ++andreas: atari_mksound rewritten to always use the envelope,
+ *                      no timer, atari_nosound removed.
+ *
  */
 
 
  * stuff from the old atasound.c
  */
 
-
-static void atari_nosound (unsigned long ignored)
-{
-       unsigned char   tmp;
-       unsigned long flags;
-       
-       /* turn off generator A in mixer control */
-       save_flags(flags);
-       cli();
-       sound_ym.rd_data_reg_sel = 7;
-       tmp = sound_ym.rd_data_reg_sel;
-       sound_ym.wd_data = tmp | 0x39;
-       restore_flags(flags);
-}      
-               
-
 void atari_microwire_cmd (int cmd)
 {
        tt_microwire.mask = 0x7ff;
@@ -58,90 +45,62 @@ void atari_microwire_cmd (int cmd)
 }
 
 
-#define        PC_FREQ         1192180
+/* PSG base frequency */
 #define        PSG_FREQ        125000
+/* PSG envelope base frequency times 10 */
+#define PSG_ENV_FREQ_10        78125
 
-
-void atari_mksound (unsigned int count, unsigned int ticks)
+void atari_mksound (unsigned int hz, unsigned int ticks)
 {
-       static struct timer_list sound_timer = { NULL, NULL, 0, 0,
-                                                    atari_nosound };
-       /*
-        * Generates sound of some count for some number of clock ticks
-        * [count = 1193180 / frequency]
-        */
+       /* Generates sound of some frequency for some number of clock
+          ticks.  */
        unsigned long flags;
        unsigned char tmp;
+       int period;
 
        save_flags(flags);
        cli();
 
-       if (count == 750 && ticks == HZ/8) {
-               /* Special case: These values are used by console.c to
-                * generate the console bell. They are cached here and the
-                * sound actually generated is somehow special: it uses the
-                * generator B and an envelope. No timer is needed therefore
-                * and the bell doesn't disturb an other ongoing sound.
-                */
+       /* Convert from frequency value to PSG period value (base
+          frequency 125 kHz).  */
+       period = PSG_FREQ / hz;
+
+       if (period > 0xfff) period = 0xfff;
 
-               /* set envelope duration to 492 ms */
+       /* Disable generator A in mixer control.  */
+       sound_ym.rd_data_reg_sel = 7;
+       tmp = sound_ym.rd_data_reg_sel;
+       tmp |= 011;
+       sound_ym.wd_data = tmp;
+       /* Set generator A frequency to hz.  */
+       sound_ym.rd_data_reg_sel = 0;
+       sound_ym.wd_data = period & 0xff;
+       sound_ym.rd_data_reg_sel = 1;
+       sound_ym.wd_data = (period >> 8) & 0xf;
+       if (ticks) {
+               /* Set length of envelope (max 8 sec).  */
+               int length = (ticks * PSG_ENV_FREQ_10) / HZ / 10;
+
+               if (length > 0xffff) length = 0xffff;
                sound_ym.rd_data_reg_sel = 11;
-               sound_ym.wd_data = 0;
+               sound_ym.wd_data = length & 0xff;
                sound_ym.rd_data_reg_sel = 12;
-               sound_ym.wd_data = 15;
-               /* envelope form: max -> min single */
+               sound_ym.wd_data = length >> 8;
+               /* Envelope form: max -> min single.  */
                sound_ym.rd_data_reg_sel = 13;
-               sound_ym.wd_data = 9;
-               /* set generator B frequency to 2400 Hz */
-               sound_ym.rd_data_reg_sel = 2;
-               sound_ym.wd_data = 52;
-               sound_ym.rd_data_reg_sel = 3;
                sound_ym.wd_data = 0;
-               /* set volume of generator B to envelope control */
-               sound_ym.rd_data_reg_sel = 9;
+               /* Use envelope for generator A.  */
+               sound_ym.rd_data_reg_sel = 8;
                sound_ym.wd_data = 0x10;
-               /* enable generator B in the mixer control */
-               sound_ym.rd_data_reg_sel = 7;
-               tmp = sound_ym.rd_data_reg_sel;
-               sound_ym.wd_data = (tmp & ~0x02) | 0x38;
-
-               restore_flags(flags);
-               return;
-       }
-
-       del_timer( &sound_timer );
-
-       if (!count) {
-               atari_nosound( 0 );
-       }
-       else {
-
-               /* convert from frequency value
-                * to PSG period value (base frequency 125 kHz).
-                */
-               int period = PSG_FREQ / count;
-
-               if (period > 0xfff) period = 0xfff;
-
-               /* set generator A frequency to 0 */
-               sound_ym.rd_data_reg_sel = 0;
-               sound_ym.wd_data = period & 0xff;
-               sound_ym.rd_data_reg_sel = 1;
-               sound_ym.wd_data = (period >> 8) & 0xf;
-               /* turn on generator A in mixer control (but not noise
-                * generator!) */
-               sound_ym.rd_data_reg_sel = 7;
-               tmp = sound_ym.rd_data_reg_sel;
-               sound_ym.wd_data = (tmp & ~0x01) | 0x38;
-               /* set generator A level to maximum, no envelope */
+       } else {
+               /* Set generator A level to maximum, no envelope.  */
                sound_ym.rd_data_reg_sel = 8;
                sound_ym.wd_data = 15;
-               
-               if (ticks) {
-                       sound_timer.expires = jiffies + ticks;
-                       add_timer( &sound_timer );
-               }
        }
+       /* Turn on generator A in mixer control.  */
+       sound_ym.rd_data_reg_sel = 7;
+       tmp &= ~1;
+       sound_ym.wd_data = tmp;
 
        restore_flags(flags);
 }
index 5497d9f73c158cd6c0d2faacdd47fcea476a8de4..57aafc4fe1b92e8e85576c1ac23c9d23da255dc3 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/atari_stram.h>
 #include <asm/system.h>
 #include <asm/machdep.h>
+#include <asm/hwtest.h>
 
 u_long atari_mch_cookie;
 u_long atari_mch_type = 0;
@@ -98,39 +99,15 @@ static char atari_sysrq_xlate[128] =
 
 extern void (*kd_mksound)(unsigned int, unsigned int);
 
-/* This function tests for the presence of an address, specially a
- * hardware register address. It is called very early in the kernel
- * initialization process, when the VBR register isn't set up yet. On
- * an Atari, it still points to address 0, which is unmapped. So a bus
- * error would cause another bus error while fetching the exception
- * vector, and the CPU would do nothing at all. So we needed to set up
- * a temporary VBR and a vector table for the duration of the test.
+/* I've moved hwreg_present() and hwreg_present_bywrite() out into
+ * mm/hwtest.c, to avoid having multiple copies of the same routine
+ * in the kernel [I wanted them in hp300 and they were already used
+ * in the nubus code. NB: I don't have an Atari so this might (just
+ * conceivably) break something.
+ * I've preserved the #if 0 version of hwreg_present_bywrite() here
+ * for posterity.
+ *   -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 05/1998
  */
-
-__initfunc(static int hwreg_present( volatile void *regp ))
-{
-    int        ret = 0;
-    long       save_sp, save_vbr;
-    long       tmp_vectors[3];
-
-    __asm__ __volatile__
-       (       "movec  %/vbr,%2\n\t"
-               "movel  #Lberr1,%4@(8)\n\t"
-                "movec %4,%/vbr\n\t"
-               "movel  %/sp,%1\n\t"
-               "moveq  #0,%0\n\t"
-               "tstb   %3@\n\t"  
-               "nop\n\t"
-               "moveq  #1,%0\n"
-                "Lberr1:\n\t"
-               "movel  %1,%/sp\n\t"
-               "movec  %2,%/vbr"
-               : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
-               : "a" (regp), "a" (tmp_vectors)
-                );
-
-    return( ret );
-}
   
 #if 0
 __initfunc(static int
@@ -163,35 +140,6 @@ hwreg_present_bywrite(volatile void *regp, unsigned char val))
 }
 #endif
 
-/* Basically the same, but writes a value into a word register, protected
- * by a bus error handler */
-
-__initfunc(static int hwreg_write( volatile void *regp, unsigned short val ))
-{
-       int             ret;
-       long    save_sp, save_vbr;
-       long    tmp_vectors[3];
-
-       __asm__ __volatile__
-       (       "movec  %/vbr,%2\n\t"
-               "movel  #Lberr2,%4@(8)\n\t"
-               "movec  %4,%/vbr\n\t"
-               "movel  %/sp,%1\n\t"
-               "moveq  #0,%0\n\t"
-               "movew  %5,%3@\n\t"  
-               "nop    \n\t"   /* If this nop isn't present, 'ret' may already be
-                                * loaded with 1 at the time the bus error
-                                * happens! */
-               "moveq  #1,%0\n"
-       "Lberr2:\n\t"
-               "movel  %1,%/sp\n\t"
-               "movec  %2,%/vbr"
-               : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
-               : "a" (regp), "a" (tmp_vectors), "g" (val)
-       );
-
-       return( ret );
-}
 
 /* ++roman: This is a more elaborate test for an SCC chip, since the plain
  * Medusa board generates DTACK at the SCC's standard addresses, but a SCC
index 82eb85288b1f74a90ddfa78e2c6183c3dd13b165..1deec96538aa681b41d73ab0173933e32f355540 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <asm/atarikb.h>
 #include <asm/atari_joystick.h>
-#include <asm/atari_mouse.h>
 #include <asm/uaccess.h>
 
 #define MAJOR_NR    JOYSTICK_MAJOR
index 2dfe2304ab1445b9d999a651d1f5ed32db778896..757e73754b4575d3fe0e55160feea361d109a1d4 100644 (file)
@@ -954,7 +954,7 @@ static int unswap_by_read( unsigned char *map, unsigned long max,
                                return( -ENOMEM );
                        }
                        DPRINTK( "unswap: reading swap page %lu to %08lx\n", i, page );
-                       read_swap_page( entry, (char *)page );
+                       rw_swap_page( READ, entry, (char *)page, 1 );
 
                        for_each_task(p) {
                                if (unswap_process( p->mm, entry, page, 0 )) {
index 8a3921c8dcb8b864408c9c63bea45b11e7221167..79c4f48f2e629bf4e682dd13eaa43d559f76b2b2 100644 (file)
@@ -83,7 +83,7 @@ static void mste_write(struct MSTE_RTC *val)
 
 #define        RTC_READ(reg)                           \
     ({ unsigned char   __val;                  \
-               writeb(reg,&tt_rtc.regsel);     \
+               (void) writeb(reg,&tt_rtc.regsel);      \
                __val = tt_rtc.data;            \
                __val;                          \
        })
diff --git a/arch/m68k/bvme6000/Makefile b/arch/m68k/bvme6000/Makefile
new file mode 100644 (file)
index 0000000..e8670c6
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/bvme6000 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := bvme6000.o
+O_OBJS   := config.o bvmeints.o rtc.o
+#OX_OBJS = ksyms.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/bvme6000/bvmeints.c b/arch/m68k/bvme6000/bvmeints.c
new file mode 100644 (file)
index 0000000..a79f555
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * arch/m68k/bvme6000/bvmeints.c
+ *
+ * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * based on amiints.c -- Amiga Linux interrupt handling code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+static void bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+static struct {
+       void            (*handler)(int, void *, struct pt_regs *);
+       unsigned long   flags;
+       void            *dev_id;
+       const char      *devname;
+       unsigned        count;
+} irq_tab[256];
+
+/*
+ * void bvme6000_init_IRQ (void)
+ *
+ * Parameters: None
+ *
+ * Returns:    Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the bvme6000 IRQ handling routines.
+ */
+
+void bvme6000_init_IRQ (void)
+{
+       int i;
+
+       for (i = 0; i < 256; i++) {
+               irq_tab[i].handler = bvme6000_defhand;
+               irq_tab[i].flags = IRQ_FLG_STD;
+               irq_tab[i].dev_id = NULL;
+               irq_tab[i].devname = NULL;
+               irq_tab[i].count = 0;
+       }
+}
+
+int bvme6000_request_irq(unsigned int irq,
+               void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+       if (irq > 255) {
+               printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+               return -ENXIO;
+       }
+#if 0
+       /* Nothing special about auto-vectored devices for the BVME6000,
+        * but treat it specially to avoid changes elsewhere.
+        */
+
+       if (irq >= VEC_INT1 && irq <= VEC_INT7)
+               return sys_request_irq(irq - VEC_SPUR, handler, flags,
+                                               devname, dev_id);
+#endif
+       if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
+               if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
+                       printk("%s: IRQ %d from %s is not replaceable\n",
+                              __FUNCTION__, irq, irq_tab[irq].devname);
+                       return -EBUSY;
+               }
+               if (flags & IRQ_FLG_REPLACE) {
+                       printk("%s: %s can't replace IRQ %d from %s\n",
+                              __FUNCTION__, devname, irq, irq_tab[irq].devname);
+                       return -EBUSY;
+               }
+       }
+       irq_tab[irq].handler = handler;
+       irq_tab[irq].flags   = flags;
+       irq_tab[irq].dev_id  = dev_id;
+       irq_tab[irq].devname = devname;
+       return 0;
+}
+
+void bvme6000_free_irq(unsigned int irq, void *dev_id)
+{
+       if (irq > 255) {
+               printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+               return;
+       }
+#if 0
+       if (irq >= VEC_INT1 && irq <= VEC_INT7) {
+               sys_free_irq(irq - VEC_SPUR, dev_id);
+               return;
+       }
+#endif
+       if (irq_tab[irq].dev_id != dev_id)
+               printk("%s: Removing probably wrong IRQ %d from %s\n",
+                      __FUNCTION__, irq, irq_tab[irq].devname);
+
+       irq_tab[irq].handler = bvme6000_defhand;
+       irq_tab[irq].flags   = IRQ_FLG_STD;
+       irq_tab[irq].dev_id  = NULL;
+       irq_tab[irq].devname = NULL;
+}
+
+void bvme6000_process_int (unsigned long vec, struct pt_regs *fp)
+{
+       if (vec > 255)
+               panic ("bvme6000_process_int: Illegal vector %ld", vec);
+       irq_tab[vec].count++;
+       irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+}
+
+int bvme6000_get_irq_list (char *buf)
+{
+       int i, len = 0;
+
+       for (i = 0; i < 256; i++) {
+               if (irq_tab[i].count)
+                       len += sprintf (buf+len, "Vec 0x%02x: %8d  %s\n",
+                           i, irq_tab[i].count,
+                           irq_tab[i].devname ? irq_tab[i].devname : "free");
+       }
+       return len;
+}
+
+
+static void bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+       printk ("Unknown interrupt 0x%02x\n", irq);
+}
+
+void bvme6000_enable_irq (unsigned int irq)
+{
+}
+
+
+void bvme6000_disable_irq (unsigned int irq)
+{
+}
+
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
new file mode 100644 (file)
index 0000000..74d15e9
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ *  arch/m68k/bvme6000/config.c
+ *
+ *  Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * Based on:
+ *
+ *  linux/amiga/config.c
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/bvme6000hw.h>
+
+extern void bvme6000_process_int (int level, struct pt_regs *regs);
+extern void bvme6000_init_IRQ (void);
+extern void bvme6000_free_irq (unsigned int, void *);
+extern int  bvme6000_get_irq_list (char *);
+extern void bvme6000_enable_irq (unsigned int);
+extern void bvme6000_disable_irq (unsigned int);
+static void bvme6000_get_model(char *model);
+static int  bvme6000_get_hardware_list(char *buffer);
+extern int  bvme6000_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void bvme6000_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int  bvme6000_keyb_init(void);
+extern int  bvme6000_kbdrate (struct kbd_repeat *);
+extern unsigned long bvme6000_gettimeoffset (void);
+extern void bvme6000_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec);
+extern int bvme6000_hwclk (int, struct hwclk_time *);
+extern int bvme6000_set_clock_mmss (unsigned long);
+extern void bvme6000_check_partition (struct gendisk *hd, unsigned int dev);
+extern void bvme6000_mksound( unsigned int count, unsigned int ticks );
+extern void bvme6000_reset (void);
+extern void bvme6000_waitbut(void);
+void bvme6000_set_vectors (void);
+
+static unsigned char bcd2bin (unsigned char b);
+static unsigned char bin2bcd (unsigned char b);
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via bvme6000_process_int() */
+
+static void (*tick_handler)(int, void *, struct pt_regs *);
+
+int bvme6000_kbdrate (struct kbd_repeat *k)
+{
+       return 0;
+}
+
+void bvme6000_mksound( unsigned int count, unsigned int ticks )
+{
+}
+
+void bvme6000_reset()
+{
+       volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
+
+       printk ("\r\n\nCalled bvme6000_reset\r\n"
+                       "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r");
+       /* The string of returns is to delay the reset until the whole
+        * message is output. */
+       /* Enable the watchdog, via PIT port C bit 4 */
+
+       pit->pcddr      |= 0x10;        /* WDOG enable */
+
+       while(1)
+               ;
+}
+
+static void bvme6000_get_model(char *model)
+{
+    /* XXX Need to detect if BVME4000 or BVME6000 */
+    sprintf(model, "BVME6000");
+}
+
+
+/* No hardware options on BVME6000? */
+
+static int bvme6000_get_hardware_list(char *buffer)
+{
+    *buffer = '\0';
+    return 0;
+}
+
+
+__initfunc(void config_bvme6000(void))
+{
+    volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
+
+#if 0
+    /* Call bvme6000_set_vectors() so ABORT will work, along with BVMBug
+     * debugger.  Note trap_init() will splat the abort vector, but
+     * bvme6000_init_IRQ() will put it back again.  Hopefully. */
+
+    bvme6000_set_vectors();
+#endif
+
+    mach_sched_init      = bvme6000_sched_init;
+    mach_keyb_init       = bvme6000_keyb_init;
+    mach_kbdrate         = bvme6000_kbdrate;
+    mach_init_IRQ        = bvme6000_init_IRQ;
+    mach_gettimeoffset   = bvme6000_gettimeoffset;
+    mach_gettod         = bvme6000_gettod;
+    mach_hwclk           = bvme6000_hwclk;
+    mach_set_clock_mmss         = bvme6000_set_clock_mmss;
+/*  mach_mksound         = bvme6000_mksound; */
+    mach_reset          = bvme6000_reset;
+    mach_free_irq       = bvme6000_free_irq;
+    mach_process_int    = bvme6000_process_int;
+    mach_get_irq_list   = bvme6000_get_irq_list;
+    mach_request_irq    = bvme6000_request_irq;
+    enable_irq          = bvme6000_enable_irq;
+    disable_irq          = bvme6000_disable_irq;
+    mach_get_model       = bvme6000_get_model;
+    mach_get_hardware_list = bvme6000_get_hardware_list;
+
+    printk ("Board is %sconfigured as a System Controller\n",
+               *config_reg_ptr & BVME_CONFIG_SW1 ? "" : "not ");
+
+    /* Now do the PIT configuration */
+
+    pit->pgcr  = 0x00; /* Unidirectional 8 bit, no handshake for now */
+    pit->psrr  = 0x18; /* PIACK and PIRQ fucntions enabled */
+    pit->pacr  = 0x00; /* Sub Mode 00, H2 i/p, no DMA */
+    pit->padr  = 0x00; /* Just to be tidy! */
+    pit->paddr = 0x00; /* All inputs for now (safest) */
+    pit->pbcr  = 0x80; /* Sub Mode 1x, H4 i/p, no DMA */
+    pit->pbdr  = 0xbc | (*config_reg_ptr & BVME_CONFIG_SW1 ? 0 : 0x40);
+                       /* PRI, SYSCON?, Level3, SCC clks from xtal */
+    pit->pbddr = 0xf3; /* Mostly outputs */
+    pit->pcdr  = 0x01; /* PA transceiver disabled */
+    pit->pcddr = 0x03; /* WDOG disable */
+}
+
+
+void bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+        unsigned long *new = (unsigned long *)vectors;
+        unsigned long *old = (unsigned long *)0xf8000000;;
+
+        /* Wait for button release */
+       while (*config_reg_ptr & BVME_ABORT_STATUS)
+               ;
+
+        *(new+4) = *(old+4);            /* Illegal instruction */
+        *(new+9) = *(old+9);            /* Trace */
+        *(new+47) = *(old+47);          /* Trap #15 */
+        *(new+0x1f) = *(old+0x1f);      /* ABORT switch */
+}
+
+
+static void bvme6000_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+    volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+    unsigned char msr = rtc->msr & 0xc0;
+
+    rtc->msr = msr | 0x20;             /* Ack the interrupt */
+
+    tick_handler(irq, dev_id, fp);
+}
+
+/*
+ * Set up the RTC timer 1 to mode 2, so T1 output toggles every 5ms
+ * (40000 x 125ns).  It will interrupt every 10ms, when T1 goes low.
+ * So, when reading the elapsed time, you should read timer1,
+ * subtract it from 39999, and then add 40000 if T1 is high.
+ * That gives you the number of 125ns ticks in to the 10ms period,
+ * so divide by 8 to get the microsecond result.
+ */
+
+void bvme6000_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+    volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+    unsigned char msr = rtc->msr & 0xc0;
+
+    rtc->msr = 0;      /* Ensure timer registers accessible */
+
+    tick_handler = timer_routine;
+    if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0,
+                               "timer", bvme6000_timer_int))
+       panic ("Couldn't register timer int");
+
+    rtc->t1cr_omr = 0x04;      /* Mode 2, ext clk */
+    rtc->t1msb = 39999 >> 8;
+    rtc->t1lsb = 39999 & 0xff;
+    rtc->irr_icr1 &= 0xef;     /* Route timer 1 to INTR pin */
+    rtc->msr = 0x40;           /* Access int.cntrl, etc */
+    rtc->pfr_icr0 = 0x80;      /* Just timer 1 ints enabled */
+    rtc->irr_icr1 = 0;
+    rtc->t1cr_omr = 0x0a;      /* INTR+T1 active lo, push-pull */
+    rtc->t0cr_rtmr &= 0xdf;    /* Stop timers in standby */
+    rtc->msr = 0;              /* Access timer 1 control */
+    rtc->t1cr_omr = 0x05;      /* Mode 2, ext clk, GO */
+
+    rtc->msr = msr;
+
+    if (request_irq(BVME_IRQ_ABORT, bvme6000_abort_int, 0,
+                               "abort", bvme6000_abort_int))
+       panic ("Couldn't register abort int");
+}
+
+
+/* This is always executed with interrupts disabled.  */
+
+/*
+ * NOTE:  Don't accept any readings within 5us of rollover, as
+ * the T1INT bit may be a little slow getting set.  There is also
+ * a fault in the chip, meaning that reads may produce invalid
+ * results...
+ */
+
+unsigned long bvme6000_gettimeoffset (void)
+{
+    volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+    volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
+    unsigned char msr = rtc->msr & 0xc0;
+    unsigned char t1int, t1op;
+    unsigned long v = 800000, ov;
+
+    rtc->msr = 0;      /* Ensure timer registers accessible */
+
+    do {
+       ov = v;
+       t1int = rtc->msr & 0x20;
+       t1op  = pit->pcdr & 0x04;
+       rtc->t1cr_omr |= 0x40;          /* Latch timer1 */
+       v = rtc->t1msb << 8;            /* Read timer1 */
+       v |= rtc->t1lsb;                /* Read timer1 */
+    } while (t1int != (rtc->msr & 0x20) ||
+               t1op != (pit->pcdr & 0x04) ||
+                       abs(ov-v) > 80 ||
+                               v > 39960);
+
+    v = 39999 - v;
+    if (!t1op)                         /* If in second half cycle.. */
+       v += 40000;
+    v /= 8;                            /* Convert ticks to microseconds */
+    if (t1int)
+       v += 10000;                     /* Int pending, + 10ms */
+    rtc->msr = msr;
+
+    return v;
+}
+
+extern void bvme6000_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec)
+{
+       volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+       unsigned char msr = rtc->msr & 0xc0;
+
+       rtc->msr = 0;           /* Ensure clock accessible */
+
+       do {    /* Loop until we get a reading with a stable seconds field */
+               *sec = bcd2bin (rtc->bcd_sec);
+               *min = bcd2bin (rtc->bcd_min);
+               *hour = bcd2bin (rtc->bcd_hr);
+               *day = bcd2bin (rtc->bcd_dom);
+               *mon = bcd2bin (rtc->bcd_mth);
+               *year = bcd2bin (rtc->bcd_year);
+       } while (bcd2bin (rtc->bcd_sec) != *sec);
+
+       rtc->msr = msr;
+}
+
+static unsigned char bcd2bin (unsigned char b)
+{
+       return ((b>>4)*10 + (b&15));
+}
+
+static unsigned char bin2bcd (unsigned char b)
+{
+       return (((b/10)*16) + (b%10));
+}
+
+
+/*
+ * Looks like op is non-zero for setting the clock, and zero for
+ * reading the clock.
+ *
+ *  struct hwclk_time {
+ *         unsigned        sec;       0..59
+ *         unsigned        min;       0..59
+ *         unsigned        hour;      0..23
+ *         unsigned        day;       1..31
+ *         unsigned        mon;       0..11
+ *         unsigned        year;      00...
+ *         int             wday;      0..6, 0 is Sunday, -1 means unknown/don't set
+ * };
+ */
+
+int bvme6000_hwclk(int op, struct hwclk_time *t)
+{
+       volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+       unsigned char msr = rtc->msr & 0xc0;
+
+       rtc->msr = 0x40;        /* Ensure clock and real-time-mode-register
+                                * are accessible */
+       if (op)
+       {       /* Write.... */
+               rtc->t0cr_rtmr = t->year%4;
+               rtc->bcd_tenms = 0;
+               rtc->bcd_sec = bin2bcd(t->sec);
+               rtc->bcd_min = bin2bcd(t->min);
+               rtc->bcd_hr  = bin2bcd(t->hour);
+               rtc->bcd_dom = bin2bcd(t->day);
+               rtc->bcd_mth = bin2bcd(t->mon + 1);
+               rtc->bcd_year = bin2bcd(t->year%100);
+               if (t->wday >= 0)
+                       rtc->bcd_dow = bin2bcd(t->wday+1);
+               rtc->t0cr_rtmr = t->year%4 | 0x08;
+       }
+       else
+       {       /* Read....  */
+               do {
+                       t->sec =  bcd2bin(rtc->bcd_sec);
+                       t->min =  bcd2bin(rtc->bcd_min);
+                       t->hour = bcd2bin(rtc->bcd_hr);
+                       t->day =  bcd2bin(rtc->bcd_dom);
+                       t->mon =  bcd2bin(rtc->bcd_mth)-1;
+                       t->year = bcd2bin(rtc->bcd_year);
+                       if (t->year < 70)
+                               t->year += 100;
+                       t->wday = bcd2bin(rtc->bcd_dow)-1;
+               } while (t->sec != bcd2bin(rtc->bcd_sec));
+       }
+
+       rtc->msr = msr;
+
+       return 0;
+}
+
+/*
+ * Set the minutes and seconds from seconds value 'nowtime'.  Fail if
+ * clock is out by > 30 minutes.  Logic lifted from atari code.
+ * Algorithm is to wait for the 10ms register to change, and then to
+ * wait a short while, and then set it.
+ */
+
+int bvme6000_set_clock_mmss (unsigned long nowtime)
+{
+       int retval = 0;
+       short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+       unsigned char rtc_minutes, rtc_tenms;
+       volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+       unsigned char msr = rtc->msr & 0xc0;
+       unsigned long flags;
+       volatile int i;
+
+       rtc->msr = 0;           /* Ensure clock accessible */
+       rtc_minutes = bcd2bin (rtc->bcd_min);
+
+       if ((rtc_minutes < real_minutes
+               ? real_minutes - rtc_minutes
+                       : rtc_minutes - real_minutes) < 30)
+       {
+               save_flags(flags);
+               cli();
+               rtc_tenms = rtc->bcd_tenms;
+               while (rtc_tenms == rtc->bcd_tenms)
+                       ;
+               for (i = 0; i < 1000; i++)
+                       ;
+               rtc->bcd_min = bin2bcd(real_minutes);
+               rtc->bcd_sec = bin2bcd(real_seconds);
+               restore_flags(flags);
+       }
+       else
+               retval = -1;
+
+       rtc->msr = msr;
+
+       return retval;
+}
+
+
+int bvme6000_keyb_init (void)
+{
+       return 0;
+}
+
+/*-------------------  Serial console stuff ------------------------*/
+
+static void bvme_scc_write(struct console *co, const char *str, unsigned cnt);
+
+
+void bvme6000_init_console_port (struct console *co, int cflag)
+{
+        co->write = bvme_scc_write;
+}
+
+
+static void scc_delay (void)
+{
+        int n;
+        char i;
+
+        for (n = 0; n < 20; n++)
+                i = *(volatile char *)0;
+}
+
+static void scc_write (char ch)
+{
+        volatile char *p = (volatile char *)BVME_SCC_A_ADDR;
+
+        do {
+                scc_delay();
+        }
+        while (!(*p & 4));
+        scc_delay();
+        *p = 8;
+        scc_delay();
+        *p = ch;
+}
+
+
+static void bvme_scc_write (struct console *co, const char *str, unsigned count)
+{
+        unsigned long   flags;
+
+        save_flags(flags);
+        cli();
+
+        while (count--)
+        {
+                if (*str == '\n')
+                        scc_write ('\r');
+                scc_write (*str++);
+        }
+        restore_flags(flags);
+}
+
diff --git a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c
new file mode 100644 (file)
index 0000000..ca9f677
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ *     Real Time Clock interface for Linux on the BVME6000
+ *
+ * Based on the PC driver by Paul Gortmaker.
+ */
+
+#define RTC_VERSION            "1.00"
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/mc146818rtc.h> /* For struct rtc_time and ioctls, etc */
+#include <asm/bvme6000hw.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/setup.h>
+
+/*
+ *     We sponge a minor off of the misc major. No need slurping
+ *     up another valuable major dev number for this. If you add
+ *     an ioctl, make sure you don't conflict with SPARC's RTC
+ *     ioctls.
+ */
+
+#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
+
+static unsigned char days_in_mo[] =
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static char rtc_status = 0;
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                    unsigned long arg)
+{
+       volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+       unsigned char msr;
+       unsigned long flags;
+       struct rtc_time wtime; 
+
+       switch (cmd) {
+       case RTC_RD_TIME:       /* Read the time/date from RTC  */
+       {
+               save_flags(flags);
+               cli();
+               /* Ensure clock and real-time-mode-register are accessible */
+               msr = rtc->msr & 0xc0;
+               rtc->msr = 0x40;
+               do {
+                       wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
+                       wtime.tm_min =  BCD2BIN(rtc->bcd_min);
+                       wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
+                       wtime.tm_mday =  BCD2BIN(rtc->bcd_dom);
+                       wtime.tm_mon =  BCD2BIN(rtc->bcd_mth)-1;
+                       wtime.tm_year = BCD2BIN(rtc->bcd_year);
+                       if (wtime.tm_year < 70)
+                               wtime.tm_year += 100;
+                       wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
+               } while (wtime.tm_sec != BCD2BIN(rtc->bcd_sec));
+               rtc->msr = msr;
+               restore_flags(flags);
+               return copy_to_user((void *)arg, &wtime, sizeof wtime) ?
+                                                               -EFAULT : 0;
+       }
+       case RTC_SET_TIME:      /* Set the RTC */
+       {
+               unsigned char leap_yr;
+               struct rtc_time rtc_tm;
+
+               if (!suser())
+                       return -EACCES;
+
+               if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+                                  sizeof(struct rtc_time)))
+                       return -EFAULT;
+
+               leap_yr = ((!(rtc_tm.tm_year % 4) && (rtc_tm.tm_year % 100)) || !(rtc_tm.tm_year % 400));
+
+               if ((rtc_tm.tm_mon > 12) || (rtc_tm.tm_mday == 0))
+                       return -EINVAL;
+
+               if (rtc_tm.tm_mday > (days_in_mo[rtc_tm.tm_mon] + ((rtc_tm.tm_mon == 2) && leap_yr)))
+                       return -EINVAL;
+                       
+               if ((rtc_tm.tm_hour >= 24) || (rtc_tm.tm_min >= 60) || (rtc_tm.tm_sec >= 60))
+                       return -EINVAL;
+
+               save_flags(flags);
+               cli();
+               /* Ensure clock and real-time-mode-register are accessible */
+               msr = rtc->msr & 0xc0;
+               rtc->msr = 0x40;
+
+               rtc->t0cr_rtmr = rtc_tm.tm_year%4;
+               rtc->bcd_tenms = 0;
+               rtc->bcd_sec = BIN2BCD(rtc_tm.tm_sec);
+               rtc->bcd_min = BIN2BCD(rtc_tm.tm_min);
+               rtc->bcd_hr  = BIN2BCD(rtc_tm.tm_hour);
+               rtc->bcd_dom = BIN2BCD(rtc_tm.tm_mday);
+               rtc->bcd_mth = BIN2BCD(rtc_tm.tm_mon + 1);
+               rtc->bcd_year = BIN2BCD(rtc_tm.tm_year%100);
+               if (rtc_tm.tm_wday >= 0)
+                       rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
+               rtc->t0cr_rtmr = rtc_tm.tm_year%4 | 0x08;
+
+               rtc->msr = msr;
+               restore_flags(flags);
+               return 0;
+       }
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ *     We enforce only one user at a time here with the open/close.
+ *     Also clear the previous interrupt data on an open, and clean
+ *     up things on a close.
+ */
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+       if(rtc_status)
+               return -EBUSY;
+
+       rtc_status = 1;
+       return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+       rtc_status = 0;
+       return 0;
+}
+
+/*
+ *     The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+       NULL,
+       NULL,
+       NULL,           /* No write */
+       NULL,           /* No readdir */
+       NULL,
+       rtc_ioctl,
+       NULL,           /* No mmap */
+       rtc_open,
+       rtc_release
+};
+
+static struct miscdevice rtc_dev=
+{
+       RTC_MINOR,
+       "rtc",
+       &rtc_fops
+};
+
+__initfunc(int rtc_DP8570A_init(void))
+{
+       if (!MACH_IS_BVME6000)
+               return -ENODEV;
+
+       printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION);
+       misc_register(&rtc_dev);
+       return 0;
+}
+
index d1ffcb62fc4b678432684bc3c5972aa82c5291fb..a701cd83a5398437c6cea7914f5994c08dcc2ae5 100644 (file)
@@ -19,7 +19,7 @@ fi
 endmenu
 
 mainmenu_option next_comment
-comment 'Platform-dependent setup'
+comment 'Platform dependent setup'
 
 bool 'Amiga support' CONFIG_AMIGA
 bool 'Atari support' CONFIG_ATARI
@@ -30,13 +30,19 @@ if [ "$CONFIG_ATARI" = "y" ]; then
   fi  
 fi
 bool 'Macintosh support' CONFIG_MAC
+if [ "$CONFIG_MAC" = "y" ]; then
+  define_bool CONFIG_NUBUS y
+fi
 bool 'Apollo support' CONFIG_APOLLO
 bool 'VME (Motorola and BVM) support' CONFIG_VME
 if [ "$CONFIG_VME" = "y" ]; then
   bool 'MVME162, 166 and 167 support' CONFIG_MVME16x
-# bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
+  bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
+fi
+bool 'HP9000/300 support' CONFIG_HP300
+if [ "$CONFIG_HP300" = "y" ]; then
+  bool 'DIO bus support' CONFIG_DIO
 fi
-
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
 fi
@@ -57,6 +63,7 @@ fi
 bool 'Advanced processor options' CONFIG_ADVANCED_CPU
 if [ "$CONFIG_ADVANCED_CPU" = "y" ]; then
   bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
+  bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH
 fi
 endmenu
 
@@ -73,11 +80,6 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
 if [ "$CONFIG_AMIGA" = "y" ]; then
   bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
-#  bool 'Amiga GSP (TMS340x0) support' CONFIG_AMIGA_GSP
-#  if [ "$CONFIG_AMIGA_GSP" = "y" ]; then
-#    bool 'DMI Resolver support' CONFIG_GSP_RESOLVER
-#    bool 'A2410 support' CONFIG_GSP_A2410
-#  fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP
@@ -85,73 +87,17 @@ if [ "$CONFIG_ATARI" = "y" ]; then
 fi
 if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
   bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
-fi
-endmenu
-
-#
-# Block device driver configuration
-#
-mainmenu_option next_comment
-comment 'Floppy, IDE, and other block devices'
-
-if [ "$CONFIG_AMIGA" = "y" ]; then
-  tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
-fi
-if [ "$CONFIG_ATARI" = "y" ]; then
-  tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
-fi
-if [ "$CONFIG_MAC" = "y" ]; then
-  tristate 'Macintosh IWM floppy support' CONFIG_MAC_FLOPPY
-fi
-#Normal floppy disk support' CONFIG_BLK_DEV_FD
-
-tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
-if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
-  dep_tristate '   Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
-  dep_tristate '   Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
-  dep_tristate '   Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
-  dep_tristate '   Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
-  dep_tristate '   SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
-  if [ "$CONFIG_AMIGA" = "y" ]; then
-    bool '   Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      bool '   Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA
-      bool '   Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE
-    fi
-  fi
-  if [ "$CONFIG_ATARI" = "y" ]; then
-    bool '   Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE
-  fi
-fi
-if [ "$CONFIG_AMIGA" = "y" ]; then
-  tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
-fi
-if [ "$CONFIG_ATARI" = "y" ]; then
-  tristate 'Atari ACSI support' CONFIG_ATARI_ACSI
-  if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
-    comment 'Some devices (e.g. CD jukebox) support multiple LUNs'
-    bool 'Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN
-    dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI
+else
+  if [ "$CONFIG_HP300" = "y" ]; then
+# We have a dedicated heartbeat LED. :-)
+  define_bool CONFIG_HEARTBEAT y
   fi
 fi
-
-comment 'Additional Block Devices'
-
-tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
-if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
-  tristate '   Linear (append) mode' CONFIG_MD_LINEAR
-  tristate '   RAID-0 (striping) mode' CONFIG_MD_STRIPED
-fi
-if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
-  bool '      Boot support (linear, striped)' CONFIG_MD_BOOT
-fi
-tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
-if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
-  bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
-fi
+bool '/proc/hardware support' CONFIG_PROC_HARDWARE
 endmenu
 
+source drivers/block/Config.in
+
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
 fi
@@ -196,15 +142,21 @@ if [ "$CONFIG_AMIGA" = "y" ]; then
     bool 'A4000T SCSI support' CONFIG_A4000T_SCSI
     bool 'A4091 SCSI support' CONFIG_A4091_SCSI
     bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
-    bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
+#    bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
 #    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
   fi
+  if [ "$CONFIG_MAC" = "y" ]; then
+    bool '   Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE
+  fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI
-  bool 'Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY
-  if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then
-    bool 'Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL
+  if [ "$CONFIG_ATARI_SCSI" != "n" ]; then
+    bool '  Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+    bool '  Reset SCSI-devices at boottime' CONFIG_ATARI_SCSI_RESET_BOOT
+    if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then
+      bool '  Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL
+    fi
   fi
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
@@ -216,6 +168,10 @@ if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
   bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI
 fi
 
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
+  bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI
+fi
+
 endmenu
 
 fi
@@ -264,6 +220,9 @@ fi
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
   bool 'MVME16x Ethernet support' CONFIG_APRICOT
 fi
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
+  bool 'BVME6000 Ethernet support' CONFIG_APRICOT
+fi
 fi
 endmenu
 
@@ -322,20 +281,31 @@ if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
   bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
 fi
-if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
+if [ "$CONFIG_MAC" = "y" ]; then
+  bool 'Mac SCC serial support' CONFIG_MAC_SCC
+fi
+if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
+  tristate 'HP DCA serial support' CONFIG_HPDCA
+fi
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
+     "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" ]; then
   if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
-       "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
-       "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then
+       "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
+       "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
+       "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
+       "$CONFIG_HPDCA" = "y" ]; then
     bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
   fi
 fi
-if [ "$CONFIG_MAC" = "y" ]; then
-  bool 'Mac SCC serial support' CONFIG_MAC_SCC
-fi
 if [ "$CONFIG_VME" = "y" ]; then
   define_bool CONFIG_SERIAL_CONSOLE y
-  bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
-  bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
+  if [ "$CONFIG_MVME16x" = "y" ]; then
+    bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
+    bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
+  fi
+  if [ "$CONFIG_BVME6000" = "y" ]; then
+    bool 'SCC support for BVME6000 serial ports' CONFIG_BVME6000_SCC
+  fi
 fi
 if [ "$CONFIG_APOLLO" = "y" ]; then
   bool 'Support for DN serial port (dummy)' CONFIG_SERIAL
@@ -348,7 +318,7 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
   bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
 fi
 bool 'Support for user misc device modules' CONFIG_UMISC
-if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o "$CONFIG_MAC" = "y" ]; then
   define_bool CONFIG_ABSTRACT_CONSOLE y
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
index 6ce3991d4e3d5ae4ceb3486f749794ad53e1116a..37b86525cb1f05b01f595c644b143366ee025a0c 100644 (file)
@@ -45,6 +45,8 @@ CONFIG_ZORRO=y
 # CONFIG_AMIGA_GSP is not set
 # CONFIG_GSP_RESOLVER is not set
 # CONFIG_GSP_A2410 is not set
+# CONFIG_HEARTBEAT is not set
+CONFIG_PROC_HARDWARE=y
 
 #
 # Block device driver configuration
@@ -133,6 +135,8 @@ CONFIG_GVP11_SCSI=y
 # CONFIG_A4091_SCSI is not set
 # CONFIG_WARPENGINE_SCSI is not set
 CONFIG_ATARI_SCSI=y
+# CONFIG_ATARI_SCSI_TOSHIBA_DELAY is not set
+# CONFIG_ATARI_SCSI_RESET_BOOT is not set
 
 #
 # Network device support
diff --git a/arch/m68k/hp300/Makefile b/arch/m68k/hp300/Makefile
new file mode 100644 (file)
index 0000000..a59cede
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for Linux arch/m68k/hp300 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := hp300.o
+O_OBJS  := ksyms.o config.o ints.o time.o reboot.o hil.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/hp300/README.hp300 b/arch/m68k/hp300/README.hp300
new file mode 100644 (file)
index 0000000..47073fb
--- /dev/null
@@ -0,0 +1,14 @@
+HP300 notes
+-----------
+
+The Linux/HP web page is at <http://www.tazenda.demon.co.uk/phil/linux-hp/>
+
+Currently only 9000/340 machines have been tested.  Any amount of RAM should
+work now but I've only tried 16MB and 12MB.
+
+The serial console is probably broken at the moment but the Topcat/HIL keyboard
+combination seems to work for me.  Your mileage may vary.
+
+The LANCE driver works after a fashion but only if you reset the chip before
+every packet.  This doesn't make for very speedy operation.
+
diff --git a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c
new file mode 100644 (file)
index 0000000..8cebc47
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  linux/arch/m68k/hp300/config.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  This file contains the HP300-specific initialisation code.  It gets
+ *  called by setup.c.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <asm/machdep.h>
+#include <asm/blinken.h>
+#include <asm/io.h>                               /* readb() and writeb() */
+#include <asm/hwtest.h>                           /* hwreg_present() */
+
+#include "ints.h"
+#include "time.h"
+
+extern void hp300_reset(void);
+extern void hp300_hil_init(void);
+
+#ifdef CONFIG_HEARTBEAT
+static void hp300_pulse(int x)
+{
+   if (x)
+      blinken_leds(0xfe);
+   else
+      blinken_leds(0xff);
+}
+#endif
+
+static int hp300_kbdrate(struct kbd_repeat *k)
+{
+  return 0;
+}
+
+static void hp300_kbd_leds(unsigned int leds)
+{
+}
+
+__initfunc(void config_hp300(void))
+{
+  mach_sched_init      = hp300_sched_init;
+  mach_keyb_init       = hp300_hil_init;
+  mach_kbdrate         = hp300_kbdrate;
+  mach_kbd_leds        = hp300_kbd_leds;
+  mach_init_IRQ        = hp300_init_IRQ;
+  mach_request_irq     = hp300_request_irq;
+  mach_free_irq        = hp300_free_irq;
+#if 0
+  mach_get_model       = hp300_get_model;
+  mach_get_irq_list    = hp300_get_irq_list;
+#endif
+  mach_gettimeoffset   = hp300_gettimeoffset;
+#if 0
+  mach_gettod          = hp300_gettod;
+#endif
+  mach_reset           = hp300_reset;
+#ifdef CONFIG_HEARTBEAT
+  mach_heartbeat       = hp300_pulse;
+#endif
+#ifdef CONFIG_FB
+  conswitchp          = &fb_con;
+#endif
+  mach_max_dma_address = 0xffffffff;
+}
+
+/* for "kbd-reset" cmdline param */
+__initfunc(void kbd_reset_setup(char *str, int *ints))
+{
+}
diff --git a/arch/m68k/hp300/hil.c b/arch/m68k/hp300/hil.c
new file mode 100644 (file)
index 0000000..76d45b4
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ *  linux/arch/m68k/hp300/hil.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  HP300 Human Interface Loop driver.  This handles the keyboard and mouse.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/keyboard.h>
+#include <linux/kbd_ll.h>
+#include <asm/io.h>
+#include <asm/hwtest.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#define HILBASE                        0xf0428000
+#define HIL_DATA                       0x1
+#define HIL_CMD                        0x3
+
+#define        HIL_BUSY                0x02
+#define        HIL_DATA_RDY            0x01
+
+#define hil_busy()             (readb(HILBASE + HIL_CMD) & HIL_BUSY)
+#define hil_data_available()   (readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
+#define hil_status()           (readb(HILBASE + HIL_CMD))
+#define hil_command(x)         do { writeb((x), HILBASE + HIL_CMD); } while (0)
+#define hil_read_data()                (readb(HILBASE + HIL_DATA))
+#define hil_write_data(x)      do { writeb((x), HILBASE + HIL_DATA); } while (0)
+
+#define        HIL_SETARD              0xA0            /* set auto-repeat delay */
+#define        HIL_SETARR              0xA2            /* set auto-repeat rate */
+#define        HIL_SETTONE             0xA3            /* set tone generator */
+#define        HIL_CNMT                0xB2            /* clear nmi */
+#define        HIL_INTON               0x5C            /* Turn on interrupts. */
+#define        HIL_INTOFF              0x5D            /* Turn off interrupts. */
+#define        HIL_TRIGGER             0xC5            /* trigger command */
+#define        HIL_STARTCMD            0xE0            /* start loop command */
+#define        HIL_TIMEOUT             0xFE            /* timeout */
+#define        HIL_READTIME            0x13            /* Read real time register */
+
+#define        HIL_READBUSY            0x02            /* internal "busy" register */
+#define        HIL_READKBDLANG         0x12            /* read keyboard language code */
+#define        HIL_READKBDSADR         0xF9
+#define        HIL_WRITEKBDSADR        0xE9
+#define        HIL_READLPSTAT          0xFA
+#define        HIL_WRITELPSTAT         0xEA
+#define        HIL_READLPCTRL          0xFB
+#define        HIL_WRITELPCTRL         0xEB
+
+#define HIL_IRQ                        1
+
+static u_short hp_plain_map[NR_KEYS] __initdata = {
+       0xf200, 0xf01b, 0xf20e, 0xf700, 0xf700, 0xf700, 0xf702, 0xf036,
+       0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
+       0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+       0xfb62, 0xfb76, 0xf063, 0xfb78, 0xfb7a, 0xf702, 0xfb61, 0xfb73,
+       0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+       0xfb68, 0xfb67, 0xfb66, 0xfb64, 0xfb73, 0xfb61, 0xfb63, 0xfb76,
+       0xfb75, 0xfb79, 0xfb74, 0xfb72, 0xfb65, 0xfb77, 0xfb71, 0xf200,
+       0xf037, 0xf036, 0xf035, 0xf034, 0xf033, 0xf032, 0xf031, 0xf104,
+       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+       0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+       0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf038, 0xf039, 0xf030, 0xf200, 0xf200, 0xf008, 0xf200, 0xf200,
+       0xfb69, 0xfb6f, 0xfb70, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+       0xfb6a, 0xfb6b, 0xfb6c, 0xf305, 0xf306, 0xf00d, 0xf302, 0xf303,
+       0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xfb6e, 0xf020, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short hp_shift_map[NR_KEYS] __initdata = {
+       0xf200, 0xf01b, 0xf20e, 0xf700, 0xf700, 0xf700, 0xf002, 0xf036,
+       0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
+       0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+       0xfb62, 0xfb76, 0xf063, 0xfb78, 0xfb7a, 0xf702, 0xfb61, 0xfb73,
+       0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+       0xfb68, 0xfb67, 0xfb66, 0xfb64, 0xfb73, 0xfb61, 0xfb63, 0xfb76,
+       0xfb75, 0xfb79, 0xfb74, 0xfb72, 0xfb65, 0xfb77, 0xfb71, 0xf200,
+       0xf037, 0xf036, 0xf035, 0xf034, 0xf033, 0xf032, 0xf031, 0xf104,
+       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+       0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+       0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf038, 0xf039, 0xf030, 0xf200, 0xf200, 0xf008, 0xf200, 0xf200,
+       0xfb69, 0xfb6f, 0xfb70, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+       0xfb6a, 0xfb6b, 0xfb6c, 0xf305, 0xf306, 0xf00d, 0xf302, 0xf303,
+       0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xfb6e, 0xf020, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short hp_ctrl_map[NR_KEYS] __initdata = {
+       0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
+       0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
+       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+       0xf00f, 0xf010, 0xf003, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
+       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+       0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xf200,
+       0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+       0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+       0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf1ff, 0xf202, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+       0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+       0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+struct {
+  unsigned char s, c;
+  int valid;
+} hil_last;
+
+#define hil_getlast(s,c)  do { s = hil_last.s; c = hil_last.c; hil_last.valid = 0; } while (0)
+
+struct {
+  unsigned char data[16];
+  unsigned int ptr;
+} poll;
+
+unsigned char curdev = 0;
+
+static void poll_finished(void)
+{
+  switch (poll.data[0])
+  {
+  case 0x40:
+    {
+      unsigned char scode = (poll.data[1] >> 1) | ((poll.data[1] & 1)?0x80:0);
+#if 0
+      if (scode & 0x80)
+       printk("[%02x]", scode & 0x7f);
+#endif
+      handle_scancode(scode);
+    }
+    break;
+  }
+  curdev = 0;
+}
+
+static inline void handle_status(unsigned char s, unsigned char c)
+{
+  if (c & 0x8) {
+    /* End of block */
+    if (c & 0x10)
+      poll_finished();
+  } else {
+    if (c & 0x10) {
+      if (curdev)
+       poll_finished();                /* just in case */
+      curdev = c & 7;
+      poll.ptr = 0;
+    }
+  }
+}
+
+static inline void handle_data(unsigned char s, unsigned char c)
+{
+  if (curdev)
+    poll.data[poll.ptr++] = c;
+}
+
+/* 
+ * Handle HIL interrupts.
+ */
+
+static void hil_interrupt(int irq, void *handle, struct pt_regs *regs)
+{
+  unsigned char s, c;
+  s = hil_status(); c = hil_read_data();
+  switch (s >> 4)
+  {
+  case 0x5:
+    handle_status(s, c);
+    break;
+  case 0x6:
+    handle_data(s, c);
+    break;
+  case 0x4:
+    hil_last.s = s;
+    hil_last.c = c;
+    mb();
+    hil_last.valid = 1;
+    break;
+  }
+}
+
+/*
+ * Send a command to the HIL
+ */
+
+static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
+{
+  unsigned long flags;
+  save_flags(flags); cli();
+  while (hil_busy());
+  hil_command(cmd);
+  while (len--) {
+    while (hil_busy());
+    hil_write_data(*(data++));
+  }
+  restore_flags(flags);
+}
+
+/*
+ * Initialise HIL. 
+ */
+
+__initfunc(void hp300_hil_init(void))
+{
+  unsigned char s, c, kbid;
+  unsigned int n = 0;
+
+  memcpy(key_maps[0], hp_plain_map, sizeof(plain_map));
+  memcpy(key_maps[1], hp_shift_map, sizeof(plain_map));
+  memcpy(key_maps[4], hp_ctrl_map, sizeof(plain_map));
+
+  if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
+    return;            /* maybe this can happen */
+
+  request_irq(HIL_IRQ, hil_interrupt, 0, "HIL", NULL);
+
+  /* Turn on interrupts */
+  hil_do(HIL_INTON, NULL, 0);
+
+  /* Look for keyboards */
+  hil_do(HIL_READKBDSADR, NULL, 0);
+  while (!hil_last.valid) {
+    if (n++ > 1000) {
+      printk("HIL: timed out, assuming no keyboard present.\n");
+      return;
+    }
+    mb();
+  }
+  hil_getlast(s, c);
+  if (c == 0) {
+    printk("HIL: no keyboard present.\n");
+    return;
+  }
+  for (kbid = 0; (kbid < 8) && ((c & (1<<kbid)) == 0); kbid++);
+  printk("HIL: keyboard found at id %d\n", kbid);
+  /* set it to raw mode */
+  c = 0;
+  hil_do(HIL_WRITEKBDSADR, &c, 1);
+}
diff --git a/arch/m68k/hp300/ints.c b/arch/m68k/hp300/ints.c
new file mode 100644 (file)
index 0000000..59a605d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  linux/arch/m68k/hp300/ints.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  This file contains the HP300-specific interrupt handling.  There
+ *  isn't much here -- we only use the autovector interrupts and at the
+ *  moment everything difficult is handled by the generic code.
+ */
+
+#include <linux/config.h>
+#include <asm/ptrace.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include "ints.h"
+
+static void hp300_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
+{
+  extern void hp300_reset(void);
+  printk("RESET pressed - self destruct sequence initiated.\n");
+  hp300_reset();
+}
+
+int hp300_request_irq(unsigned int irq,
+               void (*handler) (int, void *, struct pt_regs *),
+               unsigned long flags, const char *devname, void *dev_id)
+{
+  return sys_request_irq(irq, handler, flags, devname, dev_id);
+}
+
+void hp300_free_irq(unsigned int irq, void *dev_id)
+{
+  sys_free_irq(irq, dev_id);
+}
+
+__initfunc(void hp300_init_IRQ(void))
+{
+  /* IPL6 - NMI (keyboard reset) */
+  sys_request_irq(7, hp300_nmi_handler, IRQ_FLG_STD, "NMI", hp300_nmi_handler);
+}
diff --git a/arch/m68k/hp300/ints.h b/arch/m68k/hp300/ints.h
new file mode 100644 (file)
index 0000000..38b62b6
--- /dev/null
@@ -0,0 +1,6 @@
+extern void hp300_init_IRQ(void);
+extern void (*hp300_handlers[8])(int, void *, struct pt_regs *);
+extern void hp300_free_irq(unsigned int irq, void *dev_id);
+extern int hp300_request_irq(unsigned int irq,
+               void (*handler) (int, void *, struct pt_regs *),
+               unsigned long flags, const char *devname, void *dev_id);
diff --git a/arch/m68k/hp300/ksyms.c b/arch/m68k/hp300/ksyms.c
new file mode 100644 (file)
index 0000000..8202830
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ *  linux/arch/m68k/hp300/ksyms.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  This file contains the HP300-specific kernel symbols.  None yet. :-)
+ */
+
+#include <linux/module.h>
diff --git a/arch/m68k/hp300/reboot.S b/arch/m68k/hp300/reboot.S
new file mode 100644 (file)
index 0000000..aaecdbd
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  linux/arch/m68k/hp300/reboot.S
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  Do the dirty work of rebooting the machine.  Basically we need to undo all the
+ *  good stuff that head.S did when we started up.  The caches and MMU must be
+ *  disabled and then we jump back to the PROM.  This is a bit gruesome but we put
+ *  a brave face on it.
+ */
+
+/* XXX Doesn't work yet.  Not sure why and can't be bothered to fix it at the moment. */
+
+       .globl  hp300_reset
+hp300_reset:
+       .chip   68030
+       oriw    #0x0700,%sr                     /* cli() */
+       movel   hp300_phys_ram_base, %d1
+       movel   #0, %d0
+       movec   %d0, %vbr                       /* reset vector table */
+       lea     zero, %a0
+       lea     1f, %a1
+       add     %d1, %a0
+       add     %d1, %a1
+       pmove   %tc, %a0@
+       bclr    #7, %a0@
+       pmove   %a0@, %tc                       /* goodbye MMU */
+       jmp     %a1@
+1:     movel   #0x808, %d0
+       movec   %d0, %cacr                      /* cache off */
+       moveb   #0, 0x1ffff
+       movel   #0x1a4, %a0
+       jmp     %a0@
+
+zero:  .quad   0
diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c
new file mode 100644 (file)
index 0000000..d854a46
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  linux/arch/m68k/hp300/time.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ *  This file contains the HP300-specific time handling code.
+ */
+
+#include <linux/config.h>
+#include <asm/ptrace.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include "ints.h"
+
+/* Clock hardware definitions */
+
+#define CLOCKBASE      0xf05f8000
+
+#define        CLKCR1          0x1
+#define        CLKCR2          0x3
+#define        CLKCR3          CLKCR1
+#define        CLKSR           CLKCR2
+#define        CLKMSB1         0x5
+#define        CLKMSB2         0x9
+#define        CLKMSB3         0xD
+
+unsigned long hp300_gettimeoffset (void)
+{
+       return 0L;
+}
+
+static void hp300_tick(int irq, void *dev_id, struct pt_regs *regs)
+{
+  unsigned long tmp;
+  void (*vector)(int, void *, struct pt_regs *) = dev_id;
+  readb(CLOCKBASE + CLKSR);
+  asm volatile ("movpw %1@(5),%0" : "=r" (tmp) : "a" (CLOCKBASE));
+  vector(irq, NULL, regs);
+}
+
+__initfunc(void hp300_sched_init(void (*vector)(int, void *, struct pt_regs *)))
+{
+  unsigned int intval = (10000 / 4) - 1;
+
+  writeb(0x1, CLOCKBASE + CLKCR2);             /* select CR1 */
+  writeb(0x1, CLOCKBASE + CLKCR1);             /* reset */
+
+  asm volatile(" movpw %0,%1@(5)" : : "d" (intval), "a" (CLOCKBASE));
+
+  sys_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
+
+  writeb(0x1, CLOCKBASE + CLKCR2);             /* select CR1 */
+  writeb(0x40, CLOCKBASE + CLKCR1);            /* enable irq */
+}
+
diff --git a/arch/m68k/hp300/time.h b/arch/m68k/hp300/time.h
new file mode 100644 (file)
index 0000000..a081903
--- /dev/null
@@ -0,0 +1,4 @@
+extern void hp300_sched_init(void (*vector)(int, void *, struct pt_regs *));
+extern unsigned long hp300_gettimeoffset (void);
+
+
index a1dc77f33303ecdafa07cd1ccdef02e902ece5be..219a89079c54bafa1c52ef182f7db886e5573830 100644 (file)
@@ -33,7 +33,6 @@
  *    been removed in this version.
  */
 
-#include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/malloc.h>
 #include <linux/mm.h>
@@ -49,7 +48,7 @@
 #define GB             (1024*MB)
 
 #define MAJOR_REV      0
-#define MINOR_REV      0
+#define MINOR_REV      1
 
 /*
  * Base addresses of the PCI memory and I/O areas on the Hades.
@@ -264,12 +263,14 @@ __initfunc(static void disable_dev(struct pci_dev *dev))
 
 #define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2)
 
-__initfunc(static void layout_dev(struct pci_dev *dev))
+__initfunc(static void layout_dev(struct pci_dev *dev, unsigned long pci_mem_base,
+                                                                 unsigned long pci_io_base))
 {
        struct pci_bus *bus;
        unsigned short cmd;
        unsigned int base, mask, size, reg;
        unsigned int alignto;
+       int i;
 
        /*
         * Skip video cards for the time being.
@@ -283,7 +284,7 @@ __initfunc(static void layout_dev(struct pci_dev *dev))
        bus = dev->bus;
        pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
 
-       for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4)
+       for (reg = PCI_BASE_ADDRESS_0, i = 0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++)
        {
                /*
                 * Figure out how much space and of what type this
@@ -297,6 +298,7 @@ __initfunc(static void layout_dev(struct pci_dev *dev))
                if (!base)
                {
                        /* this base-address register is unused */
+                       dev->base_address[i] = 0;
                        continue;
                }
 
@@ -322,6 +324,7 @@ __initfunc(static void layout_dev(struct pci_dev *dev))
                        io_base = base + size;
                        pcibios_write_config_dword(bus->number, dev->devfn,
                                                   reg, base | 0x1);
+                       dev->base_address[i] = (pci_io_base + base) | 1;
                        DBG_DEVS(("layout_dev: IO address: %lX\n", base));
                }
                else
@@ -369,6 +372,7 @@ __initfunc(static void layout_dev(struct pci_dev *dev))
                        mem_base = base + size;
                        pcibios_write_config_dword(bus->number, dev->devfn,
                                                   reg, base);
+                       dev->base_address[i] = pci_mem_base + base;
                }
        }
 
@@ -396,7 +400,8 @@ __initfunc(static void layout_dev(struct pci_dev *dev))
                  bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
 }
 
-__initfunc(static void layout_bus(struct pci_bus *bus))
+__initfunc(static void layout_bus(struct pci_bus *bus, unsigned long pci_mem_base,
+                                                                 unsigned long pci_io_base))
 {
        struct pci_dev *dev;
 
@@ -438,7 +443,7 @@ __initfunc(static void layout_bus(struct pci_bus *bus))
        for (dev = bus->devices; dev; dev = dev->sibling)
        {
                if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
-                       layout_dev(dev);
+                       layout_dev(dev, pci_mem_base, pci_io_base);
        }
 }
 
@@ -507,8 +512,7 @@ int pcibios_present(void)
                return 0;
 }
 
-__initfunc(unsigned long pcibios_init(unsigned long mem_start,
-                                     unsigned long mem_end))
+__initfunc(void pcibios_init(void))
 {
        printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
 
@@ -516,7 +520,8 @@ __initfunc(unsigned long pcibios_init(unsigned long mem_start,
        printk("...NOT modifying existing PCI configuration\n");
 #endif
 
-       return mem_start;
+       pci_mem_base = 0x80000000;
+       pci_io_base = 0xB0000000;
 }
 
 /*
@@ -555,26 +560,35 @@ __initfunc(static inline void hades_fixup(void))
        }
 }
 
-__initfunc(unsigned long pcibios_fixup(unsigned long mem_start,
-                                      unsigned long mem_end))
+__initfunc(void pcibios_fixup(void))
 {
 #if PCI_MODIFY
+       unsigned long orig_mem_base, orig_io_base;
+
+       orig_mem_base = pci_mem_base;
+       orig_io_base = pci_io_base;
+       pci_mem_base = 0;
+       pci_io_base = 0;
+
        /*
         * Scan the tree, allocating PCI memory and I/O space.
         */
 
-       layout_bus(&pci_root);
-#endif
+       layout_bus(&pci_root, orig_mem_base, orig_io_base);
 
-       pci_mem_base = 0x80000000;
-       pci_io_base = 0xB0000000;
+       pci_mem_base = orig_mem_base;
+       pci_io_base = orig_io_base;
+#endif
 
        /*
         * Now is the time to do all those dirty little deeds...
         */
 
        hades_fixup();
+}
 
-       return mem_start;
+__initfunc(char *pcibios_setup(char *str))
+{
+       return str;
 }
 #endif /* CONFIG_PCI */
index 1c157c26ac00c2295ab68d8fd1c8bc30bf2d1d04..3f9e9450ecdf3d922b1d2a31369f240294a0d994 100644 (file)
@@ -579,6 +579,9 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_pread)            /* 180 */
        .long SYMBOL_NAME(sys_pwrite)
        .long SYMBOL_NAME(sys_lchown);
+       .long SYMBOL_NAME(sys_getcwd)
+       .long SYMBOL_NAME(sys_capget)
+       .long SYMBOL_NAME(sys_capset)           /* 185 */
        .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
                .long SYMBOL_NAME(sys_ni_syscall)
        .endr
index 1f3795a7c7ce37fd9c343ba5abb4df2db8ac8c50..e98f39fa86e61ca872bede17de9b3ed6c440d3f0 100644 (file)
@@ -17,6 +17,7 @@
 ** 95/11/18 Richard Hirst: Added MVME166 support
 ** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
 **                           Magnum- and FX-alternate ram
+** 98/04/25 Phil Blundell: added HP300 support
 **
 ** This file is subject to the terms and conditions of the GNU General Public
 ** License. See the file README.legal in the main directory of this archive
 #include <asm/pgtable.h>
 
 .globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
-.globl SYMBOL_NAME(availmem), SYMBOL_NAME(mvme_bdid_ptr)
+.globl SYMBOL_NAME(availmem)
 .globl SYMBOL_NAME(m68k_pgtable_cachemode)
 .globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
 
+#if defined(CONFIG_MVME16x)
+.globl SYMBOL_NAME(mvme_bdid_ptr)
+#endif
+
+/*
+ * Added m68k_supervisor_cachemode for 68060 boards where some drivers
+ * need writethrough caching for supervisor accesses.  Drivers known to
+ * be effected are 53c7xx.c and apricot.c (when used on VME boards).
+ * Richard Hirst.
+ */
+
+#ifdef CONFIG_060_WRITETHROUGH
+.globl SYMBOL_NAME(m68k_supervisor_cachemode)
+#endif
+
 D6B_0460 = 16          /* indicates 680[46]0 in d6 */
 D6B_060  = 17          /* indicates 68060 in d6 */
 D6F_040  = 1<<D6B_0460
@@ -146,12 +162,23 @@ TABLENR_16MB      = 64    /* same for 16 MB */
 #define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab
 #define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab
 #define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab
+#define is_not_bvme6000(lab) moveq &MACH_BVME6000,%d7; cmpl %d4,%d7; jne lab
+#define is_not_hp300(lab) moveq &MACH_HP300,%d7        ;  cmpl %d4,%d7; jne lab
 
 #define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab
 #define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab
 #define is_060(lab) btst &D6B_060,%d6; jne lab
 #define is_not_060(lab) btst &D6B_060,%d6; jeq lab
 
+/* On the HP300 we use the on-board LEDs for debug output before
+   the console is running.  Writing a 1 bit turns the corresponding LED
+   _off_ - on the 340 bit 7 is towards the back panel of the machine.  */
+#ifdef CONFIG_HP300
+#define leds(x) is_not_hp300(42f) ; moveb #(x),%d7 ; jbsr Lset_leds; 42:
+#else
+#define leds(x)
+#endif
+
 .text
 ENTRY(_stext)
 /*
@@ -164,6 +191,7 @@ ENTRY(_stext)
        .long   MACH_AMIGA, AMIGA_BOOTI_VERSION
        .long   MACH_ATARI, ATARI_BOOTI_VERSION
        .long   MACH_MVME16x, MVME16x_BOOTI_VERSION
+       .long   MACH_BVME6000, BVME6000_BOOTI_VERSION
        .long   0
 1:     jra     SYMBOL_NAME(_start)
 
@@ -224,6 +252,22 @@ ENTRY(_start)
        movew   %d6,%d0
        movel   %d0,%a0@                /* save cache mode for page tables */
 
+       /*
+        * If this is a 68060 board using drivers with cache coherency
+        * problems, then supervisor memory accesses need to be write-through
+         * also; otherwise, we want copyback.
+        */
+
+#if defined(CONFIG_060_WRITETHROUGH)
+       is_not_060(Lset_norm)
+       jra     1f
+Lset_norm:
+       move.w  #_PAGE_CACHE040,%d0
+1:
+       lea     %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0
+       movel   %d0,%a0@
+#endif
+
 /*
  * raise interrupt level
  */
@@ -386,7 +430,12 @@ Lnotypetest:
 
        movel   %a3,%a0
        movel   %d5,%a1
-       addw    #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+#if defined(CONFIG_060_WRITETHROUGH)
+       addw    #_PAGE_GLOBAL040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+       addl    m68k_supervisor_cachemode,%a1
+#else
+       addw    #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+#endif
        movew   #(PAGE_TABLE_SIZE*TABLENR_4MB)-1,%d1
        movel   #PAGESIZE,%d2
 1:     movel   %a1,%a0@+
@@ -424,6 +473,9 @@ Lnotypetest:
         * of %a2 are forgotten.
         */
 Lnot040:
+
+       leds(0x4)
+       
 /*
  * Do any machine specific page table initializations.
  */
@@ -615,6 +667,21 @@ Lspata68040:
 Lnotatari:
 #endif
 
+#ifdef CONFIG_HP300
+       is_not_hp300(Lnothp300)
+
+/* On the HP300, we map the ROM, INTIO and DIO regions (phys. 0x00xxxxxx)
+   by mapping 32MB from 0xf0xxxxxx -> 0x00xxxxxx) using an 030 early 
+   termination page descriptor.  The ROM mapping is needed because the LEDs 
+   are mapped there too.  */
+
+       movel   #_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0
+       movel   %d0,%a5@(0x78<<2)
+
+Lnothp300:
+       
+#endif
+
 #if defined(CONFIG_MVME16x)
        is_not_mvme16x(Lnot16x)
 
@@ -639,6 +706,25 @@ Lnotatari:
 Lnot16x:
 #endif
 
+#if defined(CONFIG_BVME6000)
+       is_not_bvme6000(Lnotbvm)
+
+       /*
+        * On BVME6000 we have already created kernel page tables for
+        * 4MB of RAM at address 0, so now need to do a transparent
+        * mapping of the top of memory space.  Make it 0.5GByte for now.
+        */
+
+       movel   #0xe01f0000,%d2         /* logical address base */
+       orw     #0xa040,%d2             /* add in magic bits */
+       .long   0x4e7b2005              /* movec d2,ittr1 */
+       .long   0x4e7b2007              /* movec d2,dttr1 */
+       .long   0x4e7b2004              /* movec d2,ittr0 */
+       .long   0x4e7b2006              /* movec d2,dttr0 */
+
+Lnotbvm:
+#endif
+
 /*
  * Setup a transparent mapping of the physical memory we are executing in.
  *
@@ -647,6 +733,7 @@ Lnot16x:
  */
 Lmapphys:
        putc('J')
+       leds(0x8)
 
 #ifdef CONFIG_AMIGA
        is_not_amiga(Lmapphysnotamiga)
@@ -853,6 +940,80 @@ Lmapphysnot16x:
 
 #endif
 
+#if defined(CONFIG_HP300)
+       is_not_hp300(Lmapphysnothp300)
+
+/*
+ * Physical RAM is at 0xff000000.  We want to map the kernel at 0x00000000.
+ * In order to avoid disaster when we enable the MMU we need to make a
+ * transparent mapping of the RAM we're executing out of as well.
+ */
+       /*
+        * save physaddr of phys mem in register a3
+        */
+
+       .chip   68030
+       lea     %pc@(Lmmu),%a3
+       movel   %d5,%d0
+       andl    #0xff000000,%d0 /* logical address base */
+       orw     #TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
+       movel   %d0,%a3@
+       pmove   %a3@,%tt0
+       /* no limit, 4byte descriptors */
+       movel   #0x80000002,%a3@
+       movel   %a5,%a3@(4)
+       pmove   %a3@,%srp
+       pmove   %a3@,%crp
+       pflusha
+       /*
+        * enable,super root enable,4096 byte pages,7 bit root index,
+        * 7 bit pointer index, 6 bit page table index.
+        */
+       movel   #0x82c07760,%a3@
+       pmove   %a3@,%tc        /* enable the MMU */
+       jmp     1f
+1:     
+       .chip   68k
+
+       /*
+        * Fix up the custom register to point to the new location of the LEDs.
+        */
+       lea     %pc@(Lcustom),%a1
+       movel   #0xf0000000,%a1@
+
+       /*
+        * Energise the FPU and caches.
+        */
+       orl     #0x64, 0xf05f400c 
+       
+Lmapphysnothp300:
+
+#endif
+
+#if defined(CONFIG_BVME6000)
+       is_not_bvme6000(Lmapphysnotbvm)
+       /*
+        * save physaddr of phys mem in register a3
+        */
+       moveq   #'L',%d7
+       jbsr    Lserial_putc
+
+       .word   0xf4d8          /* CINVA I/D    */
+       .word   0xf518          /* pflusha      */
+       .long   0x4e7bd807      /* movec a5,srp */
+       .long   0x4e7bd806      /* movec a5,urp */
+       movel   #(TC_ENABLE+TC_PAGE4K),%d0
+       /*
+        * this value is also ok for the 68060, we don`t use the cache
+        * mode/protection defaults
+        */
+       .long   0x4e7b0003      /* movec d0,tc  (enable the MMU) */
+       jra     LdoneMMUenable  /* branch to continuation of startup */
+
+Lmapphysnotbvm:
+
+#endif
+
 LdoneMMUenable:
 
 /*
@@ -861,6 +1022,7 @@ LdoneMMUenable:
  */
 
        putc('M')
+       leds(0x10)
 
        /*
         * d5 contains physaddr of kernel start
@@ -917,6 +1079,7 @@ Lcache68060:
 
 /* jump to the kernel start */
        putr()
+       leds(0x55)
 
        subl    %a6,%a6 /* clear a6 for gdb */
        jbsr    SYMBOL_NAME(start_kernel)
@@ -998,6 +1161,11 @@ LMFP_UDR     = 0xfffa2f
 #endif
 #endif
 
+#if defined (CONFIG_BVME6000)
+BVME_SCC_CTRL_A = 0xffb0000b
+BVME_SCC_DATA_A = 0xffb0000f
+#endif
+
 /*
  * Serial port output support.
  */
@@ -1062,6 +1230,17 @@ Lserial_init:
 9:
        rts
 
+#ifdef CONFIG_HP300
+/* Set LEDs to %d7 */
+       .even
+Lset_leds:
+       moveml  %a0/%a1,%sp@-
+       movel   %pc@(Lcustom),%a1
+       moveb   %d7,%a1@(0x1ffff)
+       moveml  %sp@+,%a0/%a1
+       rts
+#endif
+       
 /*
  * Output character in d7 on serial port.
  * d7 thrashed.
@@ -1073,6 +1252,16 @@ Lserial_putc:
        jne     2f
        moveb   %d7,%sp@-
        .long   0x4e4f0020
+       jra     9f
+2:
+#endif
+#ifdef CONFIG_BVME6000
+       cmpil   #MACH_BVME6000,%d4
+       jne     2f
+1:     btst    #2,BVME_SCC_CTRL_A
+       jeq     1b
+       moveb   %d7,BVME_SCC_DATA_A
+       jra     9f
 2:
 #endif
 #ifdef CONFIG_AMIGA
@@ -1199,5 +1388,11 @@ SYMBOL_NAME_LABEL(availmem)
        .long 0
 SYMBOL_NAME_LABEL(m68k_pgtable_cachemode)
        .long 0
+#ifdef CONFIG_060_WRITETHROUGH
+SYMBOL_NAME_LABEL(m68k_supervisor_cachemode)
+       .long 0
+#endif
+#if defined(CONFIG_MVME16x)
 SYMBOL_NAME_LABEL(mvme_bdid_ptr)
        .long 0
+#endif
index a9109ab0a3f71e83f79ca12cb5514364ea92deba..20e39f17f6b62a1c765ecc77d20e9eeda4f557d2 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 
+#include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
@@ -212,7 +213,7 @@ static void dummy_free_irq(unsigned int irq, void *dev_id)
 
 asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
 {
-       if (vec >= VEC_INT1 && vec <= VEC_INT7) {
+       if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) {
                vec -= VEC_SPUR;
                kstat.irqs[0][vec]++;
                irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
index d78d6cba9f95377b3ed75c1a52fa6689372e2a2b..633fd10a2646a2da009a0b106333255126d8ee98 100644 (file)
@@ -62,7 +62,3 @@ EXPORT_SYMBOL_NOVERS(memcmp);
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
-
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
index 4a2a95f4b03867af249d4b3449279f6f33f2d644..da91d32deedf09719ca2592ed669b18215ac773b 100644 (file)
@@ -347,9 +347,13 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        goto out;
                child->flags |= PF_PTRACED;
                if (child->p_pptr != current) {
+                       unsigned long flags;
+
+                       write_lock_irqsave(&tasklist_lock, flags);
                        REMOVE_LINKS(child);
                        child->p_pptr = current;
                        SET_LINKS(child);
+                       write_unlock_irqrestore(&tasklist_lock, flags);
                }
                send_sig(SIGSTOP, child, 1);
                ret = 0;
@@ -491,6 +495,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                }
 
                case PTRACE_DETACH: { /* detach a process that was attached. */
+                       unsigned long flags;
                        long tmp;
 
                        ret = -EIO;
@@ -499,9 +504,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        child->flags &= ~(PF_PTRACED|PF_TRACESYS);
                        wake_up_process(child);
                        child->exit_code = data;
+                       write_lock_irqsave(&tasklist_lock, flags);
                        REMOVE_LINKS(child);
                        child->p_pptr = child->p_opptr;
                        SET_LINKS(child);
+                       write_unlock_irqrestore(&tasklist_lock, flags);
                        /* make sure the single step bit is not set. */
                        tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
                        put_reg(child, PT_SR, tmp);
index fccf8b4cf152d1874931a6a3ccfae1153e26233a..fb5420f61364d1d9173dc32d2df68a4587f7d48b 100644 (file)
@@ -102,6 +102,8 @@ extern void config_mac(void);
 extern void config_sun3(void);
 extern void config_apollo(void);
 extern void config_mvme16x(void);
+extern void config_bmve6000(void);
+extern void config_hp300(void);
 
 #define MASK_256K 0xfffc0000
 
@@ -249,6 +251,16 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
            case MACH_MVME16x:
                config_mvme16x();
                break;
+#endif
+#ifdef CONFIG_BVME6000
+           case MACH_BVME6000:
+               config_bvme6000();
+               break;
+#endif
+#ifdef CONFIG_HP300
+           case MACH_HP300:
+               config_hp300();
+               break;
 #endif
            default:
                panic ("No configuration setup");
index 97809d3823dd26c8be2e52c68e09ecf85183f5af..875dbbf7f904476d5b654ef4c99d3646898ec082 100644 (file)
@@ -875,6 +875,30 @@ segv_and_exit:
        do_exit(SIGSEGV);
 }
 
+static inline void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+{
+       switch (regs->d0) {
+       case -ERESTARTNOHAND:
+               if (!has_handler)
+                       goto do_restart;
+               regs->d0 = -EINTR;
+               break;
+
+       case -ERESTARTSYS:
+               if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
+                       regs->d0 = -EINTR;
+                       break;
+               }
+       /* fallthrough */
+       case -ERESTARTNOINTR:
+       do_restart:
+               regs->d0 = regs->orig_d0;
+               regs->pc -= 2;
+               break;
+       }
+}
+
 /*
  * OK, we're invoking a handler
  */
@@ -883,24 +907,9 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
              sigset_t *oldset, struct pt_regs *regs)
 {
        /* are we from a system call? */
-       if (regs->orig_d0 >= 0) {
+       if (regs->orig_d0 >= 0)
                /* If so, check system call restarting.. */
-               switch (regs->d0) {
-                       case -ERESTARTNOHAND:
-                               regs->d0 = -EINTR;
-                               break;
-
-                       case -ERESTARTSYS:
-                               if (!(ka->sa.sa_flags & SA_RESTART)) {
-                                       regs->d0 = -EINTR;
-                                       break;
-                               }
-                       /* fallthrough */
-                       case -ERESTARTNOINTR:
-                               regs->d0 = regs->orig_d0;
-                               regs->pc -= 2;
-               }
-       }
+               handle_restart(regs, ka, 1);
 
        /* set up the stack frame */
        if (ka->sa.sa_flags & SA_SIGINFO)
@@ -952,13 +961,14 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
 
                        /* Did we come from a system call? */
                        if (regs->orig_d0 >= 0) {
-                               /* Restart the system call */
-                               if (regs->d0 == -ERESTARTNOHAND ||
-                                   regs->d0 == -ERESTARTSYS ||
-                                   regs->d0 == -ERESTARTNOINTR) {
-                                       regs->d0 = regs->orig_d0;
-                                       regs->pc -= 2;
-                               }
+                               /* Restart the system call the same way as
+                                  if the process were not traced.  */
+                               struct k_sigaction *ka =
+                                       &current->sig->action[signr-1];
+                               int has_handler =
+                                       (ka->sa.sa_handler != SIG_IGN &&
+                                        ka->sa.sa_handler != SIG_DFL);
+                               handle_restart(regs, ka, has_handler);
                        }
                        notify_parent(current, SIGCHLD);
                        schedule();
@@ -1052,15 +1062,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
        }
 
        /* Did we come from a system call? */
-       if (regs->orig_d0 >= 0) {
+       if (regs->orig_d0 >= 0)
                /* Restart the system call - no handlers present */
-               if (regs->d0 == -ERESTARTNOHAND ||
-                   regs->d0 == -ERESTARTSYS ||
-                   regs->d0 == -ERESTARTNOINTR) {
-                       regs->d0 = regs->orig_d0;
-                       regs->pc -= 2;
-               }
-       }
+               handle_restart(regs, NULL, 0);
 
        /* If we are about to discard some frame stuff we must copy
           over the remaining frame. */
index 50d56413448e142b5c5a462b94ef0e1c8e33a36e..e716bf81a860062711d91478a90288166d0ea77f 100644 (file)
@@ -73,11 +73,14 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg)
 
        if (!(a.flags & MAP_ANONYMOUS)) {
                error = -EBADF;
-               if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd]))
+               file = fget(a.fd);
+               if (!file)
                        goto out;
        }
        a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+       if (file)
+               fput(file);
 out:
        unlock_kernel();
        return error;
index 458a01f4499edb710b053ec04a5b9939bf8ecc32..cfd63295a6c702f84b876909a9f2c78e7161b3c8 100644 (file)
@@ -10,7 +10,8 @@
 EXTRA_CFLAGS := -Wa,-m68020
 
 O_TARGET := mac.o
-O_OBJS  := config.o ksyms.o bootparse.o macints.o via6522.o \
+O_OBJS  := config.o bootparse.o macints.o via6522.o \
                mackeyb.o adb-bus.o macboing.o debug.o
+OX_OBJS  := mac_ksyms.o
 
 include $(TOPDIR)/Rules.make
index b2fb01b95887ea10f1bbf7c859259352a327571e..d60815ae77426a805290681c50d5d3ab255950fe 100644 (file)
@@ -93,6 +93,9 @@ static int prefix_len;
 
 static int status = ST_IDLE|TREQ;
 static int last_status;
+
+static int driver_running = 0;
+
 /*static int adb_delay;*/
 int in_keybinit = 1;
 
@@ -106,11 +109,15 @@ static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs);
 static void adb_hw_setup_IIsi(void);
 
 /*
- * Misc. defines for testing 
+ * debug level 10 required for ADB logging (should be && debug_adb, ideally)
  */
 
 extern int console_loglevel;
 
+/*
+ * Misc. defines for testing - should go to header :-(
+ */
+
 #define ADBDEBUG_STATUS                (1)
 #define ADBDEBUG_STATE         (2)
 #define ADBDEBUG_READ          (4)
@@ -128,7 +135,7 @@ extern int console_loglevel;
 #define ADBDEBUG_IISI          (8192)
 
 
-#define DEBUG_ADB
+/*#define DEBUG_ADB*/
 
 #ifdef DEBUG_ADB
 #define ADBDEBUG       (ADBDEBUG_INPUT | ADBDEBUG_READ | ADBDEBUG_START | ADBDEBUG_WRITE | ADBDEBUG_SRQ | ADBDEBUG_REQUEST)
@@ -857,10 +864,22 @@ void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs)
 void adb_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
        int x, adbdir;
+       unsigned long flags;
        struct adb_request *req;
 
        last_status = status;
 
+       /* prevent races due to SCSI enabling ints */
+       save_flags(flags);
+       cli();
+
+       if (driver_running) {
+               restore_flags(flags);
+               return;
+       }
+
+       driver_running = 1;
+       
 #ifdef USE_ORIG
        status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
 #else
@@ -877,7 +896,6 @@ void adb_interrupt(int irq, void *arg, struct pt_regs *regs)
                        adb_state, status, last_status, adbdir);
 #endif
 
-
        switch (adb_state) 
        {
                case idle:
@@ -1614,6 +1632,9 @@ void adb_interrupt(int irq, void *arg, struct pt_regs *regs)
                        printk("adb_interrupt: unknown adb_state %d?\n", adb_state);
 #endif
        }
+       /* reset mutex and interrupts */
+       driver_running = 0;
+       restore_flags(flags);
 }
 
 /*
index a7d30a0430c4eb9f45c11150758504d27d255df3..1b3d74946f22668cb9169d2c4a43f66470834f34 100644 (file)
 
 #include "via6522.h"
 
-/* old bootinfo stuff */
+/* Mac bootinfo struct */
 
 struct mac_booter_data mac_bi_data = {0,};
 int mac_bisize = sizeof mac_bi_data;
 
-struct compat_bootinfo compat_boot_info ={0,};
-int compat_bisize = sizeof compat_boot_info;
-
-int compat_bi = 0;
-
-/* New bootinfo stuff */
+/* New m68k bootinfo stuff and videobase */
 
 extern int m68k_num_memory;
 extern struct mem_info m68k_memory[NUM_MEMINFO];
@@ -59,7 +54,7 @@ extern char m68k_command_line[CL_SIZE];
 
 void *mac_env;         /* Loaded by the boot asm */
 
-/* The locgial video addr. determined by head.S - testing */
+/* The logical video addr. determined by head.S - testing */
 extern unsigned long mac_videobase;
 
 /* The phys. video addr. - might be bogus on some machines */
@@ -84,23 +79,22 @@ extern void mac_debugging_long(int, long);
 extern void mac_debug_init(void);
 
 #ifdef CONFIG_MAGIC_SYSRQ
+
+/* XXX FIXME: Atari scancodes still */
 static char mac_sysrq_xlate[128] =
-       "\000\0331234567890-=\177\t"                                    /* 0x00 - 0x0f */
-       "qwertyuiop[]\r\000as"                                                  /* 0x10 - 0x1f */
-       "dfghjkl;'`\000\\zxcv"                                                  /* 0x20 - 0x2f */
-       "bnm,./\000\000\000 \000\201\202\203\204\205"   /* 0x30 - 0x3f */
+       "\000\0331234567890-=\177\t"                            /* 0x00 - 0x0f */
+       "qwertyuiop[]\r\000as"                                  /* 0x10 - 0x1f */
+       "dfghjkl;'`\000\\zxcv"                                  /* 0x20 - 0x2f */
+       "bnm,./\000\000\000 \000\201\202\203\204\205"           /* 0x30 - 0x3f */
        "\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */
        "\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-       "\000\000\000()/*789456123"                                             /* 0x60 - 0x6f */
+       "\000\000\000()/*789456123"                             /* 0x60 - 0x6f */
        "0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000";     /* 0x70 - 0x7f */
 #endif
 
 extern void (*kd_mksound)(unsigned int, unsigned int);
 
-void mac_get_model(char *str)
-{
-       strcpy(str,"Macintosh");
-}
+static void mac_get_model(char *str);
 
 void mac_bang(int irq, void *vector, struct pt_regs *p)
 {
@@ -120,20 +114,21 @@ unsigned long mac_gettimeoffset (void)
 
 extern int console_loglevel;
 
+/*
+ * This function translates the boot timeval into a proper date, to initialize
+ * the system time.
+ * Known problem: off by one after Feb. 27 on leap years
+ */
+
 void mac_gettod (int *yearp, int *monp, int *dayp,
                 int *hourp, int *minp, int *secp)
 {
        unsigned long time;
        int leap, oldleap, isleap;
-       int mon_days[14] = { -1, 31, 27, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 };
+       int mon_days[14] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 };
 
        time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */
 
-#if 0
-       printk("mac_gettod: boottime 0x%lx gmtbias %ld \n",
-               mac_bi_data.boottime, mac_bi_data.gmtbias);
-#endif 
-
        *minp = time / 60;
        *secp = time - (*minp * 60);
        time  = *minp;                          /* minutes now */
@@ -149,7 +144,7 @@ void mac_gettod (int *yearp, int *monp, int *dayp,
        /* for leap day calculation */
        *yearp = (time / 365) + 1970;           /* approx. year */
 
-       /* leap year calculation - there's an easier way, I bet */
+       /* leap year calculation - there's an easier way, I bet. And it's broken :-( */
        /* calculate leap days up to previous year */
        oldleap =  (*yearp-1)/4 - (*yearp-1)/100 + (*yearp-1)/400;
        /* calculate leap days incl. this year */
@@ -167,7 +162,7 @@ void mac_gettod (int *yearp, int *monp, int *dayp,
        time = *dayp;
        
        if (isleap)                             /* add leap day ?? */
-               mon_days[2] = 28;
+               mon_days[2] += 1;
 
        /* count the months */
        for (*monp = 1; time > mon_days[*monp]; (*monp)++) 
@@ -175,12 +170,6 @@ void mac_gettod (int *yearp, int *monp, int *dayp,
 
        *dayp = time;
 
-#if 1
-       printk("mac_gettod: %d-%d-%d %d:%d.%d GMT (GMT offset %d)\n",
-               *yearp, *monp, *dayp, *hourp, *minp, *secp, 
-               (signed long) mac_bi_data.gmtbias);
-#endif
-
        return;
 }
 
@@ -189,13 +178,10 @@ void mac_waitbut (void)
        ;
 }
 
+extern struct consw fb_con;
+extern struct fb_info *mac_fb_init(long *);
 extern void mac_video_setup(char *, int *);
 
-void mac_debug_init (void)
-{
-       ;
-}
-
 void (*mac_handlers[8])(int, void *, struct pt_regs *)=
 {
        mac_default_handler,
@@ -222,6 +208,7 @@ __initfunc(int mac_parse_bootinfo(const struct bi_record *record))
            mac_bi_data.id = *data;
            break;
        case BI_MAC_VADDR:
+           /* save booter supplied videobase; use the one mapped in head.S! */
            mac_orig_videoaddr = *data;
            mac_bi_data.videoaddr = mac_videobase;
            break;
@@ -265,8 +252,6 @@ __initfunc(void config_mac(void))
       printk("ERROR: no Mac, but config_mac() called!! \n");
     }
     
-    mac_debugging_penguin(5);
-
     mac_debug_init();
         
     mach_sched_init      = mac_sched_init;
@@ -289,9 +274,6 @@ __initfunc(void config_mac(void))
     mach_mksound         = mac_mksound;
 #endif
     mach_reset           = mac_reset;
-#ifdef CONFIG_MAC_FLOPPY
-    mach_floppy_setup   = mac_floppy_setup;
-#endif
     conswitchp          = &fb_con;
     mach_max_dma_address = 0xffffffff;
 #if 0
@@ -330,12 +312,19 @@ __initfunc(void config_mac(void))
 
     nubus_sweep_video();
 
-    mac_debugging_penguin(6);
 }      
 
 
 /*
- *     Macintosh Table
+ *     Macintosh Table: hardcoded model configuration data. 
+ *
+ *     Much of this was defined by Alan, based on who knows what docs. 
+ *     I've added a lot more, and some of that was pure guesswork based 
+ *     on hardware pages present on the Mac web site. Possibly wildly 
+ *     inaccurate, so look here if a new Mac model won't run. Example: if
+ *     a Mac crashes immediately after the VIA1 registers have been dumped
+ *     to the screen, it probably died attempting to read DirB on a RBV. 
+ *     Meaning it should have MAC_VIA_IIci here :-)
  */
  
 struct mac_model *macintosh_config;
@@ -359,10 +348,11 @@ static struct mac_model mac_data_table[]=
         *
         *      The IIfx apparently has different ADB hardware, and stuff
         *      so zany nobody knows how to drive it.
+        *      Even so, with Marten's help we'll try to deal with it :-)
         */
 
        {       MAC_MODEL_IICI, "IIci", MAC_ADB_II,     MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
-       {       MAC_MODEL_IIFX, "IIfx", MAC_ADB_NONE,   MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_IIFX, "IIfx", MAC_ADB_II,     MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_IISI, "IIsi", MAC_ADB_IISI,   MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_IIVI, "IIvi", MAC_ADB_IISI,   MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_IIVX, "IIvx", MAC_ADB_IISI,   MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
@@ -378,6 +368,7 @@ static struct mac_model mac_data_table[]=
         *      Some Mac LC machines. Basically the same as the IIci, ADB like IIsi
         */
        
+       {       MAC_MODEL_LC,   "LC",     MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_LCII, "LC II",  MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_LCIII,"LC III", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
 
@@ -389,32 +380,35 @@ static struct mac_model mac_data_table[]=
         *      place to confuse us. The 840 seems to have a scsi location of its own
         */      
         
-       {       MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,     MAC_ETHER_SONIC,        MAC_NUBUS},
-       {       MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,     MAC_ETHER_SONIC,        MAC_NUBUS},
-       {       MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,     MAC_ETHER_SONIC,        MAC_NUBUS},
-       {       MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,     MAC_ETHER_SONIC,        MAC_NUBUS},
+       {       MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,   MAC_ETHER_SONIC,        MAC_NUBUS},
+       {       MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,   MAC_ETHER_SONIC,        MAC_NUBUS},
+       {       MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_QUADRA, MAC_SCC_QUADRA,   MAC_ETHER_SONIC,        MAC_NUBUS},
+       {       MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,   MAC_ETHER_SONIC,        MAC_NUBUS},
        /*      The Q700 does have a NS Sonic */
-       {       MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2,    MAC_ETHER_SONIC,        MAC_NUBUS},
-       {       MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,     MAC_ETHER_SONIC,        MAC_NUBUS},
+       {       MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_QUADRA2,  MAC_ETHER_SONIC,        MAC_NUBUS},
+       {       MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,   MAC_ETHER_SONIC,        MAC_NUBUS},
        /* Does the 840 have ethernet ??? documents seem to indicate its not quite a
           Quadra in this respect ? */
-       {       MAC_MODEL_Q840, "Quadra 840", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II,         MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_Q840, "Quadra 840", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE,   MAC_SCC_II,       MAC_ETHER_NONE,         MAC_NUBUS},
        /* These might have IOP problems */
-       {       MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2,    MAC_ETHER_SONIC,        MAC_NUBUS},
-       {       MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2,    MAC_ETHER_SONIC,        MAC_NUBUS},
+       {       MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,      MAC_ETHER_SONIC,        MAC_NUBUS},
+       {       MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,      MAC_ETHER_SONIC,        MAC_NUBUS},
 
        /* 
         *      Performa - more LC type machines
         */
 
-       {       MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,   MAC_ETHER_NONE, MAC_NUBUS},
-       {       MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,        MAC_ETHER_NONE, MAC_NUBUS},
-       {       MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,   MAC_ETHER_NONE, MAC_NUBUS},
-       {       MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,   MAC_ETHER_NONE, MAC_NUBUS},
-       {       MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,   MAC_ETHER_NONE, MAC_NUBUS},
-       {       MAC_MODEL_TV,   "TV",           MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,   MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_P460,  "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,  MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_P475,  "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,       MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,       MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_P520,  "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,       MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_P550,  "Performa 550", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,       MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,       MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_P588,  "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,       MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_TV,    "TV",           MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD,    MAC_IDE_NONE, MAC_SCC_II,       MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_P600,  "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
 #if 0  /* other sources seem to suggest the P630/Q630/LC630 is more like LCIII */
-       {       MAC_MODEL_P630, "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,   MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_P630,  "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,  MAC_ETHER_NONE, MAC_NUBUS},
 #endif
        /*
         *      Centris - just guessing again; maybe like Quadra
@@ -431,14 +425,14 @@ static struct mac_model mac_data_table[]=
        {       MAC_MODEL_PB140,  "PowerBook 140",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB145,  "PowerBook 145",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
        /*      The PB150 has IDE, and IIci style VIA */
-       {       MAC_MODEL_PB150,  "PowerBook 150",   MAC_ADB_PB1, MAC_VIA_IIci,   MAC_SCSI_QUADRA, MAC_IDE_PB,    MAC_SCC_QUADRA,       MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_PB150,  "PowerBook 150",   MAC_ADB_PB1, MAC_VIA_IIci,   MAC_SCSI_QUADRA, MAC_IDE_PB,   MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB160,  "PowerBook 160",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB165,  "PowerBook 165",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB165C, "PowerBook 165c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB170,  "PowerBook 170",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB180,  "PowerBook 180",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB180C, "PowerBook 180c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
-       {       MAC_MODEL_PB190,  "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_PB190,  "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_PB,   MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB520,  "PowerBook 520",   MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,        MAC_ETHER_NONE, MAC_NUBUS},
 
        /*
@@ -446,7 +440,7 @@ static struct mac_model mac_data_table[]=
         */
 
        {       MAC_MODEL_PB210,  "PowerBook Duo 210",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,    MAC_ETHER_NONE, MAC_NUBUS},
-       {       MAC_MODEL_PB230,  "PowerBook Duo 230",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,    MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_PB230,  "PowerBook Duo 230",  MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD,    MAC_IDE_NONE, MAC_SCC_QUADRA,      MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB250,  "PowerBook Duo 250",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,    MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,    MAC_ETHER_NONE, MAC_NUBUS},
        {       MAC_MODEL_PB280,  "PowerBook Duo 280",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,    MAC_ETHER_NONE, MAC_NUBUS},
@@ -483,8 +477,6 @@ void mac_identify(void)
        {
                printk("\nUnknown macintosh model %d, probably unsupported.\n", 
                        model);
-               mac_debugging_long(1, (long) 0x55555555);
-               mac_debugging_long(1, (long) model);
                model = MAC_MODEL_Q800;
                printk("Defaulting to: Quadra800, model id %d\n", model);
                printk("Please report this case to linux-mac68k@wave.lm.com\n");
@@ -502,7 +494,7 @@ void mac_identify(void)
        /*
         * Report booter data:
         */
-       printk (" Penguin (bootinfo version %d) data:\n", 2-compat_bi);
+       printk (" Penguin bootinfo data:\n");
        printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %d x %d\n", 
                mac_bi_data.videoaddr, mac_bi_data.videorow, 
                mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, 
@@ -536,6 +528,12 @@ void mac_report_hardware(void)
        printk("Apple Macintosh %s\n", macintosh_config->name);
 }
 
+static void mac_get_model(char *str)
+{
+       strcpy(str,"Macintosh ");
+       strcat(str, macintosh_config->name);
+}
+
 /*
  * Local variables:
  *  c-indent-level: 4
index 70010a914e0ef34a58f46056d14a5610190d4f40..6fc3ac52d0aada2652c435cc76b22560e3f9e9cc 100644 (file)
@@ -36,6 +36,9 @@ extern unsigned long mac_videobase;
 extern unsigned long mac_videodepth;
 extern unsigned long mac_rowbytes;
 
+#define DEBUG_SCREEN
+#define DEBUG_SERIAL
+
 /*
  * These two auxiliary debug functions should go away ASAP. Only usage: 
  * before the console output is up (after head.S come some other crucial
@@ -46,21 +49,30 @@ extern unsigned long mac_rowbytes;
  * The 'pos' argument now simply means 'linefeed after print' ...
  */
 
+#ifdef DEBUG_SCREEN
 static int peng=0, line=0;
+#endif
 
 void mac_debugging_short(int pos, short num)
 {
+#ifdef DEBUG_SCREEN
        unsigned char *pengoffset;
        unsigned char *pptr;
        int i;
+#endif
+
+#ifdef DEBUG_SERIAL
+       printk("debug: %d !\n", num);
+#endif
 
+#ifdef DEBUG_SCREEN
        if (!MACH_IS_MAC) {
                /* printk("debug: %d !\n", num); */
                return;
        }
 
        /* calculate current offset */
-       pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes)
+       pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
                    +80*peng;
        
        pptr=pengoffset;
@@ -77,20 +89,28 @@ void mac_debugging_short(int pos, short num)
                line++;
                peng = 0;
        }
+#endif
 }
 
 void mac_debugging_long(int pos, long addr)
 {
+#ifdef DEBUG_SCREEN
        unsigned char *pengoffset;
        unsigned char *pptr;
        int i;
+#endif
 
+#ifdef DEBUG_SERIAL
+       printk("debug: #%ld !\n", addr);
+#endif
+
+#ifdef DEBUG_SCREEN
        if (!MACH_IS_MAC) {
                /* printk("debug: #%ld !\n", addr); */
                return;
        }
        
-       pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes)
+       pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
                    +80*peng;
        
        pptr=pengoffset;
@@ -106,6 +126,7 @@ void mac_debugging_long(int pos, long addr)
                line++;
                peng = 0;
        }
+#endif
 }
 
 /*
@@ -115,20 +136,29 @@ char that_penguin[]={
 #include "that_penguin.h"
 };
 
+#ifdef DEBUG_SCREEN
 /* 
  * B/W version of penguin, unfinished - any takers??
  */
 static char bw_penguin[]={
 #include "bw_penguin.h"
 };
+#endif
 
 void mac_debugging_penguin(int peng)
 {
+#ifdef DEBUG_SCREEN
        unsigned char *pengoffset;
        unsigned char *pptr;
        unsigned char *bwpdptr=bw_penguin;
        int i;
+#endif
 
+#ifdef DEBUG_SERIAL
+       printk("Penguin: #%d !\n", peng);
+#endif
+
+#ifdef DEBUG_SCREEN
        if (!MACH_IS_MAC) 
                return;
 
@@ -147,15 +177,19 @@ void mac_debugging_penguin(int peng)
                bwpdptr+=4;
                pptr+=mac_rowbytes;
        }
+#endif
 }
 
+#ifdef DEBUG_SCREEN
 /*
  * B/W version of flaming Mac, unfinished (see above).
  */
 static char bw_kaboom_map[]={
 #include "bw_mac.h"
 };
+#endif
 
+#ifdef DEBUG_SCREEN
 static void mac_boom_boom(void)
 {
        static unsigned char *boomoffset=NULL;
@@ -163,6 +197,13 @@ static void mac_boom_boom(void)
        unsigned char *bwpdptr=bw_kaboom_map;
        int i;
        
+#ifdef DEBUG_SERIAL
+       printk("BOOM !\n");
+#endif
+
+       if (!MACH_IS_MAC) 
+               return;
+
        if(!boomoffset)
                if (mac_videodepth == 1) {
                        boomoffset=(unsigned char *)(mac_videobase+160*mac_rowbytes);
@@ -184,25 +225,43 @@ static void mac_boom_boom(void)
                pptr+=mac_rowbytes;
        }
 }
+#endif
 
 void mac_boom(int booms)
 {
+#ifdef DEBUG_SCREEN
        int i;
+#endif
 
        if (!MACH_IS_MAC) 
                return;
 
+#ifdef DEBUG_SCREEN
        for(i=0;i<booms;i++)
                mac_boom_boom();
        while(1);
+#endif
 }
 
 
-#if 0
+#ifdef DEBUG_SERIAL
 /*
  * TODO: serial debug code
  */
 
+#define SCC_BAS (0x50F04000)
+struct SCC
+ {
+  u_char cha_b_ctrl;
+  u_char char_dummy1;
+  u_char cha_a_ctrl;
+  u_char char_dummy2;
+  u_char cha_b_data;
+  u_char char_dummy3;
+  u_char cha_a_data;
+ };
+# define scc ((*(volatile struct SCC*)SCC_BAS))
+
 /* Flag that serial port is already initialized and used */
 int mac_SCC_init_done = 0;
 /* Can be set somewhere, if a SCC master reset has already be done and should
@@ -225,54 +284,113 @@ static struct console mac_console_driver = {
 
 static int scc_port;
 
-static inline void mac_scc_out (char c)
+/* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/
+
+#define US 1
+
+static inline void mac_sccb_out (char c)
 {
+    int i;
     do {
-       MFPDELAY();
+       for( i = US; i > 0; --i )
+               barrier();
     } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
-    MFPDELAY();
+    for( i = US; i > 0; --i )
+       barrier();
     scc.cha_b_data = c;
 }
 
-void mac_scc_console_write (struct console *co, const char *str,
+static inline void mac_scca_out (char c)
+{
+    int i;
+    do {
+       for( i = US; i > 0; --i )
+               barrier();
+    } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
+    for( i = US; i > 0; --i )
+       barrier();
+    scc.cha_a_data = c;
+}
+
+void mac_sccb_console_write (struct console *co, const char *str,
                              unsigned int count)
 {
     while (count--) {
        if (*str == '\n')
-           mac_scc_out( '\r' );
-       mac_scc_out( *str++ );
+           mac_sccb_out( '\r' );
+       mac_sccb_out( *str++ );
+    }
+}
+
+void mac_scca_console_write (struct console *co, const char *str,
+                             unsigned int count)
+{
+    while (count--) {
+       if (*str == '\n')
+           mac_scca_out( '\r' );
+       mac_scca_out( *str++ );
     }
 }
 
 #ifdef CONFIG_SERIAL_CONSOLE
-int mac_scc_console_wait_key(struct console *co)
+int mac_sccb_console_wait_key(struct console *co)
 {
+    int i;
     do {
-       MFPDELAY();
+       for( i = US; i > 0; --i )
+               barrier();
     } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
-    MFPDELAY();
+    for( i = US; i > 0; --i )
+       barrier();
     return( scc.cha_b_data );
 }
+
+int mac_scca_console_wait_key(struct console *co)
+{
+    int i;
+    do {
+       for( i = US; i > 0; --i )
+               barrier();
+    } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */
+    for( i = US; i > 0; --i )
+       barrier();
+    return( scc.cha_a_data );
+}
 #endif
 
 /* The following two functions do a quick'n'dirty initialization of the MFP or
  * SCC serial ports. They're used by the debugging interface, kgdb, and the
  * serial console code. */
-#define SCC_WRITE(reg,val)                             \
+#define SCCB_WRITE(reg,val)                            \
     do {                                               \
+       int i;                                          \
        scc.cha_b_ctrl = (reg);                         \
-       MFPDELAY();                                     \
+       for( i = US; i > 0; --i )                       \
+               barrier();                              \
        scc.cha_b_ctrl = (val);                         \
-       MFPDELAY();                                     \
+       for( i = US; i > 0; --i )                       \
+               barrier();                              \
+    } while(0)
+
+#define SCCA_WRITE(reg,val)                            \
+    do {                                               \
+       int i;                                          \
+       scc.cha_a_ctrl = (reg);                         \
+       for( i = US; i > 0; --i )                       \
+               barrier();                              \
+       scc.cha_a_ctrl = (val);                         \
+       for( i = US; i > 0; --i )                       \
+               barrier();                              \
     } while(0)
 
 /* loops_per_sec isn't initialized yet, so we can't use udelay(). This does a
  * delay of ~ 60us. */
+/* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/
 #define LONG_DELAY()                           \
     do {                                       \
        int i;                                  \
-       for( i = 100; i > 0; --i )              \
-           MFPDELAY();                         \
+       for( i = 60*US; i > 0; --i )            \
+           barrier();                          \
     } while(0)
     
 #ifndef CONFIG_SERIAL_CONSOLE
@@ -310,30 +428,56 @@ void mac_init_scc_port( int cflag, int port )
 
     reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
     reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
-    
-    (void)scc.cha_b_ctrl;      /* reset reg pointer */
-    SCC_WRITE( 9, 0xc0 );      /* reset */
-    LONG_DELAY();              /* extra delay after WR9 access */
-    SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
-                 0x04 /* 1 stopbit */ |
-                 clkmode );
-    SCC_WRITE( 3, reg3 );
-    SCC_WRITE( 5, reg5 );
-    SCC_WRITE( 9, 0 );         /* no interrupts */
-    LONG_DELAY();              /* extra delay after WR9 access */
-    SCC_WRITE( 10, 0 );                /* NRZ mode */
-    SCC_WRITE( 11, clksrc );   /* main clock source */
-    SCC_WRITE( 12, div );      /* BRG value */
-    SCC_WRITE( 13, 0 );                /* BRG high byte */
-    SCC_WRITE( 14, brgsrc_table[baud] );
-    SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
-    SCC_WRITE( 3, reg3 | 1 );
-    SCC_WRITE( 5, reg5 | 8 );
-    
+
+#if 0    
+    if (port) {
+#endif
+           (void)scc.cha_b_ctrl;       /* reset reg pointer */
+           SCCB_WRITE( 9, 0xc0 );      /* reset */
+           LONG_DELAY();               /* extra delay after WR9 access */
+           SCCB_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+                         0x04 /* 1 stopbit */ |
+                         clkmode );
+           SCCB_WRITE( 3, reg3 );
+           SCCB_WRITE( 5, reg5 );
+           SCCB_WRITE( 9, 0 );         /* no interrupts */
+           LONG_DELAY();               /* extra delay after WR9 access */
+           SCCB_WRITE( 10, 0 );                /* NRZ mode */
+           SCCB_WRITE( 11, clksrc );   /* main clock source */
+           SCCB_WRITE( 12, div );      /* BRG value */
+           SCCB_WRITE( 13, 0 );                /* BRG high byte */
+           SCCB_WRITE( 14, brgsrc_table[baud] );
+           SCCB_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
+           SCCB_WRITE( 3, reg3 | 1 );
+           SCCB_WRITE( 5, reg5 | 8 );
+#if 0
+    } else {
+#endif
+           (void)scc.cha_a_ctrl;       /* reset reg pointer */
+           SCCA_WRITE( 9, 0xc0 );      /* reset */
+           LONG_DELAY();               /* extra delay after WR9 access */
+           SCCA_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+                         0x04 /* 1 stopbit */ |
+                         clkmode );
+           SCCA_WRITE( 3, reg3 );
+           SCCA_WRITE( 5, reg5 );
+           SCCA_WRITE( 9, 0 );         /* no interrupts */
+           LONG_DELAY();               /* extra delay after WR9 access */
+           SCCA_WRITE( 10, 0 );                /* NRZ mode */
+           SCCA_WRITE( 11, clksrc );   /* main clock source */
+           SCCA_WRITE( 12, div );      /* BRG value */
+           SCCA_WRITE( 13, 0 );                /* BRG high byte */
+           SCCA_WRITE( 14, brgsrc_table[baud] );
+           SCCA_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
+           SCCA_WRITE( 3, reg3 | 1 );
+           SCCA_WRITE( 5, reg5 | 8 );
+#if 0
+    }
+#endif
     mac_SCC_reset_done = 1;
     mac_SCC_init_done = 1;
 }
-
+#endif /* DEBUG_SERIAL */
 
 __initfunc(void mac_debug_init(void))
 {
@@ -341,23 +485,24 @@ __initfunc(void mac_debug_init(void))
     /* the m68k_debug_device is used by the GDB stub, do nothing here */
     return;
 #endif
+#ifdef DEBUG_SERIAL
     if (!strcmp( m68k_debug_device, "ser" )) {
        strcpy( m68k_debug_device, "ser1" );
     }
     if (!strcmp( m68k_debug_device, "ser1" )) {
        /* ST-MFP Modem1 serial port */
        mac_init_scc_port( B9600|CS8, 0 );
-       mac_console_driver.write = mac_scc_console_write;
+       mac_console_driver.write = mac_scca_console_write;
     }
     else if (!strcmp( m68k_debug_device, "ser2" )) {
        /* SCC Modem2 serial port */
        mac_init_scc_port( B9600|CS8, 1 );
-       mac_console_driver.write = mac_scc_console_write;
+       mac_console_driver.write = mac_sccb_console_write;
     }
     if (mac_console_driver.write)
        register_console(&mac_console_driver);
-}
 #endif
+}
 
 /*
  * Local variables:
diff --git a/arch/m68k/mac/ksyms.c b/arch/m68k/mac/ksyms.c
deleted file mode 100644 (file)
index 05373b0..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <linux/module.h>
-#include <asm/ptrace.h>
-#include <asm/traps.h>
-/* Hook for mouse driver */
-extern void (*mac_mouse_interrupt_hook) (char *);
-
-EXPORT_SYMBOL(mac_mouse_interrupt_hook);
diff --git a/arch/m68k/mac/mac_ksyms.c b/arch/m68k/mac/mac_ksyms.c
new file mode 100644 (file)
index 0000000..05373b0
--- /dev/null
@@ -0,0 +1,7 @@
+#include <linux/module.h>
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+/* Hook for mouse driver */
+extern void (*mac_mouse_interrupt_hook) (char *);
+
+EXPORT_SYMBOL(mac_mouse_interrupt_hook);
index 3347438cfdf5c303ce0ba44039fb91e1e8d39bb0..ed3720863caf8e66dbf32bdfaf8a97497edf1150 100644 (file)
  *
  *     7       - Debug output
  *
+ * AV Macs only, handled by PSC:
+ *
+ *     3       - MACE ethernet IRQ (DMA complete on level 4)
+ *
+ *     5       - DSP ?? 
+ *
  * Using the autovector irq numbers for Linux/m68k hardware interrupts without
  * the IRQ_MACHSPEC bit set would interfere with the general m68k interrupt 
  * handling in kernel versions 2.0.x, so the following strategy is used:
  *   should be sufficient to use the same numbers (everything > 7 is assumed 
  *   to be machspec, according to Jes!).
  *
+ *   TODO:
+ * - integrate Nubus interrupts in request/free_irq
+ *
+ * - 
  */
 
 #include <linux/types.h>
@@ -64,6 +74,7 @@
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h> /* for intr_count */
+#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
@@ -98,7 +109,10 @@ struct irqflags {
 static struct irqhandler  via1_handler[8];
 static struct irqhandler  via2_handler[8];
 static struct irqhandler   rbv_handler[8];
+static struct irqhandler  psc3_handler[8];
 static struct irqhandler   scc_handler[8];
+static struct irqhandler  psc5_handler[8];
+static struct irqhandler  psc6_handler[8];
 static struct irqhandler nubus_handler[8];
 
 static struct irqhandler *handler_table[8];
@@ -111,7 +125,10 @@ static struct irqhandler *handler_table[8];
 static struct irqparam  via1_param[8];
 static struct irqparam  via2_param[8];
 static struct irqparam   rbv_param[8];
+static struct irqparam  psc3_param[8];
 static struct irqparam   scc_param[8];
+static struct irqparam  psc5_param[8];
+static struct irqparam  psc6_param[8];
 static struct irqparam nubus_param[8];
 
 static struct irqparam *param_table[8];
@@ -125,27 +142,51 @@ static struct irqflags irq_flags[8];
 
 /*
  * This array holds the pointers to the various VIA or other interrupt 
- * controllers
+ * controllers, indexed by interrupt level
  */
 
 static volatile unsigned char *via_table[8];
 
-#ifdef VIABASE_WEIRDNESS
 /*
- * VIA2 / RBV default base address 
+ * Arrays with irq statistics
  */
+static unsigned long via1_irqs[8];
+static unsigned long via2_irqs[8];
+static unsigned long rbv_irqs[8];
+static unsigned long psc3_irqs[8];
+static unsigned long scc_irqs[8];
+static unsigned long psc5_irqs[8];
+static unsigned long psc6_irqs[8];
+static unsigned long nubus_irqs[8];
 
-volatile unsigned char *via2_regp = ((volatile unsigned char *)VIA2_BAS);
-volatile unsigned char *rbv_regp  = ((volatile unsigned char *)VIA2_BAS_IIci);
-#endif
+static unsigned long *mac_irqs[8];
+
+/*
+ * VIA2 / RBV register base pointers
+ */
+
+volatile unsigned char *via2_regp=(volatile unsigned char *)VIA2_BAS;
+volatile unsigned char *rbv_regp=(volatile unsigned char *)VIA2_BAS_IIci;
+volatile unsigned char *oss_regp=(volatile unsigned char *)OSS_BAS;
+volatile unsigned char *psc_regp=(volatile unsigned char *)PSC_BAS;
 
 /*
  * Flags to control via2 / rbv behaviour
  */ 
 
 static int via2_is_rbv = 0;
+static int via2_is_oss = 0;
 static int rbv_clear = 0;
 
+/* fake VIA2 to OSS bit mapping */
+static int oss_map[8] = {2, 7, 0, 1, 3, 4, 5};
+
+void oss_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void oss_do_nubus(int irq, void *dev_id, struct pt_regs *regs);
+
+/* PSC ints */
+void psc_irq(int irq, void *dev_id, struct pt_regs *regs);
+
 /*
  * console_loglevel determines NMI handler function
  */
@@ -177,6 +218,10 @@ void mac_init_IRQ(void)
 #ifdef DEBUG_MACINTS
        printk("Mac interrupt stuff initializing ...\n");
 #endif
+
+       via2_regp = (unsigned char *)VIA2_BAS;
+       rbv_regp  = (unsigned char *)VIA2_BAS_IIci;
+
         /* initialize the hardwired (primary, autovector) IRQs */
 
        /* level 1 IRQ: VIA1, always present */
@@ -184,17 +229,34 @@ void mac_init_IRQ(void)
 
        /* via2 or rbv?? */
        if (macintosh_config->via_type == MAC_VIA_IIci) {
-               /* VIA2 is part of the RBV: different base, other offsets */
-               via2_is_rbv = 1;
-               /* LC III weirdness: IFR seems to behave like VIA2 */
-               /* FIXME: maybe also for LC II ?? */ 
-               if (macintosh_config->ident == MAC_MODEL_LCIII) {
-                       rbv_clear = 0x0;
+               /*
+                * A word of caution: the definitions here only affect interrupt
+                * handling, see via6522.c for yet another file to change
+                * base addresses and RBV flags
+                */
+
+               /* yes, this is messy - the IIfx deserves a class of his own */
+               if (macintosh_config->ident == MAC_MODEL_IIFX) {
+                       /* no real VIA2, the OSS seems _very_different */       
+                       via2_is_oss = 1;
+                       /* IIfx has OSS, at a different base address than RBV */
+                       if (macintosh_config->ident == MAC_MODEL_IIFX)
+                               rbv_regp = (unsigned char *) OSS_BAS;
+                       sys_request_irq(2, oss_irq, IRQ_FLG_LOCK, "oss", oss_irq);
                } else {
-                       rbv_clear = 0x80;
+                       /* VIA2 is part of the RBV: different base, other offsets */
+                       via2_is_rbv = 1;
+
+                       /* LC III weirdness: IFR seems to behave like VIA2 */
+                       /* FIXME: maybe also for LC II ?? */ 
+                       if (macintosh_config->ident == MAC_MODEL_LCIII) {
+                               rbv_clear = 0x0;
+                       } else {
+                               rbv_clear = 0x80;
+                       }
+                       /* level 2 IRQ: RBV/OSS; we only care about RBV for now */
+                       sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq);
                }
-               /* level 2 IRQ: RBV/OSS; we only care about RBV for now */
-               sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq);
        } else
                /* level 2 IRQ: VIA2 */
                sys_request_irq(2, via2_irq, IRQ_FLG_LOCK, "via2", via2_irq);
@@ -205,7 +267,7 @@ void mac_init_IRQ(void)
         *              Currently, one interrupt per channel is used, solely
         *              to pass the correct async_info as parameter!
         */
-#if 0  /* doesn't seem to work yet */
+#if 0  /* want to install debug/SCC shutup routine until SCC init */
        sys_request_irq(4, mac_SCC_handler, IRQ_FLG_STD, "INT4", mac_SCC_handler);
 #else
        sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler);
@@ -253,24 +315,64 @@ void mac_init_IRQ(void)
        via_table[0]     =  via1_regp;
        handler_table[0] =  &via1_handler[0];
        param_table[0]   =  &via1_param[0];
+       mac_irqs[0]      =  &via1_irqs[0];
 
        if (via2_is_rbv) {
                via_table[1]     =  rbv_regp;
                handler_table[1] =  &rbv_handler[0];
                param_table[1]   =  &rbv_param[0];
+               mac_irqs[1]      =  &rbv_irqs[0];
        } else {
                via_table[1]     =  via2_regp;
                handler_table[1] =  &via2_handler[0];
                param_table[1]   =  &via2_param[0];
+               mac_irqs[1]      =  &via2_irqs[0];
        }
        via_table[2]     =  NULL;
        via_table[3]     =  NULL;
        
        handler_table[2] =   &rbv_handler[0];
-       handler_table[3] = &nubus_handler[0];
+       handler_table[3] =  &scc_handler[0];
+       handler_table[4] =  NULL;
+       handler_table[5] =  NULL;
+       handler_table[6] =  NULL;
+       handler_table[7] = &nubus_handler[0];
 
        param_table[2]   =   &rbv_param[0];
-       param_table[3]   = &nubus_param[0];
+       param_table[3]   =  &scc_param[0];
+       param_table[7]   = &nubus_param[0];
+
+       mac_irqs[2]      =  &rbv_irqs[0];
+       mac_irqs[3]      =  &scc_irqs[0];
+       mac_irqs[7]      =  &nubus_irqs[0];
+
+       /*
+        *      AV Macs: shutup the PSC ints
+        */
+       if (macintosh_config->ident == MAC_MODEL_C660
+        || macintosh_config->ident == MAC_MODEL_Q840) {
+               psc_init();
+
+               handler_table[2] = &psc3_handler[0];
+               /* handler_table[3] = &psc4_handler[0]; */
+               handler_table[4] = &psc5_handler[0];
+               handler_table[5] = &psc6_handler[0];
+
+               param_table[2]   = &psc3_param[0];
+               /* param_table[3]   = &psc4_param[0]; */
+               param_table[4]   = &psc5_param[0];
+               param_table[5]   = &psc6_param[0];
+
+               mac_irqs[2]      = &psc3_irqs[0]; 
+               /* mac_irqs[3]   = &psc4_irqs[0]; */
+               mac_irqs[4]      = &psc5_irqs[0];
+               mac_irqs[5]      = &psc6_irqs[0];
+
+               sys_request_irq(3, psc_irq, IRQ_FLG_STD, "PSC3", psc_irq);
+               sys_request_irq(4, psc_irq, IRQ_FLG_STD, "PSC4", psc_irq);
+               sys_request_irq(5, psc_irq, IRQ_FLG_STD, "PSC5", psc_irq);
+               sys_request_irq(6, psc_irq, IRQ_FLG_STD, "PSC6", psc_irq);
+       }
 
 #ifdef DEBUG_MACINTS
        printk("Mac interrupt init done!\n");
@@ -281,7 +383,7 @@ void mac_init_IRQ(void)
  *     We have no machine specific interrupts on a macintoy
  *      Yet, we need to register/unregister interrupts ... :-)
  *      Currently unimplemented: Test for valid irq number, chained irqs,
- *      Nubus interrupts.
+ *      Nubus interrupts (use nubus_request_irq!).
  */
  
 int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
@@ -312,8 +414,8 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re
                return -EINVAL;
        } 
 
-       /* figure out if SCC pseudo-irq */
-        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) {
+       /* figure out if SCC pseudo-irq (redundant ??) */
+        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) {
                /* set specific SCC handler */
                scc_handler[irqidx].handler = handler;
                scc_handler[irqidx].dev_id  = dev_id;
@@ -323,6 +425,8 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re
                return 0;
        } 
 
+       /* add similar hack for Nubus pseudo-irq here - hide nubus_request_irq */
+
        via         = (volatile unsigned char *) via_table[srcidx];
        if (!via) 
                return -EINVAL;
@@ -338,9 +442,11 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re
        via_param[irqidx].flags     = flags;
        via_param[irqidx].devname   = devname;
 
-       /* and turn it on ... */
+       /* and turn it on ... careful, that's VIA only ... */
        if (srcidx == SRC_VIA2 && via2_is_rbv)
                via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
+       else if (srcidx == SRC_VIA2 && via2_is_oss)
+               via_write(oss_regp, oss_map[irqidx]+8, 2);
        else
                via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
 
@@ -348,8 +454,18 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re
        if (irq == IRQ_IDX(IRQ_MAC_SCSI)) {
                /*
                 * Set vPCR for SCSI interrupts. (what about RBV here?)
+                * 980429 MS: RBV is ok, OSS seems to be differentt
                 */
-               via_write(via, vPCR, 0x66);
+               if (!via2_is_oss)
+                       /* CB2 (IRQ) indep. interrupt input, positive edge */
+                       /* CA2 (DRQ) indep. interrupt input, positive edge */
+                       via_write(via, vPCR, 0x66);
+#if 0
+               else
+                       /* CB2 (IRQ) indep. interrupt input, negative edge */
+                       /* CA2 (DRQ) indep. interrupt input, negative edge */
+                       via_write(via, vPCR, 0x22);
+#endif
        }
 
        return 0;
@@ -379,7 +495,7 @@ void mac_free_irq (unsigned int irq, void *dev_id)
        cli();
 
        /* figure out if SCC pseudo-irq */
-        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) {
+        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) {
                /* clear specific SCC handler */
                scc_handler[irqidx].handler = mac_default_handler;
                scc_handler[irqidx].dev_id  = NULL;
@@ -408,6 +524,8 @@ void mac_free_irq (unsigned int irq, void *dev_id)
        /* and turn it off */
        if (srcidx == SRC_VIA2 && via2_is_rbv)
                via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
+       else if (srcidx == SRC_VIA2 && via2_is_oss)
+               via_write(oss_regp, oss_map[irqidx]+8, 0);
        else
                via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
 
@@ -450,8 +568,8 @@ not_found:
 
 void mac_enable_irq (unsigned int irq)
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+       int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+       int irqidx = (irq & IRQ_IDX_MASK);
 
        irq_flags[srcidx].disabled &= ~(1<<irqidx);
        /*
@@ -465,8 +583,8 @@ void mac_enable_irq (unsigned int irq)
 
 void mac_disable_irq (unsigned int irq)
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+       int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+       int irqidx = (irq & IRQ_IDX_MASK);
 
        irq_flags[srcidx].disabled |= (1<<irqidx);
 }
@@ -478,8 +596,8 @@ void mac_disable_irq (unsigned int irq)
 
 void mac_turnon_irq( unsigned int irq )
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+       int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+       int irqidx = (irq & IRQ_IDX_MASK);
        volatile unsigned char *via;
 
        via         = (volatile unsigned char *) via_table[srcidx];
@@ -488,6 +606,11 @@ void mac_turnon_irq( unsigned int irq )
 
        if (srcidx == SRC_VIA2 && via2_is_rbv)
                via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
+       else if (srcidx == SRC_VIA2 && via2_is_oss)
+               via_write(oss_regp, oss_map[irqidx]+8, 2);
+       else if (srcidx >= SRC_VIA2)
+               via_write(via, (0x104 + 0x10*srcidx), 
+                       via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx)));
        else
                via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
 
@@ -495,8 +618,8 @@ void mac_turnon_irq( unsigned int irq )
 
 void mac_turnoff_irq( unsigned int irq )
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+       int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+       int irqidx = (irq & IRQ_IDX_MASK);
        volatile unsigned char *via;
 
        via         = (volatile unsigned char *) via_table[srcidx];
@@ -505,6 +628,11 @@ void mac_turnoff_irq( unsigned int irq )
 
        if (srcidx == SRC_VIA2 && via2_is_rbv)
                via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
+       else if (srcidx == SRC_VIA2 && via2_is_oss)
+               via_write(oss_regp, oss_map[irqidx]+8, 0);
+       else if (srcidx >= SRC_VIA2)
+               via_write(via, (0x104 + 0x10*srcidx), 
+                       via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx)));
        else
                via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
 }
@@ -519,23 +647,91 @@ void mac_turnoff_irq( unsigned int irq )
 
 void mac_clear_pending_irq( unsigned int irq )
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+       int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+       int irqidx = (irq & IRQ_IDX_MASK);
 
        irq_flags[srcidx].pending &= ~(1<<irqidx);
 }
 
 int  mac_irq_pending( unsigned int irq )
 {
-        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-        int irqidx = (irq & IRQ_IDX_MASK);
+       int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+       int irqidx = (irq & IRQ_IDX_MASK);
 
        return (irq_flags[srcidx].pending & (1<<irqidx));
 }
 
 int mac_get_irq_list (char *buf)
 {
-       return 0;
+       int i, len = 0;
+       int srcidx, irqidx;
+
+       for (i = VIA1_SOURCE_BASE; i < NUM_MAC_SOURCES+8; ++i) {
+               srcidx = ((i & IRQ_SRC_MASK)>>3) - 1;
+               irqidx = (i & IRQ_IDX_MASK);
+
+               /*
+                * Not present: skip
+                */
+
+               if (mac_irqs[srcidx] == NULL)
+                       continue;
+
+               /* 
+                * never used by VIAs, unused by others so far, counts 
+                * the magic 'nothing pending' cases ...
+                */
+               if (irqidx == 7 && mac_irqs[srcidx][irqidx]) {
+                       len += sprintf(buf+len, "Level %01d: %10u (spurious) \n",
+                                      srcidx, 
+                                      mac_irqs[srcidx][irqidx]);
+                       continue;
+               }
+
+               /*
+                * Nothing registered for this IPL: skip
+                */
+
+               if (handler_table[srcidx] == NULL)
+                       continue;
+
+               /*
+                * No handler installed: skip
+                */ 
+
+               if (handler_table[srcidx][irqidx].handler == mac_default_handler ||
+                   handler_table[srcidx][irqidx].handler == nubus_wtf)
+                       continue;
+
+
+               if (i < VIA2_SOURCE_BASE)
+                       len += sprintf(buf+len, "via1  %01d: %10u ",
+                                      irqidx,
+                                      mac_irqs[srcidx][irqidx]);
+               else if (i < RBV_SOURCE_BASE)
+                       len += sprintf(buf+len, "via2  %01d: %10u ",
+                                      irqidx,
+                                      mac_irqs[srcidx][irqidx]);
+               else if (i < MAC_SCC_SOURCE_BASE)
+                       len += sprintf(buf+len, "rbv   %01d: %10u ",
+                                      irqidx,
+                                      mac_irqs[srcidx][irqidx]);
+               else if (i < NUBUS_SOURCE_BASE)
+                       len += sprintf(buf+len, "scc   %01d: %10u ",
+                                      irqidx,
+                                      mac_irqs[srcidx][irqidx]);
+               else /* Nubus */
+                       len += sprintf(buf+len, "nubus %01d: %10u ",
+                                      irqidx,
+                                      mac_irqs[srcidx][irqidx]);
+
+                       len += sprintf(buf+len, "%s\n", 
+                                      param_table[srcidx][irqidx].devname);
+
+       }
+       if (num_spurious)
+               len += sprintf(buf+len, "spurio.: %10u\n", num_spurious);
+       return len;
 }
 
 void via_scsi_clear(void)
@@ -544,6 +740,9 @@ void via_scsi_clear(void)
        if (via2_is_rbv) {
                via_write(rbv_regp, rIFR, (1<<3)|(1<<0)|0x80);
                deep_magic = via_read(rbv_regp, rBufB);
+       } else if (via2_is_oss) {
+               /* nothing */
+               /* via_write(oss_regp, 9, 0) */;
        } else
                deep_magic = via_read(via2_regp, vBufB);
        mac_enable_irq( IRQ_IDX(IRQ_MAC_SCSI) );
@@ -567,12 +766,24 @@ void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
        }
 }
 
+void scsi_mac_debug(void);
+void scsi_mac_polled(void);
+
 void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
 {
+       int i;
        /* 
         * generate debug output on NMI switch if 'debug' kernel option given
         * (only works with Penguin!)
         */
+#if 0
+       scsi_mac_debug();
+       printk("PC: %08lx\nSR: %04x  SP: %p\n", fp->pc, fp->sr, fp);
+#endif
+       for (i=0; i<100; i++)
+               udelay(1000);
+       scsi_mac_polled();
+
        if ( console_loglevel >= 8 ) {
 #if 0
                show_state();
@@ -607,6 +818,7 @@ static void via_irq(unsigned char *via, int *viaidx, struct pt_regs *regs)
        int ct = 0;
        struct irqhandler *via_handler = handler_table[*viaidx];
        struct irqparam   *via_param   = param_table[*viaidx];
+       unsigned long     *via_irqs    = mac_irqs[*viaidx];
 
        /* to be changed, possibly: for each non'masked', enabled IRQ, read 
         * flag bit, ack and call handler ...
@@ -623,7 +835,12 @@ static void via_irq(unsigned char *via, int *viaidx, struct pt_regs *regs)
         
        if(events==0)
        {
-               printk("via%d_irq: nothing pending!\n", *viaidx + 1);
+#ifdef DEBUG_VIA
+               /* should go away; mostly missing timer ticks and ADB events */
+               printk("via%d_irq: nothing pending, flags %x mask %x!\n",
+                       *viaidx + 1, via_read(via, vIFR), via_read(via,vIER));
+#endif
+               via_irqs[7]++;
                return;
        }
 
@@ -658,9 +875,12 @@ static void via_irq(unsigned char *via, int *viaidx, struct pt_regs *regs)
                        /* call corresponding handlers */
                        if (events&(1<<i)) {
                                if (irq_flags[*viaidx].disabled & (1<<i)) {
+                                       if (!irq_flags[*viaidx].pending&(1<<i))
+                                               via_irqs[i]++;
                                        /* irq disabled -> mark pending */
                                        irq_flags[*viaidx].pending |= (1<<i);
                                } else {
+                                       via_irqs[i]++;
                                        /* irq enabled -> call handler */
                                        (via_handler[i].handler)(irq, via, regs);
                                }
@@ -683,7 +903,9 @@ static void via_irq(unsigned char *via, int *viaidx, struct pt_regs *regs)
                ct++;
                if(events && ct>8)
                {
+#ifdef DEBUG_VIA
                        printk("via%d: stuck events %x\n", (*viaidx)+1, events);
+#endif
                        break;
                }
        }
@@ -740,6 +962,23 @@ void rbv_irq(int irq, void *dev_id, struct pt_regs *regs)
        struct irqhandler *via_handler = handler_table[srcidx];
        struct irqparam   *via_param   = param_table[srcidx];
 
+        /* shouldn't we disable interrupts here ?? */
+
+       
+       /*
+        *      Shouldnt happen
+        */
+        
+       if(events==0)
+       {
+#ifdef DEBUG_VIA
+               printk("rbv_irq: nothing pending, flags %x mask %x!\n",
+                       via_read(via, rIFR), via_read(via,rIER));
+#endif
+               rbv_irqs[7]++;
+               return;
+       }
+
 #ifdef DEBUG_VIA       
        /*
         * limited verbosity for RBV interrupts (add more if needed)
@@ -754,19 +993,6 @@ void rbv_irq(int irq, void *dev_id, struct pt_regs *regs)
         * If ack for masked IRQ required: keep 'pending' info separate.
         */
 
-        /* shouldn't we disable interrupts here ?? */
-
-       
-       /*
-        *      Shouldnt happen
-        */
-        
-       if(events==0)
-       {
-               printk("rbv_irq: nothing pending!\n");
-               return;
-       }
-       
        do {
                /*
                 *      Clear the pending flag
@@ -784,12 +1010,16 @@ void rbv_irq(int irq, void *dev_id, struct pt_regs *regs)
                        int irq = (srcidx+1)* 8 + i;
                        /* call corresponding handlers */
                        if (events&(1<<i)) {
-                               if (irq_flags[srcidx].disabled & (1<<i))
+                               if (irq_flags[srcidx].disabled & (1<<i)) {
+                                       if (!irq_flags[srcidx].pending&(1<<i))
+                                               rbv_irqs[i]++;
                                        /* irq disabled -> mark pending */
                                        irq_flags[srcidx].pending |= (1<<i);
-                               else
+                               } else {
+                                       rbv_irqs[i]++;
                                        /* irq enabled -> call handler */
                                        (via_handler[i].handler)(irq, via, regs);
+                               }
                        }
                        /* and call handlers for pending irqs - first ?? */
                        if (    (irq_flags[srcidx].pending  & (1<<i))
@@ -800,7 +1030,7 @@ void rbv_irq(int irq, void *dev_id, struct pt_regs *regs)
                                irq_flags[srcidx].pending  &= ~(1<<i);
                        }
                }
-       
+
                /*
                 *      And done ... check for more punishment!
                 */
@@ -840,23 +1070,276 @@ void via_wtf(int slot, void *via, struct pt_regs *regs)
 #endif
 }
 
+/*
+ *     Nubus / SCSI interrupts; OSS style
+ *     The OSS is even more different than the RBV. OSS appears to stand for 
+ *     Obscenely Screwed Silicon ... 
+ *
+ *     Latest NetBSD sources suggest the OSS should behave like a RBV, but 
+ *     that's probably true for the 0x203 offset (Nubus/ADB-SWIM IOP) at best
+ */
+void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int srcidx = IRQ_IDX(irq) - 1;  /* MUST be 1 !! */
+       volatile unsigned char *via = oss_regp;
+       unsigned char events=(via_read(via, oIFR))&0x03;
+       unsigned char nub_ev=(via_read(via, nIFR))&0x4F;
+       unsigned char adb_ev;
+       int i;
+       int ct = 0;
+       struct irqhandler *via_handler = handler_table[srcidx];
+       struct irqparam   *via_param   = param_table[srcidx];
+
+        /* shouldn't we disable interrupts here ?? */
+
+       adb_ev = nub_ev & 0x40;
+       nub_ev &= 0x3F;
+
+       /*
+        *      Shouldnt happen
+        */
+
+       if (events==0 && adb_ev==0 && nub_ev==0)
+       {
+               printk("oss_irq: nothing pending, flags %x %x!\n",
+                       via_read(via, oIFR), via_read(via, nIFR));
+               rbv_irqs[7]++;
+               return;
+       }
+
+#ifdef DEBUG_VIA       
+       /*
+        * limited verbosity for RBV interrupts (add more if needed)
+        */
+       if ( events != 1<<3 )           /* SCSI IRQ */
+               printk("oss_irq: irq %d events %x %x %x !\n", irq, srcidx+1, 
+                       events, adb_ev, nub_ev);
+#endif
+
+       /* 
+        * OSS priorities: call ADB handler first if registered, other events,
+        * then Nubus 
+        * ADB: yet to be implemented!
+        */
+
+       /*
+        * ADB: try to shutup the IOP 
+        */
+       if (adb_ev) {
+               printk("Hands off ! Don't press this button ever again !!!\n");
+               via_write(via, 6, 0);
+       }
+
+       do {
+               /*
+                *      Clear the pending flags
+                *      How exactly is that supposed to work ??
+                */
+
+               /*
+                *      Now see what bits are raised
+                */
+                
+               for(i=0;i<7;i++)
+               {
+                       /* HACK HACK: map to bit number in OSS register */
+                       int irqidx = oss_map[i];
+                       /* determine machspec. irq no. */
+                       int irq = (srcidx+1)* 8 + i;
+                       /* call corresponding handlers */
+                       if ( (events&(1<<irqidx)) &&            /* bit set*/
+                            (via_read(via, irqidx+8)&0x7) ) {  /* irq enabled */
+                               if (irq_flags[srcidx].disabled & (1<<i)) {
+                                       if (!irq_flags[srcidx].pending&(1<<i))
+                                               rbv_irqs[i]++;
+                                       /* irq disabled -> mark pending */
+                                       irq_flags[srcidx].pending |= (1<<i);
+                               } else {
+                                       rbv_irqs[i]++;
+                                       /* irq enabled -> call handler */
+                                       (via_handler[i].handler)(irq, via, regs);
+                               }
+                       }
+                       /* and call handlers for pending irqs - first ?? */
+                       if (    (irq_flags[srcidx].pending  & (1<<i))
+                           && !(irq_flags[srcidx].disabled & (1<<i)) ) {
+                               /* call handler for re-enabled irq */
+                               (via_handler[i].handler)(irq, via, regs);
+                               /* and clear pending flag :-) */
+                               irq_flags[srcidx].pending  &= ~(1<<i);
+                       }
+               }
+       
+               /*
+                *      And done ... check for more punishment!
+                */
+
+               events=(via_read(via, oIFR)/*&via_read(via,rIER)*/)&0x03;
+               ct++;
+               if(events && ct>8)
+               {
+                       printk("oss: stuck events %x\n",events);
+                       for(i=0;i<7;i++)
+                       {
+                               if(events&(1<<i))
+                               {
+                                       printk("oss - bashing source %d\n",
+                                               i);
+                                       /* that should disable it */
+                                       via_write(via, 8+i, 0);
+                               }
+                       }
+                       break;
+               }
+       }
+       while(events);
+#if 0
+       scsi_mac_polled();
+#endif
+
+       if (nub_ev)
+               oss_do_nubus(irq, via, regs);
+
+}
+
+/*
+ *     Unexpected slot interrupt
+ */
 void nubus_wtf(int slot, void *via, struct pt_regs *regs)
 {
-#ifdef DEBUG_VIA
+#ifdef DEBUG_VIA_NUBUS
        printk("Unexpected interrupt on nubus slot %d\n",slot);
 #endif
 }
 
+/*
+ *     SCC master interrupt handler; sole purpose: pass the registered 
+ *     async struct to the SCC handler proper.
+ */
+
 void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
        int i;
-
-       for (i = 0; i < 8; i++) 
+                               /* 1+2: compatibility with PSC ! */
+       for (i = 1; i < 3; i++) /* currently only these two used */
                if (scc_handler[i].handler != mac_default_handler)
                        (scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
 
 }
 
+/*
+ *     PSC interrupt handler
+ */
+
+void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int srcidx = IRQ_IDX(irq) - 1;
+       volatile unsigned char *via = psc_regp;
+       unsigned int pIFR = 0x100 + 0x10*srcidx;
+       unsigned int pIER = 0x104 + 0x10*srcidx;
+       unsigned char events=(via_read(via, pIFR)&via_read(via,pIER))&0xF;
+       int i;
+       int ct = 0;
+       struct irqhandler *via_handler = handler_table[srcidx];
+       struct irqparam   *via_param   = param_table[srcidx];
+
+        /* shouldn't we disable interrupts here ?? */
+
+       
+       /*
+        *      Shouldnt happen
+        */
+        
+       if(events==0)
+       {
+#ifdef DEBUG_VIA
+               printk("rbv_irq: nothing pending, flags %x mask %x!\n",
+                       via_read(via, pIFR), via_read(via,pIER));
+#endif
+               mac_irqs[srcidx][7]++;
+               return;
+       }
+
+#ifdef DEBUG_VIA       
+       /*
+        * limited verbosity for RBV interrupts (add more if needed)
+        */
+       if ( srcidx == 1 && events != 1<<3 && events != 1<<1 )          /* SCSI IRQ */
+               printk("psc_irq: irq %d events %x !\n", irq, srcidx+1, events);
+#endif
+
+       /* to be changed, possibly: for each non'masked', enabled IRQ, read 
+        * flag bit, ack and call handler ...
+         * Currently: all pending irqs ack'ed en bloc.
+        * If ack for masked IRQ required: keep 'pending' info separate.
+        */
+
+       do {
+               /*
+                *      Clear the pending flag
+                */
+                
+               /* via_write(via, pIFR, events); */
+                
+               /*
+                *      Now see what bits are raised
+                */
+                
+               for(i=0;i<7;i++)
+               {
+                       /* determine machspec. irq no. */
+                       int irq = (srcidx+1)* 8 + i;
+                       /* call corresponding handlers */
+                       if (events&(1<<i)) {
+                               if (irq_flags[srcidx].disabled & (1<<i)) {
+                                       if (!irq_flags[srcidx].pending&(1<<i))
+                                               mac_irqs[srcidx][i]++;
+                                       /* irq disabled -> mark pending */
+                                       irq_flags[srcidx].pending |= (1<<i);
+                               } else {
+                                       mac_irqs[srcidx][i]++;
+                                       /* irq enabled -> call handler */
+                                       (via_handler[i].handler)(irq, via, regs);
+                               }
+                       }
+                       /* and call handlers for pending irqs - first ?? */
+                       if (    (irq_flags[srcidx].pending  & (1<<i))
+                           && !(irq_flags[srcidx].disabled & (1<<i)) ) {
+                               /* call handler for re-enabled irq */
+                               (via_handler[i].handler)(irq, via, regs);
+                               /* and clear pending flag :-) */
+                               irq_flags[srcidx].pending  &= ~(1<<i);
+                       }
+               }
+
+               /*
+                *      And done ... check for more punishment!
+                */
+
+               events=(via_read(via,pIFR)&via_read(via,pIER))&0x7F;
+               ct++;
+               if(events && ct>8)
+               {
+                       printk("psc: stuck events %x\n",events);
+                       for(i=0;i<7;i++)
+                       {
+                               if(events&(1<<i))
+                               {
+                                       printk("psc - bashing source %d\n",
+                                               i);
+                                       via_write(via, pIER, 1<<i);
+                                       /* via_write(via, pIFR, (1<<i)); */
+                               }
+                       }
+                       break;
+               }
+       }
+       while(events);
+}
+
+
 /*
  *     Nubus handling
  *      Caution: slot numbers are currently 'hardcoded' to the range 9-15!
@@ -875,16 +1358,17 @@ int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct
        nubus_handler[slot].handler=handler;
        nubus_handler[slot].dev_id =dev_id;
        nubus_param[slot].flags    = IRQ_FLG_LOCK;
-       nubus_param[slot].devname  = "nubus";
+       nubus_param[slot].devname  = "nubus slot";
 
        /* 
         * if no nubus int. was active previously: register the main nubus irq
         * handler now!
         */
 
-       if (!nubus_active)
-         request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK, 
-                     "nubus dispatch", via_do_nubus);
+       if (!nubus_active && !via2_is_oss) {
+               request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK, 
+                           "nubus dispatch", via_do_nubus);
+       }
 
        nubus_active|=1<<slot;
 /*     printk("program slot %d\n",slot);*/
@@ -894,7 +1378,9 @@ int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct
                via_read(via2, vDirA)|(1<<slot));
        via_write(via2, vBufA, 0);
 #endif         
-       if (!via2_is_rbv) {
+       if (via2_is_oss)
+               via_write(oss_regp, slot, 2);
+       else if (!via2_is_rbv) {
                /* Make sure the bit is an input */
                via_write(via2_regp, vDirA, 
                        via_read(via2_regp, vDirA)&~(1<<slot));
@@ -914,6 +1400,8 @@ int nubus_free_irq(int slot)
 
        if (via2_is_rbv)
                via_write(rbv_regp, rBufA, 1<<slot);
+       else if (via2_is_oss)
+               via_write(oss_regp, slot, 0);
        else {
                via_write(via2_regp, vDirA, 
                        via_read(via2_regp, vDirA)|(1<<slot));
@@ -924,6 +1412,16 @@ int nubus_free_irq(int slot)
        return 0;
 }
 
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+/*
+ * IDE interrupt hook
+ */
+extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
+#endif
+
+/*
+ * Nubus dispatch handler - VIA/RBV style
+ */
 static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
 {
        unsigned char map;
@@ -938,6 +1436,14 @@ static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
        else
                via_write(via2_regp, vIFR, 0x82);
        
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+       /* IDE hack */
+       if (mac_ide_intr_hook)
+               /* 'slot' is lacking the machspec bit in 2.0 */
+               /* need to pass proper dev_id = hwgroup here */
+               mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+#endif
+
        while(1)
        {
                if (via2_is_rbv)
@@ -945,15 +1451,23 @@ static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
                else
                        map = ~via_read(via2_regp, vBufA);
                
-#ifdef DEBUG_VIA
-               printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+               if( (map = (map&nubus_active)) ==0 ) {
+#ifdef DEBUG_NUBUS_INT
+                       printk("nubus_irq: nothing pending, map %x mask %x\n", 
+                               map, nubus_active);
 #endif
-               if( (map = (map&nubus_active)) ==0 )
+                       nubus_irqs[7]++;
                        break;
+               }
+#ifdef DEBUG_NUBUS_INT
+               printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+#endif
 
                if(ct++>2)
                {
+#ifdef DEBUG_NUBUS_INT
                        printk("nubus stuck events - %d/%d\n", map, nubus_active);
+#endif
                        return;
                }
 
@@ -961,6 +1475,7 @@ static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
                {
                        if(map&(1<<i))
                        {
+                               nubus_irqs[i]++;
                                (nubus_handler[i].handler)(i+9, nubus_handler[i].dev_id, regs);
                        }
                }
@@ -974,3 +1489,72 @@ static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
        
        /* And done */
 }
+
+/*
+ * Nubus dispatch handler - OSS style
+ */
+static void oss_do_nubus(int slot, void *via, struct pt_regs *regs)
+{
+       unsigned char map;
+       int i;
+       int ct=0;
+
+/*     printk("nubus interrupt\n");*/
+               
+#if 0
+       /* lock the nubus interrupt */
+       if (via2_is_rbv) 
+               via_write(rbv_regp, rIFR, 0x82);
+       else
+               via_write(via2_regp, vIFR, 0x82);
+#endif
+
+       /* IDE hack for Quadra: uses Nubus interrupt without any slot bit set */
+       if (mac_ide_intr_hook)
+               mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+       
+       while(1)
+       {
+               /* pending events */
+               map=(via_read(via, nIFR))&0x3F;
+               
+#ifdef DEBUG_VIA_NUBUS
+               printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+#endif
+               if( (map = (map&nubus_active)) ==0 ) {
+                       if (!mac_ide_intr_hook)
+                               printk("nubus_irq: nothing pending, map %x mask %x\n", 
+                                       map, nubus_active);
+                       nubus_irqs[7]++;
+                       break;
+               }
+
+               if(ct++>2)
+               {
+#if 0
+                       printk("nubus stuck events - %d/%d\n", map, nubus_active);
+#endif
+                       return;
+               }
+
+               for(i=0;i<7;i++)
+               {
+                       if(map&(1<<i))
+                       {
+                               nubus_irqs[i]++;
+                               /* call handler */
+                               (nubus_handler[i].handler)((i+9), nubus_handler[i].dev_id, regs);
+                               /* clear interrupt ?? */
+#if 0
+                               via_write(oss_regp, i, 0);
+#endif
+                       }
+               }
+               /* clear it */ 
+#if 0
+               via_write(oss_regp, nIFR, map);
+#endif
+       }
+       
+       /* And done */
+}
index f338253f3e1c1f5792d7c5562ffb8d8cd68bcb00..e1d2ab3e7caa32d43e5eea166fd1334e9d6b72bc 100644 (file)
@@ -600,13 +600,13 @@ __initfunc(int mac_keyb_init(void))
        volatile int ct;
 
        /* setup key map */
-       memcpy (plain_map, mac_plain_map, sizeof(plain_map));
-       memcpy(shift_map, mac_shift_map, sizeof(shift_map));
-       memcpy(altgr_map, mac_altgr_map, sizeof(altgr_map));
-       memcpy(ctrl_map, mac_ctrl_map, sizeof(ctrl_map));
-       memcpy(shift_ctrl_map, mac_shift_ctrl_map, sizeof(shift_ctrl_map));
-       memcpy(alt_map, mac_alt_map, sizeof(alt_map));
-       memcpy(ctrl_alt_map, mac_ctrl_alt_map, sizeof(ctrl_alt_map));
+       memcpy(key_maps[0], mac_plain_map, sizeof(plain_map));
+       memcpy(key_maps[1], mac_shift_map, sizeof(plain_map));
+       memcpy(key_maps[2], mac_altgr_map, sizeof(plain_map));
+       memcpy(key_maps[4], mac_ctrl_map, sizeof(plain_map));
+       memcpy(key_maps[5], mac_shift_ctrl_map, sizeof(plain_map));
+       memcpy(key_maps[8], mac_alt_map, sizeof(plain_map));
+       memcpy(key_maps[12], mac_ctrl_alt_map, sizeof(plain_map));
 
        /* initialize mouse interrupt hook */
        mac_mouse_interrupt_hook = NULL;
diff --git a/arch/m68k/mac/psc.h b/arch/m68k/mac/psc.h
new file mode 100644 (file)
index 0000000..964f654
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *     Apple Peripheral System Controller (PSC)
+ *
+ *     The PSC is used on the AV Macs to control IO functions not handled
+ *     by the VIAs (Ethernet, DSP, SCC).
+ */
+#define PSCBASE                0x50F31000
+
+#define pIFR3          0x130
+#define pIFR4          0x140
+#define pIFR5          0x150
+#define pIFR6          0x160
+
+#define pIER3          0x134
+#define pIER4          0x144
+#define pIER5          0x154
+#define pIER6          0x164
index d2a25ab130375315feda92c23d66b715e3a65c31..c464811d7a53178ff8a1437fb0fa453fed298f72 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  *     6522 Versatile Interface Adapter (VIA)
  *
@@ -6,6 +5,7 @@
  *     via them as are assorted bits and bobs - eg rtc, adb.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <asm/macintosh.h> 
 #include <asm/macints.h> 
 #include "via6522.h"
+#include "psc.h"
 
 volatile unsigned char *via1=(unsigned char *)VIABASE;
 volatile unsigned char *via2=(unsigned char *)VIABASE2;
+volatile unsigned char *psc=(unsigned char *)PSCBASE;
 
 unsigned char via1_clock, via1_datab;
 
 static int rbv=0;
+static int oss=0;
+
+extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
 
 /*
- * Debugging the VBL ints
+ * hardware reset vector
  */
-
-extern int console_loglevel;
+static void (*rom_reset)(void);
 
 /*
- *     VIA1 - hardwired vectors
+ * Timer defs.
  */
-
-#if 0 /* gone to macints.[ch] */
-extern void via_wtf(int slot, void *via, struct pt_regs *regs);
-static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs);
-
-extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
-
-static struct via_irq_tab via1_func_tab=
-{
-       {
-               via_wtf,        /* One second interrupt */
-               via_wtf,        /* Vblank */
-               via_wtf,        /* ADB data ready */
-               via_wtf,        /* ADB data */
-               via_wtf,        /* ADB clock */
-               via_wtf,
-               via_wtf,        /* Slot 6 is replaced by the timer */
-               via_wtf
-       }
-};
-
-static struct via_irq_tab via2_func_tab=
-{
-       {
-               via_wtf,
-               via_do_nubus,
-               via_wtf,
-               via_wtf,
-               via_wtf,
-               via_wtf,
-               via_wtf,
-               via_wtf
-       }
-};
-
-static struct via_irq_tab nubus_func_tab=
-{
-       {
-               via_wtf,
-               via_wtf,
-               via_wtf,
-               via_wtf,
-               via_wtf,
-               via_wtf,
-               via_wtf,
-               via_wtf
-       }
-};
-#endif
-
-extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
-
 #define MAC_CLOCK_TICK         (783300/HZ)     /* ticks per HZ */
 #define MAC_CLOCK_LOW          (MAC_CLOCK_TICK&0xFF)
 #define MAC_CLOCK_HIGH         (MAC_CLOCK_TICK>>8)
@@ -91,8 +43,6 @@ void via_init_clock(void (*func)(int, void *, struct pt_regs *))
 {
        unsigned char c;
 
-/*     mac_debugging_penguin(6);*/
-       
        switch(macintosh_config->via_type)
        {
                /*
@@ -102,6 +52,10 @@ void via_init_clock(void (*func)(int, void *, struct pt_regs *))
                        via1=(void *)0x50F00000;
                        via2=(void *)0x50F26000;
                        rbv=1;
+                       if (macintosh_config->ident == MAC_MODEL_IIFX) {
+                               via2=(void *)0x50F1A000;
+                               oss=1;
+                       }
                        break;
                /*
                 *      Quadra and early MacIIs agree on the VIA locations
@@ -162,7 +116,7 @@ void via_init_clock(void (*func)(int, void *, struct pt_regs *))
                via_write(via2,vT2CH,0);
                via_write(via2,vIER, 0x7F);      
        }
-       else
+       else if (oss==0)
        {
                /*
                 *      Init the RBV chip a bit
@@ -201,30 +155,18 @@ void via_init_clock(void (*func)(int, void *, struct pt_regs *))
        
        request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func);
 
-/*     mac_debugging_penguin(7);*/
-
        /* 
         * SE/30: disable video int. 
         * XXX: testing for SE/30 VBL
         */
 
-       if (macintosh_config->ident == MAC_MODEL_SE30 
-           && console_loglevel != 10) {
+       if (macintosh_config->ident == MAC_MODEL_SE30) {
                c = via_read(via1, vBufB);
                via_write(via1, vBufB, c|(0x40));
                c = via_read(via1, vDirB);
                via_write(via1, vDirB, c|(0x40));
        } 
 
-       /*
-        * XXX: use positive edge
-        */
-
-       if (console_loglevel == 10) {
-               c = via_read(via1, vPCR);
-               via_write(via1, vPCR, c|(0x1));
-       }
-
 #if 0 /* gone to mac_init_IRQ */
        /*
         * Set vPCR for SCSI interrupts.
@@ -237,172 +179,29 @@ void via_init_clock(void (*func)(int, void *, struct pt_regs *))
 
 }
 
-#if 0 /* moved to macints.c */
-
-static void via_irq(volatile unsigned char *via, struct via_irq_tab *irqtab,
-       struct pt_regs *regs)
-{
-       unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
-       int i;
-       int ct=0;       
-
-       /*
-        *      Shouldnt happen
-        */
-        
-       if(events==0)
-       {
-               printk("via_irq: nothing pending!\n");
-               return;
-       }
-
-       do {
-               /*
-                *      Clear the pending flag
-                */
-
-               /* HACK HACK - FIXME !!! - just testing some keyboard ideas */
-       
-               /* events&=~(1<<4); */           
-               via_write(via, vIFR, events);
-        
-               /*
-                *      Now see what bits are raised
-                */
-        
-               for(i=0;i<7;i++)
-               {
-                       if(events&(1<<i))
-                               (irqtab->vector[i])(i, via, regs);
-               }
-       
-               /*
-                *      And done..
-                */
-               events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
-               ct++;
-               if(events && ct>8)
-               {
-                       printk("via: stuck events %x\n",events);
-                       break;
-               }
-       }
-       while(events);
-
-       scsi_mac_polled();
-}
-
-/*
- *
- *     The RBV is different. RBV appears to stand for randomly broken
- *     VIA.
- */
-
-static void rbv_irq(volatile unsigned char *via, struct via_irq_tab *irqtab,
-       struct pt_regs *regs)
-{
-       unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
-       int i;
-       int ct=0;       
-
-       /*
-        *      Shouldnt happen
-        */
-        
-       if(events==0)
-       {
-               printk("rbv_irq: nothing pending!\n");
-               return;
-       }
-
-       do {
-               /*
-                *      Clear the pending flag
-                */
-
-               /* HACK HACK - FIXME !!! - just testing some keyboard ideas */
-       
-               /* events&=~(1<<4); */           
-               via_write(via, rIFR, events);
-        
-               /*
-                *      Now see what bits are raised
-                */
-        
-               for(i=0;i<7;i++)
-               {
-                       if(events&(1<<i))
-                               (irqtab->vector[i])(i, via, regs);
-               }
-       
-               /*
-                *      And done..
-                */
-               events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
-               ct++;
-               if(events && ct>8)
-               {
-                       printk("rbv: stuck events %x\n",events);
-                       for(i=0;i<7;i++)
-                       {
-                               if(events&(1<<i))
-                               {
-                                       printk("rbv - bashing source %d\n",
-                                               i);
-                                       via_write(via, rIER, i);
-                                       via_write(via, rIFR, i);
-                               }
-                       }
-                       break;
-               }
-       }
-       while(events);
-}
-
-/*
- *     System interrupts
- */
-
-void via1_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-       via_irq(via1, &via1_func_tab, regs);
-}
-
-/*
- *     Nubus interrupts
- */
-void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-/*     printk("via2 interrupt\n");*/
-       if(rbv)
-               rbv_irq(via2, &via2_func_tab, regs);
-       else
-               via_irq(via2, &via2_func_tab, regs);
-}
-
 /*
- *     Unexpected via interrupt
+ *     PSC (AV Macs; level 3-6): initialize interrupt enable registers
  */
-void via_wtf(int slot, volatile void *via, struct pt_regs *regs)
-{
-       printk("Unexpected event %d on via %p\n",slot,via);
-}
 
-void nubus_wtf(int slot, volatile void *via, struct pt_regs *regs)
+void psc_init(void)
 {
-       printk("Unexpected interrupt on nubus slot %d\n",slot);
+       via_write(psc, pIER3, 0x01);
+       via_write(psc, pIER4, 0x09);
+       via_write(psc, pIER4, 0x86);
+       via_write(psc, pIER5, 0x03);
+       via_write(psc, pIER6, 0x07);
 }
 
-#endif
-
 /*
  *     The power switch - yes its software!
  */
  
-void mac_reset(void)
+void mac_poweroff(void)
 {
+#if 0
+       /*
+        * Powerdown, for the Macs that support it
+        */
        if(rbv) {
                via_write(via2, rBufB, via_read(via2, rBufB)&~0x04);
        } else {
@@ -411,7 +210,38 @@ void mac_reset(void)
                /* Send a value of 0 on that line */
                via_write(via2,vBufB,via_read(via2,vBufB)&~0x04);
        }
+#endif
+       /* We should never make it this far... */
+       /* XXX - delay do we need to spin here ? */
+       while(1);       /* Just in case .. */
+}
+
+/* 
+ * Not all Macs support software power down; for the rest, just 
+ * try the ROM reset vector ...
+ */
+void mac_reset(void)
+{
+       unsigned long flags;
+       unsigned long *reset_hook;
+
+       save_flags(flags);
+       cli();
+
+#if 0  /* need ROMBASE in booter */
+#if 0  /* works on some */
+       rom_reset = (boot_info.bi_mac.rombase + 0xa);
+#else  /* testing, doesn't work on SE/30 either */
+       reset_hook = (unsigned long *) (boot_info.bi_mac.rombase + 0x4);
+       printk("ROM reset hook: %p\n", *reset_hook);
+       rom_reset = *reset_hook;
+#endif
+       rom_reset();
+#endif
+       restore_flags(flags);
+
        /* We never make it this far... */
+       printk(" reboot failed, reboot manually!\n");
        /* XXX - delay do we need to spin here ? */
        while(1);       /* Just in case .. */
 }
@@ -442,140 +272,13 @@ void via1_set_head(int head)
                via_write(via1, vBufA, via_read(via1, vBufA)|0x20);
 }
 
-#if 0 /* moved to macints.c */
-
-
-/*
- *    Set up the SCSI
- */
-
-void via_scsi_disable(void)
-{
-       if (rbv)
-               via_write(via2, rIER, (1<<3)|(1<<0));
-       else
-               via_write(via2, vIER, (1<<3)|(1<<0));
-}
-
-void via_scsi_enable(void)
-{
-       if (rbv)
-               via_write(via2, rIER, (1<<3)|(1<<0)|0x80);
-       else
-               via_write(via2, vIER, (1<<3)|(1<<0)|0x80);
-}
-
-void via_scsi_clear(void)
-{
-        if (rbv) 
-               via_write(via2, rIFR, (1<<3)|(1<<0)|0x80);
-       volatile unsigned char deep_magic=via_read(via2, vBufB);
-       via_scsi_enable();
-}
-void via_setup_scsi(void (*handler)(int,volatile void *,struct pt_regs *))
-{
-       via2_func_tab.vector[0]=handler;        /* SCSI DRQ */
-       via2_func_tab.vector[3]=handler;        /* SCSI IRQ */
-       via_write(via2, vPCR, 0x66);            /* Edge direction! */
-       via_scsi_enable();
-}
-
-/*
- *     Nubus handling
- */
-static int nubus_active=0;
-int nubus_request_irq(int slot, void (*handler)(int,void *,struct pt_regs *))
-{
-       slot-=9;
-/*     printk("Nubus request irq for slot %d\n",slot);*/
-       if(nubus_func_tab.vector[slot]==nubus_wtf)
-               return -EBUSY;
-       nubus_func_tab.vector[slot]=handler;
-       nubus_active|=1<<slot;
-/*     printk("program slot %d\n",slot);*/
-/*     printk("via2=%p\n",via2);*/
-#if 0
-       via_write(via2, vDirA, 
-               via_read(via2, vDirA)|(1<<slot));
-       via_write(via2, vBufA, 0);
-#endif         
-       if (!rbv) {
-       /* Make sure the bit is an input */
-       via_write(via2, vDirA, 
-               via_read(via2, vDirA)&~(1<<slot));
-       }
-/*     printk("nubus irq on\n");*/
-       return 0;
-}
-
-int nubus_free_irq(int slot)
-{
-       slot-=9;
-       nubus_active&=~(1<<slot);
-       nubus_func_tab.vector[slot]=nubus_wtf;
-       if (rbv) {
-               via_write(via2, rBufA, 1<<slot);
-       } else {
-               via_write(via2, vDirA, 
-                       via_read(via2, vDirA)|(1<<slot));
-               via_write(via2, vBufA, 1<<slot);
-               via_write(via2, vDirA, 
-                       via_read(via2, vDirA)&~(1<<slot));
-       }
-       return 0;
-}
-
-static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs)
-{
-       unsigned char map;
-       int i;
-       int ct=0;
-
-/*     printk("nubus interrupt\n");*/
-               
-       if (rbv) {
-               via_write(via2, rIFR, 0x82);    /* lock the nubus interrupt */
-       } else {
-               via_write(via2, vIFR, 0x82);    /* lock the nubus interrupt */
-               
-       while(1)
-       {
-               if(rbv)
-                       map=~via_read(via2, rBufA);
-               else
-                       map=~via_read(via2, vBufA);
-               if((map=(map&nubus_active))==0)
-                       break;
-               if(ct++>2)
-               {
-                       printk("nubus stuck events - %d/%d\n", map, nubus_active);
-                       return;
-               }
-               for(i=0;i<7;i++)
-               {
-                       if(map&(1<<i))
-                       {
-                               (nubus_func_tab.vector[i])(i+9, via, regs);
-                       }
-               }
-               if (rbv)
-                       via_write(via2, rIFR, 0x02);    /* clear it */
-               else
-                       via_write(via2, vIFR, 0x02);    /* clear it */
-       }
-       
-       /* And done */
-}
-#endif
-
 void nubus_init_via(void)
 {
        if (rbv) {
-               via_write(via2, rBufB, via_read(via2, rBufB)|0x02);
-               via_write(via2, rIER, 0x82);    /* Interrupts on */
+               if (oss==0) {
+                       via_write(via2, rBufB, via_read(via2, rBufB)|0x02);
+                       via_write(via2, rIER, 0x82);    /* Interrupts on */
+               }
        } else {
                /* Assert the nubus active */
                via_write(via2, vDirB, via_read(via2, vDirB)|0x02);
@@ -584,7 +287,13 @@ void nubus_init_via(void)
                /* via_write(via2, vDirA, 0xFF); */
                via_write(via2, vIER, 0x82);    /* Interrupts on */
        }
-       printk("BTW  boot via1 acr=%X datab=%X pcr=%X\n",
-               (int)via1_clock, (int)via1_datab, (int)via_read(via1, vPCR));
-}
 
+       printk("nubus_init_via: via1 acr=%X datab=%X pcr=%X\n",
+               (int)via_read(via1, vACR), (int)via_read(via1, vBufB), 
+               (int)via_read(via1, vPCR));
+
+       if (rbv==0)
+               printk("nubus_init_via: via2 acr=%X datab=%X pcr=%X\n",
+                       (int)via_read(via2, vACR), (int)via_read(via2, vBufB), 
+                       (int)via_read(via2, vPCR));
+}
index 2ad15d8610f45ca00b8ff393b84d7ea00cceb974..54f0fae1aaf9795b749cd7b4e473830508ca34ce 100644 (file)
@@ -8,6 +8,6 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS  := init.o fault.o memory.o kmap.o extable.o
+O_OBJS  := init.o fault.o memory.o kmap.o extable.o hwtest.o
 
 include $(TOPDIR)/Rules.make
index aecbe0a5da724e96c0693199b08abca45260e167..f9fd457157dc47cc024166b296b725fcf1a215b1 100644 (file)
@@ -48,6 +48,8 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
        vma = find_vma(mm, address);
        if (!vma)
          goto bad_area;
+       if (vma->vm_flags & VM_IO)
+               goto bad_area;
        if (vma->vm_start <= address)
                goto good_area;
        if (!(vma->vm_flags & VM_GROWSDOWN))
diff --git a/arch/m68k/mm/hwtest.c b/arch/m68k/mm/hwtest.c
new file mode 100644 (file)
index 0000000..60ad5e8
--- /dev/null
@@ -0,0 +1,81 @@
+/* Tests for presence or absence of hardware registers.
+ * This code was originally in atari/config.c, but I noticed
+ * that it was also in drivers/nubus/nubus.c and I wanted to
+ * use it in hp300/config.c, so it seemed sensible to pull it
+ * out into its own file.
+ * 
+ * The test is for use when trying to read a hardware register
+ * that isn't present would cause a bus error. We set up a 
+ * temporary handler so that this doesn't kill the kernel.
+ *
+ * There is a test-by-reading and a test-by-writing; I present
+ * them here complete with the comments from the original atari
+ * config.c...
+ *                -- PMM <pmaydell@chiark.greenend.org.uk>, 05/1998
+ */
+
+/* This function tests for the presence of an address, specially a
+ * hardware register address. It is called very early in the kernel
+ * initialization process, when the VBR register isn't set up yet. On
+ * an Atari, it still points to address 0, which is unmapped. So a bus
+ * error would cause another bus error while fetching the exception
+ * vector, and the CPU would do nothing at all. So we needed to set up
+ * a temporary VBR and a vector table for the duration of the test.
+ */
+
+int hwreg_present( volatile void *regp )
+{
+    int        ret = 0;
+    long       save_sp, save_vbr;
+    long       tmp_vectors[3];
+
+    __asm__ __volatile__
+       (       "movec  %/vbr,%2\n\t"
+               "movel  #Lberr1,%4@(8)\n\t"
+                "movec %4,%/vbr\n\t"
+               "movel  %/sp,%1\n\t"
+               "moveq  #0,%0\n\t"
+               "tstb   %3@\n\t"  
+               "nop\n\t"
+               "moveq  #1,%0\n"
+                "Lberr1:\n\t"
+               "movel  %1,%/sp\n\t"
+               "movec  %2,%/vbr"
+               : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
+               : "a" (regp), "a" (tmp_vectors)
+                );
+
+    return( ret );
+}
+  
+/* Basically the same, but writes a value into a word register, protected
+ * by a bus error handler. Returns 1 if successful, 0 otherwise.
+ */
+
+int hwreg_write( volatile void *regp, unsigned short val )
+{
+       int             ret;
+       long    save_sp, save_vbr;
+       long    tmp_vectors[3];
+
+       __asm__ __volatile__
+       (       "movec  %/vbr,%2\n\t"
+               "movel  #Lberr2,%4@(8)\n\t"
+               "movec  %4,%/vbr\n\t"
+               "movel  %/sp,%1\n\t"
+               "moveq  #0,%0\n\t"
+               "movew  %5,%3@\n\t"  
+               "nop    \n\t"   /* If this nop isn't present, 'ret' may already be
+                                * loaded with 1 at the time the bus error
+                                * happens! */
+               "moveq  #1,%0\n"
+       "Lberr2:\n\t"
+               "movel  %1,%/sp\n\t"
+               "movec  %2,%/vbr"
+               : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
+               : "a" (regp), "a" (tmp_vectors), "g" (val)
+       );
+
+       return( ret );
+}
+
index 3db24ff9953b2704f6be4bec178ca3b916135c01..befb9030668a50621581488d6288af227e03d2fe 100644 (file)
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void init_kpointer_table(void);
 extern void show_net_buffers(void);
-extern const char PgtabStr_bad_pmd[];
-
-struct pgtable_cache_struct quicklists;
-
-void __bad_pte(pmd_t *pmd)
-{
-       printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-       pmd_set(pmd, BAD_PAGETABLE);
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-       pte_t *pte;
-
-       pte = (pte_t *) __get_free_page(GFP_KERNEL);
-       if (pmd_none(*pmd)) {
-               if (pte) {
-                       memset(pte, 0, PAGE_SIZE)
-                       flush_page_to_ram((unsigned long)pte);
-                       flush_tlb_kernel_page((unsigned long)pte);
-                       nocache_page((unsigned long)pte);
-                       pmd_set(pmd, pte);
-                       return pte + offset;
-               }
-               pmd_set(pmd, BAD_PAGETABLE);
-               return NULL;
-       }
-       free_page((unsigned long)pte);
-       if (pmd_bad(*pmd)) {
-               __bad_pte(pmd);
-               return NULL;
-       }
-       return (pte_t *) pmd_page(*pmd) + offset;
-}
 
 /*
  * BAD_PAGE is the page that is used for page faults when linux
@@ -110,7 +76,7 @@ void show_mem(void)
        total++;
        if (PageReserved(mem_map+i))
            reserved++;
-       else if (PageSwapCache(mem_map+i))
+       if (PageSwapCache(mem_map+i))
            cached++;
        else if (!atomic_read(&mem_map[i].count))
            free++;
@@ -125,7 +91,6 @@ void show_mem(void)
     printk("%d pages nonshared\n",nonshared);
     printk("%d pages shared\n",shared);
     printk("%d pages swap cached\n",cached);
-    printk("%d pages in page table cache\n",pgtable_cache_size);
     show_buffers();
 #ifdef CONFIG_NET
     show_net_buffers();
@@ -266,7 +231,7 @@ map_chunk (unsigned long addr, unsigned long size, unsigned long *memavailp))
                         */
                        for (i = 0; i < 64; i++) {
                                pte_val(ktablep[i]) = physaddr | _PAGE_PRESENT
-                                       | _PAGE_CACHE040 | _PAGE_GLOBAL040
+                                 | m68k_supervisor_cachemode | _PAGE_GLOBAL040
                                        | _PAGE_ACCESSED;
                                physaddr += PAGE_SIZE;
                        }
index 1e43f11504958cad453330b2265910b696874ccc..e1a49b1306fbf61ed00dc32be8ba20e1b71d01c1 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 1995  Hamish Macdonald
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -16,7 +17,9 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/traps.h>
+#ifdef CONFIG_AMIGA
 #include <asm/amigahw.h>
+#endif
 
 /* Strings for `extern inline' functions in <asm/pgtable.h>.  If put
    directly into these functions, they are output for every file that
@@ -451,12 +454,14 @@ unsigned long mm_ptov (unsigned long paddr)
         *
         */
 
+#ifdef CONFIG_AMIGA
        /*
         * if on an amiga and address is in first 16M, move it 
         * to the ZTWO_VADDR range
         */
        if (MACH_IS_AMIGA && paddr < 16*1024*1024)
                return ZTWO_VADDR(paddr);
+#endif
        return paddr;
 }
 
index c79ff17adb434bb81f117df0d848c478ae5dcb7a..fbb370a07f8f6d85ab44a04807f340b2ecaeff4f 100644 (file)
@@ -127,7 +127,7 @@ int mvme16x_get_irq_list (char *buf)
 
 static void mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp)
 {
-       panic ("Unknown interrupt 0x%02x", irq);
+       printk ("Unknown interrupt 0x%02x\n", irq);
 }
 
 
index 97c670f3c6ef81f51b6f9dcaaaa7a6b9dc082c91..bb7485ab8985273d0214165aa8c026d63e0107ec 100644 (file)
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := mvme16x.o
-O_OBJS   := config.o 16xints.o
+O_OBJS   := config.o 16xints.o rtc.o
 #OX_OBJS = ksyms.o
 
 include $(TOPDIR)/Rules.make
index 00e7db8d150400e06ec67292f355071d6a04d50b..838c3bbacf027921ff13f1d79af529408ff651f4 100644 (file)
 #include <asm/machdep.h>
 #include <asm/mvme16xhw.h>
 
-typedef struct {
-       unsigned char
-               ctrl,
-               bcd_sec,
-               bcd_min,
-               bcd_hr,
-               bcd_dow,
-               bcd_dom,
-               bcd_mth,
-               bcd_year;
-} MK48T08;
-
-#define RTC_WRITE      0x80
-#define RTC_READ       0x40
-#define RTC_STOP       0x20
-
 int atari_SCC_reset_done = 1;          /* So SCC doesn't get reset */
 u_long atari_mch_cookie = 0;
 
-MK48T08 * volatile rtc = (MK48T08 *)0xfffc1ff8;
+static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
 
 extern void mvme16x_process_int (int level, struct pt_regs *regs);
 extern void mvme16x_init_IRQ (void);
@@ -143,6 +127,11 @@ static int mvme16x_get_hardware_list(char *buffer)
 }
 
 
+#define pcc2chip       ((volatile u_char *)0xfff42000)
+#define PccSCCMICR     0x1d
+#define PccSCCTICR     0x1e
+#define PccSCCRICR     0x1f
+
 __initfunc(void config_mvme16x(void))
 {
     p_bdid p = (p_bdid)mvme_bdid_ptr;
@@ -197,7 +186,43 @@ __initfunc(void config_mvme16x(void))
                        rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : "");
     }
     else
+    {
        mvme16x_config = MVME16x_CONFIG_GOT_LP | MVME16x_CONFIG_GOT_CD2401;
+
+       /* Dont allow any interrupts from the CD2401 until the interrupt */
+       /* handlers are installed                                        */
+
+       pcc2chip[PccSCCMICR] = 0x10;
+       pcc2chip[PccSCCTICR] = 0x10;
+       pcc2chip[PccSCCRICR] = 0x10;
+    }
+}
+
+static void mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+       p_bdid p = (p_bdid)mvme_bdid_ptr;
+       unsigned long *new = (unsigned long *)vectors;
+       unsigned long *old = (unsigned long *)0xffe00000;
+       volatile unsigned char uc, *ucp;
+
+       if (p->brdno == 0x0162 || p->brdno == 0x172)
+       {
+               ucp = (volatile unsigned char *)0xfff42043;
+               uc = *ucp | 8;
+               *ucp = uc;
+       }
+       else
+       {
+               *(volatile unsigned long *)0xfff40074 = 0x40000000;
+       }
+       *(new+4) = *(old+4);            /* Illegal instruction */
+       *(new+9) = *(old+9);            /* Trace */
+       *(new+47) = *(old+47);          /* Trap #15 */
+
+       if (p->brdno == 0x0162 || p->brdno == 0x172)
+               *(new+0x5e) = *(old+0x5e);      /* ABORT switch */
+       else
+               *(new+0x6e) = *(old+0x6e);      /* ABORT switch */
 }
 
 static void mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp)
@@ -208,15 +233,26 @@ static void mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp)
 
 void mvme16x_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
 {
+    p_bdid p = (p_bdid)mvme_bdid_ptr;
+    int irq;
+
     tick_handler = timer_routine;
     /* Using PCCchip2 or MC2 chip tick timer 1 */
     *(volatile unsigned long *)0xfff42008 = 0;
     *(volatile unsigned long *)0xfff42004 = 10000;     /* 10ms */
     *(volatile unsigned char *)0xfff42017 |= 3;
     *(volatile unsigned char *)0xfff4201b = 0x16;
-    if (request_irq(IRQ_MVME16x_TIMER, mvme16x_timer_int, 0,
+    if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0,
                                "timer", mvme16x_timer_int))
        panic ("Couldn't register timer int");
+
+    if (p->brdno == 0x0162 || p->brdno == 0x172)
+       irq = MVME162_IRQ_ABORT;
+    else
+        irq = MVME167_IRQ_ABORT;
+    if (request_irq(irq, mvme16x_abort_int, 0,
+                               "abort", mvme16x_abort_int))
+       panic ("Couldn't register abort int");
 }
 
 
@@ -254,76 +290,11 @@ int mvme16x_set_clock_mmss (unsigned long nowtime)
        return 0;
 }
 
-/*
- * console_map_init(), here to avoid having to modify drivers/block/genhd.c
- */
-
-void console_map_init(void)
-{
-}
-
-/*
- * fbmem_init(), here to avoid having to modify drivers/char/mem.c
- */
-
-void fbmem_init(void)
-{
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-unsigned long con_init(unsigned long kmem_start)
-{
-       return (kmem_start);
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-int vcs_init(void)
-{
-       return (0);
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-int kbd_init(void)
-{
-       return (0);
-}
-
-/* Avoid mods to init/main.c */
-
-void no_scroll(char *str, int *ints)
-{
-}
-
-/* Avoid mods to kernel/panic.c */
-
-void do_unblank_screen(void)
-{
-}
-
 int mvme16x_keyb_init (void)
 {
        return 0;
 }
 
-void mvme16x_set_vectors (void)
-{
-       p_bdid p = (p_bdid)mvme_bdid_ptr;
-       unsigned long *new = (unsigned long *)vectors;
-       unsigned long *old = (unsigned long *)0xffe00000;;
-
-       *(new+4) = *(old+4);            /* Illegal instruction */
-       *(new+9) = *(old+9);            /* Trace */
-       *(new+47) = *(old+47);          /* Trap #15 */
-
-       if (p->brdno == 0x0162 || p->brdno == 0x172)
-               *(new+0x5e) = *(old+0x5e);      /* ABORT switch */
-       else
-               *(new+0x6e) = *(old+0x6e);      /* ABORT switch */
-}
-
 /*-------------------  Serial console stuff ------------------------*/
 
 extern void mvme167_serial_console_setup(int cflag);
@@ -372,7 +343,7 @@ static void scc_delay (void)
 
 static void scc_write (char ch)
 {
-       volatile char *p = (volatile char *)SCC_A_ADDR;
+       volatile char *p = (volatile char *)MVME_SCC_A_ADDR;
 
        do {
                scc_delay();
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
new file mode 100644 (file)
index 0000000..6b7c0c0
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ *     Real Time Clock interface for Linux on the MVME16x
+ *
+ * Based on the PC driver by Paul Gortmaker.
+ */
+
+#define RTC_VERSION            "1.00"
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/mc146818rtc.h> /* For struct rtc_time and ioctls, etc */
+#include <asm/mvme16xhw.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/setup.h>
+
+/*
+ *     We sponge a minor off of the misc major. No need slurping
+ *     up another valuable major dev number for this. If you add
+ *     an ioctl, make sure you don't conflict with SPARC's RTC
+ *     ioctls.
+ */
+
+#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
+
+static unsigned char days_in_mo[] =
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static char rtc_status = 0;
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                    unsigned long arg)
+{
+       volatile MK48T08ptr_t rtc = (MK48T08ptr_t)MVME_RTC_BASE;
+       unsigned long flags;
+       struct rtc_time wtime; 
+
+       switch (cmd) {
+       case RTC_RD_TIME:       /* Read the time/date from RTC  */
+       {
+               save_flags(flags);
+               cli();
+               /* Ensure clock and real-time-mode-register are accessible */
+               rtc->ctrl = RTC_READ;
+               wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
+               wtime.tm_min =  BCD2BIN(rtc->bcd_min);
+               wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
+               wtime.tm_mday =  BCD2BIN(rtc->bcd_dom);
+               wtime.tm_mon =  BCD2BIN(rtc->bcd_mth)-1;
+               wtime.tm_year = BCD2BIN(rtc->bcd_year);
+               if (wtime.tm_year < 70)
+                       wtime.tm_year += 100;
+               wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
+               rtc->ctrl = 0;
+               restore_flags(flags);
+               return copy_to_user((void *)arg, &wtime, sizeof wtime) ?
+                                                               -EFAULT : 0;
+       }
+       case RTC_SET_TIME:      /* Set the RTC */
+       {
+               unsigned char leap_yr;
+               struct rtc_time rtc_tm;
+
+               if (!suser())
+                       return -EACCES;
+
+               if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+                                  sizeof(struct rtc_time)))
+                       return -EFAULT;
+
+               leap_yr = ((!(rtc_tm.tm_year % 4) && (rtc_tm.tm_year % 100)) || !(rtc_tm.tm_year % 400));
+
+               if ((rtc_tm.tm_mon > 12) || (rtc_tm.tm_mday == 0))
+                       return -EINVAL;
+
+               if (rtc_tm.tm_mday > (days_in_mo[rtc_tm.tm_mon] + ((rtc_tm.tm_mon == 2) && leap_yr)))
+                       return -EINVAL;
+                       
+               if ((rtc_tm.tm_hour >= 24) || (rtc_tm.tm_min >= 60) || (rtc_tm.tm_sec >= 60))
+                       return -EINVAL;
+
+               save_flags(flags);
+               cli();
+               rtc->ctrl = RTC_WRITE;
+
+               rtc->bcd_sec = BIN2BCD(rtc_tm.tm_sec);
+               rtc->bcd_min = BIN2BCD(rtc_tm.tm_min);
+               rtc->bcd_hr  = BIN2BCD(rtc_tm.tm_hour);
+               rtc->bcd_dom = BIN2BCD(rtc_tm.tm_mday);
+               rtc->bcd_mth = BIN2BCD(rtc_tm.tm_mon + 1);
+               rtc->bcd_year = BIN2BCD(rtc_tm.tm_year%100);
+               if (rtc_tm.tm_wday >= 0)
+                       rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
+
+               rtc->ctrl = 0;
+               restore_flags(flags);
+               return 0;
+       }
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ *     We enforce only one user at a time here with the open/close.
+ *     Also clear the previous interrupt data on an open, and clean
+ *     up things on a close.
+ */
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+       if(rtc_status)
+               return -EBUSY;
+
+       rtc_status = 1;
+       return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+       rtc_status = 0;
+       return 0;
+}
+
+/*
+ *     The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+       NULL,
+       NULL,
+       NULL,           /* No write */
+       NULL,           /* No readdir */
+       NULL,
+       rtc_ioctl,
+       NULL,           /* No mmap */
+       rtc_open,
+       rtc_release
+};
+
+static struct miscdevice rtc_dev=
+{
+       RTC_MINOR,
+       "rtc",
+       &rtc_fops
+};
+
+__initfunc(int rtc_MK48T08_init(void))
+{
+       if (!MACH_IS_MVME16x)
+               return -ENODEV;
+
+       printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
+       misc_register(&rtc_dev);
+       return 0;
+}
+
index 2fe56b344d1065d619c756103b7c9d21e9e88f34..7e1924ec955b6294b3290eafbc471473a5ba233f 100644 (file)
@@ -334,15 +334,23 @@ asmlinkage int sys_pause(void)
 
 asmlinkage int sys_getdomainname(char *name, int len)
 {
-       int nlen = strlen(system_utsname.domainname);
+       int nlen;
+       int err = -EFAULT;
+       
+       down(&uts_sem);
+       
+       nlen = strlen(system_utsname.domainname);
 
        if (nlen < len)
                len = nlen;
        if(len > __NEW_UTS_LEN)
-               return -EFAULT;
+               goto done
        if(copy_to_user(name, system_utsname.domainname, len))
-               return -EFAULT;
-       return 0;
+               goto done;
+       err=0;
+done:  
+       up(&uts_sem);   
+       return err;
 }
 
 
index 645f9376b9c0a48025e118d8c1e07985559ae12f..4d562d99358d4e27c71f0d0124e53bf1fc65188d 100644 (file)
@@ -463,6 +463,7 @@ void make_request(int major,int rw, struct buffer_head * bh)
             case IDE4_MAJOR:
             case IDE5_MAJOR:
             case ACSI_MAJOR:
+            case MFM_ACORN_MAJOR:
                /*
                 * The scsi disk and cdrom drivers completely remove the request
                 * from the queue when they start processing an entry.  For this
@@ -817,6 +818,9 @@ __initfunc(int blk_dev_init(void))
 #ifdef CONFIG_BLK_DEV_XD
        xd_init();
 #endif
+#ifdef CONFIG_BLK_DEV_MFM
+       mfm_init();
+#endif
 #ifdef CONFIG_PARIDE
        { extern void paride_init(void); paride_init(); };
 #endif
index eae3638aa8516671c216e39a14ca0257fb1ffc40..00dd9c8e4b787219d2751abd40a0ab4b04e602a2 100644 (file)
@@ -6,12 +6,14 @@ dep_tristate '  Parallel port IDE disks' CONFIG_PARIDE_PD $CONFIG_PARIDE
 dep_tristate '  Parallel port ATAPI CD-ROMs' CONFIG_PARIDE_PCD $CONFIG_PARIDE
 dep_tristate '  Parallel port ATAPI disks' CONFIG_PARIDE_PF $CONFIG_PARIDE
 dep_tristate '  Parallel port ATAPI tapes' CONFIG_PARIDE_PT $CONFIG_PARIDE
+dep_tristate '  Parallel port generic ATAPI devices' CONFIG_PARIDE_PG $CONFIG_PARIDE
 comment 'Parallel IDE protocol modules'
 dep_tristate '    ATEN EH-100 protocol' CONFIG_PARIDE_ATEN $CONFIG_PARIDE
 dep_tristate '    MicroSolutions backpack protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE
 dep_tristate '    DataStor Commuter protocol' CONFIG_PARIDE_COMM $CONFIG_PARIDE
 dep_tristate '    DataStor EP-2000 protocol' CONFIG_PARIDE_DSTR $CONFIG_PARIDE
 dep_tristate '    FIT TD-2000 protocol' CONFIG_PARIDE_FIT2 $CONFIG_PARIDE
+dep_tristate '    FIT TD-3000 protocol' CONFIG_PARIDE_FIT3 $CONFIG_PARIDE
 dep_tristate '    Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE
 dep_tristate '    Shuttle EPIA protocol' CONFIG_PARIDE_EPIA $CONFIG_PARIDE
 dep_tristate '    FreeCom power protocol' CONFIG_PARIDE_FRPW $CONFIG_PARIDE
index 108736fa4c31ee11d3aa7cc165172e50f3e7aa11..abb45d2fc84c0d897c8907f4be95f53b0342667b 100644 (file)
@@ -58,6 +58,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_PARIDE_PG),y)
+  LX_OBJS += pg.o
+else
+  ifeq ($(CONFIG_PARIDE_PG),m)
+    MX_OBJS += pg.o
+  endif
+endif
+
 ifeq ($(CONFIG_PARIDE_ATEN),y)
   LX_OBJS += aten.o
 else
@@ -122,6 +130,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_PARIDE_FIT3),y)
+  LX_OBJS += fit3.o
+else
+  ifeq ($(CONFIG_PARIDE_FIT3),m)
+    MX_OBJS += fit3.o
+  endif
+endif
+
 ifeq ($(CONFIG_PARIDE_FRPW),y)
   LX_OBJS += frpw.o
 else
diff --git a/drivers/block/paride/fit3.c b/drivers/block/paride/fit3.c
new file mode 100644 (file)
index 0000000..f449bcf
--- /dev/null
@@ -0,0 +1,221 @@
+/* 
+        fit3.c        (c) 1998  Grant R. Guenther <grant@torque.net>
+                          Under the terms of the GNU public license.
+
+       fit3.c is a low-level protocol driver for newer models 
+        of the Fidelity International Technology parallel port adapter.  
+       This adapter is used in their TransDisk 3000 portable 
+       hard-drives, as well as CD-ROM, PD-CD and other devices.
+
+       The TD-2000 and certain older devices use a different protocol.
+       Try the fit2 protocol module with them.
+
+        NB:  The FIT adapters do not appear to support the control 
+       registers.  So, we map ALT_STATUS to STATUS and NO-OP writes 
+       to the device control register - this means that IDE reset 
+       will not work on these devices.
+
+*/
+
+#define FIT3_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define j44(a,b)                (((a>>3)&0x0f)|((b<<1)&0xf0))
+
+#define w7(byte)                {out_p(7,byte);}
+#define r7()                    (in_p(7) & 0xff)
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+
+*/
+
+static void  fit3_write_regr( PIA *pi, int cont, int regr, int val)
+
+{      if (cont == 1) return;
+
+       switch (pi->mode) {
+
+       case 0:
+       case 1: w2(0xc); w0(regr); w2(0x8); w2(0xc); 
+               w0(val); w2(0xd); 
+               w0(0);   w2(0xc);
+               break;
+
+       case 2: w2(0xc); w0(regr); w2(0x8); w2(0xc);
+               w4(val); w4(0);
+               w2(0xc);
+               break;
+
+       }
+}
+
+static int fit3_read_regr( PIA *pi, int cont, int regr )
+
+{      int  a, b;
+
+       if (cont) {
+         if (regr != 6) return 0xff;
+         regr = 7;
+       } 
+
+       switch (pi->mode) {
+
+       case 0: w2(0xc); w0(regr + 0x10); w2(0x8); w2(0xc);
+               w2(0xd); a = r1();
+               w2(0xf); b = r1(); 
+               w2(0xc);
+               return j44(a,b);
+
+       case 1: w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc);
+               w2(0xec); w2(0xee); w2(0xef); a = r0(); 
+               w2(0xc);
+               return a;
+
+       case 2: w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc); 
+               w2(0xec); 
+               a = r4(); b = r4(); 
+               w2(0xc);
+               return a;
+
+       }
+       return -1; 
+
+}
+
+static void fit3_read_block( PIA *pi, char * buf, int count )
+
+{      int  k, a, b, c, d;
+
+       switch (pi->mode) {
+
+       case 0: w2(0xc); w0(0x10); w2(0x8); w2(0xc);
+               for (k=0;k<count/2;k++) {
+                   w2(0xd); a = r1();
+                   w2(0xf); b = r1();
+                   w2(0xc); c = r1();
+                   w2(0xe); d = r1();
+                   buf[2*k  ] = j44(a,b);
+                   buf[2*k+1] = j44(c,d);
+               }
+               w2(0xc);
+               break;
+
+       case 1: w2(0xc); w0(0x90); w2(0x8); w2(0xc); 
+               w2(0xec); w2(0xee);
+               for (k=0;k<count/2;k++) {
+                   w2(0xef); a = r0();
+                   w2(0xee); b = r0();
+                    buf[2*k  ] = a;
+                    buf[2*k+1] = b;
+               }
+               w2(0xec); 
+               w2(0xc);
+               break;
+
+       case 2: w2(0xc); w0(0x90); w2(0x8); w2(0xc); 
+                w2(0xec);
+               for (k=0;k<count;k++) buf[k] = r4();
+                w2(0xc);
+               break;
+
+       }
+}
+
+static void fit3_write_block( PIA *pi, char * buf, int count )
+
+{      int k;
+
+        switch (pi->mode) {
+
+       case 0:
+        case 1: w2(0xc); w0(0); w2(0x8); w2(0xc);
+                for (k=0;k<count/2;k++) {
+                   w0(buf[2*k  ]); w2(0xd);
+                   w0(buf[2*k+1]); w2(0xc);
+               }
+               break;
+
+        case 2: w2(0xc); w0(0); w2(0x8); w2(0xc); 
+                for (k=0;k<count;k++) w4(buf[k]);
+                w2(0xc);
+               break;
+       }
+}
+
+static void fit3_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+       w2(0xc); w0(0); w2(0xa);
+       if (pi->mode == 2) { 
+               w2(0xc); w0(0x9); w2(0x8); w2(0xc); 
+               }
+}
+
+static void fit3_disconnect ( PIA *pi )
+
+{       w2(0xc); w0(0xa); w2(0x8); w2(0xc);
+       w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static void fit3_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       char    *mode_string[3] = {"4-bit","8-bit","EPP"};
+
+       printk("%s: fit3 %s, FIT 3000 adapter at 0x%x, "
+              "mode %d (%s), delay %d\n",
+                pi->device,FIT3_VERSION,pi->port,
+               pi->mode,mode_string[pi->mode],pi->delay);
+
+}
+
+static void fit3_init_proto(PIA *pi)
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void fit3_release_proto(PIA *pi)
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol fit3 = {"fit3",0,3,2,1,1,
+                           fit3_write_regr,
+                           fit3_read_regr,
+                           fit3_write_block,
+                           fit3_read_block,
+                           fit3_connect,
+                           fit3_disconnect,
+                           0,
+                           0,
+                           0,
+                           fit3_log_adapter,
+                           fit3_init_proto,
+                           fit3_release_proto
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &fit3 ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &fit3 );
+}
+
+#endif
+
+/* end of fit3.c */
index afff807ff9a41a08b7f76f7a8cf016ab059bc3ef..971f099b40aa63ef2c483fcf01392bdf29318708 100644 (file)
@@ -2,6 +2,9 @@
 #
 # mkd -- a script to create the device special files for the PARIDE subsystem
 #
+#  block devices:      pd (45), pcd (46), pf (47)
+#  character devices:  pt (96), pg (97)
+#
 function mkdev {
   mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
 }
@@ -21,5 +24,7 @@ for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done
 for u in 0 1 2 3 ; do mkdev pf$u  b 47 $u ; done 
 for u in 0 1 2 3 ; do mkdev pt$u  c 96 $u ; done 
 for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done 
+for u in 0 1 2 3 ; do mkdev pg$u  c 97 $u ; done
 #
 # end of mkd
+
index aa718253bca4ed17f722d8a19a199c8fe6018448..96052c3c27a2ec1467cc95e9eb2add9883351340 100644 (file)
@@ -454,6 +454,11 @@ void       paride_init( void )
           pi_register(&fit2);
         };
 #endif
+#ifdef CONFIG_PARIDE_FIT3
+        { extern struct pi_protocol fit3;
+          pi_register(&fit3);
+        };
+#endif
 #ifdef CONFIG_PARIDE_KBIC
         { extern struct pi_protocol k951;
           extern struct pi_protocol k971;
index c30794c5ccff9f3be41db771265ad10052d08460..6d37736ec299b05c4c531272c2940a19fcfada11 100644 (file)
@@ -23,6 +23,7 @@
 #define PI_PCD 1       /* ATAPI CDrom */
 #define PI_PF   2      /* ATAPI disk */
 #define PI_PT  3       /* ATAPI tape */
+#define PI_PG   4       /* ATAPI generic */
 
 /* The paride module contains no state, instead the drivers allocate
    a pi_adapter data structure and pass it to paride in every operation.
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
new file mode 100644 (file)
index 0000000..be994c1
--- /dev/null
@@ -0,0 +1,691 @@
+/* 
+        pg.c    (c) 1998  Grant R. Guenther <grant@torque.net>
+                          Under the terms of the GNU public license.
+
+       The pg driver provides a simple character device interface for
+        sending ATAPI commands to a device.  With the exception of the
+       ATAPI reset operation, all operations are performed by a pair
+        of read and write operations to the appropriate /dev/pgN device.
+       A write operation delivers a command and any outbound data in
+        a single buffer.  Normally, the write will succeed unless the
+        device is offline or malfunctioning, or there is already another
+       command pending.  If the write succeeds, it should be followed
+        immediately by a read operation, to obtain any returned data and
+        status information.  A read will fail if there is no operation
+        in progress.
+
+       As a special case, the device can be reset with a write operation,
+        and in this case, no following read is expected, or permitted.
+
+       There are no ioctl() operations.  Any single operation
+       may transfer at most PG_MAX_DATA bytes.  Note that the driver must
+        copy the data through an internal buffer.  In keeping with all
+       current ATAPI devices, command packets are assumed to be exactly
+       12 bytes in length.
+
+       To permit future changes to this interface, the headers in the
+       read and write buffers contain a single character "magic" flag.
+        Currently this flag must be the character "P".
+
+        By default, the driver will autoprobe for a single parallel
+        port ATAPI device, but if their individual parameters are
+        specified, the driver can handle up to 4 devices.
+
+       To use this device, you must have the following device 
+       special files defined:
+
+               /dev/pg0 b 97 0
+               /dev/pg1 b 97 1
+               /dev/pg2 b 97 2
+               /dev/pg3 b 97 3
+
+       (You'll need to change the 97 to something else if you use
+       the 'major' parameter to install the driver on a different
+        major number.)
+
+        The behaviour of the pg driver can be altered by setting
+        some parameters from the insmod command line.  The following
+        parameters are adjustable:
+
+            drive0      These four arguments can be arrays of       
+            drive1      1-6 integers as follows:
+            drive2
+            drive3      <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
+
+                        Where,
+
+                <prt>   is the base of the parallel port address for
+                        the corresponding drive.  (required)
+
+                <pro>   is the protocol number for the adapter that
+                        supports this drive.  These numbers are
+                        logged by 'paride' when the protocol modules
+                        are initialised.  (0 if not given)
+
+                <uni>   for those adapters that support chained
+                        devices, this is the unit selector for the
+                        chain of devices on the given port.  It should
+                        be zero for devices that don't support chaining.
+                        (0 if not given)
+
+                <mod>   this can be -1 to choose the best mode, or one
+                        of the mode numbers supported by the adapter.
+                        (-1 if not given)
+
+                <slv>   ATAPI devices can be jumpered to master or slave.
+                        Set this to 0 to choose the master drive, 1 to
+                        choose the slave, -1 (the default) to choose the
+                        first drive found.
+
+                <dly>   some parallel ports require the driver to 
+                        go more slowly.  -1 sets a default value that
+                        should work with the chosen protocol.  Otherwise,
+                        set this to a small integer, the larger it is
+                        the slower the port i/o.  In some cases, setting
+                        this to zero will speed up the device. (default -1)
+
+           major       You may use this parameter to overide the
+                       default major number (97) that this driver
+                       will use.  Be sure to change the device
+                       name as well.
+
+           name        This parameter is a character string that
+                       contains the name the kernel will use for this
+                       device (in /proc output, for instance).
+                       (default "pg").
+
+            verbose     This parameter controls the amount of logging
+                        that is done by the driver.  Set it to 0 for 
+                       quiet operation, to 1 to enable progress
+                       messages while the driver probes for devices,
+                       or to 2 for full debug logging.  (default 0)
+
+        If this driver is built into the kernel, you can use 
+        the following command line parameters, with the same values
+        as the corresponding module parameters listed above:
+
+            pg.drive0
+            pg.drive1
+            pg.drive2
+            pg.drive3
+
+        In addition, you can use the parameter pg.disable to disable
+        the driver entirely.
+
+*/
+
+#define PG_VERSION      "1.0"
+#define PG_MAJOR       97
+#define PG_NAME                "pg"
+#define PG_UNITS       4
+
+/* Here are things one can override from the insmod command.
+   Most are autoprobed by paride unless set here.  Verbose is 0
+   by default.
+
+*/
+
+static int     verbose = 0;
+static int     major = PG_MAJOR;
+static char    *name = PG_NAME;
+static int      disable = 0;
+
+static int drive0[6] = {0,0,0,-1,-1,-1};
+static int drive1[6] = {0,0,0,-1,-1,-1};
+static int drive2[6] = {0,0,0,-1,-1,-1};
+static int drive3[6] = {0,0,0,-1,-1,-1};
+
+static int (*drives[4])[6] = {&drive0,&drive1,&drive2,&drive3};
+static int pg_drive_count;
+
+#define D_PRT   0
+#define D_PRO   1
+#define D_UNI   2
+#define D_MOD   3
+#define D_SLV   4
+#define D_DLY   5
+
+#define DU              (*drives[unit])
+
+/* end of parameters */
+
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/mtio.h>
+#include <linux/pg.h>
+
+#include <asm/uaccess.h>
+
+#ifndef MODULE
+
+#include "setup.h"
+
+static STT pg_stt[5] = {{"drive0",6,drive0},
+                        {"drive1",6,drive1},
+                        {"drive2",6,drive2},
+                        {"drive3",6,drive3},
+                       {"disable",1,&disable}};
+
+void pg_setup( char *str, int *ints)
+
+{       generic_setup(pg_stt,5,str);
+}
+
+#endif
+
+MODULE_PARM(verbose,"i");
+MODULE_PARM(major,"i");
+MODULE_PARM(name,"s");
+MODULE_PARM(drive0,"1-6i");
+MODULE_PARM(drive1,"1-6i");
+MODULE_PARM(drive2,"1-6i");
+MODULE_PARM(drive3,"1-6i");
+
+#include "paride.h"
+
+#define PG_SPIN_DEL     50              /* spin delay in micro-seconds  */
+#define PG_SPIN         200
+#define PG_TMO         HZ
+
+#define STAT_ERR        0x01
+#define STAT_INDEX      0x02
+#define STAT_ECC        0x04
+#define STAT_DRQ        0x08
+#define STAT_SEEK       0x10
+#define STAT_WRERR      0x20
+#define STAT_READY      0x40
+#define STAT_BUSY       0x80
+
+#define ATAPI_IDENTIFY         0x12
+
+int pg_init(void);
+#ifdef MODULE
+void cleanup_module( void );
+#endif
+
+static int pg_open(struct inode *inode, struct file *file);
+static int pg_release (struct inode *inode, struct file *file);
+static ssize_t pg_read(struct file * filp, char * buf, 
+                       size_t count, loff_t *ppos);
+static ssize_t pg_write(struct file * filp, const char * buf, 
+                        size_t count, loff_t *ppos);
+static int pg_detect(void);
+
+static int pg_identify (int unit, int log);
+
+#define PG_NAMELEN      8
+
+struct pg_unit {
+       struct pi_adapter pia;    /* interface to paride layer */
+       struct pi_adapter *pi;
+       int busy;                 /* write done, read expected */
+       int start;                /* jiffies at command start */
+       int dlen;                 /* transfer size requested */
+       int timeout;              /* timeout requested */
+       int status;               /* last sense key */
+       int drive;                /* drive */
+       int access;               /* count of active opens ... */
+       int present;              /* device present ? */
+       char *bufptr;
+       char name[PG_NAMELEN];    /* pg0, pg1, ... */
+       };
+
+struct pg_unit pg[PG_UNITS];
+
+/*  'unit' must be defined in all functions - either as a local or a param */
+
+#define PG pg[unit]
+#define PI PG.pi
+
+static char pg_scratch[512];            /* scratch block buffer */
+
+/* kernel glue structures */
+
+static struct file_operations pg_fops = {
+        NULL,                   /* lseek - default */
+        pg_read,                /* read */
+        pg_write,               /* write */
+        NULL,                   /* readdir - bad */
+        NULL,                   /* select */
+        NULL,                   /* ioctl */
+        NULL,                   /* mmap */
+        pg_open,                /* open */
+        pg_release,             /* release */
+        NULL,                   /* fsync */
+        NULL,                   /* fasync */
+        NULL,                   /* media change ? */
+        NULL                    /* revalidate new media */
+};
+
+void pg_init_units( void )
+
+{       int     unit, j;
+
+        pg_drive_count = 0;
+        for (unit=0;unit<PG_UNITS;unit++) {
+                PG.pi = & PG.pia;
+                PG.access = 0;
+                PG.busy = 0;
+                PG.present = 0;
+               PG.bufptr = NULL;
+               PG.drive = DU[D_SLV];
+                j = 0;
+                while ((j < PG_NAMELEN-2) && (PG.name[j]=name[j])) j++;
+                PG.name[j++] = '0' + unit;
+                PG.name[j] = 0;
+                if (DU[D_PRT]) pg_drive_count++;
+        }
+} 
+
+int pg_init (void)      /* preliminary initialisation */
+
+{       int unit;
+
+       if (disable) return -1;
+
+       pg_init_units();
+
+       if (pg_detect()) return -1;
+
+        if (register_chrdev(major,name,&pg_fops)) {
+                printk("pg_init: unable to get major number %d\n",
+                        major);
+               for (unit=0;unit<PG_UNITS;unit++)
+                 if (PG.present) pi_release(PI);
+                return -1;
+        }
+
+        return 0;
+}
+
+#ifdef MODULE
+
+/* Glue for modules ... */
+
+void    cleanup_module(void);
+
+int     init_module(void)
+
+{       int     err;
+        long    flags;
+
+        save_flags(flags);
+        cli();
+
+        err = pg_init();
+
+        restore_flags(flags);
+        return err;
+}
+
+void    cleanup_module(void)
+
+{       long flags;
+       int unit;
+
+        save_flags(flags);
+        cli();
+
+        unregister_chrdev(major,name);
+
+       for (unit=0;unit<PG_UNITS;unit++)
+         if (PG.present) pi_release(PI);
+       
+        restore_flags(flags);
+}
+
+#endif
+
+#define        WR(c,r,v)       pi_write_regr(PI,c,r,v)
+#define        RR(c,r)         (pi_read_regr(PI,c,r))
+
+#define DRIVE           (0xa0+0x10*PG.drive)
+
+static void pg_sleep( int cs )
+
+{       current->state = TASK_INTERRUPTIBLE;
+        current->timeout = jiffies + cs;
+        schedule();
+}
+
+static int pg_wait( int unit, int go, int stop, int tmo, char * msg )
+
+{       int j, r, e, s, p;
+
+       PG.status = 0;
+
+        j = 0;
+        while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(jiffies<tmo)) {
+                if (j++ < PG_SPIN) udelay(PG_SPIN_DEL);
+               else pg_sleep(1);
+       }
+
+        if ((r&(STAT_ERR&stop))||(jiffies>=tmo)) {
+           s = RR(0,7);
+           e = RR(0,1);
+           p = RR(0,2);
+           if (verbose > 1)
+            printk("%s: %s: stat=0x%x err=0x%x phase=%d%s\n",
+                   PG.name,msg,s,e,p,(jiffies>=tmo)?" timeout":"");
+
+
+           if (jiffies>=tmo) e |= 0x100;
+          PG.status = (e >> 4) & 0xff;
+           return -1;
+        }
+        return 0;
+}
+
+static int pg_command( int unit, char * cmd, int dlen, int tmo )
+
+{       int k;
+
+       pi_connect(PI);
+
+        WR(0,6,DRIVE);
+
+        if (pg_wait(unit,STAT_BUSY|STAT_DRQ,0,tmo,"before command")) {
+                pi_disconnect(PI);
+                return -1;
+        }
+
+        WR(0,4,dlen % 256);
+        WR(0,5,dlen / 256);
+        WR(0,7,0xa0);          /* ATAPI packet command */
+
+        if (pg_wait(unit,STAT_BUSY,STAT_DRQ,tmo,"command DRQ")) {
+                pi_disconnect(PI);
+                return -1;
+        }
+
+        if (RR(0,2) != 1) {
+           printk("%s: command phase error\n",PG.name);
+           pi_disconnect(PI);
+           return -1;
+        }
+
+        pi_write_block(PI,cmd,12);
+
+       if (verbose > 1) {
+               printk("%s: Command sent, dlen=%d packet= ", PG.name,dlen);
+               for (k=0;k<12;k++) printk("%02x ",cmd[k]&0xff);
+               printk("\n");
+       }
+        return 0;
+}
+
+static int pg_completion( int unit, char * buf, int tmo)
+
+{       int r, s, d, n, p;
+
+        r = pg_wait(unit,STAT_BUSY,STAT_DRQ|STAT_READY|STAT_ERR,
+                       tmo,"completion");
+
+       PG.dlen = 0;
+
+        if (RR(0,7)&STAT_DRQ) { 
+           d = (RR(0,4)+256*RR(0,5));
+           n = ((d+3)&0xfffc);
+          p = RR(0,2)&3;
+          if (p == 0) pi_write_block(PI,buf,n);
+          if (p == 2) pi_read_block(PI,buf,n);
+          if (verbose > 1) printk("%s: %s %d bytes\n",PG.name,
+                                   p?"Read":"Write",n);
+          PG.dlen = (1-p)*d;
+        }
+
+        s = pg_wait(unit,STAT_BUSY,STAT_READY|STAT_ERR,tmo,"data done");
+
+        pi_disconnect(PI); 
+
+        return (r?r:s);
+}
+
+static int pg_reset( int unit )
+
+{      int     i, k, flg;
+       int     expect[5] = {1,1,1,0x14,0xeb};
+
+       pi_connect(PI);
+       WR(0,6,DRIVE);
+       WR(0,7,8);
+
+       pg_sleep(2);
+
+        k = 0;
+        while ((k++ < PG_TMO) && (RR(1,6)&STAT_BUSY))
+                pg_sleep(1);
+
+       flg = 1;
+       for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
+
+       if (verbose) {
+               printk("%s: Reset (%d) signature = ",PG.name,k);
+               for (i=0;i<5;i++) printk("%3x",RR(0,i+1));
+               if (!flg) printk(" (incorrect)");
+               printk("\n");
+       }
+       
+       pi_disconnect(PI);
+       return flg-1;   
+}
+
+static void xs( char *buf, char *targ, int offs, int len )
+
+{      int     j,k,l;
+
+       j=0; l=0;
+       for (k=0;k<len;k++) 
+          if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
+               l=targ[j++]=buf[k+offs];
+       if (l==0x20) j--; targ[j]=0;
+}
+
+static int pg_identify( int unit, int log )
+
+{      int     s;
+       char    *ms[2] = {"master","slave"};
+       char    mf[10], id[18];
+       char    id_cmd[12] = { ATAPI_IDENTIFY,0,0,0,36,0,0,0,0,0,0,0};
+       char    buf[36];
+
+        s = pg_command(unit,id_cmd,36,jiffies+PG_TMO);
+       if (s) return -1;
+       s = pg_completion(unit,buf,jiffies+PG_TMO);
+       if (s) return -1;
+
+       if (log) {
+               xs(buf,mf,8,8);
+               xs(buf,id,16,16);
+               printk("%s: %s %s, %s\n",PG.name,mf,id,ms[PG.drive]);
+       }
+
+       return 0;
+}
+
+static int pg_probe( int unit )
+
+/*     returns  0, with id set if drive is detected
+               -1, if drive detection failed
+*/
+
+{      if (PG.drive == -1) {
+          for (PG.drive=0;PG.drive<=1;PG.drive++)
+               if (!pg_reset(unit)) return pg_identify(unit,1);
+       } else {
+          if (!pg_reset(unit)) return pg_identify(unit,1);
+       }
+        return -1; 
+}
+
+static int pg_detect( void )
+
+{      int     k, unit;
+
+       printk("%s: %s version %s, major %d\n",
+               name,name,PG_VERSION,major);
+
+       k = 0;
+       if (pg_drive_count == 0) {
+           unit = 0;
+           if (pi_init(PI,1,-1,-1,-1,-1,-1,pg_scratch,
+                        PI_PG,verbose,PG.name)) {
+               if (!pg_probe(unit)) {
+                       PG.present = 1;
+                       k++;
+               } else pi_release(PI);
+           }
+
+       } else for (unit=0;unit<PG_UNITS;unit++) if (DU[D_PRT])
+           if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
+                       DU[D_PRO],DU[D_DLY],pg_scratch,PI_PG,verbose,
+                       PG.name)) { 
+                if (!pg_probe(unit)) {
+                        PG.present = 1;
+                        k++;
+                } else pi_release(PI);
+            }
+
+       if (k) return 0;
+
+       printk("%s: No ATAPI device detected\n",name);
+       return -1;
+}
+
+#define DEVICE_NR(dev) (MINOR(dev) % 128)
+
+static int pg_open (struct inode *inode, struct file *file)
+
+{       int    unit = DEVICE_NR(inode->i_rdev);
+
+        if ((unit >= PG_UNITS) || (!PG.present)) return -ENODEV;
+
+        PG.access++;
+
+       if (PG.access > 1) {
+               PG.access--;
+               return -EBUSY;
+       }
+
+        MOD_INC_USE_COUNT;
+
+       if (PG.busy) {
+               pg_reset(unit);
+               PG.busy = 0;
+       }
+
+       pg_identify(unit,(verbose>1));
+
+
+       PG.bufptr = kmalloc(PG_MAX_DATA,GFP_KERNEL);
+       if (PG.bufptr == NULL) {
+               PG.access--;
+               MOD_DEC_USE_COUNT;
+               printk("%s: buffer allocation failed\n",PG.name);
+               return -ENOMEM;
+       }
+
+        return 0;
+}
+
+static int pg_release (struct inode *inode, struct file *file)
+{
+        int    unit = DEVICE_NR(inode->i_rdev);
+
+        if ((unit >= PG_UNITS) || (PG.access <= 0)) 
+                return -EINVAL;
+
+       PG.access--;
+
+       kfree(PG.bufptr);
+       PG.bufptr = NULL;
+
+        MOD_DEC_USE_COUNT;
+
+       return 0;
+
+}
+
+static ssize_t pg_write(struct file * filp, const char * buf, 
+                        size_t count, loff_t *ppos)
+
+{       struct inode            *ino = filp->f_dentry->d_inode;
+        int                     unit = DEVICE_NR(ino->i_rdev);
+        struct pg_write_hdr     hdr;
+        int                     hs = sizeof(hdr);
+
+       if (PG.busy) return -EBUSY;
+       if (count < hs) return -EINVAL;
+       
+       copy_from_user((char *)&hdr,buf,hs);
+
+       if (hdr.magic != PG_MAGIC) return -EINVAL;
+       if (hdr.dlen > PG_MAX_DATA) return -EINVAL;
+       if ((count - hs) > PG_MAX_DATA) return -EINVAL;
+
+       if (hdr.func == PG_RESET) {
+               if (count != hs) return -EINVAL;
+               if (pg_reset(unit)) return -EIO;
+               return count;
+       }
+
+       if (hdr.func != PG_COMMAND) return -EINVAL;
+
+       PG.start = jiffies;
+       PG.timeout = hdr.timeout*HZ + HZ/2 + jiffies;
+
+       if (pg_command(unit,hdr.packet,hdr.dlen,jiffies+PG_TMO)) {
+               if (PG.status & 0x10) return -ETIME;
+               return -EIO;
+       }
+
+       PG.busy = 1;
+
+       copy_from_user(PG.bufptr,buf+hs,count-hs);
+
+       return count;
+}
+
+static ssize_t pg_read(struct file * filp, char * buf, 
+                       size_t count, loff_t *ppos)
+
+{      struct inode            *ino = filp->f_dentry->d_inode;
+       int                     unit = DEVICE_NR(ino->i_rdev);
+       struct pg_read_hdr      hdr;
+       int                     hs = sizeof(hdr);
+       int                     copy;
+
+       if (!PG.busy) return -EINVAL;
+       if (count < hs) return -EINVAL;
+
+       PG.busy = 0;
+
+       if (pg_completion(unit,PG.bufptr,PG.timeout))
+         if (PG.status & 0x10) return -ETIME;
+
+       hdr.magic = PG_MAGIC;
+       hdr.dlen = PG.dlen;
+       copy = 0;
+
+       if (hdr.dlen < 0) {
+               hdr.dlen = -1 * hdr.dlen;
+               copy = hdr.dlen;
+               if (copy > (count - hs)) copy = count - hs;
+       }
+
+       hdr.duration = (jiffies - PG.start + HZ/2) / HZ;
+       hdr.scsi = PG.status & 0x0f;
+
+       copy_to_user(buf,(char *)&hdr,hs);
+       if (copy > 0) copy_to_user(buf+hs,PG.bufptr,copy);
+       
+       return copy+hs;
+}
+
+/* end of pg.c */
+
index 0236029527a9a1534a6dbe40afb1463795737cbc..17615c2caaf7fd684072f5753bc2e0694a5ae6ae 100644 (file)
@@ -45,7 +45,7 @@ static int ps_timeout;
 static int ps_timer_active = 0;
 static int ps_tq_active = 0;
 
-spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED;
+static spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED;
 
 static struct timer_list ps_timer = {0,0,0,0,ps_timer_int};
 static struct tq_struct ps_tq = {0,0,ps_tq_int,NULL};
diff --git a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c
new file mode 100644 (file)
index 0000000..35e0c83
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Macintosh ADB Mouse driver for Linux
+ *
+ * 27 Oct 1997 Michael Schmitz
+ * logitech fixes by anthony tong
+ *
+ * Apple mouse protocol according to:
+ *
+ * Device code shamelessly stolen from:
+ */
+/*
+ * Atari Mouse Driver for Linux
+ * by Robert de Vries (robert@and.nl) 19Jul93
+ *
+ * 16 Nov 1994 Andreas Schwab
+ * Compatibility with busmouse
+ * Support for three button mouse (shamelessly stolen from MiNT)
+ * third button wired to one of the joystick directions on joystick 1
+ *
+ * 1996/02/11 Andreas Schwab
+ * Module support
+ * Allow multiple open's
+ */
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+
+#include <asm/adb_mouse.h>
+#include <asm/segment.h>
+#include <asm/processor.h>
+
+static struct mouse_status mouse;
+static int adb_mouse_x_threshold = 2, adb_mouse_y_threshold = 2;
+static int adb_mouse_buttons = 0;
+
+extern void (*adb_mouse_interrupt_hook) (char *, int);
+
+extern int console_loglevel;
+
+/*
+ *     XXX: need to figure out what ADB mouse packets mean ... 
+ *     This is the stuff stolen from the Atari driver ...
+ */
+static void adb_mouse_interrupt(char *buf, int nb)
+{
+    static int buttons = 7;
+
+  /*
+    Handler 1 -- 100cpi original Apple mouse protocol.
+    Handler 2 -- 200cpi original Apple mouse protocol.
+
+    For Apple's standard one-button mouse protocol the data array will
+    contain the following values:
+
+                BITS    COMMENTS
+    data[0] = 0000 0000 ADB packet identifer.
+    data[1] = ???? ???? (?)
+    data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
+    data[3] = bxxx xxxx First button and x-axis motion.
+    data[4] = byyy yyyy Second button and y-axis motion.
+
+    NOTE: data[0] is confirmed by the parent function and need not be
+    checked here.
+  */
+
+  /*
+    Handler 4 -- Apple Extended mouse protocol.
+
+    For Apple's 3-button mouse protocol the data array will contain the
+    following values:
+
+               BITS    COMMENTS
+    data[0] = 0000 0000 ADB packet identifer.
+    data[1] = 0100 0000 Extended protocol register.
+             Bits 6-7 are the device id, which should be 1.
+             Bits 4-5 are resolution which is in "units/inch".
+             The Logitech MouseMan returns these bits clear but it has
+             200/300cpi resolution.
+             Bits 0-3 are unique vendor id.
+    data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
+             Bits 2-3 should be 8 + 4.
+                     Bits 4-7 should be 3 for a mouse device.
+    data[3] = bxxx xxxx Left button and x-axis motion.
+    data[4] = byyy yyyy Second button and y-axis motion.
+    data[5] = byyy bxxx Third button and fourth button.  
+             Y is additiona. high bits of y-axis motion.  
+             X is additional high bits of x-axis motion.
+
+    NOTE: data[0] and data[2] are confirmed by the parent function and
+    need not be checked here.
+  */
+
+    /*
+     * 'buttons' here means 'button down' states!
+     * Button 1 (left)  : bit 2, busmouse button 3
+     * Button 2 (right) : bit 0, busmouse button 1
+     * Button 3 (middle): bit 1, busmouse button 2
+     */
+
+    /* x/y and buttons swapped */
+    
+    if (nb > 0)        {                               /* real packet : use buttons? */
+       if (console_loglevel >= 8)
+           printk("adb_mouse: real data; "); 
+       /* button 1 (left, bit 2) : always significant ! */
+       buttons = (buttons&3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
+       /* button 2 (middle) */
+       buttons = (buttons&5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
+       /* button 3 (right) present?
+        *  on a logitech mouseman, the right and mid buttons sometimes behave
+        *  strangely until they both have been pressed after booting. */
+       /* data valid only if extended mouse format ! (buf[3] = 0 else) */
+       if ( nb == 6 )
+           buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
+    } else {                                   /* fake packet : use 2+3 */
+       if (console_loglevel >= 8)
+           printk("adb_mouse: fake data; "); 
+       /* we only see state changes here, but the fake driver takes care
+        * to preserve state... button 1 state must stay unchanged! */
+       buttons = (buttons&4) | ((buf[2] & 0x80 ? 1 : 0) |
+                 (buf[3] & 0x80 ? 2 : 0));
+    }
+
+    add_mouse_randomness(((~buttons & 7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
+    mouse.buttons = buttons & 7;
+    mouse.dx += ((buf[2]&0x7f) < 64 ? (buf[2]&0x7f) : (buf[2]&0x7f)-128 );
+    mouse.dy -= ((buf[1]&0x7f) < 64 ? (buf[1]&0x7f) : (buf[1]&0x7f)-128 );
+
+    if (console_loglevel >= 8)
+        printk(" %X %X %X buttons %x dx %d dy %d \n", 
+               buf[1], buf[2], buf[3], mouse.buttons, mouse.dx, mouse.dy);
+    mouse.ready = 1;
+    wake_up_interruptible(&mouse.wait);
+    if (mouse.fasyncptr)
+       kill_fasync(mouse.fasyncptr, SIGIO);
+
+}
+
+static int fasync_mouse(struct file *filp, int on)
+{
+       int retval;
+
+       retval = fasync_helper(filp, on, &mouse.fasyncptr);
+       if (retval < 0)
+               return retval;
+       return 0;
+}
+
+static int release_mouse(struct inode *inode, struct file *file)
+{
+    fasync_mouse(file, 0);
+    if (--mouse.active)
+      return 0;
+
+    adb_mouse_interrupt_hook = NULL;
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+static int open_mouse(struct inode *inode, struct file *file)
+{
+    if (mouse.active++)
+       return 0;
+       
+    mouse.ready = 0;
+
+    mouse.dx = mouse.dy = 0;
+    adb_mouse_buttons = 0;
+    MOD_INC_USE_COUNT;
+    adb_mouse_interrupt_hook = adb_mouse_interrupt;
+    return 0;
+}
+
+static ssize_t write_mouse(struct file *file, const char *buffer,
+                          size_t count, loff_t *ppos)
+{
+    return -EINVAL;
+}
+
+static ssize_t read_mouse(struct file *file, char *buffer, size_t count,
+                         loff_t *ppos)
+{
+    int dx, dy, buttons;
+
+    if (count < 3)
+       return -EINVAL;
+    if (!mouse.ready)
+       return -EAGAIN;
+    dx = mouse.dx;
+    dy = mouse.dy;
+    buttons = mouse.buttons;
+    if (dx > 127)
+      dx = 127;
+    else if (dx < -128)
+      dx = -128;
+    if (dy > 127)
+      dy = 127;
+    else if (dy < -128)
+      dy = -128;
+    mouse.dx -= dx;
+    mouse.dy -= dy;
+    if (mouse.dx == 0 && mouse.dy == 0)
+      mouse.ready = 0;
+    if (put_user(buttons | 0x80, buffer++) ||
+       put_user((char) dx, buffer++) ||
+       put_user((char) dy, buffer++))
+      return -EFAULT;
+    if (count > 3)
+      if (clear_user(buffer, count - 3))
+       return -EFAULT;
+    return count;
+}
+
+static unsigned int mouse_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &mouse.wait, wait);
+       if (mouse.ready)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+struct file_operations adb_mouse_fops = {
+    NULL,              /* mouse_seek */
+    read_mouse,
+    write_mouse,
+    NULL,              /* mouse_readdir */
+    mouse_poll,
+    NULL,              /* mouse_ioctl */
+    NULL,              /* mouse_mmap */
+    open_mouse,
+    release_mouse,
+    NULL,
+    fasync_mouse,
+};
+
+#define ADB_MOUSE_MINOR        10
+
+static struct miscdevice adb_mouse = {
+    ADB_MOUSE_MINOR, "adbmouse", &adb_mouse_fops
+};
+
+__initfunc(int adb_mouse_init(void))
+{
+    mouse.active = 0;
+    mouse.ready = 0;
+    mouse.wait = NULL;
+
+    if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+           return -ENODEV;
+    printk(KERN_INFO "Macintosh ADB mouse installed.\n");
+    misc_register(&adb_mouse);
+    return 0;
+}
+
+
+#define        MIN_THRESHOLD 1
+#define        MAX_THRESHOLD 20        /* more seems not reasonable... */
+
+__initfunc(void adb_mouse_setup(char *str, int *ints))
+{
+    if (ints[0] < 1) {
+       printk( "adb_mouse_setup: no arguments!\n" );
+       return;
+    }
+    else if (ints[0] > 2) {
+       printk( "adb_mouse_setup: too many arguments\n" );
+    }
+
+    if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD)
+       printk( "adb_mouse_setup: bad threshold value (ignored)\n" );
+    else {
+       adb_mouse_x_threshold = ints[1];
+       adb_mouse_y_threshold = ints[1];
+       if (ints[0] > 1) {
+           if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD)
+               printk("adb_mouse_setup: bad threshold value (ignored)\n" );
+           else
+               adb_mouse_y_threshold = ints[2];
+       }
+    }
+       
+}
+
+#ifdef MODULE
+#include <asm/setup.h>
+
+int init_module(void)
+{
+    return adb_mouse_init();
+}
+
+void cleanup_module(void)
+{
+    misc_deregister(&adb_mouse);
+}
+#endif
index 69ddcb5c77818f78a5962a74dffca0a3ff87d937..1177ed1adfa7ee0b38074759c750ba1afc79a541 100644 (file)
@@ -1922,7 +1922,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        }
                        btv->win.sheight=v.height;
                        btv->win.swidth=v.width;
-+                      btv->win.bpp=((v.depth+1)&0x18)/8;
+                       btv->win.bpp=((v.depth+1)&0x38)/8;
                        btv->win.depth=v.depth;
                        btv->win.bpl=v.bytesperline;
                        
@@ -2313,6 +2313,8 @@ static struct vidbases vbs[] = {
                "DEC DC21030", PCI_BASE_ADDRESS_0},
        { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL,
                "Matrox Millennium", PCI_BASE_ADDRESS_1},
+       { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2,
+               "Matrox Millennium II", PCI_BASE_ADDRESS_0},
        { PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1},
        { PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128, 
                "Number Nine Imagine 128", PCI_BASE_ADDRESS_0},
index af6a7a5c4db155691849120192489dc06167976b..f5c8158fbf30015bf9a1bda01b526eaa53c35e75 100644 (file)
@@ -1256,13 +1256,12 @@ static void setterm_command(int currcons)
 
 static void insert_char(int currcons, unsigned int nr)
 {
-       unsigned int i = x;
-       unsigned short * p, * q = (unsigned short *) pos;
+       unsigned short *p, *q = (unsigned short *) pos;
 
-       while (i++ <= video_num_columns - nr) {
+       p = q + video_num_columns - nr - x;
+       while (--p >= q)
                scr_writew(scr_readw(p), p + nr);
-               p++;
-       }
+
        memsetw(q, video_erase_char, nr*2);
        need_wrap = 0;
 }
index 7bb4ec634a63161b77259dec655b3c6a5b540072..8ca6d4e9b12d261b1494894a549d99351b773548 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/lp_intern.h>
 
 static int minor = -1;
+MODULE_PARM(minor,"i");
 
 static void lp_int_out(int, int);
 static int lp_int_busy(int);
diff --git a/drivers/char/mac_SCC.c b/drivers/char/mac_SCC.c
new file mode 100644 (file)
index 0000000..0295ab4
--- /dev/null
@@ -0,0 +1,1543 @@
+/*
+ * mac_SCC.c: m68k version of
+ *
+ * macserial.c: Serial port driver for Power Macintoshes.
+ *             Extended for the 68K mac by Alan Cox.
+ *              Rewritten to m68k serial design by Michael Schmitz
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/*
+ * Design note for the m68k rewrite:
+ * The structure of the m68k serial code requires separation of the low-level
+ * functions that talk directly to the hardware from the Linux serial driver 
+ * code interfacing to the tty layer. The reason for this separation is simply
+ * the fact that the m68k serial hardware is, unlike the i386, based on a 
+ * variety of chips, and the rs_* serial routines need to be shared.
+ *
+ * I've tried to make consistent use of the async_struct info populated in the
+ * midlevel code, and introduced an async_private struct to hold the Macintosh 
+ * SCC internals (this was added to the async_struct for the PowerMac driver).
+ * Exception: the console and kgdb hooks still use the zs_soft[] data, and this
+ * is still filled in by the probe_sccs() routine, which provides some data 
+ * for mac_SCC_init as well. Interrupts are registered in mac_SCC_init, so 
+ * the console/kgdb stuff probably won't work before proper serial init, and 
+ * I have to rely on keeping info and zs_soft consistent at least for the 
+ * console/kgdb port.
+ *
+ * Update (16-11-97): The SCC interrupt handling was suffering from the problem
+ * that the autovector SCC interrupt was registered only once, hence only one
+ * async_struct was passed to the interrupt function and only interrupts from 
+ * the corresponding channel could be handled (yes, major design flaw).
+ * The autovector interrupt is now registered by the main interrupt initfunc, 
+ * and uses a handler that will call the registered SCC specific interrupts in 
+ * turn. The SCC init has to register these as machspec interrupts now, as is 
+ * done for the VIA interrupts elsewhere.
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/macints.h>
+#ifndef CONFIG_MAC
+#include <asm/prom.h>
+#endif
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+
+#include "mac_SCC.h"
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on NUM_SERIAL, so we could support any number of
+ * Z8530s, but for now...
+ */
+#define NUM_SERIAL     2               /* Max number of ZS chips supported */
+#define NUM_CHANNELS   (NUM_SERIAL * 2)        /* 2 channels per chip */
+
+#ifdef CONFIG_MAC
+/*
+ *     All the Macintosh 68K boxes that have an MMU also have hardware
+ *     recovery delays.
+ */
+#define RECOVERY_DELAY
+#else
+/* On PowerMacs, the hardware takes care of the SCC recovery time,
+   but we need the eieio to make sure that the accesses occur
+   in the order we want. */
+#define RECOVERY_DELAY eieio()
+#endif
+
+struct mac_zschannel *zs_kgdbchan;
+struct mac_zschannel zs_channels[NUM_CHANNELS];
+
+struct m68k_async_struct  zs_soft[NUM_CHANNELS];
+struct m68k_async_private zs_soft_private[NUM_CHANNELS];
+int zs_channels_found;
+struct m68k_async_struct *zs_chain;    /* list of all channels */
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+/** struct tty_struct *zs_constty; **/
+
+/* Console hooks... */
+static int zs_cons_chanout = 0;
+static int zs_cons_chanin = 0;
+struct m68k_async_struct  *zs_consinfo = 0;
+struct mac_zschannel *zs_conschan;
+
+static unsigned char kgdb_regs[16] = {
+       0, 0, 0,                /* write 0, 1, 2 */
+       (Rx8 | RxENABLE),       /* write 3 */
+       (X16CLK | SB1 | PAR_EVEN), /* write 4 */
+       (Tx8 | TxENAB),         /* write 5 */
+       0, 0, 0,                /* write 6, 7, 8 */
+       (NV),                   /* write 9 */
+       (NRZ),                  /* write 10 */
+       (TCBR | RCBR),          /* write 11 */
+       1, 0,                   /* 38400 baud divisor, write 12 + 13 */
+       (BRENABL),              /* write 14 */
+       (DCDIE)                 /* write 15 */
+};
+
+#define ZS_CLOCK         3686400       /* Z8530 RTxC input clock rate */
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void probe_sccs(void);
+
+#ifndef MIN
+#define MIN(a,b)       ((a) < (b) ? (a) : (b))
+#endif
+
+
+/***************************** Prototypes *****************************/
+
+static void SCC_init_port( struct m68k_async_struct *info, int type, int channel );
+#if 0
+#ifdef MODULE
+static void SCC_deinit_port( struct m68k_async_struct *info, int channel );
+#endif
+#endif
+
+/* FIXME !!! Currently, only autovector interrupt used! */
+#if 0
+static void SCC_rx_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_spcond_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_tx_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_stat_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_ri_int (int irq, void *data, struct pt_regs *fp);
+#endif
+
+static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct
+                           *tty, struct file *file );
+static void SCC_init( struct m68k_async_struct *info );
+static void SCC_deinit( struct m68k_async_struct *info, int leave_dtr );
+static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag );
+static int SCC_check_custom_divisor( struct m68k_async_struct *info, int baud_base,
+                                   int divisor );
+static void SCC_change_speed( struct m68k_async_struct *info );
+#if 0
+static int SCC_clocksrc( unsigned baud_base, unsigned channel );
+#endif
+static void SCC_throttle( struct m68k_async_struct *info, int status );
+static void SCC_set_break( struct m68k_async_struct *info, int break_flag );
+static void SCC_get_serial_info( struct m68k_async_struct *info, struct
+                               serial_struct *retinfo );
+static unsigned int SCC_get_modem_info( struct m68k_async_struct *info );
+static int SCC_set_modem_info( struct m68k_async_struct *info, int new_dtr, int
+                             new_rts );
+static int SCC_ioctl( struct tty_struct *tty, struct file *file, struct
+                    m68k_async_struct *info, unsigned int cmd, unsigned long arg );
+static void SCC_stop_receive (struct m68k_async_struct *info);
+static int SCC_trans_empty (struct m68k_async_struct *info);
+
+/************************* End of Prototypes **************************/
+
+
+static SERIALSWITCH SCC_switch = {
+       SCC_init, SCC_deinit, SCC_enab_tx_int,
+       SCC_check_custom_divisor, SCC_change_speed,
+       SCC_throttle, SCC_set_break,
+       SCC_get_serial_info, SCC_get_modem_info,
+       SCC_set_modem_info, SCC_ioctl, SCC_stop_receive, SCC_trans_empty,
+       SCC_check_open
+};
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 0 };
+
+/* 
+ * Reading and writing Z8530 registers.
+ */
+static inline unsigned char read_zsreg(struct mac_zschannel *channel,
+                                      unsigned char reg)
+{
+       unsigned char retval;
+
+       if (reg != 0) {
+               *channel->control = reg;
+               RECOVERY_DELAY;
+       }
+       retval = *channel->control;
+       RECOVERY_DELAY;
+       return retval;
+}
+
+static inline void write_zsreg(struct mac_zschannel *channel,
+                              unsigned char reg, unsigned char value)
+{
+       if (reg != 0) {
+               *channel->control = reg;
+               RECOVERY_DELAY;
+       }
+       *channel->control = value;
+       RECOVERY_DELAY;
+       return;
+}
+
+static inline unsigned char read_zsdata(struct mac_zschannel *channel)
+{
+       unsigned char retval;
+
+       retval = *channel->data;
+       RECOVERY_DELAY;
+       return retval;
+}
+
+static inline void write_zsdata(struct mac_zschannel *channel,
+                               unsigned char value)
+{
+       *channel->data = value;
+       RECOVERY_DELAY;
+       return;
+}
+
+static inline void load_zsregs(struct mac_zschannel *channel,
+                              unsigned char *regs)
+{
+       ZS_CLEARERR(channel);
+       ZS_CLEARFIFO(channel);
+       /* Load 'em up */
+       write_zsreg(channel, R4, regs[R4]);
+       write_zsreg(channel, R10, regs[R10]);
+       write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+       write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+       write_zsreg(channel, R1, regs[R1]);
+       write_zsreg(channel, R9, regs[R9]);
+       write_zsreg(channel, R11, regs[R11]);
+       write_zsreg(channel, R12, regs[R12]);
+       write_zsreg(channel, R13, regs[R13]);
+       write_zsreg(channel, R14, regs[R14]);
+       write_zsreg(channel, R15, regs[R15]);
+       write_zsreg(channel, R3, regs[R3]);
+       write_zsreg(channel, R5, regs[R5]);
+       return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct m68k_async_struct *ss, int set)
+{
+       if (set)
+               ss->private->curregs[5] |= (RTS | DTR);
+       else
+               ss->private->curregs[5] &= ~(RTS | DTR);
+       write_zsreg(ss->private->zs_channel, 5, ss->private->curregs[5]);
+       return;
+}
+
+static inline void kgdb_chaninit(struct m68k_async_struct *ss, int intson, int bps)
+{
+       int brg;
+
+       if (intson) {
+               kgdb_regs[R1] = INT_ALL_Rx;
+               kgdb_regs[R9] |= MIE;
+       } else {
+               kgdb_regs[R1] = 0;
+               kgdb_regs[R9] &= ~MIE;
+       }
+       brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+       kgdb_regs[R12] = brg;
+       kgdb_regs[R13] = brg >> 8;
+       load_zsregs(ss->private->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct m68k_async_struct *ss)
+{
+       struct mac_zschannel *channel = ss->private->zs_channel;
+       int brg;
+
+       /* The baud rate is split up between two 8-bit registers in
+        * what is termed 'BRG time constant' format in my docs for
+        * the chip, it is a function of the clk rate the chip is
+        * receiving which happens to be constant.
+        */
+       brg = (read_zsreg(channel, 13) << 8);
+       brg |= read_zsreg(channel, 12);
+       return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->private->clk_divisor)));
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void SCC_recv_clear(struct mac_zschannel *zsc)
+{
+       write_zsreg(zsc, 0, ERR_RES);
+       write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+extern void breakpoint(void);  /* For the KGDB frame character */
+
+static /*_INLINE_*/ void receive_chars(struct m68k_async_struct *info,
+                                  struct pt_regs *regs)
+{
+       struct tty_struct *tty = info->tty;
+       unsigned char ch, stat, flag;
+
+       while ((read_zsreg(info->private->zs_channel, 0) & Rx_CH_AV) != 0) {
+
+               stat = read_zsreg(info->private->zs_channel, R1);
+               ch = read_zsdata(info->private->zs_channel);
+
+#ifdef SCC_DEBUG
+               printk("mac_SCC: receive_chars stat=%X char=%X \n", stat, ch);
+#endif
+
+#if 0  /* KGDB not yet supported */
+               /* Look for kgdb 'stop' character, consult the gdb documentation
+                * for remote target debugging and arch/sparc/kernel/sparc-stub.c
+                * to see how all this works.
+                */
+               if ((info->kgdb_channel) && (ch =='\003')) {
+                       breakpoint();
+                       continue;
+               }
+#endif
+
+               if (!tty)
+                       continue;
+
+               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+                       tty_flip_buffer_push(tty);
+               
+               if (stat & Rx_OVR) {
+                       flag = TTY_OVERRUN;
+                       /* reset the error indication */
+                       write_zsreg(info->private->zs_channel, 0, ERR_RES);
+               } else if (stat & FRM_ERR) {
+                       /* this error is not sticky */
+                       flag = TTY_FRAME;
+               } else if (stat & PAR_ERR) {
+                       flag = TTY_PARITY;
+                       /* reset the error indication */
+                       write_zsreg(info->private->zs_channel, 0, ERR_RES);
+               } else
+                       flag = 0;
+
+               if (tty->flip.buf_num 
+                   && tty->flip.count >= TTY_FLIPBUF_SIZE) {
+#ifdef SCC_DEBUG_OVERRUN
+                       printk("mac_SCC: flip buffer overrun!\n");
+#endif
+                       return;
+               }
+
+               if (!tty->flip.buf_num 
+                   && tty->flip.count >= 2*TTY_FLIPBUF_SIZE) {
+                       printk("mac_SCC: double flip buffer overrun!\n");
+                       return;
+               }
+
+               tty->flip.count++;
+               *tty->flip.flag_buf_ptr++ = flag;
+               *tty->flip.char_buf_ptr++ = ch;
+               info->icount.rx++;
+               tty_flip_buffer_push(tty);
+       }
+#if 0
+clear_and_exit:
+       SCC_recv_clear(info->private->zs_channel);
+#endif
+}
+
+/* that's SCC_enable_tx_int, basically */
+
+static void transmit_chars(struct m68k_async_struct *info)
+{
+       if ((read_zsreg(info->private->zs_channel, 0) & Tx_BUF_EMP) == 0)
+               return;
+       info->private->tx_active = 0;
+
+       if (info->x_char) {
+               /* Send next char */
+               write_zsdata(info->private->zs_channel, info->x_char);
+               info->x_char = 0;
+               info->private->tx_active = 1;
+               return;
+       }
+
+       if ((info->xmit_cnt <= 0) || info->tty->stopped 
+            || info->private->tx_stopped) {
+               write_zsreg(info->private->zs_channel, 0, RES_Tx_P);
+               return;
+       }
+
+       /* Send char */
+       write_zsdata(info->private->zs_channel, info->xmit_buf[info->xmit_tail++]);
+       info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+       info->icount.tx++;
+       info->xmit_cnt--;
+       info->private->tx_active = 1;
+
+       if (info->xmit_cnt < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+}
+
+static /*_INLINE_*/ void status_handle(struct m68k_async_struct *info)
+{
+       unsigned char status;
+
+       /* Get status from Read Register 0 */
+       status = read_zsreg(info->private->zs_channel, 0);
+
+       /* Check for DCD transitions */
+       if (((status ^ info->private->read_reg_zero) & DCD) != 0
+           && info->tty && C_CLOCAL(info->tty)) {
+               if (status & DCD) {
+                       wake_up_interruptible(&info->open_wait);
+               } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+                       if (info->tty)
+                               tty_hangup(info->tty);
+               }
+       }
+
+       /* Check for CTS transitions */
+       if (info->tty && C_CRTSCTS(info->tty)) {
+               /*
+                * For some reason, on the Power Macintosh,
+                * it seems that the CTS bit is 1 when CTS is
+                * *negated* and 0 when it is asserted.
+                * The DCD bit doesn't seem to be inverted
+                * like this.
+                */
+               if ((status & CTS) == 0) {
+                       if (info->private->tx_stopped) {
+                               info->private->tx_stopped = 0;
+                               if (!info->private->tx_active)
+                                       transmit_chars(info);
+                       }
+               } else {
+                       info->private->tx_stopped = 1;
+               }
+       }
+
+       /* Clear status condition... */
+       write_zsreg(info->private->zs_channel, 0, RES_EXT_INT);
+       info->private->read_reg_zero = status;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void mac_SCC_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct m68k_async_struct *info = (struct m68k_async_struct *) dev_id;
+       unsigned char zs_intreg;
+       int shift;
+
+       /* NOTE: The read register 3, which holds the irq status,
+        *       does so for both channels on each chip.  Although
+        *       the status value itself must be read from the A
+        *       channel and is only valid when read from channel A.
+        *       Yes... broken hardware...
+        */
+#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+#ifdef SCC_DEBUG
+       printk("mac_SCC: interrupt; port: %lx channel: %lx \n", 
+               info->port, info->private->zs_channel);
+#endif
+
+       if (info->private->zs_chan_a == info->private->zs_channel)
+               shift = 3;      /* Channel A */
+       else
+               shift = 0;      /* Channel B */
+
+       for (;;) {
+               zs_intreg = read_zsreg(info->private->zs_chan_a, 3);
+#ifdef SCC_DEBUG
+               printk("mac_SCC: status %x shift %d shifted %x \n", 
+               zs_intreg, shift, zs_intreg >> shift);
+#endif
+               zs_intreg = zs_intreg >> shift;
+               if ((zs_intreg & CHAN_IRQMASK) == 0)
+                       break;
+
+               if (zs_intreg & CHBRxIP)
+                       receive_chars(info, regs);
+               if (zs_intreg & CHBTxIP)
+                       transmit_chars(info);
+               if (zs_intreg & CHBEXT)
+                       status_handle(info);
+       }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * ------------------------------------------------------------
+ */
+
+static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag )
+{
+       unsigned long flags;
+
+       if (enab_flag) {
+#if 0
+               save_flags(flags); cli();
+               if (info->private->curregs[5] & TxENAB) {
+                       info->private->curregs[5] &= ~TxENAB;
+                       info->private->pendregs[5] &= ~TxENAB;
+                       write_zsreg(info->private->zs_channel, 5, 
+                                   info->private->curregs[5]);
+               }
+               restore_flags(flags);
+#endif
+       /* FIXME: should call transmit_chars here ??? */
+               transmit_chars(info);
+       } else {
+       save_flags(flags); cli();
+#if 0
+               if (  info->xmit_cnt && info->xmit_buf && 
+                   !(info->private->curregs[5] & TxENAB)) {
+                       info->private->curregs[5] |= TxENAB;
+                       info->private->pendregs[5] = info->private->curregs[5];
+                       write_zsreg(info->private->zs_channel, 5, 
+                                   info->private->curregs[5]);
+               }
+#else
+               if ( info->xmit_cnt && info->xmit_buf && 
+                   !info->private->tx_active) {
+                       transmit_chars(info);
+               }
+#endif
+               restore_flags(flags);   
+       }
+
+}
+
+#if 0
+/*
+ * leftover from original driver ...
+ */
+static int SCC_startup(struct m68k_async_struct * info)
+{
+       unsigned long flags;
+
+       save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
+#endif
+
+       /*
+        * Clear the receive FIFO.
+        */
+       ZS_CLEARFIFO(info->private->zs_channel);
+       info->xmit_fifo_size = 1;
+
+       /*
+        * Clear the interrupt registers.
+        */
+       write_zsreg(info->private->zs_channel, 0, ERR_RES);
+       write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
+
+       /*
+        * Turn on RTS and DTR.
+        */
+       zs_rtsdtr(info, 1);
+
+       /*
+        * Finally, enable sequencing and interrupts
+        */
+       info->private->curregs[1] = (info->private->curregs[1] & ~0x18) 
+                                   | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+       info->private->pendregs[1] = info->private->curregs[1];
+       info->private->curregs[3] |= (RxENABLE | Rx8);
+       info->private->pendregs[3] = info->private->curregs[3];
+       info->private->curregs[5] |= (TxENAB | Tx8);
+       info->private->pendregs[5] = info->private->curregs[5];
+       info->private->curregs[9] |= (NV | MIE);
+       info->private->pendregs[9] = info->private->curregs[9];
+       write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+       write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+       write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
+
+       /*
+        * Set the speed of the serial port
+        */
+       SCC_change_speed(info);
+
+       /* Save the current value of RR0 */
+       info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
+
+       restore_flags(flags);
+       return 0;
+}
+#endif
+
+/* FIXME: are these required ?? */
+static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct *tty,
+                         struct file *file )
+{
+       /* check on the basis of info->whatever ?? */
+       if (info->private->kgdb_channel || info->private->is_cons)
+               return -EBUSY;
+       return( 0 );
+}
+
+static void SCC_init( struct m68k_async_struct *info )
+{
+       /* FIXME: init currently done in probe_sccs() */
+
+       /* BUT: startup part needs to be done here! */
+
+#ifdef SCC_DEBUG
+       printk("mac_SCC: init, info %lx, info->port %lx  \n", info, info->port);
+#endif
+       /*
+        * Clear the receive FIFO.
+        */
+       ZS_CLEARFIFO(info->private->zs_channel);
+       info->xmit_fifo_size = 1;
+
+       /*
+        * Clear the interrupt registers.
+        */
+       write_zsreg(info->private->zs_channel, 0, ERR_RES);
+       write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
+
+       /*
+        * Turn on RTS and DTR.
+        */
+       zs_rtsdtr(info, 1);
+
+       /*
+        * Finally, enable sequencing and interrupts
+        */
+       info->private->curregs[1] = (info->private->curregs[1] & ~0x18) 
+                                   | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+       info->private->pendregs[1] = info->private->curregs[1];
+       info->private->curregs[3] |= (RxENABLE | Rx8);
+       info->private->pendregs[3] = info->private->curregs[3];
+       info->private->curregs[5] |= (TxENAB | Tx8);
+       info->private->pendregs[5] = info->private->curregs[5];
+       info->private->curregs[9] |= (NV | MIE);
+       info->private->pendregs[9] = info->private->curregs[9];
+       write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+       write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+       write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
+
+       /*
+        * Set the speed of the serial port - done in startup() !!
+        */
+#if 0
+       SCC_change_speed(info);
+#endif
+
+       /* Save the current value of RR0 */
+       info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
+
+}
+
+static void SCC_init_port( struct m68k_async_struct *info, int type, int channel )
+{
+       static int got_autovector = 0;
+
+#ifdef SCC_DEBUG
+       printk("mac_SCC: init_port, info %x \n", info);
+#endif
+       info->sw = &SCC_switch;
+       info->private = &zs_soft_private[channel];
+       info->private->zs_channel = &zs_channels[channel];
+       info->irq = IRQ4;
+       info->private->clk_divisor = 16;
+       info->private->zs_baud = get_zsbaud(info);
+       info->port = (int) info->private->zs_channel->control;
+
+       /*
+        * MSch: Extended interrupt scheme:
+        * The generic m68k interrupt code can't use multiple handlers for
+        * the same interrupt source (no chained interrupts).
+        * We have to plug in a 'master' interrupt handler instead, calling 
+        * mac_SCC_interrupt with the proper arguments ...
+        */
+
+       if (!got_autovector) {
+               if(sys_request_irq(IRQ4, mac_SCC_handler, 0, "SCC master", info))
+                       panic("macserial: can't get irq %d", IRQ4);
+#ifdef SCC_DEBUG
+               printk("mac_SCC: got SCC master interrupt %d, channel %d info %p\n",
+                       IRQ4, channel, info);
+#endif
+               got_autovector = 1;
+       }
+
+       if (info->private->zs_chan_a == info->private->zs_channel) {
+               /* Channel A */
+               if (request_irq(IRQ_SCCA, mac_SCC_interrupt, 0, "SCC A", info))
+                       panic("mac_SCC: can't get irq %d", IRQ_SCCA);
+#ifdef SCC_DEBUG
+               printk("mac_SCC: got SCC A interrupt %d, channel %d info %p\n",
+                       IRQ_SCCA, channel, info);
+#endif
+       } else {
+               /* Channel B */
+               if (request_irq(IRQ_SCCB, mac_SCC_interrupt, 0, "SCC B", info))
+                       panic("mac_SCC: can't get irq %d", IRQ_SCCB);
+#ifdef SCC_DEBUG
+               printk("mac_SCC: got SCC B interrupt %d, channel %d info %p\n", 
+                       IRQ_SCCB, channel, info);
+#endif
+       }
+
+       /* If console serial line, then enable interrupts. */
+       if (info->private->is_cons) {
+               printk("mac_SCC: console line %lx; enabling interrupt!\n", info);
+               write_zsreg(info->private->zs_channel, R1,
+                           (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
+               write_zsreg(info->private->zs_channel, R9, (NV | MIE));
+               write_zsreg(info->private->zs_channel, R10, (NRZ));
+               write_zsreg(info->private->zs_channel, R3, (Rx8 | RxENABLE));
+               write_zsreg(info->private->zs_channel, R5, (Tx8 | TxENAB));
+       }
+       /* If this is the kgdb line, enable interrupts because we
+        * now want to receive the 'control-c' character from the
+        * client attached to us asynchronously.
+        */
+       if (info->private->kgdb_channel) {
+               printk("mac_SCC: kgdb line %lx; enabling interrupt!\n", info);
+               kgdb_chaninit(info, 1, info->private->zs_baud);
+       }
+       /* Report settings (in m68kserial.c) */
+#ifndef CONFIG_MAC
+       printk("ttyS%d at 0x%08x (irq = %d)", info->line, 
+                      info->port, info->irq);
+       printk(" is a Z8530 SCC\n");
+#endif
+
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void SCC_deinit(struct m68k_async_struct * info, int leave_dtr)
+{
+       unsigned long   flags;
+
+       save_flags(flags); cli(); /* Disable interrupts */
+       
+       info->private->pendregs[1] = info->private->curregs[1] = 0;
+       write_zsreg(info->private->zs_channel, 1, 0);   /* no interrupts */
+
+       info->private->curregs[3] &= ~RxENABLE;
+       info->private->pendregs[3] = info->private->curregs[3];
+       write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+
+       info->private->curregs[5] &= ~TxENAB;
+
+       if (!leave_dtr)
+               info->private->curregs[5] &= ~(DTR | RTS);
+       else
+               info->private->curregs[5] &= ~(RTS);
+
+       info->private->pendregs[5] = info->private->curregs[5];
+       write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+
+       restore_flags(flags);
+}
+
+/* FIXME !!! */
+static int SCC_check_custom_divisor( struct m68k_async_struct *info,
+                                   int baud_base, int divisor )
+{
+       return 0;
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void SCC_change_speed(struct m68k_async_struct *info)
+{
+       unsigned short port;
+       unsigned cflag;
+       int     i;
+       int     brg;
+       unsigned long flags;
+
+       if (!info->tty || !info->tty->termios)
+               return;
+       cflag = info->tty->termios->c_cflag;
+       if (!(port = info->port))
+               return;
+       i = cflag & CBAUD;
+
+       if (i == 0 && !(info->flags & ASYNC_SPD_MASK)) {
+               /* speed == 0 -> drop DTR */
+               save_flags(flags);
+               cli();
+               info->private->curregs[5] &= ~(DTR | RTS);
+               write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+               restore_flags(flags);
+               return;
+       }
+
+
+       if (i & CBAUDEX) {
+               /* XXX CBAUDEX is not obeyed.
+                * It is impossible at a 32bits PPC.  XXX??
+                * But we have to report this to user ... someday.
+                */
+               i = B9600;
+       }
+
+       save_flags(flags); cli();
+       info->private->zs_baud = baud_table[i];
+       info->private->clk_divisor = 16;
+
+       info->private->curregs[4] = X16CLK;
+       info->private->curregs[11] = TCBR | RCBR;
+       brg = BPS_TO_BRG(info->private->zs_baud, 
+                        ZS_CLOCK/info->private->clk_divisor);
+       info->private->curregs[12] = (brg & 255);
+       info->private->curregs[13] = ((brg >> 8) & 255);
+       info->private->curregs[14] = BRENABL;
+
+       /* byte size and parity */
+       info->private->curregs[3] &= ~RxNBITS_MASK;
+       info->private->curregs[5] &= ~TxNBITS_MASK;
+       switch (cflag & CSIZE) {
+       case CS5:
+               info->private->curregs[3] |= Rx5;
+               info->private->curregs[5] |= Tx5;
+               break;
+       case CS6:
+               info->private->curregs[3] |= Rx6;
+               info->private->curregs[5] |= Tx6;
+               break;
+       case CS7:
+               info->private->curregs[3] |= Rx7;
+               info->private->curregs[5] |= Tx7;
+               break;
+       case CS8:
+       default: /* defaults to 8 bits */
+               info->private->curregs[3] |= Rx8;
+               info->private->curregs[5] |= Tx8;
+               break;
+       }
+       info->private->pendregs[3] = info->private->curregs[3];
+       info->private->pendregs[5] = info->private->curregs[5];
+
+       info->private->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
+       if (cflag & CSTOPB) {
+               info->private->curregs[4] |= SB2;
+       } else {
+               info->private->curregs[4] |= SB1;
+       }
+       if (cflag & PARENB) {
+               info->private->curregs[4] |= PAR_ENA;
+       }
+       if (!(cflag & PARODD)) {
+               info->private->curregs[4] |= PAR_EVEN;
+       }
+       info->private->pendregs[4] = info->private->curregs[4];
+
+       info->private->curregs[15] &= ~(DCDIE | CTSIE);
+       if (!(cflag & CLOCAL)) {
+               info->private->curregs[15] |= DCDIE;
+       }
+       if (cflag & CRTSCTS) {
+               info->private->curregs[15] |= CTSIE;
+               if ((read_zsreg(info->private->zs_channel, 0) & CTS) != 0)
+                       info->private->tx_stopped = 1;
+       } else
+               info->private->tx_stopped = 0;
+       info->private->pendregs[15] = info->private->curregs[15];
+
+       /* Load up the new values */
+       load_zsregs(info->private->zs_channel, info->private->curregs);
+
+       restore_flags(flags);
+}
+
+/* This is for console output over ttya/ttyb */
+static void SCC_put_char(char ch)
+{
+       struct mac_zschannel *chan = zs_conschan;
+       int loops = 0;
+       unsigned long flags;
+
+       if(!chan)
+               return;
+
+       save_flags(flags); cli();
+       while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0 && loops < 10000) {
+               loops++;
+               udelay(5);
+       }
+       write_zsdata(chan, ch);
+       restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+       struct mac_zschannel *chan = zs_kgdbchan;
+
+       while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+               udelay(5);
+       write_zsdata(chan, kgdb_char);
+}
+
+char getDebugChar(void)
+{
+       struct mac_zschannel *chan = zs_kgdbchan;
+
+       while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+               udelay(5);
+       return read_zsdata(chan);
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void SCC_fair_output(void)
+{
+       int left;               /* Output no more than that */
+       unsigned long flags;
+       struct m68k_async_struct *info = zs_consinfo;
+       char c;
+
+       if (info == 0) return;
+       if (info->xmit_buf == 0) return;
+
+       save_flags(flags);  cli();
+       left = info->xmit_cnt;
+       while (left != 0) {
+               c = info->xmit_buf[info->xmit_tail];
+               info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt--;
+               restore_flags(flags);
+
+               SCC_put_char(c);
+
+               save_flags(flags);  cli();
+               left = MIN(info->xmit_cnt, left-1);
+       }
+
+       restore_flags(flags);
+       return;
+}
+
+/*
+ * zs_console_print is registered for printk.
+ */
+static void zs_console_print(const char *p)
+{
+       char c;
+
+       while ((c = *(p++)) != 0) {
+               if (c == '\n')
+                       SCC_put_char('\r');
+               SCC_put_char(c);
+       }
+
+       /* Comment this if you want to have a strict interrupt-driven output */
+       SCC_fair_output();
+}
+
+/* FIXME: check with SCC_enab_tx_int!! */
+#if 0
+static void rs_flush_chars(struct tty_struct *tty)
+{
+       struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+               return;
+
+       if (info->xmit_cnt <= 0 || tty->stopped || info->private->tx_stopped ||
+           !info->xmit_buf)
+               return;
+
+       /* Enable transmitter */
+       save_flags(flags); cli();
+       transmit_chars(info);
+       restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+                   const unsigned char *buf, int count)
+{
+       int     c, total = 0;
+       struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "rs_write"))
+               return 0;
+
+       if (!tty || !info->xmit_buf)
+               return 0;
+
+       save_flags(flags);
+       while (1) {
+               cli();          
+               c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                  SERIAL_XMIT_SIZE - info->xmit_head));
+               if (c <= 0)
+                       break;
+
+               if (from_user) {
+                       down(&tmp_buf_sem);
+                       memcpy_fromfs(tmp_buf, buf, c);
+                       c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                      SERIAL_XMIT_SIZE - info->xmit_head));
+                       memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+                       up(&tmp_buf_sem);
+               } else
+                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
+               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+               info->xmit_cnt += c;
+               restore_flags(flags);
+               buf += c;
+               count -= c;
+               total += c;
+       }
+       if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
+           && !info->tx_active)
+               transmit_chars(info);
+       restore_flags(flags);
+       return total;
+}
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void SCC_throttle(struct m68k_async_struct *info, int status)
+{
+       unsigned long   flags;
+
+       save_flags(flags); 
+       cli();
+
+       if (status) {
+               /*
+                * Here we want to turn off the RTS line.  On Macintoshes,
+                * we only get the DTR line, which goes to both DTR and
+                * RTS on the modem.  RTS doesn't go out to the serial
+                * port socket.  So you should make sure your modem is
+                * set to ignore DTR if you're using CRTSCTS.
+                */
+               info->private->curregs[5] &= ~(DTR | RTS);
+               info->private->pendregs[5] &= ~(DTR | RTS);
+               write_zsreg(info->private->zs_channel, 5, 
+                           info->private->curregs[5]);
+       } else {
+               /* Assert RTS and DTR lines */
+               info->private->curregs[5] |= DTR | RTS;
+               info->private->pendregs[5] |= DTR | RTS;
+               write_zsreg(info->private->zs_channel, 5, 
+                           info->private->curregs[5]);
+       }
+
+       restore_flags(flags);
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static void SCC_get_serial_info(struct m68k_async_struct * info,
+                          struct serial_struct * retinfo)
+{
+       struct serial_struct tmp;
+  
+       retinfo->baud_base = info->baud_base;
+       retinfo->custom_divisor = info->custom_divisor;
+}
+
+/* FIXME: set_serial_info needs check_custom_divisor !!! */
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space. 
+ */
+static int SCC_get_lsr_info(struct m68k_async_struct * info, unsigned int *value)
+{
+       unsigned char status;
+
+       cli();
+       status = read_zsreg(info->private->zs_channel, 0);
+       sti();
+       return status;
+}
+
+static unsigned int SCC_get_modem_info(struct m68k_async_struct *info)
+{
+       unsigned char control, status;
+       unsigned int result;
+
+       cli();
+       control = info->private->curregs[5];
+       status = read_zsreg(info->private->zs_channel, 0);
+       sti();
+       result =  ((control & RTS) ? TIOCM_RTS: 0)
+               | ((control & DTR) ? TIOCM_DTR: 0)
+               | ((status  & DCD) ? TIOCM_CAR: 0)
+               | ((status  & CTS) ? 0: TIOCM_CTS);
+       return result;
+}
+
+/* FIXME: zs_setdtr was used in rs_open ... */
+
+static int SCC_set_modem_info(struct m68k_async_struct *info, 
+                             int new_dtr, int new_rts)
+{
+       int error;
+       unsigned int arg, bits;
+
+       bits = (new_rts ? RTS: 0) + (new_dtr ? DTR: 0);
+       info->private->curregs[5] = (info->private->curregs[5] & ~(DTR | RTS)) | bits;
+       info->private->pendregs[5] = info->private->curregs[5];
+       write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+       sti();
+       return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void SCC_set_break(struct m68k_async_struct * info, int break_flag)
+{
+       unsigned long   flags;
+
+       save_flags(flags);
+       cli();
+
+       if (break_flag) {
+               info->private->curregs[5] |= SND_BRK;
+               write_zsreg(info->private->zs_channel, 5, 
+                           info->private->curregs[5]);
+       } else {
+               info->private->curregs[5] &= ~SND_BRK;
+               write_zsreg(info->private->zs_channel, 5, 
+                           info->private->curregs[5]);
+       }
+
+       restore_flags(flags);
+}
+
+/* FIXME: these have to be enabled in rs_ioctl !! */
+
+static int SCC_ioctl(struct tty_struct *tty, struct file * file,
+                   struct m68k_async_struct * info, unsigned int cmd, 
+                   unsigned long arg)
+{
+       int error;
+       int retval;
+
+       switch (cmd) {
+               case TIOCSERGETLSR: /* Get line status register */
+                       error = verify_area(VERIFY_WRITE, (void *) arg,
+                               sizeof(unsigned int));
+                       if (error)
+                               return error;
+                       else
+                           return SCC_get_lsr_info(info, (unsigned int *) arg);
+
+               case TIOCSERGSTRUCT:
+                       error = verify_area(VERIFY_WRITE, (void *) arg,
+                                               sizeof(struct m68k_async_struct));
+                       if (error)
+                               return error;
+                       copy_to_user((struct m68k_async_struct *) arg,
+                                     info, sizeof(struct m68k_async_struct));
+                       return 0;
+                       
+               default:
+                       return -ENOIOCTLCMD;
+               }
+       return 0;
+}
+
+static void SCC_stop_receive (struct m68k_async_struct *info)
+{
+       /* disable Rx */
+       info->private->curregs[3] &= ~RxENABLE;
+       info->private->pendregs[3] = info->private->curregs[3];
+       write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+       /* disable Rx interrupts */
+       info->private->curregs[1] &= ~(0x18);   /* disable any rx ints */
+       info->private->pendregs[1] = info->private->curregs[1];
+       write_zsreg(info->private->zs_channel, 1, info->private->curregs[1]);
+       ZS_CLEARFIFO(info->private->zs_channel);
+}
+
+static int SCC_trans_empty (struct m68k_async_struct *info)
+{
+       return  (read_zsreg(info->private->zs_channel, 1) & ALL_SNT) != 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+#ifdef CONFIG_MAC
+
+/*
+ *     Mac: use boot_info data; assume 2 channels
+ */
+static void probe_sccs(void)
+{
+       int n;
+
+#define ZS_CONTROL     0x50F04000
+#define ZS_DATA                (ZS_CONTROL+4)
+#define ZS_IRQ         5
+#define ZS_MOVE                -2
+#define ZS_DATA_MOVE   4
+#define ZS_CH_A_FIRST  2
+
+       /* last-ditch fixup for NetBSD booter case */
+       if (mac_bi_data.sccbase == 0)
+               mac_bi_data.sccbase = ZS_CONTROL;
+
+       /* testing: fix up broken 24 bit addresses (ClassicII) */
+       if ((mac_bi_data.sccbase & 0x00FFFFFF) == mac_bi_data.sccbase)
+               mac_bi_data.sccbase |= 0x50000000;
+
+       for(n=0;n<2;n++)
+       {
+#if 0
+               zs_channels[n].control = (volatile unsigned char *)
+                               ZS_CONTROL+ZS_MOVE*n;
+               zs_channels[n].data = (volatile unsigned char *)ZS_DATA+ZS_MOVE*n;
+#else
+               zs_channels[n].control = (volatile unsigned char *)
+                       (mac_bi_data.sccbase+ZS_CH_A_FIRST)+ZS_MOVE*n;
+               zs_channels[n].data = (volatile unsigned char *)
+                       (mac_bi_data.sccbase+ZS_CH_A_FIRST+ZS_DATA_MOVE)+ZS_MOVE*n;
+#endif
+               zs_soft[n].private = &zs_soft_private[n];
+               zs_soft[n].private->zs_channel = &zs_channels[n];
+               zs_soft[n].irq = IRQ4;
+#if 0          
+               if (request_irq(ch->intrs[0], rs_interrupt, 0,
+                               "SCC", &zs_soft[n]))
+                       panic("macserial: can't get irq %d",
+                             ch->intrs[0]);
+#endif
+               if (n & 1)
+                       zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
+               else
+                       zs_soft[n].private->zs_chan_a = &zs_channels[n];
+       }
+
+       zs_channels_found=2;
+}
+
+#else
+
+/*
+ *     PowerMAC - query the PROM
+ */
+static void show_serial_version(void)
+{
+       printk("PowerMac Z8530 serial driver version 1.00\n");
+}
+
+/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
+static void
+probe_sccs()
+{
+       struct device_node *dev, *ch;
+       struct m68k_async_struct **pp;
+       int n;
+
+       n = 0;
+       pp = &zs_chain;
+       for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+               if (n >= NUM_CHANNELS) {
+                       printk("Sorry, can't use %s: no more channels\n",
+                              dev->full_name);
+                       continue;
+               }
+               for (ch = dev->child; ch != 0; ch = ch->sibling) {
+                       if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
+                               printk("Can't use %s: %d addrs %d intrs\n",
+                                     ch->full_name, ch->n_addrs, ch->n_intrs);
+                               continue;
+                       }
+                       zs_channels[n].control = (volatile unsigned char *)
+                               ch->addrs[0].address;
+                       zs_channels[n].data = zs_channels[n].control
+                               + ch->addrs[0].size / 2;
+                       zs_soft[n].private = &zs_soft_private[n];
+                       zs_soft[n].private->zs_channel = &zs_channels[n];
+                       zs_soft[n].irq = ch->intrs[0];
+                       if (request_irq(ch->intrs[0], mac_SCC_interrupt, 0,
+                                       "SCC", &zs_soft[n]))
+                               panic("macserial: can't get irq %d",
+                                     ch->intrs[0]);
+                       /* XXX this assumes the prom puts chan A before B */
+                       if (n & 1)
+                               zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
+                       else
+                               zs_soft[n].private->zs_chan_a = &zs_channels[n];
+
+                       *pp = &zs_soft[n];
+                       pp = &zs_soft[n].private->zs_next;
+                       ++n;
+               }
+       }
+       *pp = 0;
+       zs_channels_found = n;
+}
+
+#endif
+
+extern void register_console(void (*proc)(const char *));
+
+static inline void
+rs_cons_check(struct m68k_async_struct *ss, int channel)
+{
+       int i, o, io;
+       static consout_registered = 0;
+       static msg_printed = 0;
+
+       i = o = io = 0;
+
+       /* Is this one of the serial console lines? */
+       if ((zs_cons_chanout != channel) &&
+           (zs_cons_chanin != channel))
+               return;
+       zs_conschan = ss->private->zs_channel;
+       zs_consinfo = ss;
+
+       /* Register the console output putchar, if necessary */
+       if (zs_cons_chanout == channel) {
+               o = 1;
+               /* double whee.. */
+               if (!consout_registered) {
+                       register_console(zs_console_print);
+                       consout_registered = 1;
+               }
+       }
+
+       if (zs_cons_chanin == channel) {
+               i = 1;
+       }
+       if (o && i)
+               io = 1;
+       if (ss->private->zs_baud != 9600)
+               panic("Console baud rate weirdness");
+
+       /* Set flag variable for this port so that it cannot be
+        * opened for other uses by accident.
+        */
+       ss->private->is_cons = 1;
+
+       if (io) {
+               if(!msg_printed) {
+                       printk("zs%d: console I/O\n", ((channel>>1)&1));
+                       msg_printed = 1;
+               }
+       } else {
+               printk("zs%d: console %s\n", ((channel>>1)&1),
+                      (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));
+       }
+
+       /* FIXME : register interrupt here??? */
+}
+
+volatile int test_done;
+
+/* rs_init inits the driver */
+int mac_SCC_init(void)
+{
+       int channel, line, nr = 0, i;
+       unsigned long flags;
+       struct serial_struct req;
+       struct m68k_async_struct *info;
+
+       printk("Mac68K Z8530 serial driver version 1.01\n");
+
+       /* SCC present at all? */
+       if (MACH_IS_ATARI || MACH_IS_AMIGA 
+#if 0
+           || !(MACHW_PRESENT(SCC) || MACHW_PRESENT(ST_ESCC))
+#endif
+          )
+               return( -ENODEV );
+
+       if (zs_chain == 0)
+               probe_sccs();
+
+       save_flags(flags);
+       cli();
+
+       /* 
+        * FIXME: init of rs_table entry and register_serial now done,
+        * but possible clash of zs_soft[channel] and rs_table[channel]!!
+        * zs_soft initialized in probe_sccs(), some settings copied to
+        * info = &rs_table[channel], which is used by the mid-level code.
+        * The info->private part is shared among both!
+        */
+
+       for (channel = 0; channel < zs_channels_found; ++channel) {
+               req.line = channel;
+               req.type = SER_SCC_MAC;
+               req.port = zs_soft[channel].private->zs_channel->control;
+
+               if ((line = register_serial( &req )) >= 0) {
+                       SCC_init_port( &rs_table[line], req.type, line );
+                       ++nr;
+               }
+               else
+                       printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line );
+       }
+
+       restore_flags(flags);
+
+       return( nr > 0 ? 0 : -ENODEV );
+}
+
+/* Hooks for running a serial console.  con_init() calls this if the
+ * console is being run over one of the serial ports.
+ * 'channel' is decoded as 0=modem 1=printer, 'chip' is ignored.
+ */
+void
+rs_cons_hook(int chip, int out, int channel)
+{
+       if (zs_chain == 0)
+               probe_sccs();
+       zs_soft[channel].private->clk_divisor = 16;
+       zs_soft[channel].private->zs_baud = get_zsbaud(&zs_soft[channel]);
+       rs_cons_check(&zs_soft[channel], channel);
+       if (out)
+               zs_cons_chanout = channel;
+       else
+               zs_cons_chanin = channel;
+
+       /* FIXME : register interrupt here??? */
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line.  The 'tty_num' argument is 0 for /dev/ttyS0 and 1
+ * for /dev/ttyS1 which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+       if (zs_chain == 0)
+               probe_sccs();
+       zs_kgdbchan = zs_soft[tty_num].private->zs_channel;
+       zs_soft[tty_num].private->clk_divisor = 16;
+       zs_soft[tty_num].private->zs_baud = get_zsbaud(&zs_soft[tty_num]);
+       zs_soft[tty_num].private->kgdb_channel = 1;     /* This runs kgdb */
+       zs_soft[tty_num ^ 1].private->kgdb_channel = 0; /* This does not */
+       /* Turn on transmitter/receiver at 8-bits/char */
+       kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+       ZS_CLEARERR(zs_kgdbchan);
+       ZS_CLEARFIFO(zs_kgdbchan);
+
+       /* FIXME : register interrupt here??? */
+}
+
diff --git a/drivers/char/mac_SCC.h b/drivers/char/mac_SCC.h
new file mode 100644 (file)
index 0000000..5e903e1
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _MAC_SCC_H
+#define _MAC_SCC_H
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF 0
+#define ZILOG_CLOSING_WAIT_NONE        65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+                                  on the callout port */
+#define ZILOG_FOURPORT  0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK      0x0004  /* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK 0x0030
+#define ZILOG_SPD_HI   0x0010  /* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI  0x0020  /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST 0x0030  /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST        0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS    0x0FFF  /* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430  /* Legal flags that non-privileged
+                                * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED      0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE   0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE    0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF    0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING          0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW         0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD         0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ * 
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+/* MSch: gone to <asm/serial.h> */
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP  0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define        FLAG    0x7e
+
+/* Write Register 0 */
+#define        R0      0               /* Register selects */
+#define        R1      1
+#define        R2      2
+#define        R3      3
+#define        R4      4
+#define        R5      5
+#define        R6      6
+#define        R7      7
+#define        R8      8
+#define        R9      9
+#define        R10     10
+#define        R11     11
+#define        R12     12
+#define        R13     13
+#define        R14     14
+#define        R15     15
+
+#define        NULLCODE        0       /* Null Code */
+#define        POINT_HIGH      0x8     /* Select upper half of registers */
+#define        RES_EXT_INT     0x10    /* Reset Ext. Status Interrupts */
+#define        SEND_ABORT      0x18    /* HDLC Abort */
+#define        RES_RxINT_FC    0x20    /* Reset RxINT on First Character */
+#define        RES_Tx_P        0x28    /* Reset TxINT Pending */
+#define        ERR_RES         0x30    /* Error Reset */
+#define        RES_H_IUS       0x38    /* Reset highest IUS */
+
+#define        RES_Rx_CRC      0x40    /* Reset Rx CRC Checker */
+#define        RES_Tx_CRC      0x80    /* Reset Tx CRC Checker */
+#define        RES_EOM_L       0xC0    /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define        EXT_INT_ENAB    0x1     /* Ext Int Enable */
+#define        TxINT_ENAB      0x2     /* Tx Int Enable */
+#define        PAR_SPEC        0x4     /* Parity is special condition */
+
+#define        RxINT_DISAB     0       /* Rx Int Disable */
+#define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
+#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
+#define        INT_ERR_Rx      0x18    /* Int on error only */
+
+#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
+#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
+#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define        RxENABLE        0x1     /* Rx Enable */
+#define        SYNC_L_INH      0x2     /* Sync Character Load Inhibit */
+#define        ADD_SM          0x4     /* Address Search Mode (SDLC) */
+#define        RxCRC_ENAB      0x8     /* Rx CRC Enable */
+#define        ENT_HM          0x10    /* Enter Hunt Mode */
+#define        AUTO_ENAB       0x20    /* Auto Enables */
+#define        Rx5             0x0     /* Rx 5 Bits/Character */
+#define        Rx7             0x40    /* Rx 7 Bits/Character */
+#define        Rx6             0x80    /* Rx 6 Bits/Character */
+#define        Rx8             0xc0    /* Rx 8 Bits/Character */
+#define RxNBITS_MASK   0xc0
+
+/* Write Register 4 */
+
+#define        PAR_ENA         0x1     /* Parity Enable */
+#define        PAR_EVEN        0x2     /* Parity Even/Odd* */
+
+#define        SYNC_ENAB       0       /* Sync Modes Enable */
+#define        SB1             0x4     /* 1 stop bit/char */
+#define        SB15            0x8     /* 1.5 stop bits/char */
+#define        SB2             0xc     /* 2 stop bits/char */
+#define SB_MASK                0xc
+
+#define        MONSYNC         0       /* 8 Bit Sync character */
+#define        BISYNC          0x10    /* 16 bit sync character */
+#define        SDLC            0x20    /* SDLC Mode (01111110 Sync Flag) */
+#define        EXTSYNC         0x30    /* External Sync Mode */
+
+#define        X1CLK           0x0     /* x1 clock mode */
+#define        X16CLK          0x40    /* x16 clock mode */
+#define        X32CLK          0x80    /* x32 clock mode */
+#define        X64CLK          0xC0    /* x64 clock mode */
+#define XCLK_MASK      0xC0
+
+/* Write Register 5 */
+
+#define        TxCRC_ENAB      0x1     /* Tx CRC Enable */
+#define        RTS             0x2     /* RTS */
+#define        SDLC_CRC        0x4     /* SDLC/CRC-16 */
+#define        TxENAB          0x8     /* Tx Enable */
+#define        SND_BRK         0x10    /* Send Break */
+#define        Tx5             0x0     /* Tx 5 bits (or less)/character */
+#define        Tx7             0x20    /* Tx 7 bits/character */
+#define        Tx6             0x40    /* Tx 6 bits/character */
+#define        Tx8             0x60    /* Tx 8 bits/character */
+#define TxNBITS_MASK   0x60
+#define        DTR             0x80    /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define        VIS     1       /* Vector Includes Status */
+#define        NV      2       /* No Vector */
+#define        DLC     4       /* Disable Lower Chain */
+#define        MIE     8       /* Master Interrupt Enable */
+#define        STATHI  0x10    /* Status high */
+#define        NORESET 0       /* No reset on write to R9 */
+#define        CHRB    0x40    /* Reset channel B */
+#define        CHRA    0x80    /* Reset channel A */
+#define        FHWRES  0xc0    /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define        BIT6    1       /* 6 bit/8bit sync */
+#define        LOOPMODE 2      /* SDLC Loop mode */
+#define        ABUNDER 4       /* Abort/flag on SDLC xmit underrun */
+#define        MARKIDLE 8      /* Mark/flag on idle */
+#define        GAOP    0x10    /* Go active on poll */
+#define        NRZ     0       /* NRZ mode */
+#define        NRZI    0x20    /* NRZI mode */
+#define        FM1     0x40    /* FM1 (transition = 1) */
+#define        FM0     0x60    /* FM0 (transition = 0) */
+#define        CRCPS   0x80    /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define        TRxCXT  0       /* TRxC = Xtal output */
+#define        TRxCTC  1       /* TRxC = Transmit clock */
+#define        TRxCBR  2       /* TRxC = BR Generator Output */
+#define        TRxCDP  3       /* TRxC = DPLL output */
+#define        TRxCOI  4       /* TRxC O/I */
+#define        TCRTxCP 0       /* Transmit clock = RTxC pin */
+#define        TCTRxCP 8       /* Transmit clock = TRxC pin */
+#define        TCBR    0x10    /* Transmit clock = BR Generator output */
+#define        TCDPLL  0x18    /* Transmit clock = DPLL output */
+#define        RCRTxCP 0       /* Receive clock = RTxC pin */
+#define        RCTRxCP 0x20    /* Receive clock = TRxC pin */
+#define        RCBR    0x40    /* Receive clock = BR Generator output */
+#define        RCDPLL  0x60    /* Receive clock = DPLL output */
+#define        RTxCX   0x80    /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define        BRENABL 1       /* Baud rate generator enable */
+#define        BRSRC   2       /* Baud rate generator source */
+#define        DTRREQ  4       /* DTR/Request function */
+#define        AUTOECHO 8      /* Auto Echo */
+#define        LOOPBAK 0x10    /* Local loopback */
+#define        SEARCH  0x20    /* Enter search mode */
+#define        RMC     0x40    /* Reset missing clock */
+#define        DISDPLL 0x60    /* Disable DPLL */
+#define        SSBR    0x80    /* Set DPLL source = BR generator */
+#define        SSRTxC  0xa0    /* Set DPLL source = RTxC */
+#define        SFMM    0xc0    /* Set FM mode */
+#define        SNRZI   0xe0    /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define        ZCIE    2       /* Zero count IE */
+#define        DCDIE   8       /* DCD IE */
+#define        SYNCIE  0x10    /* Sync/hunt IE */
+#define        CTSIE   0x20    /* CTS IE */
+#define        TxUIE   0x40    /* Tx Underrun/EOM IE */
+#define        BRKIE   0x80    /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define        Rx_CH_AV        0x1     /* Rx Character Available */
+#define        ZCOUNT          0x2     /* Zero count */
+#define        Tx_BUF_EMP      0x4     /* Tx Buffer empty */
+#define        DCD             0x8     /* DCD */
+#define        SYNC_HUNT       0x10    /* Sync/hunt */
+#define        CTS             0x20    /* CTS */
+#define        TxEOM           0x40    /* Tx underrun */
+#define        BRK_ABRT        0x80    /* Break/Abort */
+
+/* Read Register 1 */
+#define        ALL_SNT         0x1     /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define        RES3            0x8     /* 0/3 */
+#define        RES4            0x4     /* 0/4 */
+#define        RES5            0xc     /* 0/5 */
+#define        RES6            0x2     /* 0/6 */
+#define        RES7            0xa     /* 0/7 */
+#define        RES8            0x6     /* 0/8 */
+#define        RES18           0xe     /* 1/8 */
+#define        RES28           0x0     /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define        PAR_ERR         0x10    /* Parity error */
+#define        Rx_OVR          0x20    /* Rx Overrun Error */
+#define        FRM_ERR         0x40    /* CRC/Framing Error */
+#define        END_FR          0x80    /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
+#define        CHBTxIP 0x2             /* Channel B Tx IP */
+#define        CHBRxIP 0x4             /* Channel B Rx IP */
+#define        CHAEXT  0x8             /* Channel A Ext/Stat IP */
+#define        CHATxIP 0x10            /* Channel A Tx IP */
+#define        CHARxIP 0x20            /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define        ONLOOP  2               /* On loop */
+#define        LOOPSEND 0x10           /* Loop sending */
+#define        CLK2MIS 0x40            /* Two clocks missing */
+#define        CLK1MIS 0x80            /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    (write_zsreg(channel, 0, ERR_RES))
+#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
+                                    garbage = read_zsdata(channel); \
+                                    garbage = read_zsdata(channel); \
+                                    garbage = read_zsdata(channel); \
+                               } while(0)
+
+#endif /* !(_MAC_SCC_H) */
index 427a24ef89333d7a82a4a8996cd9329ba2ad7009..cf2dea85a401eebaf73f700f77489cf1eacb9fc5 100644 (file)
 #include <asm/pgtable.h>
 
 #ifdef CONFIG_SOUND
+void soundcore_init(void);
+#ifdef CONFIG_SOUND_OSS
 void soundcard_init(void);
 #endif
+#ifdef CONFIG_DMASOUND
+void dmasound_init(void);
+#endif
+#endif
 #ifdef CONFIG_ISDN
 int isdn_init(void);
 #endif
@@ -540,6 +546,9 @@ __initfunc(int chr_dev_init(void))
 #ifdef CONFIG_SOUND_OSS        
        soundcard_init();
 #endif 
+#ifdef CONFIG_DMASOUND
+       dmasound_init();
+#endif 
 #endif
 #ifdef CONFIG_JOYSTICK
        /*
index 4cd1831f7e45f2d38340e0b702c1e4a4b34b013d..bbdb2c638e597dab680c6a5d0ab7b78004dcbae7 100644 (file)
@@ -72,6 +72,7 @@ extern int atixl_busmouse_init(void);
 extern int amiga_mouse_init(void);
 extern int atari_mouse_init(void);
 extern int sun_mouse_init(void);
+extern int adb_mouse_init(void);
 extern void watchdog_init(void);
 extern void wdt_init(void);
 extern void acq_init(void);
@@ -223,6 +224,9 @@ __initfunc(int misc_init(void))
 #ifdef CONFIG_SUN_MOUSE
        sun_mouse_init();
 #endif
+#ifdef CONFIG_MACMOUSE
+       adb_mouse_init();
+#endif
 #ifdef CONFIG_PC110_PAD
        pc110pad_init();
 #endif
@@ -250,7 +254,7 @@ __initfunc(int misc_init(void))
 #ifdef CONFIG_H8
        h8_init();
 #endif
-#ifdef CONFIG_RTC
+#if defined(CONFIG_RTC) || defined(CONFIG_SUN_MOSTEK_RTC)
        rtc_init();
 #endif
 #ifdef CONFIG_ATARI_DSP56K
index fba8c7d5125f05ac5856bec3ce51f40146c7fd96..a3353f4afab3628410b4288f325efba13084acfd 100644 (file)
@@ -156,7 +156,7 @@ static __inline__ void nvram_set_checksum_int( void )
  *
  * They're only built if CONFIG_ATARI is defined, because Atari drivers use
  * them. For other configurations (PC), the rest of the kernel can't rely on
- * them being present (this driver couldn't be configured at all, or as a
+ * them being present (this driver may not be configured at all, or as a
  * module), so they access config information themselves.
  */
 
@@ -227,12 +227,15 @@ static long long nvram_llseek(struct file *file,loff_t offset, int origin )
        return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL );
 }
 
-static ssize_t nvram_read( struct file * file,
-                                               char * buf, size_t count, loff_t *ppos )
+static ssize_t nvram_read(struct file * file,
+       char * buf, size_t count, loff_t *ppos )
 {
        unsigned long flags;
        unsigned i = *ppos;
        char *tmp = buf;
+       
+       if (i != *ppos)
+               return -EINVAL;
 
        save_flags(flags);
        cli();
@@ -250,12 +253,16 @@ static ssize_t nvram_read( struct file * file,
        return( tmp - buf );
 }
 
-static ssize_t nvram_write( struct file * file, const char * buf, size_t count, loff_t *ppos )
+static ssize_t nvram_write(struct file * file,
+               const char * buf, size_t count, loff_t *ppos )
 {
        unsigned long flags;
        unsigned i = *ppos;
        const char *tmp = buf;
        char c;
+       
+       if (i != *ppos)
+               return -EINVAL;
 
        save_flags(flags);
        cli();
@@ -411,7 +418,7 @@ __initfunc(int nvram_init(void))
        if (!CHECK_DRIVER_INIT())
            return( -ENXIO );
 
-       printk( "Non-volatile memory driver v%s\n", NVRAM_VERSION );
+       printk(KERN_INFO "Non-volatile memory driver v%s\n", NVRAM_VERSION );
        misc_register( &nvram_dev );
 #ifdef CONFIG_PROC_FS
        if ((proc_nvram = create_proc_entry( "nvram", 0, 0 )))
@@ -618,7 +625,7 @@ static char *colors[] = {
 #define fieldsize(a)   (sizeof(a)/sizeof(*a))
 
 static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
-                                                        off_t *begin, off_t offset, int size )
+                           off_t *begin, off_t offset, int size )
 {
        int checksum = nvram_check_checksum();
        int i;
@@ -645,7 +652,7 @@ static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
 
        /* the following entries are defined only for the Falcon */
        if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
-               return;
+               return 1;
 
        PRINT_PROC( "OS language      : " );
        if (nvram[6] < fieldsize(languages))
index 425f2e8a6753aa9b3a1289c8985af00c623512ff..778a23df67efac94f604f24424137bc0ecaf2a3a 100644 (file)
@@ -178,6 +178,20 @@ __initfunc(static char *initialize_kbd2(void))
                              | KBD_MODE_DISABLE_MOUSE
                              | KBD_MODE_KCC);
 
+       /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
+       kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE);
+       if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+               /*
+                * If the controller does not support conversion,
+                * Set the keyboard to scan-code set 1.
+                */
+               kbd_write(KBD_DATA_REG, 0xF0);
+               kbd_wait_for_input();
+               kbd_write(KBD_DATA_REG, 0x01);
+               kbd_wait_for_input();
+       }
+
+       
        kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
        if (kbd_wait_for_input() != KBD_REPLY_ACK)
                return "Enable keyboard: no ACK";
index 4f0d5fdb25a32b61ff32d58803a1ca70b24fc2b4..7f97e0f899cf574dc249dcf5cefc3c1c8d685238 100644 (file)
@@ -1,6 +1,7 @@
 /* radiotrack (radioreveal) driver for Linux radio support
  * (c) 1997 M. Kirkwood
  * Coverted to new API by Alan Cox <Alan.Cox@linux.org>
+ * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
  * TODO: Allow for more than one of these foolish entities :-)
  *
@@ -47,7 +48,7 @@ struct rt_device
 
 /* local things */
 
-static void sleep_delay(int n)
+static void sleep_delay(long n)
 {
        /* Sleep nicely for 'n' uS */
        int d=n/1000000/HZ;
@@ -61,108 +62,129 @@ static void sleep_delay(int n)
                        schedule();
        }
 }
-       
-/* Clock out data to the chip. This looks suspiciously like i2c as usual */
-
-static void outbits(int bits, int data, int port)
-{
-       while(bits--) 
-       {
-               if(data & 1) 
-               {
-                       outw(5, port);
-                       outw(5, port);
-                       outw(7, port);
-                       outw(7, port);
-               }
-               else 
-               {
-                       outw(1, port);
-                       outw(1, port);
-                       outw(3, port);
-                       outw(3, port);
-               }
-               data>>=1;
-       }
-}
 
-static void rt_decvol(int port)
+static void rt_decvol(void)
 {
-       outb(0x48, port);
+       outb(0x58, io);         /* volume down + sigstr + on    */
        sleep_delay(100000);
-       outb(0xc8, port);
+       outb(0xd8, io);         /* volume steady + sigstr + on  */
 }
 
-static void rt_incvol(int port)
+static void rt_incvol(void)
 {
-       outb(0x88, port);
+       outb(0x98, io);         /* volume up + sigstr + on      */
        sleep_delay(100000);
-       outb(0xc8, port);
+       outb(0xd8, io);         /* volume steady + sigstr + on  */
 }
 
-static void rt_mute(int port)
+static void rt_mute(void)
 {
-       outb(0, port);
-       outb(0xc0, port);
-}
-
-static void rt_unmute(int port)
-{
-       outb(0, port);
-       outb(0xc8, port);
+       outb(0x48, io);                 /* volume down but still "on"   */
+       sleep_delay(2000000);           /* make sure it's totally down  */
+       outb(0xc0, io);                 /* volume steady, off           */
 }
 
 static int rt_setvol(struct rt_device *dev, int vol)
 {
        int i;
-       if(vol == dev->curvol)
+
+       if(vol == dev->curvol)          /* no change needed */
                return 0;
 
-       if(vol == 0)
-               rt_mute(dev->port);
+       if(vol == 0) {                  /* volume = 0 means mute the card */
+               rt_mute();
+               dev->curvol = 0;
+               return 0;
+       }
 
        if(vol > dev->curvol)
-               for(i = dev->curvol; i < vol; i++)
-                       rt_incvol(dev->port);
+               for(i = dev->curvol; i < vol; i++) 
+                       rt_incvol();
        else
-               for(i = dev->curvol; i > vol; i--)
-                       rt_decvol(dev->port);
+               for(i = dev->curvol; i > vol; i--) 
+                       rt_decvol();
 
-       if(dev->curvol == 0)
-               rt_unmute(dev->port);
+       dev->curvol = vol;
 
        return 0;
 }
 
-static int rt_setfreq(struct rt_device *dev, unsigned long frequency)
+/* the 128+64 on these outb's is to keep the volume stable while tuning 
+ * without them, the volume _will_ creep up with each frequency change
+ * and bit 4 (+16) is to keep the signal strength meter enabled
+ */
+
+void send_0_byte(int port, struct rt_device *dev)
+{
+       if (dev->curvol == 0) {
+               outb_p(128+64+16+  1, port);   /* wr-enable + data low */
+               outb_p(128+64+16+2+1, port);   /* clock */
+       }
+       else {
+               outb_p(128+64+16+8+  1, port);  /* on + wr-enable + data low */
+               outb_p(128+64+16+8+2+1, port);  /* clock */
+       }
+       sleep_delay(1000); 
+}
+
+void send_1_byte(int port, struct rt_device *dev)
+{
+       if (dev->curvol == 0) {
+               outb_p(128+64+16+4  +1, port);   /* wr-enable+data high */
+               outb_p(128+64+16+4+2+1, port);   /* clock */
+       } 
+       else {
+               outb_p(128+64+16+8+4  +1, port); /* on+wr-enable+data high */
+               outb_p(128+64+16+8+4+2+1, port); /* clock */
+       }
+
+       sleep_delay(1000); 
+}
+
+static int rt_setfreq(struct rt_device *dev, unsigned long freq)
 {
-       int myport = dev->port;
-#define        RTRACK_ENCODE(x)        (((((x)*2)/5)-(40*88))+0xf6c)
-       outbits(16, RTRACK_ENCODE(frequency), myport);
-       outbits(8, 0xa0, myport);
-/* XXX - get rid of this once setvol is implemented properly - XXX */
-/* these insist on turning the thing on.  not sure I approve... */
-       udelay(1000);
-       outb(0, myport);
-       outb(0xc8, myport);
+       int i;
+
+       /* adapted from radio-aztech.c */
+
+       freq = (freq / 16.0) * 100;     /* massage the data a little    */
+       freq += 1070;                   /* IF = 10.7 MHz                */
+       freq /= 5;                      /* ref = 25 kHz                 */
+
+       send_0_byte (io, dev);          /*  0: LSB of frequency         */
+
+       for (i = 0; i < 13; i++)        /*   : frequency bits (1-13)    */
+               if (freq & (1 << i))
+                       send_1_byte (io, dev);
+               else
+                       send_0_byte (io, dev);
+
+       send_0_byte (io, dev);          /* 14: test bit - always 0    */
+       send_0_byte (io, dev);          /* 15: test bit - always 0    */
+
+       send_0_byte (io, dev);          /* 16: band data 0 - always 0 */
+       send_0_byte (io, dev);          /* 17: band data 1 - always 0 */
+       send_0_byte (io, dev);          /* 18: band data 2 - always 0 */
+       send_0_byte (io, dev);          /* 19: time base - always 0   */
+
+       send_0_byte (io, dev);          /* 20: spacing (0 = 25 kHz)   */
+       send_1_byte (io, dev);          /* 21: spacing (1 = 25 kHz)   */
+       send_0_byte (io, dev);          /* 22: spacing (0 = 25 kHz)   */
+       send_1_byte (io, dev);          /* 23: AM/FM (FM = 1, always) */
+
+       if (dev->curvol == 0)
+               outb (0xd0, io);        /* volume steady + sigstr */
+       else
+               outb (0xd8, io);        /* volume steady + sigstr + on */
 
        return 0;
 }
 
 int rt_getsigstr(struct rt_device *dev)
 {
-       int res;
-       int myport = dev->port;
-
-       outb(0xf8, myport);
-       sleep_delay(200000);
-       res = (int)inb(myport);
-       sleep_delay(10000);
-       outb(0xe8, myport);
-       if(res == 0xfd)
-               return 1;
-       else
+       if (inb(io) & 2)        /* bit set = no signal present  */
                return 0;
+       return 1;               /* signal present               */
 }
 
 static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
@@ -226,7 +248,7 @@ static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        struct video_audio v;
                        memset(&v,0, sizeof(v));
                        v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
-                       v.volume=rt->curvol;
+                       v.volume=rt->curvol * 6554;
                        strcpy(v.name, "Radio");
                        if(copy_to_user(arg,&v, sizeof(v)))
                                return -EFAULT;
@@ -239,12 +261,14 @@ static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                                return -EFAULT; 
                        if(v.audio) 
                                return -EINVAL;
-                       rt->curvol=v.volume;
 
-                       if(v.flags&VIDEO_AUDIO_MUTE) 
-                               rt_mute(rt->port);
+                       if(v.flags&VIDEO_AUDIO_MUTE) {
+                               rt_mute();
+                               rt->curvol=0;
+                       }
                        else
-                               rt_setvol(rt,rt->curvol/6554);  
+                               rt_setvol(rt,v.volume/6554);    
+
                        return 0;
                }
                default:
@@ -299,7 +323,8 @@ __initfunc(int rtrack_init(struct video_init *v))
        request_region(io, 2, "rtrack");
        printk(KERN_INFO "AIMSlab Radiotrack/radioreveal card driver.\n");
        /* mute card - prevents noisy bootups */
-       rt_mute(io);
+       rt_mute();
+       rtrack_unit.curvol = 0;
        return 0;
 }
 
index e7fbc2efd2eea6e83d682b0287ddbb22ad127bf7..0b0433b17956ae4dd93f5950a734008f51ebbc2b 100644 (file)
@@ -513,6 +513,10 @@ static void init_std_data(struct random_bucket *r)
        do_gettimeofday(&tv);
        add_entropy_words(r, tv.tv_sec, tv.tv_usec);
 
+       /*
+        *      This doesnt lock system.utsname. Howeve we are generating
+        *      entropy so a race with a name set here is fine.
+        */
        p = (__u32 *)&system_utsname;
        for (i = sizeof(system_utsname) / sizeof(words); i; i--) {
                memcpy(words, p, sizeof(words));
index 0f50d34db9bcf4625eddd247dedcb98418a188c6..1da51e1a1d780beab668d3da5ecb95eac1c4e309 100644 (file)
@@ -123,6 +123,10 @@ static int tty_release(struct inode *, struct file *);
 static int tty_ioctl(struct inode * inode, struct file * file,
                     unsigned int cmd, unsigned long arg);
 static int tty_fasync(struct file * filp, int on);
+#ifdef CONFIG_8xx
+extern long console_8xx_init(void);
+extern int rs_8xx_init(void);
+#endif /* CONFIG_8xx */
 
 #ifndef MIN
 #define MIN(a,b)       ((a) < (b) ? (a) : (b))
@@ -2055,6 +2059,9 @@ __initfunc(int tty_init(void))
 #ifdef CONFIG_SERIAL
        rs_init();
 #endif
+#ifdef CONFIG_MAC_SERIAL
+       macserial_init();
+#endif
 #ifdef CONFIG_ROCKETPORT
        rp_init();
 #endif
@@ -2079,6 +2086,9 @@ __initfunc(int tty_init(void))
 #ifdef CONFIG_SPECIALIX
        specialix_init();
 #endif
+#ifdef CONFIG_8xx
+        rs_8xx_init();
+#endif /* CONFIG_8xx */
        pty_init();
 #ifdef CONFIG_VT
        vcs_init();
diff --git a/drivers/dio/Makefile b/drivers/dio/Makefile
new file mode 100644 (file)
index 0000000..48d3522
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+#
+# NB: cribbed from the drivers/sbus/Makefile -- PMM
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_OBJS   := dio.o
+L_TARGET := dio.a
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/dio/dio.c b/drivers/dio/dio.c
new file mode 100644 (file)
index 0000000..eaab1ab
--- /dev/null
@@ -0,0 +1,292 @@
+/* Code to support devices on the DIO (and eventually DIO-II) bus
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * 
+ * This code has basically these routines at the moment:
+ * int dio_find(u_int deviceid)
+ *    Search the list of DIO devices and return the select code
+ *    of the next unconfigured device found that matches the given device ID.
+ *    Note that the deviceid parameter should be the encoded ID.
+ *    This means that framebuffers should pass it as 
+ *    DIO_ENCODE_ID(DIO_ID_FBUFFER,DIO_ID2_TOPCAT)
+ *    (or whatever); everybody else just uses DIO_ID_FOOBAR.
+ * void *dio_scodetoviraddr(int scode)
+ *    Return the virtual address corresponding to the given select code.
+ *    NB: DIO-II devices will have to be mapped in in this routine!
+ * int dio_scodetoipl(int scode)
+ *    Every DIO card has a fixed interrupt priority level. This function 
+ *    returns it, whatever it is.
+ * const char *dio_scodetoname(int scode)
+ *    Return a character string describing this board [might be "" if 
+ *    not CONFIG_DIO_CONSTANTS]
+ * void dio_config_board(int scode)     mark board as configured in the list
+ * void dio_unconfig_board(int scode)   mark board as no longer configured
+ *
+ * This file is based on the way the Amiga port handles Zorro II cards, 
+ * although we aren't so complicated...
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/dio.h>
+#include <linux/malloc.h>                         /* kmalloc() */
+#include <linux/init.h>
+#include <asm/hwtest.h>                           /* hwreg_present() */
+#include <asm/io.h>                               /* readb() */
+/* not a real config option yet! */
+#define CONFIG_DIO_CONSTANTS
+
+#ifdef CONFIG_DIO_CONSTANTS
+/* We associate each numeric ID with an appropriate descriptive string
+ * using a constant array of these structs.
+ * FIXME: we should be able to arrange to throw away most of the strings
+ * using the initdata stuff. Then we wouldn't need to worry about 
+ * carrying them around...
+ * I think we do this by copying them into newly kmalloc()ed memory and 
+ * marking the names[] array as .initdata ?
+ */
+struct dioname
+{
+        int id;
+        const char *name;
+};
+
+/* useful macro */
+#define DIONAME(x) { DIO_ID_##x, DIO_DESC_##x }
+#define DIOFBNAME(x) { DIO_ENCODE_ID( DIO_ID_FBUFFER, DIO_ID2_##x), DIO_DESC2_##x }
+
+static struct dioname names[] = 
+{
+        DIONAME(DCA0), DIONAME(DCA0REM), DIONAME(DCA1), DIONAME(DCA1REM),
+        DIONAME(DCM), DIONAME(DCMREM),
+        DIONAME(LAN),
+        DIONAME(FHPIB), DIONAME(NHPIB), DIONAME(IHPIB),
+        DIONAME(SCSI0), DIONAME(SCSI1), DIONAME(SCSI2), DIONAME(SCSI3),
+        DIONAME(FBUFFER),
+        DIONAME(PARALLEL), DIONAME(VME), DIONAME(DCL), DIONAME(DCLREM),
+        DIONAME(MISC0), DIONAME(MISC1), DIONAME(MISC2), DIONAME(MISC3),
+        DIONAME(MISC4), DIONAME(MISC5), DIONAME(MISC6), DIONAME(MISC7),
+        DIONAME(MISC8), DIONAME(MISC9), DIONAME(MISC10), DIONAME(MISC11), 
+        DIONAME(MISC12), DIONAME(MISC13),
+        DIOFBNAME(GATORBOX), DIOFBNAME(TOPCAT), DIOFBNAME(RENAISSANCE),
+        DIOFBNAME(LRCATSEYE), DIOFBNAME(HRCCATSEYE), DIOFBNAME(HRMCATSEYE),
+        DIOFBNAME(DAVINCI), DIOFBNAME(XXXCATSEYE), DIOFBNAME(HYPERION),
+        DIOFBNAME(XGENESIS), DIOFBNAME(TIGER), DIOFBNAME(YGENESIS)   
+};
+
+#undef DIONAME
+#undef DIOFBNAME
+
+#define NUMNAMES (sizeof(names) / sizeof(struct dioname))
+
+static const char *unknowndioname 
+        = "unknown DIO board -- please email <pmaydell@chiark.greenend.org.uk>!";
+
+static const char *dio_getname(int id)
+{
+        /* return pointer to a constant string describing the board with given ID */
+       unsigned int i;
+        for (i = 0; i < NUMNAMES; i++)
+                if (names[i].id == id) 
+                        return names[i].name;
+        
+        return unknowndioname;
+}
+
+#else
+
+static char dio_no_name[] = { 0 };
+#define dio_getname(_id)       (dio_no_name)
+
+#endif /* CONFIG_DIO_CONSTANTS */
+
+/* We represent all the DIO boards in the system with a linked list of these structs. */
+struct dioboard
+{
+        struct dioboard *next;                    /* link to next struct in list */
+        int ipl;                                  /* IPL of this board */
+        int configured;                           /* has this board been configured? */
+        int scode;                                /* select code of this board */
+        int id;                                   /* encoded ID */
+        const char *name;
+};
+
+static struct dioboard *blist = NULL;
+
+__initfunc(static int dio_find_slow(int deviceid))
+{
+       /* Called to find a DIO device before the full bus scan has run.  Basically
+          only used by the console driver.  */
+       int scode;
+       for (scode = 0; scode < DIO_SCMAX; scode++)
+       {
+               void *va;
+
+                if (DIO_SCINHOLE(scode))
+                        continue;
+                
+                va = dio_scodetoviraddr(scode);
+                if (!va || !hwreg_present(va + DIO_IDOFF))
+                        continue;             /* no board present at that select code */
+
+               if (DIO_ID(va) == deviceid)
+                       return scode;
+       }
+       return 0;
+}
+
+int dio_find(int deviceid)
+{
+       if (blist) 
+       {
+               /* fast way */
+               struct dioboard *b;
+               for (b = blist; b; b = b->next)
+                       if (b->id == deviceid && b->configured == 0)
+                               return b->scode;
+               return 0;
+       }
+       return dio_find_slow(deviceid);
+}
+
+/* This is the function that scans the DIO space and works out what
+ * hardware is actually present.
+ */
+__initfunc(void dio_init(void))
+{
+        int scode;
+        struct dioboard *b, *bprev = NULL;
+   
+        printk("Scanning for DIO devices...\n");
+        
+        for (scode = 0; scode < DIO_SCMAX; ++scode)
+        {
+                u_char prid, secid = 0;        /* primary, secondary ID bytes */
+                u_char *va;
+                
+                if (DIO_SCINHOLE(scode))
+                        continue;
+                
+                va = dio_scodetoviraddr(scode);
+                if (!va || !hwreg_present(va + DIO_IDOFF))
+                        continue;              /* no board present at that select code */
+
+                /* Found a board, allocate it an entry in the list */
+                b = kmalloc(sizeof(struct dioboard), GFP_KERNEL);
+                
+                /* read the ID byte(s) and encode if necessary. Note workaround 
+                 * for broken internal HPIB devices...
+                 */
+                if (!DIO_ISIHPIB(scode))
+                        prid = DIO_ID(va);
+                else 
+                        prid = DIO_ID_IHPIB;
+                
+                if (DIO_NEEDSSECID(prid))
+                {
+                        secid = DIO_SECID(va);
+                        b->id = DIO_ENCODE_ID(prid, secid);
+                }
+                else
+                        b->id = prid;
+      
+                b->configured = 0;
+                b->scode = scode;
+                b->ipl = DIO_IPL(va);
+                b->name = dio_getname(b->id);
+                printk("select code %3d: ID %02X", scode, prid);
+                if (DIO_NEEDSSECID(b->id))
+                        printk(":%02X", secid);
+                printk(" %s\n", b->name);
+                
+                b->next = NULL;
+
+                if (bprev)
+                        bprev->next = b;
+                else
+                        blist = b;
+                bprev = b;
+        }
+}
+
+/* Bear in mind that this is called in the very early stages of initialisation
+ * in order to get the virtual address of the serial port for the console...
+ */
+void *dio_scodetoviraddr(int scode)
+{
+        if (scode > DIOII_SCBASE)
+        {
+                printk("dio_scodetoviraddr: don't support DIO-II yet!\n");
+                return 0;
+        }
+        else if (scode > DIO_SCMAX || scode < 0)
+                return 0;
+        else if (DIO_SCINHOLE(scode))
+                return 0;
+        else if (scode == DIO_IHPIBSCODE) /* this should really be #ifdef CONFIG_IHPIB */
+                return (void*)DIO_IHPIBADDR;   /* or something similar... */
+        
+        return (void*)(DIO_VIRADDRBASE + DIO_BASE + scode * 0x10000);
+}
+
+int dio_scodetoipl(int scode)
+{
+        struct dioboard *b;
+        for (b = blist; b; b = b->next)
+                if (b->scode == scode) 
+                        break;
+        
+        if (!b)
+        {
+                printk("dio_scodetoipl: bad select code %d\n", scode);
+                return 0;
+        }
+        else
+                return b->ipl;
+}
+
+const char *dio_scodetoname(int scode)
+{
+        struct dioboard *b;
+        for (b = blist; b; b = b->next)
+                if (b->scode == scode) 
+                        break;
+        
+        if (!b)
+        {
+                printk("dio_scodetoname: bad select code %d\n", scode);
+                return NULL;
+        }
+        else
+                return b->name;
+}
+
+void dio_config_board(int scode)
+{
+        struct dioboard *b;
+        for (b = blist; b; b = b->next)
+                if (b->scode == scode)
+                        break;
+   
+        if (!b) 
+                printk("dio_config_board: bad select code %d\n", scode);
+        else if (b->configured)
+                printk("dio_config_board: board at select code %d already configured\n", scode);
+        else
+                b->configured = 1;
+}
+
+void dio_unconfig_board(int scode)
+{
+        struct dioboard *b;
+        for (b = blist; b; b = b->next)
+                if (b->scode == scode) 
+                        break;
+   
+        if (!b) 
+                printk("dio_unconfig_board: bad select code %d\n", scode);
+        else if (!b->configured)
+                printk("dio_unconfig_board: board at select code %d not configured\n", 
+                      scode);
+        else 
+                b->configured = 0;
+}
index d9cb1c7d63e59432f459c0fcc4297ff0f017aafa..0b2f1c660e3db5cbc4194c6604b75271de360d44 100644 (file)
@@ -82,6 +82,12 @@ static struct parport_operations parport_arc_ops =
        arc_release_resources,
        arc_claim_resources,
        
+       NULL, /* epp_write_data */
+       NULL, /* epp_read_data */
+       NULL, /* epp_write_addr */
+       NULL, /* epp_read_addr */
+       NULL, /* epp_check_timeout */
+
        NULL, /* epp_write_block */
        NULL, /* epp_read_block */
 
index 892df94d566b99f2d252c691c789de4a944f2147..fa1b6fddeaba60b6125a4436cc3673a5dc413376 100644 (file)
@@ -39,7 +39,8 @@
 #define DATA           0x00
 #define STATUS         0x01
 #define CONTROL                0x02
-#define EPPREG         0x04
+#define EPPADDR                0x03
+#define EPPDATA                0x04
 
 #define CFIFO          0x400
 #define DFIFO          0x400
@@ -57,13 +58,34 @@ parport_ax_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
 void
 parport_ax_write_epp(struct parport *p, unsigned char d)
 {
-       outb(d, p->base + EPPREG);
+       outb(d, p->base + EPPDATA);
 }
 
 unsigned char
 parport_ax_read_epp(struct parport *p)
 {
-       return inb(p->base + EPPREG);
+       return inb(p->base + EPPDATA);
+}
+
+void
+parport_ax_write_epp_addr(struct parport *p, unsigned char d)
+{
+       outb(d, p->base + EPPADDR);
+}
+
+unsigned char
+parport_ax_read_epp_addr(struct parport *p)
+{
+       return inb(p->base + EPPADDR);
+}
+
+int 
+parport_ax_check_epp_timeout(struct parport *p)
+{
+       if (!(inb(p->base+STATUS) & 1))
+               return 0;
+       parport_ax_epp_clear_timeout(p);
+       return 1;
 }
 
 unsigned char
@@ -302,6 +324,12 @@ static struct parport_operations parport_ax_ops =
        parport_ax_release_resources,
        parport_ax_claim_resources,
        
+       parport_ax_write_epp,
+       parport_ax_read_epp,
+       parport_ax_write_epp_addr,
+       parport_ax_read_epp_addr,
+       parport_ax_check_epp_timeout,
+
        parport_ax_epp_write_block,
        parport_ax_epp_read_block,
 
@@ -498,7 +526,7 @@ init_one_port(struct linux_ebus_device *dev)
        if (!(p = parport_register_port(base, irq, dma, &parport_ax_ops)))
                return 0;
 
-       /* Safe away pointer to our EBus DMA */
+       /* Save away pointer to our EBus DMA */
        p->private_data = (void *)dev->base_address[2];
 
        p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p);
index c01010c71b6d9b40f76ba1d319f50a8091946c68..78373a969ed39a5f0f355771a9b9dc12e16a6745 100644 (file)
@@ -20,8 +20,8 @@
  *
  * In addition, there are some optional registers:
  *
- *     base+3          EPP command
- *     base+4          EPP
+ *     base+3          EPP address
+ *     base+4          EPP data
  *     base+0x400      ECP config A
  *     base+0x401      ECP config B
  *     base+0x402      ECP control
@@ -60,12 +60,30 @@ static void parport_pc_null_intr_func(int irq, void *dev_id, struct pt_regs *reg
 
 void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
-       outb(d, p->base+EPPREG);
+       outb(d, p->base+EPPDATA);
 }
 
 unsigned char parport_pc_read_epp(struct parport *p)
 {
-       return inb(p->base+EPPREG);
+       return inb(p->base+EPPDATA);
+}
+
+void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
+{
+       outb(d, p->base+EPPADDR);
+}
+
+unsigned char parport_pc_read_epp_addr(struct parport *p)
+{
+       return inb(p->base+EPPADDR);
+}
+
+int parport_pc_check_epp_timeout(struct parport *p)
+{
+       if (!(inb(p->base+STATUS) & 1))
+               return 0;
+       parport_pc_epp_clear_timeout(p);
+       return 1;
 }
 
 unsigned char parport_pc_read_configb(struct parport *p)
@@ -196,7 +214,7 @@ size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length)
 {
        size_t got = 0;
        for (; got < length; got++) {
-               *((char*)buf)++ = inb (p->base+EPPREG);
+               *((char*)buf)++ = inb (p->base+EPPDATA);
                if (inb (p->base+STATUS) & 0x01)
                        break;
        }
@@ -207,7 +225,7 @@ size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length)
 {
        size_t written = 0;
        for (; written < length; written++) {
-               outb (*((char*)buf)++, p->base+EPPREG);
+               outb (*((char*)buf)++, p->base+EPPDATA);
                if (inb (p->base+STATUS) & 0x01)
                        break;
        }
@@ -267,6 +285,12 @@ struct parport_operations parport_pc_ops =
        parport_pc_release_resources,
        parport_pc_claim_resources,
        
+       parport_pc_write_epp,
+       parport_pc_read_epp,
+       parport_pc_write_epp_addr,
+       parport_pc_read_epp_addr,
+       parport_pc_check_epp_timeout,
+
        parport_pc_epp_write_block,
        parport_pc_epp_read_block,
 
@@ -290,7 +314,7 @@ struct parport_operations parport_pc_ops =
 /*
  * Clear TIMEOUT BIT in EPP MODE
  */
-static int epp_clear_timeout(struct parport *pb)
+int parport_pc_epp_clear_timeout(struct parport *pb)
 {
        unsigned char r;
 
@@ -313,6 +337,14 @@ static int epp_clear_timeout(struct parport *pb)
  */
 static int parport_SPP_supported(struct parport *pb)
 {
+       /*
+        * first clear an eventually pending EPP timeout 
+        * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
+        * that does not even respond to SPP cycles if an EPP
+        * timeout is pending
+        */
+       parport_pc_epp_clear_timeout(pb);
+
        /* Do a simple read-write test to make sure the port exists. */
        parport_pc_write_control(pb, 0xc);
        parport_pc_write_data(pb, 0xaa);
@@ -406,18 +438,18 @@ static int parport_ECP_supported(struct parport *pb)
 static int parport_EPP_supported(struct parport *pb)
 {
        /* If EPP timeout bit clear then EPP available */
-       if (!epp_clear_timeout(pb))
+       if (!parport_pc_epp_clear_timeout(pb))
                return 0;  /* No way to clear timeout */
 
        parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
        parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
-       epp_clear_timeout(pb);
+       parport_pc_epp_clear_timeout(pb);
        
        parport_pc_read_epp(pb);
        udelay(30);  /* Wait for possible EPP timeout */
        
        if (parport_pc_read_status(pb) & 0x01) {
-               epp_clear_timeout(pb);
+               parport_pc_epp_clear_timeout(pb);
                return PARPORT_MODE_PCEPP;
        }
 
@@ -465,7 +497,7 @@ static int parport_PS2_supported(struct parport *pb)
        int ok = 0;
        unsigned char octr = parport_pc_read_control(pb);
   
-       epp_clear_timeout(pb);
+       parport_pc_epp_clear_timeout(pb);
 
        parport_pc_write_control(pb, octr | 0x20);  /* try to tri-state the buffer */
        
@@ -563,10 +595,10 @@ static int irq_probe_EPP(struct parport *pb)
        if (pb->modes & PARPORT_MODE_PCECR)
                parport_pc_frob_econtrol (pb, 0x10, 0x10);
        
-       epp_clear_timeout(pb);
+       parport_pc_epp_clear_timeout(pb);
        parport_pc_frob_control (pb, 0x20, 0x20);
        parport_pc_frob_control (pb, 0x10, 0x10);
-       epp_clear_timeout(pb);
+       parport_pc_epp_clear_timeout(pb);
 
        /* Device isn't expecting an EPP read
         * and generates an IRQ.
@@ -648,12 +680,12 @@ static int parport_irq_probe(struct parport *pb)
            (pb->modes & PARPORT_MODE_PCECPEPP))
                pb->irq = irq_probe_EPP(pb);
 
-       epp_clear_timeout(pb);
+       parport_pc_epp_clear_timeout(pb);
 
        if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_PCEPP))
                pb->irq = irq_probe_EPP(pb);
 
-       epp_clear_timeout(pb);
+       parport_pc_epp_clear_timeout(pb);
 
        if (pb->irq == PARPORT_IRQ_NONE)
                pb->irq = irq_probe_SPP(pb);
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
new file mode 100644 (file)
index 0000000..149479b
--- /dev/null
@@ -0,0 +1,651 @@
+/* 
+ * 7990.c -- LANCE ethernet IC generic routines. 
+ * This is an attempt to separate out the bits of various ethernet
+ * drivers that are common because they all use the AMD 7990 LANCE 
+ * (Local Area Network Controller for Ethernet) chip.
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ *
+ * Most of this stuff was obtained by looking at other LANCE drivers,
+ * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
+ * NB: this was made easy by the fact that Jes Sorensen had cleaned up
+ * most of a2025 and sunlance with the aim of merging them, so the 
+ * common code was pretty obvious.
+ */
+#include <linux/config.h>
+#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/delay.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/pgtable.h>
+#include <linux/errno.h>
+
+/* Used for the temporal inet entries and routing */
+#include <linux/socket.h>
+#include <linux/route.h>
+
+#include <linux/dio.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "7990.h"
+
+/* Lossage Factor Nine, Mr Sulu. */
+#define WRITERAP(x) (lp->writerap(lp,x))
+#define WRITERDP(x) (lp->writerdp(lp,x))
+#define READRDP() (lp->readrdp(lp))
+/* These used to be ll->rap = x, ll->rdp = x, and (ll->rdp). Sigh. 
+ * If you want to switch them back then 
+ * #define DECLARE_LL volatile struct lance_regs *ll = lp->ll
+ */
+#define DECLARE_LL /* nothing to declare */
+
+/* debugging output macros, various flavours */
+/* #define TEST_HITS */
+#ifdef UNDEF
+#define PRINT_RINGS() \
+do { \
+        int t; \
+        for (t=0; t < RX_RING_SIZE; t++) { \
+                printk("R%d: @(%02X %04X) len %04X, mblen %04X, bits %02X\n",\
+                       t, ib->brx_ring[t].rmd1_hadr, ib->brx_ring[t].rmd0,\
+                       ib->brx_ring[t].length,\
+                       ib->brx_ring[t].mblength, ib->brx_ring[t].rmd1_bits);\
+        }\
+        for (t=0; t < TX_RING_SIZE; t++) { \
+                printk("T%d: @(%02X %04X) len %04X, misc %04X, bits %02X\n",\
+                       t, ib->btx_ring[t].tmd1_hadr, ib->btx_ring[t].tmd0,\
+                       ib->btx_ring[t].length,\
+                       ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits);\
+        }\
+} while (0) 
+#else
+#define PRINT_RINGS()
+#endif        
+
+/* Load the CSR registers. The LANCE has to be STOPped when we do this! */
+static void load_csrs (struct lance_private *lp)
+{
+        volatile struct lance_init_block *aib = lp->lance_init_block;
+        int leptr;
+        DECLARE_LL;
+
+        leptr = LANCE_ADDR (aib);
+
+        WRITERAP(LE_CSR1);                        /* load address of init block */
+        WRITERDP(leptr & 0xFFFF);
+        WRITERAP(LE_CSR2);
+        WRITERDP(leptr >> 16);
+        WRITERAP(LE_CSR3);
+        WRITERDP(lp->busmaster_regval);           /* set byteswap/ALEctrl/byte ctrl */
+
+        /* Point back to csr0 */
+        WRITERAP(LE_CSR0);
+}
+
+/* #define to 0 or 1 appropriately */
+#define DEBUG_IRING 0
+/* Set up the Lance Rx and Tx rings and the init block */
+/* Sets dev->tbusy */
+static void lance_init_ring (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */
+        int leptr;
+        int i;
+
+        aib = lp->lance_init_block;
+
+        /* Lock out other processes while setting up hardware */
+        dev->tbusy = 1;
+        lp->rx_new = lp->tx_new = 0;
+        lp->rx_old = lp->tx_old = 0;
+
+        ib->mode = LE_MO_PROM;                             /* normal, enable Tx & Rx */
+
+        /* Copy the ethernet address to the lance init block
+         * Notice that we do a byteswap if we're big endian.
+         * [I think this is the right criterion; at least, sunlance,
+         * a2065 and atarilance do the byteswap and lance.c (PC) doesn't.
+         * However, the datasheet says that the BSWAP bit doesn't affect
+         * the init block, so surely it should be low byte first for
+         * everybody? Um.] 
+         * We could define the ib->physaddr as three 16bit values and
+         * use (addr[1] << 8) | addr[0] & co, but this is more efficient.
+         */
+#ifdef __BIG_ENDIAN
+        ib->phys_addr [0] = dev->dev_addr [1];
+        ib->phys_addr [1] = dev->dev_addr [0];
+        ib->phys_addr [2] = dev->dev_addr [3];
+        ib->phys_addr [3] = dev->dev_addr [2];
+        ib->phys_addr [4] = dev->dev_addr [5];
+        ib->phys_addr [5] = dev->dev_addr [4];
+#else
+        for (i=0; i<6; i++)
+           ib->phys_addr[i] = dev->dev_addr[i];
+#endif        
+
+        if (DEBUG_IRING)
+                printk ("TX rings:\n");
+    
+        /* Setup the Tx ring entries */
+        for (i = 0; i < (1<<lp->lance_log_tx_bufs); i++) {
+                leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
+                ib->btx_ring [i].tmd0      = leptr;
+                ib->btx_ring [i].tmd1_hadr = leptr >> 16;
+                ib->btx_ring [i].tmd1_bits = 0;
+                ib->btx_ring [i].length    = 0xf000; /* The ones required by tmd2 */
+                ib->btx_ring [i].misc      = 0;
+                if (DEBUG_IRING) 
+                   printk ("%d: 0x%8.8x\n", i, leptr);
+        }
+
+        /* Setup the Rx ring entries */
+        if (DEBUG_IRING)
+                printk ("RX rings:\n");
+        for (i = 0; i < (1<<lp->lance_log_rx_bufs); i++) {
+                leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
+
+                ib->brx_ring [i].rmd0      = leptr;
+                ib->brx_ring [i].rmd1_hadr = leptr >> 16;
+                ib->brx_ring [i].rmd1_bits = LE_R1_OWN;
+                /* 0xf000 == bits that must be one (reserved, presumably) */
+                ib->brx_ring [i].length    = -RX_BUFF_SIZE | 0xf000;
+                ib->brx_ring [i].mblength  = 0;
+                if (DEBUG_IRING)
+                        printk ("%d: 0x%8.8x\n", i, leptr);
+        }
+
+        /* Setup the initialization block */
+    
+        /* Setup rx descriptor pointer */
+        leptr = LANCE_ADDR(&aib->brx_ring);
+        ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
+        ib->rx_ptr = leptr;
+        if (DEBUG_IRING)
+                printk ("RX ptr: %8.8x\n", leptr);
+    
+        /* Setup tx descriptor pointer */
+        leptr = LANCE_ADDR(&aib->btx_ring);
+        ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
+        ib->tx_ptr = leptr;
+        if (DEBUG_IRING)
+                printk ("TX ptr: %8.8x\n", leptr);
+
+        /* Clear the multicast filter */
+        ib->filter [0] = 0;
+        ib->filter [1] = 0;
+        PRINT_RINGS();
+}
+
+/* LANCE must be STOPped before we do this, too... */
+static int init_restart_lance (struct lance_private *lp)
+{
+        int i;
+        DECLARE_LL;
+
+        WRITERAP(LE_CSR0);
+        WRITERDP(LE_C0_INIT);
+
+        /* Need a hook here for sunlance ledma stuff */
+
+        /* Wait for the lance to complete initialization */
+        for (i = 0; (i < 100) && !(READRDP() & (LE_C0_ERR | LE_C0_IDON)); i++)
+                barrier();
+        if ((i == 100) || (READRDP() & LE_C0_ERR)) {
+                printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP());
+                return -1;
+        }
+
+        /* Clear IDON by writing a "1", enable interrupts and start lance */
+        WRITERDP(LE_C0_IDON);
+        WRITERDP(LE_C0_INEA | LE_C0_STRT);
+
+        return 0;
+}
+
+static int lance_reset (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *)dev->priv;
+        int status;
+        DECLARE_LL;
+    
+        /* Stop the lance */
+        WRITERAP(LE_CSR0);
+        WRITERDP(LE_C0_STOP);
+
+        load_csrs (lp);
+        lance_init_ring (dev);
+        dev->trans_start = jiffies;
+        dev->interrupt = 0;
+        dev->start = 1;
+        dev->tbusy = 0;
+        status = init_restart_lance (lp);
+#ifdef DEBUG_DRIVER
+        printk ("Lance restart=%d\n", status);
+#endif
+        return status;
+}
+
+static int lance_rx (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        volatile struct lance_rx_desc *rd;
+        unsigned char bits;
+        int len = 0;                    /* XXX shut up gcc warnings */
+        struct sk_buff *skb = 0;        /* XXX shut up gcc warnings */
+#ifdef TEST_HITS
+        int i;
+#endif
+        DECLARE_LL;
+
+#ifdef TEST_HITS
+        printk ("[");
+        for (i = 0; i < RX_RING_SIZE; i++) {
+                if (i == lp->rx_new)
+                        printk ("%s",
+                                ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "_" : "X");
+                else
+                        printk ("%s",
+                                ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "." : "1");
+        }
+        printk ("]");
+#endif
+    
+        WRITERDP(LE_C0_RINT | LE_C0_INEA);     /* ack Rx int, reenable ints */
+        for (rd = &ib->brx_ring [lp->rx_new];     /* For each Rx ring we own... */
+             !((bits = rd->rmd1_bits) & LE_R1_OWN);
+             rd = &ib->brx_ring [lp->rx_new]) {
+
+                /* We got an incomplete frame? */
+                if ((bits & LE_R1_POK) != LE_R1_POK) {
+                        lp->stats.rx_over_errors++;
+                        lp->stats.rx_errors++;
+                        continue;
+                } else if (bits & LE_R1_ERR) {
+                        /* Count only the end frame as a rx error,
+                         * not the beginning
+                         */
+                        if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
+                        if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
+                        if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
+                        if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
+                        if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+                } else {
+                        len = (rd->mblength & 0xfff) - 4;
+                        skb = dev_alloc_skb (len+2);
+
+                        if (skb == 0) {
+                                printk ("%s: Memory squeeze, deferring packet.\n",
+                                        dev->name);
+                                lp->stats.rx_dropped++;
+                                rd->mblength = 0;
+                                rd->rmd1_bits = LE_R1_OWN;
+                                lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
+                                return 0;
+                        }
+            
+                        skb->dev = dev;
+                        skb_reserve (skb, 2);           /* 16 byte align */
+                        skb_put (skb, len);             /* make room */
+                        eth_copy_and_sum(skb,
+                                         (unsigned char *)&(ib->rx_buf [lp->rx_new][0]),
+                                         len, 0);
+                        skb->protocol = eth_type_trans (skb, dev);
+                        netif_rx (skb);
+                        lp->stats.rx_packets++;
+                }
+
+                /* Return the packet to the pool */
+                rd->mblength = 0;
+                rd->rmd1_bits = LE_R1_OWN;
+                lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
+        }
+        return 0;
+}
+
+static int lance_tx (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        volatile struct lance_tx_desc *td;
+        int i, j;
+        int status;
+        DECLARE_LL;
+
+        /* csr0 is 2f3 */
+        WRITERDP(LE_C0_TINT | LE_C0_INEA);
+        /* csr0 is 73 */
+
+        j = lp->tx_old;
+        for (i = j; i != lp->tx_new; i = j) {
+                td = &ib->btx_ring [i];
+
+                /* If we hit a packet not owned by us, stop */
+                if (td->tmd1_bits & LE_T1_OWN)
+                        break;
+                
+                if (td->tmd1_bits & LE_T1_ERR) {
+                        status = td->misc;
+            
+                        lp->stats.tx_errors++;
+                        if (status & LE_T3_RTY)  lp->stats.tx_aborted_errors++;
+                        if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+
+                        if (status & LE_T3_CLOS) {
+                                lp->stats.tx_carrier_errors++;
+                                if (lp->auto_select) {
+                                        lp->tpe = 1 - lp->tpe;
+                                        printk("%s: Carrier Lost, trying %s\n",
+                                               dev->name, lp->tpe?"TPE":"AUI");
+                                        /* Stop the lance */
+                                        WRITERAP(LE_CSR0);
+                                        WRITERDP(LE_C0_STOP);
+                                        lance_init_ring (dev);
+                                        load_csrs (lp);
+                                        init_restart_lance (lp);
+                                        return 0;
+                                }
+                        }
+
+                        /* buffer errors and underflows turn off the transmitter */
+                        /* Restart the adapter */
+                        if (status & (LE_T3_BUF|LE_T3_UFL)) {
+                                lp->stats.tx_fifo_errors++;
+
+                                printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
+                                        dev->name);
+                                /* Stop the lance */
+                                WRITERAP(LE_CSR0);
+                                WRITERDP(LE_C0_STOP);
+                                lance_init_ring (dev);
+                                load_csrs (lp);
+                                init_restart_lance (lp);
+                                return 0;
+                        }
+                } else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) {
+                        /*
+                         * So we don't count the packet more than once.
+                         */
+                        td->tmd1_bits &= ~(LE_T1_POK);
+
+                        /* One collision before packet was sent. */
+                        if (td->tmd1_bits & LE_T1_EONE)
+                                lp->stats.collisions++;
+
+                        /* More than one collision, be optimistic. */
+                        if (td->tmd1_bits & LE_T1_EMORE)
+                                lp->stats.collisions += 2;
+
+                        lp->stats.tx_packets++;
+                }
+        
+                j = (j + 1) & lp->tx_ring_mod_mask;
+        }
+        lp->tx_old = j;
+        WRITERDP(LE_C0_TINT | LE_C0_INEA);
+        return 0;
+}
+
+static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+        struct device *dev = (struct device *)dev_id;
+        struct lance_private *lp = (struct lance_private *)dev->priv;
+        int csr0;
+        DECLARE_LL;
+        
+        WRITERAP(LE_CSR0);              /* LANCE Controller Status */
+        csr0 = READRDP();
+
+        PRINT_RINGS();
+        
+        if (!(csr0 & LE_C0_INTR))       /* Check if any interrupt has */
+                return;                 /* been generated by the Lance. */
+
+        if (dev->interrupt)
+                printk ("%s: again", dev->name);
+
+        dev->interrupt = 1;
+
+        /* Acknowledge all the interrupt sources ASAP */
+        WRITERDP(csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT));
+
+        if ((csr0 & LE_C0_ERR)) {
+                /* Clear the error condition */
+                WRITERDP(LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA);
+        }
+
+        if (csr0 & LE_C0_RINT)
+                lance_rx (dev);
+
+        if (csr0 & LE_C0_TINT)
+                lance_tx (dev);
+
+        /* Log misc errors. */
+        if (csr0 & LE_C0_BABL)
+                lp->stats.tx_errors++;       /* Tx babble. */
+        if (csr0 & LE_C0_MISS)
+                lp->stats.rx_errors++;       /* Missed a Rx frame. */
+        if (csr0 & LE_C0_MERR) {
+                printk("%s: Bus master arbitration failure, status %4.4x.\n", 
+                       dev->name, csr0);
+                /* Restart the chip. */
+                WRITERDP(LE_C0_STRT);
+        }
+
+        if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) {
+                dev->tbusy = 0;
+                mark_bh (NET_BH);
+        }
+        
+        WRITERAP(LE_CSR0);
+        WRITERDP(LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
+        
+        dev->interrupt = 0;
+}
+
+int lance_open (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *)dev->priv;
+        DECLARE_LL;
+        
+        /* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
+        if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev))
+                return -EAGAIN;
+
+        return lance_reset(dev);
+}
+
+int lance_close (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        DECLARE_LL;
+        
+        dev->start = 0;
+        dev->tbusy = 1;
+
+        /* Stop the LANCE */
+        WRITERAP(LE_CSR0);
+        WRITERDP(LE_C0_STOP);
+
+        free_irq(lp->irq, dev);
+
+        return 0;
+}
+
+int lance_start_xmit (struct sk_buff *skb, struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *)dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        int entry, skblen, len;
+        int status = 0;
+        static int outs;
+        DECLARE_LL;
+
+       lance_reset(dev);
+
+        /* Transmitter timeout, serious problems */
+        if (dev->tbusy) {
+                int tickssofar = jiffies - dev->trans_start;
+            
+                if (tickssofar < 100) {
+                        status = -1;
+                } else {
+                        printk ("%s: transmit timed out, status %04x, resetting\n",
+                                dev->name, READRDP());
+                        lance_reset (dev);
+                }
+                return status;
+        }
+
+        /* Block a timer-based transmit from overlapping. */
+        if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
+                printk ("Transmitter access conflict.\n");
+                return -1;
+        }
+
+        skblen = skb->len;
+
+        if (!TX_BUFFS_AVAIL)
+                return -1;
+
+#ifdef DEBUG_DRIVER
+        /* dump the packet */
+        {
+                int i;
+        
+                for (i = 0; i < 64; i++) {
+                        if ((i % 16) == 0)
+                                printk ("\n");
+                        printk ("%2.2x ", skb->data [i]);
+                }
+        }
+#endif
+        len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+        entry = lp->tx_new & lp->tx_ring_mod_mask;
+        ib->btx_ring [entry].length = (-len) | 0xf000;
+        ib->btx_ring [entry].misc = 0;
+    
+        memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
+    
+        /* Now, give the packet to the lance */
+        ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
+        lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
+
+        outs++;
+        /* Kick the lance: transmit now */
+        WRITERDP(LE_C0_INEA | LE_C0_TDMD);
+        dev->trans_start = jiffies;
+        dev_kfree_skb (skb);
+    
+        if (TX_BUFFS_AVAIL)
+                dev->tbusy = 0;
+
+        return status;
+}
+
+struct net_device_stats *lance_get_stats (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+
+        return &lp->stats;
+}
+
+/* taken from the depca driver via a2065.c */
+static void lance_load_multicast (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        volatile u16 *mcast_table = (u16 *)&ib->filter;
+        struct dev_mc_list *dmi=dev->mc_list;
+        char *addrs;
+        int i, j, bit, byte;
+        u32 crc, poly = CRC_POLYNOMIAL_LE;
+        
+        /* set all multicast bits */
+        if (dev->flags & IFF_ALLMULTI){ 
+                ib->filter [0] = 0xffffffff;
+                ib->filter [1] = 0xffffffff;
+                return;
+        }
+        /* clear the multicast filter */
+        ib->filter [0] = 0;
+        ib->filter [1] = 0;
+
+        /* Add addresses */
+        for (i = 0; i < dev->mc_count; i++){
+                addrs = dmi->dmi_addr;
+                dmi   = dmi->next;
+
+                /* multicast address? */
+                if (!(*addrs & 1))
+                        continue;
+                
+                crc = 0xffffffff;
+                for (byte = 0; byte < 6; byte++)
+                        for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
+                        {
+                                int test;
+
+                                test = ((bit ^ crc) & 0x01);
+                                crc >>= 1;
+
+                                if (test)
+                                {
+                                        crc = crc ^ poly;
+                                }
+                        }
+                
+                crc = crc >> 26;
+                mcast_table [crc >> 4] |= 1 << (crc & 0xf);
+        }
+        return;
+}
+
+
+void lance_set_multicast (struct device *dev)
+{
+        struct lance_private *lp = (struct lance_private *) dev->priv;
+        volatile struct lance_init_block *ib = lp->init_block;
+        DECLARE_LL;
+
+        while (dev->tbusy)
+                schedule();
+        set_bit (0, (void *) &dev->tbusy);
+
+        while (lp->tx_old != lp->tx_new)
+                schedule();
+
+        WRITERAP(LE_CSR0);
+        WRITERDP(LE_C0_STOP);
+        lance_init_ring (dev);
+
+        if (dev->flags & IFF_PROMISC) {
+                ib->mode |= LE_MO_PROM;
+        } else {
+                ib->mode &= ~LE_MO_PROM;
+                lance_load_multicast (dev);
+        }
+        load_csrs (lp);
+        init_restart_lance (lp);
+        dev->tbusy = 0;
+}
+
diff --git a/drivers/net/7990.h b/drivers/net/7990.h
new file mode 100644 (file)
index 0000000..4a8f072
--- /dev/null
@@ -0,0 +1,256 @@
+/* 
+ * 7990.h -- LANCE ethernet IC generic routines.
+ * This is an attempt to separate out the bits of various ethernet
+ * drivers that are common because they all use the AMD 7990 LANCE
+ * (Local Area Network Controller for Ethernet) chip.
+ * 
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ *
+ * Most of this stuff was obtained by looking at other LANCE drivers,
+ * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
+ */
+
+#ifndef _7990_H
+#define _7990_H
+
+/* The lance only has two register locations. We communicate mostly via memory. */
+struct lance_regs 
+{
+        unsigned short rdp;                       /* Register Data Port */
+        unsigned short rap;                       /* Register Address Port */
+};
+
+/* Transmit/receive ring definitions.
+ * We allow the specific drivers to override these defaults if they want to.
+ * NB: according to lance.c, increasing the number of buffers is a waste
+ * of space and reduces the chance that an upper layer will be able to
+ * reorder queued Tx packets based on priority. [Clearly there is a minimum
+ * limit too: too small and we drop rx packets and can't tx at full speed.]
+ * 4+4 seems to be the usual setting; the atarilance driver uses 3 and 5.
+ */
+
+/* Blast! This won't work. The problem is that we can't specify a default
+ * setting because that would cause the lance_init_block struct to be
+ * too long (and overflow the RAM on shared-memory cards like the HP LANCE.
+ */
+#ifndef LANCE_LOG_TX_BUFFERS
+#define LANCE_LOG_TX_BUFFERS 1
+#define LANCE_LOG_RX_BUFFERS 3
+#endif
+
+#define TX_RING_SIZE (1<<LANCE_LOG_TX_BUFFERS)
+#define RX_RING_SIZE (1<<LANCE_LOG_RX_BUFFERS)
+#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
+#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
+#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
+#define PKT_BUFF_SIZE (1544)
+#define RX_BUFF_SIZE PKT_BUFF_SIZE
+#define TX_BUFF_SIZE PKT_BUFF_SIZE
+
+/* Each receive buffer is described by a receive message descriptor (RMD) */
+struct lance_rx_desc {
+       volatile unsigned short rmd0;        /* low address of packet */
+       volatile unsigned char  rmd1_bits;   /* descriptor bits */
+       volatile unsigned char  rmd1_hadr;   /* high address of packet */
+       volatile short    length;           /* This length is 2s complement (negative)!
+                                    * Buffer length
+                                    */
+       volatile unsigned short mblength;    /* Actual number of bytes received */
+};
+/* Ditto for TMD: */
+struct lance_tx_desc {
+       volatile unsigned short tmd0;        /* low address of packet */
+       volatile unsigned char  tmd1_bits;   /* descriptor bits */
+       volatile unsigned char  tmd1_hadr;   /* high address of packet */
+       volatile short    length;                   /* Length is 2s complement (negative)! */
+       volatile unsigned short misc;
+};
+
+/* There are three memory structures accessed by the LANCE:
+ * the initialization block, the receive and transmit descriptor rings,
+ * and the data buffers themselves. In fact we might as well put the
+ * init block,the Tx and Rx rings and the buffers together in memory:
+ */
+struct lance_init_block {
+        volatile unsigned short mode;            /* Pre-set mode (reg. 15) */
+        volatile unsigned char phys_addr[6];     /* Physical ethernet address */
+        volatile unsigned filter[2];             /* Multicast filter (64 bits) */
+
+        /* Receive and transmit ring base, along with extra bits. */
+        volatile unsigned short rx_ptr;          /* receive descriptor addr */
+        volatile unsigned short rx_len;          /* receive len and high addr */
+        volatile unsigned short tx_ptr;          /* transmit descriptor addr */
+        volatile unsigned short tx_len;          /* transmit len and high addr */
+    
+        /* The Tx and Rx ring entries must be aligned on 8-byte boundaries. 
+         * This will be true if this whole struct is 8-byte aligned.
+         */
+        volatile struct lance_tx_desc btx_ring[TX_RING_SIZE];
+        volatile struct lance_rx_desc brx_ring[RX_RING_SIZE];
+
+        volatile char   tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
+        volatile char   rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
+        /* we use this just to make the struct big enough that we can move its startaddr
+         * in order to force alignment to an eight byte boundary.
+         */
+};
+
+/* This is where we keep all the stuff the driver needs to know about.
+ * I'm definitely unhappy about the mechanism for allowing specific
+ * drivers to add things...
+ */
+struct lance_private
+{
+        char *name;
+        volatile struct lance_regs *ll;
+        volatile struct lance_init_block *init_block; /* CPU address of RAM */
+        volatile struct lance_init_block *lance_init_block; /* LANCE address of RAM */
+        
+        int rx_new, tx_new;
+        int rx_old, tx_old;
+        
+        int lance_log_rx_bufs, lance_log_tx_bufs;
+        int rx_ring_mod_mask, tx_ring_mod_mask;
+        
+        struct net_device_stats stats;
+        int tpe;                                  /* TPE is selected */
+        int auto_select;                          /* cable-selection is by carrier */
+        unsigned short busmaster_regval;
+
+        unsigned int irq;                         /* IRQ to register */
+        
+        /* This is because the HP LANCE is disgusting and you have to check 
+         * a DIO-specific register every time you read/write the LANCE regs :-<
+         * [could we get away with making these some sort of macro?]
+         */
+        void (*writerap)(void *, unsigned short);
+        void (*writerdp)(void *, unsigned short);
+        unsigned short (*readrdp)(struct lance_private *);
+};
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+
+/*
+ *              Am7990 Control and Status Registers
+ */
+#define LE_CSR0         0x0000          /* LANCE Controller Status */
+#define LE_CSR1         0x0001          /* IADR[15:0] (bit0==0 ie word aligned) */
+#define LE_CSR2         0x0002          /* IADR[23:16] (high bits reserved) */
+#define LE_CSR3         0x0003          /* Misc */
+
+/*
+ *             Bit definitions for CSR0 (LANCE Controller Status)
+ */
+#define LE_C0_ERR      0x8000          /* Error = BABL | CERR | MISS | MERR */
+#define LE_C0_BABL     0x4000          /* Babble: Transmitted too many bits */
+#define LE_C0_CERR     0x2000          /* No Heartbeat (10BASE-T) */
+#define LE_C0_MISS     0x1000          /* Missed Frame (no rx buffer to put it in) */
+#define LE_C0_MERR     0x0800          /* Memory Error */
+#define LE_C0_RINT     0x0400          /* Receive Interrupt */
+#define LE_C0_TINT     0x0200          /* Transmit Interrupt */
+#define LE_C0_IDON     0x0100          /* Initialization Done */
+#define LE_C0_INTR     0x0080          /* Interrupt Flag 
+                                         = BABL | MISS | MERR | RINT | TINT | IDON */
+#define LE_C0_INEA     0x0040          /* Interrupt Enable */
+#define LE_C0_RXON     0x0020          /* Receive On */
+#define LE_C0_TXON     0x0010          /* Transmit On */
+#define LE_C0_TDMD     0x0008          /* Transmit Demand */
+#define LE_C0_STOP     0x0004          /* Stop */
+#define LE_C0_STRT     0x0002          /* Start */
+#define LE_C0_INIT     0x0001          /* Initialize */
+
+
+/*
+ *             Bit definitions for CSR3
+ */
+#define LE_C3_BSWP     0x0004          /* Byte Swap
+                                          (on for big endian byte order) */
+#define LE_C3_ACON     0x0002          /* ALE Control
+                                          (on for active low ALE) */
+#define LE_C3_BCON     0x0001          /* Byte Control */
+
+
+/*
+ *             Mode Flags
+ */
+#define LE_MO_PROM     0x8000          /* Promiscuous Mode */
+/* these next ones 0x4000 -- 0x0080 are not available on the LANCE 7990,
+ * but they are in NetBSD's am7990.h, presumably for backwards-compatible chips
+ */
+#define LE_MO_DRCVBC  0x4000          /* disable receive broadcast */
+#define LE_MO_DRCVPA  0x2000          /* disable physical address detection */
+#define LE_MO_DLNKTST 0x1000          /* disable link status */
+#define LE_MO_DAPC    0x0800          /* disable automatic polarity correction */
+#define LE_MO_MENDECL 0x0400          /* MENDEC loopback mode */
+#define LE_MO_LRTTSEL 0x0200          /* lower RX threshold / TX mode selection */
+#define LE_MO_PSEL1   0x0100          /* port selection bit1 */
+#define LE_MO_PSEL0   0x0080          /* port selection bit0 */
+/* and this one is from the C-LANCE data sheet... */
+#define LE_MO_EMBA      0x0080          /* Enable Modified Backoff Algorithm 
+                                           (C-LANCE, not original LANCE) */
+#define LE_MO_INTL     0x0040          /* Internal Loopback */
+#define LE_MO_DRTY     0x0020          /* Disable Retry */
+#define LE_MO_FCOLL    0x0010          /* Force Collision */
+#define LE_MO_DXMTFCS  0x0008          /* Disable Transmit CRC */
+#define LE_MO_LOOP     0x0004          /* Loopback Enable */
+#define LE_MO_DTX      0x0002          /* Disable Transmitter */
+#define LE_MO_DRX      0x0001          /* Disable Receiver */
+
+
+/*
+ *             Receive Flags
+ */
+#define LE_R1_OWN      0x80            /* LANCE owns the descriptor */
+#define LE_R1_ERR      0x40            /* Error */
+#define LE_R1_FRA      0x20            /* Framing Error */
+#define LE_R1_OFL      0x10            /* Overflow Error */
+#define LE_R1_CRC      0x08            /* CRC Error */
+#define LE_R1_BUF      0x04            /* Buffer Error */
+#define LE_R1_SOP      0x02            /* Start of Packet */
+#define LE_R1_EOP      0x01            /* End of Packet */
+#define LE_R1_POK       0x03           /* Packet is complete: SOP + EOP */
+
+
+/*
+ *             Transmit Flags
+ */
+#define LE_T1_OWN      0x80            /* LANCE owns the descriptor */
+#define LE_T1_ERR      0x40            /* Error */
+#define LE_T1_RES      0x20            /* Reserved, LANCE writes this with a zero */
+#define LE_T1_EMORE    0x10            /* More than one retry needed */
+#define LE_T1_EONE     0x08            /* One retry needed */
+#define LE_T1_EDEF     0x04            /* Deferred */
+#define LE_T1_SOP      0x02            /* Start of Packet */
+#define LE_T1_EOP      0x01            /* End of Packet */
+#define LE_T1_POK      0x03            /* Packet is complete: SOP + EOP */
+
+/*
+ *             Error Flags
+ */
+#define LE_T3_BUF      0x8000          /* Buffer Error */
+#define LE_T3_UFL      0x4000          /* Underflow Error */
+#define LE_T3_LCOL     0x1000          /* Late Collision */
+#define LE_T3_CLOS     0x0800          /* Loss of Carrier */
+#define LE_T3_RTY      0x0400          /* Retry Error */
+#define LE_T3_TDR      0x03ff          /* Time Domain Reflectometry */
+
+/* Miscellaneous useful macros */
+
+#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
+                        lp->tx_old+lp->tx_ring_mod_mask-lp->tx_new:\
+                        lp->tx_old - lp->tx_new-1)
+
+/* The LANCE only uses 24 bit addresses. This does the obvious thing. */
+#define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
+
+/* Now the prototypes we export */
+extern int lance_open(struct device *dev);
+extern int lance_close (struct device *dev);
+extern int lance_start_xmit (struct sk_buff *skb, struct device *dev);
+extern struct net_device_stats *lance_get_stats (struct device *dev);
+extern void lance_set_multicast (struct device *dev);
+
+#endif /* ndef _7990_H */
index 49fa6ce1da718d617fbcbc6f9fee90ad74e81f28..f6ef665192f224365aa27cebc58dc9c7a332efeb 100644 (file)
@@ -334,7 +334,6 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        }
     
        dev->interrupt = 1;
-       sti();
     
        /* Change to page 0 and read the intr status reg. */
        outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
index 4fe605dbe769f36d4afa2172d72722fd3b3934b4..bb65cb876ad2ba2237051007a36d0308d92d2aed 100644 (file)
@@ -24,6 +24,13 @@ fi
 #
 bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
+  if [ "$CONFIG_ARM" = "y" ]; then
+    if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
+      tristate 'AM79C961A support' CONFIG_ARM_AM79C961A
+    else
+      source drivers/acorn/net/Config.in
+    fi
+  fi
   if [ "$CONFIG_PMAC" = "y" ]; then
     bool 'MACE (Power Mac Ethernet) support' CONFIG_MACE
   fi
index 2e7cd531fa4103c5fcdaa9e90e1cf16bbbb7b26f..263448930cb7549ee4deeee619a0cd58c04bbb0a 100644 (file)
@@ -12,14 +12,16 @@ L_OBJS   := auto_irq.o
 M_OBJS   :=
 MOD_LIST_NAME := NET_MODULES
 
-# Need these to keep track of whether the 8390, PPP and SLHC modules should
-# really go in the kernel or a module.
+# Need these to keep track of whether the 7990 (LANCE), 8390, PPP and SLHC 
+# modules should really go in the kernel or a module.
 CONFIG_8390_BUILTIN :=
 CONFIG_8390_MODULE  :=
 CONFIG_SLHC_BUILTIN :=
 CONFIG_SLHC_MODULE  :=
 CONFIG_PPPDEF_BUILTIN :=
 CONFIG_PPPDEF_MODULE  :=
+CONFIG_7990_BUILTIN :=
+CONFIG_7990_MODULE :=
 
 ifeq ($(CONFIG_ISDN),y)
   ifeq ($(CONFIG_ISDN_PPP),y)
@@ -111,6 +113,13 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_ETHERH),y)
+CONFIG_8390_BUILTIN = y
+else
+  ifeq ($(CONFIG_ETHERH),m)
+  CONFIG_8390_MODULE = y
+  endif
+endif
 
 ifeq ($(CONFIG_WD80x3),y)
 L_OBJS += wd.o
@@ -667,6 +676,24 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_HPLANCE),y)
+L_OBJS += hplance.o
+CONFIG_7990_BUILTIN = y
+else
+  ifeq ($(CONFIG_HPLANCE),m)
+  CONFIG_7990_MODULE = y
+  M_OBJS += hplance.o
+  endif
+endif
+# If we need generic LANCE support, either in the kernel or as a module,
+# build it in the appropriate way.
+ifdef CONFIG_7990_BUILTIN
+L_OBJS += 7990.o
+else
+  ifdef CONFIG_7990_MODULE
+  M_OBJS += 7990.o
+  endif
+endif
 
 ifeq ($(CONFIG_EQUALIZER),y)
 L_OBJS += eql.o
index 4725c580a9bab2fd3bcae25e305472c0e478147e..88406fc804d4653e07e1a8fad89ac0d68da72e4f 100644 (file)
@@ -92,12 +92,17 @@ extern int atarilance_probe(struct device *);
 extern int a2065_probe(struct device *);
 extern int ariadne_probe(struct device *);
 extern int hydra_probe(struct device *);
+extern int bionet_probe(struct device *);
+extern int pamsnet_probe(struct device *);
 extern int tlan_probe(struct device *);
 extern int mace_probe(struct device *);
 extern int cs89x0_probe(struct device *dev);
 extern int ethertap_probe(struct device *dev);
+extern int acorn_ethif_probe(struct device *dev);
+extern int am79c961_probe(struct device *dev);
 extern int epic100_probe(struct device *dev);
 extern int rtl8139_probe(struct device *dev);
+extern int hplance_probe(struct device *dev);
 
 /* Gigabit Ethernet adapters */
 extern int yellowfin_probe(struct device *dev);
@@ -276,6 +281,15 @@ __initfunc(static int ethif_probe(struct device *dev))
 #ifdef CONFIG_HYDRA            /* Hydra Systems Amiganet Ethernet board */
        && hydra_probe(dev)
 #endif
+#ifdef CONFIG_ATARI_BIONET     /* Atari Bionet Ethernet board */
+       && bionet_probe(dev)
+#endif
+#ifdef CONFIG_ATARI_PAMSNET    /* Atari PAMsNet Ethernet board */
+       && pamsnet_probe(dev)
+#endif
+#ifdef CONFIG_HPLANCE          /* HP300 internal Ethernet */
+       && hplance_probe(dev)
+#endif
 #ifdef CONFIG_SUNLANCE
        && sparc_lance_probe(dev)
 #endif
@@ -296,7 +310,7 @@ __initfunc(static int ethif_probe(struct device *dev))
 #endif
 #ifdef CONFIG_MIPS_JAZZ_SONIC
        && sonic_probe(dev)
-#endif 
+#endif
 #ifdef CONFIG_ARCH_ACORN
        && acorn_ethif_probe(dev)
 #endif
@@ -425,7 +439,7 @@ static struct device atp_dev = {
 # define ETH0_IRQ 0
 #endif
 
-#ifndef __sparc__
+#if !defined(__sparc__) && !defined(CONFIG_ARCH_ACORN)
 #define ETH_NOPROBE_ADDR 0xffe0
 #else
 #define ETH_NOPROBE_ADDR 0
index 23c8054e3a8de5bd31d7da9a9d1ea31b812b8bb9..f17950109b9c84a5e1bcbb6707344bc12e69f3e2 100644 (file)
@@ -6,6 +6,8 @@
  * and         Torsten Narjes <narjes@ifk-mp.uni-kiel.de>
  *
  * Little adaptions for integration into pl7 by Roman Hodek
+ *
+ * Some changes in bionet_poll_rx by Karl-Heinz Lohner
  *
        What is it ?
        ------------
@@ -238,7 +240,7 @@ get_frame(unsigned long paddr, int odd) {
        dma_wd.dma_mode_status          = 0x9a;
        dma_wd.dma_mode_status          = 0x19a;
        dma_wd.dma_mode_status          = 0x9a;
-       dma_wd.fdc_acces_seccount       = 0x05;         /* sector count */
+       dma_wd.fdc_acces_seccount       = 0x04;         /* sector count (was 5) */
        dma_wd.dma_lo                   = (unsigned char)paddr;
        paddr >>= 8;
        dma_wd.dma_md                   = (unsigned char)paddr;
@@ -293,7 +295,7 @@ hardware_send_packet(unsigned long paddr, int cnt) {
        paddr >>= 8;
        dma_wd.dma_hi           = (unsigned char)paddr;
 
-       dma_wd.fdc_acces_seccount       = 0xaa;         /* sector count */
+       dma_wd.fdc_acces_seccount       = 0x4;          /* sector count */
        restore_flags(flags);
 
        c = sendcmd(0,0x100,NODE_ADR | C_WRITE);        /* CMD: WRITE */
@@ -454,6 +456,28 @@ bionet_send_packet(struct sk_buff *skb, struct device *dev) {
                        buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer;
                }
 
+               if (bionet_debug >1) {
+                       u_char *data = nic_packet->buffer, *p;
+                       int i;
+                       
+                       printk( "%s: TX pkt type 0x%4x from ", dev->name,
+                                 ((u_short *)data)[6]);
+
+                       for( p = &data[6], i = 0; i < 6; i++ )
+                               printk("%02x%s", *p++,i != 5 ? ":" : "" );
+                       printk(" to ");
+
+                       for( p = data, i = 0; i < 6; i++ )
+                               printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+
+                       printk( "%s: ", dev->name );
+                       printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+                              " %02x%02x%02x%02x len %d\n",
+                                 data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
+                                 data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
+                                 data[28], data[29], data[30], data[31], data[32], data[33],
+                                 length );
+               }
                dma_cache_maintenance(buf, length, 1);
 
                stat = hardware_send_packet(buf, length);
@@ -499,7 +523,7 @@ bionet_poll_rx(struct device *dev) {
        while(boguscount--) {
                status = get_frame((unsigned long)phys_nic_packet, 0);
 
-               if( status != 1 ) break;
+               if( status == 0 ) break;
 
                /* Good packet... */
 
@@ -508,34 +532,63 @@ bionet_poll_rx(struct device *dev) {
                pkt_len = (nic_packet->l_hi << 8) | nic_packet->l_lo;
 
                lp->poll_time = bionet_min_poll_time;    /* fast poll */
-               if( pkt_len >= 60 && pkt_len <= 1514 ) {
-
+               if( pkt_len >= 60 && pkt_len <= 1520 ) {
+                                       /*      ^^^^ war 1514  KHL */
                        /* Malloc up new buffer.
                         */
-                       struct sk_buff *skb = alloc_skb(pkt_len, GFP_ATOMIC);
+                       struct sk_buff *skb = dev_alloc_skb( pkt_len + 2 );
                        if (skb == NULL) {
                                printk("%s: Memory squeeze, dropping packet.\n",
                                        dev->name);
                                lp->stats.rx_dropped++;
                                break;
                        }
-                       skb->len = pkt_len;
+
                        skb->dev = dev;
+                       skb_reserve( skb, 2 );          /* 16 Byte align  */
+                       skb_put( skb, pkt_len );        /* make room */
 
                        /* 'skb->data' points to the start of sk_buff data area.
                         */
                        memcpy(skb->data, nic_packet->buffer, pkt_len);
+                       skb->protocol = eth_type_trans( skb, dev ); 
                        netif_rx(skb);
                        lp->stats.rx_packets++;
                        lp->stats.rx_bytes+=pkt_len;
-               }
-       }
 
        /* If any worth-while packets have been received, dev_rint()
           has done a mark_bh(INET_BH) for us and will work on them
           when we get to the bottom-half routine.
         */
 
+                       if (bionet_debug >1) {
+                               u_char *data = nic_packet->buffer, *p;
+                               int i;
+                               
+                               printk( "%s: RX pkt type 0x%4x from ", dev->name,
+                                         ((u_short *)data)[6]);
+                                        
+                               
+                               for( p = &data[6], i = 0; i < 6; i++ )
+                                       printk("%02x%s", *p++,i != 5 ? ":" : "" );
+                               printk(" to ");
+                               for( p = data, i = 0; i < 6; i++ )
+                                       printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+                               printk( "%s: ", dev->name );
+                               printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+                                      " %02x%02x%02x%02x len %d\n",
+                                         data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
+                                         data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
+                                         data[28], data[29], data[30], data[31], data[32], data[33],
+                                                 pkt_len );
+                       }
+               }
+               else {
+                       printk(" Packet has wrong length: %04d bytes\n", pkt_len);
+                       lp->stats.rx_errors++;
+               }
+       }
        stdma_release();
        ENABLE_IRQ();
        return;
index 5fce49bb499e2ba0a15cc6707c57aaf62039b811..bf453dc53c582471b3cd6cdce490b10c6cf51d9a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dmascc.c,v 1.2.1.3 1997/12/19 13:40:15 oe1kib Exp $
+ * $Id: dmascc.c,v 1.2.1.4 1998/06/10 02:24:11 kudielka Exp $
  *
  * Driver for high-speed SCC boards (those with DMA support)
  * Copyright (C) 1997 Klaus Kudielka
diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c
new file mode 100644 (file)
index 0000000..0c3f517
--- /dev/null
@@ -0,0 +1,249 @@
+/* hplance.c  : the  Linux/hp300/lance ethernet driver
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Based on the Sun Lance driver and the NetBSD HP Lance driver
+ * Uses the generic 7990.c LANCE code.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* Used for the temporal inet entries and routing */
+#include <linux/socket.h>
+#include <linux/route.h>
+
+#include <linux/dio.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "hplance.h"
+
+/* We have 16834 bytes of RAM for the init block and buffers. This places
+ * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
+ * buffers and 2 Tx buffers.
+ */
+#define LANCE_LOG_TX_BUFFERS 1
+#define LANCE_LOG_RX_BUFFERS 3
+
+#include "7990.h"                                 /* use generic LANCE code */
+
+/* Our private data structure */
+struct hplance_private {
+  struct lance_private lance;
+  unsigned int scode;
+  void *base;
+};
+
+/* function prototypes... This is easy because all the grot is in the
+ * generic LANCE support. All we have to support is probing for boards,
+ * plus board-specific init, open and close actions. 
+ * Oh, and we need to tell the generic code how to read and write LANCE registers...
+ */
+int hplance_probe(struct device *dev);
+static int hplance_init(struct device *dev, int scode);
+static int hplance_open(struct device *dev);
+static int hplance_close(struct device *dev);
+static void hplance_writerap(struct hplance_private *lp, unsigned short value);
+static void hplance_writerdp(struct hplance_private *lp, unsigned short value);
+static unsigned short hplance_readrdp(struct hplance_private *lp);
+
+#ifdef MODULE
+static struct hplance_private *root_hplance_dev = NULL;
+#endif
+
+/* Find all the HP Lance boards and initialise them... */
+__initfunc(int hplance_probe(struct device *dev))
+{
+        int cards = 0, called = 0;
+
+        if (!MACH_IS_HP300 || called)
+                return(ENODEV);
+        called++;
+        
+        /* Isn't DIO nice? */
+        for(;;)
+        {
+                int v, scode = dio_find(DIO_ID_LAN);
+                                
+                if (!scode)
+                        break;
+                
+                if(cards)
+                        dev = NULL;      /* don't trash previous device, make a new one */
+                cards++;
+                
+                v = hplance_init(dev, scode);
+                if (v)                            /* error, abort immediately */
+                        return v;
+        }
+        /* OK, return success, or ENODEV if we didn't find any cards */
+        if (!cards)
+                return ENODEV;
+        return 0;
+}
+
+/* Initialise a single lance board at the given select code */
+__initfunc (static int hplance_init(struct device *dev, int scode))
+{
+        /* const char *name = dio_scodetoname(scode); */
+        static const char name[] = "HP LANCE";
+        void *va = dio_scodetoviraddr(scode);
+        struct hplance_private *lp;
+        int i;
+        
+        if (dev == NULL)
+                dev = init_etherdev(0, sizeof(struct hplance_private));
+        else
+        {
+                dev->priv = kmalloc(sizeof(struct hplance_private), GFP_KERNEL);
+                if (dev->priv == NULL)
+                        return -ENOMEM;
+                memset(dev->priv, 0, sizeof(struct hplance_private));
+        }
+        printk("%s: HP LANCE; select code %d, addr", dev->name, scode);
+
+        /* reset the board */
+        writeb(0xff,va+DIO_IDOFF);
+        udelay(100);                              /* ariba! ariba! udelay! udelay! */
+
+        /* Fill the dev fields */
+        dev->base_addr = (unsigned long)va;
+        dev->open = &hplance_open;
+        dev->stop = &hplance_close;
+        dev->hard_start_xmit = &lance_start_xmit;
+        dev->get_stats = &lance_get_stats;
+        dev->set_multicast_list = &lance_set_multicast;
+        dev->dma = 0;
+        
+        for (i=0; i<6; i++)
+        {
+                /* The NVRAM holds our ethernet address, one nibble per byte,
+                 * at bytes NVRAMOFF+1,3,5,7,9...
+                 */
+                dev->dev_addr[i] = ((readb(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
+                        | (readb(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
+                printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
+        }
+        
+        lp = (struct hplance_private *)dev->priv;
+        lp->lance.name = (char*)name;                   /* discards const, shut up gcc */
+        lp->lance.ll = (struct lance_regs *)(va + HPLANCE_REGOFF);
+        lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
+        lp->lance.lance_init_block = 0;                 /* LANCE addr of same RAM */
+        lp->lance.busmaster_regval = LE_C3_BSWP;        /* we're bigendian */
+        lp->lance.irq = dio_scodetoipl(scode);
+        lp->lance.writerap = hplance_writerap;
+        lp->lance.writerdp = hplance_writerdp;
+        lp->lance.readrdp = hplance_readrdp;
+        lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
+        lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
+        lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
+        lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
+        lp->scode = scode;
+       lp->base = va;
+        ether_setup(dev);
+       printk(", irq %d\n", lp->lance.irq);
+
+#ifdef MODULE
+        dev->ifindex = dev_new_index();
+        lp->next_module = root_hplance_dev;
+        root_hplance_dev = lp;
+#endif /* MODULE */
+
+        dio_config_board(scode);                  /* tell bus scanning code this one's taken */
+        return 0;
+}
+
+/* This is disgusting. We have to check the DIO status register for ack every
+ * time we read or write the LANCE registers.
+ */
+static void hplance_writerap(struct hplance_private *lp, unsigned short value)
+{
+        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        do {
+                lp->lance.ll->rap = value;
+        } while ((hpregs->status & LE_ACK) == 0);
+}
+
+static void hplance_writerdp(struct hplance_private *lp, unsigned short value)
+{
+        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        do {
+                lp->lance.ll->rdp = value;
+        } while ((hpregs->status & LE_ACK) == 0);
+}
+
+static unsigned short hplance_readrdp(struct hplance_private *lp)
+{
+        unsigned short val;
+        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        do {
+                val = lp->lance.ll->rdp;
+        } while ((hpregs->status & LE_ACK) == 0);
+        return val;
+}
+
+static int hplance_open(struct device *dev)
+{
+        int status;
+        struct hplance_private *lp = (struct hplance_private *)dev->priv;
+        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        
+        status = lance_open(dev);                 /* call generic lance open code */
+        if (status)
+                return status;
+        /* enable interrupts at board level. */
+        writeb(LE_IE, &(hpregs->status));
+
+        MOD_INC_USE_COUNT;
+        return 0;
+}
+
+static int hplance_close(struct device *dev)
+{
+        struct hplance_private *lp = (struct hplance_private *)dev->priv;
+        struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+        writeb(0,&(hpregs->status));              /* disable interrupts at boardlevel */
+        lance_close(dev);
+        MOD_DEC_USE_COUNT;
+        return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+        root_lance_dev = NULL;
+        return hplance_probe(NULL);
+}
+
+void cleanup_module(void)
+{
+        /* Walk the chain of devices, unregistering them */
+        struct hplance_private *lp;
+        while (root_hplance_dev) {
+                lp = root_hplance_dev->next_module;
+                dio_unconfig_board(lp->scode);
+                unregister_netdev(root_lance_dev->dev);
+                kfree(root_lance_dev->dev);
+                root_lance_dev = lp;
+        }
+}
+
+#endif /* MODULE */
diff --git a/drivers/net/hplance.h b/drivers/net/hplance.h
new file mode 100644 (file)
index 0000000..3af4c4d
--- /dev/null
@@ -0,0 +1,31 @@
+/* Random defines and structures for the HP Lance driver.
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Based on the Sun Lance driver and the NetBSD HP Lance driver
+ */
+
+/* Registers */
+struct hplance_reg
+{
+        u_char pad0;
+        volatile u_char id;                       /* DIO register: ID byte */
+        u_char pad1;
+        volatile u_char status;                   /* DIO register: interrupt enable */
+};
+
+/* Control and status bits for the hplance->status register */
+#define LE_IE 0x80                                /* interrupt enable */
+#define LE_IR 0x40                                /* interrupt requested */
+#define LE_LOCK 0x08                              /* lock status register */
+#define LE_ACK 0x04                               /* ack of lock */
+#define LE_JAB 0x02                               /* loss of tx clock (???) */
+/* We can also extract the IPL from the status register with the standard
+ * DIO_IPL(hplance) macro, or using dio_scodetoipl()
+ */
+
+/* These are the offsets for the DIO regs (hplance_reg), lance_ioreg,
+ * memory and NVRAM:
+ */
+#define HPLANCE_IDOFF 0                           /* board baseaddr, struct hplance_reg */
+#define HPLANCE_REGOFF 0x4000                     /* struct lance_regs */
+#define HPLANCE_MEMOFF 0x8000                     /* struct lance_init_block */
+#define HPLANCE_NVRAMOFF 0xC008                   /* etheraddress as one *nibble* per byte */
index 63723afb5ad44fee187d97757a920c2f95c1974f..b2aa9b27bfe1bddfc257497ee5eda1028d7968e7 100644 (file)
@@ -52,7 +52,7 @@
 #include <linux/if_ether.h>    /* For the statistics structure. */
 #include <linux/if_arp.h>      /* For ARPHRD_ETHER */
 
-#define LOOPBACK_MTU (PAGE_SIZE*7/8)
+#define LOOPBACK_MTU   (PAGE_SIZE - 172)
 
 /*
  * The higher levels take care of making this non-reentrant (it's
index b7cdc8bb90fd7cb388a8e7660a45b2d132d19c27..73b69e14d7c37ec8bfc081518effe3444f6b0ff1 100644 (file)
@@ -10,7 +10,7 @@
  *
  *  Machine hang caused by NULLing a live wait queue fix. <Alan.Cox@linux.org>
  *
- *  ==FILEVERSION 980607==
+ *  ==FILEVERSION 980608==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
@@ -208,6 +208,7 @@ static void ppp_tty_wakeup (struct tty_struct *tty);
        CHECK_PPP_MAGIC(ppp); \
        if (!ppp->inuse) { \
                printk (ppp_warning, __LINE__); \
+               return; \
        } \
 } while (0)
 
@@ -1706,7 +1707,6 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, size_t nr)
 {
        struct ppp *ppp = tty2ppp (tty);
        __u8 c;
-       int error;
        ssize_t len, ret;
 
 #define GETC(c)                                                \
@@ -1720,41 +1720,40 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, size_t nr)
  */
        if (!ppp)
                return -EIO;
-
-       /* if (ppp->magic != PPP_MAGIC)
-               return -EIO; */
-
        CHECK_PPP (-ENXIO);
 
 /*
  * Before we attempt to write the frame to the user, ensure that the
  * user has access to the pages for the total buffer length.
  */
-       error = verify_area (VERIFY_WRITE, buf, nr);
-       if (error != 0)
-               return (error);
+       if (verify_area (VERIFY_WRITE, buf, nr))
+               return -EFAULT;
+
+/*
+ * Increment the module use count so that the module can't get unloaded
+ * while we're sleeping below.  The problem is that ppp_tty_close() can
+ * get called (as a result of a hangup from the tty) while we're sleeping.
+ */
+       MOD_INC_USE_COUNT;
 
 /*
  * Acquire the read lock.
  */
        for (;;) {
+               ret = 0;
                ppp = tty2ppp (tty);
                if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
                    || tty != ppp->tty)
-                       return 0;
+                       goto done;
 
                if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) {
-#if 0
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_DEBUG
-                                    "ppp_tty_read: sleeping(ubuf)\n");
-#endif
                        current->timeout = 0;
                        current->state   = TASK_INTERRUPTIBLE;
-                       schedule ();
+                       schedule();
 
+                       ret = -EINTR;
                        if (signal_pending(current))
-                               return -EINTR;
+                               goto done;
                        continue;
                }
 
@@ -1777,17 +1776,14 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, size_t nr)
  */
                /* no data */
                clear_bit (0, &ppp->ubuf->locked);
+               ret = -EAGAIN;
                if (file->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
+                       goto done;
                current->timeout = 0;
-#if 0
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_DEBUG
-                               "ppp_tty_read: sleeping(read_wait)\n");
-#endif
                interruptible_sleep_on (&ppp->read_wait);
+               ret = -EINTR;
                if (signal_pending(current))
-                       return -EINTR;
+                       goto done;
        }
 
 /*
@@ -1802,7 +1798,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, size_t nr)
                                "ppp: read of %lu bytes too small for %ld "
                                "frame\n", (unsigned long) nr, (long) len + 2);
                ppp->stats.ppp_ierrors++;
-               error = -EOVERFLOW;
+               ret = -EOVERFLOW;
                goto out;
        }
 
@@ -1810,35 +1806,32 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, size_t nr)
  * Fake the insertion of the ADDRESS and CONTROL information because these
  * were not saved in the buffer.
  */
-       error = put_user((u_char) PPP_ALLSTATIONS, buf);
-       if (error)
+       ret = -EFAULT;
+       if (put_user((u_char) PPP_ALLSTATIONS, buf)
+           || put_user((u_char) PPP_UI, buf+1))
                goto out;
-       ++buf;
-       error = put_user((u_char) PPP_UI, buf);
-       if (error)
-               goto out;
-       ++buf;
+       buf += 2;
 
 /*
  * Copy the received data from the buffer to the caller's area.
  */
-       ret = len + 2;  /* Account for ADDRESS and CONTROL bytes */
+       nr = len + 2;   /* Account for ADDRESS and CONTROL bytes */
        while (len-- > 0) {
                GETC (c);
-               error = put_user(c, buf);
-               if (error)
+               if (put_user(c, buf))
                        goto out;
                ++buf;
        }
-
-       clear_bit (0, &ppp->ubuf->locked);
-       return ret;
+       ret = nr;
 
 out:
-       ppp->ubuf->tail += len;
-       ppp->ubuf->tail &= ppp->ubuf->size;
-       clear_bit (0, &ppp->ubuf->locked);
-       return error;
+       if (len > 0)
+               ppp->ubuf->tail = (ppp->ubuf->tail + len) & ppp->ubuf->size;
+       clear_bit(0, &ppp->ubuf->locked);
+
+done:
+       MOD_DEC_USE_COUNT;
+       return ret;
 #undef GETC
 }
 
@@ -2100,6 +2093,14 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
        error = -EFAULT;
        if (copy_from_user(new_data, data, count))
                goto out_free;
+
+/*
+ * Increment the module use count so that the module can't get unloaded
+ * while we're sleeping below.  The problem is that ppp_tty_close() can
+ * get called (as a result of a hangup from the tty) while we're sleeping.
+ */
+       MOD_INC_USE_COUNT;
+
 /*
  * Lock this PPP unit so we will be the only writer,
  * sleeping if necessary.
@@ -2131,7 +2132,7 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
        current->state = TASK_RUNNING;
        remove_wait_queue(&ppp->write_wait, &wait);
        if (error)
-               goto out_free;
+               goto out_free_dec;
 
 /*
  * Change the LQR frame
@@ -2154,6 +2155,8 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
        }
        error = count;
 
+out_free_dec:
+       MOD_DEC_USE_COUNT;
 out_free:
        kfree (new_data);
 out:
@@ -2619,6 +2622,7 @@ ppp_dev_open (struct device *dev)
                        dev->name);
 
        CHECK_PPP (-ENXIO);
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -2631,6 +2635,7 @@ ppp_dev_close (struct device *dev)
 {
        struct ppp *ppp = dev2ppp (dev);
 
+       MOD_DEC_USE_COUNT;
        if (ppp2tty (ppp) == NULL) {
                return -ENXIO;
        }
@@ -3094,6 +3099,8 @@ ppp_alloc (void)
                ppp_last->next = ppp;
        ppp_last = ppp;
        ppp->next = 0;
+       ppp->read_wait  = NULL;
+       ppp->write_wait = NULL;
 
        dev = ppp2dev(ppp);
        dev->next      = NULL;
index 269a0f55a792bfc8eea46bb68d8a022da08d145d..214fb7a993e3a8de8b22136d2e0f11f117ca5bab 100644 (file)
@@ -1,10 +1,10 @@
 /*
- *     Wavelan ISA driver
+ *     WaveLAN ISA driver
  *
  *             Jean II - HPLB '96
  *
  * Reorganisation and extension of the driver.
- * Original copyrigth follow (see also end of this file).
+ * Original copyright follows (also see the end of this file).
  * See wavelan.p.h for details.
  */
 
@@ -19,7 +19,7 @@
 /************************* MISC SUBROUTINES **************************/
 /*
  * Subroutines which won't fit in one of the following category
- * (wavelan modem or i82586)
+ * (WaveLAN modem or i82586)
  */
 
 /*------------------------------------------------------------------*/
@@ -95,14 +95,14 @@ wv_struct_check(void)
 #undef SC
 
   return((char *) NULL);
-} /* wv_structuct_check */
+} /* wv_struct_check */
 #endif /* STRUCT_CHECK */
 
 /********************* HOST ADAPTER SUBROUTINES *********************/
 /*
- * Usefull subroutines to manage the wavelan ISA interface
+ * Useful subroutines to manage the WaveLAN ISA interface
  *
- * One major difference with the Pcmcia hardware (exept the port mapping)
+ * One major difference with the PCMCIA hardware (except the port mapping)
  * is that we have to keep the state of the Host Control Register
  * because of the interrupt enable & bus size flags.
  */
@@ -166,7 +166,7 @@ wv_hacr_reset(u_long        ioaddr)
 
 /*------------------------------------------------------------------*/
 /*
- * Set the i/o transfer over the ISA bus to 8 bits mode
+ * Set the I/O transfer over the ISA bus to 8-bit mode
  */
 static inline void
 wv_16_off(u_long       ioaddr,
@@ -178,7 +178,7 @@ wv_16_off(u_long    ioaddr,
 
 /*------------------------------------------------------------------*/
 /*
- * Set the i/o transfer over the ISA bus to 8 bits mode
+ * Set the I/O transfer over the ISA bus to 8-bit mode
  */
 static inline void
 wv_16_on(u_long                ioaddr,
@@ -190,7 +190,7 @@ wv_16_on(u_long             ioaddr,
 
 /*------------------------------------------------------------------*/
 /*
- * Disable interrupts on the wavelan hardware
+ * Disable interrupts on the WaveLAN hardware.
  */
 static inline void
 wv_ints_off(device *   dev)
@@ -209,7 +209,7 @@ wv_ints_off(device *        dev)
 
 /*------------------------------------------------------------------*/
 /*
- * Enable interrupts on the wavelan hardware
+ * Enable interrupts on the WaveLAN hardware.
  */
 static inline void
 wv_ints_on(device *    dev)
@@ -228,7 +228,7 @@ wv_ints_on(device * dev)
 
 /******************* MODEM MANAGEMENT SUBROUTINES *******************/
 /*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the WaveLAN
  */
 
 /*------------------------------------------------------------------*/
@@ -259,7 +259,7 @@ psa_read(u_long             ioaddr,
 
 /*------------------------------------------------------------------*/
 /*
- * Write the Paramter Storage Area to the WaveLAN card's memory
+ * Write the Parameter Storage Area to the WaveLAN card's memory.
  */
 static void
 psa_write(u_long       ioaddr,
@@ -294,10 +294,10 @@ psa_write(u_long  ioaddr,
 /*------------------------------------------------------------------*/
 /*
  * Calculate the PSA CRC (not tested yet)
- * As the Wavelan drivers don't use the CRC, I won't use it either...
- * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code
+ * As the WaveLAN drivers don't use the CRC, I won't use it either.
+ * Thanks to Nico Valster <NVALSTER@wcnd.nl.lucent.com> for the code
  * NOTE: By specifying a length including the CRC position the
- * returned value should be zero. (i.e. a correct checksum in the PSA)
+ * returned value should be zero. (i.e. a correct checksum in the PSA).
  */
 static u_short
 psa_crc(u_short *      psa,    /* The PSA */
@@ -344,7 +344,7 @@ mmc_out(u_long              ioaddr,
 /*------------------------------------------------------------------*/
 /*
  * Routine to write bytes to the Modem Management Controller.
- * We start by the end because it is the way it should be !
+ * We start at the end because it is the way it should be!
  */
 static inline void
 mmc_write(u_long       ioaddr,
@@ -361,8 +361,8 @@ mmc_write(u_long    ioaddr,
 
 /*------------------------------------------------------------------*/
 /*
- * Read 1 byte from the MMC.
- * Optimised version for 1 byte, avoid using memory...
+ * Read a byte from the MMC.
+ * Optimised version for 1 byte, avoid using memory.
  */
 static inline u_char
 mmc_in(u_long  ioaddr,
@@ -383,7 +383,7 @@ mmc_in(u_long       ioaddr,
  * The implementation is complicated by a lack of address lines,
  * which prevents decoding of the low-order bit.
  * (code has just been moved in the above function)
- * We start by the end because it is the way it should be !
+ * We start at the end because it is the way it should be!
  */
 static inline void
 mmc_read(u_long                ioaddr,
@@ -400,7 +400,7 @@ mmc_read(u_long             ioaddr,
 
 /*------------------------------------------------------------------*/
 /*
- * Get the type of encryption available...
+ * Get the type of encryption available.
  */
 static inline int
 mmc_encr(u_long                ioaddr) /* i/o port of the card */
@@ -416,8 +416,8 @@ mmc_encr(u_long             ioaddr) /* i/o port of the card */
 
 /*------------------------------------------------------------------*/
 /*
- * Wait for the frequency EEprom to complete a command...
- * I hope this one will be optimally inlined...
+ * Wait for the frequency EEPROM to complete a command.
+ * I hope this one will be optimally inlined.
  */
 static inline void
 fee_wait(u_long                ioaddr, /* i/o port of the card */
@@ -433,7 +433,7 @@ fee_wait(u_long             ioaddr, /* i/o port of the card */
 
 /*------------------------------------------------------------------*/
 /*
- * Read bytes from the Frequency EEprom (frequency select cards).
+ * Read bytes from the Frequency EEPROM (frequency select cards).
  */
 static void
 fee_read(u_long                ioaddr, /* i/o port of the card */
@@ -452,21 +452,21 @@ fee_read(u_long           ioaddr, /* i/o port of the card */
       /* Write the read command */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);
 
-      /* Wait until EEprom is ready (should be quick !) */
+      /* Wait until EEPROM is ready (should be quick). */
       fee_wait(ioaddr, 10, 100);
 
-      /* Read the value */
+      /* Read the value. */
       *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) |
              mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
     }
 }
 
-#ifdef WIRELESS_EXT    /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT    /* if the wireless extension exists in the kernel */
 
 /*------------------------------------------------------------------*/
 /*
- * Write bytes from the Frequency EEprom (frequency select cards).
- * This is a bit complicated, because the frequency eeprom has to
+ * Write bytes from the Frequency EEPROM (frequency select cards).
+ * This is a bit complicated, because the frequency EEPROM has to
  * be unprotected and the write enabled.
  * Jean II
  */
@@ -476,7 +476,7 @@ fee_write(u_long    ioaddr, /* i/o port of the card */
          u_short *     b,      /* data buffer */
          int           n)      /* number of registers */
 {
-  b += n;              /* Position at the end of the area */
+  b += n;              /* Position at the end of the area. */
 
 #ifdef EEPROM_IS_PROTECTED     /* disabled */
 #ifdef DOESNT_SEEM_TO_WORK     /* disabled */
@@ -485,19 +485,19 @@ fee_write(u_long  ioaddr, /* i/o port of the card */
 
   fee_wait(ioaddr, 10, 100);
 
-  /* Read the protected register */
+  /* Read the protected register. */
   printk("Protected 2 : %02X-%02X\n",
         mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
         mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
 #endif /* DOESNT_SEEM_TO_WORK */
 
-  /* Enable protected register */
+  /* Enable protected register. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
 
   fee_wait(ioaddr, 10, 100);
 
-  /* Unprotect area */
+  /* Unprotect area. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
 #ifdef DOESNT_SEEM_TO_WORK     /* disabled */
@@ -508,38 +508,38 @@ fee_write(u_long  ioaddr, /* i/o port of the card */
   fee_wait(ioaddr, 10, 100);
 #endif /* EEPROM_IS_PROTECTED */
 
-  /* Write enable */
+  /* Write enable. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
 
   fee_wait(ioaddr, 10, 100);
 
-  /* Write the EEprom address */
+  /* Write the EEPROM address. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
 
   /* Loop on all buffer */
   while(n-- > 0)
     {
-      /* Write the value */
+      /* Write the value. */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
       mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
 
-      /* Write the write command */
+      /* Write the write command. */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE);
 
-      /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */
+      /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */
       mdelay(10);
       fee_wait(ioaddr, 10, 100);
     }
 
-  /* Write disable */
+  /* Write disable. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
 
   fee_wait(ioaddr, 10, 100);
 
 #ifdef EEPROM_IS_PROTECTED     /* disabled */
-  /* Reprotect EEprom */
+  /* Reprotect EEPROM. */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
 
@@ -550,13 +550,13 @@ fee_write(u_long  ioaddr, /* i/o port of the card */
 
 /************************ I82586 SUBROUTINES *************************/
 /*
- * Usefull subroutines to manage the Ethernet controler
+ * Useful subroutines to manage the Ethernet controller
  */
 
 /*------------------------------------------------------------------*/
 /*
  * Read bytes from the on-board RAM.
- * Why inlining this function make it fail ???
+ * Why does inlining this function make it fail?
  */
 static /*inline*/ void
 obram_read(u_long      ioaddr,
@@ -584,7 +584,7 @@ obram_write(u_long  ioaddr,
 
 /*------------------------------------------------------------------*/
 /*
- * Acknowledge the reading of the status issued by the i82586
+ * Acknowledge the reading of the status issued by the i82586.
  */
 static void
 wv_ack(device *                dev)
@@ -626,7 +626,7 @@ wv_ack(device *             dev)
 /*------------------------------------------------------------------*/
 /*
  * Set channel attention bit and busy wait until command has
- * completed, then acknowledge the command completion.
+ * completed, then acknowledge completion of the command.
  */
 static inline int
 wv_synchronous_cmd(device *    dev,
@@ -675,7 +675,7 @@ wv_synchronous_cmd(device * dev,
 /*------------------------------------------------------------------*/
 /*
  * Configuration commands completion interrupt.
- * Check if done, and if ok...
+ * Check if done, and if OK.
  */
 static inline int
 wv_config_complete(device *    dev,
@@ -693,7 +693,7 @@ wv_config_complete(device * dev,
   mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t)
     + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t);
 
-  /* Read the status of the last command (set mc list) */
+  /* Read the status of the last command (set mc list). */
   obram_read(ioaddr, acoff(mcs_addr, ac_status), (unsigned char *)&status, sizeof(status));
 
   /* If not completed -> exit */
@@ -717,7 +717,7 @@ wv_config_complete(device * dev,
        printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n",
               dev->name, str, status);
 
-      /* Check config command */
+      /* Check config command. */
       cfg_addr = ias_addr - sizeof(ac_cfg_t);
       obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status));
       if(status & AC_SFLD_OK != 0)
@@ -776,7 +776,7 @@ if (lp->tx_n_in_use > 0)
        printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
 */
 
-      /* Was it the last one ? */
+      /* Was it the last one? */
       if(lp->tx_n_in_use <= 0)
        lp->tx_first_in_use = I82586NULL;
       else
@@ -882,12 +882,12 @@ if (lp->tx_n_in_use > 0)
 
 /*------------------------------------------------------------------*/
 /*
- * Reconfigure the i82586, or at least ask for it...
- * Because wv_82586_config use a transmission buffer, we must do it
+ * Reconfigure the i82586, or at least ask for it.
+ * Because wv_82586_config uses a transmission buffer, we must do it
  * when we are sure that there is one left, so we do it now
  * or in wavelan_packet_xmit() (I can't find any better place,
- * wavelan_interrupt is not an option...), so you may experience
- * some delay sometime...
+ * wavelan_interrupt is not an option), so you may experience
+ * delays sometimes.
  */
 static inline void
 wv_82586_reconfig(device *     dev)
@@ -909,8 +909,8 @@ wv_82586_reconfig(device *  dev)
 
 /********************* DEBUG & INFO SUBROUTINES *********************/
 /*
- * This routines are used in the code to show debug informations.
- * Most of the time, it dump the content of hardware structures...
+ * This routine is used in the code to show information for debugging.
+ * Most of the time, it dumps the contents of hardware structures.
  */
 
 #ifdef DEBUG_PSA_SHOW
@@ -921,7 +921,7 @@ wv_82586_reconfig(device *  dev)
 static void
 wv_psa_show(psa_t *    p)
 {
-  printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN psa contents: #####\n");
   printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
         p->psa_io_base_addr_1,
         p->psa_io_base_addr_2,
@@ -1006,7 +1006,7 @@ wv_psa_show(psa_t *       p)
 /*------------------------------------------------------------------*/
 /*
  * Print the formatted status of the Modem Management Controller.
- * This function need to be completed...
+ * This function needs to be completed.
  */
 static void
 wv_mmc_show(device *   dev)
@@ -1028,12 +1028,12 @@ wv_mmc_show(device *    dev)
   mmc_read(ioaddr, 0, (u_char *)&m, sizeof(m));
   mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
 
-#ifdef WIRELESS_EXT    /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT    /* if wireless extension exists in the kernel */
   /* Don't forget to update statistics */
   lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
 #endif /* WIRELESS_EXT */
 
-  printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
 #ifdef DEBUG_SHOW_UNUSED
   printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
         m.mmr_unused0[0],
@@ -1045,7 +1045,7 @@ wv_mmc_show(device *      dev)
         m.mmr_unused0[6],
         m.mmr_unused0[7]);
 #endif /* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n",
+  printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
         m.mmr_des_avail, m.mmr_des_status);
 #ifdef DEBUG_SHOW_UNUSED
   printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
@@ -1093,7 +1093,7 @@ wv_mmc_show(device *      dev)
 #ifdef DEBUG_I82586_SHOW
 /*------------------------------------------------------------------*/
 /*
- * Print the last block of the i82586 memory
+ * Print the last block of the i82586 memory.
  */
 static void
 wv_scb_show(u_long     ioaddr)
@@ -1102,7 +1102,7 @@ wv_scb_show(u_long        ioaddr)
 
   obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));   
 
-  printk(KERN_DEBUG "##### wavelan system control block: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN system control block: #####\n");
 
   printk(KERN_DEBUG "status: ");
   printk("stat 0x%x[%s%s%s%s] ",
@@ -1163,7 +1163,7 @@ wv_ru_show(device *       dev)
 {
   /* net_local *lp = (net_local *) dev->priv; */
 
-  printk(KERN_DEBUG "##### wavelan i82586 receiver unit status: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n");
   printk(KERN_DEBUG "ru:");
   /*
    * Not implemented yet...
@@ -1173,7 +1173,7 @@ wv_ru_show(device *       dev)
 
 /*------------------------------------------------------------------*/
 /*
- * Display info about one control block of the i82586 memory
+ * Display info about one control block of the i82586 memory.
  */
 static void
 wv_cu_show_one(device *                dev,
@@ -1206,7 +1206,7 @@ wv_cu_show_one(device *           dev,
 
 /*------------------------------------------------------------------*/
 /*
- * Print status of the command unit of the i82586
+ * Print status of the command unit of the i82586.
  */
 static void
 wv_cu_show(device *    dev)
@@ -1215,7 +1215,7 @@ wv_cu_show(device *       dev)
   unsigned int i;
   u_short      p;
 
-  printk(KERN_DEBUG "##### wavelan i82586 command unit status: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN i82586 command unit status: #####\n");
 
   printk(KERN_DEBUG);
   for(i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++)
@@ -1310,8 +1310,8 @@ wv_packet_info(u_char *           p,              /* Packet to dump */
 
 /*------------------------------------------------------------------*/
 /*
- * This is the information which is displayed by the driver at startup
- * There  is a lot of flag to configure it at your will...
+ * This is the information which is displayed by the driver at startup.
+ * There are lots of flags for configuring it to your liking.
  */
 static inline void
 wv_init_info(device *  dev)
@@ -1341,7 +1341,7 @@ wv_init_info(device *     dev)
     printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
   printk(", IRQ %d", dev->irq);
 
-  /* Print current network id */
+  /* Print current network ID. */
   if(psa.psa_nwid_select)
     printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]);
   else
@@ -1353,14 +1353,14 @@ wv_init_info(device *   dev)
     {
       unsigned short   freq;
 
-      /* Ask the EEprom to read the frequency from the first area */
+      /* Ask the EEPROM to read the frequency from the first area */
       fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
               &freq, 1);
 
       /* Print frequency */
       printk(", 2.00, %ld", (freq >> 6) + 2400L);
 
-      /* Hack !!! */
+      /* Hack! */
       if(freq & 0x20)
        printk(".5");
     }
@@ -1381,7 +1381,7 @@ wv_init_info(device *     dev)
          printk("MCIA");
          break;
        default:
-         printk("???");
+         printk("?");
        }
       printk(", ");
       switch (psa.psa_subband)
@@ -1402,7 +1402,7 @@ wv_init_info(device *     dev)
          printk("2430.5");
          break;
        default:
-         printk("???");
+         printk("?");
        }
     }
 
@@ -1417,7 +1417,7 @@ wv_init_info(device *     dev)
 
 /********************* IOCTL, STATS & RECONFIG *********************/
 /*
- * We found here routines that are called by Linux on differents
+ * We found here routines that are called by Linux on different
  * occasions after the configuration and not for transmitting data
  * These may be called when the user use ifconfig, /proc/net/dev
  * or wireless extensions
@@ -1425,7 +1425,7 @@ wv_init_info(device *     dev)
 
 /*------------------------------------------------------------------*/
 /*
- * Get the current ethernet statistics. This may be called with the
+ * Get the current Ethernet statistics. This may be called with the
  * card open or closed.
  * Used when the user read /proc/net/dev
  */
@@ -1461,9 +1461,9 @@ wavelan_set_multicast_list(device *       dev)
         dev->name, dev->flags, dev->mc_count);
 #endif
 
-  /* If we ask for promiscuous mode,
-   * or all multicast addresses (we don't have that !)
-   * or too much multicast addresses for the hardware filter */
+  /* Are we asking for promiscuous mode,
+   * or all multicast addresses (we don't have that!)
+   * or too many multicast addresses for the hardware filter? */
   if((dev->flags & IFF_PROMISC) ||
      (dev->flags & IFF_ALLMULTI) ||
      (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES))
@@ -1478,12 +1478,12 @@ wavelan_set_multicast_list(device *     dev)
 
          wv_82586_reconfig(dev);
 
-         /* Tell the kernel that we are doing a really bad job... */
+         /* Tell the kernel that we are doing a really bad job. */
          dev->flags |= IFF_PROMISC;
        }
     }
   else
-    /* If there is some multicast addresses to send */
+    /* Are there multicast addresses to send? */
     if(dev->mc_list != (struct dev_mc_list *) NULL)
       {
        /*
@@ -1522,7 +1522,7 @@ wavelan_set_multicast_list(device *       dev)
 
 /*------------------------------------------------------------------*/
 /*
- * This function doesn't exist...
+ * This function doesn't exist.
  */
 static int
 wavelan_set_mac_address(device *       dev,
@@ -1530,16 +1530,16 @@ wavelan_set_mac_address(device *        dev,
 {
   struct sockaddr *    mac = addr;
 
-  /* Copy the address */
+  /* Copy the address. */
   memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
 
-  /* Reconfig the beast */
+  /* Reconfigure the beast. */
   wv_82586_reconfig(dev);
 
   return 0;
 }
 
-#ifdef WIRELESS_EXT    /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT    /* if wireless extension exists in the kernel */
 
 /*------------------------------------------------------------------*/
 /*
@@ -1558,10 +1558,10 @@ wv_set_frequency(u_long         ioaddr, /* i/o port of the card */
 #endif
 
   /* Setting by frequency */
-  /* Theoritically, you may set any frequency between
+  /* Theoretically, you may set any frequency between
    * the two limits with a 0.5 MHz precision. In practice,
    * I don't want you to have trouble with local
-   * regulations... */
+   * regulations. */
   if((frequency->e == 1) &&
      (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
     {
@@ -1569,29 +1569,29 @@ wv_set_frequency(u_long         ioaddr, /* i/o port of the card */
     }
 
   /* Setting by channel (same as wfreqsel) */
-  /* Warning : each channel is 22MHz wide, so some of the channels
-   * will interfere... */
+  /* Warning: each channel is 22 MHz wide, so some of the channels
+   * will interfere. */
   if((frequency->e == 0) &&
      (frequency->m >= 0) && (frequency->m < BAND_NUM))
     {
-      /* frequency in 1/4 of MHz (as read in the offset register) */
+      /* frequency in units of 250 kHz (as read in the offset register) */
       short    bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, 0xD0, 0xF0, 0xF8, 0x150 };
 
-      /* Get frequency offset */
+      /* Get frequency offset. */
       freq = bands[frequency->m] >> 1;
     }
 
-  /* Verify if the frequency is allowed */
+  /* Verify that the frequency is allowed. */
   if(freq != 0L)
     {
       u_short  table[10];      /* Authorized frequency table */
 
-      /* Read the frequency table */
+      /* Read the frequency table. */
       fee_read(ioaddr, 0x71 /* frequency table */,
               table, 10);
 
 #ifdef DEBUG_IOCTL_INFO
-      printk(KERN_DEBUG "Frequency table :");
+      printk(KERN_DEBUG "Frequency table");
       for(i = 0; i < 10; i++)
        {
          printk(" %04X",
@@ -1600,7 +1600,7 @@ wv_set_frequency(u_long           ioaddr, /* i/o port of the card */
       printk("\n");
 #endif
 
-      /* Look in the table if the frequency is allowed */
+      /* Look in the table to see whether the frequency is allowed. */
       if(!(table[9 - ((freq - 24) / 16)] &
           (1 << ((freq - 24) % 16))))
        return -EINVAL;         /* not allowed */
@@ -1608,7 +1608,7 @@ wv_set_frequency(u_long           ioaddr, /* i/o port of the card */
   else
     return -EINVAL;
 
-  /* If we get a usable frequency */
+  /* if we get a usable frequency */
   if(freq != 0L)
     {
       unsigned short   area[16];
@@ -1616,7 +1616,7 @@ wv_set_frequency(u_long           ioaddr, /* i/o port of the card */
       unsigned short   area_verify[16];
       unsigned short   dac_verify[2];
       /* Corresponding gain (in the power adjust value table)
-       * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8
+       * see AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
        * & WCIN062D.DOC, page 6.2.9 */
       unsigned short   power_limit[] = { 40, 80, 120, 160, 0 };
       int              power_band = 0;         /* Selected band */
@@ -1628,15 +1628,15 @@ wv_set_frequency(u_long         ioaddr, /* i/o port of the card */
            (power_limit[++power_band] != 0))
        ;
 
-      /* Read the first area */
+      /* Read the first area. */
       fee_read(ioaddr, 0x00,
               area, 16);
 
-      /* Read the DAC */
+      /* Read the DAC. */
       fee_read(ioaddr, 0x60,
               dac, 2);
 
-      /* Read the new power adjust value */
+      /* Read the new power adjust value. */
       fee_read(ioaddr, 0x6B - (power_band >> 1),
               &power_adjust, 1);
       if(power_band & 0x1)
@@ -1645,7 +1645,7 @@ wv_set_frequency(u_long           ioaddr, /* i/o port of the card */
        power_adjust &= 0xFF;
 
 #ifdef DEBUG_IOCTL_INFO
-      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+      printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
       for(i = 0; i < 16; i++)
        {
          printk(" %04X",
@@ -1653,11 +1653,11 @@ wv_set_frequency(u_long         ioaddr, /* i/o port of the card */
        }
       printk("\n");
 
-      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+      printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
             dac[0], dac[1]);
 #endif
 
-      /* Frequency offset (for info only...) */
+      /* Frequency offset (for info only) */
       area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
 
       /* Receiver Principle main divider coefficient */
@@ -1668,43 +1668,43 @@ wv_set_frequency(u_long         ioaddr, /* i/o port of the card */
       area[13] = (freq >> 1) + 2400L;
       area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
 
-      /* Others part of the area are flags, bit streams or unused... */
+      /* Other parts of the area are flags, bit streams or unused. */
 
-      /* Set the value in the DAC */
+      /* Set the value in the DAC. */
       dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
       dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
 
-      /* Write the first area */
+      /* Write the first area. */
       fee_write(ioaddr, 0x00,
                area, 16);
 
-      /* Write the DAC */
+      /* Write the DAC. */
       fee_write(ioaddr, 0x60,
                dac, 2);
 
-      /* We now should verify here that the EEprom writting was ok */
+      /* We now should verify here that the writing of the EEPROM was OK. */
 
-      /* ReRead the first area */
+      /* Reread the first area. */
       fee_read(ioaddr, 0x00,
               area_verify, 16);
 
-      /* ReRead the DAC */
+      /* Reread the DAC. */
       fee_read(ioaddr, 0x60,
               dac_verify, 2);
 
-      /* Compare */
+      /* Compare. */
       if(memcmp(area, area_verify, 16 * 2) ||
         memcmp(dac, dac_verify, 2 * 2))
        {
 #ifdef DEBUG_IOCTL_ERROR
-         printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
+         printk(KERN_INFO "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");
 #endif
          return -EOPNOTSUPP;
        }
 
       /* We must download the frequency parameters to the
-       * synthetisers (from the EEprom - area 1)
-       * Note : as the EEprom is auto decremented, we set the end
+       * synthesizers (from the EEPROM - area 1)
+       * Note: as the EEPROM is automatically decremented, we set the end
        * if the area... */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F);
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
@@ -1714,7 +1714,7 @@ wv_set_frequency(u_long           ioaddr, /* i/o port of the card */
       fee_wait(ioaddr, 100, 100);
 
       /* We must now download the power adjust value (gain) to
-       * the synthetisers (from the EEprom - area 7 - DAC) */
+       * the synthesizers (from the EEPROM - area 7 - DAC) */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
              MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
@@ -1723,9 +1723,9 @@ wv_set_frequency(u_long           ioaddr, /* i/o port of the card */
       fee_wait(ioaddr, 100, 100);
 
 #ifdef DEBUG_IOCTL_INFO
-      /* Verification of what we have done... */
+      /* Verification of what we have done */
 
-      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+      printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
       for(i = 0; i < 16; i++)
        {
          printk(" %04X",
@@ -1733,7 +1733,7 @@ wv_set_frequency(u_long           ioaddr, /* i/o port of the card */
        }
       printk("\n");
 
-      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+      printk(KERN_DEBUG "WaveLAN EEPROM DAC:  %04X %04X\n",
             dac_verify[0], dac_verify[1]);
 #endif
 
@@ -1760,7 +1760,7 @@ wv_frequency_list(u_long  ioaddr, /* i/o port of the card */
   fee_read(ioaddr, 0x71 /* frequency table */,
           table, 10);
 
-  /* Look all frequencies */
+  /* Check all frequencies */
   i = 0;
   for(freq = 0; freq < 150; freq++)
     /* Look in the table if the frequency is allowed */
@@ -1770,7 +1770,7 @@ wv_frequency_list(u_long  ioaddr, /* i/o port of the card */
        list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
        list[i++].e = 1;
 
-       /* Check number */
+       /* Check number. */
        if(i >= max)
          return(i);
       }
@@ -1781,9 +1781,9 @@ wv_frequency_list(u_long  ioaddr, /* i/o port of the card */
 #ifdef WIRELESS_SPY
 /*------------------------------------------------------------------*/
 /*
- * Gather wireless spy statistics : for each packet, compare the source
- * address with out list, and if match, get the stats...
- * Sorry, but this function really need wireless extensions...
+ * Gather wireless spy statistics for each packet, compare the source
+ * address with our list, and if they match, get the statistics.
+ * Sorry, but this function really needs the wireless extensions.
  */
 static inline void
 wl_spy_gather(device * dev,
@@ -1793,7 +1793,7 @@ wl_spy_gather(device *    dev,
   net_local *  lp = (net_local *) dev->priv;
   int          i;
 
-  /* Look all addresses */
+  /* Check all addresses. */
   for(i = 0; i < lp->spy_number; i++)
     /* If match */
     if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
@@ -1810,12 +1810,12 @@ wl_spy_gather(device *  dev,
 #ifdef HISTOGRAM
 /*------------------------------------------------------------------*/
 /*
- * This function calculate an histogram on the signal level.
+ * This function calculates a histogram of the signal level.
  * As the noise is quite constant, it's like doing it on the SNR.
  * We have defined a set of interval (lp->his_range), and each time
  * the level goes in that interval, we increment the count (lp->his_sum).
- * With this histogram you may detect if one wavelan is really weak,
- * or you may also calculate the mean and standard deviation of the level...
+ * With this histogram you may detect if one WaveLAN is really weak,
+ * or you may also calculate the mean and standard deviation of the level.
  */
 static inline void
 wl_his_gather(device * dev,
@@ -1825,25 +1825,25 @@ wl_his_gather(device *  dev,
   u_char       level = stats[0] & MMR_SIGNAL_LVL;
   int          i;
 
-  /* Find the correct interval */
+  /* Find the correct interval. */
   i = 0;
   while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++]))
     ;
 
-  /* Increment interval counter */
+  /* Increment interval counter. */
   (lp->his_sum[i])++;
 }
 #endif /* HISTOGRAM */
 
 /*------------------------------------------------------------------*/
 /*
- * Perform ioctl : config & info stuff
+ * Perform ioctl:  configuration and information
  * This is here that are treated the wireless extensions (iwconfig)
  */
 static int
-wavelan_ioctl(struct device *  dev,    /* Device on wich the ioctl apply */
-             struct ifreq *    rq,     /* Data passed */
-             int               cmd)    /* Ioctl number */
+wavelan_ioctl(struct device *  dev,    /* device on which the ioctl is applied */
+             struct ifreq *    rq,     /* data passed */
+             int               cmd)    /* ioctl number */
 {
   u_long               ioaddr = dev->base_addr;
   net_local *          lp = (net_local *)dev->priv;    /* lp is not unused */
@@ -1870,7 +1870,7 @@ wavelan_ioctl(struct device *     dev,    /* Device on wich the ioctl apply */
       break;
 
     case SIOCSIWNWID:
-      /* Set NWID in wavelan */
+      /* Set NWID in WaveLAN. */
       if(wrq->u.nwid.on)
        {
          /* Set NWID in psa */
@@ -1889,19 +1889,19 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
        }
       else
        {
-         /* Disable nwid in the psa */
+         /* Disable NWID in the psa. */
          psa.psa_nwid_select = 0x00;
          psa_write(ioaddr, lp->hacr,
                    (char *)&psa.psa_nwid_select - (char *)&psa,
                    (unsigned char *)&psa.psa_nwid_select, 1);
 
-         /* Disable nwid in the mmc (no filtering) */
+         /* Disable NWID in the mmc (no filtering). */
          mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
        }
       break;
 
     case SIOCGIWNWID:
-      /* Read the NWID */
+      /* Read the NWID. */
       psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
               (unsigned char *)psa.psa_nwid, 3);
       wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
@@ -1909,7 +1909,7 @@ wavelan_ioctl(struct device *     dev,    /* Device on wich the ioctl apply */
       break;
 
     case SIOCSIWFREQ:
-      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
       if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
           (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
        ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
@@ -1918,14 +1918,14 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
       break;
 
     case SIOCGIWFREQ:
-      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-       * (does it work for everybody ??? - especially old cards...) */
+      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
+       * Does it work for everybody, especially old cards? */
       if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
           (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
        {
          unsigned short        freq;
 
-         /* Ask the EEprom to read the frequency from the first area */
+         /* Ask the EEPROM to read the frequency from the first area */
          fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
                   &freq, 1);
          wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
@@ -1949,7 +1949,7 @@ wavelan_ioctl(struct device *     dev,    /* Device on wich the ioctl apply */
       break;
 
     case SIOCSIWSENS:
-      /* Set the level threshold */
+      /* Set the level threshold. */
       if(!suser())
        return -EPERM;
       psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
@@ -1959,14 +1959,14 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
       break;
 
     case SIOCGIWSENS:
-      /* Read the level threshold */
+      /* Read the level threshold. */
       psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
               (unsigned char *) &psa.psa_thr_pre_set, 1);
       wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
       break;
 
      case SIOCSIWENCODE:
-       /* Set encryption key */
+       /* Set encryption key. */
        if(!mmc_encr(ioaddr))
         {
           ret = -EOPNOTSUPP;
@@ -1974,7 +1974,7 @@ wavelan_ioctl(struct device *     dev,    /* Device on wich the ioctl apply */
         }
 
        if(wrq->u.encoding.method)
-        {      /* enable encryption */
+        {      /* Enable encryption. */
           int          i;
           long long    key = wrq->u.encoding.code;
 
@@ -1994,7 +1994,7 @@ wavelan_ioctl(struct device *     dev,    /* Device on wich the ioctl apply */
                     (unsigned char *) &psa.psa_encryption_key, 8);
         }
        else
-        {      /* disable encryption */
+        {      /* Disable encryption. */
           psa.psa_encryption_select = 0;
           psa_write(ioaddr, lp->hacr,
                     (char *) &psa.psa_encryption_select - (char *) &psa,
@@ -2005,14 +2005,14 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
        break;
 
      case SIOCGIWENCODE:
-       /* Read the encryption key */
+       /* Read the encryption key. */
        if(!mmc_encr(ioaddr))
         {
           ret = -EOPNOTSUPP;
           break;
         }
 
-       /* only super-user can see encryption key */
+       /* Only super-user can see encryption key. */
        if(!suser())
         {
           ret = -EPERM;
@@ -2042,26 +2042,26 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
        break;
 
     case SIOCGIWRANGE:
-      /* Basic checking... */
+      /* basic checking */
       if(wrq->u.data.pointer != (caddr_t) 0)
        {
          struct iw_range       range;
 
-         /* Verify the user buffer */
+         /* Verify the user buffer. */
          ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
                            sizeof(struct iw_range));
          if(ret)
            break;
 
-         /* Set the length (useless : its constant...) */
+         /* Set the length (useless:  it's constant). */
          wrq->u.data.length = sizeof(struct iw_range);
 
-         /* Set information in the range struct */
+         /* Set information in the range struct */
          range.throughput = 1.6 * 1024 * 1024; /* don't argue on this ! */
          range.min_nwid = 0x0000;
          range.max_nwid = 0xFFFF;
 
-         /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+         /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
          if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
               (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
            {
@@ -2077,14 +2077,14 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
          range.max_qual.level = MMR_SIGNAL_LVL;
          range.max_qual.noise = MMR_SILENCE_LVL;
 
-         /* Copy structure to the user buffer */
+         /* Copy structure to the user buffer. */
          copy_to_user(wrq->u.data.pointer, &range,
                       sizeof(struct iw_range));
        }
       break;
 
     case SIOCGIWPRIV:
-      /* Basic checking... */
+      /* Basic checking */
       if(wrq->u.data.pointer != (caddr_t) 0)
        {
          struct iw_priv_args   priv[] =
@@ -2102,10 +2102,10 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
          if(ret)
            break;
 
-         /* Set the number of ioctl available */
+         /* Set the number of available ioctls. */
          wrq->u.data.length = 4;
 
-         /* Copy structure to the user buffer */
+         /* Copy structure to the user buffer. */
          copy_to_user(wrq->u.data.pointer, (u_char *) priv,
                       sizeof(priv));
        }
@@ -2115,7 +2115,7 @@ wavelan_ioctl(struct device *     dev,    /* Device on wich the ioctl apply */
     case SIOCSIWSPY:
       /* Set the spy list */
 
-      /* Check the number of addresses */
+      /* Check the number of addresses. */
       if(wrq->u.data.length > IW_MAX_SPY)
        {
          ret = -E2BIG;
@@ -2123,33 +2123,33 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
        }
       lp->spy_number = wrq->u.data.length;
 
-      /* If there is some addresses to copy */
+      /* Are there are addresses to copy? */
       if(lp->spy_number > 0)
        {
          struct sockaddr       address[IW_MAX_SPY];
          int                   i;
 
-         /* Verify where the user has set his addresses */
+         /* Verify where the user has set his addresses. */
          ret = verify_area(VERIFY_READ, wrq->u.data.pointer,
                            sizeof(struct sockaddr) * lp->spy_number);
          if(ret)
            break;
-         /* Copy addresses to the driver */
+         /* Copy addresses to the driver. */
          copy_from_user(address, wrq->u.data.pointer,
                         sizeof(struct sockaddr) * lp->spy_number);
 
-         /* Copy addresses to the lp structure */
+         /* Copy addresses to the lp structure. */
          for(i = 0; i < lp->spy_number; i++)
            {
              memcpy(lp->spy_address[i], address[i].sa_data,
                     WAVELAN_ADDR_SIZE);
            }
 
-         /* Reset structure... */
+         /* Reset structure. */
          memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
 
 #ifdef DEBUG_IOCTL_INFO
-         printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
+         printk(KERN_DEBUG "SetSpy - Set of new addresses is\n");
          for(i = 0; i < wrq->u.data.length; i++)
            printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n",
                   lp->spy_address[i][0],
@@ -2164,25 +2164,25 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
       break;
 
     case SIOCGIWSPY:
-      /* Get the spy list and spy stats */
+      /* Get the spy list and spy stats. */
 
       /* Set the number of addresses */
       wrq->u.data.length = lp->spy_number;
 
-      /* If the user want to have the addresses back... */
+      /* Does the user want to have the addresses back? */
       if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
        {
          struct sockaddr       address[IW_MAX_SPY];
          int                   i;
 
-         /* Verify the user buffer */
+         /* Verify the user buffer. */
          ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
                            (sizeof(iw_qual) + sizeof(struct sockaddr))
                            * IW_MAX_SPY);
          if(ret)
            break;
 
-         /* Copy addresses from the lp structure */
+         /* Copy addresses from the lp structure. */
          for(i = 0; i < lp->spy_number; i++)
            {
              memcpy(address[i].sa_data, lp->spy_address[i],
@@ -2190,16 +2190,16 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
              address[i].sa_family = AF_UNIX;
            }
 
-         /* Copy addresses to the user buffer */
+         /* Copy addresses to the user buffer. */
          copy_to_user(wrq->u.data.pointer, address,
                       sizeof(struct sockaddr) * lp->spy_number);
 
-         /* Copy stats to the user buffer (just after) */
+         /* Copy stats to the user buffer (just after). */
          copy_to_user(wrq->u.data.pointer +
                       (sizeof(struct sockaddr) * lp->spy_number),
                       lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
 
-         /* Reset updated flags */
+         /* Reset updated flags. */
          for(i = 0; i < lp->spy_number; i++)
            lp->spy_stat[i].updated = 0x0;
        }       /* if(pointer != NULL) */
@@ -2230,7 +2230,7 @@ wavelan_ioctl(struct device *     dev,    /* Device on wich the ioctl apply */
       if(!suser())
        return -EPERM;
 
-      /* Check the number of intervals */
+      /* Check the number of intervals. */
       if(wrq->u.data.length > 16)
        {
          ret = -E2BIG;
@@ -2238,10 +2238,10 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
        }
       lp->his_number = wrq->u.data.length;
 
-      /* If there is some addresses to copy */
+      /* Are there addresses to copy? */
       if(lp->his_number > 0)
        {
-         /* Verify where the user has set his addresses */
+         /* Verify where the user has set his addresses. */
          ret = verify_area(VERIFY_READ, wrq->u.data.pointer,
                            sizeof(char) * lp->his_number);
          if(ret)
@@ -2250,25 +2250,25 @@ wavelan_ioctl(struct device *   dev,    /* Device on wich the ioctl apply */
          copy_from_user(lp->his_range, wrq->u.data.pointer,
                         sizeof(char) * lp->his_number);
 
-         /* Reset structure... */
+         /* Reset structure. */
          memset(lp->his_sum, 0x00, sizeof(long) * 16);
        }
       break;
 
     case SIOCGIPHISTO:
-      /* Set the number of intervals */
+      /* Set the number of intervals. */
       wrq->u.data.length = lp->his_number;
 
       /* Give back the distribution statistics */
       if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
        {
-         /* Verify the user buffer */
+         /* Verify the user buffer. */
          ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
                            sizeof(long) * 16);
          if(ret)
            break;
 
-         /* Copy data to the user buffer */
+         /* Copy data to the user buffer. */
          copy_to_user(wrq->u.data.pointer, lp->his_sum,
                       sizeof(long) * lp->his_number);
        }       /* if(pointer != NULL) */
@@ -2281,7 +2281,7 @@ wavelan_ioctl(struct device *     dev,    /* Device on wich the ioctl apply */
       ret = -EOPNOTSUPP;
     }
 
-  /* ReEnable interrupts & restore flags */
+  /* Enable interrupts and restore flags. */
   wv_splx(x);
 
 #ifdef DEBUG_IOCTL_TRACE
@@ -2292,8 +2292,8 @@ wavelan_ioctl(struct device *     dev,    /* Device on wich the ioctl apply */
 
 /*------------------------------------------------------------------*/
 /*
- * Get wireless statistics
- * Called by /proc/net/wireless...
+ * Get wireless statistics.
+ * Called by /proc/net/wireless
  */
 static iw_stats *
 wavelan_get_wireless_stats(device *    dev)
@@ -2308,14 +2308,14 @@ wavelan_get_wireless_stats(device *     dev)
   printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
 #endif
 
-  /* Disable interrupts & save flags */
+  /* Disable interrupts and save flags. */
   x = wv_splhi();
 
   if(lp == (net_local *) NULL)
     return (iw_stats *) NULL;
   wstats = &lp->wstats;
 
-  /* Get data from the mmc */
+  /* Get data from the mmc. */
   mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
 
   mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
@@ -2324,7 +2324,7 @@ wavelan_get_wireless_stats(device *       dev)
 
   mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
 
-  /* Copy data to wireless stuff */
+  /* Copy data to wireless stuff. */
   wstats->status = m.mmr_dce_status;
   wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
   wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
@@ -2336,7 +2336,7 @@ wavelan_get_wireless_stats(device *       dev)
   wstats->discard.code = 0L;
   wstats->discard.misc = 0L;
 
-  /* ReEnable interrupts & restore flags */
+  /* Enable interrupts and restore flags. */
   wv_splx(x);
 
 #ifdef DEBUG_IOCTL_TRACE
@@ -2348,22 +2348,22 @@ wavelan_get_wireless_stats(device *     dev)
 
 /************************* PACKET RECEPTION *************************/
 /*
- * This part deal with receiving the packets.
- * The interrupt handler get an interrupt when a packet has been
- * successfully received and called this part...
+ * This part deals with receiving the packets.
+ * The interrupt handler gets an interrupt when a packet has been
+ * successfully received and calls this part.
  */
 
 /*------------------------------------------------------------------*/
 /*
- * This routine does the actual copy of data (including the ethernet
+ * This routine does the actual copying of data (including the Ethernet
  * header structure) from the WaveLAN card to an sk_buff chain that
- * will be passed up to the network interface layer. NOTE: We
+ * will be passed up to the network interface layer. NOTE: we
  * currently don't handle trailer protocols (neither does the rest of
  * the network interface), so if that is needed, it will (at least in
  * part) be added here.  The contents of the receive ring buffer are
  * copied to a message chain that is then passed to the kernel.
  *
- * Note: if any errors occur, the packet is "dropped on the floor"
+ * Note: if any errors occur, the packet is "dropped on the floor".
  * (called by wv_packet_rcv())
  */
 static inline void
@@ -2393,7 +2393,7 @@ wv_packet_read(device *           dev,
 
   skb->dev = dev;
 
-  /* Copy the packet to the buffer */
+  /* Copy the packet to the buffer. */
   obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
   skb->protocol=eth_type_trans(skb, dev);
 
@@ -2401,7 +2401,7 @@ wv_packet_read(device *           dev,
   wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
 #endif /* DEBUG_RX_INFO */
 
-  /* Statistics gathering & stuff associated.
+  /* Statistics-gathering and associated stuff.
    * It seem a bit messy with all the define, but it's really simple... */
 #if defined(WIRELESS_SPY) || defined(HISTOGRAM)
   if(
@@ -2413,13 +2413,13 @@ wv_packet_read(device *         dev,
 #endif /* HISTOGRAM */
      0)
     {
-      u_char   stats[3];       /* Signal level, Noise level, Signal quality */
+      u_char   stats[3];       /* signal level, noise level, signal quality */
 
-      /* read signal level, silence level and signal quality bytes */
-      /* Note : in the Pcmcia hardware, these are part of the frame. It seem
+      /* Read signal level, silence level and signal quality bytes. */
+      /* Note: in the PCMCIA hardware, these are part of the frame. It seems
        * that for the ISA hardware, it's nowhere to be found in the frame,
-       * so I'm oblige to do this (it has side effect on /proc/net/wireless)
-       * Any idea ? */
+       * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
+       * Any ideas? */
       mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
       mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
       mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
@@ -2440,11 +2440,11 @@ wv_packet_read(device *         dev,
 #endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
 
   /*
-   * Hand the packet to the Network Module
+   * Hand the packet to the network module.
    */
   netif_rx(skb);
 
-  /* Keep stats up to date */
+  /* Keep statistics up to date */
   lp->stats.rx_packets++;
   lp->stats.rx_bytes += skb->len;
 
@@ -2470,7 +2470,7 @@ wv_receive(device *       dev)
   printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name);
 #endif
 
-  /* Loop on each received packet */
+  /* Loop on each received packet. */
   for(;;)
     {
       fd_t             fd;
@@ -2479,13 +2479,13 @@ wv_receive(device *     dev)
 
       obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd));
 
-      /* If the current frame is not complete, we have reach the end... */
+      /* If the current frame is not complete, we have reached the end. */
       if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
-       break;          /* This is how we exit the loop */
+       break;          /* This is how we exit the loop. */
 
       nreaped++;
 
-      /* Check if frame correctly received */
+      /* Check whether frame was correctly received. */
       if((fd.fd_status & (FD_STATUS_B | FD_STATUS_OK)) !=
         (FD_STATUS_B | FD_STATUS_OK))
        {
@@ -2508,7 +2508,7 @@ wv_receive(device *       dev)
 #endif
        }
 
-      /* Check is there was problems in the frame processing */
+      /* Were there problems in processing the frame?  Let's check. */
       if((fd.fd_status & (FD_STATUS_S6 | FD_STATUS_S7 | FD_STATUS_S8 |
                          FD_STATUS_S9 | FD_STATUS_S10 | FD_STATUS_S11))
         != 0)
@@ -2565,7 +2565,7 @@ wv_receive(device *       dev)
            }
        }
 
-      /* Check if frame contain a pointer to the data */
+      /* Does the frame contain a pointer to the data?  Let's check. */
       if(fd.fd_rbd_offset == I82586NULL)
 #ifdef DEBUG_RX_ERROR
        printk(KERN_INFO "%s: wv_receive(): frame has no data.\n", dev->name);
@@ -2618,7 +2618,7 @@ wv_receive(device *       dev)
 
 /*********************** PACKET TRANSMISSION ***********************/
 /*
- * This part deal with sending packet through the wavelan
+ * This part deals with sending packets through the WaveLAN.
  *
  */
 
@@ -2628,13 +2628,13 @@ wv_receive(device *     dev)
  * locations on the WaveLAN card and starts the card off on
  * the transmit.
  *
- * The principle :
- * Each block contains a transmit command, a nop command,
+ * The principle:
+ * Each block contains a transmit command, a NOP command,
  * a transmit block descriptor and a buffer.
  * The CU reads the transmit block which points to the tbd,
  * reads the tbd and the content of the buffer.
  * When it has finished with it, it goes to the next command
- * which in our case is the nop. The nop points on itself,
+ * which in our case is the NOP. The NOP points on itself,
  * so the CU stops here.
  * When we add the next block, we modify the previous nop
  * to make it point on the new tx command.
@@ -2665,13 +2665,13 @@ wv_packet_write(device *        dev,
   printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
 #endif
 
-  /* Check if we need some padding */
+  /* Do we need some padding? */
   if(clen < ETH_ZLEN)
     clen = ETH_ZLEN;
 
   x = wv_splhi();
 
-  /* Calculate addresses of next block and previous block */
+  /* Calculate addresses of next block and previous block. */
   txblock = lp->tx_first_free;
   txpred = txblock - TXBLOCKZ;
   if(txpred < OFFSET_CU)
@@ -2687,14 +2687,14 @@ if (lp->tx_n_in_use > 0)
 
   lp->tx_n_in_use++;
 
-  /* Calculate addresses of the differents part of the block */
+  /* Calculate addresses of the different parts of the block. */
   tx_addr = txblock;
   nop_addr = tx_addr + sizeof(tx);
   tbd_addr = nop_addr + sizeof(nop);
   buf_addr = tbd_addr + sizeof(tbd);
 
   /*
-   * Transmit command.
+   * Transmit command
    */
   tx.tx_h.ac_status = 0;
   obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
@@ -2702,7 +2702,7 @@ if (lp->tx_n_in_use > 0)
              sizeof(tx.tx_h.ac_status));
 
   /*
-   * NOP command.
+   * NOP command
    */
   nop.nop_h.ac_status = 0;
   obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
@@ -2714,7 +2714,7 @@ if (lp->tx_n_in_use > 0)
              sizeof(nop.nop_h.ac_link));
 
   /*
-   * Transmit buffer descriptor
+   * Transmit buffer descriptor
    */
   tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen);
   tbd.tbd_next_bd_offset = I82586NULL;
@@ -2723,7 +2723,7 @@ if (lp->tx_n_in_use > 0)
   obram_write(ioaddr, tbd_addr, (unsigned char *)&tbd, sizeof(tbd));
 
   /*
-   * Data.
+   * Data
    */
   obram_write(ioaddr, buf_addr, buf, clen);
 
@@ -2741,13 +2741,13 @@ if (lp->tx_n_in_use > 0)
              (unsigned char *) &nop.nop_h.ac_link,
              sizeof(nop.nop_h.ac_link));
 
-  /* Keep stats up to date */
+  /* Keep stats up to date. */
   lp->stats.tx_bytes += length;
 
   /* If watchdog not already active, activate it... */
   if(lp->watchdog.prev == (timer_list *) NULL)
     {
-      /* set timer to expire in WATCHDOG_JIFFIES */
+      /* Set timer to expire in WATCHDOG_JIFFIES. */
       lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
       add_timer(&lp->watchdog);
     }
@@ -2774,7 +2774,7 @@ if (lp->tx_n_in_use > 0)
  * This routine is called when we want to send a packet (NET3 callback)
  * In this routine, we check if the hardware is ready to accept
  * the packet. We also prevent reentrance. Then, we call the function
- * to send the packet...
+ * to send the packet.
  */
 static int
 wavelan_packet_xmit(struct sk_buff *   skb,
@@ -2788,9 +2788,9 @@ wavelan_packet_xmit(struct sk_buff *      skb,
 #endif
 
   /* This flag indicate that the hardware can't perform a transmission.
-   * Theoritically, NET3 check it before sending a packet to the driver,
-   * but in fact it never do that and pool continuously.
-   * As the watchdog will abort too long transmissions, we are quite safe...
+   * Theoretically, NET3 checks it before sending a packet to the driver,
+   * but in fact it never does that and pools continuously.
+   * As the watchdog will abort overly long transmissions, we are quite safe.
    */
   if(dev->tbusy)
     return 1;
@@ -2805,7 +2805,9 @@ wavelan_packet_xmit(struct sk_buff *      skb,
 #endif
   else
     {
-      /* If somebody has asked to reconfigure the controler, we can do it now */
+      /* If somebody has asked to reconfigure the controller, 
+       * we can do it now.
+       */
       if(lp->reconfig_82586)
        {
          wv_82586_config(dev);
@@ -2829,12 +2831,12 @@ wavelan_packet_xmit(struct sk_buff *    skb,
   return 0;
 }
 
-/********************** HARDWARE CONFIGURATION **********************/
+/*********************** HARDWARE CONFIGURATION ***********************/
 /*
- * This part do the real job of starting and configuring the hardware.
+ * This part does the real job of starting and configuring the hardware.
  */
 
-/*------------------------------------------------------------------*/
+/*--------------------------------------------------------------------*/
 /*
  * Routine to initialize the Modem Management Controller.
  * (called by wv_hw_reset())
@@ -2852,7 +2854,7 @@ wv_mmc_init(device *      dev)
   printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
 #endif
 
-  /* Read the parameter storage area */
+  /* Read the parameter storage area. */
   psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
 
 #ifdef USE_PSA_CONFIG
@@ -2864,11 +2866,11 @@ wv_mmc_init(device *    dev)
   /* Is the PSA is not configured */
   if(!configured)
     {
-      /* User will be able to configure NWID after (with iwconfig) */
+      /* User will be able to configure NWID later (with iwconfig). */
       psa.psa_nwid[0] = 0;
       psa.psa_nwid[1] = 0;
 
-      /* As NWID is not set : no NWID checking */
+      /* no NWID checking since NWID is not set */
       psa.psa_nwid_select = 0;
 
       /* Disable encryption */
@@ -2901,10 +2903,10 @@ wv_mmc_init(device *    dev)
 #endif
     }
 
-  /* Zero the mmc structure */
+  /* Zero the mmc structure. */
   memset(&m, 0x00, sizeof(m));
 
-  /* Copy PSA info to the mmc */
+  /* Copy PSA info to the mmc. */
   m.mmw_netw_id_l = psa.psa_nwid[1];
   m.mmw_netw_id_h = psa.psa_nwid[0];
   
@@ -2924,7 +2926,7 @@ wv_mmc_init(device *      dev)
   m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
   m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
 
-  /* Missing : encryption stuff... */
+  /* Encryption stuff is missing. */
 
   /*
    * Set default modem control parameters.
@@ -2942,58 +2944,58 @@ wv_mmc_init(device *    dev)
   m.mmw_decay_prm = 0;
   m.mmw_decay_updat_prm = 0;
 
-  /* Write all info to mmc */
+  /* Write all info to MMC. */
   mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m));
 
-  /* The following code start the modem of the 2.00 frequency
+  /* The following code starts the modem of the 2.00 frequency
    * selectable cards at power on. It's not strictly needed for the
-   * following boots...
+   * following boots.
    * The original patch was by Joe Finney for the PCMCIA driver, but
-   * I've cleaned it a bit and add documentation.
+   * I've cleaned it up a bit and added documentation.
    * Thanks to Loeke Brederveld from Lucent for the info.
    */
 
   /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * (does it work for everybody ??? - especially old cards...) */
-  /* Note : WFREQSEL verify that it is able to read from EEprom
-   * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
-   * is 0xA (Xilinx version) or 0xB (Ariadne version).
-   * My test is more crude but do work... */
+   * Does it work for everybody, especially old cards? */
+  /* Note: WFREQSEL verifies that it is able to read a sensible
+   * frequency from from EEPROM (address 0x00) and that
+   * MMR_FEE_STATUS_ID is 0xA (Xilinx version) or 0xB (Ariadne version).
+   * My test is more crude but does work. */
   if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
        (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
     {
       /* We must download the frequency parameters to the
-       * synthetisers (from the EEprom - area 1)
-       * Note : as the EEprom is auto decremented, we set the end
+       * synthesizers (from the EEPROM - area 1)
+       * Note: as the EEPROM is automatically decremented, we set the end
        * if the area... */
       m.mmw_fee_addr = 0x0F;
       m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
       mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
                (unsigned char *)&m.mmw_fee_ctrl, 2);
 
-      /* Wait until the download is finished */
+      /* Wait until the download is finished. */
       fee_wait(ioaddr, 100, 100);
 
 #ifdef DEBUG_CONFIG_INFO
-      /* The frequency was in the last word downloaded... */
+      /* The frequency was in the last word downloaded. */
       mmc_read(ioaddr, (char *)&m.mmw_fee_data_l - (char *)&m,
               (unsigned char *)&m.mmw_fee_data_l, 2);
 
-      /* Print some info for the user */
-      printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n",
+      /* Print some info for the user. */
+      printk(KERN_DEBUG "%s: WaveLAN 2.00 recognised (frequency select).  Current frequency = %ld\n",
             dev->name,
             ((m.mmw_fee_data_h << 4) |
              (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L);
 #endif
 
       /* We must now download the power adjust value (gain) to
-       * the synthetisers (from the EEprom - area 7 - DAC) */
+       * the synthesizers (from the EEPROM - area 7 - DAC). */
       m.mmw_fee_addr = 0x61;
       m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
       mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
                (unsigned char *)&m.mmw_fee_ctrl, 2);
 
-      /* Wait until the download is finished */
+      /* Wait until the download is finished. */
     }  /* if 2.00 card */
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3091,13 +3093,13 @@ wv_ru_start(device *    dev)
  * Start the command unit executing the NOP
  * self-loop of the first transmit block.
  *
- * Here, we create the list of send buffer used to transmit packets
+ * Here we create the list of send buffers used to transmit packets
  * between the PC and the command unit. For each buffer, we create a
  * buffer descriptor (pointing on the buffer), a transmit command
- * (pointing to the buffer descriptor) and a nop command.
- * The transmit command is linked to the nop, and the nop to itself.
- * When we will have finish to execute the transmit command, we will
- * then loop on the nop. By releasing the nop link to a new command,
+ * (pointing to the buffer descriptor) and a NOP command.
+ * The transmit command is linked to the NOP, and the NOP to itself.
+ * When we will have finished executing the transmit command, we will
+ * then loop on the NOP. By releasing the NOP link to a new command,
  * we may send another buffer.
  *
  * (called by wv_hw_reset())
@@ -3194,12 +3196,13 @@ wv_cu_start(device *    dev)
 
 /*------------------------------------------------------------------*/
 /*
- * This routine does a standard config of the WaveLAN controler (i82586).
+ * This routine does a standard configuration of the WaveLAN 
+ * controller (i82586).
  *
- * It initialise the scp, iscp and scb structure
- * The two first are only pointer to the next.
+ * It initialises the scp, iscp and scb structure
+ * The first two are just pointers to the next.
  * The last one is used for basic configuration and for basic
- * communication (interrupt status)
+ * communication (interrupt status).
  *
  * (called by wv_hw_reset())
  */
@@ -3240,7 +3243,7 @@ wv_82586_start(device *   dev)
   iscp.iscp_offset = OFFSET_SCB;
   obram_write(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp));
 
-  /* Our first command is to reset the i82586 */
+  /* Our first command is to reset the i82586. */
   memset(&scb, 0x00, sizeof(scb));
   scb.scb_command = SCB_CMD_RESET;
   scb.scb_cbl_offset = OFFSET_CU;
@@ -3249,7 +3252,7 @@ wv_82586_start(device *   dev)
 
   set_chan_attn(ioaddr, lp->hacr);
 
-  /* Wait for command to finish */
+  /* Wait for command to finish. */
   for(i = 1000; i > 0; i--)
     {
       obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, sizeof(iscp));
@@ -3269,7 +3272,7 @@ wv_82586_start(device *   dev)
       return -1;
     }
 
-  /* Check command completion */
+  /* Check command completion. */
   for(i = 15; i > 0; i--)
     {
       obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, sizeof(scb));
@@ -3291,7 +3294,7 @@ wv_82586_start(device *   dev)
 
   wv_ack(dev);
 
-  /* Set the action command header */
+  /* Set the action command header. */
   memset(&cb, 0x00, sizeof(cb));
   cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
   cb.ac_link = OFFSET_CU;
@@ -3322,14 +3325,15 @@ wv_82586_start(device * dev)
 
 /*------------------------------------------------------------------*/
 /*
- * This routine does a standard config of the WaveLAN controler (i82586).
+ * This routine does a standard configuration of the WaveLAN
+ * controller (i82586).
  *
  * This routine is a violent hack. We use the first free transmit block
  * to make our configuration. In the buffer area, we create the three
- * configure command (linked). We make the previous nop point to the
- * beggining of the buffer instead of the tx command. After, we go as
- * usual to the nop command...
- * Note that only the last command (mc_set) will generate an interrupt...
+ * configuration commands (linked). We make the previous NOP point to
+ * the beginning of the buffer instead of the tx command. After, we go
+ * as usual to the NOP command.
+ * Note that only the last command (mc_set) will generate an interrupt.
  *
  * (called by wv_hw_reset(), wv_82586_reconfig())
  */
@@ -3360,7 +3364,7 @@ wv_82586_config(device *  dev)
 
   x = wv_splhi();
 
-  /* Calculate addresses of next block and previous block */
+  /* Calculate addresses of next block and previous block. */
   txblock = lp->tx_first_free;
   txpred = txblock - TXBLOCKZ;
   if(txpred < OFFSET_CU)
@@ -3371,16 +3375,16 @@ wv_82586_config(device *        dev)
 
   lp->tx_n_in_use++;
 
-  /* Calculate addresses of the differents part of the block */
+  /* Calculate addresses of the different parts of the block. */
   tx_addr = txblock;
   nop_addr = tx_addr + sizeof(tx);
   tbd_addr = nop_addr + sizeof(nop);
-  cfg_addr = tbd_addr + sizeof(tbd_t); /* beggining of the buffer */
+  cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */
   ias_addr = cfg_addr + sizeof(cfg);
   mcs_addr = ias_addr + sizeof(ias);
 
   /*
-   * Transmit command.
+   * Transmit command
    */
   tx.tx_h.ac_status = 0xFFFF;  /* Fake completion value */
   obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
@@ -3388,7 +3392,7 @@ wv_82586_config(device *  dev)
              sizeof(tx.tx_h.ac_status));
 
   /*
-   * NOP command.
+   * NOP command
    */
   nop.nop_h.ac_status = 0;
   obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
@@ -3399,23 +3403,23 @@ wv_82586_config(device *        dev)
              (unsigned char *) &nop.nop_h.ac_link,
              sizeof(nop.nop_h.ac_link));
 
-  /* Create a configure action */
+  /* Create a configure action. */
   memset(&cfg, 0x00, sizeof(cfg));
 
 #if    0
   /*
-   * The default board configuration.
+   * The default board configuration
    */
   cfg.fifolim_bytecnt  = 0x080c;
   cfg.addrlen_mode     = 0x2600;
   cfg.linprio_interframe       = 0x7820;       /* IFS=120, ACS=2 */
   cfg.slot_time        = 0xf00c;       /* slottime=12    */
-  cfg.hardware         = 0x0008;       /* tx even w/o CD */
+  cfg.hardware         = 0x0008;       /* tx even without CD */
   cfg.min_frame_len    = 0x0040;
 #endif /* 0 */
 
   /*
-   * For Linux we invert AC_CFG_ALOC(..) so as to conform
+   * For Linux we invert AC_CFG_ALOC() so as to conform
    * to the way that net packets reach us from above.
    * (See also ac_tx_t.)
    */
@@ -3456,21 +3460,21 @@ wv_82586_config(device *        dev)
   cfg.cfg_h.ac_link = ias_addr;
   obram_write(ioaddr, cfg_addr, (unsigned char *)&cfg, sizeof(cfg));
 
-  /* Setup the MAC address */
+  /* Set up the MAC address */
   memset(&ias, 0x00, sizeof(ias));
   ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup);
   ias.ias_h.ac_link = mcs_addr;
   memcpy(&ias.ias_addr[0], (unsigned char *)&dev->dev_addr[0], sizeof(ias.ias_addr));
   obram_write(ioaddr, ias_addr, (unsigned char *)&ias, sizeof(ias));
 
-  /* Initialize adapter's ethernet multicast addresses */
+  /* Initialize adapter's Ethernet multicast addresses */
   memset(&mcs, 0x00, sizeof(mcs));
   mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup);
   mcs.mcs_h.ac_link = nop_addr;
   mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count;
   obram_write(ioaddr, mcs_addr, (unsigned char *)&mcs, sizeof(mcs));
 
-  /* If any address to set */
+  /* Any address to set? */
   if(lp->mc_count)
     {
       for(dmi=dev->mc_list; dmi; dmi=dmi->next)
@@ -3526,8 +3530,8 @@ wv_82586_config(device *  dev)
 
 /*------------------------------------------------------------------*/
 /*
- * This routine stop gracefully the WaveLAN controler (i82586).
- * (called by wavelan_close())
+ * This routine, called by wavelan_close(), gracefully stops the 
+ * WaveLAN controller (i82586).
  */
 static inline void
 wv_82586_stop(device * dev)
@@ -3540,7 +3544,7 @@ wv_82586_stop(device *    dev)
   printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name);
 #endif
 
-  /* Suspend both command unit and receive unit */
+  /* Suspend both command unit and receive unit. */
   scb_cmd = (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & SCB_CMD_RUC_SUS);
   obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
              (unsigned char *)&scb_cmd, sizeof(scb_cmd));
@@ -3556,7 +3560,7 @@ wv_82586_stop(device *    dev)
 
 /*------------------------------------------------------------------*/
 /*
- * Totally reset the wavelan and restart it.
+ * Totally reset the WaveLAN and restart it.
  * Performs the following actions:
  *     1. A power reset (reset DMA)
  *     2. Initialize the radio modem (using wv_mmc_init)
@@ -3575,11 +3579,11 @@ wv_hw_reset(device *    dev)
         (unsigned int)dev);
 #endif
 
-  /* If watchdog was activated, kill it ! */
+  /* If watchdog was activated, kill it! */
   if(lp->watchdog.prev != (timer_list *) NULL)
     del_timer(&lp->watchdog);
 
-  /* Increase the number of resets done */
+  /* Increase the number of resets done. */
   lp->nresets++;
 
   wv_hacr_reset(ioaddr);
@@ -3589,7 +3593,7 @@ wv_hw_reset(device *      dev)
      (wv_82586_start(dev) < 0))
     return -1;
 
-  /* Enable the card to send interrupts */
+  /* Enable the card to send interrupts. */
   wv_ints_on(dev);
 
   /* Start card functions */
@@ -3597,7 +3601,7 @@ wv_hw_reset(device *      dev)
      (wv_cu_start(dev) < 0))
     return -1;
 
-  /* Finish configuration */
+  /* Finish configuration. */
   wv_82586_config(dev);
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3608,8 +3612,8 @@ wv_hw_reset(device *      dev)
 
 /*------------------------------------------------------------------*/
 /*
- * Check if there is a wavelan at the specific base address.
- * As a side effect, it read the MAC address.
+ * Check if there is a WaveLAN at the specific base address.
+ * As a side effect, this reads the MAC address.
  * (called in wavelan_probe() and init_module())
  */
 static int
@@ -3618,22 +3622,22 @@ wv_check_ioaddr(u_long          ioaddr,
 {
   int          i;              /* Loop counter */
 
-  /* Check if the base address if available */
+  /* Check if the base address if available. */
   if(check_region(ioaddr, sizeof(ha_t)))
-    return  EADDRINUSE;                /* ioaddr already used... */
+    return  EADDRINUSE;                /* ioaddr already used */
 
   /* Reset host interface */
   wv_hacr_reset(ioaddr);
 
-  /* Read the MAC address from the parameter storage area */
+  /* Read the MAC address from the parameter storage area. */
   psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr),
           mac, 6);
 
   /*
-   * Check the first three octets of the addr for the manufacturer's code.
-   * Note: If you can't find your wavelan card, you've got a
-   * non-NCR/AT&T/Lucent ISA cards, see wavelan.p.h for detail on
-   * how to configure your card...
+   * Check the first three octets of the address for the manufacturer's code.
+   * Note: if this can't find your WaveLAN card, you've got a
+   * non-NCR/AT&T/Lucent ISA card.  See wavelan.p.h for detail on
+   * how to configure your card.
    */
   for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
     if((mac[0] == MAC_ADDRESSES[i][0]) &&
@@ -3642,7 +3646,7 @@ wv_check_ioaddr(u_long            ioaddr,
       return 0;
 
 #ifdef DEBUG_CONFIG_INFO
-  printk(KERN_WARNING "Wavelan (0x%3X) : Your MAC address might be : %02X:%02X:%02X...\n",
+  printk(KERN_WARNING "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n",
         ioaddr, mac[0], mac[1], mac[2]);
 #endif
     return ENODEV;
@@ -3675,7 +3679,7 @@ wavelan_interrupt(int                     irq,
   lp = (net_local *) dev->priv;
   ioaddr = dev->base_addr;
 
-  /* Prevent reentrance. What should we do here ? */
+  /* Prevent reentrance. What should we do here? */
 #ifdef DEBUG_INTERRUPT_ERROR
   if(dev->interrupt)
     printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n",
@@ -3708,7 +3712,7 @@ wavelan_interrupt(int                     irq,
       return;
     }
 
-  /* Read interrupt data */
+  /* Read interrupt data. */
   obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
             (unsigned char *) &status, sizeof(status));
 
@@ -3755,7 +3759,7 @@ wavelan_interrupt(int                     irq,
       wv_receive(dev);
     }
 
-  /* Check the state of the command unit */
+  /* Check the state of the command unit. */
   if(((status & SCB_ST_CNA) == SCB_ST_CNA) ||
      (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && dev->start))
     {
@@ -3766,7 +3770,7 @@ wavelan_interrupt(int                     irq,
       wv_hw_reset(dev);
     }
 
-  /* Check the state of the command unit */
+  /* Check the state of the command unit. */
   if(((status & SCB_ST_RNR) == SCB_ST_RNR) ||
      (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && dev->start))
     {
@@ -3786,14 +3790,14 @@ wavelan_interrupt(int                   irq,
 
 /*------------------------------------------------------------------*/
 /*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel.  If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, we set a timer in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we try to unlock the hardware.
  *
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the previous version of the ISA driver. I make it this
+ * Note: this watchdog doesn't work on the same principle as the
+ * watchdog in the previous version of the ISA driver. I made it this
  * way because the overhead of add_timer() and del_timer() is nothing
- * and that it avoid calling the watchdog, saving some CPU...
+ * and because it avoids calling the watchdog, saving some CPU.
  */
 static void
 wavelan_watchdog(u_long                a)
@@ -3860,7 +3864,7 @@ wavelan_watchdog(u_long           a)
       wv_hw_reset(dev);
     }
   else
-    /* Re-set watchodog for next transmission */
+    /* Reset watchdog for next transmission. */
     if(lp->tx_n_in_use > 0)
       {
        /* set timer to expire in WATCHDOG_JIFFIES */
@@ -3877,15 +3881,15 @@ wavelan_watchdog(u_long         a)
 
 /********************* CONFIGURATION CALLBACKS *********************/
 /*
- * Here are the functions called by the linux networking (NET3) for
- * initialization, configuration and deinstallations of the Wavelan
- * ISA Hardware.
+ * Here are the functions called by the Linux networking code (NET3)
+ * for initialization, configuration and deinstallations of the 
+ * WaveLAN ISA hardware.
  */
 
 /*------------------------------------------------------------------*/
 /*
  * Configure and start up the WaveLAN PCMCIA adaptor.
- * Called by NET3 when it "open" the device.
+ * Called by NET3 when it "opens" the device.
  */
 static int
 wavelan_open(device *  dev)
@@ -3901,7 +3905,7 @@ wavelan_open(device *     dev)
   if(dev->irq == 0)
     {
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wavelan_open(): no irq\n", dev->name);
+      printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name);
 #endif
       return -ENXIO;
     }
@@ -3909,7 +3913,7 @@ wavelan_open(device *     dev)
   if(request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0)
     {
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wavelan_open(): invalid irq\n", dev->name);
+      printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name);
 #endif
       return -EAGAIN;
     }
@@ -3941,8 +3945,8 @@ wavelan_open(device *     dev)
 
 /*------------------------------------------------------------------*/
 /*
- * Shutdown the WaveLAN ISA card.
- * Called by NET3 when it "close" the device.
+ * Shut down the WaveLAN ISA card.
+ * Called by NET3 when it "closes" the device.
  */
 static int
 wavelan_close(device * dev)
@@ -3954,14 +3958,14 @@ wavelan_close(device *  dev)
         (unsigned int) dev);
 #endif
 
-  /* Not do the job twice... */
+  /* Don't do the job twice. */
   if(dev->start == 0)
     return 0;
 
   dev->tbusy = 1;
   dev->start = 0;
 
-  /* If watchdog was activated, kill it ! */
+  /* If watchdog was activated, kill it! */
   if(lp->watchdog.prev != (timer_list *) NULL)
     del_timer(&lp->watchdog);
 
@@ -3982,9 +3986,9 @@ wavelan_close(device *    dev)
 
 /*------------------------------------------------------------------*/
 /*
- * Probe an i/o address, and if the wavelan is there configure the
+ * Probe an I/O address, and if the WaveLAN is there configure the
  * device structure
- * (called by wavelan_probe() & via init_module())
+ * (called by wavelan_probe() and via init_module()).
  */
 __initfunc(static int
 wavelan_config(device *        dev))
@@ -3999,7 +4003,7 @@ wavelan_config(device *   dev))
         (unsigned int)dev, ioaddr);
 #endif
 
-  /* Check irq arg on command line */
+  /* Check IRQ argument on command line. */
   if(dev->irq != 0)
     {
       irq_mask = wv_irq_to_psa(dev->irq);
@@ -4007,7 +4011,7 @@ wavelan_config(device *   dev))
       if(irq_mask == 0)
        {
 #ifdef DEBUG_CONFIG_ERROR
-         printk(KERN_WARNING "%s: wavelan_config(): invalid irq %d -- ignored.\n",
+         printk(KERN_WARNING "%s: wavelan_config(): invalid IRQ %d ignored.\n",
                 dev->name, dev->irq);
 #endif
          dev->irq = 0;
@@ -4015,7 +4019,7 @@ wavelan_config(device *   dev))
       else
        {
 #ifdef DEBUG_CONFIG_INFO
-         printk(KERN_DEBUG "%s: wavelan_config(): changing irq to %d\n",
+         printk(KERN_DEBUG "%s: wavelan_config(): changing IRQ to %d\n",
                 dev->name, dev->irq);
 #endif
          psa_write(ioaddr, HACR_DEFAULT,
@@ -4049,9 +4053,9 @@ wavelan_config(device *   dev))
   memset(dev->priv, 0x00, sizeof(net_local));
   lp = (net_local *)dev->priv;
 
-  /* Back link to the device structure */
+  /* Back link to the device structure. */
   lp->dev = dev;
-  /* Add the device at the beggining of the linked list */
+  /* Add the device at the beginning of the linked list. */
   lp->next = wavelan_list;
   wavelan_list = lp;
 
@@ -4064,7 +4068,7 @@ wavelan_config(device *   dev))
 
   /*
    * Fill in the fields of the device structure
-   * with ethernet-generic values.
+   * with generic Ethernet values.
    */
   ether_setup(dev);
 
@@ -4075,14 +4079,14 @@ wavelan_config(device * dev))
   dev->set_multicast_list = &wavelan_set_multicast_list;
   dev->set_mac_address = &wavelan_set_mac_address;
 
-#ifdef WIRELESS_EXT    /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT    /* if wireless extension exists in the kernel */
   dev->do_ioctl = wavelan_ioctl;
   dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
 
   dev->mtu = WAVELAN_MTU;
 
-  /* Display nice info */
+  /* Display nice information. */
   wv_init_info(dev);
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4093,18 +4097,17 @@ wavelan_config(device * dev))
 
 /*------------------------------------------------------------------*/
 /*
- * Check for a network adaptor of this type.
- * Return '0' iff one exists.
- * (There seem to be different interpretations of
+ * Check for a network adaptor of this type.  Return '0' iff one 
+ * exists.  There seem to be different interpretations of
  * the initial value of dev->base_addr.
- * We follow the example in drivers/net/ne.c.)
+ * We follow the example in drivers/net/ne.c.
  * (called in "Space.c")
  */
 __initfunc(int
 wavelan_probe(device * dev))
 {
   short                base_addr;
-  mac_addr     mac;            /* Mac address (check wavelan existence) */
+  mac_addr     mac;            /* MAC address (check existence of WaveLAN) */
   int          i;
   int          r;
 
@@ -4122,7 +4125,7 @@ wavelan_probe(device *    dev))
     }
 #endif /* STRUCT_CHECK */
 
-  /* Check the value of the command line parameter for base address */
+  /* Check the value of the command line parameter for base address. */
   base_addr = dev->base_addr;
 
   /* Don't probe at all. */
@@ -4138,10 +4141,10 @@ wavelan_probe(device *  dev))
   /* Check a single specified location. */
   if(base_addr > 0x100)
     {
-      /* Check if the is something at this base address */
+      /* Check if there is something at this base address */
       if((r = wv_check_ioaddr(base_addr, mac)) == 0)
        {
-         memcpy(dev->dev_addr, mac, 6);        /* Copy mac address */
+         memcpy(dev->dev_addr, mac, 6);        /* Copy MAC address. */
          r = wavelan_config(dev);
        }
 
@@ -4157,14 +4160,14 @@ wavelan_probe(device *  dev))
       return r;
     }
 
-  /* Scan all possible address of the wavelan hardware */
+  /* Scan all possible addresses of the WaveLAN hardware. */
   for(i = 0; i < NELS(iobase); i++)
     {
-      /* Check if the is something at this base address */
+      /* Check whether there is something at this base address. */
       if(wv_check_ioaddr(iobase[i], mac) == 0)
        {
-         dev->base_addr = iobase[i];           /* Copy base address */
-         memcpy(dev->dev_addr, mac, 6);        /* Copy mac address */
+         dev->base_addr = iobase[i];           /* Copy base address. */
+         memcpy(dev->dev_addr, mac, 6);        /* Copy MAC address. */
          if(wavelan_config(dev) == 0)
            {
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4175,7 +4178,7 @@ wavelan_probe(device *    dev))
        }
     }
 
-  /* We may have touch base_addr : another driver may not like it... */
+  /* We may have touched base_addr.  Another driver may not like it. */
   dev->base_addr = base_addr;
 
 #ifdef DEBUG_CONFIG_INFO
@@ -4188,19 +4191,19 @@ wavelan_probe(device *  dev))
 
 /****************************** MODULE ******************************/
 /*
- * Module entry point : insertion & removal
+ * Module entry point: insertion and removal
  */
 
 #ifdef MODULE
 /*------------------------------------------------------------------*/
 /*
- * Insertion of the module...
- * I'm now quite proud of the multi-device support...
+ * Insertion of the module
+ * I'm now quite proud of the multi-device support.
  */
 int
 init_module(void)
 {
-  mac_addr     mac;            /* Mac address (check wavelan existence) */
+  mac_addr     mac;            /* MAC address (check WaveLAN existence) */
   int          ret = 0;
   int          i;
 
@@ -4212,48 +4215,48 @@ init_module(void)
   if(io[0] == 0)
     {
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "wavelan init_module(): doing device probing (bad !)\n");
+      printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n");
       printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n");
 #endif
 
-      /* Copy the basic set of address to be probed */
+      /* Copy the basic set of address to be probed. */
       for(i = 0; i < NELS(iobase); i++)
        io[i] = iobase[i];
     }
 
 
-  /* Loop on all possible base addresses */
+  /* Loop on all possible base addresses. */
   i = -1;
   while((io[++i] != 0) && (i < NELS(io)))
     {
-      /* Check if the is something at this base address */
+      /* Check if there is something at this base address. */
       if(wv_check_ioaddr(io[i], mac) == 0)
        {
          device *      dev;
 
-         /* Create device and set basics args */
+         /* Create device and set basic arguments. */
          dev = kmalloc(sizeof(struct device), GFP_KERNEL);
          memset(dev, 0x00, sizeof(struct device));
          dev->name = name[i];
          dev->base_addr = io[i];
          dev->irq = irq[i];
          dev->init = &wavelan_config;
-         memcpy(dev->dev_addr, mac, 6);        /* Copy mac address */
+         memcpy(dev->dev_addr, mac, 6);        /* Copy MAC address. */
 
-         /* Try to create the device */
+         /* Try to create the device. */
          if(register_netdev(dev) != 0)
            {
-             /* DeAllocate everything */
-             /* Note : if dev->priv is mallocated, there is no way to fail */
+             /* Deallocate everything. */
+             /* Note: if dev->priv is mallocated, there is no way to fail. */
              kfree_s(dev, sizeof(struct device));
              ret = -EIO;
            }
-       }       /* If there is something at the address */
-    }          /* Loop on all addresses */
+       }       /* if there is something at the address */
+    }          /* Loop on all addresses. */
 
 #ifdef DEBUG_CONFIG_ERRORS
   if(wavelan_list == (net_local *) NULL)
-    printk(KERN_WARNING "wavelan init_module(): No device found\n");
+    printk(KERN_WARNING "WaveLAN init_module(): no device found\n");
 #endif
 
 #ifdef DEBUG_MODULE_TRACE
@@ -4273,7 +4276,7 @@ cleanup_module(void)
   printk(KERN_DEBUG "-> cleanup_module()\n");
 #endif
 
-  /* Loop on all devices and release them */
+  /* Loop on all devices and release them. */
   while(wavelan_list != (net_local *) NULL)
     {
       device * dev = wavelan_list->dev;
@@ -4283,16 +4286,16 @@ cleanup_module(void)
             dev->name, (unsigned int) dev);
 #endif
 
-      /* Release the ioport-region. */
+      /* Release the ioport region. */
       release_region(dev->base_addr, sizeof(ha_t));
 
-      /* Remove definitely the device */
+      /* Definitely remove the device. */
       unregister_netdev(dev);
 
-      /* Unlink the device */
+      /* Unlink the device. */
       wavelan_list = wavelan_list->next;
 
-      /* Free pieces */
+      /* Free pieces. */
       kfree_s(dev->priv, sizeof(struct net_local));
       kfree_s(dev, sizeof(struct device));
     }
index 1527361d4ce78b25e2fae24f684462b686d1e948..8cef1e7358f0555bcf8b25173ca353344c1545e5 100644 (file)
@@ -131,4 +131,7 @@ if [ "$CONFIG_PPC" = "y" ]; then
   fi
   dep_tristate '53C94 (Power Mac external SCSI) support' CONFIG_SCSI_MAC53C94 $CONFIG_SCSI
 fi
+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+  source drivers/acorn/scsi/Config.in
+fi
 endmenu
index c464151a37375680cb091bedf5cc884152955297..f3b693255dfe58b2c5837ad5fc4b451a95afe56c 100644 (file)
@@ -395,12 +395,6 @@ static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
        esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
        esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
 
-       /* Reload the configuration registers */
-       eregs->esp_cfact = esp->cfact;
-       eregs->esp_stp   = 0;
-       eregs->esp_soff  = 0;
-       eregs->esp_timeo = esp->neg_defp;
-
        /* This is the only point at which it is reliable to read
         * the ID-code for a fast ESP chip variant.
         */
@@ -417,7 +411,10 @@ static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
                  }
 #endif
                if(family_code == 0x02)
-                       esp->erev = fas236;
+                       if ((version & 7) == 2)
+                               esp->erev = fas216;     
+                        else
+                               esp->erev = fas236;
                else if(family_code == 0x0a)
                        esp->erev = fashme; /* Version is usually '5'. */
                else
@@ -425,13 +422,20 @@ static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
                printk("esp%d: FAST chip is %s (family=%d, version=%d)\n",
                       esp->esp_id,
                       (esp->erev == fas236) ? "fas236" :
-                      ((esp->erev == fas100a) ? "fas100a" :
-                      "fasHME"), family_code, (version & 7));
+                      ((esp->erev == fas216) ? "fas216" :                     
+                      (((esp->erev == fas100a) ? "fas100a" :
+                      "fasHME"))), family_code, (version & 7));
 
                esp->min_period = ((4 * esp->ccycle) / 1000);
        } else {
                esp->min_period = ((5 * esp->ccycle) / 1000);
        }
+
+       /* Reload the configuration registers */
+       eregs->esp_cfact = esp->cfact;
+       eregs->esp_stp   = 0;
+       eregs->esp_soff  = 0;
+       eregs->esp_timeo = esp->neg_defp;
        esp->max_period = (esp->max_period + 3)>>2;
        esp->min_period = (esp->min_period + 3)>>2;
 
@@ -451,6 +455,7 @@ static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
        case fashme:
                esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
                /* fallthrough... */
+       case fas216:        
        case fas236:
                /* Fast 236 or HME */
                eregs->esp_cfg2 = esp->config2;
@@ -630,6 +635,9 @@ void esp_initialize(struct NCR_ESP *esp)
        esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
        esp->sync_defp = SYNC_DEFP_SLOW;
 
+       printk("SCSI ID %d  Clock %d MHz CCF=%d Time-Out %d ",
+              esp->scsi_id, (esp->cfreq / 1000000),
+              esp->ccf, (int) esp->neg_defp);
 
        /* Fill in ehost data */
        esp->ehost->base = (unsigned char *) eregs;
@@ -707,10 +715,6 @@ void esp_initialize(struct NCR_ESP *esp)
        esp_bootup_reset(esp, eregs);
        
        esps_in_use++;
-
-       printk("SCSI ID %d  Clock %d MHz CCF=%d Time-Out %d ",
-              esp->scsi_id, (esp->cfreq / 1000000),
-              esp->ccf, (int) esp->neg_defp);
 }
 
 /* The info function will return whatever useful
@@ -724,17 +728,19 @@ const char *esp_info(struct Scsi_Host *host)
        esp = (struct NCR_ESP *) host->hostdata;
        switch(esp->erev) {
        case esp100:
-               return "Sparc ESP100 (NCR53C90)";
+               return "ESP100 (NCR53C90)";
        case esp100a:
-               return "Sparc ESP100A (NCR53C90A)";
+               return "ESP100A (NCR53C90A)";
        case esp236:
-               return "Sparc ESP236";
+               return "ESP236";
+       case fas216:
+               return "ESP216-FAST";
        case fas236:
-               return "Sparc ESP236-FAST";
+               return "ESP236-FAST";
        case fashme:
-               return "Sparc ESP366-HME";
+               return "ESP366-HME";
        case fas100a:
-               return "Sparc ESP100A-FAST";
+               return "ESP100A-FAST";
        default:
                panic("Bogon ESP revision");
        };
@@ -807,6 +813,9 @@ static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len)
        case esp236:
                copy_info(&info, "ESP236\n");
                break;
+       case fas216:
+               copy_info(&info, "FAS216\n");
+               break;
        case fas236:
                copy_info(&info, "FAS236\n");
                break;
@@ -1252,20 +1261,11 @@ int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                SCpnt->SCp.buffer           =
                        (struct scatterlist *) SCpnt->request_buffer;
                SCpnt->SCp.buffers_residual = 0;
-#ifdef CONFIG_SCSI_SUNESP
-               /* Sneaky. */
-               SCpnt->SCp.have_data_in = mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
-                                                          SCpnt->SCp.this_residual,
-                                                          ((struct linux_sbus_device*) (esp->edev))->my_bus);
-               /* XXX The casts are extremely gross, but with 64-bit kernel
-                * XXX and 32-bit SBUS what am I to do? -DaveM
-                */
-               SCpnt->SCp.ptr = (char *)((unsigned long)SCpnt->SCp.have_data_in);
-#else
-               SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
-                       (char *) VTOP((unsigned long) SCpnt->request_buffer);
-#endif
-
+               if (esp->dma_mmu_get_scsi_one)
+                       esp->dma_mmu_get_scsi_one (esp, SCpnt);
+               else
+                       SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
+                               (char *) virt_to_phys(SCpnt->request_buffer);
        } else {
                ESPQUEUE(("use_sg "));
 #ifdef DEBUG_ESP_SG
@@ -1275,16 +1275,11 @@ int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->buffer;
                SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
                SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
-#ifdef CONFIG_SCSI_SUNESP
-               mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer,
-                                SCpnt->SCp.buffers_residual,
-                                ((struct linux_sbus_device *) (esp->edev))->my_bus);
-               /* XXX Again these casts are sick... -DaveM */
-               SCpnt->SCp.ptr=(char *)((unsigned long)SCpnt->SCp.buffer->dvma_address);
-#else
-               SCpnt->SCp.ptr = 
-                 (char *) VTOP((unsigned long) SCpnt->SCp.buffer->address);
-#endif
+               if (esp->dma_mmu_get_scsi_sgl)
+                       esp->dma_mmu_get_scsi_sgl (esp, SCpnt);
+               else
+                       SCpnt->SCp.ptr = 
+                               (char *) virt_to_phys(SCpnt->SCp.buffer->address);
        }
        SCpnt->SCp.Status           = CHECK_CONDITION;
        SCpnt->SCp.Message          = 0xff;
@@ -1481,21 +1476,14 @@ static void esp_done(struct NCR_ESP *esp, int error)
 
                /* Free dvma entry. */
                if(!done_SC->use_sg) {
-#ifdef CONFIG_SCSI_SUNESP
-                       /* Sneaky. */
-                       mmu_release_scsi_one(done_SC->SCp.have_data_in,
-                                            done_SC->request_bufflen,
-                                            ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+                       if (esp->dma_mmu_release_scsi_one)
+                               esp->dma_mmu_release_scsi_one (esp, done_SC);
                } else {
 #ifdef DEBUG_ESP_SG
                        printk("esp%d: unmapping sg ", esp->esp_id);
 #endif
-#ifdef CONFIG_SCSI_SUNESP
-                       mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer,
-                                            done_SC->use_sg - 1,
-                                            ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+                       if (esp->dma_mmu_release_scsi_sgl)
+                               esp->dma_mmu_release_scsi_sgl (esp, done_SC);
 #ifdef DEBUG_ESP_SG
                        printk("done.\n");
 #endif
@@ -1861,16 +1849,15 @@ static inline int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs)
        return do_work_bus;
 }
 
-static inline void advance_sg(Scsi_Cmnd *sp)
+static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
        ++sp->SCp.buffer;
        --sp->SCp.buffers_residual;
        sp->SCp.this_residual = sp->SCp.buffer->length;
-#ifdef CONFIG_SCSI_SUNESP
-       sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
-#else
-       sp->SCp.ptr = (char *)VTOP((unsigned long) sp->SCp.buffer->address);
-#endif
+        if (esp->dma_advance_sg)
+              esp->dma_advance_sg (sp);
+        else
+              sp->SCp.ptr = (char *)virt_to_phys(sp->SCp.buffer->address);
 }
 
 /* Please note that the way I've coded these routines is that I _always_
@@ -2067,7 +2054,7 @@ static inline int esp_do_data_finale(struct NCR_ESP *esp,
                 * figure this out.
                 */
                if(SCptr->use_sg && !SCptr->SCp.this_residual)
-                       advance_sg(SCptr);
+                       advance_sg(esp, SCptr);
                if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
                        ESPDATA(("to more data\n"));
                        return esp_do_data(esp, eregs);
@@ -2922,6 +2909,7 @@ static inline int check_multibyte_msg(struct NCR_ESP *esp,
                        tmp = esp->ccycle / 1000;
                        regval = (((period << 2) + tmp - 1) / tmp);
                        if(regval && ((esp->erev == fas100a ||
+                                      esp->erev == fas216 ||                                  
                                       esp->erev == fas236 ||
                                       esp->erev == fashme))) {
                                if(period >= 50)
@@ -2934,7 +2922,7 @@ static inline int check_multibyte_msg(struct NCR_ESP *esp,
 
                        SDptr->sync_min_period = (regval & 0x1f);
                        SDptr->sync_max_offset = (offset | esp->radelay);
-                       if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
+                       if((esp->erev == fas100a || esp->erev == fas216 || esp->erev == fas236 || esp->erev == fashme)) {
                                if((esp->erev == fas100a) || (esp->erev == fashme))
                                        bit = ESP_CONFIG3_FAST;
                                else
@@ -2963,7 +2951,7 @@ static inline int check_multibyte_msg(struct NCR_ESP *esp,
                        SDptr->sync_min_period = 0;
                        eregs->esp_soff = 0;
                        eregs->esp_stp = 0;
-                       if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
+                       if((esp->erev == fas100a || esp->erev == fas216 || esp->erev == fas236 || esp->erev == fashme)) {
                                if((esp->erev == fas100a) || (esp->erev == fashme))
                                        bit = ESP_CONFIG3_FAST;
                                else
@@ -3595,17 +3583,13 @@ again:
                if(esp->current_SC) {
                        Scsi_Cmnd *SCptr = esp->current_SC;
 
-#ifdef CONFIG_SCSI_SUNESP
-                       if(!SCptr->use_sg)
-                               mmu_release_scsi_one(SCptr->SCp.have_data_in,
-                                                    SCptr->request_bufflen,
-                                                    ((struct linux_sbus_device *) (esp->edev))->my_bus);
-                       else
-                               mmu_release_scsi_sgl((struct mmu_sglist *)
-                                                    SCptr->buffer,
-                                                    SCptr->use_sg - 1,
-                                                    ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+                       if(!SCptr->use_sg) {
+                               if (esp->dma_mmu_release_scsi_one)
+                                       esp->dma_mmu_release_scsi_one (esp, SCptr);
+                       } else {
+                               if (esp->dma_mmu_release_scsi_sgl)
+                                       esp->dma_mmu_release_scsi_sgl (esp, SCptr);
+                       }
                        SCptr->result = (DID_RESET << 16);
 
                        SCptr->scsi_done(SCptr);
@@ -3614,17 +3598,13 @@ again:
                if(esp->disconnected_SC) {
                        Scsi_Cmnd *SCptr;
                        while((SCptr = remove_first_SC(&esp->disconnected_SC))) {
-                               if(!SCptr->use_sg)
-#ifdef CONFIG_SCSI_SUNESP
-                                       mmu_release_scsi_one(SCptr->SCp.have_data_in,
-                                                            SCptr->request_bufflen,
-                                                            ((struct linux_sbus_device *) (esp->edev))->my_bus);
-                               else
-                                       mmu_release_scsi_sgl((struct mmu_sglist *)
-                                                            SCptr->buffer,
-                                                            SCptr->use_sg - 1,
-                                                            ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+                               if(!SCptr->use_sg) {
+                                       if (esp->dma_mmu_release_scsi_one)
+                                               esp->dma_mmu_release_scsi_one (esp, SCptr);
+                               } else {
+                                       if (esp->dma_mmu_release_scsi_sgl)
+                                               esp->dma_mmu_release_scsi_sgl (esp, SCptr);
+                               }
                                SCptr->result = (DID_RESET << 16);
 
                                SCptr->scsi_done(SCptr);
@@ -3671,7 +3651,9 @@ void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
 repeat:
        again = 0;
        for_each_esp(esp) {
+#ifndef __mips__           
                if(((esp)->irq & 0xf) == irq) {
+#endif             
                        if(esp->dma_irq_p(esp)) {
                                again = 1;
 
@@ -3683,7 +3665,9 @@ repeat:
 
                                esp->dma_ints_on(esp);
                        }
+#ifndef __mips__                   
                }
+#endif     
        }
        if(again)
                goto repeat;
index a7431ca870920dfc8117e9de32e828039fccecbc..2a5ff92a65b85df55e876009661592b263a3c9a9 100644 (file)
         (printk ("Internal ESP driver error in file %s, line %d\n", \
                 __FILE__, __LINE__))
 
+/*
+ * padding for register structure
+ */
+#ifdef CONFIG_JAZZ_ESP
+#define EREGS_PAD(n)
+#else
+#define EREGS_PAD(n)    unchar n[3];
+#endif
+
 /* The ESP SCSI controllers have their register sets in three
  * "classes":
  *
 struct ESP_regs {
                                 /* Access    Description              Offset */
     volatile unchar esp_tclow;  /* rw  Low bits of the transfer count 0x00   */
-                                unchar tlpad1[3];
+                                EREGS_PAD(tlpad1);
     volatile unchar esp_tcmed;  /* rw  Mid bits of the transfer count 0x04   */
-                                unchar fdpad[3];
+                                EREGS_PAD(fdpad);
     volatile unchar esp_fdata;  /* rw  FIFO data bits                 0x08   */
-                                unchar cbpad[3];
+                                EREGS_PAD(cbpad);
     volatile unchar esp_cmd;    /* rw  SCSI command bits              0x0c   */
-                                unchar stpad[3];
+                                EREGS_PAD(stpad);
     volatile unchar esp_status; /* ro  ESP status register            0x10   */
 #define esp_busid   esp_status  /* wo  Bus ID for select/reselect     0x10   */
-                                unchar irqpd[3];
+                                EREGS_PAD(irqpd);
     volatile unchar esp_intrpt; /* ro  Kind of interrupt              0x14   */
 #define esp_timeo   esp_intrpt  /* wo  Timeout value for select/resel 0x14   */
-                                unchar sspad[3];
+                                EREGS_PAD(sspad);
     volatile unchar esp_sstep;  /* ro  Sequence step register         0x18   */
 #define esp_stp     esp_sstep   /* wo  Transfer period per sync       0x18   */
-                                unchar ffpad[3];
+                                EREGS_PAD(ffpad);
     volatile unchar esp_fflags; /* ro  Bits of current FIFO info      0x1c   */
 #define esp_soff    esp_fflags  /* wo  Sync offset                    0x1c   */
-                                unchar cf1pd[3];
+                                EREGS_PAD(cf1pd);
     volatile unchar esp_cfg1;   /* rw  First configuration register   0x20   */
-                                unchar cfpad[3];
+                                EREGS_PAD(cfpad);
     volatile unchar esp_cfact;  /* wo  Clock conversion factor        0x24   */
 #define esp_status2 esp_cfact   /* ro  HME status2 register           0x24   */
-                                unchar ctpad[3];
+                                EREGS_PAD(ctpad);
     volatile unchar esp_ctest;  /* wo  Chip test register             0x28   */
-                                unchar cf2pd[3];
+                                EREGS_PAD(cf2pd);
     volatile unchar esp_cfg2;   /* rw  Second configuration register  0x2c   */
-                                unchar cf3pd[3];
+                                EREGS_PAD(cf3pd);
 
     /* The following is only found on the 53C9X series SCSI chips */
     volatile unchar esp_cfg3;   /* rw  Third configuration register   0x30  */
-                                unchar thpd[7];
-
+                                EREGS_PAD(holep);
+    volatile unchar esp_hole;   /* hole in register map               0x34  */
+                                EREGS_PAD(thpd);    
     /* The following is found on all chips except the NCR53C90 (ESP100) */
     volatile unchar esp_tchi;   /* rw  High bits of transfer count    0x38  */
 #define esp_uid     esp_tchi    /* ro  Unique ID code                 0x38  */
 #define fas_rlo     esp_tchi    /* rw  HME extended counter           0x38  */
-                                unchar fgpad[3];
+                                EREGS_PAD(fgpad);    
     volatile unchar esp_fgrnd;  /* rw  Data base for fifo             0x3c  */
 #define fas_rhi     esp_fgrnd   /* rw  HME extended counter           0x3c  */
 };
@@ -175,7 +185,8 @@ enum esp_rev {
   fas100a    = 0x04,
   fast       = 0x05,
   fashme     = 0x06,
-  espunknown = 0x07
+  fas216     = 0x07,    
+  espunknown = 0x08
 };
 
 /* We get one of these for each ESP probed. */
@@ -303,6 +314,13 @@ struct NCR_ESP {
   void (*dma_led_on)(struct NCR_ESP *);
   void (*dma_poll)(struct NCR_ESP *, unsigned char *);
   void (*dma_reset)(struct NCR_ESP *);
+    
+  /* Optional virtual DMA functions */
+  void (*dma_mmu_get_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_mmu_get_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_mmu_release_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_mmu_release_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_advance_sg)(Scsi_Cmnd *);
 };
 
 /* Bitfield meanings for the above registers. */
index 8770ef0ad0244a010de890742c4e2eef4a071055..2f94d0e3305ab9b05c576391042fa02de325871c 100644 (file)
@@ -130,6 +130,7 @@ int blz1230_esp_detect(Scsi_Host_Template *tpnt)
                esp->eregs = eregs;
 
                /* Set the command buffer */
+               esp->esp_command = (volatile unsigned char*) cmd_buffer;
                esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
 
                esp->irq = IRQ_AMIGA_PORTS;
index 6438521a9f9a271bb5cd5838a3532a709aa360b3..3712b0f0d6660be7c9f9ddd22649f5bd47628d11 100644 (file)
@@ -56,27 +56,17 @@ extern int esp_reset(Scsi_Cmnd *, unsigned int);
 extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
                         int hostno, int inout);
 
-#define SCSI_BLZ1230 {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,                   \
-/* const char *name */                                         "Blizzard1230 SCSI IV", \
-/* int detect(struct SHT *) */                                 blz1230_esp_detect,             \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *) */                                   esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_BLZ1230      { proc_dir:          &proc_scsi_esp, \
+                           name:               "Blizzard1230 SCSI IV", \
+                           detect:             blz1230_esp_detect, \
+                           release:            NULL, \
+                           queuecommand:       esp_queue, \
+                           abort:              esp_abort, \
+                           reset:              esp_reset, \
+                           can_queue:          7, \
+                           this_id:            7, \
+                           sg_tablesize:       SG_ALL, \
+                           cmd_per_lun:        1, \
+                           use_clustering:     DISABLE_CLUSTERING }
 
 #endif /* BLZ1230_H */
index a8b1cf69629fa85b7ce662a3f7e5d2a6cde2ed60..c36cc859cc5fbcbff871350b9975b8e4f598023f 100644 (file)
@@ -106,6 +106,7 @@ int blz2060_esp_detect(Scsi_Host_Template *tpnt)
                esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR);
                
                /* Set the command buffer */
+               esp->esp_command = (volatile unsigned char*) cmd_buffer;
                esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
 
                esp->irq = IRQ_AMIGA_PORTS;
index 5b085f06aa25c3e41d8f8043741cce693e5f4f03..445442ac7b54f76a40bdd798babe290ee1ce5f45 100644 (file)
@@ -52,27 +52,17 @@ extern int esp_reset(Scsi_Cmnd *, unsigned int);
 extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
                         int hostno, int inout);
 
-#define SCSI_BLZ2060 {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,                   \
-/* const char *name */                                         "Blizzard2060 SCSI", \
-/* int detect(struct SHT *) */                                 blz2060_esp_detect,             \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *) */                                   esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_BLZ2060      { proc_dir:          &proc_scsi_esp, \
+                           name:               "Blizzard2060 SCSI", \
+                           detect:             blz2060_esp_detect, \
+                           release:            NULL, \
+                           queuecommand:       esp_queue, \
+                           abort:              esp_abort, \
+                           reset:              esp_reset, \
+                           can_queue:          7, \
+                           this_id:            7, \
+                           sg_tablesize:       SG_ALL, \
+                           cmd_per_lun:        1, \
+                           use_clustering:     DISABLE_CLUSTERING }
 
 #endif /* BLZ2060_H */
index dd6674fa007fcf6c6db21f0f82dd8f3c5837d34c..b4f7f165a96d81f2b233d6f317ffadfd7b621ba7 100644 (file)
@@ -126,6 +126,7 @@ int cyber_esp_detect(Scsi_Host_Template *tpnt)
                esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR);
                
                /* Set the command buffer */
+               esp->esp_command = (volatile unsigned char*) cmd_buffer;
                esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
 
                esp->irq = IRQ_AMIGA_PORTS;
index b38649011eb5fdb33b5deac4a67c41650d1336f3..8c720c9b9c861f0b0971a7820086b6fb50640503 100644 (file)
@@ -55,28 +55,18 @@ extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
                         int hostno, int inout);
 
 
-#define SCSI_CYBERSTORM {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,                   \
-/* const char *name */                                         "CyberStorm SCSI", \
-/* int detect(struct SHT *) */                                 cyber_esp_detect,  \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *) */                                   esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_CYBERSTORM   { proc_dir:          &proc_scsi_esp, \
+                           name:               "CyberStorm SCSI", \
+                           detect:             cyber_esp_detect, \
+                           release:            NULL, \
+                           queuecommand:       esp_queue, \
+                           abort:              esp_abort, \
+                           reset:              esp_reset, \
+                           can_queue:          7, \
+                           this_id:            7, \
+                           sg_tablesize:       SG_ALL, \
+                           cmd_per_lun:        1, \
+                           use_clustering:     DISABLE_CLUSTERING }
 
 #endif /* CYBER_ESP_H */
 
index b83876cae49396db609e03bbfa2515258d411e33..d62e09e3b71be35832e378e3d75b6f61d4e9a6a8 100644 (file)
@@ -117,6 +117,7 @@ int cyberII_esp_detect(Scsi_Host_Template *tpnt)
                esp->eregs = eregs;
                
                /* Set the command buffer */
+               esp->esp_command = (volatile unsigned char*) cmd_buffer;
                esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
 
                esp->irq = IRQ_AMIGA_PORTS;
index b04fb37e84d3e50c1da4ec9316a5668cdf5547ef..257e438b18f7e139bb15853e3d63bd6cafaeb75d 100644 (file)
@@ -42,28 +42,18 @@ extern int esp_reset(Scsi_Cmnd *, unsigned int);
 extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
                         int hostno, int inout);
 
-#define SCSI_CYBERSTORMII {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,                   \
-/* const char *name */                                         "CyberStorm Mk II SCSI", \
-/* int detect(struct SHT *) */                                 cyberII_esp_detect,  \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *) */                                   esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_CYBERSTORMII { proc_dir:          &proc_scsi_esp, \
+                           name:               "CyberStorm Mk II SCSI", \
+                           detect:             cyberII_esp_detect, \
+                           release:            NULL, \
+                           queuecommand:       esp_queue, \
+                           abort:              esp_abort, \
+                           reset:              esp_reset, \
+                           can_queue:          7, \
+                           this_id:            7, \
+                           sg_tablesize:       SG_ALL, \
+                           cmd_per_lun:        1, \
+                           use_clustering:     DISABLE_CLUSTERING }
 
 #endif /* CYBERII_ESP_H */
 
index acf6051efd37294d5590ebdc9efe2a0812147f59..c073576e8ea76edcd349e2db6733227fb1713ed1 100644 (file)
@@ -5,8 +5,8 @@
  * This driver is based on the CyberStorm driver, hence the occasional
  * reference to CyberStorm.
  *
- * Betatesting & crucial adjustments by Patrik Rak 
- * (prak3264@ss1000.ms.mff.cuni.cz)
+ * Betatesting & crucial adjustments by
+ *        Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
  *
  */
 
 
 #include <asm/pgtable.h>
 
+/* Such day has just come... */
+#if 0
 /* Let this defined unless you really need to enable DMA IRQ one day */
 #define NODMAIRQ
+#endif
 
 static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
 static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
@@ -55,6 +58,7 @@ static void dma_init_write(struct NCR_ESP *esp, __u32 vaddr, int length);
 static void dma_ints_off(struct NCR_ESP *esp);
 static void dma_ints_on(struct NCR_ESP *esp);
 static int  dma_irq_p(struct NCR_ESP *esp);
+static void dma_irq_exit(struct NCR_ESP *esp);
 static void dma_led_off(struct NCR_ESP *esp);
 static void dma_led_on(struct NCR_ESP *esp);
 static int  dma_ports_p(struct NCR_ESP *esp);
@@ -113,7 +117,7 @@ int fastlane_esp_detect(Scsi_Host_Template *tpnt)
                esp->dma_drain = 0;
                esp->dma_invalidate = 0;
                esp->dma_irq_entry = 0;
-               esp->dma_irq_exit = 0;
+               esp->dma_irq_exit = &dma_irq_exit;
                esp->dma_led_on = &dma_led_on;
                esp->dma_led_off = &dma_led_off;
                esp->dma_poll = 0;
@@ -158,6 +162,7 @@ int fastlane_esp_detect(Scsi_Host_Template *tpnt)
                esp->edev = (void *) address;
                
                /* Set the command buffer */
+               esp->esp_command = (volatile unsigned char*) cmd_buffer;
                esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
 
                esp->irq = IRQ_AMIGA_PORTS;
@@ -278,39 +283,34 @@ static void dma_ints_on(struct NCR_ESP *esp)
        enable_irq(esp->irq);
 }
 
+static void dma_irq_exit(struct NCR_ESP *esp)
+{
+       struct fastlane_dma_registers *dregs = 
+               (struct fastlane_dma_registers *) (esp->dregs);
+
+       dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI);
+       nop();
+       dregs->ctrl_reg = ctrl_data;
+}
+
 static int dma_irq_p(struct NCR_ESP *esp)
 {
        struct fastlane_dma_registers *dregs = 
                (struct fastlane_dma_registers *) (esp->dregs);
-#if 0
        unsigned char dma_status;
-       int r = 0;
 
        dma_status = dregs->cond_reg;
 
        if(dma_status & FASTLANE_DMA_IACT)
                return 0;       /* not our IRQ */
 
-       /* Return 1 if ESP requested IRQ */
-       if(
+       /* Return non-zero if ESP requested IRQ */
+       return (
 #ifndef NODMAIRQ
           (dma_status & FASTLANE_DMA_CREQ) &&
 #endif
           (!(dma_status & FASTLANE_DMA_MINT)) &&
-          ((((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR))
-               r = 1;
-
-       dregs->ctrl_reg = (ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI) );
-       dregs->ctrl_reg = ctrl_data;
-
-       return r;
-#else
-       int r;
-       r = (((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR;
-       dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI);
-       dregs->ctrl_reg = ctrl_data;
-       return r;
-#endif
+          ((((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR));
 }
 
 static void dma_led_off(struct NCR_ESP *esp)
index 0ff4d231c91330cfeb6d709778be3473d09bdab7..984a177c9c189b0ac03cb939530f0f31803f229e 100644 (file)
@@ -47,27 +47,17 @@ extern int esp_reset(Scsi_Cmnd *, unsigned int);
 extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
                         int hostno, int inout);
 
-#define SCSI_FASTLANE {                                                               \
-/* struct SHT *next */                                         NULL,                   \
-/* long *usage_count */                                        NULL,                   \
-/* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,                   \
-/* const char *name */                                         "Fastlane SCSI", \
-/* int detect(struct SHT *) */                                 fastlane_esp_detect,  \
-/* int release(struct Scsi_Host *) */                          NULL,                   \
-/* const char *info(struct Scsi_Host *) */                     esp_info,               \
-/* int command(Scsi_Cmnd *) */                                 esp_command,            \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
-/* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
-/* int reset(Scsi_Cmnd *) */                                   esp_reset,              \
-/* int slave_attach(int, int) */                               NULL,                   \
-/* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            7,                      \
-/* int this_id */                                              7,                      \
-/* short unsigned int sg_tablesize */                          SG_ALL,                 \
-/* short cmd_per_lun */                                        1,                      \
-/* unsigned char present */                                    0,                      \
-/* unsigned unchecked_isa_dma:1 */                             0,                      \
-/* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
+#define SCSI_FASTLANE     { proc_dir:          &proc_scsi_esp, \
+                           name:               "Fastlane SCSI", \
+                           detect:             fastlane_esp_detect, \
+                           release:            NULL, \
+                           queuecommand:       esp_queue, \
+                           abort:              esp_abort, \
+                           reset:              esp_reset, \
+                           can_queue:          7, \
+                           this_id:            7, \
+                           sg_tablesize:       SG_ALL, \
+                           cmd_per_lun:        1, \
+                           use_clustering:     DISABLE_CLUSTERING }
 
 #endif /* FASTLANE_H */
index e13e43306d150cce53f5d71f47f3cbede4505b49..195faaac09858705c9211f09b812c18efd02d816 100644 (file)
 #include "scsi_debug.h"
 #endif
 
+#ifdef CONFIG_SCSI_ACORNSCSI_3
+#include "../acorn/scsi/acornscsi.h"
+#endif
+
+#ifdef CONFIG_SCSI_CUMANA_1
+#include "../acorn/scsi/cumana_1.h"
+#endif
+
+#ifdef CONFIG_SCSI_CUMANA_2
+#include "../acorn/scsi/cumana_2.h"
+#endif
+
+#ifdef CONFIG_SCSI_ECOSCSI
+#include "../acorn/scsi/ecoscsi.h"
+#endif
+
+#ifdef CONFIG_SCSI_OAK1
+#include "../acorn/scsi/oak.h"
+#endif
+
+#ifdef CONFIG_SCSI_POWERTECSCSI
+#include "../acorn/scsi/powertec.h"
+#endif
 
 /*
 static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.20 1996/12/12 19:18:32 davem Exp $";
@@ -424,6 +447,26 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_PLUTO
     PLUTO,
 #endif
+#ifdef CONFIG_ARCH_ACORN
+#ifdef CONFIG_SCSI_ACORNSCSI_3
+    ACORNSCSI_3,
+#endif
+#ifdef CONFIG_SCSI_CUMANA_1
+    CUMANA_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_CUMANA_2
+    CUMANA_FAS216,
+#endif
+#ifdef CONFIG_SCSI_ECOSCSI
+    ECOSCSI_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_OAK1
+    OAK_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_POWERTECSCSI
+    POWERTECSCSI,
+#endif
+#endif
 #ifdef CONFIG_SCSI_DEBUG
     SCSI_DEBUG,
 #endif
index bbf645acdf59f778ba90d3f44ef170727d6da4c1..2426ef8aa99c94adf0ef1e209a8a8b25348f73ac 100644 (file)
@@ -79,7 +79,7 @@ static int scsi_abort (Scsi_Cmnd *, int code);
 static int scsi_reset (Scsi_Cmnd *, unsigned int);
 
 extern void scsi_old_done (Scsi_Cmnd *SCpnt);
-static int update_timeout (Scsi_Cmnd *, int);
+int update_timeout (Scsi_Cmnd *, int);
 extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
 extern void internal_cmnd (Scsi_Cmnd * SCpnt);
 
@@ -1058,7 +1058,7 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
  * set the timer, we want to take this value into account.
  */
 
-static int update_timeout(Scsi_Cmnd * SCset, int timeout)
+int update_timeout(Scsi_Cmnd * SCset, int timeout)
 {
   int  rtn;
 
index 7c8b95138c260986410ddc62e666106ff41634f9..cebab71ef05513d48614baed9e5ac371f4a53345 100644 (file)
@@ -184,9 +184,9 @@ parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
     
     if (!buf || !cmdList)                           /* bad input ?     */
        return(NULL);
-    if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), 1)) == 0)
+    if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), GFP_KERNEL)) == 0)
        return(NULL);                               /* out of memory   */
-    if ((handle->cmdPos = (char**) kmalloc(sizeof(int), cmdNum)) == 0) {
+    if ((handle->cmdPos = (char**) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL)) == 0) {
        kfree(handle);
        return(NULL);                               /* out of memory   */
     }
index 95a6d806ab045f386aeb202a6519140be4e286df..299a7b06d4b6bf41d700711f1ca060762ebc9420 100644 (file)
@@ -93,7 +93,14 @@ retry:
                     printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
                if (retries++ < 10) {
                    /* sleep 2 sec and try again */
+                   /*
+                    * The spinlock is silly - we should really lock more of this
+                    * function, but the minimal locking required to not lock up
+                    * is around this - scsi_sleep() assumes we hold the spinlock.
+                    */
+                   spin_lock_irqsave(&io_request_lock, flags);
                    scsi_sleep(2*HZ);
+                   spin_unlock_irqrestore(&io_request_lock, flags);
                     goto retry;
                } else {
                    /* 20 secs are enouth? */
index 64f56e592065407ccc3f9ad54945acf3ebb83882..9a1bb5524b7f76c0d9e67cca805ff4ab82c8a023 100644 (file)
@@ -137,6 +137,19 @@ if [ "$CONFIG_SOUND_OSS" != "n" ]; then
        string '  Full pathname of OSWF.MOT firmware file' CONFIG_MAUI_BOOT_FILE
       fi
   fi
+
+  if [ "$CONFIG_SOUND" = "m" ]; then
+    dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
+    if [ "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then
+       string '  Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE
+       string '  Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE
+    fi
+    dep_tristate 'Support for Turtle Beach MultiSound Pinnacle, Fiji' CONFIG_SOUND_MSNDPIN $CONFIG_SOUND
+    if [ "$CONFIG_SOUND_MSNDPIN" = "m" ]; then
+       string '  Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE
+       string '  Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE
+    fi
+  fi
   
   dep_tristate 'Support for Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
   if [ "$CONFIG_SOUND_SGALAXY" = "y" ]; then
index d05b38add80cf8cf525c160fd66987bf69ee4595..bf068ee9d1cf6f8e6123def8607951e877b1157f 100644 (file)
@@ -23,8 +23,9 @@ endif
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
 export-objs    :=  ad1848.o audio_syms.o midi_syms.o mpu401.o \
-                   opl3.o sb_card.o sequencer_syms.o sound_core.o \
-                   sound_firmware.o sound_syms.o uart401.o
+                   msnd.o opl3.o sb_card.o sequencer_syms.o \
+                   sound_core.o sound_firmware.o sound_syms.o \
+                   uart401.o
 
 
 
@@ -53,6 +54,8 @@ obj-$(CONFIG_SOUND_GUS)               += gus.o ad1848.o
 obj-$(CONFIG_SOUND_MAD16)      += mad16.o ad1848.o sb.o uart401.o
 obj-$(CONFIG_SOUND_MAUI)       += maui.o mpu401.o
 obj-$(CONFIG_SOUND_MPU401)     += mpu401.o
+obj-$(CONFIG_SOUND_MSNDCLAS)   += msnd.o msnd_classic.o
+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_PAS)                += pas2.o sb.o uart401.o
index 7805bed434e6f7893dd8de4c4717027366414674..a5cf5dcd94848a5f8baf8301d1577685c0e17981 100644 (file)
@@ -4,6 +4,7 @@
 /*
 
 OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k
+Extended to support Power Macintosh for Linux/ppc by Paul Mackerras
 
 (c) 1995 by Michael Schlueter & Michael Marte
 
@@ -85,7 +86,9 @@ History:
 #include <linux/mm.h>
 #include <linux/malloc.h>
 
+#ifdef __mc68000__
 #include <asm/setup.h>
+#endif
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
@@ -100,10 +103,23 @@ History:
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#endif /* CONFIG_PMAC_PBOOK */
+#include "awacs_defs.h"
+#include <linux/nvram.h>
+#include <linux/vt_kern.h>
+#endif /* CONFIG_PMAC */
 
 #include "dmasound.h"
 #include <linux/soundcard.h>
 
+#define HAS_8BIT_TABLES
 
 #ifdef MODULE
 static int chrdev_registered = 0;
@@ -143,6 +159,90 @@ extern u_short amiga_audio_period;
 
 #endif /* CONFIG_AMIGA */
 
+#ifdef CONFIG_PMAC
+/*
+ * Interrupt numbers and addresses, obtained from the device tree.
+ */
+static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
+static volatile struct awacs_regs *awacs;
+static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
+static int awacs_rate_index;
+
+/*
+ * Space for the DBDMA command blocks.
+ */
+static void *awacs_tx_cmd_space;
+static volatile struct dbdma_cmd *awacs_tx_cmds;
+
+/*
+ * Cached values of AWACS registers (we can't read them).
+ */
+int awacs_reg[5];
+
+#define HAS_16BIT_TABLES
+#undef HAS_8BIT_TABLES
+
+/*
+ * Stuff for outputting a beep.  The values range from -327 to +327
+ * so we can multiply by an amplitude in the range 0..100 to get a
+ * signed short value to put in the output buffer.
+ */
+static short beep_wform[256] = {
+       0,      40,     79,     117,    153,    187,    218,    245,
+       269,    288,    304,    316,    323,    327,    327,    324,
+       318,    310,    299,    288,    275,    262,    249,    236,
+       224,    213,    204,    196,    190,    186,    183,    182,
+       182,    183,    186,    189,    192,    196,    200,    203,
+       206,    208,    209,    209,    209,    207,    204,    201,
+       197,    193,    188,    183,    179,    174,    170,    166,
+       163,    161,    160,    159,    159,    160,    161,    162,
+       164,    166,    168,    169,    171,    171,    171,    170,
+       169,    167,    163,    159,    155,    150,    144,    139,
+       133,    128,    122,    117,    113,    110,    107,    105,
+       103,    103,    103,    103,    104,    104,    105,    105,
+       105,    103,    101,    97,     92,     86,     78,     68,
+       58,     45,     32,     18,     3,      -11,    -26,    -41,
+       -55,    -68,    -79,    -88,    -95,    -100,   -102,   -102,
+       -99,    -93,    -85,    -75,    -62,    -48,    -33,    -16,
+       0,      16,     33,     48,     62,     75,     85,     93,
+       99,     102,    102,    100,    95,     88,     79,     68,
+       55,     41,     26,     11,     -3,     -18,    -32,    -45,
+       -58,    -68,    -78,    -86,    -92,    -97,    -101,   -103,
+       -105,   -105,   -105,   -104,   -104,   -103,   -103,   -103,
+       -103,   -105,   -107,   -110,   -113,   -117,   -122,   -128,
+       -133,   -139,   -144,   -150,   -155,   -159,   -163,   -167,
+       -169,   -170,   -171,   -171,   -171,   -169,   -168,   -166,
+       -164,   -162,   -161,   -160,   -159,   -159,   -160,   -161,
+       -163,   -166,   -170,   -174,   -179,   -183,   -188,   -193,
+       -197,   -201,   -204,   -207,   -209,   -209,   -209,   -208,
+       -206,   -203,   -200,   -196,   -192,   -189,   -186,   -183,
+       -182,   -182,   -183,   -186,   -190,   -196,   -204,   -213,
+       -224,   -236,   -249,   -262,   -275,   -288,   -299,   -310,
+       -318,   -324,   -327,   -327,   -323,   -316,   -304,   -288,
+       -269,   -245,   -218,   -187,   -153,   -117,   -79,    -40,
+};
+
+#define BEEP_SPEED     2       /* 22050 Hz sample rate */
+#define BEEP_BUFLEN    512
+#define BEEP_VOLUME    15      /* 0 - 100 */
+
+static int beep_volume = BEEP_VOLUME;
+static int beep_playing = 0;
+static short *beep_buf;
+static volatile struct dbdma_cmd *beep_dbdma_cmd;
+static void (*orig_mksound)(unsigned int, unsigned int);
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Stuff for restoring after a sleep.
+ */
+static int awacs_sleep_notify(struct notifier_block *, unsigned long, void *);
+struct notifier_block awacs_sleep_notifier = {
+       awacs_sleep_notify
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+#endif /* CONFIG_PMAC */
 
 /*** Some declarations *******************************************************/
 
@@ -150,6 +250,7 @@ extern u_short amiga_audio_period;
 #define DMASND_TT              1
 #define DMASND_FALCON          2
 #define DMASND_AMIGA           3
+#define DMASND_AWACS           4
 
 #define MAX_CATCH_RADIUS       10
 #define MIN_BUFFERS            4
@@ -165,164 +266,164 @@ static int catchRadius = 0, numBufs = 4, bufSize = 32;
 #define le2be16dbl(x)  (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
 
 #define IOCTL_IN(arg, ret) \
- do { int error = get_user(ret, (int *)(arg)); \
-      if (error) return error; \
- } while (0)
      do { int error = get_user(ret, (int *)(arg)); \
+               if (error) return error; \
      } while (0)
 #define IOCTL_OUT(arg, ret)    ioctl_return((int *)(arg), ret)
 
 
 /*** Some low level helpers **************************************************/
 
-
+#ifdef HAS_8BIT_TABLES
 /* 8 bit mu-law */
 
 static char ulaw2dma8[] = {
-    -126,   -122,   -118,   -114,   -110,   -106,   -102,    -98,
-     -94,    -90,    -86,    -82,    -78,    -74,    -70,    -66,
-     -63,    -61,    -59,    -57,    -55,    -53,    -51,    -49,
-     -47,    -45,    -43,    -41,    -39,    -37,    -35,    -33,
-     -31,    -30,    -29,    -28,    -27,    -26,    -25,    -24,
-     -23,    -22,    -21,    -20,    -19,    -18,    -17,    -16,
-     -16,    -15,    -15,    -14,    -14,    -13,    -13,    -12,
-     -12,    -11,    -11,    -10,    -10,     -9,     -9,     -8,
-      -8,     -8,     -7,     -7,     -7,     -7,     -6,     -6,
-      -6,     -6,     -5,     -5,     -5,     -5,     -4,     -4,
-      -4,     -4,     -4,     -4,     -3,     -3,     -3,     -3,
-      -3,     -3,     -3,     -3,     -2,     -2,     -2,     -2,
-      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
-      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
-      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
-      -1,     -1,     -1,     -1,     -1,     -1,     -1,      0,
-     125,    121,    117,    113,    109,    105,    101,     97,
-      93,     89,     85,     81,     77,     73,     69,     65,
-      62,     60,     58,     56,     54,     52,     50,     48,
-      46,     44,     42,     40,     38,     36,     34,     32,
-      30,     29,     28,     27,     26,     25,     24,     23,
-      22,     21,     20,     19,     18,     17,     16,     15,
-      15,     14,     14,     13,     13,     12,     12,     11,
-      11,     10,     10,      9,      9,      8,      8,      7,
-       7,      7,      6,      6,      6,      6,      5,      5,
-       5,      5,      4,      4,      4,      4,      3,      3,
-       3,      3,      3,      3,      2,      2,      2,      2,
-       2,      2,      2,      2,      1,      1,      1,      1,
-       1,      1,      1,      1,      1,      1,      1,      1,
-       0,      0,      0,      0,      0,      0,      0,      0,
-       0,      0,      0,      0,      0,      0,      0,      0,
-       0,      0,      0,      0,      0,      0,      0,      0
+       -126,   -122,   -118,   -114,   -110,   -106,   -102,   -98,
+       -94,    -90,    -86,    -82,    -78,    -74,    -70,    -66,
+       -63,    -61,    -59,    -57,    -55,    -53,    -51,    -49,
+       -47,    -45,    -43,    -41,    -39,    -37,    -35,    -33,
+       -31,    -30,    -29,    -28,    -27,    -26,    -25,    -24,
+       -23,    -22,    -21,    -20,    -19,    -18,    -17,    -16,
+       -16,    -15,    -15,    -14,    -14,    -13,    -13,    -12,
+       -12,    -11,    -11,    -10,    -10,    -9,     -9,     -8,
+       -8,     -8,     -7,     -7,     -7,     -7,     -6,     -6,
+       -6,     -6,     -5,     -5,     -5,     -5,     -4,     -4,
+       -4,     -4,     -4,     -4,     -3,     -3,     -3,     -3,
+       -3,     -3,     -3,     -3,     -2,     -2,     -2,     -2,
+       -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
+       -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+       -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+       -1,     -1,     -1,     -1,     -1,     -1,     -1,     0,
+       125,    121,    117,    113,    109,    105,    101,    97,
+       93,     89,     85,     81,     77,     73,     69,     65,
+       62,     60,     58,     56,     54,     52,     50,     48,
+       46,     44,     42,     40,     38,     36,     34,     32,
+       30,     29,     28,     27,     26,     25,     24,     23,
+       22,     21,     20,     19,     18,     17,     16,     15,
+       15,     14,     14,     13,     13,     12,     12,     11,
+       11,     10,     10,     9,      9,      8,      8,      7,
+       7,      7,      6,      6,      6,      6,      5,      5,
+       5,      5,      4,      4,      4,      4,      3,      3,
+       3,      3,      3,      3,      2,      2,      2,      2,
+       2,      2,      2,      2,      1,      1,      1,      1,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0
 };
 
 /* 8 bit A-law */
 
 static char alaw2dma8[] = {
-     -22,    -21,    -24,    -23,    -18,    -17,    -20,    -19,
-     -30,    -29,    -32,    -31,    -26,    -25,    -28,    -27,
-     -11,    -11,    -12,    -12,     -9,     -9,    -10,    -10,
-     -15,    -15,    -16,    -16,    -13,    -13,    -14,    -14,
-     -86,    -82,    -94,    -90,    -70,    -66,    -78,    -74,
-    -118,   -114,   -126,   -122,   -102,    -98,   -110,   -106,
-     -43,    -41,    -47,    -45,    -35,    -33,    -39,    -37,
-     -59,    -57,    -63,    -61,    -51,    -49,    -55,    -53,
-      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
-      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
-      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
-      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
-      -6,     -6,     -6,     -6,     -5,     -5,     -5,     -5,
-      -8,     -8,     -8,     -8,     -7,     -7,     -7,     -7,
-      -3,     -3,     -3,     -3,     -3,     -3,     -3,     -3,
-      -4,     -4,     -4,     -4,     -4,     -4,     -4,     -4,
-      21,     20,     23,     22,     17,     16,     19,     18,
-      29,     28,     31,     30,     25,     24,     27,     26,
-      10,     10,     11,     11,      8,      8,      9,      9,
-      14,     14,     15,     15,     12,     12,     13,     13,
-      86,     82,     94,     90,     70,     66,     78,     74,
-     118,    114,    126,    122,    102,     98,    110,    106,
-      43,     41,     47,     45,     35,     33,     39,     37,
-      59,     57,     63,     61,     51,     49,     55,     53,
-       1,      1,      1,      1,      1,      1,      1,      1,
-       1,      1,      1,      1,      1,      1,      1,      1,
-       0,      0,      0,      0,      0,      0,      0,      0,
-       0,      0,      0,      0,      0,      0,      0,      0,
-       5,      5,      5,      5,      4,      4,      4,      4,
-       7,      7,      7,      7,      6,      6,      6,      6,
-       2,      2,      2,      2,      2,      2,      2,      2,
-       3,      3,      3,      3,      3,      3,      3,      3
+       -22,    -21,    -24,    -23,    -18,    -17,    -20,    -19,
+       -30,    -29,    -32,    -31,    -26,    -25,    -28,    -27,
+       -11,    -11,    -12,    -12,    -9,     -9,     -10,    -10,
+       -15,    -15,    -16,    -16,    -13,    -13,    -14,    -14,
+       -86,    -82,    -94,    -90,    -70,    -66,    -78,    -74,
+       -118,   -114,   -126,   -122,   -102,   -98,    -110,   -106,
+       -43,    -41,    -47,    -45,    -35,    -33,    -39,    -37,
+       -59,    -57,    -63,    -61,    -51,    -49,    -55,    -53,
+       -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
+       -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
+       -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+       -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+       -6,     -6,     -6,     -6,     -5,     -5,     -5,     -5,
+       -8,     -8,     -8,     -8,     -7,     -7,     -7,     -7,
+       -3,     -3,     -3,     -3,     -3,     -3,     -3,     -3,
+       -4,     -4,     -4,     -4,     -4,     -4,     -4,     -4,
+       21,     20,     23,     22,     17,     16,     19,     18,
+       29,     28,     31,     30,     25,     24,     27,     26,
+       10,     10,     11,     11,     8,      8,      9,      9,
+       14,     14,     15,     15,     12,     12,     13,     13,
+       86,     82,     94,     90,     70,     66,     78,     74,
+       118,    114,    126,    122,    102,    98,     110,    106,
+       43,     41,     47,     45,     35,     33,     39,     37,
+       59,     57,     63,     61,     51,     49,     55,     53,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       5,      5,      5,      5,      4,      4,      4,      4,
+       7,      7,      7,      7,      6,      6,      6,      6,
+       2,      2,      2,      2,      2,      2,      2,      2,
+       3,      3,      3,      3,      3,      3,      3,      3
 };
-
+#endif /* HAS_8BIT_TABLES */
 
 #ifdef HAS_16BIT_TABLES
 
 /* 16 bit mu-law */
 
-static char ulaw2dma16[] = {
-    -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
-    -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
-    -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
-    -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
-     -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
-     -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
-     -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
-     -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
-     -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
-     -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
-      -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
-      -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
-      -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
-      -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
-      -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
-       -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
-     32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
-     23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
-     15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
-     11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
-      7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
-      5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
-      3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
-      2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
-      1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
-      1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
-       876,    844,    812,    780,    748,    716,    684,    652,
-       620,    588,    556,    524,    492,    460,    428,    396,
-       372,    356,    340,    324,    308,    292,    276,    260,
-       244,    228,    212,    196,    180,    164,    148,    132,
-       120,    112,    104,     96,     88,     80,     72,     64,
-        56,     48,     40,     32,     24,     16,      8,      0,
+static short ulaw2dma16[] = {
+       -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
+       -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
+       -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
+       -11900, -11388, -10876, -10364, -9852,  -9340,  -8828,  -8316,
+       -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
+       -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
+       -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
+       -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
+       -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
+       -1372,  -1308,  -1244,  -1180,  -1116,  -1052,  -988,   -924,
+       -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
+       -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
+       -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
+       -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
+       -120,   -112,   -104,   -96,    -88,    -80,    -72,    -64,
+       -56,    -48,    -40,    -32,    -24,    -16,    -8,     0,
+       32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
+       23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
+       15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
+       11900,  11388,  10876,  10364,  9852,   9340,   8828,   8316,
+       7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
+       5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
+       3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
+       2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
+       1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
+       1372,   1308,   1244,   1180,   1116,   1052,   988,    924,
+       876,    844,    812,    780,    748,    716,    684,    652,
+       620,    588,    556,    524,    492,    460,    428,    396,
+       372,    356,    340,    324,    308,    292,    276,    260,
+       244,    228,    212,    196,    180,    164,    148,    132,
+       120,    112,    104,    96,     88,     80,     72,     64,
+       56,     48,     40,     32,     24,     16,     8,      0,
 };
 
 /* 16 bit A-law */
 
-static char alaw2dma16[] = {
-     -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
-     -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
-     -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
-     -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
-    -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
-    -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
-    -11008, -10496, -12032, -11520,  -8960,  -8448,  -9984,  -9472,
-    -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
-      -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
-      -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
-       -88,    -72,   -120,   -104,    -24,     -8,    -56,    -40,
-      -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
-     -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
-     -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
-      -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
-      -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848,
-      5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
-      7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
-      2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
-      3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
-     22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
-     30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
-     11008,  10496,  12032,  11520,   8960,   8448,   9984,   9472,
-     15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
-       344,    328,    376,    360,    280,    264,    312,    296,
-       472,    456,    504,    488,    408,    392,    440,    424,
-        88,     72,    120,    104,     24,      8,     56,     40,
-       216,    200,    248,    232,    152,    136,    184,    168,
-      1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
-      1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
-       688,    656,    752,    720,    560,    528,    624,    592,
-       944,    912,   1008,    976,    816,    784,    880,    848,
+static short alaw2dma16[] = {
+       -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
+       -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
+       -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
+       -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
+       -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
+       -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
+       -11008, -10496, -12032, -11520, -8960,  -8448,  -9984,  -9472,
+       -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
+       -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
+       -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
+       -88,    -72,    -120,   -104,   -24,    -8,     -56,    -40,
+       -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
+       -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
+       -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
+       -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
+       -944,   -912,   -1008,  -976,   -816,   -784,   -880,   -848,
+       5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
+       7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
+       2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
+       3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
+       22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
+       30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
+       11008,  10496,  12032,  11520,  8960,   8448,   9984,   9472,
+       15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
+       344,    328,    376,    360,    280,    264,    312,    296,
+       472,    456,    504,    488,    408,    392,    440,    424,
+       88,     72,     120,    104,    24,     8,      56,     40,
+       216,    200,    248,    232,    152,    136,    184,    168,
+       1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
+       1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
+       688,    656,    752,    720,    560,    528,    624,    592,
+       944,    912,    1008,   976,    816,    784,    880,    848,
 };
 #endif /* HAS_16BIT_TABLES */
 
@@ -332,75 +433,75 @@ static char alaw2dma16[] = {
 /* 14 bit mu-law (LSB) */
 
 static char alaw2dma14l[] = {
-        33,     33,     33,     33,     33,     33,     33,     33,
-        33,     33,     33,     33,     33,     33,     33,     33,
-        33,     33,     33,     33,     33,     33,     33,     33,
-        33,     33,     33,     33,     33,     33,     33,     33,
-         1,      1,      1,      1,      1,      1,      1,      1,
-         1,      1,      1,      1,      1,      1,      1,      1,
-        49,     17,     49,     17,     49,     17,     49,     17,
-        49,     17,     49,     17,     49,     17,     49,     17,
-        41,     57,      9,     25,     41,     57,      9,     25,
-        41,     57,      9,     25,     41,     57,      9,     25,
-        37,     45,     53,     61,      5,     13,     21,     29,
-        37,     45,     53,     61,      5,     13,     21,     29,
-        35,     39,     43,     47,     51,     55,     59,     63,
-         3,      7,     11,     15,     19,     23,     27,     31,
-        34,     36,     38,     40,     42,     44,     46,     48,
-        50,     52,     54,     56,     58,     60,     62,      0,
-        31,     31,     31,     31,     31,     31,     31,     31,
-        31,     31,     31,     31,     31,     31,     31,     31,
-        31,     31,     31,     31,     31,     31,     31,     31,
-        31,     31,     31,     31,     31,     31,     31,     31,
-        63,     63,     63,     63,     63,     63,     63,     63,
-        63,     63,     63,     63,     63,     63,     63,     63,
-        15,     47,     15,     47,     15,     47,     15,     47,
-        15,     47,     15,     47,     15,     47,     15,     47,
-        23,      7,     55,     39,     23,      7,     55,     39,
-        23,      7,     55,     39,     23,      7,     55,     39,
-        27,     19,     11,      3,     59,     51,     43,     35,
-        27,     19,     11,      3,     59,     51,     43,     35,
-        29,     25,     21,     17,     13,      9,      5,      1,
-        61,     57,     53,     49,     45,     41,     37,     33,
-        30,     28,     26,     24,     22,     20,     18,     16,
-        14,     12,     10,      8,      6,      4,      2,      0
+       33,     33,     33,     33,     33,     33,     33,     33,
+       33,     33,     33,     33,     33,     33,     33,     33,
+       33,     33,     33,     33,     33,     33,     33,     33,
+       33,     33,     33,     33,     33,     33,     33,     33,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       49,     17,     49,     17,     49,     17,     49,     17,
+       49,     17,     49,     17,     49,     17,     49,     17,
+       41,     57,     9,      25,     41,     57,     9,      25,
+       41,     57,     9,      25,     41,     57,     9,      25,
+       37,     45,     53,     61,     5,      13,     21,     29,
+       37,     45,     53,     61,     5,      13,     21,     29,
+       35,     39,     43,     47,     51,     55,     59,     63,
+       3,      7,      11,     15,     19,     23,     27,     31,
+       34,     36,     38,     40,     42,     44,     46,     48,
+       50,     52,     54,     56,     58,     60,     62,     0,
+       31,     31,     31,     31,     31,     31,     31,     31,
+       31,     31,     31,     31,     31,     31,     31,     31,
+       31,     31,     31,     31,     31,     31,     31,     31,
+       31,     31,     31,     31,     31,     31,     31,     31,
+       63,     63,     63,     63,     63,     63,     63,     63,
+       63,     63,     63,     63,     63,     63,     63,     63,
+       15,     47,     15,     47,     15,     47,     15,     47,
+       15,     47,     15,     47,     15,     47,     15,     47,
+       23,     7,      55,     39,     23,     7,      55,     39,
+       23,     7,      55,     39,     23,     7,      55,     39,
+       27,     19,     11,     3,      59,     51,     43,     35,
+       27,     19,     11,     3,      59,     51,     43,     35,
+       29,     25,     21,     17,     13,     9,      5,      1,
+       61,     57,     53,     49,     45,     41,     37,     33,
+       30,     28,     26,     24,     22,     20,     18,     16,
+       14,     12,     10,     8,      6,      4,      2,      0
 };
 
 /* 14 bit A-law (LSB) */
 
 static char alaw2dma14l[] = {
-        32,     32,     32,     32,     32,     32,     32,     32,
-        32,     32,     32,     32,     32,     32,     32,     32,
-        16,     48,     16,     48,     16,     48,     16,     48,
-        16,     48,     16,     48,     16,     48,     16,     48,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-        42,     46,     34,     38,     58,     62,     50,     54,
-        10,     14,      2,      6,     26,     30,     18,     22,
-        42,     46,     34,     38,     58,     62,     50,     54,
-        10,     14,      2,      6,     26,     30,     18,     22,
-        40,     56,      8,     24,     40,     56,      8,     24,
-        40,     56,      8,     24,     40,     56,      8,     24,
-        20,     28,      4,     12,     52,     60,     36,     44,
-        20,     28,      4,     12,     52,     60,     36,     44,
-        32,     32,     32,     32,     32,     32,     32,     32,
-        32,     32,     32,     32,     32,     32,     32,     32,
-        48,     16,     48,     16,     48,     16,     48,     16,
-        48,     16,     48,     16,     48,     16,     48,     16,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-         0,      0,      0,      0,      0,      0,      0,      0,
-        22,     18,     30,     26,      6,      2,     14,     10,
-        54,     50,     62,     58,     38,     34,     46,     42,
-        22,     18,     30,     26,      6,      2,     14,     10,
-        54,     50,     62,     58,     38,     34,     46,     42,
-        24,      8,     56,     40,     24,      8,     56,     40,
-        24,      8,     56,     40,     24,      8,     56,     40,
-        44,     36,     60,     52,     12,      4,     28,     20,
-        44,     36,     60,     52,     12,      4,     28,     20
+       32,     32,     32,     32,     32,     32,     32,     32,
+       32,     32,     32,     32,     32,     32,     32,     32,
+       16,     48,     16,     48,     16,     48,     16,     48,
+       16,     48,     16,     48,     16,     48,     16,     48,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       42,     46,     34,     38,     58,     62,     50,     54,
+       10,     14,     2,      6,      26,     30,     18,     22,
+       42,     46,     34,     38,     58,     62,     50,     54,
+       10,     14,     2,      6,      26,     30,     18,     22,
+       40,     56,     8,      24,     40,     56,     8,      24,
+       40,     56,     8,      24,     40,     56,     8,      24,
+       20,     28,     4,      12,     52,     60,     36,     44,
+       20,     28,     4,      12,     52,     60,     36,     44,
+       32,     32,     32,     32,     32,     32,     32,     32,
+       32,     32,     32,     32,     32,     32,     32,     32,
+       48,     16,     48,     16,     48,     16,     48,     16,
+       48,     16,     48,     16,     48,     16,     48,     16,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       22,     18,     30,     26,     6,      2,      14,     10,
+       54,     50,     62,     58,     38,     34,     46,     42,
+       22,     18,     30,     26,     6,      2,      14,     10,
+       54,     50,     62,     58,     38,     34,     46,     42,
+       24,     8,      56,     40,     24,     8,      56,     40,
+       24,     8,      56,     40,     24,     8,      56,     40,
+       44,     36,     60,     52,     12,     4,      28,     20,
+       44,     36,     60,     52,     12,     4,      28,     20
 };
 #endif /* HAS_14BIT_TABLES */
 
@@ -456,26 +557,48 @@ static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount,
                         u_char frame[], long *frameUsed, long frameLeft);
 #endif /* CONFIG_AMIGA */
 
+#ifdef CONFIG_PMAC
+static long pmac_ct_law(const u_char *userPtr, unsigned long userCount,
+                       u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_s8(const u_char *userPtr, unsigned long userCount,
+                      u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_u8(const u_char *userPtr, unsigned long userCount,
+                      u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_s16(const u_char *userPtr, unsigned long userCount,
+                       u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_u16(const u_char *userPtr, unsigned long userCount,
+                       u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_law(const u_char *userPtr, unsigned long userCount,
+                        u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_s8(const u_char *userPtr, unsigned long userCount,
+                       u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_u8(const u_char *userPtr, unsigned long userCount,
+                       u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_s16(const u_char *userPtr, unsigned long userCount,
+                        u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_u16(const u_char *userPtr, unsigned long userCount,
+                        u_char frame[], long *frameUsed, long frameLeft);
+#endif /* CONFIG_PMAC */
 
 /*** Machine definitions *****************************************************/
 
 
 typedef struct {
-    int type;
-    void *(*dma_alloc)(unsigned int, int);
-    void (*dma_free)(void *, unsigned int);
-    int (*irqinit)(void);
+       int type;
+       void *(*dma_alloc)(unsigned int, int);
+       void (*dma_free)(void *, unsigned int);
+       int (*irqinit)(void);
 #ifdef MODULE
-    void (*irqcleanup)(void);
+       void (*irqcleanup)(void);
 #endif /* MODULE */
-    void (*init)(void);
-    void (*silence)(void);
-    int (*setFormat)(int);
-    int (*setVolume)(int);
-    int (*setBass)(int);
-    int (*setTreble)(int);
-    int (*setGain)(int);
-    void (*play)(void);
+       void (*init)(void);
+       void (*silence)(void);
+       int (*setFormat)(int);
+       int (*setVolume)(int);
+       int (*setBass)(int);
+       int (*setTreble)(int);
+       int (*setGain)(int);
+       void (*play)(void);
 } MACHINE;
 
 
@@ -483,38 +606,38 @@ typedef struct {
 
 
 typedef struct {
-    int format;                /* AFMT_* */
-    int stereo;                /* 0 = mono, 1 = stereo */
-    int size;          /* 8/16 bit*/
-    int speed;         /* speed */
+       int format;             /* AFMT_* */
+       int stereo;             /* 0 = mono, 1 = stereo */
+       int size;               /* 8/16 bit*/
+       int speed;              /* speed */
 } SETTINGS;
 
 typedef struct {
-    long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long);
-    long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long);
+       long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long);
+       long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long);
+       long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long);
+       long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long);
+       long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long);
+       long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long);
+       long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long);
+       long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long);
 } TRANS;
 
 struct sound_settings {
-    MACHINE mach;      /* machine dependent things */
-    SETTINGS hard;     /* hardware settings */
-    SETTINGS soft;     /* software settings */
-    SETTINGS dsp;      /* /dev/dsp default settings */
-    TRANS *trans;      /* supported translations */
-    int volume_left;   /* volume (range is machine dependent) */
-    int volume_right;
-    int bass;          /* tone (range is machine dependent) */
-    int treble;
-    int gain;
-    int minDev;                /* minor device number currently open */
-#ifdef CONFIG_ATARI
-    int bal;           /* balance factor for expanding (not volume!) */
-    u_long data;       /* data for expanding */
+       MACHINE mach;           /* machine dependent things */
+       SETTINGS hard;          /* hardware settings */
+       SETTINGS soft;          /* software settings */
+       SETTINGS dsp;           /* /dev/dsp default settings */
+       TRANS *trans;           /* supported translations */
+       int volume_left;        /* volume (range is machine dependent) */
+       int volume_right;
+       int bass;               /* tone (range is machine dependent) */
+       int treble;
+       int gain;
+       int minDev;             /* minor device number currently open */
+#if defined(CONFIG_ATARI) || defined(CONFIG_PMAC)
+       int bal;                /* balance factor for expanding (not volume!) */
+       u_long data;            /* data for expanding */
 #endif /* CONFIG_ATARI */
 };
 
@@ -561,6 +684,26 @@ static void AmiPlay(void);
 static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
 #endif /* CONFIG_AMIGA */
 
+#ifdef CONFIG_PMAC
+static void *PMacAlloc(unsigned int size, int flags);
+static void PMacFree(void *ptr, unsigned int size);
+static int PMacIrqInit(void);
+#ifdef MODULE
+static void PMacIrqCleanup(void);
+#endif /* MODULE */
+static void PMacSilence(void);
+static void PMacInit(void);
+static void PMacPlay(void);
+static int PMacSetFormat(int format);
+static int PMacSetVolume(int volume);
+static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
+static void awacs_write(int val);
+static int awacs_get_volume(int reg, int lshift);
+static int awacs_volume_setter(int volume, int n, int mute, int lshift);
+static void awacs_mksound(unsigned int hz, unsigned int ticks);
+static void awacs_nosound(unsigned long xx);
+#endif /* CONFIG_PMAC */
 
 /*** Mid level stuff *********************************************************/
 
@@ -574,7 +717,9 @@ static int sound_set_volume(int volume);
 #ifdef CONFIG_ATARI
 static int sound_set_bass(int bass);
 #endif /* CONFIG_ATARI */
+#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
 static int sound_set_treble(int treble);
+#endif /* CONFIG_ATARI || CONFIG_AMIGA */
 static long sound_copy_translate(const u_char *userPtr,
                                 unsigned long userCount,
                                 u_char frame[], long *frameUsed,
@@ -603,29 +748,30 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
  */
 
 struct sound_queue {
-    int max_count, block_size;
-    char **buffers;
-
-    /* it shouldn't be necessary to declare any of these volatile */
-    int front, rear, count;
-    int rear_size;
-    /*
-     * The use of the playing field depends on the hardware
-     *
-     * Atari: The number of frames that are loaded/playing
-     *
-     * Amiga: Bit 0 is set: a frame is loaded
-     *        Bit 1 is set: a frame is playing
-     */
-    int playing;
-    struct wait_queue *write_queue, *open_queue, *sync_queue;
-    int open_mode;
-    int busy, syncing;
+       int max_count, block_size;
+       char **buffers;
+       int max_active;
+
+       /* it shouldn't be necessary to declare any of these volatile */
+       int front, rear, count;
+       int rear_size;
+       /*
+        *      The use of the playing field depends on the hardware
+        *
+        *      Atari, PMac: The number of frames that are loaded/playing
+        *
+        *      Amiga: Bit 0 is set: a frame is loaded
+        *             Bit 1 is set: a frame is playing
+        */
+       int playing;
+       struct wait_queue *write_queue, *open_queue, *sync_queue;
+       int open_mode;
+       int busy, syncing;
 #ifdef CONFIG_ATARI
-    int ignore_int;            /* ++TeSche: used for Falcon */
+       int ignore_int;         /* ++TeSche: used for Falcon */
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-    int block_size_half, block_size_quarter;
+       int block_size_half, block_size_quarter;
 #endif /* CONFIG_AMIGA */
 };
 
@@ -648,6 +794,7 @@ static int sq_open(int open_mode);
 static void sq_reset(void);
 static int sq_sync(void);
 static int sq_release(void);
+static void init_settings(void);
 
 
 /*
@@ -655,9 +802,9 @@ static int sq_release(void);
  */
 
 struct sound_state {
-    int busy;
-    char buf[512];
-    int len, ptr;
+       int busy;
+       char buf[512];
+       int len, ptr;
 };
 
 static struct sound_state state;
@@ -681,10 +828,10 @@ static ssize_t sound_write(struct file *file, const char *buf, size_t count,
                           loff_t *ppos);
 static inline int ioctl_return(int *addr, int value)
 {
-    if (value < 0)
-       return(value);
+       if (value < 0)
+               return(value);
 
-    return put_user(value, addr);
+       return put_user(value, addr)? -EFAULT: 0;
 }
 static int unknown_minor_dev(char *fname, int dev);
 static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
@@ -730,554 +877,581 @@ void sound_setup(char *str, int *ints);         /* ++Martin: stub for now */
 static long ata_ct_law(const u_char *userPtr, unsigned long userCount,
                       u_char frame[], long *frameUsed, long frameLeft)
 {
-    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-    long count, used;
-    u_char *p = &frame[*frameUsed];
+       char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+       long count, used;
+       u_char *p = &frame[*frameUsed];
 
-    count = min(userCount, frameLeft);
-    if (sound.soft.stereo)
-       count &= ~1;
-    used = count;
-    while (count > 0) {
-       u_char data;
-       get_user(data, userPtr++);
-       *p++ = table[data];
-       count--;
-    }
-    *frameUsed += used;
-    return(used);
+       count = min(userCount, frameLeft);
+       if (sound.soft.stereo)
+               count &= ~1;
+       used = count;
+       while (count > 0) {
+               u_char data;
+               if (get_user(data, userPtr++))
+                       return -EFAULT;
+               *p++ = table[data];
+               count--;
+       }
+       *frameUsed += used;
+       return(used);
 }
 
 
 static long ata_ct_s8(const u_char *userPtr, unsigned long userCount,
                      u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    void *p = &frame[*frameUsed];
+       long count, used;
+       void *p = &frame[*frameUsed];
 
-    count = min(userCount, frameLeft);
-    if (sound.soft.stereo)
-       count &= ~1;
-    used = count;
-    copy_from_user(p, userPtr, count);
-    *frameUsed += used;
-    return(used);
+       count = min(userCount, frameLeft);
+       if (sound.soft.stereo)
+               count &= ~1;
+       used = count;
+       if (copy_from_user(p, userPtr, count))
+               return -EFAULT;
+       *frameUsed += used;
+       return(used);
 }
 
 
 static long ata_ct_u8(const u_char *userPtr, unsigned long userCount,
                      u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-
-    if (!sound.soft.stereo) {
-       u_char *p = &frame[*frameUsed];
-       count = min(userCount, frameLeft);
-       used = count;
-       while (count > 0) {
-           u_char data;
-           get_user(data, userPtr++);
-           *p++ = data ^ 0x80;
-           count--;
-       }
-    } else {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       count = min(userCount, frameLeft)>>1;
-       used = count*2;
-       while (count > 0) {
-           u_short data;
-           get_user(data, ((u_short *)userPtr)++);
-           *p++ = data ^ 0x8080;
-           count--;
+       long count, used;
+
+       if (!sound.soft.stereo) {
+               u_char *p = &frame[*frameUsed];
+               count = min(userCount, frameLeft);
+               used = count;
+               while (count > 0) {
+                       u_char data;
+                       if (get_user(data, userPtr++))
+                               return -EFAULT;
+                       *p++ = data ^ 0x80;
+                       count--;
+               }
+       } else {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               count = min(userCount, frameLeft)>>1;
+               used = count*2;
+               while (count > 0) {
+                       u_short data;
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       *p++ = data ^ 0x8080;
+                       count--;
+               }
        }
-    }
-    *frameUsed += used;
-    return(used);
+       *frameUsed += used;
+       return(used);
 }
 
 
 static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount,
                         u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
-
-    if (!sound.soft.stereo) {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       count = min(userCount, frameLeft)>>1;
-       used = count*2;
-       while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           *p++ = data;
-           *p++ = data;
-           count--;
-       }
-       *frameUsed += used*2;
-    } else {
-       void *p = (u_short *)&frame[*frameUsed];
-       count = min(userCount, frameLeft) & ~3;
-       used = count;
-       copy_from_user(p, userPtr, count);
-       *frameUsed += used;
-    }
-    return(used);
+       long count, used;
+       u_long data;
+
+       if (!sound.soft.stereo) {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               count = min(userCount, frameLeft)>>1;
+               used = count*2;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       *p++ = data;
+                       *p++ = data;
+                       count--;
+               }
+               *frameUsed += used*2;
+       } else {
+               void *p = (u_short *)&frame[*frameUsed];
+               count = min(userCount, frameLeft) & ~3;
+               used = count;
+               if (copy_from_user(p, userPtr, count))
+                       return -EFAULT;
+               *frameUsed += used;
+       }
+       return(used);
 }
 
 
 static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount,
                         u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
-
-    if (!sound.soft.stereo) {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       count = min(userCount, frameLeft)>>1;
-       used = count*2;
-       while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           data ^= 0x8000;
-           *p++ = data;
-           *p++ = data;
-           count--;
-       }
-       *frameUsed += used*2;
-    } else {
-       u_long *p = (u_long *)&frame[*frameUsed];
-       count = min(userCount, frameLeft)>>2;
-       used = count*4;
-       while (count > 0) {
-           get_user(data, ((u_int *)userPtr)++);
-           *p++ = data ^ 0x80008000;
-           count--;
+       long count, used;
+       u_long data;
+
+       if (!sound.soft.stereo) {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               count = min(userCount, frameLeft)>>1;
+               used = count*2;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data ^= 0x8000;
+                       *p++ = data;
+                       *p++ = data;
+                       count--;
+               }
+               *frameUsed += used*2;
+       } else {
+               u_long *p = (u_long *)&frame[*frameUsed];
+               count = min(userCount, frameLeft)>>2;
+               used = count*4;
+               while (count > 0) {
+                       if (get_user(data, ((u_int *)userPtr)++))
+                               return -EFAULT;
+                       *p++ = data ^ 0x80008000;
+                       count--;
+               }
+               *frameUsed += used;
        }
-       *frameUsed += used;
-    }
-    return(used);
+       return(used);
 }
 
 
 static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount,
                         u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
-
-    count = frameLeft;
-    if (!sound.soft.stereo) {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       count = min(userCount, frameLeft)>>1;
-       used = count*2;
-       while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           data = le2be16(data);
-           *p++ = data;
-           *p++ = data;
-           count--;
-       }
-       *frameUsed += used*2;
-    } else {
-       u_long *p = (u_long *)&frame[*frameUsed];
-       count = min(userCount, frameLeft)>>2;
-       used = count*4;
-       while (count > 0) {
-           get_user(data, ((u_int *)userPtr)++);
-           data = le2be16dbl(data);
-           *p++ = data;
-           count--;
+       long count, used;
+       u_long data;
+
+       count = frameLeft;
+       if (!sound.soft.stereo) {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               count = min(userCount, frameLeft)>>1;
+               used = count*2;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data = le2be16(data);
+                       *p++ = data;
+                       *p++ = data;
+                       count--;
+               }
+               *frameUsed += used*2;
+       } else {
+               u_long *p = (u_long *)&frame[*frameUsed];
+               count = min(userCount, frameLeft)>>2;
+               used = count*4;
+               while (count > 0) {
+                       if (get_user(data, ((u_int *)userPtr)++))
+                               return -EFAULT;
+                       data = le2be16dbl(data);
+                       *p++ = data;
+                       count--;
+               }
+               *frameUsed += used;
        }
-       *frameUsed += used;
-    }
-    return(used);
+       return(used);
 }
 
 
 static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount,
                         u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
-
-    count = frameLeft;
-    if (!sound.soft.stereo) {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       count = min(userCount, frameLeft)>>1;
-       used = count*2;
-       while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           data = le2be16(data) ^ 0x8000;
-           *p++ = data;
-           *p++ = data;
-       }
-       *frameUsed += used*2;
-    } else {
-       u_long *p = (u_long *)&frame[*frameUsed];
-       count = min(userCount, frameLeft)>>2;
-       used = count;
-       while (count > 0) {
-           get_user(data, ((u_int *)userPtr)++);
-           data = le2be16dbl(data) ^ 0x80008000;
-           *p++ = data;
-           count--;
+       long count, used;
+       u_long data;
+
+       count = frameLeft;
+       if (!sound.soft.stereo) {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               count = min(userCount, frameLeft)>>1;
+               used = count*2;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data = le2be16(data) ^ 0x8000;
+                       *p++ = data;
+                       *p++ = data;
+               }
+               *frameUsed += used*2;
+       } else {
+               u_long *p = (u_long *)&frame[*frameUsed];
+               count = min(userCount, frameLeft)>>2;
+               used = count;
+               while (count > 0) {
+                       if (get_user(data, ((u_int *)userPtr)++))
+                               return -EFAULT;
+                       data = le2be16dbl(data) ^ 0x80008000;
+                       *p++ = data;
+                       count--;
+               }
+               *frameUsed += used;
        }
-       *frameUsed += used;
-    }
-    return(used);
+       return(used);
 }
 
 
 static long ata_ctx_law(const u_char *userPtr, unsigned long userCount,
                        u_char frame[], long *frameUsed, long frameLeft)
 {
-    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-       u_char *p = &frame[*frameUsed];
-       while (frameLeft) {
-           u_char c;
-           if (bal < 0) {
-               if (!userCount)
-                   break;
-               get_user(c, userPtr++);
-               data = table[c];
-               userCount--;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           frameLeft--;
-           bal -= sSpeed;
-       }
-    } else {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       while (frameLeft >= 2) {
-           u_char c;
-           if (bal < 0) {
-               if (userCount < 2)
-                   break;
-               get_user(c, userPtr++);
-               data = table[c] << 8;
-               get_user(c, userPtr++);
-               data |= table[c];
-               userCount -= 2;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           frameLeft -= 2;
-           bal -= sSpeed;
-       }
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+       char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+       /* this should help gcc to stuff everything into registers */
+       u_long data = sound.data;
+       long bal = sound.bal;
+       long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       long used, usedf;
+
+       used = userCount;
+       usedf = frameLeft;
+       if (!sound.soft.stereo) {
+               u_char *p = &frame[*frameUsed];
+               while (frameLeft) {
+                       u_char c;
+                       if (bal < 0) {
+                               if (!userCount)
+                                       break;
+                               if (get_user(c, userPtr++))
+                                       return -EFAULT;
+                               data = table[c];
+                               userCount--;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       frameLeft--;
+                       bal -= sSpeed;
+               }
+       } else {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               while (frameLeft >= 2) {
+                       u_char c;
+                       if (bal < 0) {
+                               if (userCount < 2)
+                                       break;
+                               if (get_user(c, userPtr++))
+                                       return -EFAULT;
+                               data = table[c] << 8;
+                               if (get_user(c, userPtr++))
+                                       return -EFAULT;
+                               data |= table[c];
+                               userCount -= 2;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       frameLeft -= 2;
+                       bal -= sSpeed;
+               }
+       }
+       sound.bal = bal;
+       sound.data = data;
+       used -= userCount;
+       *frameUsed += usedf-frameLeft;
+       return(used);
 }
 
 
 static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount,
                       u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-       u_char *p = &frame[*frameUsed];
-       while (frameLeft) {
-           if (bal < 0) {
-               if (!userCount)
-                   break;
-               get_user(data, userPtr++);
-               userCount--;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           frameLeft--;
-           bal -= sSpeed;
-       }
-    } else {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       while (frameLeft >= 2) {
-           if (bal < 0) {
-               if (userCount < 2)
-                   break;
-               get_user(data, ((u_short *)userPtr)++);
-               userCount -= 2;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           frameLeft -= 2;
-           bal -= sSpeed;
-       }
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+       /* this should help gcc to stuff everything into registers */
+       u_long data = sound.data;
+       long bal = sound.bal;
+       long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       long used, usedf;
+
+       used = userCount;
+       usedf = frameLeft;
+       if (!sound.soft.stereo) {
+               u_char *p = &frame[*frameUsed];
+               while (frameLeft) {
+                       if (bal < 0) {
+                               if (!userCount)
+                                       break;
+                               if (get_user(data, userPtr++))
+                                       return -EFAULT;
+                               userCount--;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       frameLeft--;
+                       bal -= sSpeed;
+               }
+       } else {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               while (frameLeft >= 2) {
+                       if (bal < 0) {
+                               if (userCount < 2)
+                                       break;
+                               if (get_user(data, ((u_short *)userPtr)++))
+                                       return -EFAULT;
+                               userCount -= 2;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       frameLeft -= 2;
+                       bal -= sSpeed;
+               }
+       }
+       sound.bal = bal;
+       sound.data = data;
+       used -= userCount;
+       *frameUsed += usedf-frameLeft;
+       return(used);
 }
 
 
 static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount,
                       u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-       u_char *p = &frame[*frameUsed];
-       while (frameLeft) {
-           if (bal < 0) {
-               if (!userCount)
-                   break;
-               get_user(data, userPtr++);
-               data ^= 0x80;
-               userCount--;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           frameLeft--;
-           bal -= sSpeed;
-       }
-    } else {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       while (frameLeft >= 2) {
-           if (bal < 0) {
-               if (userCount < 2)
-                   break;
-               get_user(data, ((u_short *)userPtr)++);
-               data ^= 0x8080;
-               userCount -= 2;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           frameLeft -= 2;
-           bal -= sSpeed;
-       }
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+       /* this should help gcc to stuff everything into registers */
+       u_long data = sound.data;
+       long bal = sound.bal;
+       long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       long used, usedf;
+
+       used = userCount;
+       usedf = frameLeft;
+       if (!sound.soft.stereo) {
+               u_char *p = &frame[*frameUsed];
+               while (frameLeft) {
+                       if (bal < 0) {
+                               if (!userCount)
+                                       break;
+                               if (get_user(data, userPtr++))
+                                       return -EFAULT;
+                               data ^= 0x80;
+                               userCount--;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       frameLeft--;
+                       bal -= sSpeed;
+               }
+       } else {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               while (frameLeft >= 2) {
+                       if (bal < 0) {
+                               if (userCount < 2)
+                                       break;
+                               if (get_user(data, ((u_short *)userPtr)++))
+                                       return -EFAULT;
+                               data ^= 0x8080;
+                               userCount -= 2;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       frameLeft -= 2;
+                       bal -= sSpeed;
+               }
+       }
+       sound.bal = bal;
+       sound.data = data;
+       used -= userCount;
+       *frameUsed += usedf-frameLeft;
+       return(used);
 }
 
 
 static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount,
                          u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       while (frameLeft >= 4) {
-           if (bal < 0) {
-               if (userCount < 2)
-                   break;
-               get_user(data, ((u_short *)userPtr)++);
-               userCount -= 2;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           *p++ = data;
-           frameLeft -= 4;
-           bal -= sSpeed;
-       }
-    } else {
-       u_long *p = (u_long *)&frame[*frameUsed];
-       while (frameLeft >= 4) {
-           if (bal < 0) {
-               if (userCount < 4)
-                   break;
-               get_user(data, ((u_int *)userPtr)++);
-               userCount -= 4;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           frameLeft -= 4;
-           bal -= sSpeed;
-       }
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+       /* this should help gcc to stuff everything into registers */
+       u_long data = sound.data;
+       long bal = sound.bal;
+       long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       long used, usedf;
+
+       used = userCount;
+       usedf = frameLeft;
+       if (!sound.soft.stereo) {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               while (frameLeft >= 4) {
+                       if (bal < 0) {
+                               if (userCount < 2)
+                                       break;
+                               if (get_user(data, ((u_short *)userPtr)++))
+                                       return -EFAULT;
+                               userCount -= 2;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       *p++ = data;
+                       frameLeft -= 4;
+                       bal -= sSpeed;
+               }
+       } else {
+               u_long *p = (u_long *)&frame[*frameUsed];
+               while (frameLeft >= 4) {
+                       if (bal < 0) {
+                               if (userCount < 4)
+                                       break;
+                               if (get_user(data, ((u_int *)userPtr)++))
+                                       return -EFAULT;
+                               userCount -= 4;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       frameLeft -= 4;
+                       bal -= sSpeed;
+               }
+       }
+       sound.bal = bal;
+       sound.data = data;
+       used -= userCount;
+       *frameUsed += usedf-frameLeft;
+       return(used);
 }
 
 
 static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount,
                          u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       while (frameLeft >= 4) {
-           if (bal < 0) {
-               if (userCount < 2)
-                   break;
-               get_user(data, ((u_short *)userPtr)++);
-               data ^= 0x8000;
-               userCount -= 2;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           *p++ = data;
-           frameLeft -= 4;
-           bal -= sSpeed;
-       }
-    } else {
-       u_long *p = (u_long *)&frame[*frameUsed];
-       while (frameLeft >= 4) {
-           if (bal < 0) {
-               if (userCount < 4)
-                   break;
-               get_user(data, ((u_int *)userPtr)++);
-               data ^= 0x80008000;
-               userCount -= 4;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           frameLeft -= 4;
-           bal -= sSpeed;
-       }
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+       /* this should help gcc to stuff everything into registers */
+       u_long data = sound.data;
+       long bal = sound.bal;
+       long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       long used, usedf;
+
+       used = userCount;
+       usedf = frameLeft;
+       if (!sound.soft.stereo) {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               while (frameLeft >= 4) {
+                       if (bal < 0) {
+                               if (userCount < 2)
+                                       break;
+                               if (get_user(data, ((u_short *)userPtr)++))
+                                       return -EFAULT;
+                               data ^= 0x8000;
+                               userCount -= 2;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       *p++ = data;
+                       frameLeft -= 4;
+                       bal -= sSpeed;
+               }
+       } else {
+               u_long *p = (u_long *)&frame[*frameUsed];
+               while (frameLeft >= 4) {
+                       if (bal < 0) {
+                               if (userCount < 4)
+                                       break;
+                               if (get_user(data, ((u_int *)userPtr)++))
+                                       return -EFAULT;
+                               data ^= 0x80008000;
+                               userCount -= 4;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       frameLeft -= 4;
+                       bal -= sSpeed;
+               }
+       }
+       sound.bal = bal;
+       sound.data = data;
+       used -= userCount;
+       *frameUsed += usedf-frameLeft;
+       return(used);
 }
 
 
 static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount,
                          u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       while (frameLeft >= 4) {
-           if (bal < 0) {
-               if (userCount < 2)
-                   break;
-               get_user(data, ((u_short *)userPtr)++);
-               data = le2be16(data);
-               userCount -= 2;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           *p++ = data;
-           frameLeft -= 4;
-           bal -= sSpeed;
-       }
-    } else {
-       u_long *p = (u_long *)&frame[*frameUsed];
-       while (frameLeft >= 4) {
-           if (bal < 0) {
-               if (userCount < 4)
-                   break;
-               get_user(data, ((u_int *)userPtr)++);
-               data = le2be16dbl(data);
-               userCount -= 4;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           frameLeft -= 4;
-           bal -= sSpeed;
-       }
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+       /* this should help gcc to stuff everything into registers */
+       u_long data = sound.data;
+       long bal = sound.bal;
+       long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       long used, usedf;
+
+       used = userCount;
+       usedf = frameLeft;
+       if (!sound.soft.stereo) {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               while (frameLeft >= 4) {
+                       if (bal < 0) {
+                               if (userCount < 2)
+                                       break;
+                               if (get_user(data, ((u_short *)userPtr)++))
+                                       return -EFAULT;
+                               data = le2be16(data);
+                               userCount -= 2;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       *p++ = data;
+                       frameLeft -= 4;
+                       bal -= sSpeed;
+               }
+       } else {
+               u_long *p = (u_long *)&frame[*frameUsed];
+               while (frameLeft >= 4) {
+                       if (bal < 0) {
+                               if (userCount < 4)
+                                       break;
+                               if (get_user(data, ((u_int *)userPtr)++))
+                                       return -EFAULT;
+                               data = le2be16dbl(data);
+                               userCount -= 4;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       frameLeft -= 4;
+                       bal -= sSpeed;
+               }
+       }
+       sound.bal = bal;
+       sound.data = data;
+       used -= userCount;
+       *frameUsed += usedf-frameLeft;
+       return(used);
 }
 
 
 static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount,
                          u_char frame[], long *frameUsed, long frameLeft)
 {
-    /* this should help gcc to stuff everything into registers */
-    u_long data = sound.data;
-    long bal = sound.bal;
-    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-    long used, usedf;
-
-    used = userCount;
-    usedf = frameLeft;
-    if (!sound.soft.stereo) {
-       u_short *p = (u_short *)&frame[*frameUsed];
-       while (frameLeft >= 4) {
-           if (bal < 0) {
-               if (userCount < 2)
-                   break;
-               get_user(data, ((u_short *)userPtr)++);
-               data = le2be16(data) ^ 0x8000;
-               userCount -= 2;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           *p++ = data;
-           frameLeft -= 4;
-           bal -= sSpeed;
-       }
-    } else {
-       u_long *p = (u_long *)&frame[*frameUsed];
-       while (frameLeft >= 4) {
-           if (bal < 0) {
-               if (userCount < 4)
-                   break;
-               get_user(data, ((u_int *)userPtr)++);
-               data = le2be16dbl(data) ^ 0x80008000;
-               userCount -= 4;
-               bal += hSpeed;
-           }
-           *p++ = data;
-           frameLeft -= 4;
-           bal -= sSpeed;
-       }
-    }
-    sound.bal = bal;
-    sound.data = data;
-    used -= userCount;
-    *frameUsed += usedf-frameLeft;
-    return(used);
+       /* this should help gcc to stuff everything into registers */
+       u_long data = sound.data;
+       long bal = sound.bal;
+       long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       long used, usedf;
+
+       used = userCount;
+       usedf = frameLeft;
+       if (!sound.soft.stereo) {
+               u_short *p = (u_short *)&frame[*frameUsed];
+               while (frameLeft >= 4) {
+                       if (bal < 0) {
+                               if (userCount < 2)
+                                       break;
+                               if (get_user(data, ((u_short *)userPtr)++))
+                                       return -EFAULT;
+                               data = le2be16(data) ^ 0x8000;
+                               userCount -= 2;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       *p++ = data;
+                       frameLeft -= 4;
+                       bal -= sSpeed;
+               }
+       } else {
+               u_long *p = (u_long *)&frame[*frameUsed];
+               while (frameLeft >= 4) {
+                       if (bal < 0) {
+                               if (userCount < 4)
+                                       break;
+                               if (get_user(data, ((u_int *)userPtr)++))
+                                       return -EFAULT;
+                               data = le2be16dbl(data) ^ 0x80008000;
+                               userCount -= 4;
+                               bal += hSpeed;
+                       }
+                       *p++ = data;
+                       frameLeft -= 4;
+                       bal -= sSpeed;
+               }
+       }
+       sound.bal = bal;
+       sound.data = data;
+       used -= userCount;
+       *frameUsed += usedf-frameLeft;
+       return(used);
 }
 #endif /* CONFIG_ATARI */
 
@@ -1286,291 +1460,698 @@ static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount,
 static long ami_ct_law(const u_char *userPtr, unsigned long userCount,
                       u_char frame[], long *frameUsed, long frameLeft)
 {
-    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-    long count, used;
-
-    if (!sound.soft.stereo) {
-       u_char *p = &frame[*frameUsed];
-       count = min(userCount, frameLeft) & ~1;
-       used = count;
-       while (count > 0) {
-           u_char data;
-           get_user(data, userPtr++);
-           *p++ = table[data];
-           count--;
-       }
-    } else {
-       u_char *left = &frame[*frameUsed>>1];
-       u_char *right = left+sq.block_size_half;
-       count = min(userCount, frameLeft)>>1 & ~1;
-       used = count*2;
-       while (count > 0) {
-           u_char data;
-           get_user(data, userPtr++);
-           *left++ = table[data];
-           get_user(data, userPtr++);
-           *right++ = table[data];
-           count--;
+       char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+       long count, used;
+
+       if (!sound.soft.stereo) {
+               u_char *p = &frame[*frameUsed];
+               count = min(userCount, frameLeft) & ~1;
+               used = count;
+               while (count > 0) {
+                       u_char data;
+                       if (get_user(data, userPtr++))
+                               return -EFAULT;
+                       *p++ = table[data];
+                       count--;
+               }
+       } else {
+               u_char *left = &frame[*frameUsed>>1];
+               u_char *right = left+sq.block_size_half;
+               count = min(userCount, frameLeft)>>1 & ~1;
+               used = count*2;
+               while (count > 0) {
+                       u_char data;
+                       if (get_user(data, userPtr++))
+                               return -EFAULT;
+                       *left++ = table[data];
+                       if (get_user(data, userPtr++))
+                               return -EFAULT;
+                       *right++ = table[data];
+                       count--;
+               }
        }
-    }
-    *frameUsed += used;
-    return(used);
+       *frameUsed += used;
+       return(used);
 }
 
 
 static long ami_ct_s8(const u_char *userPtr, unsigned long userCount,
                      u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-
-    if (!sound.soft.stereo) {
-       void *p = &frame[*frameUsed];
-       count = min(userCount, frameLeft) & ~1;
-       used = count;
-       copy_from_user(p, userPtr, count);
-    } else {
-       u_char *left = &frame[*frameUsed>>1];
-       u_char *right = left+sq.block_size_half;
-       count = min(userCount, frameLeft)>>1 & ~1;
-       used = count*2;
-       while (count > 0) {
-           get_user(*left++, userPtr++);
-           get_user(*right++, userPtr++);
-           count--;
+       long count, used;
+
+       if (!sound.soft.stereo) {
+               void *p = &frame[*frameUsed];
+               count = min(userCount, frameLeft) & ~1;
+               used = count;
+               if (copy_from_user(p, userPtr, count))
+                       return -EFAULT;
+       } else {
+               u_char *left = &frame[*frameUsed>>1];
+               u_char *right = left+sq.block_size_half;
+               count = min(userCount, frameLeft)>>1 & ~1;
+               used = count*2;
+               while (count > 0) {
+                       if (get_user(*left++, userPtr++)
+                           || get_user(*right++, userPtr++))
+                               return -EFAULT;
+                       count--;
+               }
        }
-    }
-    *frameUsed += used;
-    return(used);
+       *frameUsed += used;
+       return(used);
 }
 
 
 static long ami_ct_u8(const u_char *userPtr, unsigned long userCount,
                      u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-
-    if (!sound.soft.stereo) {
-       char *p = &frame[*frameUsed];
-       count = min(userCount, frameLeft) & ~1;
-       used = count;
-       while (count > 0) {
-           u_char data;
-           get_user(data, userPtr++);
-           *p++ = data ^ 0x80;
-           count--;
-       }
-    } else {
-       u_char *left = &frame[*frameUsed>>1];
-       u_char *right = left+sq.block_size_half;
-       count = min(userCount, frameLeft)>>1 & ~1;
-       used = count*2;
-       while (count > 0) {
-           u_char data;
-           get_user(data, userPtr++);
-           *left++ = data ^ 0x80;
-           get_user(data, userPtr++);
-           *right++ = data ^ 0x80;
-           count--;
-        }
-    }
-    *frameUsed += used;
-    return(used);
+       long count, used;
+
+       if (!sound.soft.stereo) {
+               char *p = &frame[*frameUsed];
+               count = min(userCount, frameLeft) & ~1;
+               used = count;
+               while (count > 0) {
+                       u_char data;
+                       if (get_user(data, userPtr++))
+                               return -EFAULT;
+                       *p++ = data ^ 0x80;
+                       count--;
+               }
+       } else {
+               u_char *left = &frame[*frameUsed>>1];
+               u_char *right = left+sq.block_size_half;
+               count = min(userCount, frameLeft)>>1 & ~1;
+               used = count*2;
+               while (count > 0) {
+                       u_char data;
+                       if (get_user(data, userPtr++))
+                               return -EFAULT;
+                       *left++ = data ^ 0x80;
+                       if (get_user(data, userPtr++))
+                               return -EFAULT;
+                       *right++ = data ^ 0x80;
+                       count--;
+               }
+       }
+       *frameUsed += used;
+       return(used);
 }
 
 
 static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount,
                         u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
-
-    if (!sound.soft.stereo) {
-       u_char *high = &frame[*frameUsed>>1];
-       u_char *low = high+sq.block_size_half;
-       count = min(userCount, frameLeft)>>1 & ~1;
-       used = count*2;
-       while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           *high++ = data>>8;
-           *low++ = (data>>2) & 0x3f;
-           count--;
-       }
-    } else {
-       u_char *lefth = &frame[*frameUsed>>2];
-       u_char *leftl = lefth+sq.block_size_quarter;
-       u_char *righth = lefth+sq.block_size_half;
-       u_char *rightl = righth+sq.block_size_quarter;
-       count = min(userCount, frameLeft)>>2 & ~1;
-       used = count*4;
-       while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           *lefth++ = data>>8;
-           *leftl++ = (data>>2) & 0x3f;
-           get_user(data, ((u_short *)userPtr)++);
-           *righth++ = data>>8;
-           *rightl++ = (data>>2) & 0x3f;
-           count--;
-       }
-    }
-    *frameUsed += used;
-    return(used);
+       long count, used;
+       u_long data;
+
+       if (!sound.soft.stereo) {
+               u_char *high = &frame[*frameUsed>>1];
+               u_char *low = high+sq.block_size_half;
+               count = min(userCount, frameLeft)>>1 & ~1;
+               used = count*2;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       *high++ = data>>8;
+                       *low++ = (data>>2) & 0x3f;
+                       count--;
+               }
+       } else {
+               u_char *lefth = &frame[*frameUsed>>2];
+               u_char *leftl = lefth+sq.block_size_quarter;
+               u_char *righth = lefth+sq.block_size_half;
+               u_char *rightl = righth+sq.block_size_quarter;
+               count = min(userCount, frameLeft)>>2 & ~1;
+               used = count*4;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       *lefth++ = data>>8;
+                       *leftl++ = (data>>2) & 0x3f;
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       *righth++ = data>>8;
+                       *rightl++ = (data>>2) & 0x3f;
+                       count--;
+               }
+       }
+       *frameUsed += used;
+       return(used);
 }
 
 
 static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount,
                         u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
-
-    if (!sound.soft.stereo) {
-       u_char *high = &frame[*frameUsed>>1];
-       u_char *low = high+sq.block_size_half;
-       count = min(userCount, frameLeft)>>1 & ~1;
-       used = count*2;
-       while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           data ^= 0x8000;
-           *high++ = data>>8;
-           *low++ = (data>>2) & 0x3f;
-           count--;
-       }
-    } else {
-       u_char *lefth = &frame[*frameUsed>>2];
-       u_char *leftl = lefth+sq.block_size_quarter;
-       u_char *righth = lefth+sq.block_size_half;
-       u_char *rightl = righth+sq.block_size_quarter;
-       count = min(userCount, frameLeft)>>2 & ~1;
-       used = count*4;
-       while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           data ^= 0x8000;
-           *lefth++ = data>>8;
-           *leftl++ = (data>>2) & 0x3f;
-           get_user(data, ((u_short *)userPtr)++);
-           data ^= 0x8000;
-           *righth++ = data>>8;
-           *rightl++ = (data>>2) & 0x3f;
-           count--;
+       long count, used;
+       u_long data;
+
+       if (!sound.soft.stereo) {
+               u_char *high = &frame[*frameUsed>>1];
+               u_char *low = high+sq.block_size_half;
+               count = min(userCount, frameLeft)>>1 & ~1;
+               used = count*2;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data ^= 0x8000;
+                       *high++ = data>>8;
+                       *low++ = (data>>2) & 0x3f;
+                       count--;
+               }
+       } else {
+               u_char *lefth = &frame[*frameUsed>>2];
+               u_char *leftl = lefth+sq.block_size_quarter;
+               u_char *righth = lefth+sq.block_size_half;
+               u_char *rightl = righth+sq.block_size_quarter;
+               count = min(userCount, frameLeft)>>2 & ~1;
+               used = count*4;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data ^= 0x8000;
+                       *lefth++ = data>>8;
+                       *leftl++ = (data>>2) & 0x3f;
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data ^= 0x8000;
+                       *righth++ = data>>8;
+                       *rightl++ = (data>>2) & 0x3f;
+                       count--;
+               }
        }
-    }
-    *frameUsed += used;
-    return(used);
+       *frameUsed += used;
+       return(used);
 }
 
 
 static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount,
                         u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
-
-    if (!sound.soft.stereo) {
-       u_char *high = &frame[*frameUsed>>1];
-       u_char *low = high+sq.block_size_half;
-       count = min(userCount, frameLeft)>>1 & ~1;
-       used = count*2;
-       while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           data = le2be16(data);
-           *high++ = data>>8;
-           *low++ = (data>>2) & 0x3f;
-           count--;
-       }
-    } else {
-       u_char *lefth = &frame[*frameUsed>>2];
-       u_char *leftl = lefth+sq.block_size_quarter;
-       u_char *righth = lefth+sq.block_size_half;
-       u_char *rightl = righth+sq.block_size_quarter;
-       count = min(userCount, frameLeft)>>2 & ~1;
-       used = count*4;
-       while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           data = le2be16(data);
-           *lefth++ = data>>8;
-           *leftl++ = (data>>2) & 0x3f;
-           get_user(data, ((u_short *)userPtr)++);
-           data = le2be16(data);
-           *righth++ = data>>8;
-           *rightl++ = (data>>2) & 0x3f;
-           count--;
+       long count, used;
+       u_long data;
+
+       if (!sound.soft.stereo) {
+               u_char *high = &frame[*frameUsed>>1];
+               u_char *low = high+sq.block_size_half;
+               count = min(userCount, frameLeft)>>1 & ~1;
+               used = count*2;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data = le2be16(data);
+                       *high++ = data>>8;
+                       *low++ = (data>>2) & 0x3f;
+                       count--;
+               }
+       } else {
+               u_char *lefth = &frame[*frameUsed>>2];
+               u_char *leftl = lefth+sq.block_size_quarter;
+               u_char *righth = lefth+sq.block_size_half;
+               u_char *rightl = righth+sq.block_size_quarter;
+               count = min(userCount, frameLeft)>>2 & ~1;
+               used = count*4;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data = le2be16(data);
+                       *lefth++ = data>>8;
+                       *leftl++ = (data>>2) & 0x3f;
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data = le2be16(data);
+                       *righth++ = data>>8;
+                       *rightl++ = (data>>2) & 0x3f;
+                       count--;
+               }
        }
-    }
-    *frameUsed += used;
-    return(used);
+       *frameUsed += used;
+       return(used);
 }
 
 
 static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount,
                         u_char frame[], long *frameUsed, long frameLeft)
 {
-    long count, used;
-    u_long data;
+       long count, used;
+       u_long data;
+
+       if (!sound.soft.stereo) {
+               u_char *high = &frame[*frameUsed>>1];
+               u_char *low = high+sq.block_size_half;
+               count = min(userCount, frameLeft)>>1 & ~1;
+               used = count*2;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data = le2be16(data) ^ 0x8000;
+                       *high++ = data>>8;
+                       *low++ = (data>>2) & 0x3f;
+                       count--;
+               }
+       } else {
+               u_char *lefth = &frame[*frameUsed>>2];
+               u_char *leftl = lefth+sq.block_size_quarter;
+               u_char *righth = lefth+sq.block_size_half;
+               u_char *rightl = righth+sq.block_size_quarter;
+               count = min(userCount, frameLeft)>>2 & ~1;
+               used = count*4;
+               while (count > 0) {
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data = le2be16(data) ^ 0x8000;
+                       *lefth++ = data>>8;
+                       *leftl++ = (data>>2) & 0x3f;
+                       if (get_user(data, ((u_short *)userPtr)++))
+                               return -EFAULT;
+                       data = le2be16(data) ^ 0x8000;
+                       *righth++ = data>>8;
+                       *rightl++ = (data>>2) & 0x3f;
+                       count--;
+               }
+       }
+       *frameUsed += used;
+       return(used);
+}
+#endif /* CONFIG_AMIGA */
+
+#ifdef CONFIG_PMAC
+static long pmac_ct_law(const u_char *userPtr, unsigned long userCount,
+                       u_char frame[], long *frameUsed, long frameLeft)
+{
+       short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
+       long count, used;
+       short *p = (short *) &frame[*frameUsed];
+       int val, stereo = sound.soft.stereo;
+
+       frameLeft >>= 2;
+       if (stereo)
+               userCount >>= 1;
+       used = count = min(userCount, frameLeft);
+       while (count > 0) {
+               u_char data;
+               if (get_user(data, userPtr++))
+                       return -EFAULT;
+               val = table[data];
+               *p++ = val;
+               if (stereo) {
+                       if (get_user(data, userPtr++))
+                               return -EFAULT;
+                       val = table[data];
+               }
+               *p++ = val;
+               count--;
+       }
+       *frameUsed += used * 4;
+       return stereo? used * 2: used;
+}
 
-    if (!sound.soft.stereo) {
-       u_char *high = &frame[*frameUsed>>1];
-       u_char *low = high+sq.block_size_half;
-       count = min(userCount, frameLeft)>>1 & ~1;
-       used = count*2;
+
+static long pmac_ct_s8(const u_char *userPtr, unsigned long userCount,
+                      u_char frame[], long *frameUsed, long frameLeft)
+{
+       long count, used;
+       short *p = (short *) &frame[*frameUsed];
+       int val, stereo = sound.soft.stereo;
+
+       frameLeft >>= 2;
+       if (stereo)
+               userCount >>= 1;
+       used = count = min(userCount, frameLeft);
        while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           data = le2be16(data) ^ 0x8000;
-           *high++ = data>>8;
-           *low++ = (data>>2) & 0x3f;
-           count--;
-       }
-    } else {
-       u_char *lefth = &frame[*frameUsed>>2];
-       u_char *leftl = lefth+sq.block_size_quarter;
-       u_char *righth = lefth+sq.block_size_half;
-       u_char *rightl = righth+sq.block_size_quarter;
-       count = min(userCount, frameLeft)>>2 & ~1;
-       used = count*4;
+               u_char data;
+               if (get_user(data, userPtr++))
+                       return -EFAULT;
+               val = data << 8;
+               *p++ = val;
+               if (stereo) {
+                       if (get_user(data, userPtr++))
+                               return -EFAULT;
+                       val = data << 8;
+               }
+               *p++ = val;
+               count--;
+       }
+       *frameUsed += used * 4;
+       return stereo? used * 2: used;
+}
+
+
+static long pmac_ct_u8(const u_char *userPtr, unsigned long userCount,
+                      u_char frame[], long *frameUsed, long frameLeft)
+{
+       long count, used;
+       short *p = (short *) &frame[*frameUsed];
+       int val, stereo = sound.soft.stereo;
+
+       frameLeft >>= 2;
+       if (stereo)
+               userCount >>= 1;
+       used = count = min(userCount, frameLeft);
        while (count > 0) {
-           get_user(data, ((u_short *)userPtr)++);
-           data = le2be16(data) ^ 0x8000;
-           *lefth++ = data>>8;
-           *leftl++ = (data>>2) & 0x3f;
-           get_user(data, ((u_short *)userPtr)++);
-           data = le2be16(data) ^ 0x8000;
-           *righth++ = data>>8;
-           *rightl++ = (data>>2) & 0x3f;
-           count--;
-       }
-    }
-    *frameUsed += used;
-    return(used);
+               u_char data;
+               if (get_user(data, userPtr++))
+                       return -EFAULT;
+               val = (data ^ 0x80) << 8;
+               *p++ = val;
+               if (stereo) {
+                       if (get_user(data, userPtr++))
+                               return -EFAULT;
+                       val = (data ^ 0x80) << 8;
+               }
+               *p++ = val;
+               count--;
+       }
+       *frameUsed += used * 4;
+       return stereo? used * 2: used;
+}
+
+
+static long pmac_ct_s16(const u_char *userPtr, unsigned long userCount,
+                       u_char frame[], long *frameUsed, long frameLeft)
+{
+       long count, used;
+       int stereo = sound.soft.stereo;
+       short *fp = (short *) &frame[*frameUsed];
+
+       frameLeft >>= 2;
+       userCount >>= (stereo? 2: 1);
+       used = count = min(userCount, frameLeft);
+       if (!stereo) {
+               short *up = (short *) userPtr;
+               while (count > 0) {
+                       short data;
+                       if (get_user(data, up++))
+                               return -EFAULT;
+                       *fp++ = data;
+                       *fp++ = data;
+                       count--;
+               }
+       } else {
+               if (copy_from_user(fp, userPtr, count * 4))
+                       return -EFAULT;
+       }
+       *frameUsed += used * 4;
+       return stereo? used * 4: used * 2;
+}
+
+static long pmac_ct_u16(const u_char *userPtr, unsigned long userCount,
+                       u_char frame[], long *frameUsed, long frameLeft)
+{
+       long count, used;
+       int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+       int stereo = sound.soft.stereo;
+       short *fp = (short *) &frame[*frameUsed];
+       short *up = (short *) userPtr;
+
+       frameLeft >>= 2;
+       userCount >>= (stereo? 2: 1);
+       used = count = min(userCount, frameLeft);
+       while (count > 0) {
+               int data;
+               if (get_user(data, up++))
+                       return -EFAULT;
+               data ^= mask;
+               *fp++ = data;
+               if (stereo) {
+                       if (get_user(data, up++))
+                               return -EFAULT;
+                       data ^= mask;
+               }
+               *fp++ = data;
+               count--;
+       }
+       *frameUsed += used * 4;
+       return stereo? used * 4: used * 2;
+}
+
+
+static long pmac_ctx_law(const u_char *userPtr, unsigned long userCount,
+                        u_char frame[], long *frameUsed, long frameLeft)
+{
+       unsigned short *table = (unsigned short *)
+               (sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
+       unsigned int data = sound.data;
+       unsigned int *p = (unsigned int *) &frame[*frameUsed];
+       int bal = sound.bal;
+       int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       int utotal, ftotal;
+       int stereo = sound.soft.stereo;
+       frameLeft >>= 2;
+       if (stereo)
+               userCount >>= 1;
+       ftotal = frameLeft;
+       utotal = userCount;
+       while (frameLeft) {
+               u_char c;
+               if (bal < 0) {
+                       if (userCount == 0)
+                               break;
+                       if (get_user(c, userPtr++))
+                               return -EFAULT;
+                       data = table[c];
+                       if (stereo) {
+                               if (get_user(c, userPtr++))
+                                       return -EFAULT;
+                               data = (data << 16) + table[c];
+                       } else
+                               data = (data << 16) + data;
+                       userCount--;
+                       bal += hSpeed;
+               }
+               *p++ = data;
+               frameLeft--;
+               bal -= sSpeed;
+       }
+       sound.bal = bal;
+       sound.data = data;
+       *frameUsed += (ftotal - frameLeft) * 4;
+       utotal -= userCount;
+       return stereo? utotal * 2: utotal;
+}
+
+
+static long pmac_ctx_s8(const u_char *userPtr, unsigned long userCount,
+                       u_char frame[], long *frameUsed, long frameLeft)
+{
+       unsigned int *p = (unsigned int *) &frame[*frameUsed];
+       unsigned int data = sound.data;
+       int bal = sound.bal;
+       int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       int stereo = sound.soft.stereo;
+       int utotal, ftotal;
+
+       frameLeft >>= 2;
+       if (stereo)
+               userCount >>= 1;
+       ftotal = frameLeft;
+       utotal = userCount;
+       while (frameLeft) {
+               u_char c;
+               if (bal < 0) {
+                       if (userCount == 0)
+                               break;
+                       if (get_user(c, userPtr++))
+                               return -EFAULT;
+                       data = c << 8;
+                       if (stereo) {
+                               if (get_user(c, userPtr++))
+                                       return -EFAULT;
+                               data = (data << 16) + (c << 8);
+                       } else
+                               data = (data << 16) + data;
+                       userCount--;
+                       bal += hSpeed;
+               }
+               *p++ = data;
+               frameLeft--;
+               bal -= sSpeed;
+       }
+       sound.bal = bal;
+       sound.data = data;
+       *frameUsed += (ftotal - frameLeft) * 4;
+       utotal -= userCount;
+       return stereo? utotal * 2: utotal;
+}
+
+
+static long pmac_ctx_u8(const u_char *userPtr, unsigned long userCount,
+                       u_char frame[], long *frameUsed, long frameLeft)
+{
+       unsigned int *p = (unsigned int *) &frame[*frameUsed];
+       unsigned int data = sound.data;
+       int bal = sound.bal;
+       int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       int stereo = sound.soft.stereo;
+       int utotal, ftotal;
+
+       frameLeft >>= 2;
+       if (stereo)
+               userCount >>= 1;
+       ftotal = frameLeft;
+       utotal = userCount;
+       while (frameLeft) {
+               u_char c;
+               if (bal < 0) {
+                       if (userCount == 0)
+                               break;
+                       if (get_user(c, userPtr++))
+                               return -EFAULT;
+                       data = (c ^ 0x80) << 8;
+                       if (stereo) {
+                               if (get_user(c, userPtr++))
+                                       return -EFAULT;
+                               data = (data << 16) + ((c ^ 0x80) << 8);
+                       } else
+                               data = (data << 16) + data;
+                       userCount--;
+                       bal += hSpeed;
+               }
+               *p++ = data;
+               frameLeft--;
+               bal -= sSpeed;
+       }
+       sound.bal = bal;
+       sound.data = data;
+       *frameUsed += (ftotal - frameLeft) * 4;
+       utotal -= userCount;
+       return stereo? utotal * 2: utotal;
+}
+
+
+static long pmac_ctx_s16(const u_char *userPtr, unsigned long userCount,
+                        u_char frame[], long *frameUsed, long frameLeft)
+{
+       unsigned int *p = (unsigned int *) &frame[*frameUsed];
+       unsigned int data = sound.data;
+       unsigned short *up = (unsigned short *) userPtr;
+       int bal = sound.bal;
+       int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       int stereo = sound.soft.stereo;
+       int utotal, ftotal;
+
+       frameLeft >>= 2;
+       if (stereo)
+               userCount >>= 1;
+       ftotal = frameLeft;
+       utotal = userCount;
+       while (frameLeft) {
+               unsigned short c;
+               if (bal < 0) {
+                       if (userCount == 0)
+                               break;
+                       if (get_user(data, up++))
+                               return -EFAULT;
+                       if (stereo) {
+                               if (get_user(c, up++))
+                                       return -EFAULT;
+                               data = (data << 16) + c;
+                       } else
+                               data = (data << 16) + data;
+                       userCount--;
+                       bal += hSpeed;
+               }
+               *p++ = data;
+               frameLeft--;
+               bal -= sSpeed;
+       }
+       sound.bal = bal;
+       sound.data = data;
+       *frameUsed += (ftotal - frameLeft) * 4;
+       utotal -= userCount;
+       return stereo? utotal * 4: utotal * 2;
+}
+
+
+static long pmac_ctx_u16(const u_char *userPtr, unsigned long userCount,
+                        u_char frame[], long *frameUsed, long frameLeft)
+{
+       int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+       unsigned int *p = (unsigned int *) &frame[*frameUsed];
+       unsigned int data = sound.data;
+       unsigned short *up = (unsigned short *) userPtr;
+       int bal = sound.bal;
+       int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+       int stereo = sound.soft.stereo;
+       int utotal, ftotal;
+
+       frameLeft >>= 2;
+       if (stereo)
+               userCount >>= 1;
+       ftotal = frameLeft;
+       utotal = userCount;
+       while (frameLeft) {
+               unsigned short c;
+               if (bal < 0) {
+                       if (userCount == 0)
+                               break;
+                       if (get_user(data, up++))
+                               return -EFAULT;
+                       data ^= mask;
+                       if (stereo) {
+                               if (get_user(c, up++))
+                                       return -EFAULT;
+                               data = (data << 16) + (c ^ mask);
+                       } else
+                               data = (data << 16) + data;
+                       userCount--;
+                       bal += hSpeed;
+               }
+               *p++ = data;
+               frameLeft--;
+               bal -= sSpeed;
+       }
+       sound.bal = bal;
+       sound.data = data;
+       *frameUsed += (ftotal - frameLeft) * 4;
+       utotal -= userCount;
+       return stereo? utotal * 4: utotal * 2;
 }
-#endif /* CONFIG_AMIGA */
+
+#endif /* CONFIG_PMAC */
 
 
 #ifdef CONFIG_ATARI
 static TRANS transTTNormal = {
-    ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
+       ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
 };
 
 static TRANS transTTExpanding = {
-    ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
+       ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
 };
 
 static TRANS transFalconNormal = {
-    ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be,
-    ata_ct_s16le, ata_ct_u16le
+       ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8,
+       ata_ct_s16be, ata_ct_u16be, ata_ct_s16le, ata_ct_u16le
 };
 
 static TRANS transFalconExpanding = {
-    ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be,
-    ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
+       ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8,
+       ata_ctx_s16be, ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
 };
 #endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
 static TRANS transAmiga = {
-    ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be,
-    ami_ct_s16le, ami_ct_u16le
+       ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8,
+       ami_ct_s16be, ami_ct_u16be, ami_ct_s16le, ami_ct_u16le
 };
 #endif /* CONFIG_AMIGA */
 
+#ifdef CONFIG_PMAC
+static TRANS transAwacsNormal = {
+       pmac_ct_law, pmac_ct_law, pmac_ct_s8, pmac_ct_u8,
+       pmac_ct_s16, pmac_ct_u16, pmac_ct_s16, pmac_ct_u16
+};
+
+static TRANS transAwacsExpand = {
+       pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8,
+       pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16
+};
+#endif /* CONFIG_PMAC */
 
 /*** Low level stuff *********************************************************/
 
@@ -1583,40 +2164,40 @@ static TRANS transAmiga = {
 
 static void *AtaAlloc(unsigned int size, int flags)
 {
-    return( atari_stram_alloc( size, NULL, "dmasound" ));
+       return( atari_stram_alloc( size, NULL, "dmasound" ));
 }
 
 static void AtaFree(void *obj, unsigned int size)
 {
-    atari_stram_free( obj );
+       atari_stram_free( obj );
 }
 
 static int AtaIrqInit(void)
 {
-    /* Set up timer A. Timer A
-    will receive a signal upon end of playing from the sound
-    hardware. Furthermore Timer A is able to count events
-    and will cause an interrupt after a programmed number
-    of events. So all we need to keep the music playing is
-    to provide the sound hardware with new data upon
-    an interrupt from timer A. */
-    mfp.tim_ct_a = 0;          /* ++roman: Stop timer before programming! */
-    mfp.tim_dt_a = 1;          /* Cause interrupt after first event. */
-    mfp.tim_ct_a = 8;          /* Turn on event counting. */
-    /* Register interrupt handler. */
-    request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
-                "DMA sound", ata_sq_interrupt);
-    mfp.int_en_a |= 0x20;      /* Turn interrupt on. */
-    mfp.int_mk_a |= 0x20;
-    return(1);
+       /* Set up timer A. Timer A
+          will receive a signal upon end of playing from the sound
+          hardware. Furthermore Timer A is able to count events
+          and will cause an interrupt after a programmed number
+          of events. So all we need to keep the music playing is
+          to provide the sound hardware with new data upon
+          an interrupt from timer A. */
+       mfp.tim_ct_a = 0;       /* ++roman: Stop timer before programming! */
+       mfp.tim_dt_a = 1;       /* Cause interrupt after first event. */
+       mfp.tim_ct_a = 8;       /* Turn on event counting. */
+       /* Register interrupt handler. */
+       request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
+                   "DMA sound", ata_sq_interrupt);
+       mfp.int_en_a |= 0x20;   /* Turn interrupt on. */
+       mfp.int_mk_a |= 0x20;
+       return(1);
 }
 
 #ifdef MODULE
 static void AtaIrqCleanUp(void)
 {
-    mfp.tim_ct_a = 0;          /* stop timer */
-    mfp.int_en_a &= ~0x20;     /* turn interrupt off */
-    free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
+       mfp.tim_ct_a = 0;       /* stop timer */
+       mfp.int_en_a &= ~0x20;  /* turn interrupt off */
+       free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
 }
 #endif /* MODULE */
 
@@ -1628,17 +2209,17 @@ static void AtaIrqCleanUp(void)
 
 static int AtaSetBass(int bass)
 {
-    sound.bass = TONE_VOXWARE_TO_DB(bass);
-    atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
-    return(TONE_DB_TO_VOXWARE(sound.bass));
+       sound.bass = TONE_VOXWARE_TO_DB(bass);
+       atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
+       return(TONE_DB_TO_VOXWARE(sound.bass));
 }
 
 
 static int AtaSetTreble(int treble)
 {
-    sound.treble = TONE_VOXWARE_TO_DB(treble);
-    atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
-    return(TONE_DB_TO_VOXWARE(sound.treble));
+       sound.treble = TONE_VOXWARE_TO_DB(treble);
+       atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
+       return(TONE_DB_TO_VOXWARE(sound.treble));
 }
 
 
@@ -1650,86 +2231,86 @@ static int AtaSetTreble(int treble)
 
 static void TTSilence(void)
 {
-    tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-    atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
+       tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+       atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
 }
 
 
 static void TTInit(void)
 {
-    int mode, i, idx;
-    const int freq[4] = {50066, 25033, 12517, 6258};
+       int mode, i, idx;
+       const int freq[4] = {50066, 25033, 12517, 6258};
 
-    /* search a frequency that fits into the allowed error range */
+       /* search a frequency that fits into the allowed error range */
 
-    idx = -1;
-    for (i = 0; i < arraysize(freq); i++)
-       /* this isn't as much useful for a TT than for a Falcon, but
-        * then it doesn't hurt very much to implement it for a TT too.
-        */
-       if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
-           idx = i;
-    if (idx > -1) {
-       sound.soft.speed = freq[idx];
-       sound.trans = &transTTNormal;
-    } else
-       sound.trans = &transTTExpanding;
-
-    TTSilence();
-    sound.hard = sound.soft;
-
-    if (sound.hard.speed > 50066) {
-       /* we would need to squeeze the sound, but we won't do that */
-       sound.hard.speed = 50066;
-       mode = DMASND_MODE_50KHZ;
-       sound.trans = &transTTNormal;
-    } else if (sound.hard.speed > 25033) {
-       sound.hard.speed = 50066;
-       mode = DMASND_MODE_50KHZ;
-    } else if (sound.hard.speed > 12517) {
-       sound.hard.speed = 25033;
-       mode = DMASND_MODE_25KHZ;
-    } else if (sound.hard.speed > 6258) {
-       sound.hard.speed = 12517;
-       mode = DMASND_MODE_12KHZ;
-    } else {
-       sound.hard.speed = 6258;
-       mode = DMASND_MODE_6KHZ;
-    }
-
-    tt_dmasnd.mode = (sound.hard.stereo ?
-                     DMASND_MODE_STEREO : DMASND_MODE_MONO) |
-                    DMASND_MODE_8BIT | mode;
-
-    sound.bal = -sound.soft.speed;
+       idx = -1;
+       for (i = 0; i < arraysize(freq); i++)
+               /* this isn't as much useful for a TT than for a Falcon, but
+                * then it doesn't hurt very much to implement it for a TT too.
+                */
+               if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+                       idx = i;
+       if (idx > -1) {
+               sound.soft.speed = freq[idx];
+               sound.trans = &transTTNormal;
+       } else
+               sound.trans = &transTTExpanding;
+
+       TTSilence();
+       sound.hard = sound.soft;
+
+       if (sound.hard.speed > 50066) {
+               /* we would need to squeeze the sound, but we won't do that */
+               sound.hard.speed = 50066;
+               mode = DMASND_MODE_50KHZ;
+               sound.trans = &transTTNormal;
+       } else if (sound.hard.speed > 25033) {
+               sound.hard.speed = 50066;
+               mode = DMASND_MODE_50KHZ;
+       } else if (sound.hard.speed > 12517) {
+               sound.hard.speed = 25033;
+               mode = DMASND_MODE_25KHZ;
+       } else if (sound.hard.speed > 6258) {
+               sound.hard.speed = 12517;
+               mode = DMASND_MODE_12KHZ;
+       } else {
+               sound.hard.speed = 6258;
+               mode = DMASND_MODE_6KHZ;
+       }
+
+       tt_dmasnd.mode = (sound.hard.stereo ?
+                         DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+               DMASND_MODE_8BIT | mode;
+
+       sound.bal = -sound.soft.speed;
 }
 
 
 static int TTSetFormat(int format)
 {
-    /* TT sound DMA supports only 8bit modes */
+       /* TT sound DMA supports only 8bit modes */
 
-    switch (format) {
+       switch (format) {
        case AFMT_QUERY:
-           return(sound.soft.format);
+               return(sound.soft.format);
        case AFMT_MU_LAW:
        case AFMT_A_LAW:
        case AFMT_S8:
        case AFMT_U8:
-           break;
+               break;
        default:
-           format = AFMT_S8;
-    }
+               format = AFMT_S8;
+       }
 
-    sound.soft.format = format;
-    sound.soft.size = 8;
-    if (sound.minDev == SND_DEV_DSP) {
-       sound.dsp.format = format;
-       sound.dsp.size = 8;
-    }
-    TTInit();
+       sound.soft.format = format;
+       sound.soft.size = 8;
+       if (sound.minDev == SND_DEV_DSP) {
+               sound.dsp.format = format;
+               sound.dsp.size = 8;
+       }
+       TTInit();
 
-    return(format);
+       return(format);
 }
 
 
@@ -1740,12 +2321,12 @@ static int TTSetFormat(int format)
 
 static int TTSetVolume(int volume)
 {
-    sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
-    atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
-    sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
-    atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
-    return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
-          (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
+       sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
+       atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
+       sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
+       atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
+       return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
+              (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
 }
 
 
@@ -1755,9 +2336,9 @@ static int TTSetVolume(int volume)
 
 static int TTSetGain(int gain)
 {
-    sound.gain = GAIN_VOXWARE_TO_DB(gain);
-    atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain));
-    return GAIN_DB_TO_VOXWARE(sound.gain);
+       sound.gain = GAIN_VOXWARE_TO_DB(gain);
+       atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain));
+       return GAIN_DB_TO_VOXWARE(sound.gain);
 }
 
 
@@ -1769,133 +2350,133 @@ static int TTSetGain(int gain)
 
 static void FalconSilence(void)
 {
-    /* stop playback, set sample rate 50kHz for PSG sound */
-    tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-    tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
-    tt_dmasnd.int_div = 0; /* STE compatible divider */
-    tt_dmasnd.int_ctrl = 0x0;
-    tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
-    tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
-    tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
-    tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
+       /* stop playback, set sample rate 50kHz for PSG sound */
+       tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+       tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
+       tt_dmasnd.int_div = 0; /* STE compatible divider */
+       tt_dmasnd.int_ctrl = 0x0;
+       tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
+       tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
+       tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
+       tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
 }
 
 
 static void FalconInit(void)
 {
-    int divider, i, idx;
-    const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
+       int divider, i, idx;
+       const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
 
-    /* search a frequency that fits into the allowed error range */
+       /* search a frequency that fits into the allowed error range */
 
-    idx = -1;
-    for (i = 0; i < arraysize(freq); i++)
-       /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
-        * be playable without expanding, but that now a kernel runtime
-        * option
-        */
-       if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
-           idx = i;
-    if (idx > -1) {
-       sound.soft.speed = freq[idx];
-       sound.trans = &transFalconNormal;
-    } else
-       sound.trans = &transFalconExpanding;
-
-    FalconSilence();
-    sound.hard = sound.soft;
-
-    if (sound.hard.size == 16) {
-       /* the Falcon can play 16bit samples only in stereo */
-       sound.hard.stereo = 1;
-    }
-
-    if (sound.hard.speed > 49170) {
-       /* we would need to squeeze the sound, but we won't do that */
-       sound.hard.speed = 49170;
-       divider = 1;
-       sound.trans = &transFalconNormal;
-    } else if (sound.hard.speed > 32780) {
-       sound.hard.speed = 49170;
-       divider = 1;
-    } else if (sound.hard.speed > 24585) {
-       sound.hard.speed = 32780;
-       divider = 2;
-    } else if (sound.hard.speed > 19668) {
-       sound.hard.speed = 24585;
-       divider = 3;
-    } else if (sound.hard.speed > 16390) {
-       sound.hard.speed = 19668;
-       divider = 4;
-    } else if (sound.hard.speed > 12292) {
-       sound.hard.speed = 16390;
-       divider = 5;
-    } else if (sound.hard.speed > 9834) {
-       sound.hard.speed = 12292;
-       divider = 7;
-    } else if (sound.hard.speed > 8195) {
-       sound.hard.speed = 9834;
-       divider = 9;
-    } else {
-       sound.hard.speed = 8195;
-       divider = 11;
-    }
-    tt_dmasnd.int_div = divider;
-
-    /* Setup Falcon sound DMA for playback */
-    tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
-    tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
-    tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
-    tt_dmasnd.cbar_dst = 0x0000;
-    tt_dmasnd.rec_track_select = 0;
-    tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
-    tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
-
-    tt_dmasnd.mode = (sound.hard.stereo ?
-                     DMASND_MODE_STEREO : DMASND_MODE_MONO) |
-                    ((sound.hard.size == 8) ?
-                      DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
-                    DMASND_MODE_6KHZ;
-
-    sound.bal = -sound.soft.speed;
-}
+       idx = -1;
+       for (i = 0; i < arraysize(freq); i++)
+               /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
+                * be playable without expanding, but that now a kernel runtime
+                * option
+                */
+               if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+                       idx = i;
+       if (idx > -1) {
+               sound.soft.speed = freq[idx];
+               sound.trans = &transFalconNormal;
+       } else
+               sound.trans = &transFalconExpanding;
+
+       FalconSilence();
+       sound.hard = sound.soft;
+
+       if (sound.hard.size == 16) {
+               /* the Falcon can play 16bit samples only in stereo */
+               sound.hard.stereo = 1;
+       }
+
+       if (sound.hard.speed > 49170) {
+               /* we would need to squeeze the sound, but we won't do that */
+               sound.hard.speed = 49170;
+               divider = 1;
+               sound.trans = &transFalconNormal;
+       } else if (sound.hard.speed > 32780) {
+               sound.hard.speed = 49170;
+               divider = 1;
+       } else if (sound.hard.speed > 24585) {
+               sound.hard.speed = 32780;
+               divider = 2;
+       } else if (sound.hard.speed > 19668) {
+               sound.hard.speed = 24585;
+               divider = 3;
+       } else if (sound.hard.speed > 16390) {
+               sound.hard.speed = 19668;
+               divider = 4;
+       } else if (sound.hard.speed > 12292) {
+               sound.hard.speed = 16390;
+               divider = 5;
+       } else if (sound.hard.speed > 9834) {
+               sound.hard.speed = 12292;
+               divider = 7;
+       } else if (sound.hard.speed > 8195) {
+               sound.hard.speed = 9834;
+               divider = 9;
+       } else {
+               sound.hard.speed = 8195;
+               divider = 11;
+       }
+       tt_dmasnd.int_div = divider;
+
+       /* Setup Falcon sound DMA for playback */
+       tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
+       tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
+       tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
+       tt_dmasnd.cbar_dst = 0x0000;
+       tt_dmasnd.rec_track_select = 0;
+       tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
+       tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
+
+       tt_dmasnd.mode = (sound.hard.stereo ?
+                         DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+               ((sound.hard.size == 8) ?
+                DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
+               DMASND_MODE_6KHZ;
+
+       sound.bal = -sound.soft.speed;
+}
 
 
 static int FalconSetFormat(int format)
 {
-    int size;
-    /* Falcon sound DMA supports 8bit and 16bit modes */
+       int size;
+       /* Falcon sound DMA supports 8bit and 16bit modes */
 
-    switch (format) {
+       switch (format) {
        case AFMT_QUERY:
-           return(sound.soft.format);
+               return(sound.soft.format);
        case AFMT_MU_LAW:
        case AFMT_A_LAW:
        case AFMT_U8:
        case AFMT_S8:
-           size = 8;
-           break;
+               size = 8;
+               break;
        case AFMT_S16_BE:
        case AFMT_U16_BE:
        case AFMT_S16_LE:
        case AFMT_U16_LE:
-           size = 16;
-           break;
+               size = 16;
+               break;
        default: /* :-) */
-           size = 8;
-           format = AFMT_S8;
-    }
+               size = 8;
+               format = AFMT_S8;
+       }
 
-    sound.soft.format = format;
-    sound.soft.size = size;
-    if (sound.minDev == SND_DEV_DSP) {
-       sound.dsp.format = format;
-       sound.dsp.size = sound.soft.size;
-    }
+       sound.soft.format = format;
+       sound.soft.size = size;
+       if (sound.minDev == SND_DEV_DSP) {
+               sound.dsp.format = format;
+               sound.dsp.size = sound.soft.size;
+       }
 
-    FalconInit();
+       FalconInit();
 
-    return(format);
+       return(format);
 }
 
 
@@ -1909,164 +2490,164 @@ static int FalconSetFormat(int format)
 
 static int FalconSetVolume(int volume)
 {
-    sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
-    sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
-    tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
-    return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
-          VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
+       sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
+       sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
+       tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
+       return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
+              VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
 }
 
 
 static void ata_sq_play_next_frame(int index)
 {
-    char *start, *end;
+       char *start, *end;
 
-    /* used by AtaPlay() if all doubts whether there really is something
-     * to be played are already wiped out.
-     */
-    start = sq_block_address(sq.front);
-    end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
-    /* end might not be a legal virtual address. */
-    DMASNDSetEnd(VTOP(end - 1) + 1);
-    DMASNDSetBase(VTOP(start));
+       /* used by AtaPlay() if all doubts whether there really is something
+        * to be played are already wiped out.
+        */
+       start = sq_block_address(sq.front);
+       end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
+       /* end might not be a legal virtual address. */
+       DMASNDSetEnd(VTOP(end - 1) + 1);
+       DMASNDSetBase(VTOP(start));
        /* Since only an even number of samples per frame can
-       be played, we might lose one byte here. (TO DO) */
-    sq.front = (sq.front+1) % sq.max_count;
-    sq.playing++;
-    tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
+          be played, we might lose one byte here. (TO DO) */
+       sq.front = (sq.front+1) % sq.max_count;
+       sq.playing++;
+       tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
 }
 
 
 static void AtaPlay(void)
 {
-    /* ++TeSche: Note that sq.playing is no longer just a flag but holds
-     * the number of frames the DMA is currently programmed for instead,
-     * may be 0, 1 (currently being played) or 2 (pre-programmed).
-     *
-     * Changes done to sq.count and sq.playing are a bit more subtle again
-     * so now I must admit I also prefer disabling the irq here rather
-     * than considering all possible situations. But the point is that
-     * disabling the irq doesn't have any bad influence on this version of
-     * the driver as we benefit from having pre-programmed the DMA
-     * wherever possible: There's no need to reload the DMA at the exact
-     * time of an interrupt but only at some time while the pre-programmed
-     * frame is playing!
-     */
-    atari_disable_irq(IRQ_MFP_TIMA);
-
-    if (sq.playing == 2 ||     /* DMA is 'full' */
-       sq.count <= 0) {        /* nothing to do */
-       atari_enable_irq(IRQ_MFP_TIMA);
-       return;
-    }
-
-    if (sq.playing == 0) {
-       /* looks like there's nothing 'in' the DMA yet, so try
-        * to put two frames into it (at least one is available).
+       /* ++TeSche: Note that sq.playing is no longer just a flag but holds
+        * the number of frames the DMA is currently programmed for instead,
+        * may be 0, 1 (currently being played) or 2 (pre-programmed).
+        *
+        * Changes done to sq.count and sq.playing are a bit more subtle again
+        * so now I must admit I also prefer disabling the irq here rather
+        * than considering all possible situations. But the point is that
+        * disabling the irq doesn't have any bad influence on this version of
+        * the driver as we benefit from having pre-programmed the DMA
+        * wherever possible: There's no need to reload the DMA at the exact
+        * time of an interrupt but only at some time while the pre-programmed
+        * frame is playing!
         */
-       if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
-           /* hmmm, the only existing frame is not
-            * yet filled and we're not syncing?
-            */
-           atari_enable_irq(IRQ_MFP_TIMA);
-           return;
-       }
-       ata_sq_play_next_frame(1);
-       if (sq.count == 1) {
-           /* no more frames */
-           atari_enable_irq(IRQ_MFP_TIMA);
-           return;
-       }
-       if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
-           /* hmmm, there were two frames, but the second
-            * one is not yet filled and we're not syncing?
-            */
-           atari_enable_irq(IRQ_MFP_TIMA);
-           return;
-       }
-       ata_sq_play_next_frame(2);
-    } else {
-       /* there's already a frame being played so we may only stuff
-        * one new into the DMA, but even if this may be the last
-        * frame existing the previous one is still on sq.count.
-        */
-       if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
-           /* hmmm, the only existing frame is not
-            * yet filled and we're not syncing?
-            */
-           atari_enable_irq(IRQ_MFP_TIMA);
-           return;
+       atari_disable_irq(IRQ_MFP_TIMA);
+
+       if (sq.playing == 2 ||  /* DMA is 'full' */
+           sq.count <= 0) {    /* nothing to do */
+               atari_enable_irq(IRQ_MFP_TIMA);
+               return;
        }
-       ata_sq_play_next_frame(2);
-    }
-    atari_enable_irq(IRQ_MFP_TIMA);
+
+       if (sq.playing == 0) {
+               /* looks like there's nothing 'in' the DMA yet, so try
+                * to put two frames into it (at least one is available).
+                */
+               if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
+                       /* hmmm, the only existing frame is not
+                        * yet filled and we're not syncing?
+                        */
+                       atari_enable_irq(IRQ_MFP_TIMA);
+                       return;
+               }
+               ata_sq_play_next_frame(1);
+               if (sq.count == 1) {
+                       /* no more frames */
+                       atari_enable_irq(IRQ_MFP_TIMA);
+                       return;
+               }
+               if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+                       /* hmmm, there were two frames, but the second
+                        * one is not yet filled and we're not syncing?
+                        */
+                       atari_enable_irq(IRQ_MFP_TIMA);
+                       return;
+               }
+               ata_sq_play_next_frame(2);
+       } else {
+               /* there's already a frame being played so we may only stuff
+                * one new into the DMA, but even if this may be the last
+                * frame existing the previous one is still on sq.count.
+                */
+               if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+                       /* hmmm, the only existing frame is not
+                        * yet filled and we're not syncing?
+                        */
+                       atari_enable_irq(IRQ_MFP_TIMA);
+                       return;
+               }
+               ata_sq_play_next_frame(2);
+       }
+       atari_enable_irq(IRQ_MFP_TIMA);
 }
 
 
 static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
 #if 0
-    /* ++TeSche: if you should want to test this... */
-    static int cnt = 0;
-    if (sq.playing == 2)
-       if (++cnt == 10) {
-           /* simulate losing an interrupt */
-           cnt = 0;
-           return;
-       }
+       /* ++TeSche: if you should want to test this... */
+       static int cnt = 0;
+       if (sq.playing == 2)
+               if (++cnt == 10) {
+                       /* simulate losing an interrupt */
+                       cnt = 0;
+                       return;
+               }
 #endif
 
-    if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
-       /* ++TeSche: Falcon only: ignore first irq because it comes
-        * immediately after starting a frame. after that, irqs come
-        * (almost) like on the TT.
-        */
-       sq.ignore_int = 0;
-       return;
-    }
+       if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
+               /* ++TeSche: Falcon only: ignore first irq because it comes
+                * immediately after starting a frame. after that, irqs come
+                * (almost) like on the TT.
+                */
+               sq.ignore_int = 0;
+               return;
+       }
 
-    if (!sq.playing) {
-       /* playing was interrupted and sq_reset() has already cleared
-        * the sq variables, so better don't do anything here.
+       if (!sq.playing) {
+               /* playing was interrupted and sq_reset() has already cleared
+                * the sq variables, so better don't do anything here.
+                */
+               WAKE_UP(sq.sync_queue);
+               return;
+       }
+
+       /* Probably ;) one frame is finished. Well, in fact it may be that a
+        * pre-programmed one is also finished because there has been a long
+        * delay in interrupt delivery and we've completely lost one, but
+        * there's no way to detect such a situation. In such a case the last
+        * frame will be played more than once and the situation will recover
+        * as soon as the irq gets through.
         */
-       WAKE_UP(sq.sync_queue);
-       return;
-    }
-
-    /* Probably ;) one frame is finished. Well, in fact it may be that a
-     * pre-programmed one is also finished because there has been a long
-     * delay in interrupt delivery and we've completely lost one, but
-     * there's no way to detect such a situation. In such a case the last
-     * frame will be played more than once and the situation will recover
-     * as soon as the irq gets through.
-     */
-    sq.count--;
-    sq.playing--;
-
-    if (!sq.playing) {
-       tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-       sq.ignore_int = 1;
-    }
+       sq.count--;
+       sq.playing--;
+
+       if (!sq.playing) {
+               tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+               sq.ignore_int = 1;
+       }
 
-    WAKE_UP(sq.write_queue);
+       WAKE_UP(sq.write_queue);
        /* At least one block of the queue is free now
-       so wake up a writing process blocked because
-       of a full queue. */
-
-    if ((sq.playing != 1) || (sq.count != 1))
-       /* We must be a bit carefully here: sq.count indicates the
-        * number of buffers used and not the number of frames to
-        * be played. If sq.count==1 and sq.playing==1 that means
-        * the only remaining frame was already programmed earlier
-        * (and is currently running) so we mustn't call AtaPlay()
-        * here, otherwise we'll play one frame too much.
-        */
-       AtaPlay();
+          so wake up a writing process blocked because
+          of a full queue. */
+
+       if ((sq.playing != 1) || (sq.count != 1))
+               /* We must be a bit carefully here: sq.count indicates the
+                * number of buffers used and not the number of frames to
+                * be played. If sq.count==1 and sq.playing==1 that means
+                * the only remaining frame was already programmed earlier
+                * (and is currently running) so we mustn't call AtaPlay()
+                * here, otherwise we'll play one frame too much.
+                */
+               AtaPlay();
 
-    if (!sq.playing) WAKE_UP(sq.sync_queue);
+       if (!sq.playing) WAKE_UP(sq.sync_queue);
        /* We are not playing after AtaPlay(), so there
-       is nothing to play any more. Wake up a process
-       waiting for audio output to drain. */
+          is nothing to play any more. Wake up a process
+          waiting for audio output to drain. */
 }
 #endif /* CONFIG_ATARI */
 
@@ -2080,107 +2661,107 @@ static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
 
 static void *AmiAlloc(unsigned int size, int flags)
 {
-    return(amiga_chip_alloc((long)size));
+       return(amiga_chip_alloc((long)size));
 }
 
 static void AmiFree(void *obj, unsigned int size)
 {
-    amiga_chip_free (obj);
+       amiga_chip_free (obj);
 }
 
 static int AmiIrqInit(void)
 {
-    /* turn off DMA for audio channels */
-    custom.dmacon = AMI_AUDIO_OFF;
+       /* turn off DMA for audio channels */
+       custom.dmacon = AMI_AUDIO_OFF;
 
-    /* Register interrupt handler. */
-    if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
-                    "DMA sound", ami_sq_interrupt))
-       return(0);
-    return(1);
+       /* Register interrupt handler. */
+       if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
+                       "DMA sound", ami_sq_interrupt))
+               return(0);
+       return(1);
 }
 
 #ifdef MODULE
 static void AmiIrqCleanUp(void)
 {
-    /* turn off DMA for audio channels */
-    custom.dmacon = AMI_AUDIO_OFF;
-    /* release the interrupt */
-    free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
+       /* turn off DMA for audio channels */
+       custom.dmacon = AMI_AUDIO_OFF;
+       /* release the interrupt */
+       free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
 }
 #endif /* MODULE */
 
 static void AmiSilence(void)
 {
-    /* turn off DMA for audio channels */
-    custom.dmacon = AMI_AUDIO_OFF;
+       /* turn off DMA for audio channels */
+       custom.dmacon = AMI_AUDIO_OFF;
 }
 
 
 static void AmiInit(void)
 {
-    int period, i;
-
-    AmiSilence();
-
-    if (sound.soft.speed)
-       period = amiga_colorclock/sound.soft.speed-1;
-    else
-       period = amiga_audio_min_period;
-    sound.hard = sound.soft;
-    sound.trans = &transAmiga;
-
-    if (period < amiga_audio_min_period) {
-       /* we would need to squeeze the sound, but we won't do that */
-       period = amiga_audio_min_period;
-    } else if (period > 65535) {
-       period = 65535;
-    }
-    sound.hard.speed = amiga_colorclock/(period+1);
+       int period, i;
+
+       AmiSilence();
+
+       if (sound.soft.speed)
+               period = amiga_colorclock/sound.soft.speed-1;
+       else
+               period = amiga_audio_min_period;
+       sound.hard = sound.soft;
+       sound.trans = &transAmiga;
+
+       if (period < amiga_audio_min_period) {
+               /* we would need to squeeze the sound, but we won't do that */
+               period = amiga_audio_min_period;
+       } else if (period > 65535) {
+               period = 65535;
+       }
+       sound.hard.speed = amiga_colorclock/(period+1);
 
-    for (i = 0; i < 4; i++)
-       custom.aud[i].audper = period;
-    amiga_audio_period = period;
+       for (i = 0; i < 4; i++)
+               custom.aud[i].audper = period;
+       amiga_audio_period = period;
 
-    AmiSetTreble(50);  /* recommended for newer amiga models */
+       AmiSetTreble(50);  /* recommended for newer amiga models */
 }
 
 
 static int AmiSetFormat(int format)
 {
-    int size;
+       int size;
 
-    /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
+       /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
 
-    switch (format) {
+       switch (format) {
        case AFMT_QUERY:
-           return(sound.soft.format);
+               return(sound.soft.format);
        case AFMT_MU_LAW:
        case AFMT_A_LAW:
        case AFMT_U8:
        case AFMT_S8:
-           size = 8;
-           break;
+               size = 8;
+               break;
        case AFMT_S16_BE:
        case AFMT_U16_BE:
        case AFMT_S16_LE:
        case AFMT_U16_LE:
-           size = 16;
-           break;
+               size = 16;
+               break;
        default: /* :-) */
-           size = 8;
-           format = AFMT_S8;
-    }
+               size = 8;
+               format = AFMT_S8;
+       }
 
-    sound.soft.format = format;
-    sound.soft.size = size;
-    if (sound.minDev == SND_DEV_DSP) {
-       sound.dsp.format = format;
-       sound.dsp.size = sound.soft.size;
-    }
-    AmiInit();
+       sound.soft.format = format;
+       sound.soft.size = size;
+       if (sound.minDev == SND_DEV_DSP) {
+               sound.dsp.format = format;
+               sound.dsp.size = sound.soft.size;
+       }
+       AmiInit();
 
-    return(format);
+       return(format);
 }
 
 
@@ -2190,22 +2771,22 @@ static int AmiSetFormat(int format)
 
 static int AmiSetVolume(int volume)
 {
-    sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
-    custom.aud[0].audvol = sound.volume_left;
-    sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
-    custom.aud[1].audvol = sound.volume_right;
-    return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
-          (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+       sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
+       custom.aud[0].audvol = sound.volume_left;
+       sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
+       custom.aud[1].audvol = sound.volume_right;
+       return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
+              (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
 }
 
 static int AmiSetTreble(int treble)
 {
-    sound.treble = treble;
-    if (treble < 50)
-       ciaa.pra &= ~0x02;
-    else
-       ciaa.pra |= 0x02;
-    return(treble);
+       sound.treble = treble;
+       if (treble < 50)
+               ciaa.pra &= ~0x02;
+       else
+               ciaa.pra |= 0x02;
+       return(treble);
 }
 
 
@@ -2216,164 +2797,550 @@ static int AmiSetTreble(int treble)
 
 static void ami_sq_play_next_frame(int index)
 {
-    u_char *start, *ch0, *ch1, *ch2, *ch3;
-    u_long size;
-
-    /* used by AmiPlay() if all doubts whether there really is something
-     * to be played are already wiped out.
-     */
-    start = sq_block_address(sq.front);
-    size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
-
-    if (sound.hard.stereo) {
-       ch0 = start;
-       ch1 = start+sq.block_size_half;
-       size >>= 1;
-    } else {
-       ch0 = start;
-       ch1 = start;
-    }
-    if (sound.hard.size == 8) {
-       custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
-       custom.aud[0].audlen = size;
-       custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
-       custom.aud[1].audlen = size;
-       custom.dmacon = AMI_AUDIO_8;
-    } else {
-       size >>= 1;
-       custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
-       custom.aud[0].audlen = size;
-       custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
-       custom.aud[1].audlen = size;
-       if (sound.volume_left == 64 && sound.volume_right == 64) {
-           /* We can play pseudo 14-bit only with the maximum volume */
-           ch3 = ch0+sq.block_size_quarter;
-           ch2 = ch1+sq.block_size_quarter;
-           custom.aud[2].audvol = 1;  /* we are being affected by the beeps */
-           custom.aud[3].audvol = 1;  /* restoring volume here helps a bit */
-           custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
-           custom.aud[2].audlen = size;
-           custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
-           custom.aud[3].audlen = size;
-           custom.dmacon = AMI_AUDIO_14;
-       } else
-           custom.dmacon = AMI_AUDIO_8;
-    }
-    sq.front = (sq.front+1) % sq.max_count;
-    sq.playing |= AMI_PLAY_LOADED;
+       u_char *start, *ch0, *ch1, *ch2, *ch3;
+       u_long size;
+
+       /* used by AmiPlay() if all doubts whether there really is something
+        * to be played are already wiped out.
+        */
+       start = sq_block_address(sq.front);
+       size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
+
+       if (sound.hard.stereo) {
+               ch0 = start;
+               ch1 = start+sq.block_size_half;
+               size >>= 1;
+       } else {
+               ch0 = start;
+               ch1 = start;
+       }
+       if (sound.hard.size == 8) {
+               custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+               custom.aud[0].audlen = size;
+               custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+               custom.aud[1].audlen = size;
+               custom.dmacon = AMI_AUDIO_8;
+       } else {
+               size >>= 1;
+               custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+               custom.aud[0].audlen = size;
+               custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+               custom.aud[1].audlen = size;
+               if (sound.volume_left == 64 && sound.volume_right == 64) {
+                       /* We can play pseudo 14-bit only with the maximum volume */
+                       ch3 = ch0+sq.block_size_quarter;
+                       ch2 = ch1+sq.block_size_quarter;
+                       custom.aud[2].audvol = 1;  /* we are being affected by the beeps */
+                       custom.aud[3].audvol = 1;  /* restoring volume here helps a bit */
+                       custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
+                       custom.aud[2].audlen = size;
+                       custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
+                       custom.aud[3].audlen = size;
+                       custom.dmacon = AMI_AUDIO_14;
+               } else
+                       custom.dmacon = AMI_AUDIO_8;
+       }
+       sq.front = (sq.front+1) % sq.max_count;
+       sq.playing |= AMI_PLAY_LOADED;
 }
 
 
 static void AmiPlay(void)
 {
-    int minframes = 1;
+       int minframes = 1;
 
-    custom.intena = IF_AUD0;
+       custom.intena = IF_AUD0;
 
-    if (sq.playing & AMI_PLAY_LOADED) {
-       /* There's already a frame loaded */
-       custom.intena = IF_SETCLR | IF_AUD0;
-       return;
-    }
+       if (sq.playing & AMI_PLAY_LOADED) {
+               /* There's already a frame loaded */
+               custom.intena = IF_SETCLR | IF_AUD0;
+               return;
+       }
 
-    if (sq.playing & AMI_PLAY_PLAYING)
-       /* Increase threshold: frame 1 is already being played */
-       minframes = 2;
+       if (sq.playing & AMI_PLAY_PLAYING)
+               /* Increase threshold: frame 1 is already being played */
+               minframes = 2;
 
-    if (sq.count < minframes) {
-       /* Nothing to do */
-       custom.intena = IF_SETCLR | IF_AUD0;
-       return;
-    }
+       if (sq.count < minframes) {
+               /* Nothing to do */
+               custom.intena = IF_SETCLR | IF_AUD0;
+               return;
+       }
 
-    if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
-       /* hmmm, the only existing frame is not
-        * yet filled and we're not syncing?
-        */
-       custom.intena = IF_SETCLR | IF_AUD0;
-       return;
-    }
+       if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
+               /* hmmm, the only existing frame is not
+                * yet filled and we're not syncing?
+                */
+               custom.intena = IF_SETCLR | IF_AUD0;
+               return;
+       }
 
-    ami_sq_play_next_frame(minframes);
+       ami_sq_play_next_frame(minframes);
 
-    custom.intena = IF_SETCLR | IF_AUD0;
+       custom.intena = IF_SETCLR | IF_AUD0;
 }
 
 
 static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
-    int minframes = 1;
+       int minframes = 1;
 
-    if (!sq.playing) {
-       /* Playing was interrupted and sq_reset() has already cleared
-        * the sq variables, so better don't do anything here.
-        */
-       WAKE_UP(sq.sync_queue);
-       return;
-    }
+       if (!sq.playing) {
+               /* Playing was interrupted and sq_reset() has already cleared
+                * the sq variables, so better don't do anything here.
+                */
+               WAKE_UP(sq.sync_queue);
+               return;
+       }
 
-    if (sq.playing & AMI_PLAY_PLAYING) {
-       /* We've just finished a frame */
-       sq.count--;
-       WAKE_UP(sq.write_queue);
-    }
+       if (sq.playing & AMI_PLAY_PLAYING) {
+               /* We've just finished a frame */
+               sq.count--;
+               WAKE_UP(sq.write_queue);
+       }
 
-    if (sq.playing & AMI_PLAY_LOADED)
-       /* Increase threshold: frame 1 is already being played */
-       minframes = 2;
+       if (sq.playing & AMI_PLAY_LOADED)
+               /* Increase threshold: frame 1 is already being played */
+               minframes = 2;
 
-    /* Shift the flags */
-    sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
+       /* Shift the flags */
+       sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
 
-    if (!sq.playing)
-       /* No frame is playing, disable audio DMA */
-       custom.dmacon = AMI_AUDIO_OFF;
+       if (!sq.playing)
+               /* No frame is playing, disable audio DMA */
+               custom.dmacon = AMI_AUDIO_OFF;
 
-    if (sq.count >= minframes)
-       /* Try to play the next frame */
-       AmiPlay();
+       if (sq.count >= minframes)
+               /* Try to play the next frame */
+               AmiPlay();
 
-    if (!sq.playing)
-       /* Nothing to play anymore.
-          Wake up a process waiting for audio output to drain. */
-       WAKE_UP(sq.sync_queue);
+       if (!sq.playing)
+               /* Nothing to play anymore.
+                  Wake up a process waiting for audio output to drain. */
+               WAKE_UP(sq.sync_queue);
 }
 #endif /* CONFIG_AMIGA */
 
+#ifdef CONFIG_PMAC
+
+/*
+ * PCI PowerMac, with AWACS and DBDMA.
+ */
+
+static void *PMacAlloc(unsigned int size, int flags)
+{
+       return kmalloc(size, flags);
+}
+
+static void PMacFree(void *ptr, unsigned int size)
+{
+       kfree(ptr);
+}
+
+static int PMacIrqInit(void)
+{
+       if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
+           || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0))
+               return 0;
+       return 1;
+}
+
+#ifdef MODULE
+static void PMacIrqCleanup(void)
+{
+       /* turn off output dma */
+       out_le32(&awacs_txdma->control, RUN<<16);
+       /* disable interrupts from awacs interface */
+       out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
+       free_irq(awacs_irq, pmac_awacs_intr);
+       free_irq(awacs_tx_irq, pmac_awacs_tx_intr);
+       kfree(awacs_tx_cmd_space);
+       if (beep_buf)
+               kfree(beep_buf);
+       kd_mksound = orig_mksound;
+}
+#endif /* MODULE */
+
+static void PMacSilence(void)
+{
+       /* turn off output dma */
+       out_le32(&awacs_txdma->control, RUN<<16);
+}
+
+static int awacs_freqs[8] = {
+       44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
+};
+
+static void PMacInit(void)
+{
+       int i, tolerance;
+
+       switch (sound.soft.format) {
+       case AFMT_S16_LE:
+       case AFMT_U16_LE:
+               sound.hard.format = AFMT_S16_LE;
+               break;
+       default:
+               sound.hard.format = AFMT_S16_BE;
+               break;
+       }
+       sound.hard.stereo = 1;
+       sound.hard.size = 16;
+
+       /*
+        * If we have a sample rate which is within catchRadius percent
+        * of the requested value, we don't have to expand the samples.
+        * Otherwise choose the next higher rate.
+        */
+       i = 8;
+       do {
+               tolerance = catchRadius * awacs_freqs[--i] / 100;
+       } while (sound.soft.speed > awacs_freqs[i] + tolerance && i > 0);
+       if (sound.soft.speed >= awacs_freqs[i] - tolerance)
+               sound.trans = &transAwacsNormal;
+       else
+               sound.trans = &transAwacsExpand;
+       sound.hard.speed = awacs_freqs[i];
+       awacs_rate_index = i;
+
+       PMacSilence();
+       out_le32(&awacs->control, MASK_IEPC | MASK_IEE | (i << 8) | 0x11);
+       awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
+       awacs_write(awacs_reg[1] | MASK_ADDR1);
+       out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+
+       sound.bal = -sound.soft.speed;
+}
+
+static int PMacSetFormat(int format)
+{
+       int size;
+
+       switch (format) {
+       case AFMT_QUERY:
+               return sound.soft.format;
+       case AFMT_MU_LAW:
+       case AFMT_A_LAW:
+       case AFMT_U8:
+       case AFMT_S8:
+               size = 8;
+               break;
+       case AFMT_S16_BE:
+       case AFMT_U16_BE:
+       case AFMT_S16_LE:
+       case AFMT_U16_LE:
+               size = 16;
+               break;
+       default: /* :-) */
+               printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
+                      format);
+               size = 8;
+               format = AFMT_U8;
+       }
+
+       sound.soft.format = format;
+       sound.soft.size = size;
+       if (sound.minDev == SND_DEV_DSP) {
+               sound.dsp.format = format;
+               sound.dsp.size = size;
+       }
+
+       PMacInit();
+
+       return format;
+}
+
+#define AWACS_VOLUME_TO_MASK(x)        (15 - ((((x) - 1) * 15) / 99))
+#define AWACS_MASK_TO_VOLUME(y)        (100 - ((y) * 99 / 15))
+
+static int awacs_get_volume(int reg, int lshift)
+{
+       int volume;
+
+       volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
+       volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
+       return volume;
+}
+
+static int awacs_volume_setter(int volume, int n, int mute, int lshift)
+{
+       int r1, rn;
+
+       if (mute && volume == 0) {
+               r1 = awacs_reg[1] | mute;
+       } else {
+               r1 = awacs_reg[1] & ~mute;
+               rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
+               rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
+               rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
+               awacs_reg[n] = rn;
+               awacs_write((n << 12) | rn);
+               volume = awacs_get_volume(rn, lshift);
+       }
+       if (r1 != awacs_reg[1]) {
+               awacs_reg[1] = r1;
+               awacs_write(r1 | MASK_ADDR1);
+       }
+       return volume;
+}
+
+static int PMacSetVolume(int volume)
+{
+       return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);
+}
+
+static void PMacPlay(void)
+{
+       volatile struct dbdma_cmd *cp;
+       int i, count;
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       if (beep_playing) {
+               /* sound takes precedence over beeps */
+               out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+               out_le32(&awacs->control,
+                        (in_le32(&awacs->control) & ~0x1f00)
+                        || (awacs_rate_index << 8));
+               out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+               beep_playing = 0;
+       }
+       i = sq.front + sq.playing;
+       if (i >= sq.max_count)
+               i -= sq.max_count;
+       while (sq.playing < 2 && sq.playing < sq.count) {
+               count = (sq.count == sq.playing + 1)? sq.rear_size: sq.block_size;
+               if (count < sq.block_size && !sq.syncing)
+                       /* last block not yet filled, and we're not syncing. */
+                       break;
+               cp = &awacs_tx_cmds[i];
+               st_le16(&cp->req_count, count);
+               st_le16(&cp->xfer_status, 0);
+               if (++i >= sq.max_count)
+                       i = 0;
+               out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
+               out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
+               if (sq.playing == 0)
+                       out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
+               out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+               ++sq.playing;
+       }
+       restore_flags(flags);
+}
+
+static void
+pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+       int i = sq.front;
+       int stat;
+       volatile struct dbdma_cmd *cp;
+
+       while (sq.playing > 0) {
+               cp = &awacs_tx_cmds[i];
+               stat = ld_le16(&cp->xfer_status);
+               if ((stat & ACTIVE) == 0)
+                       break;  /* this frame is still going */
+               --sq.count;
+               --sq.playing;
+               if (++i >= sq.max_count)
+                       i = 0;
+       }
+       if (i != sq.front)
+               WAKE_UP(sq.write_queue);
+       sq.front = i;
+
+       PMacPlay();
+
+       if (!sq.playing)
+               WAKE_UP(sq.sync_queue);
+}
+
+static void
+pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
+{
+       int ctrl = in_le32(&awacs->control);
+
+       if (ctrl & MASK_PORTCHG) {
+               /* do something when headphone is plugged/unplugged? */
+       }
+       if (ctrl & MASK_CNTLERR) {
+               printk(KERN_ERR "AWACS: error, status = %x\n",
+                      in_le32(&awacs->codec_stat));
+       }
+       /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
+       out_le32(&awacs->control, ctrl);
+}
+
+static void
+awacs_write(int val)
+{
+       while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
+               ;       /* XXX should have timeout */
+       out_le32(&awacs->codec_ctrl, val);
+}
+
+static void awacs_nosound(unsigned long xx)
+{
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       if (beep_playing) {
+               st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+               beep_playing = 0;
+       }
+       restore_flags(flags);
+}
+
+static struct timer_list beep_timer = {
+       NULL, NULL, 0, 0, awacs_nosound
+};
+
+static void awacs_mksound(unsigned int hz, unsigned int ticks)
+{
+       unsigned long flags;
+       int srate = awacs_freqs[BEEP_SPEED];
+       int period, ncycles, nsamples;
+       int i, j, f;
+       short *p;
+       static int beep_hz_cache;
+       static int beep_nsamples_cache;
+       static int beep_volume_cache;
+
+       if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
+#if 1
+               /* this is a hack for broken X server code */
+               hz = 750;
+               ticks = 12;
+#else
+               /* cancel beep currently playing */
+               awacs_nosound(0);
+               return;
+#endif
+       }
+       save_flags(flags); cli();
+       del_timer(&beep_timer);
+       if (ticks) {
+               beep_timer.expires = jiffies + ticks;
+               add_timer(&beep_timer);
+       }
+       if (beep_playing || sq.playing || beep_buf == NULL) {
+               restore_flags(flags);
+               return;         /* too hard, sorry :-( */
+       }
+       beep_playing = 1;
+       st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
+       restore_flags(flags);
+
+       if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
+               nsamples = beep_nsamples_cache;
+       } else {
+               period = srate * 256 / hz;      /* fixed point */
+               ncycles = BEEP_BUFLEN * 256 / period;
+               nsamples = (period * ncycles) >> 8;
+               f = ncycles * 65536 / nsamples;
+               j = 0;
+               p = beep_buf;
+               for (i = 0; i < nsamples; ++i, p += 2) {
+                       p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
+                       j = (j + f) & 0xffff;
+               }
+               beep_hz_cache = hz;
+               beep_volume_cache = beep_volume;
+               beep_nsamples_cache = nsamples;
+       }
+
+       st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
+       st_le16(&beep_dbdma_cmd->xfer_status, 0);
+       st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
+       st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
+
+       save_flags(flags); cli();
+       if (beep_playing) {     /* i.e. haven't been terminated already */
+               out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+               out_le32(&awacs->control,
+                        (in_le32(&awacs->control) & ~0x1f00)
+                        | (BEEP_SPEED << 8));
+               out_le32(&awacs->byteswap, 0);
+               out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+               out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+       }
+       restore_flags(flags);
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Save state when going to sleep, restore it afterwards.
+ */
+static int awacs_sleep_notify(struct notifier_block *this,
+                             unsigned long code, void *x)
+{
+       switch (code) {
+       case PBOOK_SLEEP:
+               /* XXX we should stop any dma in progress when going to sleep
+                  and restart it when we wake. */
+               PMacSilence();
+               break;
+       case PBOOK_WAKE:
+               out_le32(&awacs->control, MASK_IEPC | MASK_IEE |
+                        (awacs_rate_index << 8) | 0x11);
+               awacs_write(awacs_reg[0] | MASK_ADDR0);
+               awacs_write(awacs_reg[1] | MASK_ADDR1);
+               awacs_write(awacs_reg[2] | MASK_ADDR2);
+               awacs_write(awacs_reg[4] | MASK_ADDR4);
+               out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+       }
+       return NOTIFY_DONE;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+#endif /* CONFIG_PMAC */
 
 /*** Machine definitions *****************************************************/
 
 
 #ifdef CONFIG_ATARI
 static MACHINE machTT = {
-    DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
+       DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
 #ifdef MODULE
-    AtaIrqCleanUp,
+       AtaIrqCleanUp,
 #endif /* MODULE */
-    TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble,
-    TTSetGain,
-    AtaPlay
+       TTInit, TTSilence, TTSetFormat, TTSetVolume,
+       AtaSetBass, AtaSetTreble, TTSetGain,
+       AtaPlay
 };
 
 static MACHINE machFalcon = {
-    DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
+       DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
 #ifdef MODULE
-    AtaIrqCleanUp,
+       AtaIrqCleanUp,
 #endif /* MODULE */
-    FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass,
-    AtaSetTreble, NULL, AtaPlay
+       FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume,
+       AtaSetBass, AtaSetTreble, NULL,
+       AtaPlay
 };
 #endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
 static MACHINE machAmiga = {
-    DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
+       DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
+#ifdef MODULE
+       AmiIrqCleanUp,
+#endif /* MODULE */
+       AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume,
+       NULL, AmiSetTreble, NULL,
+       AmiPlay
+};
+#endif /* CONFIG_AMIGA */
+
+#ifdef CONFIG_PMAC
+static MACHINE machPMac = {
+       DMASND_AWACS, PMacAlloc, PMacFree, PMacIrqInit,
 #ifdef MODULE
-    AmiIrqCleanUp,
+       PMacIrqCleanup,
 #endif /* MODULE */
-    AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble,
-    NULL,
-    AmiPlay
+       PMacInit, PMacSilence, PMacSetFormat, PMacSetVolume,
+       NULL, NULL, NULL,       /* bass, treble, gain */
+       PMacPlay
 };
 #endif /* CONFIG_AMIGA */
 
@@ -2383,78 +3350,79 @@ static MACHINE machAmiga = {
 
 static void sound_silence(void)
 {
-    /* update hardware settings one more */
-    (*sound.mach.init)();
+       /* update hardware settings one more */
+       (*sound.mach.init)();
 
-    (*sound.mach.silence)();
+       (*sound.mach.silence)();
 }
 
 
 static void sound_init(void)
 {
-    (*sound.mach.init)();
+       (*sound.mach.init)();
 }
 
 
 static int sound_set_format(int format)
 {
-    return(*sound.mach.setFormat)(format);
+       return(*sound.mach.setFormat)(format);
 }
 
 
 static int sound_set_speed(int speed)
 {
-    if (speed < 0)
-       return(sound.soft.speed);
+       if (speed < 0)
+               return(sound.soft.speed);
 
-    sound.soft.speed = speed;
-    (*sound.mach.init)();
-    if (sound.minDev == SND_DEV_DSP)
-       sound.dsp.speed = sound.soft.speed;
+       sound.soft.speed = speed;
+       (*sound.mach.init)();
+       if (sound.minDev == SND_DEV_DSP)
+               sound.dsp.speed = sound.soft.speed;
 
-    return(sound.soft.speed);
+       return(sound.soft.speed);
 }
 
 
 static int sound_set_stereo(int stereo)
 {
-    if (stereo < 0)
-       return(sound.soft.stereo);
+       if (stereo < 0)
+               return(sound.soft.stereo);
 
-    stereo = !!stereo;    /* should be 0 or 1 now */
+       stereo = !!stereo;    /* should be 0 or 1 now */
 
-    sound.soft.stereo = stereo;
-    if (sound.minDev == SND_DEV_DSP)
-       sound.dsp.stereo = stereo;
-    (*sound.mach.init)();
+       sound.soft.stereo = stereo;
+       if (sound.minDev == SND_DEV_DSP)
+               sound.dsp.stereo = stereo;
+       (*sound.mach.init)();
 
-    return(stereo);
+       return(stereo);
 }
 
 
 static int sound_set_volume(int volume)
 {
-    return(*sound.mach.setVolume)(volume);
+       return(*sound.mach.setVolume)(volume);
 }
 
 
 #ifdef CONFIG_ATARI
 static int sound_set_bass(int bass)
 {
-    return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
+       return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
 }
 
 static int sound_set_gain(int gain)
 {
-    return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
+       return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
 }
 #endif /* CONFIG_ATARI */
 
-
+#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
 static int sound_set_treble(int treble)
 {
-    return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
+       return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
 }
+#endif /* CONFIG_ATARI || CONFIG_AMIGA */
 
 
 static long sound_copy_translate(const u_char *userPtr,
@@ -2462,38 +3430,38 @@ static long sound_copy_translate(const u_char *userPtr,
                                 u_char frame[], long *frameUsed,
                                 long frameLeft)
 {
-    long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL;
+       long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL;
 
-    switch (sound.soft.format) {
+       switch (sound.soft.format) {
        case AFMT_MU_LAW:
-           ct_func = sound.trans->ct_ulaw;
-           break;
+               ct_func = sound.trans->ct_ulaw;
+               break;
        case AFMT_A_LAW:
-           ct_func = sound.trans->ct_alaw;
-           break;
+               ct_func = sound.trans->ct_alaw;
+               break;
        case AFMT_S8:
-           ct_func = sound.trans->ct_s8;
-           break;
+               ct_func = sound.trans->ct_s8;
+               break;
        case AFMT_U8:
-           ct_func = sound.trans->ct_u8;
-           break;
+               ct_func = sound.trans->ct_u8;
+               break;
        case AFMT_S16_BE:
-           ct_func = sound.trans->ct_s16be;
-           break;
+               ct_func = sound.trans->ct_s16be;
+               break;
        case AFMT_U16_BE:
-           ct_func = sound.trans->ct_u16be;
-           break;
+               ct_func = sound.trans->ct_u16be;
+               break;
        case AFMT_S16_LE:
-           ct_func = sound.trans->ct_s16le;
-           break;
+               ct_func = sound.trans->ct_s16le;
+               break;
        case AFMT_U16_LE:
-           ct_func = sound.trans->ct_u16le;
-           break;
-    }
-    if (ct_func)
-       return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft));
-    else
-       return(0);
+               ct_func = sound.trans->ct_u16le;
+               break;
+       }
+       if (ct_func)
+               return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft));
+       else
+               return(0);
 }
 
 
@@ -2509,201 +3477,308 @@ static long sound_copy_translate(const u_char *userPtr,
 
 static void mixer_init(void)
 {
-    mixer.busy = 0;
-    sound.treble = 0;
-    sound.bass = 0;
-    switch (sound.mach.type) {
+       mixer.busy = 0;
+       sound.treble = 0;
+       sound.bass = 0;
+       switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
        case DMASND_TT:
-           atari_microwire_cmd(MW_LM1992_VOLUME(0));
-           sound.volume_left = 0;
-           atari_microwire_cmd(MW_LM1992_BALLEFT(0));
-           sound.volume_right = 0;
-           atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
-           atari_microwire_cmd(MW_LM1992_TREBLE(0));
-           atari_microwire_cmd(MW_LM1992_BASS(0));
-           break;
+               atari_microwire_cmd(MW_LM1992_VOLUME(0));
+               sound.volume_left = 0;
+               atari_microwire_cmd(MW_LM1992_BALLEFT(0));
+               sound.volume_right = 0;
+               atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
+               atari_microwire_cmd(MW_LM1992_TREBLE(0));
+               atari_microwire_cmd(MW_LM1992_BASS(0));
+               break;
        case DMASND_FALCON:
-           sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
-           sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
-           break;
+               sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
+               sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
+               break;
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
        case DMASND_AMIGA:
-           sound.volume_left = 64;
-           sound.volume_right = 64;
-           custom.aud[0].audvol = sound.volume_left;
-           custom.aud[3].audvol = 1;                   /* For pseudo 14bit */
-           custom.aud[1].audvol = sound.volume_right;
-           custom.aud[2].audvol = 1;                   /* For pseudo 14bit */
-           sound.treble = 50;
-           break;
+               sound.volume_left = 64;
+               sound.volume_right = 64;
+               custom.aud[0].audvol = sound.volume_left;
+               custom.aud[3].audvol = 1;       /* For pseudo 14bit */
+               custom.aud[1].audvol = sound.volume_right;
+               custom.aud[2].audvol = 1;       /* For pseudo 14bit */
+               sound.treble = 50;
+               break;
 #endif /* CONFIG_AMIGA */
-    }
+       }
 }
 
 
 static int mixer_open(int open_mode)
 {
-    if (mixer.busy)
-       return(-EBUSY);
-    mixer.busy = 1;
-    return(0);
+       mixer.busy = 1;
+       return(0);
 }
 
 
 static int mixer_release(void)
 {
-    mixer.busy = 0;
-    return(0);
+       mixer.busy = 0;
+       return(0);
 }
 
 
 static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
                       u_long arg)
 {
-    int data;
-    switch (sound.mach.type) {
+       int data;
+       switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
        case DMASND_FALCON:
-           switch (cmd) {
+               switch (cmd) {
                case SOUND_MIXER_READ_DEVMASK:
-                   return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+                       return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
                case SOUND_MIXER_READ_RECMASK:
-                   return(IOCTL_OUT(arg, SOUND_MASK_MIC));
+                       return(IOCTL_OUT(arg, SOUND_MASK_MIC));
                case SOUND_MIXER_READ_STEREODEVS:
-                   return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
+                       return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
                case SOUND_MIXER_READ_CAPS:
-                   return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT));
+                       return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT));
                case SOUND_MIXER_READ_VOLUME:
-                   return(IOCTL_OUT(arg,
-                       VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
-                       VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8));
+                       return(IOCTL_OUT(arg,
+                               VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
+                               VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8));
                case SOUND_MIXER_WRITE_MIC:
-                   IOCTL_IN(arg, data);
-                   tt_dmasnd.input_gain =
-                       RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
-                       RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
-                   /* fall thru, return set value */
+                       IOCTL_IN(arg, data);
+                       tt_dmasnd.input_gain =
+                               RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
+                               RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
+                       /* fall thru, return set value */
                case SOUND_MIXER_READ_MIC:
-                   return(IOCTL_OUT(arg,
-                       RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
-                       RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8));
+                       return(IOCTL_OUT(arg,
+                               RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
+                               RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8));
                case SOUND_MIXER_READ_SPEAKER:
-                   {
-                       int porta;
-                       cli();
-                       sound_ym.rd_data_reg_sel = 14;
-                       porta = sound_ym.rd_data_reg_sel;
-                       sti();
-                       return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-                   }
+                       {
+                               int porta;
+                               cli();
+                               sound_ym.rd_data_reg_sel = 14;
+                               porta = sound_ym.rd_data_reg_sel;
+                               sti();
+                               return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+                       }
                case SOUND_MIXER_WRITE_VOLUME:
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_volume(data)));
-               case SOUND_MIXER_WRITE_SPEAKER:
-                   {
-                       int porta;
                        IOCTL_IN(arg, data);
-                       cli();
-                       sound_ym.rd_data_reg_sel = 14;
-                       porta = (sound_ym.rd_data_reg_sel & ~0x40) |
-                               (data < 50 ? 0x40 : 0);
-                       sound_ym.wd_data = porta;
-                       sti();
-                       return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-                   }
-           }
-           break;
+                       return(IOCTL_OUT(arg, sound_set_volume(data)));
+               case SOUND_MIXER_WRITE_SPEAKER:
+                       {
+                               int porta;
+                               IOCTL_IN(arg, data);
+                               cli();
+                               sound_ym.rd_data_reg_sel = 14;
+                               porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+                                       (data < 50 ? 0x40 : 0);
+                               sound_ym.wd_data = porta;
+                               sti();
+                               return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+                       }
+               }
+               break;
 
        case DMASND_TT:
-           switch (cmd) {
+               switch (cmd) {
                case SOUND_MIXER_READ_DEVMASK:
-                   return(IOCTL_OUT(arg,
-                       SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
-                       (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0)));
+                       return(IOCTL_OUT(arg,
+                                        SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
+                                        (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0)));
                case SOUND_MIXER_READ_RECMASK:
-                   return(IOCTL_OUT(arg, 0));
+                       return(IOCTL_OUT(arg, 0));
                case SOUND_MIXER_READ_STEREODEVS:
-                   return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+                       return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
                case SOUND_MIXER_READ_VOLUME:
-                   return(IOCTL_OUT(arg,
-                       VOLUME_DB_TO_VOXWARE(sound.volume_left) |
-                       (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)));
+                       return(IOCTL_OUT(arg,
+                                        VOLUME_DB_TO_VOXWARE(sound.volume_left) |
+                                        (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)));
                case SOUND_MIXER_READ_BASS:
-                   return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass)));
+                       return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass)));
                case SOUND_MIXER_READ_TREBLE:
-                   return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble)));
+                       return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble)));
                case SOUND_MIXER_READ_OGAIN:
-                   return(IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain)));
+                       return(IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain)));
                case SOUND_MIXER_READ_SPEAKER:
-                   {
-                       int porta;
-                       if (MACH_IS_TT) {
-                           cli();
-                           sound_ym.rd_data_reg_sel = 14;
-                           porta = sound_ym.rd_data_reg_sel;
-                           sti();
-                           return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-                       } else
-                           return(-EINVAL);
-                   }
+                       {
+                               int porta;
+                               if (MACH_IS_TT) {
+                                       cli();
+                                       sound_ym.rd_data_reg_sel = 14;
+                                       porta = sound_ym.rd_data_reg_sel;
+                                       sti();
+                                       return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+                               } else
+                                       return(-EINVAL);
+                       }
                case SOUND_MIXER_WRITE_VOLUME:
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_volume(data)));
+                       IOCTL_IN(arg, data);
+                       return(IOCTL_OUT(arg, sound_set_volume(data)));
                case SOUND_MIXER_WRITE_BASS:
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_bass(data)));
+                       IOCTL_IN(arg, data);
+                       return(IOCTL_OUT(arg, sound_set_bass(data)));
                case SOUND_MIXER_WRITE_TREBLE:
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_treble(data)));
+                       IOCTL_IN(arg, data);
+                       return(IOCTL_OUT(arg, sound_set_treble(data)));
                case SOUND_MIXER_WRITE_OGAIN:
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_gain(data)));
-               case SOUND_MIXER_WRITE_SPEAKER:
-                   if (MACH_IS_TT) {
-                       int porta;
                        IOCTL_IN(arg, data);
-                       cli();
-                       sound_ym.rd_data_reg_sel = 14;
-                       porta = (sound_ym.rd_data_reg_sel & ~0x40) |
-                               (data < 50 ? 0x40 : 0);
-                       sound_ym.wd_data = porta;
-                       sti();
-                       return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-                   } else
-                       return(-EINVAL);
-           }
-           break;
+                       return(IOCTL_OUT(arg, sound_set_gain(data)));
+               case SOUND_MIXER_WRITE_SPEAKER:
+                       if (MACH_IS_TT) {
+                               int porta;
+                               IOCTL_IN(arg, data);
+                               cli();
+                               sound_ym.rd_data_reg_sel = 14;
+                               porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+                                       (data < 50 ? 0x40 : 0);
+                               sound_ym.wd_data = porta;
+                               sti();
+                               return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+                       } else
+                               return(-EINVAL);
+               }
+               break;
 #endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
        case DMASND_AMIGA:
-           switch (cmd) {
+               switch (cmd) {
                case SOUND_MIXER_READ_DEVMASK:
-                   return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
+                       return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
                case SOUND_MIXER_READ_RECMASK:
-                   return(IOCTL_OUT(arg, 0));
+                       return(IOCTL_OUT(arg, 0));
                case SOUND_MIXER_READ_STEREODEVS:
-                   return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+                       return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
                case SOUND_MIXER_READ_VOLUME:
-                   return(IOCTL_OUT(arg,
-                       VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
-                       VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+                       return(IOCTL_OUT(arg,
+                               VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
+                               VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
                case SOUND_MIXER_WRITE_VOLUME:
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_volume(data)));
+                       IOCTL_IN(arg, data);
+                       return(IOCTL_OUT(arg, sound_set_volume(data)));
                case SOUND_MIXER_READ_TREBLE:
-                   return(IOCTL_OUT(arg, sound.treble));
+                       return(IOCTL_OUT(arg, sound.treble));
                case SOUND_MIXER_WRITE_TREBLE:
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_treble(data)));
-           }
-           break;
+                       IOCTL_IN(arg, data);
+                       return(IOCTL_OUT(arg, sound_set_treble(data)));
+               }
+               break;
 #endif /* CONFIG_AMIGA */
-    }
 
-    return(-EINVAL);
+#ifdef CONFIG_PMAC
+       case DMASND_AWACS:
+               switch (cmd) {
+               case SOUND_MIXER_READ_DEVMASK:
+                       data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+                               | SOUND_MASK_LINE | SOUND_MASK_MIC
+                               | SOUND_MASK_CD | SOUND_MASK_RECLEV
+                               | SOUND_MASK_ALTPCM;
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_READ_RECMASK:
+                       data = SOUND_MASK_LINE | SOUND_MASK_MIC
+                               | SOUND_MASK_CD;
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_READ_RECSRC:
+                       data = 0;
+                       if (awacs_reg[0] & MASK_MUX_AUDIN)
+                               data |= SOUND_MASK_LINE;
+                       if (awacs_reg[0] & MASK_MUX_MIC)
+                               data |= SOUND_MASK_MIC;
+                       if (awacs_reg[0] & MASK_MUX_CD)
+                               data |= SOUND_MASK_CD;
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_WRITE_RECSRC:
+                       IOCTL_IN(arg, data);
+                       data &= (SOUND_MASK_LINE
+                                | SOUND_MASK_MIC | SOUND_MASK_CD);
+                       awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
+                                       | MASK_MUX_AUDIN);
+                       if (data & SOUND_MASK_LINE)
+                               awacs_reg[0] |= MASK_MUX_AUDIN;
+                       if (data & SOUND_MASK_MIC)
+                               awacs_reg[0] |= MASK_MUX_MIC;
+                       if (data & SOUND_MASK_CD)
+                               awacs_reg[0] |= MASK_MUX_CD;
+                       awacs_write(awacs_reg[0] | MASK_ADDR0);
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_READ_STEREODEVS:
+                       data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+                               | SOUND_MASK_RECLEV;
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_READ_CAPS:
+                       return IOCTL_OUT(arg, 0);
+               case SOUND_MIXER_READ_VOLUME:
+                       data = (awacs_reg[1] & MASK_AMUTE)? 0:
+                               awacs_get_volume(awacs_reg[2], 6);
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_WRITE_VOLUME:
+                       IOCTL_IN(arg, data);
+                       return IOCTL_OUT(arg, sound_set_volume(data));
+               case SOUND_MIXER_READ_SPEAKER:
+                       data = (awacs_reg[1] & MASK_CMUTE)? 0:
+                               awacs_get_volume(awacs_reg[4], 6);
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_WRITE_SPEAKER:
+                       IOCTL_IN(arg, data);
+                       data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_WRITE_ALTPCM:  /* really bell volume */
+                       IOCTL_IN(arg, data);
+                       beep_volume = data & 0xff;
+                       /* fall through */
+               case SOUND_MIXER_READ_ALTPCM:
+                       return IOCTL_OUT(arg, beep_volume);
+               case SOUND_MIXER_WRITE_LINE:
+                       IOCTL_IN(arg, data);
+                       awacs_reg[0] &= ~MASK_MUX_AUDIN;
+                       if ((data & 0xff) >= 50)
+                               awacs_reg[0] |= MASK_MUX_AUDIN;
+                       awacs_write(MASK_ADDR0 | awacs_reg[0]);
+                       /* fall through */
+               case SOUND_MIXER_READ_LINE:
+                       data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_WRITE_MIC:
+                       IOCTL_IN(arg, data);
+                       data &= 0xff;
+                       awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);
+                       if (data >= 25) {
+                               awacs_reg[0] |= MASK_MUX_MIC;
+                               if (data >= 75)
+                                       awacs_reg[0] |= MASK_GAINLINE;
+                       }
+                       awacs_write(MASK_ADDR0 | awacs_reg[0]);
+                       /* fall through */
+               case SOUND_MIXER_READ_MIC:
+                       data = (awacs_reg[0] & MASK_MUX_MIC)?
+                               (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_WRITE_CD:
+                       IOCTL_IN(arg, data);
+                       awacs_reg[0] &= ~MASK_MUX_CD;
+                       if ((data & 0xff) >= 50)
+                               awacs_reg[0] |= MASK_MUX_CD;
+                       awacs_write(MASK_ADDR0 | awacs_reg[0]);
+                       /* fall through */
+               case SOUND_MIXER_READ_CD:
+                       data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_WRITE_RECLEV:
+                       IOCTL_IN(arg, data);
+                       data = awacs_volume_setter(data, 0, 0, 4);
+                       return IOCTL_OUT(arg, data);
+               case SOUND_MIXER_READ_RECLEV:
+                       data = awacs_get_volume(awacs_reg[0], 4);
+                       return IOCTL_OUT(arg, data);
+               }
+               break;
+#endif
+       }
+
+       return(-EINVAL);
 }
 
 
@@ -2715,62 +3790,88 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
 
 static void sq_init(int numBufs, int bufSize, char **buffers)
 {
-    sq.max_count = numBufs;
-    sq.block_size = bufSize;
-    sq.buffers = buffers;
-
-    sq.front = sq.count = 0;
-    sq.rear = -1;
-    sq.write_queue = sq.open_queue = sq.sync_queue = 0;
-    sq.busy = 0;
-    sq.syncing = 0;
+#ifdef CONFIG_PMAC
+       int i;
+       volatile struct dbdma_cmd *cp;
+#endif /* CONFIG_PMAC */
+
+       sq.max_count = numBufs;
+       sq.max_active = numBufs;
+       sq.block_size = bufSize;
+       sq.buffers = buffers;
+
+       sq.front = sq.count = 0;
+       sq.rear = -1;
+       sq.write_queue = sq.open_queue = sq.sync_queue = 0;
+       sq.busy = 0;
+       sq.syncing = 0;
 
-    sq.playing = 0;
+       sq.playing = 0;
 
 #ifdef CONFIG_ATARI
-    sq.ignore_int = 0;
+       sq.ignore_int = 0;
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-    sq.block_size_half = sq.block_size>>1;
-    sq.block_size_quarter = sq.block_size_half>>1;
+       sq.block_size_half = sq.block_size>>1;
+       sq.block_size_quarter = sq.block_size_half>>1;
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+       cp = awacs_tx_cmds;
+       memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
+       for (i = 0; i < numBufs; ++i, ++cp) {
+               st_le32(&cp->phy_addr, virt_to_bus(buffers[i]));
+       }
+       st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+       st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
+       out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+       out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
+#endif /* CONFIG_PMAC */
+}
 
-    sound_silence();
-
-    /* whatever you like as startup mode for /dev/dsp,
-     * (/dev/audio hasn't got a startup mode). note that
-     * once changed a new open() will *not* restore these!
-     */
-    sound.dsp.format = AFMT_S8;
-    sound.dsp.stereo = 0;
-    sound.dsp.size = 8;
+static void
+init_settings(void)
+{
+       /* whatever you like as startup mode for /dev/dsp,
+        * (/dev/audio hasn't got a startup mode). note that
+        * once changed a new open() will *not* restore these!
+        */
+       sound.dsp.format = AFMT_U8;
+       sound.dsp.stereo = 0;
+       sound.dsp.size = 8;
 
-    /* set minimum rate possible without expanding */
-    switch (sound.mach.type) {
+       /* set minimum rate possible without expanding */
+       switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
        case DMASND_TT:
-           sound.dsp.speed = 6258;
-           break;
+               sound.dsp.speed = 6258;
+               break;
        case DMASND_FALCON:
-           sound.dsp.speed = 8195;
-           break;
+               sound.dsp.speed = 8195;
+               break;
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
        case DMASND_AMIGA:
-           sound.dsp.speed = 8000;
-           break;
+               sound.dsp.speed = 8000;
+               break;
 #endif /* CONFIG_AMIGA */
-    }
+#ifdef CONFIG_PMAC
+       case DMASND_AWACS:
+               sound.dsp.speed = 8000;
+               break;
+#endif /* CONFIG_PMAC */
+       }
+
+       /* before the first open to /dev/dsp this wouldn't be set */
+       sound.soft = sound.dsp;
+       sound.hard = sound.dsp;
 
-    /* before the first open to /dev/dsp this wouldn't be set */
-    sound.soft = sound.dsp;
-    sound.hard = sound.dsp;
+       sound_silence();
 }
 
 
 static void sq_play(void)
 {
-    (*sound.mach.play)();
+       (*sound.mach.play)();
 }
 
 
@@ -2778,133 +3879,139 @@ static void sq_play(void)
 
 static long sq_write(const char *src, unsigned long uLeft)
 {
-    long uWritten = 0;
-    u_char *dest;
-    long uUsed, bUsed, bLeft;
+       long uWritten = 0;
+       u_char *dest;
+       long uUsed, bUsed, bLeft;
 
-    /* ++TeSche: Is something like this necessary?
-     * Hey, that's an honest question! Or does any other part of the
-     * filesystem already checks this situation? I really don't know.
-     */
-    if (uLeft == 0)
-       return(0);
+       /* ++TeSche: Is something like this necessary?
+        * Hey, that's an honest question! Or does any other part of the
+        * filesystem already checks this situation? I really don't know.
+        */
+       if (uLeft == 0)
+               return(0);
 
-    /* The interrupt doesn't start to play the last, incomplete frame.
-     * Thus we can append to it without disabling the interrupts! (Note
-     * also that sq.rear isn't affected by the interrupt.)
-     */
-
-    if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
-       dest = sq_block_address(sq.rear);
-       bUsed = sq.rear_size;
-       uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-       src += uUsed;
-       uWritten += uUsed;
-       uLeft -= uUsed;
-       sq.rear_size = bUsed;
-    }
-
-    do {
-       while (sq.count == sq.max_count) {
-           sq_play();
-           if (NON_BLOCKING(sq.open_mode))
-               return(uWritten > 0 ? uWritten : -EAGAIN);
-           SLEEP(sq.write_queue, ONE_SECOND);
-           if (SIGNAL_RECEIVED)
-               return(uWritten > 0 ? uWritten : -EINTR);
-       }
-
-       /* Here, we can avoid disabling the interrupt by first
-        * copying and translating the data, and then updating
-        * the sq variables. Until this is done, the interrupt
-        * won't see the new frame and we can work on it
-        * undisturbed.
+       /* The interrupt doesn't start to play the last, incomplete frame.
+        * Thus we can append to it without disabling the interrupts! (Note
+        * also that sq.rear isn't affected by the interrupt.)
         */
 
-       dest = sq_block_address((sq.rear+1) % sq.max_count);
-       bUsed = 0;
-       bLeft = sq.block_size;
-       uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-       src += uUsed;
-       uWritten += uUsed;
-       uLeft -= uUsed;
-       if (bUsed) {
-           sq.rear = (sq.rear+1) % sq.max_count;
-           sq.rear_size = bUsed;
-           sq.count++;
+       if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
+               dest = sq_block_address(sq.rear);
+               bUsed = sq.rear_size;
+               uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
+               if (uUsed <= 0)
+                       return uUsed;
+               src += uUsed;
+               uWritten += uUsed;
+               uLeft -= uUsed;
+               sq.rear_size = bUsed;
        }
-    } while (bUsed);   /* uUsed may have been 0 */
 
-    sq_play();
+       do {
+               while (sq.count == sq.max_active) {
+                       sq_play();
+                       if (NON_BLOCKING(sq.open_mode))
+                               return(uWritten > 0 ? uWritten : -EAGAIN);
+                       SLEEP(sq.write_queue, ONE_SECOND);
+                       if (SIGNAL_RECEIVED)
+                               return(uWritten > 0 ? uWritten : -EINTR);
+               }
+
+               /* Here, we can avoid disabling the interrupt by first
+                * copying and translating the data, and then updating
+                * the sq variables. Until this is done, the interrupt
+                * won't see the new frame and we can work on it
+                * undisturbed.
+                */
+
+               dest = sq_block_address((sq.rear+1) % sq.max_count);
+               bUsed = 0;
+               bLeft = sq.block_size;
+               uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
+               if (uUsed <= 0)
+                       break;
+               src += uUsed;
+               uWritten += uUsed;
+               uLeft -= uUsed;
+               if (bUsed) {
+                       sq.rear = (sq.rear+1) % sq.max_count;
+                       sq.rear_size = bUsed;
+                       sq.count++;
+               }
+       } while (bUsed);   /* uUsed may have been 0 */
 
-    return(uWritten);
+       sq_play();
+
+       return(uUsed < 0? uUsed: uWritten);
 }
 
 
 static int sq_open(int open_mode)
 {
-    if (sq.busy) {
-       if (NON_BLOCKING(open_mode))
-           return(-EBUSY);
-       while (sq.busy) {
-           SLEEP(sq.open_queue, ONE_SECOND);
-           if (SIGNAL_RECEIVED)
-               return(-EINTR);
-       }
-    }
-    sq.open_mode = open_mode;
-    sq.busy = 1;
+       if (sq.busy) {
+               if (NON_BLOCKING(open_mode))
+                       return(-EBUSY);
+               while (sq.busy) {
+                       SLEEP(sq.open_queue, ONE_SECOND);
+                       if (SIGNAL_RECEIVED)
+                               return(-EINTR);
+               }
+       }
+       sq_init(numBufs, bufSize << 10, sound_buffers);
+       sq.open_mode = open_mode;
+       sq.busy = 1;
 #ifdef CONFIG_ATARI
-    sq.ignore_int = 1;
+       sq.ignore_int = 1;
 #endif /* CONFIG_ATARI */
-    return(0);
+       return(0);
 }
 
 
 static void sq_reset(void)
 {
-    sound_silence();
-    sq.playing = 0;
-    sq.count = 0;
-    sq.front = (sq.rear+1) % sq.max_count;
+       sound_silence();
+       sq.playing = 0;
+       sq.count = 0;
+       sq.front = (sq.rear+1) % sq.max_count;
 }
 
 
 static int sq_sync(void)
 {
-    int rc = 0;
-
-    sq.syncing = 1;
-    sq_play(); /* there may be an incomplete frame waiting */
-
-    while (sq.playing) {
-       SLEEP(sq.sync_queue, ONE_SECOND);
-       if (SIGNAL_RECEIVED) {
-           /* While waiting for audio output to drain, an interrupt occurred.
-              Stop audio output immediately and clear the queue. */
-           sq_reset();
-           rc = -EINTR;
-           break;
+       int rc = 0;
+
+       sq.syncing = 1;
+       sq_play();      /* there may be an incomplete frame waiting */
+
+       while (sq.playing) {
+               SLEEP(sq.sync_queue, ONE_SECOND);
+               if (SIGNAL_RECEIVED) {
+                       /* While waiting for audio output to drain, an
+                        * interrupt occurred.  Stop audio output immediately
+                        * and clear the queue. */
+                       sq_reset();
+                       rc = -EINTR;
+                       break;
+               }
        }
-    }
 
-    sq.syncing = 0;
-    return(rc);
+       sq.syncing = 0;
+       return(rc);
 }
 
 
 static int sq_release(void)
 {
-    int rc = 0;
-    if (sq.busy) {
-       rc = sq_sync();
-       sq.busy = 0;
-       WAKE_UP(sq.open_queue);
-       /* Wake up a process waiting for the queue being released.
-          Note: There may be several processes waiting for a call to open()
-                returning. */
-    }
-    return(rc);
+       int rc = 0;
+       if (sq.busy) {
+               rc = sq_sync();
+               sq.busy = 0;
+               WAKE_UP(sq.open_queue);
+               /* Wake up a process waiting for the queue being released.
+                * Note: There may be several processes waiting for a call
+                * to open() returning. */
+       }
+       return(rc);
 }
 
 
@@ -2916,7 +4023,7 @@ static int sq_release(void)
 
 static void state_init(void)
 {
-    state.busy = 0;
+       state.busy = 0;
 }
 
 
@@ -2924,118 +4031,125 @@ static void state_init(void)
 
 static int state_open(int open_mode)
 {
-    char *buffer = state.buf, *mach = "";
-    int len = 0;
+       char *buffer = state.buf, *mach = "";
+       int len = 0;
 
-    if (state.busy)
-       return(-EBUSY);
+       if (state.busy)
+               return(-EBUSY);
 
-    state.ptr = 0;
-    state.busy = 1;
+       state.ptr = 0;
+       state.busy = 1;
 
-    switch (sound.mach.type) {
+       switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
        case DMASND_TT:
        case DMASND_FALCON:
-           mach = "Atari ";
-           break;
+               mach = "Atari ";
+               break;
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
        case DMASND_AMIGA:
-           mach = "Amiga ";
-           break;
+               mach = "Amiga ";
+               break;
 #endif /* CONFIG_AMIGA */
-    }
-    len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
+#ifdef CONFIG_PMAC
+       case DMASND_AWACS:
+               mach = "PowerMac ";
+               break;
+#endif /* CONFIG_PMAC */
+       }
+       len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
 
-    len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
-    switch (sound.soft.format) {
+       len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
+       switch (sound.soft.format) {
        case AFMT_MU_LAW:
-           len += sprintf(buffer+len, " (mu-law)");
-           break;
+               len += sprintf(buffer+len, " (mu-law)");
+               break;
        case AFMT_A_LAW:
-           len += sprintf(buffer+len, " (A-law)");
-           break;
+               len += sprintf(buffer+len, " (A-law)");
+               break;
        case AFMT_U8:
-           len += sprintf(buffer+len, " (unsigned 8 bit)");
-           break;
+               len += sprintf(buffer+len, " (unsigned 8 bit)");
+               break;
        case AFMT_S8:
-           len += sprintf(buffer+len, " (signed 8 bit)");
-           break;
+               len += sprintf(buffer+len, " (signed 8 bit)");
+               break;
        case AFMT_S16_BE:
-           len += sprintf(buffer+len, " (signed 16 bit big)");
-           break;
+               len += sprintf(buffer+len, " (signed 16 bit big)");
+               break;
        case AFMT_U16_BE:
-           len += sprintf(buffer+len, " (unsigned 16 bit big)");
-           break;
+               len += sprintf(buffer+len, " (unsigned 16 bit big)");
+               break;
        case AFMT_S16_LE:
-           len += sprintf(buffer+len, " (signed 16 bit little)");
-           break;
+               len += sprintf(buffer+len, " (signed 16 bit little)");
+               break;
        case AFMT_U16_LE:
-           len += sprintf(buffer+len, " (unsigned 16 bit little)");
-           break;
-    }
-    len += sprintf(buffer+len, "\n");
-    len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
-                  sound.soft.speed, sound.hard.speed);
-    len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
-                  sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
-    switch (sound.mach.type) {
+               len += sprintf(buffer+len, " (unsigned 16 bit little)");
+               break;
+       }
+       len += sprintf(buffer+len, "\n");
+       len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
+                      sound.soft.speed, sound.hard.speed);
+       len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+                      sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
+       switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
        case DMASND_TT:
-           len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
-                          sound.volume_left);
-           len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
-                          sound.volume_right);
-           len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
-                          sound.bass);
-           len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
-                          sound.treble);
-           break;
+               len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
+                              sound.volume_left);
+               len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
+                              sound.volume_right);
+               len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
+                              sound.bass);
+               len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
+                              sound.treble);
+               break;
        case DMASND_FALCON:
-           len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
-                          sound.volume_left);
-           len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
-                          sound.volume_right);
-           break;
+               len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
+                              sound.volume_left);
+               len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
+                              sound.volume_right);
+               break;
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
        case DMASND_AMIGA:
-           len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
-                          sound.volume_left);
-           len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
-                          sound.volume_right);
-           break;
+               len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
+                              sound.volume_left);
+               len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
+                              sound.volume_right);
+               break;
 #endif /* CONFIG_AMIGA */
-    }
-    len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d\n",
-                  sq.block_size, sq.max_count);
-    len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
-                  sq.rear_size);
-    len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
-                  sq.playing, sq.syncing);
-    state.len = len;
-    return(0);
+       }
+       len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
+                      " sq.max_active = %d\n",
+                      sq.block_size, sq.max_count, sq.max_active);
+       len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
+                      sq.rear_size);
+       len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
+                      sq.playing, sq.syncing);
+       state.len = len;
+       return(0);
 }
 
 
 static int state_release(void)
 {
-    state.busy = 0;
-    return(0);
+       state.busy = 0;
+       return(0);
 }
 
 
 static long state_read(char *dest, unsigned long count)
 {
-    int n = state.len-state.ptr;
-    if (n > count)
-       n = count;
-    if (n <= 0)
-       return(0);
-    copy_to_user(dest, &state.buf[state.ptr], n);
-    state.ptr += n;
-    return(n);
+       int n = state.len-state.ptr;
+       if (n > count)
+               n = count;
+       if (n <= 0)
+               return(0);
+       if (copy_to_user(dest, &state.buf[state.ptr], n))
+               return -EFAULT;
+       state.ptr += n;
+       return(n);
 }
 
 
@@ -3045,230 +4159,252 @@ static long state_read(char *dest, unsigned long count)
 
 static int sound_open(struct inode *inode, struct file *file)
 {
-    int dev = MINOR(inode->i_rdev) & 0x0f;
-    int rc = 0;
+       int dev = MINOR(inode->i_rdev) & 0x0f;
+       int rc = 0;
 
-    switch (dev) {
+       switch (dev) {
        case SND_DEV_STATUS:
-           rc = state_open(file->f_flags);
-           break;
+               rc = state_open(file->f_flags);
+               break;
        case SND_DEV_CTL:
-           rc = mixer_open(file->f_flags);
-           break;
+               rc = mixer_open(file->f_flags);
+               break;
        case SND_DEV_DSP:
        case SND_DEV_AUDIO:
-           rc = sq_open(file->f_flags);
-           if (rc == 0) {
-               sound.minDev = dev;
-               sound.soft = sound.dsp;
-               sound.hard = sound.dsp;
-               sound_init();
-               if (dev == SND_DEV_AUDIO) {
-                   sound_set_speed(8000);
-                   sound_set_stereo(0);
-                   sound_set_format(AFMT_MU_LAW);
-               }
-           }
-           break;
+               rc = sq_open(file->f_flags);
+               if (rc == 0) {
+                       sound.minDev = dev;
+                       sound.soft = sound.dsp;
+                       sound.hard = sound.dsp;
+                       sound_init();
+                       if (dev == SND_DEV_AUDIO) {
+                               sound_set_speed(8000);
+                               sound_set_stereo(0);
+                               sound_set_format(AFMT_MU_LAW);
+                       }
+               }
+               break;
        default:
-           rc = -ENXIO;
-    }
+               rc = -ENXIO;
+       }
 #ifdef MODULE
-    if (rc >= 0)
-       MOD_INC_USE_COUNT;
+       if (rc >= 0)
+               MOD_INC_USE_COUNT;
 #endif
-    return(rc);
+       return(rc);
 }
 
 
 static int sound_fsync(struct file *filp, struct dentry *dentry)
 {
-    int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f;
+       int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f;
 
-    switch (dev) {
+       switch (dev) {
        case SND_DEV_STATUS:
        case SND_DEV_CTL:
-           return(0);
+               return(0);
        case SND_DEV_DSP:
        case SND_DEV_AUDIO:
-           return(sq_sync());
+               return(sq_sync());
        default:
-           return(unknown_minor_dev("sound_fsync", dev));
-    }
+               return(unknown_minor_dev("sound_fsync", dev));
+       }
 }
 
 
 static int sound_release(struct inode *inode, struct file *file)
 {
-    int dev = MINOR(inode->i_rdev);
+       int dev = MINOR(inode->i_rdev);
 
-    switch (dev & 0x0f) {
+       switch (dev & 0x0f) {
        case SND_DEV_STATUS:
-           state_release();
-           break;
+               state_release();
+               break;
        case SND_DEV_CTL:
-           mixer_release();
-           break;
+               mixer_release();
+               break;
        case SND_DEV_DSP:
        case SND_DEV_AUDIO:
-           sq_release();
-           sound.soft = sound.dsp;
-           sound.hard = sound.dsp;
-           sound_silence();
-           break;
+               sq_release();
+               sound.soft = sound.dsp;
+               sound.hard = sound.dsp;
+               sound_silence();
+               break;
        default:
-           return unknown_minor_dev("sound_release", dev);
-    }
+               return unknown_minor_dev("sound_release", dev);
+       }
 #ifdef MODULE
-    MOD_DEC_USE_COUNT;
+       MOD_DEC_USE_COUNT;
 #endif
-    return 0;
+       return 0;
 }
 
 
 static long long sound_lseek(struct file *file, long long offset, int orig)
 {
-    return -ESPIPE;
+       return -ESPIPE;
 }
 
 
 static ssize_t sound_read(struct file *file, char *buf, size_t count,
                          loff_t *ppos)
 {
-    struct inode *inode = file->f_dentry->d_inode;
-    int dev = MINOR(inode->i_rdev);
+       struct inode *inode = file->f_dentry->d_inode;
+       int dev = MINOR(inode->i_rdev);
 
-    switch (dev & 0x0f) {
+       switch (dev & 0x0f) {
        case SND_DEV_STATUS:
-           return(state_read(buf, count));
+               return(state_read(buf, count));
        case SND_DEV_CTL:
        case SND_DEV_DSP:
        case SND_DEV_AUDIO:
-           return(-EPERM);
+               return(-EPERM);
        default:
-           return(unknown_minor_dev("sound_read", dev));
-    }
+               return(unknown_minor_dev("sound_read", dev));
+       }
 }
 
 
 static ssize_t sound_write(struct file *file, const char *buf, size_t count,
                           loff_t *ppos)
 {
-    struct inode *inode = file->f_dentry->d_inode;
-    int dev = MINOR(inode->i_rdev);
+       struct inode *inode = file->f_dentry->d_inode;
+       int dev = MINOR(inode->i_rdev);
 
-    switch (dev & 0x0f) {
+       switch (dev & 0x0f) {
        case SND_DEV_STATUS:
        case SND_DEV_CTL:
-           return(-EPERM);
+               return(-EPERM);
        case SND_DEV_DSP:
        case SND_DEV_AUDIO:
-           return(sq_write(buf, count));
+               return(sq_write(buf, count));
        default:
-           return(unknown_minor_dev("sound_write", dev));
-    }
+               return(unknown_minor_dev("sound_write", dev));
+       }
 }
 
 
 static int unknown_minor_dev(char *fname, int dev)
 {
-    /* printk("%s: Unknown minor device %d\n", fname, dev); */
-    return(-ENXIO);
+       /* printk("%s: Unknown minor device %d\n", fname, dev); */
+       return(-ENXIO);
 }
 
 
 static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
                       u_long arg)
 {
-    int dev = MINOR(inode->i_rdev);
-    u_long fmt;
-    int data;
+       int dev = MINOR(inode->i_rdev);
+       u_long fmt;
+       int data;
+       int size, nbufs;
 
-    switch (dev & 0x0f) {
+       switch (dev & 0x0f) {
        case SND_DEV_STATUS:
-           return(-EPERM);
+               return(-EPERM);
        case SND_DEV_CTL:
-           return(mixer_ioctl(inode, file, cmd, arg));
+               return(mixer_ioctl(inode, file, cmd, arg));
        case SND_DEV_AUDIO:
        case SND_DEV_DSP:
-           switch (cmd) {
+               switch (cmd) {
                case SNDCTL_DSP_RESET:
-                   sq_reset();
-                   return(0);
+                       sq_reset();
+                       return(0);
                case SNDCTL_DSP_POST:
                case SNDCTL_DSP_SYNC:
-                   return(sound_fsync(file, file->f_dentry));
+                       return(sound_fsync(file, file->f_dentry));
 
-               /* ++TeSche: before changing any of these it's probably wise to
-                * wait until sound playing has settled down
-                */
+                       /* ++TeSche: before changing any of these it's
+                        * probably wise to wait until sound playing has
+                        * settled down. */
                case SNDCTL_DSP_SPEED:
-                   sound_fsync(file, file->f_dentry);
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_speed(data)));
+                       sound_fsync(file, file->f_dentry);
+                       IOCTL_IN(arg, data);
+                       return(IOCTL_OUT(arg, sound_set_speed(data)));
                case SNDCTL_DSP_STEREO:
-                   sound_fsync(file, file->f_dentry);
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_stereo(data)));
+                       sound_fsync(file, file->f_dentry);
+                       IOCTL_IN(arg, data);
+                       return(IOCTL_OUT(arg, sound_set_stereo(data)));
                case SOUND_PCM_WRITE_CHANNELS:
-                   sound_fsync(file, file->f_dentry);
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1));
+                       sound_fsync(file, file->f_dentry);
+                       IOCTL_IN(arg, data);
+                       return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1));
                case SNDCTL_DSP_SETFMT:
-                   sound_fsync(file, file->f_dentry);
-                   IOCTL_IN(arg, data);
-                   return(IOCTL_OUT(arg, sound_set_format(data)));
+                       sound_fsync(file, file->f_dentry);
+                       IOCTL_IN(arg, data);
+                       return(IOCTL_OUT(arg, sound_set_format(data)));
                case SNDCTL_DSP_GETFMTS:
-                   fmt = 0;
-                   if (sound.trans) {
-                       if (sound.trans->ct_ulaw)
-                           fmt |= AFMT_MU_LAW;
-                       if (sound.trans->ct_alaw)
-                           fmt |= AFMT_A_LAW;
-                       if (sound.trans->ct_s8)
-                           fmt |= AFMT_S8;
-                       if (sound.trans->ct_u8)
-                           fmt |= AFMT_U8;
-                       if (sound.trans->ct_s16be)
-                           fmt |= AFMT_S16_BE;
-                       if (sound.trans->ct_u16be)
-                           fmt |= AFMT_U16_BE;
-                       if (sound.trans->ct_s16le)
-                           fmt |= AFMT_S16_LE;
-                       if (sound.trans->ct_u16le)
-                           fmt |= AFMT_U16_LE;
-                   }
-                   return(IOCTL_OUT(arg, fmt));
+                       fmt = 0;
+                       if (sound.trans) {
+                               if (sound.trans->ct_ulaw)
+                                       fmt |= AFMT_MU_LAW;
+                               if (sound.trans->ct_alaw)
+                                       fmt |= AFMT_A_LAW;
+                               if (sound.trans->ct_s8)
+                                       fmt |= AFMT_S8;
+                               if (sound.trans->ct_u8)
+                                       fmt |= AFMT_U8;
+                               if (sound.trans->ct_s16be)
+                                       fmt |= AFMT_S16_BE;
+                               if (sound.trans->ct_u16be)
+                                       fmt |= AFMT_U16_BE;
+                               if (sound.trans->ct_s16le)
+                                       fmt |= AFMT_S16_LE;
+                               if (sound.trans->ct_u16le)
+                                       fmt |= AFMT_U16_LE;
+                       }
+                       return(IOCTL_OUT(arg, fmt));
                case SNDCTL_DSP_GETBLKSIZE:
-                   return(IOCTL_OUT(arg, 10240));
+                       size = sq.block_size
+                               * sound.soft.size * (sound.soft.stereo + 1)
+                               / (sound.hard.size * (sound.hard.stereo + 1));
+                       return(IOCTL_OUT(arg, size));
                case SNDCTL_DSP_SUBDIVIDE:
+                       break;
                case SNDCTL_DSP_SETFRAGMENT:
-                   break;
+                       if (sq.count || sq.playing || sq.syncing)
+                               return -EINVAL;
+                       IOCTL_IN(arg, size);
+                       nbufs = size >> 16;
+                       if (nbufs < 2 || nbufs > numBufs)
+                               nbufs = numBufs;
+                       size &= 0xffff;
+                       if (size >= 8 && size <= 30) {
+                               size = 1 << size;
+                               size *= sound.hard.size * (sound.hard.stereo + 1);
+                               size /= sound.soft.size * (sound.soft.stereo + 1);
+                               if (size > (bufSize << 10))
+                                       size = bufSize << 10;
+                       } else
+                               size = bufSize << 10;
+                       sq_init(numBufs, size, sound_buffers);
+                       sq.max_active = nbufs;
+                       break;
 
                default:
-                   return(mixer_ioctl(inode, file, cmd, arg));
-           }
-           break;
+                       return(mixer_ioctl(inode, file, cmd, arg));
+               }
+               break;
 
        default:
-           return(unknown_minor_dev("sound_ioctl", dev));
-    }
-    return(-EINVAL);
+               return(unknown_minor_dev("sound_ioctl", dev));
+       }
+       return(-EINVAL);
 }
 
 
 static struct file_operations sound_fops =
 {
-    sound_lseek,
-    sound_read,
-    sound_write,
-    NULL,
-    NULL,                      /* select */
-    sound_ioctl,
-    NULL,
-    sound_open,
-    sound_release,
-    sound_fsync
+       sound_lseek,
+       sound_read,
+       sound_write,
+       NULL,
+       NULL,                      /* select */
+       sound_ioctl,
+       NULL,
+       sound_open,
+       sound_release,
+       sound_fsync
 };
 
 
@@ -3278,87 +4414,142 @@ static struct file_operations sound_fops =
 
 void soundcard_init(void)
 {
-    int has_sound = 0;
-    int i;
+       int has_sound = 0;
+       int i;
 
-    switch (m68k_machtype) {
+#ifdef __mc68000__
+       switch (m68k_machtype) {
 #ifdef CONFIG_ATARI
        case MACH_ATARI:
-           if (ATARIHW_PRESENT(PCM_8BIT)) {
-               if (ATARIHW_PRESENT(CODEC))
-                   sound.mach = machFalcon;
-               else if (ATARIHW_PRESENT(MICROWIRE))
-                   sound.mach = machTT;
-               else
-                   break;
-               if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
-                   has_sound = 1;
-               else
-                   printk("DMA sound driver: Timer A interrupt already in use\n");
-           }
-           break;
+               if (ATARIHW_PRESENT(PCM_8BIT)) {
+                       if (ATARIHW_PRESENT(CODEC))
+                               sound.mach = machFalcon;
+                       else if (ATARIHW_PRESENT(MICROWIRE))
+                               sound.mach = machTT;
+                       else
+                               break;
+                       if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+                               has_sound = 1;
+                       else
+                               printk("DMA sound driver: Timer A interrupt already in use\n");
+               }
+               break;
 
 #endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
        case MACH_AMIGA:
-           if (AMIGAHW_PRESENT(AMI_AUDIO)) {
-               sound.mach = machAmiga;
-               has_sound = 1;
-           }
-           break;
+               if (AMIGAHW_PRESENT(AMI_AUDIO)) {
+                       sound.mach = machAmiga;
+                       has_sound = 1;
+               }
+               break;
 #endif /* CONFIG_AMIGA */
-    }
-    if (!has_sound)
-       return;
+       }
+#endif /* __mc68000__ */
 
-    /* Set up sound queue, /dev/audio and /dev/dsp. */
-    sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
-    if (!sound_buffers) {
-out_of_memory:
-       printk("DMA sound driver: Not enough buffer memory, driver disabled!\n");
-       return;
-    }
-    for (i = 0; i < numBufs; i++) {
-       sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
-       if (!sound_buffers[i]) {
-           while (i--)
-               sound.mach.dma_free (sound_buffers[i], bufSize << 10);
-           kfree (sound_buffers);
-           sound_buffers = 0;
-           goto out_of_memory;
-        }
-    }
+#ifdef CONFIG_PMAC
+       struct device_node *np;
+
+       np = find_devices("awacs");
+       if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
+               int vol;
+               sound.mach = machPMac;
+               has_sound = 1;
+               awacs = (volatile struct awacs_regs *)
+                       ioremap(np->addrs[0].address, 0x80);
+               awacs_txdma = (volatile struct dbdma_regs *)
+                       ioremap(np->addrs[1].address, 0x100);
+               awacs_rxdma = (volatile struct dbdma_regs *)
+                       ioremap(np->addrs[2].address, 0x100);
+               awacs_irq = np->intrs[0].line;
+               awacs_tx_irq = np->intrs[1].line;
+               awacs_rx_irq = np->intrs[2].line;
+               awacs_tx_cmd_space = kmalloc((numBufs + 4) * sizeof(struct dbdma_cmd),
+                                            GFP_KERNEL);
+               if (awacs_tx_cmd_space == NULL)
+                       goto out_of_memory;
+               awacs_tx_cmds = (volatile struct dbdma_cmd *)
+                       DBDMA_ALIGN(awacs_tx_cmd_space);
+               awacs_reg[0] = MASK_MUX_CD;
+               awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
+               /* get default volume from nvram */
+               vol = (~nvram_read_byte(0x1308) & 7) << 1;
+               awacs_reg[2] = vol + (vol << 6);
+               awacs_reg[4] = vol + (vol << 6);
+               awacs_write(awacs_reg[0] + MASK_ADDR0);
+               awacs_write(awacs_reg[1] + MASK_ADDR1);
+               awacs_write(awacs_reg[2] + MASK_ADDR2);
+               awacs_write(awacs_reg[4] + MASK_ADDR4);
+
+               /* Initialize beep stuff */
+               beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1);
+               orig_mksound = kd_mksound;
+               kd_mksound = awacs_mksound;
+               beep_buf = (short *) kmalloc(BEEP_BUFLEN * 2, GFP_KERNEL);
+               if (beep_buf == NULL)
+                       printk(KERN_WARNING "dmasound: no memory for "
+                              "beep buffer\n");
+#ifdef CONFIG_PMAC_PBOOK
+               notifier_chain_register(&sleep_notifier_list,
+                                       &awacs_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+       }
+#endif /* CONFIG_PMAC */
+
+       if (!has_sound)
+               return;
+
+       /* Set up sound queue, /dev/audio and /dev/dsp. */
+       sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
+       if (!sound_buffers) {
+       out_of_memory:
+               printk("DMA sound driver: Not enough buffer memory, driver disabled!\n");
+               return;
+       }
+       for (i = 0; i < numBufs; i++) {
+               sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
+               if (!sound_buffers[i]) {
+                       while (i--)
+                               sound.mach.dma_free (sound_buffers[i], bufSize << 10);
+                       kfree (sound_buffers);
+                       sound_buffers = 0;
+                       goto out_of_memory;
+               }
+       }
 
 #ifndef MODULE
-    /* Register driver with the VFS. */
-    register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
+       /* Register driver with the VFS. */
+       register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
 #endif
 
-    sq_init(numBufs, bufSize << 10, sound_buffers);
+       sq_init(numBufs, bufSize << 10, sound_buffers);
 
-    /* Set up /dev/sndstat. */
-    state_init();
+       /* Set default settings. */
+       init_settings();
 
-    /* Set up /dev/mixer. */
-    mixer_init();
+       /* Set up /dev/sndstat. */
+       state_init();
 
-    if (!sound.mach.irqinit()) {
-       printk("DMA sound driver: Interrupt initialization failed\n");
-       return;
-    }
+       /* Set up /dev/mixer. */
+       mixer_init();
+
+       if (!sound.mach.irqinit()) {
+               printk("DMA sound driver: Interrupt initialization failed\n");
+               return;
+       }
 #ifdef MODULE
-    irq_installed = 1;
+       irq_installed = 1;
 #endif
 
-    printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs,
-          bufSize);
+       printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs,
+              bufSize);
 
-    return;
+       return;
 }
 
 void sound_setup(char *str, int *ints)
 {
-    /* ++Martin: stub, could possibly be merged with soundcard.c et al later */
+       /* ++Martin: stub, could possibly be merged with soundcard.c et al later */
 }
 
 
@@ -3366,30 +4557,30 @@ void sound_setup(char *str, int *ints)
 
 void dmasound_setup(char *str, int *ints)
 {
-    /* check the bootstrap parameter for "dmasound=" */
+       /* check the bootstrap parameter for "dmasound=" */
 
-    switch (ints[0]) {
+       switch (ints[0]) {
        case 3:
-           if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
-               printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
-           else
-               catchRadius = ints[3];
-           /* fall through */
+               if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
+                       printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+               else
+                       catchRadius = ints[3];
+               /* fall through */
        case 2:
-           if (ints[1] < MIN_BUFFERS)
-               printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
-           else
-               numBufs = ints[1];
-           if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
-               printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
-           else
-               bufSize = ints[2];
-           break;
+               if (ints[1] < MIN_BUFFERS)
+                       printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
+               else
+                       numBufs = ints[1];
+               if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
+                       printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
+               else
+                       bufSize = ints[2];
+               break;
        case 0:
-           break;
+               break;
        default:
-           printk("dmasound_setup: illegal number of arguments\n");
-    }
+               printk("dmasound_setup: illegal number of arguments\n");
+       }
 }
 
 
@@ -3399,48 +4590,48 @@ static int dmasound[MAXARGS] = { 0 };
 
 int init_module(void)
 {
-    int err, i = 0;
-    int ints[MAXARGS+1];
+       int err, i = 0;
+       int ints[MAXARGS+1];
 
-    while (i < MAXARGS && dmasound[i])
-       ints[i + 1] = dmasound[i++];
-    ints[0] = i;
+       while (i < MAXARGS && dmasound[i])
+               ints[i + 1] = dmasound[i++];
+       ints[0] = i;
 
-    if (i)
-       dmasound_setup("dmasound=", ints);
+       if (i)
+               dmasound_setup("dmasound=", ints);
 
-    err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
-    if (err) {
-       printk("dmasound: driver already loaded/included in kernel\n");
-       return err;
-    }
-    chrdev_registered = 1;
-    soundcard_init();
+       err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
+       if (err) {
+               printk("dmasound: driver already loaded/included in kernel\n");
+               return err;
+       }
+       chrdev_registered = 1;
+       soundcard_init();
 
-    return 0;
+       return 0;
 }
 
 
 void cleanup_module(void)
 {
-    int i;
+       int i;
 
-    if (MOD_IN_USE)
-       return;
+       if (MOD_IN_USE)
+               return;
 
-    if (chrdev_registered)
-       unregister_chrdev(SOUND_MAJOR, "sound");
+       if (chrdev_registered)
+               unregister_chrdev(SOUND_MAJOR, "sound");
 
-    if (irq_installed) {
-       sound_silence();
-       sound.mach.irqcleanup();
-    }
-
-    if (sound_buffers) {
-       for (i = 0; i < numBufs; i++)
-           sound.mach.dma_free(sound_buffers[i], bufSize << 10);
-       kfree(sound_buffers);
-    }
+       if (irq_installed) {
+               sound_silence();
+               sound.mach.irqcleanup();
+       }
+
+       if (sound_buffers) {
+               for (i = 0; i < numBufs; i++)
+                       sound.mach.dma_free(sound_buffers[i], bufSize << 10);
+               kfree(sound_buffers);
+       }
 }
 
 #endif /* MODULE */
index d99b8fb684ea5ea6c6e62978f54f54f51a0f5a8a..c15bced8806e99b1adcfd3b7d3c8b4ccb53cd975 100644 (file)
@@ -3128,30 +3128,24 @@ void gus_wave_init(struct address_info *hw_config)
        
        if ((gus_mem_size > 0) & !gus_no_wave_dma)
        {
-               if ((dev = sound_alloc_audiodev()) != -1)
+               hw_config->slots[4] = -1;
+               if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
+                                       "Ultrasound",
+                                       &gus_audio_driver,
+                                       sizeof(struct audio_driver),
+                                       NEEDS_RESTART |
+                                       ((!iw_mode && dma2 != dma && dma2 != -1) ?
+                                               DMA_DUPLEX : 0),
+                                       AFMT_U8 | AFMT_S16_LE,
+                                       NULL, dma, dma2)) < 0)
                {
-                       hw_config->slots[4] = dev;
-                       if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
-                                                           "Ultrasound",
-                                                      &gus_audio_driver,
-                                            sizeof(struct audio_driver),
-                                                         NEEDS_RESTART |
-                                                                                  ((!iw_mode && dma2 != dma && dma2 != -1) ?
-                                                        DMA_DUPLEX : 0),
-                                                  AFMT_U8 | AFMT_S16_LE,
-                                                                  NULL,
-                                                                  dma,
-                                                             dma2)) < 0)
-                       {
-                               return;
-                       }
+                       return;
+               }
 
-                       audio_devs[gus_devnum]->min_fragment = 9;       /* 512k */
-                       audio_devs[gus_devnum]->max_fragment = 11;      /* 8k (must match size of bounce_buf */
-                       audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */
-                       audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
-               } else
-                       printk(KERN_WARNING "GUS: Too many audio devices available\n");
+               audio_devs[gus_devnum]->min_fragment = 9;       /* 512k */
+               audio_devs[gus_devnum]->max_fragment = 11;      /* 8k (must match size of bounce_buf */
+               audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */
+               audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
        }
        
        /*
diff --git a/drivers/sound/msnd.c b/drivers/sound/msnd.c
new file mode 100644 (file)
index 0000000..11a6953
--- /dev/null
@@ -0,0 +1,382 @@
+/*********************************************************************
+ *
+ * msnd.c - Driver Base
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd.c,v 1.2 1998/06/09 20:37:39 andrewtv Exp $
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/spinlock.h>
+#include "msnd.h"
+
+#define LOGNAME                        "msnd"
+
+#define MSND_MAX_DEVS          4
+
+static multisound_dev_t                *devs[MSND_MAX_DEVS];
+static int                     num_devs;
+
+int msnd_register(multisound_dev_t *dev)
+{
+       int i;
+
+       for (i = 0; i < MSND_MAX_DEVS; ++i)
+               if (devs[i] == NULL)
+                       break;
+
+       if (i == MSND_MAX_DEVS)
+               return -ENOMEM;
+       
+       devs[i] = dev;
+       ++num_devs;
+
+       MOD_INC_USE_COUNT;
+
+       return 0;
+}
+
+void msnd_unregister(multisound_dev_t *dev)
+{
+       int i;
+
+       for (i = 0; i < MSND_MAX_DEVS; ++i)
+               if (devs[i] == dev)
+                       break;
+
+       if (i == MSND_MAX_DEVS) {
+               printk(KERN_WARNING LOGNAME ": Unregistering unknown device\n");
+               return;
+       }
+
+       devs[i] = NULL;
+       --num_devs;
+
+       MOD_DEC_USE_COUNT;
+}
+
+int msnd_get_num_devs(void)
+{
+       return num_devs;
+}
+
+multisound_dev_t *msnd_get_dev(int j)
+{
+       int i;
+
+       for (i = 0; i < MSND_MAX_DEVS && j; ++i)
+               if (devs[i] != NULL)
+                       --j;
+       
+       if (i == MSND_MAX_DEVS || j != 0)
+               return NULL;
+
+       return devs[i];
+}
+
+void msnd_fifo_init(msnd_fifo *f)
+{
+       f->data = NULL;
+}
+
+void msnd_fifo_free(msnd_fifo *f)
+{
+       if (f->data) {
+               vfree(f->data);
+               f->data = NULL;
+       }
+}
+
+int msnd_fifo_alloc(msnd_fifo *f, size_t n)
+{
+       msnd_fifo_free(f);
+       f->data = (char *)vmalloc(n);
+       f->n = n;
+       f->tail = 0;
+       f->head = 0;
+       f->len = 0;
+
+       if (!f->data)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void msnd_fifo_make_empty(msnd_fifo *f)
+{
+       f->len = f->tail = f->head = 0;
+}
+
+int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user)
+{
+       int count = 0;
+
+       if (f->len == f->n)
+               return 0;
+       
+       while ((count < len) && (f->len != f->n)) {
+               
+               int nwritten;
+               
+               if (f->head <= f->tail) {
+                       nwritten = len - count;
+                       if (nwritten > f->n - f->tail)
+                               nwritten = f->n - f->tail;
+               }
+               else {
+                       nwritten = f->head - f->tail;
+                       if (nwritten > len - count)
+                               nwritten = len - count;
+               }
+
+               if (user) {
+                       if (copy_from_user(f->data + f->tail, buf, nwritten))
+                               return -EFAULT;
+               } else
+                       memcpy(f->data + f->tail, buf, nwritten);
+
+               count += nwritten;
+               buf += nwritten;
+               f->len += nwritten;
+               f->tail += nwritten;
+               f->tail %= f->n;
+       }
+       
+       return count;
+}
+
+int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user)
+{
+       int count = 0;
+
+       if (f->len == 0)
+               return f->len;
+       
+       while ((count < len) && (f->len > 0)) {
+               
+               int nread;
+               
+               if (f->tail <= f->head) {
+                       nread = len - count;
+                       if (nread > f->n - f->head)
+                               nread = f->n - f->head;
+               }
+               else {
+                       nread = f->tail - f->head;
+                       if (nread > len - count)
+                               nread = len - count;
+               }
+               
+               if (user) {
+                       if (copy_to_user(buf, f->data + f->head, nread))
+                               return -EFAULT;
+               } else
+                       memcpy(buf, f->data + f->head, nread);
+               
+               count += nread;
+               buf += nread;
+               f->len -= nread;
+               f->head += nread;
+               f->head %= f->n;
+       }
+       
+       return count;
+}
+
+int msnd_wait_TXDE(multisound_dev_t *dev)
+{
+       register unsigned int io = dev->io;
+       register int timeout = 5000;
+    
+       while(timeout-- > 0)
+               if (inb(io + HP_ISR) & HPISR_TXDE)
+                       return 0;
+
+       return -EIO;
+}
+
+int msnd_wait_HC0(multisound_dev_t *dev)
+{
+       register unsigned int io = dev->io;
+       register int timeout = 25000;
+
+       while(timeout-- > 0)
+               if (!(inb(io + HP_CVR) & HPCVR_HC))
+                       return 0;
+
+       return -EIO;
+}
+
+int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd)
+{
+       unsigned long flags;
+       
+       spin_lock_irqsave(&dev->lock, flags);
+       if (msnd_wait_HC0(dev) == 0) {
+
+               outb(cmd, dev->io + HP_CVR);
+               spin_unlock_irqrestore(&dev->lock, flags);
+               return 0;
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       printk(KERN_WARNING LOGNAME ": Send DSP command timeout\n");
+       
+       return -EIO;
+}
+
+int msnd_send_word(multisound_dev_t *dev, unsigned char high,
+                  unsigned char mid, unsigned char low)
+{
+       register unsigned int io = dev->io;
+
+       if (msnd_wait_TXDE(dev) == 0) {
+               
+               outb(high, io + HP_TXH);
+               outb(mid, io + HP_TXM);
+               outb(low, io + HP_TXL);
+               return 0;
+       }
+
+       printk(KERN_WARNING LOGNAME ": Send host word timeout\n");
+
+       return -EIO;
+}
+
+int msnd_upload_host(multisound_dev_t *dev, char *bin, int len)
+{
+       int i;
+
+       if (len % 3 != 0) {
+               
+               printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n");         
+               return -EINVAL;
+       }
+
+       for (i = 0; i < len; i += 3)
+               if (msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]) != 0)
+                       return -EIO;
+
+       inb(dev->io + HP_RXL);
+       inb(dev->io + HP_CVR);
+
+       return 0;
+}
+
+int msnd_enable_irq(multisound_dev_t *dev)
+{
+       printk(KERN_INFO LOGNAME ": enable_irq: count %d\n", dev->irq_ref);
+
+       if (dev->irq_ref++ != 0)
+               return 0;
+
+       printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n");
+
+       if (msnd_wait_TXDE(dev) == 0) {
+
+               unsigned long flags;
+               
+               spin_lock_irqsave(&dev->lock, flags);
+               
+               outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
+
+               if (dev->type == msndClassic)
+                       outb(dev->irqid, dev->io + HP_IRQM);
+
+               outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
+               outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
+
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               return 0;
+       }
+
+       return -EIO;
+}
+
+int msnd_disable_irq(multisound_dev_t *dev)
+{
+       unsigned long flags;
+
+       printk(KERN_DEBUG LOGNAME ": disable_irq: count %d\n", dev->irq_ref);
+
+       if (--dev->irq_ref > 0)
+               return 0;
+
+       if (dev->irq_ref < 0)
+               dev->irq_ref = 0;
+
+       printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n");
+
+       spin_lock_irqsave(&dev->lock, flags);
+       outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
+       
+       if (dev->type == msndClassic)
+               outb(HPIRQ_NONE, dev->io + HP_IRQM);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(msnd_register);
+EXPORT_SYMBOL(msnd_unregister);
+EXPORT_SYMBOL(msnd_get_num_devs);
+EXPORT_SYMBOL(msnd_get_dev);
+
+EXPORT_SYMBOL(msnd_fifo_init);
+EXPORT_SYMBOL(msnd_fifo_free);
+EXPORT_SYMBOL(msnd_fifo_alloc);
+EXPORT_SYMBOL(msnd_fifo_make_empty);
+EXPORT_SYMBOL(msnd_fifo_write);
+EXPORT_SYMBOL(msnd_fifo_read);
+
+EXPORT_SYMBOL(msnd_wait_TXDE);
+EXPORT_SYMBOL(msnd_wait_HC0);
+EXPORT_SYMBOL(msnd_send_dsp_cmd);
+EXPORT_SYMBOL(msnd_send_word);
+EXPORT_SYMBOL(msnd_upload_host);
+
+EXPORT_SYMBOL(msnd_enable_irq);
+EXPORT_SYMBOL(msnd_disable_irq);
+
+#ifdef MODULE
+MODULE_AUTHOR                          ("Andrew Veliath <andrewtv@usa.net>");
+MODULE_DESCRIPTION                     ("Turtle Beach MultiSound Driver Base");
+
+int init_module(void)
+{
+       return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif
diff --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h
new file mode 100644 (file)
index 0000000..428e120
--- /dev/null
@@ -0,0 +1,259 @@
+/*********************************************************************
+ *
+ * msnd.h
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd.h,v 1.3 1998/06/09 20:39:34 andrewtv Exp $
+ *
+ ********************************************************************/
+#ifndef __MSND_H
+#define __MSND_H
+
+#define VERSION                        "0.6"
+
+#define DEFSAMPLERATE          44100
+#define DEFSAMPLESIZE          16
+#define DEFCHANNELS            2
+
+#define DEFFIFOSIZE            64
+
+#define SNDCARD_MSND           38
+
+#define SRAM_BANK_SIZE         0x8000
+#define SRAM_CNTL_START                0x7F00
+
+#define DSP_BASE_ADDR          0x4000
+#define DSP_BANK_BASE          0x4000
+
+#define        HP_ICR                  0x00
+#define        HP_CVR                  0x01
+#define        HP_ISR                  0x02
+#define        HP_IVR                  0x03
+#define HP_NU                  0x04
+#define HP_INFO                        0x04
+#define        HP_TXH                  0x05
+#define        HP_RXH                  0x05
+#define        HP_TXM                  0x06
+#define        HP_RXM                  0x06
+#define        HP_TXL                  0x07
+#define        HP_RXL                  0x07
+
+#define HP_ICR_DEF             0x00
+#define HP_CVR_DEF             0x12
+#define HP_ISR_DEF             0x06
+#define HP_IVR_DEF             0x0f
+#define HP_NU_DEF              0x00
+
+#define        HP_IRQM                 0x09
+
+#define        HPR_BLRC                0x08
+#define        HPR_SPR1                0x09
+#define        HPR_SPR2                0x0A
+#define        HPR_TCL0                0x0B
+#define        HPR_TCL1                0x0C
+#define        HPR_TCL2                0x0D
+#define        HPR_TCL3                0x0E
+#define        HPR_TCL4                0x0F
+
+#define        HPICR_INIT              0x80
+#define HPICR_HM1              0x40
+#define HPICR_HM0              0x20
+#define HPICR_HF1              0x10
+#define HPICR_HF0              0x08
+#define        HPICR_TREQ              0x02
+#define        HPICR_RREQ              0x01
+
+#define HPCVR_HC               0x80
+
+#define        HPISR_HREQ              0x80
+#define HPISR_DMA              0x40
+#define HPISR_HF3              0x10
+#define HPISR_HF2              0x08
+#define        HPISR_TRDY              0x04
+#define        HPISR_TXDE              0x02
+#define        HPISR_RXDF              0x01
+
+#define        HPIO_290                0
+#define        HPIO_260                1
+#define        HPIO_250                2
+#define        HPIO_240                3
+#define        HPIO_230                4
+#define        HPIO_220                5
+#define        HPIO_210                6
+#define        HPIO_3E0                7
+
+#define        HPMEM_NONE              0
+#define        HPMEM_B000              1
+#define        HPMEM_C800              2
+#define        HPMEM_D000              3
+#define        HPMEM_D400              4
+#define        HPMEM_D800              5
+#define        HPMEM_E000              6
+#define        HPMEM_E800              7
+
+#define        HPIRQ_NONE              0
+#define HPIRQ_5                        1
+#define HPIRQ_7                        2
+#define HPIRQ_9                        3
+#define HPIRQ_10               4
+#define HPIRQ_11               5
+#define HPIRQ_12               6
+#define HPIRQ_15               7
+
+#define        HIMT_PLAY_DONE          0x00
+#define        HIMT_RECORD_DONE        0x01
+#define        HIMT_MIDI_EOS           0x02
+#define        HIMT_MIDI_OUT           0x03
+
+#define        HIMT_MIDI_IN_UCHAR      0x0E
+#define        HIMT_DSP                0x0F
+
+#define HIWORD(l)              ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF ))
+#define LOWORD(l)              ((WORD)(DWORD)(l))
+#define HIBYTE(w)              ((BYTE)(((WORD)(w) >> 8 ) & 0xFF ))
+#define LOBYTE(w)              ((BYTE)(w))
+#define MAKELONG(low,hi)       ((long)(((WORD)(low))|(((DWORD)((WORD)(hi)))<<16)))
+#define MAKEWORD(low,hi)       ((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8)))
+
+#define PCTODSP_OFFSET(w)      (USHORT)((w)/2)
+#define PCTODSP_BASED(w)       (USHORT)(((w)/2) + DSP_BASE_ADDR)
+
+#ifdef SLOWIO
+#  define outb                 outb_p
+#  define inb                  inb_p
+#endif
+
+typedef unsigned char          BYTE;
+typedef unsigned short         USHORT;
+typedef unsigned short         WORD;
+typedef unsigned int           DWORD;
+typedef 
+struct DAQueueDataStruct *     LPDAQD;
+
+#define GCC_PACKED             __attribute__ ((packed))
+
+struct JobQueueStruct {
+       WORD wStart;
+       WORD wSize;
+       WORD wHead;
+       WORD wTail;
+} GCC_PACKED;
+
+struct DAQueueDataStruct {
+       WORD wStart;
+       WORD wSize;
+       WORD wFormat;
+       WORD wSampleSize;
+       WORD wChannels;
+       WORD wSampleRate;
+       WORD wIntMsg;
+       WORD wFlags;
+} GCC_PACKED;
+
+typedef struct {
+       size_t n, len;
+       char *data;
+       int head, tail;
+} msnd_fifo;
+
+typedef struct multisound_dev {
+
+       char *name;
+       int dsp_minor, mixer_minor;
+
+       /* Hardware resources */
+       unsigned int io, numio;
+       int memid, irqid;
+       int irq, irq_ref;
+       unsigned char info;
+       char *base;
+       spinlock_t lock;
+
+       /* MultiSound DDK variables */
+       enum { msndClassic, msndPinnacle } type;
+       struct SMA0_CommonData *SMA;    /* diff. structure for classic vs. pinnacle */
+       struct DAQueueDataStruct *CurDAQD;
+       struct DAQueueDataStruct *CurDARQD;
+       WORD *pwDSPQData , *pwMIDQData , *pwMODQData;
+       struct JobQueueStruct *DAPQ , *DARQ , *MODQ , *MIDQ , *DSPQ;
+
+       /* State variables */
+       mode_t mode;
+       unsigned long flags;
+#define F_BANKONE                      0
+#define F_INTERRUPT                    1
+#define F_WRITING                      2
+#define F_WRITEBLOCK                   3
+#define F_READING                      4
+#define F_READBLOCK                    5
+#define F_AUDIO_INUSE                  6
+#define F_EXT_MIDI_INUSE               7
+#define F_INT_MIDI_INUSE               8
+       struct wait_queue *writeblock, *readblock;
+       unsigned long recsrc;
+       int left_levels[16];
+       int right_levels[16];
+       int calibrate_signal;
+       int sample_size;
+       int sample_rate;
+       int channels;
+       void (*inc_ref)(void);
+       void (*dec_ref)(void);
+
+       /* Digital audio FIFOs */
+       int fifosize;
+       msnd_fifo DAPF, DARF;
+       int lastbank;
+
+       /* MIDI in callback */
+       void (*midi_in_interrupt)(struct multisound_dev *);
+
+} multisound_dev_t;
+
+#ifndef mdelay
+#  define mdelay(a)            udelay((a) * 1000)
+#endif
+
+int                            msnd_register(multisound_dev_t *dev);
+void                           msnd_unregister(multisound_dev_t *dev);
+int                            msnd_get_num_devs(void);
+multisound_dev_t *             msnd_get_dev(int i);
+
+void                           msnd_fifo_init(msnd_fifo *f);
+void                           msnd_fifo_free(msnd_fifo *f);
+int                            msnd_fifo_alloc(msnd_fifo *f, size_t n);
+void                           msnd_fifo_make_empty(msnd_fifo *f);
+int                            msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user);
+int                            msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user);
+
+int                            msnd_wait_TXDE(multisound_dev_t *dev);
+int                            msnd_wait_HC0(multisound_dev_t *dev);
+int                            msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd);
+int                            msnd_send_word(multisound_dev_t *dev, unsigned char high,
+                                              unsigned char mid, unsigned char low);
+int                            msnd_upload_host(multisound_dev_t *dev, char *bin, int len);
+int                            msnd_enable_irq(multisound_dev_t *dev);
+int                            msnd_disable_irq(multisound_dev_t *dev);
+
+#endif /* __MSND_H */
diff --git a/drivers/sound/msnd_classic.c b/drivers/sound/msnd_classic.c
new file mode 100644 (file)
index 0000000..e908e0b
--- /dev/null
@@ -0,0 +1,1306 @@
+/*********************************************************************
+ *
+ * msnd_classic.c - Support for Turtle Beach Classic/Monterey/Tahiti
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd_classic.c,v 1.2 1998/06/09 20:37:39 andrewtv Exp $
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include "sound_config.h"
+#include "sound_firmware.h"
+#define SLOWIO
+#include "msnd.h"
+#include "msnd_classic.h"
+
+#define LOGNAME                                "msnd_classic"
+#define DEVNAME                                dev.name
+#define MIXERMINOR                     dev.mixer_minor
+#define DSPMINOR                       dev.dsp_minor
+
+multisound_dev_t                       dev;
+
+#ifndef HAVE_DSPCODEH
+static char                            *dspini, *permini;
+static int                             sizeof_dspini, sizeof_permini;
+#endif
+
+static void reset_play_queue(void)
+{
+       int n;
+       LPDAQD lpDAQ;
+
+       msnd_fifo_make_empty(&dev.DAPF);
+       dev.DAPQ->wHead = 0;
+       dev.DAPQ->wTail = PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE);
+       dev.CurDAQD = (LPDAQD)(dev.base + 1 * DAPQ_DATA_BUFF);
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+       memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+
+       for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+               
+               writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+               writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+               writew(1, &lpDAQ->wFormat);
+               writew(dev.sample_size, &lpDAQ->wSampleSize);
+               writew(dev.channels, &lpDAQ->wChannels);
+               writew(dev.sample_rate, &lpDAQ->wSampleRate);
+               writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+               writew(n + 1, &lpDAQ->wFlags);
+
+       }
+
+       dev.lastbank = -1;
+}
+
+static void reset_record_queue(void)
+{
+       int n;
+       LPDAQD lpDAQ;
+
+       msnd_fifo_make_empty(&dev.DARF);
+       dev.DARQ->wHead = 0;
+       dev.DARQ->wTail = PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE);
+       dev.CurDARQD = (LPDAQD)(dev.base + 1 * DARQ_DATA_BUFF);
+       outb(HPBLKSEL_1, dev.io + HP_BLKS);
+       memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+       for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+               writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+               writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+               writew(1, &lpDAQ->wFormat);
+               writew(dev.sample_size, &lpDAQ->wSampleSize);
+               writew(dev.channels, &lpDAQ->wChannels);
+               writew(dev.sample_rate, &lpDAQ->wSampleRate);
+               writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+               writew(n + 1, &lpDAQ->wFlags);
+
+       }
+}
+
+static void reset_queues(void)
+{
+       dev.DSPQ->wHead = dev.DSPQ->wTail = 0;
+       reset_play_queue();
+       reset_record_queue();
+}
+
+static int dsp_ioctl(unsigned int cmd, unsigned long arg)
+{
+       int val, i, data;
+       LPDAQD lpDAQ, lpDARQ;
+
+       lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+       lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+       switch (cmd) {
+       case SNDCTL_DSP_SUBDIVIDE:
+       case SNDCTL_DSP_SETFRAGMENT:
+       case SNDCTL_DSP_SETDUPLEX:
+               return 0;
+
+       case SNDCTL_DSP_GETIPTR:
+       case SNDCTL_DSP_GETOPTR:
+       case SNDCTL_DSP_MAPINBUF:
+       case SNDCTL_DSP_MAPOUTBUF:
+               return -EINVAL;
+
+       case SNDCTL_DSP_SYNC:
+       case SNDCTL_DSP_RESET:
+
+               reset_play_queue();
+               reset_record_queue();
+
+               return 0;
+               
+       case SNDCTL_DSP_GETBLKSIZE:
+
+               if (put_user(dev.fifosize / 4, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case SNDCTL_DSP_NONBLOCK:
+
+               dev.mode |= O_NONBLOCK;
+
+               return 0;
+
+       case SNDCTL_DSP_GETCAPS:
+
+               val = DSP_CAP_DUPLEX | DSP_CAP_BATCH;
+               if (put_user(val, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case SNDCTL_DSP_SAMPLESIZE:
+                       
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
+
+               switch (val) {
+               case 16:
+               case 8:
+                       data = val;
+                       break;
+               default:
+                       data = DEFSAMPLESIZE;
+                       break;
+               }
+
+               for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+                       lpDAQ->wSampleSize = data;
+                       lpDARQ->wSampleSize = data;
+               }
+               
+               dev.sample_size = data;
+               
+               if (put_user(data, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case SNDCTL_DSP_SPEED:
+                       
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
+
+               if (val < 8000)
+                       val = 8000;
+
+               if (val > 48000)
+                       val = 48000;
+
+               data = val;
+
+               for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+                       lpDAQ->wSampleRate = data;
+                       lpDARQ->wSampleRate = data;
+               }
+               
+               dev.sample_rate = data;
+
+               if (put_user(data, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case SNDCTL_DSP_CHANNELS:
+                       
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
+                       
+               switch (val) {
+               case 1:
+               case 2:
+                       data = val;
+                       break;
+               default:
+                       val = data = 2;
+                       break;
+               }
+                                                                       
+               for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+                       lpDAQ->wChannels = data;
+                       lpDARQ->wChannels = data;
+               }
+
+               dev.channels = data;
+
+               if (put_user(val, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case SNDCTL_DSP_STEREO:
+                       
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
+                       
+               switch (val) {
+               case 0:
+                       data = 1;
+                       break;
+               default:
+                       val = 1;
+               case 1:
+                       data = 2;
+                       break;
+               }
+                                                                       
+               for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+                       lpDAQ->wChannels = data;
+                       lpDARQ->wChannels = data;
+               }
+
+               dev.channels = data;
+
+               if (put_user(val, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int mixer_get(int d)
+{
+       if (d > 31)
+               return -EINVAL;
+
+       switch (d) {
+       case SOUND_MIXER_VOLUME:
+       case SOUND_MIXER_SYNTH:
+       case SOUND_MIXER_PCM:
+       case SOUND_MIXER_LINE:
+       case SOUND_MIXER_MIC:
+       case SOUND_MIXER_IMIX:
+       case SOUND_MIXER_LINE1:
+               return (dev.left_levels[d] >> 8) * 100 / 0xff | 
+                       (((dev.right_levels[d] >> 8) * 100 / 0xff) << 8);
+       default:
+               return 0;
+       }
+}
+
+#define update_vol(a,b,s)                                                              \
+       writew(dev.left_levels[a] * readw(&dev.SMA->wCurrMastVolLeft) / 0xffff / s,     \
+              &dev.SMA->b##Left);                                                      \
+       writew(dev.right_levels[a] * readw(&dev.SMA->wCurrMastVolRight) / 0xffff / s,   \
+              &dev.SMA->b##Right);
+
+static int mixer_set(int d, int value)
+{
+       int left = value & 0x000000ff;
+       int right = (value & 0x0000ff00) >> 8;
+       int bLeft, bRight;
+       int wLeft, wRight;
+
+       if (d > 31)
+               return -EINVAL;
+
+       bLeft = left * 0xff / 100;
+       wLeft = left * 0xffff / 100;
+
+       bRight = right * 0xff / 100;
+       wRight = right * 0xffff / 100;
+
+       dev.left_levels[d] = wLeft;
+       dev.right_levels[d] = wRight;
+
+       switch (d) {
+       case SOUND_MIXER_VOLUME:                /* master volume */
+               writew(wLeft / 2, &dev.SMA->wCurrMastVolLeft);
+               writew(wRight / 2, &dev.SMA->wCurrMastVolRight);
+               break;
+
+               /* pot controls */
+       case SOUND_MIXER_LINE:                  /* aux pot control */
+               writeb(bLeft, &dev.SMA->bInPotPosLeft);
+               writeb(bRight, &dev.SMA->bInPotPosRight);
+               if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
+                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+               break;
+
+       case SOUND_MIXER_LINE1:                 /* line pot control */
+               writeb(bLeft, &dev.SMA->bAuxPotPosLeft);
+               writeb(bRight, &dev.SMA->bAuxPotPosRight);
+               if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0)
+                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+               break;
+
+               /* digital controls */
+       case SOUND_MIXER_SYNTH:                 /* synth vol (dsp mix) */
+       case SOUND_MIXER_PCM:                   /* pcm vol (dsp mix) */
+       case SOUND_MIXER_IMIX:                  /* input monitor (dsp mix) */
+               break;
+
+       default:
+               return 0;
+       }
+
+       /* update digital controls for master volume */
+       update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1);
+       update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1);
+       
+       return mixer_get(d);
+}
+
+static unsigned long set_recsrc(unsigned long recsrc)
+{
+#ifdef HAVE_NORECSRC
+       if (recsrc == 0)
+               dev.recsrc = 0;
+       else
+#endif
+               dev.recsrc ^= recsrc;
+
+       return dev.recsrc;
+}
+
+static int mixer_ioctl(unsigned int cmd, unsigned long arg)
+{
+       int val = 0;
+
+       if (((cmd >> 8) & 0xff) == 'M') {
+               
+               if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+
+                       switch (cmd & 0xff) {
+                       case SOUND_MIXER_RECSRC:
+                               if (get_user(val, (int *)arg))
+                                       return -EFAULT;
+                               val = set_recsrc(val);
+                               break;
+                               
+                       default:
+                               if (get_user(val, (int *)arg))
+                                       return -EFAULT;
+                               val = mixer_set(cmd & 0xff, val);
+                               break;
+                       }
+
+                       return put_user(val, (int *)arg);
+               }
+               else {
+                       switch (cmd & 0xff) {
+                       case SOUND_MIXER_RECSRC:
+                               val = dev.recsrc;
+                               break;
+                               
+                       case SOUND_MIXER_DEVMASK:
+                       case SOUND_MIXER_STEREODEVS:
+                               val =   SOUND_MASK_VOLUME |
+                                       SOUND_MASK_PCM |
+                                       SOUND_MASK_LINE |
+                                       SOUND_MASK_IMIX |
+                                       SOUND_MASK_LINE1;
+                               break;
+                                 
+                       case SOUND_MIXER_RECMASK:
+                               val = 0;
+                               break;
+                                 
+                       case SOUND_MIXER_CAPS:
+                               val =   SOUND_CAP_EXCL_INPUT;
+                               break;
+                               
+                       default:
+                               if ((val = mixer_get(cmd & 0xff)) < 0)
+                                       return -EINVAL;
+                               break;
+                       }
+               }
+
+               return put_user(val, (int *)arg); 
+       }
+
+       return -EINVAL;
+}
+
+static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int minor = MINOR(inode->i_rdev);
+
+       if (minor == DSPMINOR)
+               return dsp_ioctl(cmd, arg);
+       else if (minor == MIXERMINOR)
+               return mixer_ioctl(cmd, arg);
+
+       return -EINVAL;
+}
+
+static void dsp_halt(void)
+{
+       mdelay(1);
+       if (test_and_clear_bit(F_READING, &dev.flags)) {
+
+               msnd_send_dsp_cmd(&dev, HDEX_RECORD_STOP);
+               msnd_disable_irq(&dev);
+
+       }
+       mdelay(1);
+       if (test_and_clear_bit(F_WRITING, &dev.flags)) {
+
+               msnd_send_dsp_cmd(&dev, HDEX_PLAY_STOP);
+               msnd_disable_irq(&dev);
+
+       }
+       mdelay(1);
+       reset_queues();
+}
+
+static int dsp_open(struct file *file)
+{
+       dev.mode = file->f_mode;
+       set_bit(F_AUDIO_INUSE, &dev.flags);
+       reset_queues();
+       return 0;
+}
+
+static int dsp_close(void)
+{
+       dsp_halt();
+       clear_bit(F_AUDIO_INUSE, &dev.flags);
+       return 0;
+}
+
+static int dev_open(struct inode *inode, struct file *file)
+{
+       int minor = MINOR(inode->i_rdev);
+       int err = 0;
+
+       if (minor == DSPMINOR) {
+
+               if (test_bit(F_AUDIO_INUSE, &dev.flags))
+                       return -EBUSY;
+
+               err = dsp_open(file);
+       }
+       else if (minor == MIXERMINOR) {
+               /* nothing */
+       } else
+               err = -EINVAL;
+       
+       if (err >= 0)
+               MOD_INC_USE_COUNT;
+
+       return err;
+}
+
+static int dev_close(struct inode *inode, struct file *file)
+{
+       int minor = MINOR(inode->i_rdev);
+       int err = 0;
+
+       if (minor == DSPMINOR) {
+               err = dsp_close();
+       }
+       else if (minor == MIXERMINOR) {
+               /* nothing */
+       } else
+               err = -EINVAL;
+
+       if (err >= 0)
+               MOD_DEC_USE_COUNT;
+       
+       return err;
+}
+
+static int DAPF_to_bank(int bank)
+{
+       return msnd_fifo_read(&dev.DAPF, dev.base + bank * DAP_BUFF_SIZE, DAP_BUFF_SIZE, 0);
+}
+
+static int bank_to_DARF(int bank)
+{
+       return msnd_fifo_write(&dev.DARF, dev.base + bank * DAR_BUFF_SIZE, DAR_BUFF_SIZE, 0);
+}
+
+static int dsp_read(char *buf, size_t len)
+{
+       int err = 0;
+       int count = len;
+
+       while (count > 0) {
+               
+               int n;
+
+               if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) {
+
+                       printk(KERN_WARNING LOGNAME ": FIFO read error\n");
+                       return n;
+               }
+
+               buf += n;
+               count -= n;
+               
+               if (!test_and_set_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) {
+
+                       reset_record_queue();
+                       msnd_enable_irq(&dev);
+                       msnd_send_dsp_cmd(&dev, HDEX_RECORD_START);
+
+               }
+
+               if (dev.mode & O_NONBLOCK)
+                       return count == len ? -EAGAIN : len - count;
+
+               if (count > 0) {
+
+                       set_bit(F_READBLOCK, &dev.flags);
+                       interruptible_sleep_on(&dev.readblock);
+                       clear_bit(F_READBLOCK, &dev.flags);
+
+                       if (signal_pending(current))
+                               err = -EINTR;
+
+               }
+
+               if (err != 0)
+                       return err;
+       }
+
+       return len - count;
+}
+
+static int dsp_write(const char *buf, size_t len)
+{
+       int err = 0;
+       int count = len;
+
+       while (count > 0) {
+
+               int n;
+
+               if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) {
+
+                       printk(KERN_WARNING LOGNAME ": FIFO write error\n");
+                       return n;
+               }
+
+               buf += n;
+               count -= n;
+
+               if (!test_and_set_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
+                       
+                       reset_play_queue();
+                       msnd_enable_irq(&dev);
+                       msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+               }
+
+               if (dev.mode & O_NONBLOCK)
+                       return count == len ? -EAGAIN : len - count;
+
+               if (count > 0) {
+                       
+                       set_bit(F_WRITEBLOCK, &dev.flags);
+                       interruptible_sleep_on(&dev.writeblock);
+                       clear_bit(F_WRITEBLOCK, &dev.flags);
+
+                       if (signal_pending(current))
+                               err = -EINTR;
+
+               }
+
+               if (err != 0)
+                       return err;
+       }
+       
+       return len - count;
+}
+
+static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off)
+{
+       int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+       if (minor == DSPMINOR) {
+
+               return dsp_read(buf, count);
+
+       } else
+               return -EINVAL;
+}
+
+static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+       int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+       if (minor == DSPMINOR) {
+
+               return dsp_write(buf, count);
+
+       } else
+               return -EINVAL;
+}
+
+static void eval_dsp_msg(WORD wMessage)
+{
+       switch (HIBYTE(wMessage)) {
+       case HIMT_PLAY_DONE:
+               
+               if (dev.lastbank == LOBYTE(wMessage))
+                       break;
+               
+               dev.lastbank = LOBYTE(wMessage);
+
+               dev.CurDAQD->wSize = DAP_BUFF_SIZE;
+
+               if ((dev.DAPQ->wTail += PCTODSP_OFFSET(DAPQ_STRUCT_SIZE)) > dev.DAPQ->wSize)
+                       dev.DAPQ->wTail = 0;
+
+               if (++dev.CurDAQD > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE))
+                       dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+
+               if (dev.lastbank < 3) {
+
+                       if (DAPF_to_bank(dev.lastbank) > 0) {
+
+                               mdelay(1);
+                               msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+                       } 
+                       else if (!test_bit(F_WRITEBLOCK, &dev.flags)) {
+
+                               memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+                               clear_bit(F_WRITING, &dev.flags);
+                               msnd_disable_irq(&dev);
+
+                       }
+               }
+
+               if (test_bit(F_WRITEBLOCK, &dev.flags))
+                       wake_up_interruptible(&dev.writeblock);
+               
+               break;
+
+       case HIMT_RECORD_DONE: {
+
+               WORD wTemp;
+               
+               wTemp = dev.DARQ->wTail + (DARQ_STRUCT_SIZE / 2);
+
+               if (wTemp > dev.DARQ->wSize)
+                       wTemp = 0;
+
+               while (wTemp == dev.DARQ->wHead);
+
+               dev.DARQ->wTail = wTemp;
+
+               outb(HPBLKSEL_1, dev.io + HP_BLKS);
+               if (bank_to_DARF(LOBYTE(wMessage)) == 0 &&
+                   !test_bit(F_READBLOCK, &dev.flags)) {
+
+                       memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+                       clear_bit(F_READING, &dev.flags);
+                       msnd_disable_irq(&dev);
+
+               }
+               outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+               if (test_bit(F_READBLOCK, &dev.flags))
+                       wake_up_interruptible(&dev.readblock);
+
+               } break;
+
+       case HIMT_DSP:
+               switch (LOBYTE(wMessage)) {
+               case HIDSP_INT_PLAY_UNDER:
+                       printk(KERN_INFO LOGNAME ": Write underflow\n");
+                       reset_play_queue();
+                       break;
+
+               case HIDSP_INT_RECORD_OVER:
+                       printk(KERN_INFO LOGNAME ": Read overflow\n");
+                       reset_record_queue();
+                       break;
+
+               default:
+                       printk(KERN_INFO LOGNAME ": DSP message %u\n", LOBYTE(wMessage));
+                       break;
+               }
+               break;
+
+        case HIMT_MIDI_IN_UCHAR:
+               if (dev.midi_in_interrupt)
+                       (*dev.midi_in_interrupt)(&dev);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static void intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       if (test_bit(F_INTERRUPT, &dev.flags) || 
+           ((multisound_dev_t *)dev_id != &dev))
+               return;
+
+       set_bit(F_INTERRUPT, &dev.flags);
+       
+       if (test_bit(F_BANKONE, &dev.flags))
+               outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+       inb(dev.io + HP_RXL);
+       while (dev.DSPQ->wTail != dev.DSPQ->wHead) {
+
+               eval_dsp_msg(*(dev.pwDSPQData + dev.DSPQ->wHead));
+
+               if (++dev.DSPQ->wHead > dev.DSPQ->wSize)
+                       dev.DSPQ->wHead = 0;
+       }
+
+       if (test_bit(F_BANKONE, &dev.flags))
+               outb(HPBLKSEL_1, dev.io + HP_BLKS);
+
+       clear_bit(F_INTERRUPT, &dev.flags);
+}
+
+static struct file_operations dev_fileops = {
+       NULL,
+       dev_read,
+       dev_write,
+       NULL,
+       NULL,
+       dev_ioctl,
+       NULL,
+       dev_open,
+       dev_close,
+};
+
+__initfunc(static int reset_dsp(void))
+{
+       int timeout = 20000;
+               
+       outb(HPDSPRESET_ON, dev.io + HP_DSPR);
+       
+       mdelay(1);
+
+       dev.info = inb(dev.io + HP_INFO);
+
+       outb(HPDSPRESET_OFF, dev.io + HP_DSPR);
+
+       mdelay(1);
+
+       while (timeout-- > 0) {
+
+               if (inb(dev.io + HP_CVR) == HP_CVR_DEF)
+                       return 0;
+               
+               mdelay(1);
+       }
+
+       printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+
+       return -EIO;
+}
+
+__initfunc(static int probe_multisound(void))
+{
+       if (check_region(dev.io, dev.numio)) {
+               
+               printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+               return -ENODEV;
+       }
+
+       request_region(dev.io, dev.numio, "probing");
+
+       if (reset_dsp() < 0) {
+               
+               release_region(dev.io, dev.numio);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO LOGNAME ": DSP reset successful\n");
+
+       dev.name = "Classic/Tahiti/Monterey";
+
+       printk(KERN_INFO LOGNAME ": Turtle Beach %s, "
+              "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%p-0x%p\n",
+              dev.name,
+              dev.io, dev.io + dev.numio - 1,
+              dev.irq,
+              dev.base, dev.base + 0x7fff);
+
+       release_region(dev.io, dev.numio);
+       
+       return 0;
+}
+
+__initfunc(static int init_sma(void))
+{
+       int n;
+       LPDAQD lpDAQ;
+
+       outb(dev.memid, dev.io + HP_MEMM);
+
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+       memset_io(dev.base, 0, 0x8000);
+       
+       outb(HPBLKSEL_1, dev.io + HP_BLKS);
+       memset_io(dev.base, 0, 0x8000);
+       
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+       dev.DAPQ = (struct JobQueueStruct *)(dev.base + DAPQ_OFFSET);
+       dev.DARQ = (struct JobQueueStruct *)(dev.base + DARQ_OFFSET);
+       dev.MODQ = (struct JobQueueStruct *)(dev.base + MODQ_OFFSET);
+       dev.MIDQ = (struct JobQueueStruct *)(dev.base + MIDQ_OFFSET);
+       dev.DSPQ = (struct JobQueueStruct *)(dev.base + DSPQ_OFFSET);
+
+       dev.SMA = (struct SMA0_CommonData *)(dev.base + SMA_STRUCT_START);
+
+       dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+       dev.CurDARQD = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+       dev.sample_size = DEFSAMPLESIZE;
+       dev.sample_rate = DEFSAMPLERATE;
+       dev.channels = DEFCHANNELS;
+
+       for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+               
+               writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+               writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+               writew(1, &lpDAQ->wFormat);
+               writew(dev.sample_size, &lpDAQ->wSampleSize);
+               writew(dev.channels, &lpDAQ->wChannels);
+               writew(dev.sample_rate, &lpDAQ->wSampleRate);
+               writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+               writew(n + 1, &lpDAQ->wFlags);
+       }
+
+       for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+               writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+               writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+               writew(1, &lpDAQ->wFormat);
+               writew(dev.sample_size, &lpDAQ->wSampleSize);
+               writew(dev.channels, &lpDAQ->wChannels);
+               writew(dev.sample_rate, &lpDAQ->wSampleRate);
+               writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+               writew(n + 1, &lpDAQ->wFlags);
+
+       }       
+
+       dev.pwDSPQData = (WORD *)(dev.base + DSPQ_DATA_BUFF);
+       dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF);
+       dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF);
+
+       writew(PCTODSP_BASED(MIDQ_DATA_BUFF), &dev.MIDQ->wStart);
+       writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, &dev.MIDQ->wSize);
+       writew(0, &dev.MIDQ->wHead);
+       writew(0, &dev.MIDQ->wTail);
+
+       writew(PCTODSP_BASED(MODQ_DATA_BUFF), &dev.MODQ->wStart);
+       writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, &dev.MODQ->wSize);
+       writew(0, &dev.MODQ->wHead);
+       writew(0, &dev.MODQ->wTail);
+
+       writew(PCTODSP_BASED(DAPQ_DATA_BUFF), &dev.DAPQ->wStart);
+       writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, &dev.DAPQ->wSize);
+       writew(0, &dev.DAPQ->wHead);
+       writew(0, &dev.DAPQ->wTail);
+
+       writew(PCTODSP_BASED(DARQ_DATA_BUFF), &dev.DARQ->wStart);
+       writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, &dev.DARQ->wSize);
+       writew(0, &dev.DARQ->wHead);
+       writew(0, &dev.DARQ->wTail);
+
+       writew(PCTODSP_BASED(DSPQ_DATA_BUFF), &dev.DSPQ->wStart);
+       writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, &dev.DSPQ->wSize);
+       writew(0, &dev.DSPQ->wHead);
+       writew(0, &dev.DSPQ->wTail);
+
+       writew(0, &dev.SMA->wCurrPlayBytes);
+       writew(0, &dev.SMA->wCurrRecordBytes);
+
+       writew(0, &dev.SMA->wCurrPlayVolLeft);
+       writew(0, &dev.SMA->wCurrPlayVolRight);
+
+       writew(0, &dev.SMA->wCurrInVolLeft);
+       writew(0, &dev.SMA->wCurrInVolRight);
+
+       writew(0, &dev.SMA->wCurrMastVolLeft);
+       writew(0, &dev.SMA->wCurrMastVolRight);
+
+       writew(0x0000, &dev.SMA->wCurrDSPStatusFlags);
+       writew(0x0000, &dev.SMA->wCurrHostStatusFlags);
+
+       writew(0x303, &dev.SMA->wCurrInputTagBits);
+       writew(0, &dev.SMA->wCurrLeftPeak);
+       writew(0, &dev.SMA->wCurrRightPeak);
+
+       writeb(0, &dev.SMA->bInPotPosRight);
+       writeb(0, &dev.SMA->bInPotPosLeft);
+
+       writeb(0, &dev.SMA->bAuxPotPosRight);
+       writeb(0, &dev.SMA->bAuxPotPosLeft);
+
+       writew(dev.sample_rate, &dev.SMA->wCalFreqAtoD);
+
+       return 0;
+}
+
+__initfunc(static int calibrate_adc(WORD srate))
+{
+       if (!dev.calibrate_signal) {
+
+               printk(KERN_INFO LOGNAME ": ADC calibration to board ground ");
+               writew(readw(&dev.SMA->wCurrHostStatusFlags)
+                      | 0x0001, &dev.SMA->wCurrHostStatusFlags);
+       }
+       else {
+
+               printk(KERN_INFO LOGNAME ": ADC calibration to signal ground ");
+               writew(readw(&dev.SMA->wCurrHostStatusFlags)
+                      & ~0x0001, &dev.SMA->wCurrHostStatusFlags);
+       }
+       
+       writew(srate, &dev.SMA->wCalFreqAtoD);
+
+       if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
+           msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
+
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + HZ;
+               schedule();
+               current->timeout = 0;
+               printk("successful\n");
+               return 0;
+       }
+
+       printk("failed\n");
+
+       return -EIO;
+}
+
+__initfunc(static int upload_dsp_code(void))
+{
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+#ifdef HAVE_DSPCODEH
+       printk(KERN_INFO LOGNAME ": Using resident Turtle Beach DSP code\n");
+#else  
+       printk(KERN_INFO LOGNAME ": Loading Turtle Beach DSP code\n");
+       INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE);
+       if (!INITCODE) {
+               printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+               return -EBUSY;
+       }
+
+       PERMCODESIZE = mod_firmware_load(PERMCODEFILE, &PERMCODE);
+       if (!PERMCODE) {
+               printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+               vfree(INITCODE);
+               return -EBUSY;
+       }
+#endif
+       memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
+
+       if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) {
+
+               printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+               return -ENODEV;
+       }
+
+#ifndef HAVE_DSPCODEH
+       vfree(INITCODE);
+       vfree(PERMCODE);
+#endif
+
+       return 0;
+}
+
+__initfunc(static void reset_proteus(void))
+{
+       outb(HPPRORESET_ON, dev.io + HP_PROR);
+       mdelay(TIME_PRO_RESET);
+       outb(HPPRORESET_OFF, dev.io + HP_PROR);
+       mdelay(TIME_PRO_RESET_DONE);
+}
+
+__initfunc(static int initialize(void))
+{
+       int err, timeout;
+
+       outb(HPWAITSTATE_0, dev.io + HP_WAIT);
+       outb(HPBITMODE_16, dev.io + HP_BITM);
+
+       reset_proteus();
+
+       if ((err = init_sma()) < 0) {
+
+               printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+               return err;
+       }
+
+       if ((err = reset_dsp()) < 0)
+               return err;
+       
+       if ((err = upload_dsp_code()) < 0) {
+
+               printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+               return err;
+
+       } else
+               printk(KERN_INFO LOGNAME ": DSP upload successful\n");
+
+       timeout = 2000;
+
+       while (readw(dev.base)) {
+               
+               mdelay(1);
+               if (--timeout < 0)
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+__initfunc(static int attach_multisound(void))
+{
+       int err;
+
+       printk(KERN_DEBUG LOGNAME ": Intializing DSP\n");
+
+       if ((err = request_irq(dev.irq, intr, SA_SHIRQ, DEVNAME, &dev)) < 0) {
+               
+               printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
+               return err;
+       
+       }
+
+       request_region(dev.io, dev.numio, DEVNAME);
+
+        if ((err = initialize()) < 0) {
+
+               printk(KERN_WARNING LOGNAME ": Initialization failure\n");
+               release_region(dev.io, dev.numio);
+               free_irq(dev.irq, &dev);
+               return err;
+
+       }
+
+       if ((err = msnd_register(&dev)) < 0) {
+
+               printk(KERN_ERR LOGNAME ": Unable to register MultiSound\n");
+               release_region(dev.io, dev.numio);
+               free_irq(dev.irq, &dev);
+               return err;
+       }
+
+       if ((DSPMINOR = register_sound_dsp(&dev_fileops)) < 0) {
+
+               printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n");
+               msnd_unregister(&dev);
+               release_region(dev.io, dev.numio);
+               free_irq(dev.irq, &dev);
+               return DSPMINOR;
+       }
+
+       if ((MIXERMINOR = register_sound_mixer(&dev_fileops)) < 0) {
+
+               printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n");
+               unregister_sound_mixer(MIXERMINOR);
+               msnd_unregister(&dev);
+               release_region(dev.io, dev.numio);
+               free_irq(dev.irq, &dev);
+               return MIXERMINOR;
+       }
+       printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", MIXERMINOR, DSPMINOR);
+
+       calibrate_adc(dev.sample_rate);
+       set_recsrc(0);
+       
+       return 0;
+}
+
+static void unload_multisound(void)
+{
+       release_region(dev.io, dev.numio);
+       free_irq(dev.irq, &dev);
+       unregister_sound_mixer(MIXERMINOR);
+       unregister_sound_dsp(DSPMINOR);
+       msnd_unregister(&dev);
+}
+
+static void mod_inc_ref(void)
+{
+       MOD_INC_USE_COUNT;
+}
+
+static void mod_dec_ref(void)
+{
+       MOD_DEC_USE_COUNT;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR                          ("Andrew Veliath <andrewtv@usa.net>");
+MODULE_DESCRIPTION                     ("Turtle Beach " LONGNAME " Linux Driver");
+MODULE_PARM                            (io, "i");
+MODULE_PARM                            (irq, "i");
+MODULE_PARM                            (mem, "i");
+MODULE_PARM                            (major, "i");
+MODULE_PARM                            (fifosize, "i");
+MODULE_PARM                            (calibrate_signal, "i");
+
+static int io __initdata =             -1;
+static int irq __initdata =            -1;
+static int mem __initdata =            -1;
+static int fifosize __initdata =       DEFFIFOSIZE;
+static int
+calibrate_signal __initdata =          0;
+
+int init_module(void)
+{
+       int err;
+
+       printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version "
+              VERSION ", Copyright (C) 1998 Andrew Veliath\n");
+       
+       if (io == -1 || irq == -1 || mem == -1) {
+
+               printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+       }
+               
+       if (io == -1 ||
+           !(io == 0x290 ||
+             io == 0x260 ||
+             io == 0x250 ||
+             io == 0x240 ||
+             io == 0x230 ||
+             io == 0x220 ||
+             io == 0x210 ||
+             io == 0x3e0)) {
+
+               printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set\n");
+               return -EINVAL;
+       }
+       
+       if (irq == -1 ||
+           !(irq == 5 ||
+             irq == 7 ||
+             irq == 9 ||
+             irq == 10 ||
+             irq == 11 ||
+             irq == 12)) {
+               
+               printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
+               return -EINVAL;
+       }
+
+       if (mem == -1 ||
+           !(mem == 0xb0000 ||
+             mem == 0xc8000 ||
+             mem == 0xd0000 ||
+             mem == 0xd8000 ||
+             mem == 0xe0000 ||
+             mem == 0xe8000)) {
+               
+               printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+                      "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
+               return -EINVAL;
+       }
+
+       switch (irq) {
+       case 5: dev.irqid = HPIRQ_5; break;
+       case 7: dev.irqid = HPIRQ_7; break;
+       case 9: dev.irqid = HPIRQ_9; break;
+       case 10: dev.irqid = HPIRQ_10; break;
+       case 11: dev.irqid = HPIRQ_11; break;
+       case 12: dev.irqid = HPIRQ_12; break;
+       }
+
+       switch (mem) {
+       case 0xb0000: dev.memid = HPMEM_B000; break;
+       case 0xc8000: dev.memid = HPMEM_C800; break;
+       case 0xd0000: dev.memid = HPMEM_D000; break;
+       case 0xd8000: dev.memid = HPMEM_D800; break;
+       case 0xe0000: dev.memid = HPMEM_E000; break;
+       case 0xe8000: dev.memid = HPMEM_E800; break;
+       }
+
+       if (fifosize < 16)
+               fifosize = 16;
+
+       if (fifosize > 768)
+               fifosize = 768;
+
+       dev.type = msndClassic;
+       dev.io = io;
+       dev.numio = DSP_NUMIO;
+       dev.irq = irq;
+       dev.base = phys_to_virt(mem);
+       dev.fifosize = fifosize * 1024;
+       dev.calibrate_signal = calibrate_signal ? 1 : 0;
+       dev.recsrc = 0;
+       dev.inc_ref = mod_inc_ref;
+       dev.dec_ref = mod_dec_ref;
+
+       init_waitqueue(&dev.writeblock);
+       init_waitqueue(&dev.readblock);
+       msnd_fifo_init(&dev.DAPF);
+       msnd_fifo_init(&dev.DARF);
+       spin_lock_init(&dev.lock);
+
+       printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize);
+
+       if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) {
+               
+               printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n");
+               return err;
+       }
+
+       if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) {
+               
+               printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n");
+               msnd_fifo_free(&dev.DAPF);
+               return err;
+       }
+
+       if ((err = probe_multisound()) < 0) {
+
+               printk(KERN_ERR LOGNAME ": Probe failed\n");
+               msnd_fifo_free(&dev.DAPF);
+               msnd_fifo_free(&dev.DARF);
+               return err;
+
+       }
+       
+       if ((err = attach_multisound()) < 0) {
+
+               printk(KERN_ERR LOGNAME ": Attach failed\n");
+               msnd_fifo_free(&dev.DAPF);
+               msnd_fifo_free(&dev.DARF);
+               return err;
+
+       }
+
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       printk(KERN_INFO LOGNAME ": Unloading\n");
+
+       unload_multisound();
+
+       msnd_fifo_free(&dev.DAPF);
+       msnd_fifo_free(&dev.DARF);
+
+}
+#endif
diff --git a/drivers/sound/msnd_classic.h b/drivers/sound/msnd_classic.h
new file mode 100644 (file)
index 0000000..a1859cb
--- /dev/null
@@ -0,0 +1,191 @@
+/*********************************************************************
+ *
+ * msnd_classic.h
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ * $Id: msnd_classic.h,v 1.3 1998/06/09 20:39:34 andrewtv Exp $
+ *
+ ********************************************************************/
+#ifndef __MSND_CLASSIC_H
+#define __MSND_CLASSIC_H
+
+#define DSP_NUMIO              0x10
+
+#define        HP_MEMM                 0x08
+
+#define        HP_BITM                 0x0E
+#define        HP_WAIT                 0x0D
+#define        HP_DSPR                 0x0A
+#define        HP_PROR                 0x0B
+#define        HP_BLKS                 0x0C
+
+#define        HPPRORESET_OFF          0
+#define HPPRORESET_ON          1
+
+#define HPDSPRESET_OFF         0
+#define HPDSPRESET_ON          1
+
+#define HPBLKSEL_0             0
+#define HPBLKSEL_1             1
+
+#define HPWAITSTATE_0          0
+#define HPWAITSTATE_1          1
+
+#define HPBITMODE_16           0
+#define HPBITMODE_8            1
+
+#define        HIDSP_INT_PLAY_UNDER    0x00
+#define        HIDSP_INT_RECORD_OVER   0x01
+#define        HIDSP_INPUT_CLIPPING    0x02
+#define        HIDSP_MIDI_IN_OVER      0x10
+#define        HIDSP_MIDI_OVERRUN_ERR  0x13
+
+#define        HDEX_BASE               0x92
+#define        HDEX_PLAY_START         (0 + HDEX_BASE)
+#define        HDEX_PLAY_STOP          (1 + HDEX_BASE)
+#define        HDEX_PLAY_PAUSE         (2 + HDEX_BASE)
+#define        HDEX_PLAY_RESUME        (3 + HDEX_BASE)
+#define        HDEX_RECORD_START       (4 + HDEX_BASE)
+#define        HDEX_RECORD_STOP        (5 + HDEX_BASE)
+#define        HDEX_MIDI_IN_START      (6 + HDEX_BASE)
+#define        HDEX_MIDI_IN_STOP       (7 + HDEX_BASE)
+#define        HDEX_MIDI_OUT_START     (8 + HDEX_BASE)
+#define        HDEX_MIDI_OUT_STOP      (9 + HDEX_BASE)
+#define        HDEX_AUX_REQ            (10 + HDEX_BASE)
+
+#define        HDEXAR_CLEAR_PEAKS      1
+#define        HDEXAR_IN_SET_POTS      2
+#define        HDEXAR_AUX_SET_POTS     3
+#define        HDEXAR_CAL_A_TO_D       4
+#define        HDEXAR_RD_EXT_DSP_BITS  5
+
+#define TIME_PRO_RESET_DONE    0x028A
+#define TIME_PRO_SYSEX         0x0040
+#define TIME_PRO_RESET         0x0032
+
+#define AGND                   0x01
+#define SIGNAL                 0x02
+
+#define EXT_DSP_BIT_DCAL       0x0001
+#define EXT_DSP_BIT_MIDI_CON   0x0002
+
+#define BUFFSIZE               0x8000
+#define HOSTQ_SIZE             0x40
+
+#define SRAM_CNTL_START                0x7F00
+#define SMA_STRUCT_START       0x7F40
+
+#define DAP_BUFF_SIZE          0x2400
+#define DAR_BUFF_SIZE          0x2000
+
+#define DAPQ_STRUCT_SIZE       0x10
+#define DARQ_STRUCT_SIZE       0x10
+#define DAPQ_BUFF_SIZE         (3 * 0x10)
+#define DARQ_BUFF_SIZE         (3 * 0x10)
+#define MODQ_BUFF_SIZE         0x400
+#define MIDQ_BUFF_SIZE         0x200
+#define DSPQ_BUFF_SIZE         0x40
+
+#define DAPQ_DATA_BUFF         0x6C00
+#define DARQ_DATA_BUFF         0x6C30
+#define MODQ_DATA_BUFF         0x6C60
+#define MIDQ_DATA_BUFF         0x7060
+#define DSPQ_DATA_BUFF         0x7260
+
+#define DAPQ_OFFSET            SRAM_CNTL_START
+#define DARQ_OFFSET            (SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET            (SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET            (SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET            (SRAM_CNTL_START + 0x20)
+
+#define MOP_PROTEUS            0x10
+#define MOP_EXTOUT             0x32
+#define MOP_EXTTHRU            0x02
+#define MOP_OUTMASK            0x01
+
+#define MIP_EXTIN              0x01
+#define MIP_PROTEUS            0x00
+#define MIP_INMASK             0x32
+
+struct SMA0_CommonData {
+       WORD wCurrPlayBytes;
+       WORD wCurrRecordBytes;
+       WORD wCurrPlayVolLeft;
+       WORD wCurrPlayVolRight;
+       WORD wCurrInVolLeft;
+       WORD wCurrInVolRight;
+       WORD wUser_3;
+       WORD wUser_4;
+       DWORD dwUser_5;
+       DWORD dwUser_6;
+       WORD wUser_7;
+       WORD wReserved_A;
+       WORD wReserved_B;
+       WORD wReserved_C;
+       WORD wReserved_D;
+       WORD wReserved_E;
+       WORD wReserved_F;
+       WORD wReserved_G;
+       WORD wReserved_H;
+       WORD wCurrDSPStatusFlags;
+       WORD wCurrHostStatusFlags;
+       WORD wCurrInputTagBits;
+       WORD wCurrLeftPeak;
+       WORD wCurrRightPeak;
+       WORD wExtDSPbits;
+       BYTE bExtHostbits;
+       BYTE bBoardLevel;
+       BYTE bInPotPosRight;
+       BYTE bInPotPosLeft;
+       BYTE bAuxPotPosRight;
+       BYTE bAuxPotPosLeft;
+       WORD wCurrMastVolLeft;
+       WORD wCurrMastVolRight;
+       BYTE bUser_12;
+       BYTE bUser_13;
+       WORD wUser_14;
+       WORD wUser_15;
+       WORD wCalFreqAtoD;
+       WORD wUser_16;
+       WORD wUser_17;
+} GCC_PACKED;
+
+#ifdef HAVE_DSPCODEH
+#  include "msndperm.c"
+#  include "msndinit.c"
+#  define PERMCODE             msndperm
+#  define INITCODE             msndinit
+#  define PERMCODESIZE         sizeof(msndperm)
+#  define INITCODESIZE         sizeof(msndinit)
+#else
+#  define PERMCODEFILE         CONFIG_MSNDCLAS_PERM_FILE
+#  define INITCODEFILE         CONFIG_MSNDCLAS_INIT_FILE
+#  define PERMCODE             dspini
+#  define INITCODE             permini
+#  define PERMCODESIZE         sizeof_dspini
+#  define INITCODESIZE         sizeof_permini
+#endif
+#define LONGNAME               "MultiSound (Classic/Monterey/Tahiti)"
+
+#endif /* __MSND_CLASSIC_H */
diff --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c
new file mode 100644 (file)
index 0000000..62eaaa4
--- /dev/null
@@ -0,0 +1,1338 @@
+/*********************************************************************
+ *
+ * msnd_pinnacle.c - Support for Turtle Beach Pinnacle and Fiji
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd_pinnacle.c,v 1.2 1998/06/09 20:37:39 andrewtv Exp $
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include "sound_config.h"
+#include "sound_firmware.h"
+#include "msnd.h"
+#include "msnd_pinnacle.h"
+
+#define LOGNAME                                "msnd_pinnacle"
+#define DEVNAME                                dev.name
+#define MIXERMINOR                     dev.mixer_minor
+#define DSPMINOR                       dev.dsp_minor
+
+multisound_dev_t                       dev;
+
+#ifndef HAVE_DSPCODEH
+static char                            *dspini, *permini;
+static int                             sizeof_dspini, sizeof_permini;
+#endif
+
+static void reset_play_queue(void)
+{
+       int n;
+       LPDAQD lpDAQ;
+
+       msnd_fifo_make_empty(&dev.DAPF);
+       dev.DAPQ->wHead = 0;
+       dev.DAPQ->wTail = PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE);
+       dev.CurDAQD = (LPDAQD)(dev.base + 1 * DAPQ_DATA_BUFF);
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+       memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+
+       for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+               
+               writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+               writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+               writew(1, &lpDAQ->wFormat);
+               writew(dev.sample_size, &lpDAQ->wSampleSize);
+               writew(dev.channels, &lpDAQ->wChannels);
+               writew(dev.sample_rate, &lpDAQ->wSampleRate);
+               writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+               writew(n + 1, &lpDAQ->wFlags);
+
+       }
+
+       dev.lastbank = -1;
+}
+
+static void reset_record_queue(void)
+{
+       int n;
+       LPDAQD lpDAQ;
+
+       msnd_fifo_make_empty(&dev.DARF);
+       dev.DARQ->wHead = 0;
+       dev.DARQ->wTail = PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE);
+       dev.CurDARQD = (LPDAQD)(dev.base + 1 * DARQ_DATA_BUFF);
+       outb(HPBLKSEL_1, dev.io + HP_BLKS);
+       memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+       for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+               writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+               writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+               writew(1, &lpDAQ->wFormat);
+               writew(dev.sample_size, &lpDAQ->wSampleSize);
+               writew(dev.channels, &lpDAQ->wChannels);
+               writew(dev.sample_rate, &lpDAQ->wSampleRate);
+               writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+               writew(n + 1, &lpDAQ->wFlags);
+
+       }
+}
+
+static void reset_queues(void)
+{
+       dev.DSPQ->wHead = dev.DSPQ->wTail = 0;
+       reset_play_queue();
+       reset_record_queue();
+}
+
+static int dsp_ioctl(unsigned int cmd, unsigned long arg)
+{
+       int val, i, data;
+       LPDAQD lpDAQ, lpDARQ;
+
+       lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+       lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+       switch (cmd) {
+       case SNDCTL_DSP_SUBDIVIDE:
+       case SNDCTL_DSP_SETFRAGMENT:
+       case SNDCTL_DSP_SETDUPLEX:
+               return 0;
+
+       case SNDCTL_DSP_GETIPTR:
+       case SNDCTL_DSP_GETOPTR:
+       case SNDCTL_DSP_MAPINBUF:
+       case SNDCTL_DSP_MAPOUTBUF:
+               return -EINVAL;
+
+       case SNDCTL_DSP_SYNC:
+       case SNDCTL_DSP_RESET:
+
+               reset_play_queue();
+               reset_record_queue();
+
+               return 0;
+               
+       case SNDCTL_DSP_GETBLKSIZE:
+
+               if (put_user(dev.fifosize / 4, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case SNDCTL_DSP_NONBLOCK:
+
+               dev.mode |= O_NONBLOCK;
+
+               return 0;
+
+       case SNDCTL_DSP_GETCAPS:
+
+               val = DSP_CAP_DUPLEX | DSP_CAP_BATCH;
+               if (put_user(val, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case SNDCTL_DSP_SAMPLESIZE:
+                       
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
+
+               switch (val) {
+               case 16:
+               case 8:
+                       data = val;
+                       break;
+               default:
+                       data = DEFSAMPLESIZE;
+                       break;
+               }
+
+               for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+                       lpDAQ->wSampleSize = data;
+                       lpDARQ->wSampleSize = data;
+               }
+               
+               dev.sample_size = data;
+               
+               if (put_user(data, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case SNDCTL_DSP_SPEED:
+                       
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
+
+               if (val < 8000)
+                       val = 8000;
+
+               if (val > 48000)
+                       val = 48000;
+
+               data = val;
+
+               for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+                       lpDAQ->wSampleRate = data;
+                       lpDARQ->wSampleRate = data;
+               }
+               
+               dev.sample_rate = data;
+
+               if (put_user(data, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case SNDCTL_DSP_CHANNELS:
+                       
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
+                       
+               switch (val) {
+               case 1:
+               case 2:
+                       data = val;
+                       break;
+               default:
+                       val = data = 2;
+                       break;
+               }
+                                                                       
+               for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+                       lpDAQ->wChannels = data;
+                       lpDARQ->wChannels = data;
+               }
+
+               dev.channels = data;
+
+               if (put_user(val, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case SNDCTL_DSP_STEREO:
+                       
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
+                       
+               switch (val) {
+               case 0:
+                       data = 1;
+                       break;
+               default:
+                       val = 1;
+               case 1:
+                       data = 2;
+                       break;
+               }
+                                                                       
+               for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+                       lpDAQ->wChannels = data;
+                       lpDARQ->wChannels = data;
+               }
+
+               dev.channels = data;
+
+               if (put_user(val, (int *)arg))
+                       return -EFAULT;
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int mixer_get(int d)
+{
+       if (d > 31)
+               return -EINVAL;
+
+       switch (d) {
+       case SOUND_MIXER_VOLUME:
+       case SOUND_MIXER_SYNTH:
+       case SOUND_MIXER_PCM:
+       case SOUND_MIXER_LINE:
+       case SOUND_MIXER_MIC:
+       case SOUND_MIXER_IMIX:
+       case SOUND_MIXER_LINE1:
+               return (dev.left_levels[d] >> 8) * 100 / 0xff | 
+                       (((dev.right_levels[d] >> 8) * 100 / 0xff) << 8);
+       default:
+               return 0;
+       }
+}
+
+#define update_vol(a,b,s)                                                              \
+       writew(dev.left_levels[a] * readw(&dev.SMA->wCurrMastVolLeft) / 0xffff / s,     \
+              &dev.SMA->b##Left);                                                      \
+       writew(dev.right_levels[a] * readw(&dev.SMA->wCurrMastVolRight) / 0xffff / s,   \
+              &dev.SMA->b##Right);
+
+static int mixer_set(int d, int value)
+{
+       int left = value & 0x000000ff;
+       int right = (value & 0x0000ff00) >> 8;
+       int bLeft, bRight;
+       int wLeft, wRight;
+
+       if (d > 31)
+               return -EINVAL;
+
+       bLeft = left * 0xff / 100;
+       wLeft = left * 0xffff / 100;
+
+       bRight = right * 0xff / 100;
+       wRight = right * 0xffff / 100;
+
+       dev.left_levels[d] = wLeft;
+       dev.right_levels[d] = wRight;
+
+       switch (d) {
+       case SOUND_MIXER_VOLUME:                /* master volume */
+               writew(wLeft / 2, &dev.SMA->wCurrMastVolLeft);
+               writew(wRight / 2, &dev.SMA->wCurrMastVolRight);
+               break;
+
+               /* pot controls */
+       case SOUND_MIXER_LINE:                  /* aux pot control */
+               writeb(bLeft, &dev.SMA->bInPotPosLeft);
+               writeb(bRight, &dev.SMA->bInPotPosRight);
+               if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
+                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+               break;
+
+       case SOUND_MIXER_MIC:                   /* mic pot control */
+               writeb(bLeft, &dev.SMA->bMicPotPosLeft);
+               writeb(bRight, &dev.SMA->bMicPotPosRight);
+               if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
+                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+               break;
+
+       case SOUND_MIXER_LINE1:                 /* line pot control */
+               writeb(bLeft, &dev.SMA->bAuxPotPosLeft);
+               writeb(bRight, &dev.SMA->bAuxPotPosRight);
+               if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0)
+                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+               break;
+
+               /* digital controls */
+       case SOUND_MIXER_SYNTH:                 /* synth vol (dsp mix) */
+       case SOUND_MIXER_PCM:                   /* pcm vol (dsp mix) */
+       case SOUND_MIXER_IMIX:                  /* input monitor (dsp mix) */
+               break;
+
+       default:
+               return 0;
+       }
+
+       /* update digital controls for master volume */
+       update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1);
+       update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1);
+       update_vol(SOUND_MIXER_SYNTH, wCurrMHdrVol, 1);
+       
+       return mixer_get(d);
+}
+
+static unsigned long set_recsrc(unsigned long recsrc)
+{
+#ifdef HAVE_NORECSRC
+       if (recsrc == 0)
+               dev.recsrc = 0;
+       else
+#endif
+               dev.recsrc ^= recsrc;
+
+       if (dev.recsrc & SOUND_MASK_LINE) {
+
+               if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0)
+                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+
+       }
+       else if (dev.recsrc & SOUND_MASK_SYNTH) {
+
+               if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_SYNTH_IN) == 0)
+                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+
+       }
+       else {
+#ifdef HAVE_NORECSRC
+               /* Select no input (?) */
+               dev.recsrc = 0;
+#else
+               dev.recsrc = SOUND_MASK_LINE;
+               if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0)
+                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+#endif
+       }
+
+       return dev.recsrc;
+}
+
+static int mixer_ioctl(unsigned int cmd, unsigned long arg)
+{
+       int val = 0;
+
+       if (((cmd >> 8) & 0xff) == 'M') {
+               
+               if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+
+                       switch (cmd & 0xff) {
+                       case SOUND_MIXER_RECSRC:
+                               if (get_user(val, (int *)arg))
+                                       return -EFAULT;
+                               val = set_recsrc(val);
+                               break;
+                               
+                       default:
+                               if (get_user(val, (int *)arg))
+                                       return -EFAULT;
+                               val = mixer_set(cmd & 0xff, val);
+                               break;
+                       }
+
+                       return put_user(val, (int *)arg);
+               }
+               else {
+                       switch (cmd & 0xff) {
+                       case SOUND_MIXER_RECSRC:
+                               val = dev.recsrc;
+                               break;
+                               
+                       case SOUND_MIXER_DEVMASK:
+                       case SOUND_MIXER_STEREODEVS:
+                               val =   SOUND_MASK_VOLUME |
+                                       SOUND_MASK_SYNTH |
+                                       SOUND_MASK_PCM |
+                                       SOUND_MASK_LINE |
+                                       SOUND_MASK_IMIX |
+                                       SOUND_MASK_MIC;
+                               break;
+                                 
+                       case SOUND_MIXER_RECMASK:
+                               val =   SOUND_MASK_LINE |
+                                       SOUND_MASK_SYNTH;
+                               break;
+                                 
+                       case SOUND_MIXER_CAPS:
+                               val =   SOUND_CAP_EXCL_INPUT;
+                               break;
+                               
+                       default:
+                               if ((val = mixer_get(cmd & 0xff)) < 0)
+                                       return -EINVAL;
+                               break;
+                       }
+               }
+
+               return put_user(val, (int *)arg); 
+       }
+
+       return -EINVAL;
+}
+
+static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int minor = MINOR(inode->i_rdev);
+
+       if (minor == DSPMINOR)
+               return dsp_ioctl(cmd, arg);
+       else if (minor == MIXERMINOR)
+               return mixer_ioctl(cmd, arg);
+
+       return -EINVAL;
+}
+
+static void dsp_halt(void)
+{
+       mdelay(1);
+       if (test_and_clear_bit(F_READING, &dev.flags)) {
+
+               msnd_send_dsp_cmd(&dev, HDEX_RECORD_STOP);
+               msnd_disable_irq(&dev);
+
+       }
+       mdelay(1);
+       if (test_and_clear_bit(F_WRITING, &dev.flags)) {
+
+               msnd_send_dsp_cmd(&dev, HDEX_PLAY_STOP);
+               msnd_disable_irq(&dev);
+
+       }
+       mdelay(1);
+       reset_queues();
+}
+
+static int dsp_open(struct file *file)
+{
+       dev.mode = file->f_mode;
+       set_bit(F_AUDIO_INUSE, &dev.flags);
+       reset_queues();
+       return 0;
+}
+
+static int dsp_close(void)
+{
+       dsp_halt();
+       clear_bit(F_AUDIO_INUSE, &dev.flags);
+       return 0;
+}
+
+static int dev_open(struct inode *inode, struct file *file)
+{
+       int minor = MINOR(inode->i_rdev);
+       int err = 0;
+
+       if (minor == DSPMINOR) {
+
+               if (test_bit(F_AUDIO_INUSE, &dev.flags))
+                       return -EBUSY;
+
+               err = dsp_open(file);
+       }
+       else if (minor == MIXERMINOR) {
+               /* nothing */
+       } else
+               err = -EINVAL;
+       
+       if (err >= 0)
+               MOD_INC_USE_COUNT;
+
+       return err;
+}
+
+static int dev_close(struct inode *inode, struct file *file)
+{
+       int minor = MINOR(inode->i_rdev);
+       int err = 0;
+
+       if (minor == DSPMINOR) {
+               err = dsp_close();
+       }
+       else if (minor == MIXERMINOR) {
+               /* nothing */
+       } else
+               err = -EINVAL;
+
+       if (err >= 0)
+               MOD_DEC_USE_COUNT;
+       
+       return err;
+}
+
+static int DAPF_to_bank(int bank)
+{
+       return msnd_fifo_read(&dev.DAPF, dev.base + bank * DAP_BUFF_SIZE, DAP_BUFF_SIZE, 0);
+}
+
+static int bank_to_DARF(int bank)
+{
+       return msnd_fifo_write(&dev.DARF, dev.base + bank * DAR_BUFF_SIZE, DAR_BUFF_SIZE, 0);
+}
+
+static int dsp_read(char *buf, size_t len)
+{
+       int err = 0;
+       int count = len;
+
+       while (count > 0) {
+               
+               int n;
+
+               if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) {
+
+                       printk(KERN_WARNING LOGNAME ": FIFO read error\n");
+                       return n;
+               }
+
+               buf += n;
+               count -= n;
+               
+               if (!test_and_set_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) {
+
+                       reset_record_queue();
+                       msnd_enable_irq(&dev);
+                       msnd_send_dsp_cmd(&dev, HDEX_RECORD_START);
+
+               }
+
+               if (dev.mode & O_NONBLOCK)
+                       return count == len ? -EAGAIN : len - count;
+
+               if (count > 0) {
+
+                       set_bit(F_READBLOCK, &dev.flags);
+                       interruptible_sleep_on(&dev.readblock);
+                       clear_bit(F_READBLOCK, &dev.flags);
+
+                       if (signal_pending(current))
+                               err = -EINTR;
+
+               }
+
+               if (err != 0)
+                       return err;
+       }
+
+       return len - count;
+}
+
+static int dsp_write(const char *buf, size_t len)
+{
+       int err = 0;
+       int count = len;
+
+       while (count > 0) {
+
+               int n;
+
+               if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) {
+
+                       printk(KERN_WARNING LOGNAME ": FIFO write error\n");
+                       return n;
+               }
+
+               buf += n;
+               count -= n;
+
+               if (!test_and_set_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
+                       
+                       reset_play_queue();
+                       msnd_enable_irq(&dev);
+                       msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+               }
+
+               if (dev.mode & O_NONBLOCK)
+                       return count == len ? -EAGAIN : len - count;
+
+               if (count > 0) {
+                       
+                       set_bit(F_WRITEBLOCK, &dev.flags);
+                       interruptible_sleep_on(&dev.writeblock);
+                       clear_bit(F_WRITEBLOCK, &dev.flags);
+
+                       if (signal_pending(current))
+                               err = -EINTR;
+
+               }
+
+               if (err != 0)
+                       return err;
+       }
+       
+       return len - count;
+}
+
+static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off)
+{
+       int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+       if (minor == DSPMINOR) {
+
+               return dsp_read(buf, count);
+
+       } else
+               return -EINVAL;
+}
+
+static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+       int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+       if (minor == DSPMINOR) {
+
+               return dsp_write(buf, count);
+
+       } else
+               return -EINVAL;
+}
+
+static void eval_dsp_msg(WORD wMessage)
+{
+       switch (HIBYTE(wMessage)) {
+       case HIMT_PLAY_DONE:
+               
+               if (dev.lastbank == LOBYTE(wMessage))
+                       break;
+               
+               dev.lastbank = LOBYTE(wMessage);
+
+               dev.CurDAQD->wSize = DAP_BUFF_SIZE;
+
+               if ((dev.DAPQ->wTail += PCTODSP_OFFSET(DAPQ_STRUCT_SIZE)) > dev.DAPQ->wSize)
+                       dev.DAPQ->wTail = 0;
+
+               if (++dev.CurDAQD > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE))
+                       dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+
+               if (dev.lastbank < 3) {
+
+                       if (DAPF_to_bank(dev.lastbank) > 0) {
+
+                               mdelay(1);
+                               msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+                       } 
+                       else if (!test_bit(F_WRITEBLOCK, &dev.flags)) {
+
+                               memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+                               clear_bit(F_WRITING, &dev.flags);
+                               msnd_disable_irq(&dev);
+
+                       }
+               }
+
+               if (test_bit(F_WRITEBLOCK, &dev.flags))
+                       wake_up_interruptible(&dev.writeblock);
+               
+               break;
+
+       case HIMT_RECORD_DONE: {
+
+               WORD wTemp;
+               
+               wTemp = dev.DARQ->wTail + (DARQ_STRUCT_SIZE / 2);
+
+               if (wTemp > dev.DARQ->wSize)
+                       wTemp = 0;
+
+               while (wTemp == dev.DARQ->wHead);
+
+               dev.DARQ->wTail = wTemp;
+
+               outb(HPBLKSEL_1, dev.io + HP_BLKS);
+               if (bank_to_DARF(LOBYTE(wMessage)) == 0 &&
+                   !test_bit(F_READBLOCK, &dev.flags)) {
+
+                       memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+                       clear_bit(F_READING, &dev.flags);
+                       msnd_disable_irq(&dev);
+
+               }
+               outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+               if (test_bit(F_READBLOCK, &dev.flags))
+                       wake_up_interruptible(&dev.readblock);
+
+               } break;
+
+       case HIMT_DSP:
+               switch (LOBYTE(wMessage)) {
+               case HIDSP_PLAY_UNDER:
+               case HIDSP_INT_PLAY_UNDER:
+                       printk(KERN_INFO LOGNAME ": Write underflow\n");
+                       reset_play_queue();
+                       break;
+
+               case HIDSP_INT_RECORD_OVER:
+                       printk(KERN_INFO LOGNAME ": Read overflow\n");
+                       reset_record_queue();
+                       break;
+
+               default:
+                       printk(KERN_INFO LOGNAME ": DSP message %u\n", LOBYTE(wMessage));
+                       break;
+               }
+               break;
+
+        case HIMT_MIDI_IN_UCHAR:
+               if (dev.midi_in_interrupt)
+                       (*dev.midi_in_interrupt)(&dev);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static void intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       if (test_bit(F_INTERRUPT, &dev.flags) || 
+           ((multisound_dev_t *)dev_id != &dev))
+               return;
+
+       set_bit(F_INTERRUPT, &dev.flags);
+       
+       if (test_bit(F_BANKONE, &dev.flags))
+               outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+       inb(dev.io + HP_RXL);
+       while (dev.DSPQ->wTail != dev.DSPQ->wHead) {
+
+               eval_dsp_msg(*(dev.pwDSPQData + dev.DSPQ->wHead));
+
+               if (++dev.DSPQ->wHead > dev.DSPQ->wSize)
+                       dev.DSPQ->wHead = 0;
+       }
+
+       if (test_bit(F_BANKONE, &dev.flags))
+               outb(HPBLKSEL_1, dev.io + HP_BLKS);
+
+       clear_bit(F_INTERRUPT, &dev.flags);
+}
+
+static struct file_operations dev_fileops = {
+       NULL,
+       dev_read,
+       dev_write,
+       NULL,
+       NULL,
+       dev_ioctl,
+       NULL,
+       dev_open,
+       dev_close,
+};
+
+__initfunc(static int reset_dsp(void))
+{
+       int timeout = 20000;
+               
+       outb(HPDSPRESET_ON, dev.io + HP_DSPR);
+       
+       mdelay(1);
+
+       dev.info = inb(dev.io + HP_INFO);
+
+       outb(HPDSPRESET_OFF, dev.io + HP_DSPR);
+
+       mdelay(1);
+
+       while (timeout-- > 0) {
+
+               if (inb(dev.io + HP_CVR) == HP_CVR_DEF)
+                       return 0;
+               
+               mdelay(1);
+       }
+
+       printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+
+       return -EIO;
+}
+
+__initfunc(static int probe_multisound(void))
+{
+       char *xv, *rev = NULL;
+       char *pin = "Pinnacle", *fiji = "Fiji";
+       char *pinfiji = "Pinnacle/Fiji";
+
+       if (check_region(dev.io, dev.numio)) {
+               
+               printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+               return -ENODEV;
+       }
+
+       request_region(dev.io, dev.numio, "probing");
+
+       if (reset_dsp() < 0) {
+               
+               release_region(dev.io, dev.numio);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO LOGNAME ": DSP reset successful\n");
+
+       switch (dev.info >> 4) {
+       case 0xf: xv = "<= 1.15"; break;
+       case 0x1: xv = "1.18/1.2"; break;
+       case 0x2: xv = "1.3"; break;
+       case 0x3: xv = "1.4"; break;
+       default: xv = "unknown"; break;
+       }
+               
+       switch (dev.info & 0x7) {
+       case 0x0: rev = "I"; dev.name = pin; break;
+       case 0x1: rev = "F"; dev.name = pin; break;
+       case 0x2: rev = "G"; dev.name = pin; break;
+       case 0x3: rev = "H"; dev.name = pin; break;
+       case 0x4: rev = "E"; dev.name = fiji; break;
+       case 0x5: rev = "C"; dev.name = fiji; break;
+       case 0x6: rev = "D"; dev.name = fiji; break;
+       case 0x7:
+               rev = "A-B (Fiji) or A-E (Pinnacle)";
+               dev.name = pinfiji;
+               break;
+       }
+
+       printk(KERN_INFO LOGNAME ": Turtle Beach %s revision %s, Xilinx version %s, "
+              "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%p-0x%p\n",
+              dev.name,
+              rev, xv,
+              dev.io, dev.io + dev.numio - 1,
+              dev.irq,
+              dev.base, dev.base + 0x7fff);
+
+       release_region(dev.io, dev.numio);
+       
+       return 0;
+}
+
+__initfunc(static int init_sma(void))
+{
+       int n;
+       LPDAQD lpDAQ;
+
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+       memset_io(dev.base, 0, 0x8000);
+       
+       outb(HPBLKSEL_1, dev.io + HP_BLKS);
+       memset_io(dev.base, 0, 0x8000);
+       
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+       dev.DAPQ = (struct JobQueueStruct *)(dev.base + DAPQ_OFFSET);
+       dev.DARQ = (struct JobQueueStruct *)(dev.base + DARQ_OFFSET);
+       dev.MODQ = (struct JobQueueStruct *)(dev.base + MODQ_OFFSET);
+       dev.MIDQ = (struct JobQueueStruct *)(dev.base + MIDQ_OFFSET);
+       dev.DSPQ = (struct JobQueueStruct *)(dev.base + DSPQ_OFFSET);
+
+       dev.SMA = (struct SMA0_CommonData *)(dev.base + SMA_STRUCT_START);
+
+       dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+       dev.CurDARQD = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+       dev.sample_size = DEFSAMPLESIZE;
+       dev.sample_rate = DEFSAMPLERATE;
+       dev.channels = DEFCHANNELS;
+
+       for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+               
+               writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+               writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+               writew(1, &lpDAQ->wFormat);
+               writew(dev.sample_size, &lpDAQ->wSampleSize);
+               writew(dev.channels, &lpDAQ->wChannels);
+               writew(dev.sample_rate, &lpDAQ->wSampleRate);
+               writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+               writew(n + 1, &lpDAQ->wFlags);
+       }
+
+       for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+               writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+               writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+               writew(1, &lpDAQ->wFormat);
+               writew(dev.sample_size, &lpDAQ->wSampleSize);
+               writew(dev.channels, &lpDAQ->wChannels);
+               writew(dev.sample_rate, &lpDAQ->wSampleRate);
+               writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+               writew(n + 1, &lpDAQ->wFlags);
+
+       }       
+
+       dev.pwDSPQData = (WORD *)(dev.base + DSPQ_DATA_BUFF);
+       dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF);
+       dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF);
+
+       writew(PCTODSP_BASED(MIDQ_DATA_BUFF), &dev.MIDQ->wStart);
+       writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, &dev.MIDQ->wSize);
+       writew(0, &dev.MIDQ->wHead);
+       writew(0, &dev.MIDQ->wTail);
+
+       writew(PCTODSP_BASED(MODQ_DATA_BUFF), &dev.MODQ->wStart);
+       writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, &dev.MODQ->wSize);
+       writew(0, &dev.MODQ->wHead);
+       writew(0, &dev.MODQ->wTail);
+
+       writew(PCTODSP_BASED(DAPQ_DATA_BUFF), &dev.DAPQ->wStart);
+       writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, &dev.DAPQ->wSize);
+       writew(0, &dev.DAPQ->wHead);
+       writew(0, &dev.DAPQ->wTail);
+
+       writew(PCTODSP_BASED(DARQ_DATA_BUFF), &dev.DARQ->wStart);
+       writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, &dev.DARQ->wSize);
+       writew(0, &dev.DARQ->wHead);
+       writew(0, &dev.DARQ->wTail);
+
+       writew(PCTODSP_BASED(DSPQ_DATA_BUFF), &dev.DSPQ->wStart);
+       writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, &dev.DSPQ->wSize);
+       writew(0, &dev.DSPQ->wHead);
+       writew(0, &dev.DSPQ->wTail);
+
+       writew(0, &dev.SMA->wCurrPlayBytes);
+       writew(0, &dev.SMA->wCurrRecordBytes);
+
+       writew(0, &dev.SMA->wCurrPlayVolLeft);
+       writew(0, &dev.SMA->wCurrPlayVolRight);
+
+       writew(0, &dev.SMA->wCurrInVolLeft);
+       writew(0, &dev.SMA->wCurrInVolRight);
+
+       writew(0, &dev.SMA->wCurrMastVolLeft);
+       writew(0, &dev.SMA->wCurrMastVolRight);
+
+       writel(0x00010000, &dev.SMA->dwCurrPlayPitch);
+       writel(0x00000001, &dev.SMA->dwCurrPlayRate);
+
+       writew(0x0000, &dev.SMA->wCurrDSPStatusFlags);
+       writew(0x0000, &dev.SMA->wCurrHostStatusFlags);
+
+       writew(0x303, &dev.SMA->wCurrInputTagBits);
+       writew(0, &dev.SMA->wCurrLeftPeak);
+       writew(0, &dev.SMA->wCurrRightPeak);
+
+       writeb(0, &dev.SMA->bInPotPosRight);
+       writeb(0, &dev.SMA->bInPotPosLeft);
+
+       writeb(0, &dev.SMA->bAuxPotPosRight);
+       writeb(0, &dev.SMA->bAuxPotPosLeft);
+
+       writew(1, &dev.SMA->wCurrPlayFormat);
+       writew(dev.sample_size, &dev.SMA->wCurrPlaySampleSize);
+       writew(dev.channels, &dev.SMA->wCurrPlayChannels);
+       writew(dev.sample_rate, &dev.SMA->wCurrPlaySampleRate);
+       writew(dev.sample_rate, &dev.SMA->wCalFreqAtoD);
+
+       return 0;
+}
+
+__initfunc(static int calibrate_adc(WORD srate))
+{
+       if (!dev.calibrate_signal) {
+
+               printk(KERN_INFO LOGNAME ": ADC calibration to board ground ");
+               writew(readw(&dev.SMA->wCurrHostStatusFlags)
+                      | 0x0001, &dev.SMA->wCurrHostStatusFlags);
+       }
+       else {
+
+               printk(KERN_INFO LOGNAME ": ADC calibration to signal ground ");
+               writew(readw(&dev.SMA->wCurrHostStatusFlags)
+                      & ~0x0001, &dev.SMA->wCurrHostStatusFlags);
+       }
+       
+       writew(srate, &dev.SMA->wCalFreqAtoD);
+
+       if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
+           msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
+
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + HZ;
+               schedule();
+               current->timeout = 0;
+               printk("successful\n");
+               return 0;
+       }
+
+       printk("failed\n");
+
+       return -EIO;
+}
+
+__initfunc(static int upload_dsp_code(void))
+{
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+#ifdef HAVE_DSPCODEH
+       printk(KERN_INFO LOGNAME ": Using resident Turtle Beach DSP code\n");
+#else  
+       printk(KERN_INFO LOGNAME ": Loading Turtle Beach DSP code\n");
+       INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE);
+       if (!INITCODE) {
+               printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+               return -EBUSY;
+       }
+
+       PERMCODESIZE = mod_firmware_load(PERMCODEFILE, &PERMCODE);
+       if (!PERMCODE) {
+               printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+               vfree(INITCODE);
+               return -EBUSY;
+       }
+#endif
+       memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
+
+       if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) {
+
+               printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+               return -ENODEV;
+       }
+
+#ifndef HAVE_DSPCODEH
+       vfree(INITCODE);
+       vfree(PERMCODE);
+#endif
+
+       return 0;
+}
+
+__initfunc(static int initialize(void))
+{
+       int err, timeout;
+
+       if ((err = init_sma()) < 0) {
+
+               printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+               return err;
+       }
+
+       if ((err = reset_dsp()) < 0)
+               return err;
+       
+       if ((err = upload_dsp_code()) < 0) {
+
+               printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+               return err;
+
+       } else
+               printk(KERN_INFO LOGNAME ": DSP upload successful\n");
+
+       timeout = 2000;
+
+       while (readw(dev.base)) {
+               
+               mdelay(1);
+               if (--timeout < 0)
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+__initfunc(static int attach_multisound(void))
+{
+       int err;
+
+       printk(KERN_DEBUG LOGNAME ": Intializing DSP\n");
+
+       if ((err = request_irq(dev.irq, intr, SA_SHIRQ, DEVNAME, &dev)) < 0) {
+               
+               printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
+               return err;
+       
+       }
+
+       request_region(dev.io, dev.numio, DEVNAME);
+
+        if ((err = initialize()) < 0) {
+
+               printk(KERN_WARNING LOGNAME ": Initialization failure\n");
+               release_region(dev.io, dev.numio);
+               free_irq(dev.irq, &dev);
+               return err;
+
+       }
+
+       if ((err = msnd_register(&dev)) < 0) {
+
+               printk(KERN_ERR LOGNAME ": Unable to register MultiSound\n");
+               release_region(dev.io, dev.numio);
+               free_irq(dev.irq, &dev);
+               return err;
+       }
+
+       if ((DSPMINOR = register_sound_dsp(&dev_fileops)) < 0) {
+
+               printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n");
+               msnd_unregister(&dev);
+               release_region(dev.io, dev.numio);
+               free_irq(dev.irq, &dev);
+               return DSPMINOR;
+       }
+
+       if ((MIXERMINOR = register_sound_mixer(&dev_fileops)) < 0) {
+
+               printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n");
+               unregister_sound_mixer(MIXERMINOR);
+               msnd_unregister(&dev);
+               release_region(dev.io, dev.numio);
+               free_irq(dev.irq, &dev);
+               return MIXERMINOR;
+       }
+       printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", MIXERMINOR, DSPMINOR);
+
+       calibrate_adc(dev.sample_rate);
+       set_recsrc(0);
+       
+       return 0;
+}
+
+static void unload_multisound(void)
+{
+       release_region(dev.io, dev.numio);
+       free_irq(dev.irq, &dev);
+       unregister_sound_mixer(MIXERMINOR);
+       unregister_sound_dsp(DSPMINOR);
+       msnd_unregister(&dev);
+}
+
+static void mod_inc_ref(void)
+{
+       MOD_INC_USE_COUNT;
+}
+
+static void mod_dec_ref(void)
+{
+       MOD_DEC_USE_COUNT;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR                          ("Andrew Veliath <andrewtv@usa.net>");
+MODULE_DESCRIPTION                     ("Turtle Beach " LONGNAME " Linux Driver");
+MODULE_PARM                            (io, "i");
+MODULE_PARM                            (irq, "i");
+MODULE_PARM                            (mem, "i");
+MODULE_PARM                            (major, "i");
+MODULE_PARM                            (fifosize, "i");
+MODULE_PARM                            (calibrate_signal, "i");
+
+static int io __initdata =             -1;
+static int irq __initdata =            -1;
+static int mem __initdata =            -1;
+static int fifosize __initdata =       DEFFIFOSIZE;
+static int
+calibrate_signal __initdata =          0;
+
+int init_module(void)
+{
+       int err;
+
+       printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version "
+              VERSION ", Copyright (C) 1998 Andrew Veliath\n");
+       
+       if (io == -1 || irq == -1 || mem == -1) {
+
+               printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+       }
+               
+       if (io == -1 ||
+           !(io == 0x290 ||
+             io == 0x260 ||
+             io == 0x250 ||
+             io == 0x240 ||
+             io == 0x230 ||
+             io == 0x220 ||
+             io == 0x210 ||
+             io == 0x3e0)) {
+
+               printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set\n");
+               return -EINVAL;
+       }
+       
+       if (irq == -1 ||
+           !(irq == 5 ||
+             irq == 7 ||
+             irq == 9 ||
+             irq == 10 ||
+             irq == 11 ||
+             irq == 12)) {
+               
+               printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
+               return -EINVAL;
+       }
+
+       if (mem == -1 ||
+           !(mem == 0xb0000 ||
+             mem == 0xc8000 ||
+             mem == 0xd0000 ||
+             mem == 0xd8000 ||
+             mem == 0xe0000 ||
+             mem == 0xe8000)) {
+               
+               printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+                      "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
+               return -EINVAL;
+       }
+
+       if (fifosize < 16)
+               fifosize = 16;
+
+       if (fifosize > 768)
+               fifosize = 768;
+
+       dev.type = msndPinnacle;
+       dev.io = io;
+       dev.numio = DSP_NUMIO;
+       dev.irq = irq;
+       dev.base = phys_to_virt(mem);
+       dev.fifosize = fifosize * 1024;
+       dev.calibrate_signal = calibrate_signal ? 1 : 0;
+       dev.recsrc = 0;
+       dev.inc_ref = mod_inc_ref;
+       dev.dec_ref = mod_dec_ref;
+
+       init_waitqueue(&dev.writeblock);
+       init_waitqueue(&dev.readblock);
+       msnd_fifo_init(&dev.DAPF);
+       msnd_fifo_init(&dev.DARF);
+       spin_lock_init(&dev.lock);
+
+       printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize);
+
+       if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) {
+               
+               printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n");
+               return err;
+       }
+
+       if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) {
+               
+               printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n");
+               msnd_fifo_free(&dev.DAPF);
+               return err;
+       }
+
+       if ((err = probe_multisound()) < 0) {
+
+               printk(KERN_ERR LOGNAME ": Probe failed\n");
+               msnd_fifo_free(&dev.DAPF);
+               msnd_fifo_free(&dev.DARF);
+               return err;
+
+       }
+       
+       if ((err = attach_multisound()) < 0) {
+
+               printk(KERN_ERR LOGNAME ": Attach failed\n");
+               msnd_fifo_free(&dev.DAPF);
+               msnd_fifo_free(&dev.DARF);
+               return err;
+
+       }
+
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       printk(KERN_INFO LOGNAME ": Unloading\n");
+
+       unload_multisound();
+
+       msnd_fifo_free(&dev.DAPF);
+       msnd_fifo_free(&dev.DARF);
+
+}
+#endif
diff --git a/drivers/sound/msnd_pinnacle.h b/drivers/sound/msnd_pinnacle.h
new file mode 100644 (file)
index 0000000..69bac91
--- /dev/null
@@ -0,0 +1,247 @@
+/*********************************************************************
+ *
+ * msnd_pinnacle.h
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd_pinnacle.h,v 1.3 1998/06/09 20:39:34 andrewtv Exp $
+ *
+ ********************************************************************/
+#ifndef __MSND_PINNACLE_H
+#define __MSND_PINNACLE_H
+
+#define DSP_NUMIO              0x08
+
+#define        HP_DSPR                 0x04
+#define        HP_BLKS                 0x04
+
+#define HPDSPRESET_OFF         2
+#define HPDSPRESET_ON          0
+
+#define HPBLKSEL_0             2
+#define HPBLKSEL_1             3
+
+#define        HIMT_DAT_OFF            0x03
+
+#define        HIDSP_PLAY_UNDER        0x00
+#define        HIDSP_INT_PLAY_UNDER    0x01
+#define        HIDSP_SSI_TX_UNDER      0x02
+#define HIDSP_RECQ_OVERFLOW    0x08
+#define HIDSP_INT_RECORD_OVER  0x09
+#define HIDSP_SSI_RX_OVERFLOW  0x0a
+
+#define        HIDSP_MIDI_IN_OVER      0x10
+
+#define        HIDSP_MIDI_FRAME_ERR    0x11
+#define        HIDSP_MIDI_PARITY_ERR   0x12
+#define        HIDSP_MIDI_OVERRUN_ERR  0x13
+
+#define HIDSP_INPUT_CLIPPING   0x20
+#define        HIDSP_MIX_CLIPPING      0x30
+#define HIDSP_DAT_IN_OFF       0x21
+
+#define        HDEX_BASE               0x92
+#define        HDEX_PLAY_START         (0 + HDEX_BASE)
+#define        HDEX_PLAY_STOP          (1 + HDEX_BASE)
+#define        HDEX_PLAY_PAUSE         (2 + HDEX_BASE)
+#define        HDEX_PLAY_RESUME        (3 + HDEX_BASE)
+#define        HDEX_RECORD_START       (4 + HDEX_BASE)
+#define        HDEX_RECORD_STOP        (5 + HDEX_BASE)
+#define        HDEX_MIDI_IN_START      (6 + HDEX_BASE)
+#define        HDEX_MIDI_IN_STOP       (7 + HDEX_BASE)
+#define        HDEX_MIDI_OUT_START     (8 + HDEX_BASE)
+#define        HDEX_MIDI_OUT_STOP      (9 + HDEX_BASE)
+#define        HDEX_AUX_REQ            (10 + HDEX_BASE)
+
+#define        HDEXAR_SET_ANA_IN       0
+#define        HDEXAR_CLEAR_PEAKS      1
+#define        HDEXAR_IN_SET_POTS      2
+#define        HDEXAR_AUX_SET_POTS     3
+#define        HDEXAR_CAL_A_TO_D       4
+#define        HDEXAR_RD_EXT_DSP_BITS  5
+
+#define        HDEXAR_SET_SYNTH_IN     4
+#define        HDEXAR_READ_DAT_IN      5
+#define        HDEXAR_MIC_SET_POTS     6
+#define        HDEXAR_SET_DAT_IN       7
+
+#define HDEXAR_SET_SYNTH_48     8
+#define HDEXAR_SET_SYNTH_44     9
+
+#define TIME_PRO_RESET_DONE    0x028A
+#define TIME_PRO_SYSEX         0x001E
+#define TIME_PRO_RESET         0x0032
+
+#define AGND                   0x01
+#define SIGNAL                 0x02
+
+#define EXT_DSP_BIT_DCAL       0x0001
+#define EXT_DSP_BIT_MIDI_CON   0x0002
+
+#define BUFFSIZE               0x8000
+#define HOSTQ_SIZE             0x40
+
+#define SRAM_CNTL_START                0x7F00
+#define SMA_STRUCT_START       0x7F40
+
+#define DAP_BUFF_SIZE          0x2400
+#define DAR_BUFF_SIZE          0x2000
+
+#define DAPQ_STRUCT_SIZE       0x10
+#define DARQ_STRUCT_SIZE       0x10
+#define DAPQ_BUFF_SIZE         (3 * 0x10)
+#define DARQ_BUFF_SIZE         (3 * 0x10)
+#define MODQ_BUFF_SIZE         0x400
+#define MIDQ_BUFF_SIZE         0x800
+#define DSPQ_BUFF_SIZE         0x5A0
+
+#define DAPQ_DATA_BUFF         0x6C00
+#define DARQ_DATA_BUFF         0x6C30
+#define MODQ_DATA_BUFF         0x6C60
+#define MIDQ_DATA_BUFF         0x7060
+#define DSPQ_DATA_BUFF         0x7860
+
+#define DAPQ_OFFSET            SRAM_CNTL_START
+#define DARQ_OFFSET            (SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET            (SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET            (SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET            (SRAM_CNTL_START + 0x20)
+
+#define WAVEHDR_MOP            0
+#define EXTOUT_MOP             1
+#define HWINIT_MOP             0xFE
+#define NO_MOP                 0xFF
+
+#define MAX_MOP                        1
+
+#define EXTIN_MIP              0
+#define WAVEHDR_MIP            1
+#define HWINIT_MIP             0xFE
+
+#define MAX_MIP                        1
+
+struct SMA0_CommonData {
+       WORD wCurrPlayBytes;
+       WORD wCurrRecordBytes;
+       WORD wCurrPlayVolLeft;
+       WORD wCurrPlayVolRight;
+
+       WORD wCurrInVolLeft;
+       WORD wCurrInVolRight;
+       WORD wCurrMHdrVolLeft;
+       WORD wCurrMHdrVolRight;
+
+       DWORD dwCurrPlayPitch;
+       DWORD dwCurrPlayRate;
+
+       WORD wCurrMIDIIOPatch;
+
+       WORD wCurrPlayFormat;
+       WORD wCurrPlaySampleSize;
+       WORD wCurrPlayChannels;
+       WORD wCurrPlaySampleRate;
+
+       WORD wCurrRecordFormat;
+       WORD wCurrRecordSampleSize;
+       WORD wCurrRecordChannels;
+       WORD wCurrRecordSampleRate;
+
+       WORD wCurrDSPStatusFlags;
+       WORD wCurrHostStatusFlags;
+
+       WORD wCurrInputTagBits;
+       WORD wCurrLeftPeak;
+       WORD wCurrRightPeak;
+
+       BYTE bMicPotPosLeft;
+       BYTE bMicPotPosRight;
+
+       BYTE bMicPotMaxLeft;
+       BYTE bMicPotMaxRight;
+
+       BYTE bInPotPosLeft;
+       BYTE bInPotPosRight;
+       
+       BYTE bAuxPotPosLeft;
+       BYTE bAuxPotPosRight;
+       
+       BYTE bInPotMaxLeft;
+       BYTE bInPotMaxRight;
+       BYTE bAuxPotMaxLeft;
+       BYTE bAuxPotMaxRight;
+       BYTE bInPotMaxMethod;
+       BYTE bAuxPotMaxMethod;
+
+       WORD wCurrMastVolLeft;
+       WORD wCurrMastVolRight;
+
+       WORD wCalFreqAtoD;
+
+       WORD wCurrAuxVolLeft;
+       WORD wCurrAuxVolRight;
+
+       WORD wCurrPlay1VolLeft;
+       WORD wCurrPlay1VolRight;
+       WORD wCurrPlay2VolLeft;
+       WORD wCurrPlay2VolRight;
+       WORD wCurrPlay3VolLeft;
+       WORD wCurrPlay3VolRight;
+       WORD wCurrPlay4VolLeft;
+       WORD wCurrPlay4VolRight;
+       WORD wCurrPlay1PeakLeft;
+       WORD wCurrPlay1PeakRight;
+       WORD wCurrPlay2PeakLeft;
+       WORD wCurrPlay2PeakRight;
+       WORD wCurrPlay3PeakLeft;
+       WORD wCurrPlay3PeakRight;
+       WORD wCurrPlay4PeakLeft;
+       WORD wCurrPlay4PeakRight;
+       WORD wCurrPlayPeakLeft;
+       WORD wCurrPlayPeakRight;
+
+       WORD wCurrDATSR;
+       WORD wCurrDATRXCHNL;
+       WORD wCurrDATTXCHNL;
+       WORD wCurrDATRXRate;
+
+       DWORD dwDSPPlayCount;
+} GCC_PACKED;
+
+#ifdef HAVE_DSPCODEH
+#  include "pndsperm.c"
+#  include "pndspini.c"
+#  define PERMCODE             pndsperm
+#  define INITCODE             pndspini
+#  define PERMCODESIZE         sizeof(pndsperm)
+#  define INITCODESIZE         sizeof(pndspini)
+#else
+#  define PERMCODEFILE         CONFIG_MSNDPIN_PERM_FILE
+#  define INITCODEFILE         CONFIG_MSNDPIN_INIT_FILE
+#  define PERMCODE             dspini
+#  define INITCODE             permini
+#  define PERMCODESIZE         sizeof_dspini
+#  define INITCODESIZE         sizeof_permini
+#endif
+#define LONGNAME               "MultiSound (Pinnacle/Fiji)"
+
+#endif /* __MSND_PINNACLE_H */
index 37ef752f74f4d5f10ada03fb3ca4518410335c2c..44696204bfb3773690b0a3aa93ca5c3b5654b06a 100644 (file)
@@ -153,13 +153,16 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len
 #else
 #define MODULEPROCSTRING "Driver compiled into kernel"
 #endif
-       
+
+       down(&uts_sem); 
+
        len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n"
                      "Load type: " MODULEPROCSTRING "\n"
                      "Kernel: %s %s %s %s %s\n"
                      "Config options: %x\n\nInstalled drivers: \n", 
                      system_utsname.sysname, system_utsname.nodename, system_utsname.release, 
                      system_utsname.version, system_utsname.machine, SELECTED_SOUND_OPTIONS);
+       up(&uts_sem);
        
        for (i = 0; (i < num_sound_drivers) && (pos <= offset + length); i++) {
                if (!sound_drivers[i].card_type)
index 35d25b4ea5f61a0b5347440b97e12505435f0d6c..c1d695c99ababfbaea39c00006a2e7b07551d802 100644 (file)
 #include <linux/config.h>
 #include <linux/module.h>
 
-#ifdef CONFIG_VMIDI
-
 #include "sound_config.h"
 #include "soundmodule.h"
+
+#ifdef CONFIG_VMIDI
+
 #include "v_midi.h"
 
 static vmidi_devc *v_devc[2] = { NULL, NULL};
index f47f467ecdc1cb209b941f435885893ac836ee2d..2f00feaa69ed60e9d09876df345417b84f72e60d 100644 (file)
@@ -129,7 +129,7 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
        if (get_write_access(inode))
                goto end_coredump;
        if (init_private_file(&file, dentry, 3))
-               goto end_coredump;
+               goto end_coredump_write;
        if (!file.f_op->write)
                goto close_coredump;
        has_dumped = 1;
@@ -213,6 +213,7 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
 close_coredump:
        if (file.f_op->release)
                file.f_op->release(inode,&file);
+end_coredump_write:
        put_write_access(inode);
 end_coredump:
        set_fs(fs);
index 54025e702b5722840ec1445a002bc8823c42d830..093140e9d3817159aa15444bc1858eb151191cf2 100644 (file)
 
 static struct super_block *mounts = NULL;
 
-static void devpts_put_inode(struct inode *inode)
-{
-}
-
-static void devpts_delete_inode(struct inode *inode)
-{
-       inode->i_size = 0;
-}
-
 static void devpts_put_super(struct super_block *sb)
 {
        struct devpts_sb_info *sbi = SBI(sb);
@@ -48,6 +39,7 @@ static void devpts_put_super(struct super_block *sb)
                        if ( inode->i_count != 1 )
                                printk("devpts_put_super: badness: entry %d count %d\n",
                                       i, inode->i_count);
+                       inode->i_nlink--;
                        iput(inode);
                }
        }
@@ -70,8 +62,8 @@ static void devpts_write_inode(struct inode *inode);
 static struct super_operations devpts_sops = {
        devpts_read_inode,
        devpts_write_inode,
-       devpts_put_inode,
-       devpts_delete_inode,
+       NULL,                   /* put_inode */
+       NULL,                   /* delete_inode */
        NULL,                   /* notify_change */
        devpts_put_super,
        NULL,                   /* write_super */
@@ -281,8 +273,6 @@ static void devpts_read_inode(struct inode *inode)
        if ( ino >= NR_PTYS )
                return;         /* Bogus */
        
-       inode->i_nlink = 1;
-
        inode->i_mode = S_IFCHR;
        inode->i_rdev = MKDEV(0,0); /* Gets filled in by devpts_pty_new() */
 
@@ -322,6 +312,7 @@ void devpts_pty_new(int number, kdev_t device)
                        inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
                        inode->i_mode = sbi->mode | S_IFCHR;
                        inode->i_rdev = device;
+                       inode->i_nlink++;
                        sbi->inodes[number] = inode;
                }
        }
@@ -340,7 +331,7 @@ void devpts_pty_kill(int number)
 
                if ( inode ) {
                        sbi->inodes[number] = NULL;
-                       inode->i_nlink = 0; /* Is this right? */
+                       inode->i_nlink--;
                        iput(inode);
                }
        }
index 1674c7389ec7fc4b467e25766f744990dd6e620a..307b48e94045a2a01a53f817eadc42984bbec933 100644 (file)
@@ -144,6 +144,10 @@ __initfunc(static void do_sys_setup(void))
        init_adfs_fs();
 #endif
 
+#ifdef CONFIG_ADFS_FS
+       init_adfs_fs();
+#endif
+
 #ifdef CONFIG_DEVPTS_FS
        init_devpts_fs();
 #endif
index bddbe4ba69a4c0d3195f2e03c92f00462e6a49fb..d1904bf9f4230437cc53a7b77a73caf8b594e342 100644 (file)
@@ -91,6 +91,32 @@ static int isofs_name_translate(char * old, int len, char * new)
        return i;
 }
 
+/* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
+int get_acorn_filename(struct iso_directory_record * de,
+                           char * retname, struct inode * inode)
+{
+       int std;
+       unsigned char * chr;
+       int retnamlen = isofs_name_translate(de->name,
+                               de->name_len[0], retname);
+       if (retnamlen == 0) return 0;
+       std = sizeof(struct iso_directory_record) + de->name_len[0];
+       if (std & 1) std++;
+       if ((*((unsigned char *) de) - std) != 32) return retnamlen;
+       chr = ((unsigned char *) de) + std;
+       if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
+       if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
+       if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
+               && ((chr[12] & 0xf0) == 0xf0))
+       {
+               retname[retnamlen] = ',';
+               sprintf(retname+retnamlen+1, "%3.3x",
+                       ((chr[12] & 0xf) << 8) | chr[11]);
+               retnamlen += 4;
+       }
+       return retnamlen;
+}
+
 /*
  * This should _really_ be cleaned up some day..
  */
@@ -230,15 +256,17 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
                                p = tmpname;
                        } else
 #endif
-                       {
-                               if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
-                                       len = isofs_name_translate(de->name, de->name_len[0],
-                                                                  tmpname);
-                                       p = tmpname;
-                               } else {
-                                       p = de->name;
-                                       len = de->name_len[0];
-                               }
+                       if (inode->i_sb->u.isofs_sb.s_mapping == 'a') {
+                               len = get_acorn_filename(de, tmpname, inode);
+                               p = tmpname;
+                       } else
+                       if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
+                               len = isofs_name_translate(de->name,
+                                       de->name_len[0], tmpname);
+                               p = tmpname;
+                       } else {
+                               p = de->name;
+                               len = de->name_len[0];
                        }
                }
                if (len > 0) {
index a1a460c06901d5c852cf73c1a7c8d6dc041afa8f..6bcdc4d834cdc1145bf720f7165c1786505054df 100644 (file)
@@ -90,7 +90,7 @@ static int parse_options(char *options, struct iso9660_options * popt)
 {
        char *this_char,*value;
 
-       popt->map = 'n';
+       popt->map = 'a';
        popt->rock = 'y';
        popt->joliet = 'y';
        popt->cruft = 'n';
@@ -141,10 +141,11 @@ static int parse_options(char *options, struct iso9660_options * popt)
                } else
 #endif
                if (!strcmp(this_char,"map") && value) {
-                       if (value[0] && !value[1] && strchr("on",*value))
+                       if (value[0] && !value[1] && strchr("ano",*value))
                                popt->map = *value;
                        else if (!strcmp(value,"off")) popt->map = 'o';
                        else if (!strcmp(value,"normal")) popt->map = 'n';
+                       else if (!strcmp(value,"acorn")) popt->map = 'a';
                        else return 0;
                }
                else if (!strcmp(this_char,"check") && value) {
index f638084b6a9cee03eba3294338b07499b166e3ab..0876f0ae8d9241aa24385385aeb58f900f270db7 100644 (file)
@@ -178,6 +178,9 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
                        dlen = get_joliet_filename(de, dir, page);
                        dpnt = page;
 #endif
+               } else if (dir->i_sb->u.isofs_sb.s_mapping == 'a') {
+                       dlen = get_acorn_filename(de, page, dir);
+                       dpnt = page;
                } else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
                        for (i = 0; i < dlen; i++) {
                                c = dpnt[i];
index 3d6f0a4263aa05aedd7d1e69913a212e1244ba03..49dde4e44efab046efe84e803891c78ffbee297e 100644 (file)
@@ -36,16 +36,17 @@ static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, _
 
        if (numblocks==0 || !(bh=map[numblocks-1]))
                return(0);
-       i = (numbits-(numblocks-1)*BLOCK_SIZE*8)/8;
+       i = ((numbits-(numblocks-1)*BLOCK_SIZE*8)/16)*2;
        for (j=0; j<i; j++) {
                sum += nibblemap[bh->b_data[j] & 0xf]
                        + nibblemap[(bh->b_data[j]>>4) & 0xf];
        }
 
-       i = numbits%8;
+       i = numbits%16;
        if (i!=0) {
-               i = bh->b_data[j] | ~((1<<i) - 1);
+               i = *(__u16 *)(&bh->b_data[j]) | ~((1<<i) - 1);
                sum += nibblemap[i & 0xf] + nibblemap[(i>>4) & 0xf];
+               sum += nibblemap[(i>>8) & 0xf] + nibblemap[(i>>12) & 0xf];
        }
        return(sum);
 }
@@ -71,11 +72,11 @@ void minix_free_block(struct super_block * sb, int block)
        zone = block - sb->u.minix_sb.s_firstdatazone + 1;
        bit = zone & 8191;
        zone >>= 13;
-       bh = sb->u.minix_sb.s_zmap[zone];
-       if (!bh) {
+       if (zone >= sb->u.minix_sb.s_zmap_blocks) {
                printk("minix_free_block: nonexistent bitmap buffer\n");
                return;
        }
+       bh = sb->u.minix_sb.s_zmap[zone];
        if (!minix_clear_bit(bit,bh->b_data))
                printk("free_block (%s:%d): bit already cleared\n",
                       kdevname(sb->s_dev), block);
@@ -94,11 +95,13 @@ int minix_new_block(struct super_block * sb)
        }
 repeat:
        j = 8192;
-       for (i=0 ; i<64 ; i++)
-               if ((bh=sb->u.minix_sb.s_zmap[i]) != NULL)
-                       if ((j=minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
-                               break;
-       if (i>=64 || !bh || j>=8192)
+       bh = NULL;
+       for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++) {
+               bh = sb->u.minix_sb.s_zmap[i];
+               if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
+                       break;
+       }
+       if (!bh || j >= 8192)
                return 0;
        if (minix_set_bit(j,bh->b_data)) {
                printk("new_block: bit already set");
@@ -134,7 +137,7 @@ static struct buffer_head *V1_minix_clear_inode(struct inode *inode)
        int ino, block;
 
        ino = inode->i_ino;
-       if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+       if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
                printk("Bad inode number on dev %s: %d is out of range\n",
                       kdevname(inode->i_dev), ino);
                return 0;
@@ -162,7 +165,7 @@ static struct buffer_head *V2_minix_clear_inode(struct inode *inode)
        int ino, block;
 
        ino = inode->i_ino;
-       if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+       if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
                printk("Bad inode number on dev %s: %d is out of range\n",
                       kdevname(inode->i_dev), ino);
                return 0;
@@ -218,15 +221,16 @@ void minix_free_inode(struct inode * inode)
                printk("free_inode: inode on nonexistent device\n");
                return;
        }
-       if (inode->i_ino < 1 || inode->i_ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+       if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.minix_sb.s_ninodes) {
                printk("free_inode: inode 0 or nonexistent inode\n");
                return;
        }
        ino = inode->i_ino;
-       if (!(bh=inode->i_sb->u.minix_sb.s_imap[ino >> 13])) {
+       if ((ino >> 13) >= inode->i_sb->u.minix_sb.s_imap_blocks) {
                printk("free_inode: nonexistent imap in superblock\n");
                return;
        }
+       bh = inode->i_sb->u.minix_sb.s_imap[ino >> 13];
        minix_clear_inode(inode);
        clear_inode(inode);
        if (!minix_clear_bit(ino & 8191, bh->b_data))
@@ -247,10 +251,12 @@ struct inode * minix_new_inode(const struct inode * dir)
        inode->i_sb = sb;
        inode->i_flags = inode->i_sb->s_flags;
        j = 8192;
-       for (i=0 ; i<8 ; i++)
-               if ((bh = inode->i_sb->u.minix_sb.s_imap[i]) != NULL)
-                       if ((j=minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
-                               break;
+       bh = NULL;
+       for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++) {
+               bh = inode->i_sb->u.minix_sb.s_imap[i];
+               if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
+                       break;
+       }
        if (!bh || j >= 8192) {
                iput(inode);
                return NULL;
@@ -262,7 +268,7 @@ struct inode * minix_new_inode(const struct inode * dir)
        }
        mark_buffer_dirty(bh, 1);
        j += i*8192;
-       if (!j || j >= inode->i_sb->u.minix_sb.s_ninodes) {
+       if (!j || j > inode->i_sb->u.minix_sb.s_ninodes) {
                iput(inode);
                return NULL;
        }
index 8934dc01269ea513a443caa906e0ce6d368641b1..8aa3c4b7d125f54ceec7e050fb5199b0c5896484 100644 (file)
@@ -63,9 +63,9 @@ void minix_put_super(struct super_block *sb)
                sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state;
                mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
        }
-       for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++)
+       for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++)
                brelse(sb->u.minix_sb.s_imap[i]);
-       for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++)
+       for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++)
                brelse(sb->u.minix_sb.s_zmap[i]);
        brelse (sb->u.minix_sb.s_sbh);
        kfree(sb->u.minix_sb.s_imap);
@@ -173,7 +173,8 @@ struct super_block *minix_read_super(struct super_block *s, void *data,
        const char * errmsg;
        struct inode *root_inode;
        
-       /* N.B. These should be compile-time tests */
+       /* N.B. These should be compile-time tests.
+          Unfortunately that is impossible. */
        if (32 != sizeof (struct minix_inode))
                panic("bad V1 i-node size");
        if (64 != sizeof(struct minix2_inode))
@@ -203,33 +204,37 @@ struct super_block *minix_read_super(struct super_block *s, void *data,
                s->u.minix_sb.s_version = MINIX_V1;
                s->u.minix_sb.s_dirsize = 16;
                s->u.minix_sb.s_namelen = 14;
+               s->u.minix_sb.s_link_max = MINIX_LINK_MAX;
        } else if (s->s_magic == MINIX_SUPER_MAGIC2) {
                s->u.minix_sb.s_version = MINIX_V1;
                s->u.minix_sb.s_dirsize = 32;
                s->u.minix_sb.s_namelen = 30;
+               s->u.minix_sb.s_link_max = MINIX_LINK_MAX;
        } else if (s->s_magic == MINIX2_SUPER_MAGIC) {
                s->u.minix_sb.s_version = MINIX_V2;
+               s->u.minix_sb.s_nzones = ms->s_zones;
                s->u.minix_sb.s_dirsize = 16;
                s->u.minix_sb.s_namelen = 14;
+               s->u.minix_sb.s_link_max = MINIX2_LINK_MAX;
        } else if (s->s_magic == MINIX2_SUPER_MAGIC2) {
                s->u.minix_sb.s_version = MINIX_V2;
+               s->u.minix_sb.s_nzones = ms->s_zones;
                s->u.minix_sb.s_dirsize = 32;
                s->u.minix_sb.s_namelen = 30;
+               s->u.minix_sb.s_link_max = MINIX2_LINK_MAX;
        } else
                goto out_no_fs;
 
-       if (s->u.minix_sb.s_zmap_blocks > MINIX_Z_MAP_SLOTS)
-               goto out_too_big;
        /*
         * Allocate the buffer map to keep the superblock small.
         */
-       i = (MINIX_I_MAP_SLOTS + MINIX_Z_MAP_SLOTS) * sizeof(bh);
+       i = (s->u.minix_sb.s_imap_blocks + s->u.minix_sb.s_zmap_blocks) * sizeof(bh);
        map = kmalloc(i, GFP_KERNEL);
        if (!map)
                goto out_no_map;
        memset(map, 0, i);
        s->u.minix_sb.s_imap = &map[0];
-       s->u.minix_sb.s_zmap = &map[MINIX_I_MAP_SLOTS];
+       s->u.minix_sb.s_zmap = &map[s->u.minix_sb.s_imap_blocks];
 
        block=2;
        for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++) {
@@ -242,8 +247,6 @@ struct super_block *minix_read_super(struct super_block *s, void *data,
                        goto out_no_bitmap;
                block++;
        }
-       if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks)
-               goto out_no_bitmap;
 
        minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data);
        minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data);
@@ -263,6 +266,8 @@ struct super_block *minix_read_super(struct super_block *s, void *data,
        if (!s->s_root)
                goto out_iput;
 
+       s->s_root->d_op = &minix_dentry_operations;
+
        if (!(s->s_flags & MS_RDONLY)) {
                ms->s_state &= ~MINIX_VALID_FS;
                mark_buffer_dirty(bh, 1);
@@ -292,9 +297,9 @@ out_no_root:
 out_no_bitmap:
        printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
     out_freemap:
-       for(i=0;i<MINIX_I_MAP_SLOTS;i++)
+       for (i = 0; i < s->u.minix_sb.s_imap_blocks; i++)
                brelse(s->u.minix_sb.s_imap[i]);
-       for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
+       for (i = 0; i < s->u.minix_sb.s_zmap_blocks; i++)
                brelse(s->u.minix_sb.s_zmap[i]);
        kfree(s->u.minix_sb.s_imap);
        goto out_release;
@@ -304,11 +309,6 @@ out_no_map:
                printk ("MINIX-fs: can't allocate map\n");
        goto out_release;
 
-out_too_big:
-       if (!silent)
-               printk ("MINIX-fs: filesystem too big\n");
-       goto out_release;
-
 out_no_fs:
        if (!silent)
                printk("VFS: Can't find a minix or minix V2 filesystem on dev "
@@ -729,7 +729,7 @@ static void V1_minix_read_inode(struct inode * inode)
        ino = inode->i_ino;
        inode->i_op = NULL;
        inode->i_mode = 0;
-       if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+       if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
                printk("Bad inode number on dev %s"
                       ": %d is out of range\n",
                        kdevname(inode->i_dev), ino);
@@ -783,7 +783,7 @@ static void V2_minix_read_inode(struct inode * inode)
        ino = inode->i_ino;
        inode->i_op = NULL;
        inode->i_mode = 0;
-       if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+       if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
                printk("Bad inode number on dev %s"
                       ": %d is out of range\n",
                        kdevname(inode->i_dev), ino);
@@ -848,7 +848,7 @@ static struct buffer_head * V1_minix_update_inode(struct inode * inode)
        int ino, block;
 
        ino = inode->i_ino;
-       if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+       if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
                printk("Bad inode number on dev %s"
                       ": %d is out of range\n",
                        kdevname(inode->i_dev), ino);
@@ -886,7 +886,7 @@ static struct buffer_head * V2_minix_update_inode(struct inode * inode)
        int ino, block;
 
        ino = inode->i_ino;
-       if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+       if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
                printk("Bad inode number on dev %s"
                       ": %d is out of range\n",
                        kdevname(inode->i_dev), ino);
index 3155e72e4b01edaabdcb659cdaafd6f8e04c28a6..17ff53aedaac15a36a9283aa74b2b4defe04d1ed 100644 (file)
 static inline int namecompare(int len, int maxlen,
        const char * name, const char * buffer)
 {
-       if (len > maxlen)
-               return 0;
        if (len < maxlen && buffer[len])
                return 0;
        return !memcmp(name, buffer, len);
 }
 
-/*
- * ok, we cannot use strncmp, as the name is not in our data space.
- * Thus we'll have to use minix_match. No big problem. Match also makes
- * some sanity tests.
- *
- * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure.
- */
-static int minix_match(int len, const char * name,
-       struct buffer_head * bh, unsigned long * offset,
-       struct minix_sb_info * info)
-{
-       struct minix_dir_entry * de;
-
-       de = (struct minix_dir_entry *) (bh->b_data + *offset);
-       *offset += info->s_dirsize;
-       if (!de->inode || len > info->s_namelen)
-               return 0;
-       return namecompare(len,info->s_namelen,name,de->name);
-}
-
 /*
  *     minix_find_entry()
  *
@@ -64,6 +42,7 @@ static struct buffer_head * minix_find_entry(struct inode * dir,
        unsigned long block, offset;
        struct buffer_head * bh;
        struct minix_sb_info * info;
+       struct minix_dir_entry *de;
 
        *res_dir = NULL;
        if (!dir || !dir->i_sb)
@@ -86,9 +65,12 @@ static struct buffer_head * minix_find_entry(struct inode * dir,
                                continue;
                        }
                }
-               *res_dir = (struct minix_dir_entry *) (bh->b_data + offset);
-               if (minix_match(namelen,name,bh,&offset,info))
+               de = (struct minix_dir_entry *) (bh->b_data + offset);
+               offset += info->s_dirsize;
+               if (de->inode && namecompare(namelen,info->s_namelen,name,de->name)) {
+                       *res_dir = de;
                        return bh;
+               }
                if (offset < bh->b_size)
                        continue;
                brelse(bh);
@@ -97,16 +79,52 @@ static struct buffer_head * minix_find_entry(struct inode * dir,
                block++;
        }
        brelse(bh);
-       *res_dir = NULL;
        return NULL;
 }
 
+#ifndef NO_TRUNCATE
+
+static int minix_hash(struct dentry *dentry, struct qstr *qstr)
+{
+       unsigned long hash;
+       int i;
+       const char *name;
+
+       i = dentry->d_inode->i_sb->u.minix_sb.s_namelen;
+       if (i >= qstr->len)
+               return 0;
+       /* Truncate the name in place, avoids having to define a compare
+          function. */
+       qstr->len = i;
+       name = qstr->name;
+       hash = init_name_hash();
+       while (i--)
+               hash = partial_name_hash(*name++, hash);
+       qstr->hash = end_name_hash(hash);
+       return 0;
+}
+
+#endif
+
+struct dentry_operations minix_dentry_operations = {
+       0,              /* revalidate */
+#ifndef NO_TRUNCATE
+       minix_hash,
+#else
+       0,
+#endif
+       0               /* compare */
+};
+
 int minix_lookup(struct inode * dir, struct dentry *dentry)
 {
        struct inode * inode = NULL;
        struct minix_dir_entry * de;
        struct buffer_head * bh;
 
+#ifndef NO_TRUNCATE
+       dentry->d_op = &minix_dentry_operations;
+#endif
        bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
        if (bh) {
                int ino = de->inode;
@@ -296,7 +314,7 @@ int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
                brelse(bh);
                return -EEXIST;
        }
-       if (dir->i_nlink >= MINIX_LINK_MAX)
+       if (dir->i_nlink >= info->s_link_max)
                return -EMLINK;
        inode = minix_new_inode(dir);
        if (!inode)
@@ -434,7 +452,7 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry)
                retval = -ENOENT;
                goto end_rmdir;
        }
-       if (inode->i_count > 1) {
+       if (dentry->d_count > 1) {
                retval = -EBUSY;
                goto end_rmdir;
        }
@@ -573,7 +591,7 @@ int minix_link(struct dentry * old_dentry, struct inode * dir,
        if (S_ISDIR(inode->i_mode))
                return -EPERM;
 
-       if (inode->i_nlink >= MINIX_LINK_MAX)
+       if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max)
                return -EMLINK;
 
        bh = minix_find_entry(dir, dentry->d_name.name,
@@ -689,7 +707,7 @@ start_up:
                if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
                        goto end_rename;
                retval = -EMLINK;
-               if (!new_inode && new_dir->i_nlink >= MINIX_LINK_MAX)
+               if (!new_inode && new_dir->i_nlink >= info->s_link_max)
                        goto end_rename;
        }
        if (!new_bh) {
index 77a158612e42e8fa514a95717b8c4282b6910fe1..220ae0bd26a6303f7792a3631ca92ef3d9bc1d64 100644 (file)
@@ -180,10 +180,8 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
 
 /*
  * CREATE processing is complicated. The keyword here is `overloaded.'
- * There's a small race condition here between the check for existence
- * and the actual create() call, but one could even consider this a
- * feature because this only happens if someone else creates the file
- * at the same time.
+ * The parent directory is kept locked between the check for existence
+ * and the actual create() call in compliance with VFS protocols.
  * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
  */
 static int
@@ -193,15 +191,14 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
        svc_fh          *dirfhp = &argp->fh;
        svc_fh          *newfhp = &resp->fh;
        struct iattr    *attr = &argp->attrs;
-       struct inode    *inode = NULL;
-       int             nfserr, type, mode;
-       int             rdonly = 0, exists;
+       struct inode    *inode;
+       int             nfserr, type, mode, rdonly = 0;
        dev_t           rdev = NODEV;
 
        dprintk("nfsd: CREATE   %d/%ld %s\n",
                SVCFH_DEV(dirfhp), SVCFH_INO(dirfhp), argp->name);
 
-       /* Get the directory inode */
+       /* First verify the parent filehandle */
        nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
        if (nfserr)
                goto done; /* must fh_put dirfhp even on error */
@@ -214,18 +211,32 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
        } else if (nfserr)
                goto done;
 
-       /* First, check if the file already exists.  */
-       exists = !nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp);
-
-       if (newfhp->fh_dverified)
-               inode = newfhp->fh_dentry->d_inode;
+       /*
+        * Do a lookup to verify the new filehandle.
+        */
+       nfserr = nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp);
+       if (nfserr) {
+               if (nfserr != nfserr_noent)
+                       goto done;
+               /*
+                * If the new filehandle wasn't verified, we can't tell
+                * whether the file exists or not. Time to bail ...
+                */
+               nfserr = nfserr_acces;
+               if (!newfhp->fh_dverified) {
+                       printk(KERN_WARNING 
+                               "nfsd_proc_create: filehandle not verified\n");
+                       goto done;
+               }
+       }
 
-       /* Get rid of this soon... */
-       if (exists && !inode) {
-               printk("nfsd_proc_create: Wheee... exists but d_inode==NULL\n");
-               nfserr = nfserr_rofs;
+       /*
+        * Lock the parent directory and check for existence.
+        */
+       nfserr = fh_lock_parent(dirfhp, newfhp->fh_dentry);
+       if (nfserr)
                goto done;
-       }               
+       inode = newfhp->fh_dentry->d_inode;
 
        /* Unfudge the mode bits */
        if (attr->ia_valid & ATTR_MODE) { 
@@ -233,7 +244,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
                mode = attr->ia_mode & ~S_IFMT;
                if (!type)      /* HP weirdness */
                        type = S_IFREG;
-       } else if (exists) {
+       } else if (inode) {
                type = inode->i_mode & S_IFMT;
                mode = inode->i_mode & ~S_IFMT;
        } else {
@@ -243,8 +254,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
 
        /* This is for "echo > /dev/null" a la SunOS. Argh. */
        nfserr = nfserr_rofs;
-       if (rdonly && (!exists || type == S_IFREG))
-               goto done;
+       if (rdonly && (!inode || type == S_IFREG))
+               goto out_unlock;
 
        attr->ia_valid |= ATTR_MODE;
        attr->ia_mode = type | mode;
@@ -252,7 +263,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
        /* Special treatment for non-regular files according to the
         * gospel of sun micro
         */
-       nfserr = 0;
        if (type != S_IFREG) {
                int     is_borc = 0;
                u32     size = attr->ia_size;
@@ -267,21 +277,21 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
                } else if (size != rdev) {
                        /* dev got truncated because of 16bit Linux dev_t */
                        nfserr = nfserr_io;     /* or nfserr_inval? */
-                       goto done;
+                       goto out_unlock;
                } else {
                        /* Okay, char or block special */
                        is_borc = 1;
                }
 
                /* Make sure the type and device matches */
-               if (exists && (type != (inode->i_mode & S_IFMT)
-                || (is_borc && inode->i_rdev != rdev))) {
-                       nfserr = nfserr_exist;
-                       goto done;
-               }
+               nfserr = nfserr_exist;
+               if (inode && (type != (inode->i_mode & S_IFMT) || 
+                   (is_borc && inode->i_rdev != rdev)))
+                       goto out_unlock;
        }
        
-       if (!exists) {
+       nfserr = 0;
+       if (!inode) {
                /* File doesn't exist. Create it and set attrs */
                nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
                                        attr, type, rdev, newfhp);
@@ -297,6 +307,10 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
                        nfserr = nfsd_setattr(rqstp, newfhp, attr);
        }
 
+out_unlock:
+       /* We don't really need to unlock, as fh_put does it. */
+       fh_unlock(dirfhp);
+
 done:
        fh_put(dirfhp);
        RETURN(nfserr);
@@ -359,9 +373,9 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
        int             nfserr;
 
        dprintk("nfsd: SYMLINK  %p %s -> %s\n",
-               SVCFH_DENTRY(&argp->ffh),
-               argp->fname, argp->tname);
+               SVCFH_DENTRY(&argp->ffh), argp->fname, argp->tname);
 
+       memset(&newfh, 0, sizeof(struct svc_fh));
        /*
         * Create the link, look up new file and set attrs.
         */
@@ -386,12 +400,13 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
 {
        int     nfserr;
 
-       dprintk("nfsd: MKDIR    %p %s\n",
-               SVCFH_DENTRY(&argp->fh),
-               argp->name);
+       dprintk("nfsd: MKDIR    %p %s\n", SVCFH_DENTRY(&argp->fh), argp->name);
+
+       if (resp->fh.fh_dverified) {
+               printk(KERN_WARNING
+                       "nfsd_proc_mkdir: response already verified??\n");
+       }
 
-       /* N.B. what about the dentry count?? */
-       resp->fh.fh_dverified = 0; /* paranoia */
        nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
                                    &argp->attrs, S_IFDIR, 0, &resp->fh);
        fh_put(&argp->fh);
index 1fba9508fe822d4b0623e364cf6b0302c0cee423..514316b04b3522220f889535df68819066d4c0d6 100644 (file)
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/nfsfh.h>
 #include <linux/quotaops.h>
 
 #if LINUX_VERSION_CODE >= 0x020100
 #include <asm/uaccess.h>
 #endif
 
-extern void fh_update(struct svc_fh*);
-
 #define NFSDDBG_FACILITY               NFSDDBG_FILEOP
 
 /* Open mode for nfsd_open */
@@ -76,6 +75,41 @@ struct raparms {
 static struct raparms          raparms[FILECACHE_MAX];
 static struct raparms *                raparm_cache = 0;
 
+/*
+ * Lock a parent directory following the VFS locking protocol.
+ */
+int
+fh_lock_parent(struct svc_fh *parent_fh, struct dentry *dchild)
+{
+       int     nfserr = 0;
+
+       fh_lock(parent_fh);
+       /*
+        * Make sure the parent->child relationship still holds,
+        * and that the child is still hashed.
+        */
+       if (dchild->d_parent != parent_fh->fh_dentry) 
+               goto out_not_parent;
+       if (list_empty(&dchild->d_hash))
+               goto out_not_hashed; 
+out:
+       return nfserr;
+
+out_not_parent:
+       printk(KERN_WARNING
+               "fh_lock_parent: %s/%s parent changed\n",
+               dchild->d_parent->d_name.name, dchild->d_name.name);
+       goto out_unlock;
+out_not_hashed:
+       printk(KERN_WARNING
+               "fh_lock_parent: %s/%s unhashed\n",
+               dchild->d_parent->d_name.name, dchild->d_name.name);
+out_unlock:
+       nfserr = nfserr_noent;
+       fh_unlock(parent_fh);
+       goto out;
+}
+
 /*
  * Deny access to certain file systems
  */
@@ -546,8 +580,11 @@ out:
 }
 
 /*
- * Create a file (regular, directory, device, fifo).
- * UNIX sockets not yet implemented.
+ * Create a file (regular, directory, device, fifo); UNIX sockets 
+ * not yet implemented.
+ * If the response fh has been verified, the parent directory should
+ * already be locked. Note that the parent directory is left locked.
+ *
  * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
  */
 int
@@ -557,13 +594,12 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
 {
        struct dentry   *dentry, *dchild;
        struct inode    *dirp;
+       nfsd_dirop_t    opfunc = NULL;
        int             err;
 
        err = nfserr_perm;
        if (!flen)
                goto out;
-       if (!(iap->ia_valid & ATTR_MODE))
-               iap->ia_mode = 0;
        err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
        if (err)
                goto out;
@@ -571,64 +607,74 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        dentry = fhp->fh_dentry;
        dirp = dentry->d_inode;
 
-       /* Get all the sanity checks out of the way before we lock the parent. */
        err = nfserr_notdir;
        if(!dirp->i_op || !dirp->i_op->lookup)
                goto out;
-       err = nfserr_perm;
-       if (type == S_IFREG) {
-               if(!dirp->i_op->create)
-                       goto out;
-       } else if(type == S_IFDIR) {
-               if(!dirp->i_op->mkdir)
-                       goto out;
-       } else if((type == S_IFCHR) || (type == S_IFBLK) || (type == S_IFIFO)) {
-               if(!dirp->i_op->mknod)
-                       goto out;
-       } else {
-               goto out;
-       }
-
        /*
-        * The response filehandle may have been setup already ...
+        * Check whether the response filehandle has been verified yet.
+        * If it has, the parent directory should already be locked.
         */
        if (!resfhp->fh_dverified) {
                dchild = lookup_dentry(fname, dget(dentry), 0);
                err = PTR_ERR(dchild);
-               if(IS_ERR(dchild))
+               if (IS_ERR(dchild))
                        goto out_nfserr;
                fh_compose(resfhp, fhp->fh_export, dchild);
-       } else
+               /* Lock the parent and check for errors ... */
+               err = fh_lock_parent(fhp, dchild);
+               if (err)
+                       goto out;
+       } else {
                dchild = resfhp->fh_dentry;
+               if (!fhp->fh_locked)
+                       printk(KERN_ERR
+                               "nfsd_create: parent %s/%s not locked!\n",
+                               dentry->d_parent->d_name.name,
+                               dentry->d_name.name);
+       }
        /*
         * Make sure the child dentry is still negative ...
         */
+       err = nfserr_exist;
        if (dchild->d_inode) {
-               printk("nfsd_create: dentry %s/%s not negative!\n",
-                       dentry->d_parent->d_name.name, dentry->d_name.name);
+               printk(KERN_WARNING
+                       "nfsd_create: dentry %s/%s not negative!\n",
+                       dentry->d_name.name, dchild->d_name.name);
+               goto out; 
        }
 
-       /* Looks good, lock the directory. */
-       fh_lock(fhp);
-       DQUOT_INIT(dirp);
+       /*
+        * Get the dir op function pointer.
+        */
+       err = nfserr_perm;
        switch (type) {
        case S_IFREG:
-               err = dirp->i_op->create(dirp, dchild, iap->ia_mode);
+               opfunc = (nfsd_dirop_t) dirp->i_op->create;
                break;
        case S_IFDIR:
-               err = dirp->i_op->mkdir(dirp, dchild, iap->ia_mode);
+               opfunc = (nfsd_dirop_t) dirp->i_op->mkdir;
                break;
        case S_IFCHR:
        case S_IFBLK:
        case S_IFIFO:
-               err = dirp->i_op->mknod(dirp, dchild, iap->ia_mode, rdev);
+               opfunc = dirp->i_op->mknod;
                break;
        }
-       DQUOT_DROP(dirp);
-       fh_unlock(fhp);
+       if (!opfunc)
+               goto out;
 
+       if (!(iap->ia_valid & ATTR_MODE))
+               iap->ia_mode = 0;
+
+       /*
+        * Call the dir op function to create the object.
+        */
+       DQUOT_INIT(dirp);
+       err = opfunc(dirp, dchild, iap->ia_mode, rdev);
+       DQUOT_DROP(dirp);
        if (err < 0)
                goto out_nfserr;
+
        if (EX_ISSYNC(fhp->fh_export))
                write_inode_now(dirp);
 
@@ -778,21 +824,29 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (IS_ERR(dnew))
                goto out_nfserr;
 
-       err = -EEXIST;
+       /*
+        * Lock the parent before checking for existence
+        */
+       err = fh_lock_parent(fhp, dnew);
+       if (err)
+               goto out_compose;
+
+       err = nfserr_exist;
        if (!dnew->d_inode) {
-               fh_lock(fhp);
                DQUOT_INIT(dirp);
                err = dirp->i_op->symlink(dirp, dnew, path);
                DQUOT_DROP(dirp);
-               fh_unlock(fhp);
                if (!err) {
                        if (EX_ISSYNC(fhp->fh_export))
                                write_inode_now(dirp);
-               }
+               } else
+                       err = nfserrno(-err);
        }
+       fh_unlock(fhp);
+
+       /* Compose the fh so the dentry will be freed ... */
+out_compose:
        fh_compose(resfhp, fhp->fh_export, dnew);
-       if (err)
-               goto out_nfserr;
 out:
        return err;
 
@@ -820,6 +874,10 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
        if (err)
                goto out;
 
+       err = nfserr_perm;
+       if (!len)
+               goto out;
+
        ddir = ffhp->fh_dentry;
        dirp = ddir->d_inode;
 
@@ -827,44 +885,48 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
        err = PTR_ERR(dnew);
        if (IS_ERR(dnew))
                goto out_nfserr;
+       /*
+        * Lock the parent before checking for existence
+        */
+       err = fh_lock_parent(ffhp, dnew);
+       if (err)
+               goto out_dput;
 
-       err = -EEXIST;
+       err = nfserr_exist;
        if (dnew->d_inode)
-               goto dput_and_out;
-
-       err = -EPERM;
-       if (!len)
-               goto dput_and_out;
+               goto out_unlock;
 
        dold = tfhp->fh_dentry;
        dest = dold->d_inode;
 
-       err = -EACCES;
+       err = nfserr_acces;
        if (nfsd_iscovered(ddir, ffhp->fh_export))
-               goto dput_and_out;
+               goto out_unlock;
+       /* FIXME: nxdev for NFSv3 */
        if (dirp->i_dev != dest->i_dev)
-               goto dput_and_out;      /* FIXME: nxdev for NFSv3 */
+               goto out_unlock;
 
-       err = -EPERM;
+       err = nfserr_perm;
        if (IS_IMMUTABLE(dest) /* || IS_APPEND(dest) */ )
-               goto dput_and_out;
+               goto out_unlock;
        if (!dirp->i_op || !dirp->i_op->link)
-               goto dput_and_out;
+               goto out_unlock;
 
-       fh_lock(ffhp);
        DQUOT_INIT(dirp);
        err = dirp->i_op->link(dold, dirp, dnew);
        DQUOT_DROP(dirp);
-       fh_unlock(ffhp);
+       if (!err) {
+               if (EX_ISSYNC(ffhp->fh_export)) {
+                       write_inode_now(dirp);
+                       write_inode_now(dest);
+               }
+       } else
+               err = nfserrno(-err);
 
-       if (!err && EX_ISSYNC(ffhp->fh_export)) {
-               write_inode_now(dirp);
-               write_inode_now(dest);
-       }
-dput_and_out:
+out_unlock:
+       fh_unlock(ffhp);
+out_dput:
        dput(dnew);
-       if (err)
-               goto out_nfserr;
 out:
        return err;
 
@@ -1005,7 +1067,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        if (IS_ERR(rdentry))
                goto out_nfserr;
 
-       fh_lock(fhp);
+       err = fh_lock_parent(fhp, rdentry);
+       if (err)
+               goto out;
+
        DQUOT_INIT(dirp);
        if (type == S_IFDIR) {
                err = -ENOTDIR;
index 9428dc944c60ae0d8e01bad9f8eba2e1c2f6c097..b6e6674265900a04f6a1e81310d4d1f448fc44d4 100644 (file)
@@ -544,6 +544,23 @@ static unsigned long get_wchan(struct task_struct *p)
        }
 #elif defined(__powerpc__)
        return (p->tss.wchan);
+#elif defined (CONFIG_ARM)
+       {
+               unsigned long fp, lr;
+               unsigned long stack_page;
+               int count = 0;
+
+               stack_page = 4096 + (unsigned long)p;
+               fp = get_css_fp (&p->tss);
+               do {
+                       if (fp < stack_page || fp > 4092+stack_page)
+                               return 0;
+                       lr = pc_pointer (((unsigned long *)fp)[-1]);
+                       if (lr < first_sched || lr > last_sched)
+                               return lr;
+                       fp = *(unsigned long *) (fp - 12);
+               } while (count ++ < 16);
+       }
 #endif
        return 0;
 }
@@ -560,6 +577,9 @@ static unsigned long get_wchan(struct task_struct *p)
 # define KSTK_EIP(tsk) \
     (*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
 # define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(CONFIG_ARM)
+# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
+# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
 #elif defined(__mc68000__)
 #define        KSTK_EIP(tsk)   \
     ({                 \
@@ -707,21 +727,6 @@ static inline char * task_mem(struct task_struct *p, char *buffer)
        return buffer;
 }
 
-char * render_sigset_t(sigset_t *set, char *buffer)
-{
-       int i = _NSIG, x;
-       do {
-               i -= 4, x = 0;
-               if (sigismember(set, i+1)) x |= 1;
-               if (sigismember(set, i+2)) x |= 2;
-               if (sigismember(set, i+3)) x |= 4;
-               if (sigismember(set, i+4)) x |= 8;
-               *buffer++ = (x < 10 ? '0' : 'a' - 10) + x;
-       } while (i >= 4);
-       *buffer = 0;
-       return buffer;
-}
-
 static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
                                    sigset_t *catch)
 {
index 0e17b3e1d58927c2e1592561453d102490edece5..7ff34acb16faf9ee71bb2d4bf9dc9db11a589c39 100644 (file)
@@ -282,7 +282,7 @@ romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        /* Not really failsafe, but we are read-only... */
        for(;;) {
                if (!offset || offset >= maxoff) {
-                       offset = 0xffffffff;
+                       offset = maxoff;
                        filp->f_pos = offset;
                        return stored;
                }
index 70c857af79c82bd663481b3c5b842dd77d32da26..664b166dd56342bfc788ef1fdd99938d2f0ad96a 100644 (file)
@@ -182,6 +182,24 @@ extern inline unsigned long ffz(unsigned long word)
        return qofs*8 + bofs;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
 /*
  * Find next zero bit in a bitmap reasonably efficiently..
  */
index 3467e61033a69277f3cbb950095d0bcb5d752881..e275fd98039e80dbbe4d515f7b69bcbe2df4d9d7 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/config.h>
 
 #include <asm/system.h>
+#include <asm/processor.h>     /* For TASK_SIZE */
 #include <asm/mmu_context.h>
 
 /* Caches aren't brain-dead on the alpha. */
@@ -181,6 +182,7 @@ extern void flush_tlb_range(struct mm_struct *, unsigned long, unsigned long);
 #define PTRS_PER_PTE   (1UL << (PAGE_SHIFT-3))
 #define PTRS_PER_PMD   (1UL << (PAGE_SHIFT-3))
 #define PTRS_PER_PGD   ((1UL << (PAGE_SHIFT-3))-1)
+#define USER_PTRS_PER_PGD      (TASK_SIZE / PGDIR_SIZE)
 
 /* the no. of pointers that fit on a page: this will go away */
 #define PTRS_PER_PAGE  (1UL << (PAGE_SHIFT-3))
@@ -401,126 +403,174 @@ extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
  * used to allocate a kernel page table - this turns on ASN bits
  * if any.
  */
-extern inline void pte_free_kernel(pte_t * pte)
+#ifndef __SMP__
+extern struct pgtable_cache_struct {
+       unsigned long *pgd_cache;
+       unsigned long *pte_cache;
+       unsigned long pgtable_cache_sz;
+} quicklists;
+#else
+#include <asm/smp.h>
+#define quicklists cpu_data[smp_processor_id()]
+#endif
+#define pgd_quicklist (quicklists.pgd_cache)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (quicklists.pte_cache)
+#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+
+extern __inline__ pgd_t *get_pgd_slow(void)
 {
-       free_page((unsigned long) pte);
+       pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init;
+       
+       if (ret) {
+               init = pgd_offset(&init_mm, 0);
+               memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+               memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+                       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+       }
+       return ret;
 }
 
-extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+extern __inline__ pgd_t *get_pgd_fast(void)
 {
-       address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-       if (pmd_none(*pmd)) {
-               pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
-               if (pmd_none(*pmd)) {
-                       if (page) {
-                               pmd_set(pmd, page);
-                               return page + address;
-                       }
-                       pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-                       return NULL;
-               }
-               free_page((unsigned long) page);
-       }
-       if (pmd_bad(*pmd)) {
-               printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-               pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-               return NULL;
-       }
-       return (pte_t *) pmd_page(*pmd) + address;
+       unsigned long *ret;
+
+       if((ret = pgd_quicklist) != NULL) {
+               pgd_quicklist = (unsigned long *)(*ret);
+               ret[0] = ret[1];
+               pgtable_cache_size--;
+       } else
+               ret = (unsigned long *)get_pgd_slow();
+       return (pgd_t *)ret;
 }
 
-extern inline void pmd_free_kernel(pmd_t * pmd)
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
 {
-       free_page((unsigned long) pmd);
+       *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+       pgd_quicklist = (unsigned long *) pgd;
+       pgtable_cache_size++;
 }
 
-extern inline pmd_t * pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
 {
-       address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-       if (pgd_none(*pgd)) {
-               pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
-               if (pgd_none(*pgd)) {
-                       if (page) {
-                               pgd_set(pgd, page);
-                               return page + address;
-                       }
-                       pgd_set(pgd, BAD_PAGETABLE);
-                       return NULL;
-               }
-               free_page((unsigned long) page);
+       free_page((unsigned long)pgd);
+}
+
+extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
+
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+       unsigned long *ret;
+
+       if((ret = (unsigned long *)pte_quicklist) != NULL) {
+               pte_quicklist = (unsigned long *)(*ret);
+               ret[0] = ret[1];
+               pgtable_cache_size--;
        }
-       if (pgd_bad(*pgd)) {
-               printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-               pgd_set(pgd, BAD_PAGETABLE);
-               return NULL;
+       return (pmd_t *)ret;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+       *(unsigned long *)pmd = (unsigned long) pte_quicklist;
+       pte_quicklist = (unsigned long *) pmd;
+       pgtable_cache_size++;
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+       free_page((unsigned long)pmd);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+       unsigned long *ret;
+
+       if((ret = (unsigned long *)pte_quicklist) != NULL) {
+               pte_quicklist = (unsigned long *)(*ret);
+               ret[0] = ret[1];
+               pgtable_cache_size--;
        }
-       return (pmd_t *) pgd_page(*pgd) + address;
+       return (pte_t *)ret;
 }
 
-extern inline void pte_free(pte_t * pte)
+extern __inline__ void free_pte_fast(pte_t *pte)
 {
-       free_page((unsigned long) pte);
+       *(unsigned long *)pte = (unsigned long) pte_quicklist;
+       pte_quicklist = (unsigned long *) pte;
+       pgtable_cache_size++;
 }
 
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+       free_page((unsigned long)pte);
+}
+
+extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pmd(pgd_t *pgd);
+
+#define pte_free_kernel(pte)   free_pte_fast(pte)
+#define pte_free(pte)          free_pte_fast(pte)
+#define pmd_free_kernel(pmd)   free_pmd_fast(pmd)
+#define pmd_free(pmd)          free_pmd_fast(pmd)
+#define pgd_free(pgd)          free_pgd_fast(pgd)
+#define pgd_alloc()            get_pgd_fast()
+
 extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
 {
        address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
        if (pmd_none(*pmd)) {
-               pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
-               if (pmd_none(*pmd)) {
-                       if (page) {
-                               pmd_set(pmd, page);
-                               return page + address;
-                       }
-                       pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-                       return NULL;
-               }
-               free_page((unsigned long) page);
+               pte_t *page = get_pte_fast();
+               
+               if (!page)
+                       return get_pte_slow(pmd, address);
+               pmd_set(pmd, page);
+               return page + address;
        }
        if (pmd_bad(*pmd)) {
-               printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-               pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+               __bad_pte(pmd);
                return NULL;
        }
        return (pte_t *) pmd_page(*pmd) + address;
 }
 
-extern inline void pmd_free(pmd_t * pmd)
-{
-       free_page((unsigned long) pmd);
-}
-
 extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
 {
        address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
        if (pgd_none(*pgd)) {
-               pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
-               if (pgd_none(*pgd)) {
-                       if (page) {
-                               pgd_set(pgd, page);
-                               return page + address;
-                       }
-                       pgd_set(pgd, BAD_PAGETABLE);
-                       return NULL;
-               }
-               free_page((unsigned long) page);
+               pmd_t *page = get_pmd_fast();
+               
+               if (!page)
+                       return get_pmd_slow(pgd, address);
+               pgd_set(pgd, page);
+               return page + address;
        }
        if (pgd_bad(*pgd)) {
-               printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-               pgd_set(pgd, BAD_PAGETABLE);
+               __bad_pmd(pgd);
                return NULL;
        }
        return (pmd_t *) pgd_page(*pgd) + address;
 }
 
-extern inline void pgd_free(pgd_t * pgd)
-{
-       free_page((unsigned long) pgd);
-}
+#define pte_alloc_kernel       pte_alloc
+#define pmd_alloc_kernel       pmd_alloc
 
-extern inline pgd_t * pgd_alloc(void)
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
 {
-       return (pgd_t *) get_free_page(GFP_KERNEL);
+       struct task_struct * p;
+       pgd_t *pgd;
+        
+       read_lock(&tasklist_lock);
+       for_each_task(p) {
+               if (!p->mm)
+                       continue;
+               *pgd_offset(p->mm,address) = entry;
+       }
+       read_unlock(&tasklist_lock);
+       for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+               pgd[(address >> PGDIR_SHIFT) & (PTRS_PER_PAGE - 1)] = entry;
 }
 
 extern pgd_t swapper_pg_dir[1024];
index 811abc297cf2799877b2f1c804e51dbf8583762f..12ccebba25dfd32ef3839ff50636fd01fdf8aa2d 100644 (file)
@@ -10,6 +10,9 @@
 struct cpuinfo_alpha {
        unsigned long loops_per_sec;
        unsigned int next;
+       unsigned long *pgd_cache;
+       unsigned long *pte_cache;
+       unsigned long pgtable_cache_sz;
 };
 
 extern struct cpuinfo_alpha cpu_data[NR_CPUS];
diff --git a/include/asm-arm/arch-a5k/a.out.h b/include/asm-arm/arch-a5k/a.out.h
deleted file mode 100644 (file)
index 0653407..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/a.out.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#ifdef __KERNEL__
-#define STACK_TOP              (0x01a00000)
-#define LIBRARY_START_TEXT     (0x00c00000)
-#endif
-
-#endif
-
diff --git a/include/asm-arm/arch-a5k/dma.h b/include/asm-arm/arch-a5k/dma.h
deleted file mode 100644 (file)
index 9acb5c1..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#define MAX_DMA_ADDRESS                0x03000000
-
-#ifdef KERNEL_ARCH_DMA
-
-static inline void arch_disable_dma (int dmanr)
-{
-    printk (dma_str, "arch_disable_dma", dmanr);
-}
-
-static inline void arch_enable_dma (int dmanr)
-{
-    printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
-    printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
-    printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
-    printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-    printk (dma_str, "arch_dma_count", dmanr);
-    return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    switch(dmanr) {
-       case 2:  disable_irq(64); break;
-       default: printk (dma_str, "disable_dma", dmanr); break;
-    }
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-    switch(dmanr) {
-       case 2:  break;
-       default: printk (dma_str, "clear_dma_ff", dmanr); break;
-    }
-}
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
- */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
-
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
-
-/* Set transfer size for a specific DMA channel.
- */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
-
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
-
-#endif /* _ASM_ARCH_DMA_H */
-
diff --git a/include/asm-arm/arch-a5k/hardware.h b/include/asm-arm/arch-a5k/hardware.h
deleted file mode 100644 (file)
index 317b4c6..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/hardware.h
- *
- * Copyright (C) 1996 Russell King.
- *
- * This file contains the hardware definitions of the A5000 series machines.
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/*
- * What hardware must be present
- */
-#define HAS_IOC
-#define HAS_PCIO
-#define HAS_MEMC
-#define HAS_MEMC1A
-#define HAS_VIDC
-
-/*
- * Optional hardware
- */
-#define HAS_EXPMASK
-
-#ifndef __ASSEMBLER__
-
-/*
- * for use with inb/outb
- */
-#define VIDC_BASE              0x80100000
-#define IOCEC4IO_BASE          0x8009c000
-#define IOCECIO_BASE           0x80090000
-#define IOC_BASE               0x80080000
-#define MEMCECIO_BASE          0x80000000
-
-/*
- * IO definitions
- */
-#define EXPMASK_BASE           ((volatile unsigned char *)0x03360000)
-#define IOEB_BASE              ((volatile unsigned char *)0x03350050)
-#define PCIO_FLOPPYDMABASE     ((volatile unsigned char *)0x0302a000)
-#define PCIO_BASE              0x03010000
-
-/*
- * Mapping areas
- */
-#define IO_END                 0x03ffffff
-#define IO_BASE                        0x03000000
-#define IO_SIZE                        (IO_END - IO_BASE)
-#define IO_START               0x03000000
-
-/*
- * Screen mapping information
- */
-#define SCREEN2_END            0x02078000
-#define SCREEN2_BASE           0x02000000
-#define SCREEN1_END            SCREEN2_BASE
-#define SCREEN1_BASE           0x01f88000
-#define SCREEN_START           0x02000000
-
-/*
- * RAM definitions
- */
-#define MAPTOPHYS(a)           (((unsigned long)a & 0x007fffff) + PAGE_OFFSET)
-#define KERNTOPHYS(a)          ((((unsigned long)(&a)) & 0x007fffff) + PAGE_OFFSET)
-#define GET_MEMORY_END(p)      (PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages))
-#define PARAMS_BASE            (PAGE_OFFSET + 0x7c000)
-#define KERNEL_BASE            (PAGE_OFFSET + 0x80000)
-
-#else
-
-#define IOEB_BASE              0x03350050
-#define IOC_BASE               0x03200000
-#define PCIO_FLOPPYDMABASE     0x0302a000
-#define PCIO_BASE              0x03010000
-#define IO_BASE                        0x03000000
-
-#endif
-#endif
-
diff --git a/include/asm-arm/arch-a5k/ide.h b/include/asm-arm/arch-a5k/ide.h
deleted file mode 100644 (file)
index 3beb3c3..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/ide.h
- *
- * Copyright (c) 1997 Russell King
- */
-
-static __inline__ int
-ide_default_irq(ide_ioreg_t base)
-{
-       if (base == 0x1f0)
-               return 11;
-       return 0;
-}
-
-static __inline__ ide_ioreg_t
-ide_default_io_base(int index)
-{
-       if (index == 0)
-               return 0x1f0;
-       return 0;
-}
-
-static __inline__ int
-ide_default_stepping(int index)
-{
-       return 0;
-}
-
-static __inline__ void
-ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int stepping, int *irq)
-{
-       ide_ioreg_t port = base;
-       ide_ioreg_t ctrl = base + 0x206;
-       int i;
-
-       i = 8;
-       while (i--) {
-               *p++ = port;
-               port += 1 << stepping;
-       }
-       *p++ = ctrl;
-       if (irq != NULL)
-               irq = 0;
-}
diff --git a/include/asm-arm/arch-a5k/io.h b/include/asm-arm/arch-a5k/io.h
deleted file mode 100644 (file)
index b305c7d..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/io.h
- *
- * Copyright (C) 1997 Russell King
- *
- * Modifications:
- *  06-Dec-1997        RMK     Created.
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define virt_to_bus(x) ((unsigned long)(x))
-#define bus_to_virt(x) ((void *)(x))
-
-/*
- * This architecture does not require any delayed IO, and
- * has the constant-optimised IO
- */
-#undef ARCH_IO_DELAY
-
-/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses.  PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1.  ARM addresses are 0x80000000+
- * and are translated to the start of IO.  Note that all addresses are
- * shifted left!
- */
-#define __PORT_PCIO(x) (!((x) & 0x80000000))
-
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-extern __inline__ void __outb (unsigned int value, unsigned int port)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "tst    %2, #0x80000000\n\t"
-       "mov    %0, %4\n\t"
-       "addeq  %0, %0, %3\n\t"
-       "strb   %1, [%0, %2, lsl #2]"
-       : "=&r" (temp)
-       : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-       : "cc");
-}
-
-extern __inline__ void __outw (unsigned int value, unsigned int port)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "tst    %2, #0x80000000\n\t"
-       "mov    %0, %4\n\t"
-       "addeq  %0, %0, %3\n\t"
-       "str    %1, [%0, %2, lsl #2]"
-       : "=&r" (temp)
-       : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-       : "cc");
-}
-
-extern __inline__ void __outl (unsigned int value, unsigned int port)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "tst    %2, #0x80000000\n\t"
-       "mov    %0, %4\n\t"
-       "addeq  %0, %0, %3\n\t"
-       "str    %1, [%0, %2, lsl #2]"
-       : "=&r" (temp)
-       : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-       : "cc");
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr)                                      \
-extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)               \
-{                                                                              \
-       unsigned long temp, value;                                              \
-       __asm__ __volatile__(                                                   \
-       "tst    %2, #0x80000000\n\t"                                            \
-       "mov    %0, %4\n\t"                                                     \
-       "addeq  %0, %0, %3\n\t"                                                 \
-       "ldr" ##instr## "       %1, [%0, %2, lsl #2]"                           \
-       : "=&r" (temp), "=r" (value)                                            \
-       : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)                \
-       : "cc");                                                                \
-       return (unsigned sz)value;                                              \
-}
-
-extern __inline__ unsigned int __ioaddr (unsigned int port)                    \
-{                                                                              \
-       if (__PORT_PCIO(port))                                                  \
-               return (unsigned int)(PCIO_BASE + (port << 2));                 \
-       else                                                                    \
-               return (unsigned int)(IO_BASE + (port << 2));                   \
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr)  \
-       DECLARE_DYN_IN(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"")
-DECLARE_IO(long,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port)                                                    \
-({                                                                             \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "strb   %0, [%1, %2]"                                           \
-               : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2));          \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "strb   %0, [%1, %2]"                                           \
-               : : "r" (value), "r" (IO_BASE), "r" ((port) << 2));             \
-})
-
-#define __inbc(port)                                                           \
-({                                                                             \
-       unsigned char result;                                                   \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "ldrb   %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "ldrb   %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
-       result;                                                                 \
-})
-
-#define __outwc(value,port)                                                    \
-({                                                                             \
-       unsigned long v = value;                                                \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "str    %0, [%1, %2]"                                           \
-               : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2));        \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "str    %0, [%1, %2]"                                           \
-               : : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2));           \
-})
-
-#define __inwc(port)                                                           \
-({                                                                             \
-       unsigned short result;                                                  \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
-       result & 0xffff;                                                        \
-})
-
-#define __outlc(v,p) __outwc((v),(p))
-
-#define __inlc(port)                                                           \
-({                                                                             \
-       unsigned long result;                                                   \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]"                                           \
-               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
-       result;                                                                 \
-})
-
-#define __ioaddrc(port)                                                                \
-({                                                                             \
-       unsigned long addr;                                                     \
-       if (__PORT_PCIO((port)))                                                \
-               addr = PCIO_BASE + ((port) << 2);                               \
-       else                                                                    \
-               addr = IO_BASE + ((port) << 2);                                 \
-       addr;                                                                   \
-})
-
-/*
- * Translated address IO functions
- *
- * IO address has already been translated to a virtual address
- */
-#define outb_t(v,p)                                                            \
-       (*(volatile unsigned char *)(p) = (v))
-
-#define inb_t(p)                                                               \
-       (*(volatile unsigned char *)(p))
-
-#define outl_t(v,p)                                                            \
-       (*(volatile unsigned long *)(p) = (v))
-
-#define inl_t(p)                                                               \
-       (*(volatile unsigned long *)(p))
-
-#endif
diff --git a/include/asm-arm/arch-a5k/irq.h b/include/asm-arm/arch-a5k/irq.h
deleted file mode 100644 (file)
index 6c868d8..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * include/asm-arm/arch-a5k/irq.h
- *
- * Copyright (C) 1996 Russell King
- *
- * Changelog:
- *   24-09-1996        RMK     Created
- *   10-10-1996        RMK     Brought up to date with arch-sa110eval
- *   22-10-1996        RMK     Changed interrupt numbers & uses new inb/outb macros
- *   11-01-1998        RMK     Added mask_and_ack_irq
- */
-
-#define BUILD_IRQ(s,n,m) \
-       void IRQ##n##_interrupt(void); \
-       void fast_IRQ##n##_interrupt(void); \
-       void bad_IRQ##n##_interrupt(void); \
-       void probe_IRQ##n##_interrupt(void);
-
-/*
- * The timer is a special interrupt
- */
-#define IRQ5_interrupt         timer_IRQ_interrupt
-
-#define IRQ_INTERRUPT(n)       IRQ##n##_interrupt
-#define FAST_INTERRUPT(n)      fast_IRQ##n##_interrupt
-#define BAD_INTERRUPT(n)       bad_IRQ##n##_interrupt
-#define PROBE_INTERRUPT(n)     probe_IRQ##n##_interrupt
-                                
-#define X(x) (x)|0x01, (x)|0x02, (x)|0x04, (x)|0x08, (x)|0x10, (x)|0x20, (x)|0x40, (x)|0x80
-#define Z(x) (x), (x), (x), (x), (x), (x), (x), (x)
-
-static __inline__ void mask_and_ack_irq(unsigned int irq)
-{
-       static const int addrmasks[] = {
-               X((IOC_IRQMASKA - IOC_BASE)<<18 | (1 << 15)),
-               X((IOC_IRQMASKB - IOC_BASE)<<18),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               X((IOC_FIQMASK - IOC_BASE)<<18),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0),
-               Z(0)
-       };
-       unsigned int temp1, temp2;
-
-       __asm__ __volatile__(
-"      ldr     %1, [%5, %3, lsl #2]\n"
-"      teq     %1, #0\n"
-"      beq     2f\n"
-"      ldrb    %0, [%2, %1, lsr #16]\n"
-"      bic     %0, %0, %1\n"
-"      strb    %0, [%2, %1, lsr #16]\n"
-"      tst     %1, #0x8000\n"                  /* do we need an IRQ clear? */
-"      strneb  %1, [%2, %4]\n"
-"2:"
-       : "=&r" (temp1), "=&r" (temp2)
-       : "r" (ioaddr(IOC_BASE)), "r" (irq),
-         "I" ((IOC_IRQCLRA - IOC_BASE) << 2), "r" (addrmasks));
-}
-
-#undef X
-#undef Z
-
-static __inline__ void mask_irq(unsigned int irq)
-{
-       extern void ecard_disableirq (unsigned int);
-       extern void ecard_disablefiq (unsigned int);
-       unsigned char mask = 1 << (irq & 7);
-
-       switch (irq >> 3) {
-       case 0:
-               outb(inb(IOC_IRQMASKA) & ~mask, IOC_IRQMASKA);
-               break;
-       case 1:
-               outb(inb(IOC_IRQMASKB) & ~mask, IOC_IRQMASKB);
-               break;
-       case 4:
-               ecard_disableirq (irq & 7);
-               break;
-       case 8:
-               outb(inb(IOC_FIQMASK) & ~mask, IOC_FIQMASK);
-               break;
-       case 12:
-               ecard_disablefiq (irq & 7);
-       }
-}
-
-static __inline__ void unmask_irq(unsigned int irq)
-{
-       extern void ecard_enableirq (unsigned int);
-       extern void ecard_enablefiq (unsigned int);
-       unsigned char mask = 1 << (irq & 7);
-
-       switch (irq >> 3) {
-       case 0:
-               outb(inb(IOC_IRQMASKA) | mask, IOC_IRQMASKA);
-               break;
-       case 1:
-               outb(inb(IOC_IRQMASKB) | mask, IOC_IRQMASKB);
-               break;
-       case 4:
-               ecard_enableirq (irq & 7);
-               break;
-       case 8:
-               outb(inb(IOC_FIQMASK) | mask, IOC_FIQMASK);
-               break;
-       case 12:
-               ecard_enablefiq (irq & 7);
-       }
-}
-
-static __inline__ unsigned long get_enabled_irqs(void)
-{
-       return inb(IOC_IRQMASKA) | inb(IOC_IRQMASKB) << 8;
-}
-
-static __inline__ void irq_init_irq(void)
-{
-       outb(0, IOC_IRQMASKA);
-       outb(0, IOC_IRQMASKB);
-       outb(0, IOC_FIQMASK);
-}
diff --git a/include/asm-arm/arch-a5k/irqs.h b/include/asm-arm/arch-a5k/irqs.h
deleted file mode 100644 (file)
index b7188fb..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/irqs.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define IRQ_PRINTER            0
-#define IRQ_BATLOW             1
-#define IRQ_FLOPPYINDEX                2
-#define IRQ_VSYNCPULSE         3
-#define IRQ_POWERON            4
-#define IRQ_TIMER0             5
-#define IRQ_TIMER1             6
-#define IRQ_IMMEDIATE          7
-#define IRQ_EXPCARDFIQ         8
-#define IRQ_SOUNDCHANGE                9
-#define IRQ_SERIALPORT         10
-#define IRQ_HARDDISK           11
-#define IRQ_FLOPPYDISK         12
-#define IRQ_EXPANSIONCARD      13
-#define IRQ_KEYBOARDTX         14
-#define IRQ_KEYBOARDRX         15
-
-#define FIQ_FLOPPYDATA         0
-#define FIQ_ECONET             2
-#define FIQ_SERIALPORT         4
-#define FIQ_EXPANSIONCARD      6
-#define FIQ_FORCE              7
diff --git a/include/asm-arm/arch-a5k/mmu.h b/include/asm-arm/arch-a5k/mmu.h
deleted file mode 100644 (file)
index 3c2fb95..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/mmu.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  22-11-1996 RMK     Created
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define __virt_to_phys(vpage) vpage
-#define __phys_to_virt(ppage) ppage
-
-#endif
diff --git a/include/asm-arm/arch-a5k/oldlatches.h b/include/asm-arm/arch-a5k/oldlatches.h
deleted file mode 100644 (file)
index fa759a2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (a5k) machine"
-#endif
diff --git a/include/asm-arm/arch-a5k/processor.h b/include/asm-arm/arch-a5k/processor.h
deleted file mode 100644 (file)
index 717ae2a..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/processor.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  10-09-1996 RMK     Created
- */
-
-#ifndef __ASM_ARCH_PROCESSOR_H
-#define __ASM_ARCH_PROCESSOR_H
-
-/*
- * Bus types
- */
-#define EISA_bus 0
-#define EISA_bus__is_a_macro /* for versions in ksyms.c */
-#define MCA_bus 0
-#define MCA_bus__is_a_macro /* for versions in ksyms.c */
-
-/*
- * User space: 26MB
- */
-#define TASK_SIZE      (0x01a00000UL)
-
-/* This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE(off)        (TASK_SIZE / 3)
-#define TASK_UNMAPPED_ALIGN(addr, off) PAGE_ALIGN(addr)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0x02000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-#endif
diff --git a/include/asm-arm/arch-a5k/serial.h b/include/asm-arm/arch-a5k/serial.h
deleted file mode 100644 (file)
index c839708..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/serial.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  15-10-1996 RMK     Created
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-     /* UART CLK        PORT  IRQ     FLAGS        */
-#define RS_UARTS \
-       { 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS },     /* ttyS0 */     \
-       { 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS },     /* ttyS1 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS2 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS3 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS12 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS13 */
-
-#endif
diff --git a/include/asm-arm/arch-a5k/shmparam.h b/include/asm-arm/arch-a5k/shmparam.h
deleted file mode 100644 (file)
index 073c7c2..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff --git a/include/asm-arm/arch-a5k/system.h b/include/asm-arm/arch-a5k/system.h
deleted file mode 100644 (file)
index a1d845c..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/system.h
- *
- * Copyright (c) 1996 Russell King
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-extern __inline__ void arch_hard_reset (void)
-{
-       extern void ecard_reset (int card);
-
-       /*
-        * Reset all expansion cards.
-        */
-       ecard_reset (-1);
-
-       /*
-        * copy branch instruction to reset location and call it
-        */
-       *(unsigned long *)0 = *(unsigned long *)0x03800000;
-       ((void(*)(void))0)();
-
-       /*
-        * If that didn't work, loop endlessly
-        */
-       while (1);
-}
-
-#endif
diff --git a/include/asm-arm/arch-a5k/time.h b/include/asm-arm/arch-a5k/time.h
deleted file mode 100644 (file)
index 0d12303..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/time.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  24-Sep-1996        RMK     Created
- *  10-Oct-1996        RMK     Brought up to date with arch-sa110eval
- *  04-Dec-1997        RMK     Updated for new arch/arm/time.c
- */
-
-extern __inline__ unsigned long gettimeoffset (void)
-{
-       unsigned int count1, count2, status1, status2;
-       unsigned long offset = 0;
-
-       status1 = IOC_IRQREQA;
-       barrier ();
-       outb (0, IOC_T0LATCH);
-       barrier ();
-       count1 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
-       barrier ();
-       status2 = inb(IOC_IRQREQA);
-       barrier ();
-       outb (0, IOC_T0LATCH);
-       barrier ();
-       count2 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
-
-       if (count2 < count1) {
-               /*
-                * This means that we haven't just had an interrupt
-                * while reading into status2.
-                */
-               if (status2 & (1 << 5))
-                       offset = tick;
-               count1 = count2;
-       } else if (count2 > count1) {
-               /*
-                * We have just had another interrupt while reading
-                * status2.
-                */
-               offset += tick;
-               count1 = count2;
-       }
-
-       count1 = LATCH - count1;
-       /*
-        * count1 = number of clock ticks since last interrupt
-        */
-       offset += count1 * tick / LATCH;
-       return offset;
-}
-
-/*
- * No need to reset the timer at every irq
- */
-#define reset_timer() 1
-
-/*
- * Updating of the RTC.  We don't currently write the time to the
- * CMOS clock.
- */
-#define update_rtc()
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-extern __inline__ unsigned long setup_timer (void)
-{
-       extern int iic_control (unsigned char, int, char *, int);
-       unsigned int year, mon, day, hour, min, sec;
-       char buf[8];
-
-       outb(LATCH & 255, IOC_T0LTCHL);
-       outb(LATCH >> 8, IOC_T0LTCHH);
-       outb(0, IOC_T0GO);
-
-       iic_control (0xa0, 0xc0, buf, 1);
-       year = buf[0];
-       if ((year += 1900) < 1970)
-               year += 100;
-
-       iic_control (0xa0, 2, buf, 5);
-       mon  = buf[4] & 0x1f;
-       day  = buf[3] & 0x3f;
-       hour = buf[2];
-       min  = buf[1];
-       sec  = buf[0];
-       BCD_TO_BIN(mon);
-       BCD_TO_BIN(day);
-       BCD_TO_BIN(hour);
-       BCD_TO_BIN(min);
-       BCD_TO_BIN(sec);
-
-       return mktime(year, mon, day, hour, min, sec);
-}
diff --git a/include/asm-arm/arch-a5k/timex.h b/include/asm-arm/arch-a5k/timex.h
deleted file mode 100644 (file)
index 84baf1f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/timex.h
- *
- * A5000 architecture timex specifications
- *
- * Copyright (C) 1997, 1998 Russell King
- */
-
-/*
- * On the RiscPC, the clock ticks at 2MHz.
- */
-#define CLOCK_TICK_RATE                2000000
-
diff --git a/include/asm-arm/arch-a5k/uncompress.h b/include/asm-arm/arch-a5k/uncompress.h
deleted file mode 100644 (file)
index e6af264..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/uncompress.h
- *
- * Copyright (C) 1996 Russell King
- */
-#define VIDMEM ((char *)0x02000000)
-#include "../arch/arm/drivers/char/font.h"
-
-int video_num_columns, video_num_lines, video_size_row;
-int white, bytes_per_char_h;
-extern unsigned long con_charconvtable[256];
-
-struct param_struct {
-       unsigned long page_size;
-       unsigned long nr_pages;
-       unsigned long ramdisk_size;
-       unsigned long mountrootrdonly;
-       unsigned long rootdev;
-       unsigned long video_num_cols;
-       unsigned long video_num_rows;
-       unsigned long video_x;
-       unsigned long video_y;
-       unsigned long memc_control_reg;
-       unsigned char sounddefault;
-       unsigned char adfsdrives;
-       unsigned char bytes_per_char_h;
-       unsigned char bytes_per_char_v;
-       unsigned long unused[256/4-11];
-};
-
-static struct param_struct *params = (struct param_struct *)0x0207c000;
-/*
- * This does not append a newline
- */
-static void puts(const char *s)
-{
-       extern void ll_write_char(char *, unsigned long);
-       int x,y;
-       unsigned char c;
-       char *ptr;
-
-       x = params->video_x;
-       y = params->video_y;
-
-       while ( ( c = *(unsigned char *)s++ ) != '\0' ) {
-               if ( c == '\n' ) {
-                       x = 0;
-                       if ( ++y >= video_num_lines ) {
-                               y--;
-                       }
-               } else {
-                       ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h);
-                       ll_write_char(ptr, c|(white<<8));
-                       if ( ++x >= video_num_columns ) {
-                               x = 0;
-                               if ( ++y >= video_num_lines ) {
-                                       y--;
-                               }
-                       }
-               }
-       }
-
-       params->video_x = x;
-       params->video_y = y;
-}
-
-static void error(char *x);
-
-/*
- * Setup for decompression
- */
-static void arch_decomp_setup(void)
-{
-       int i;
-       
-       video_num_lines = params->video_num_rows;
-       video_num_columns = params->video_num_cols;
-       bytes_per_char_h = params->bytes_per_char_h;
-       video_size_row = video_num_columns * bytes_per_char_h;
-       if (bytes_per_char_h == 4)
-               for (i = 0; i < 256; i++)
-                       con_charconvtable[i] =
-                               (i & 128 ? 1 << 0  : 0) |
-                               (i & 64  ? 1 << 4  : 0) |
-                               (i & 32  ? 1 << 8  : 0) |
-                               (i & 16  ? 1 << 12 : 0) |
-                               (i & 8   ? 1 << 16 : 0) |
-                               (i & 4   ? 1 << 20 : 0) |
-                               (i & 2   ? 1 << 24 : 0) |
-                               (i & 1   ? 1 << 28 : 0);
-       else
-               for (i = 0; i < 16; i++)
-                       con_charconvtable[i] =
-                               (i & 8   ? 1 << 0  : 0) |
-                               (i & 4   ? 1 << 8  : 0) |
-                               (i & 2   ? 1 << 16 : 0) |
-                               (i & 1   ? 1 << 24 : 0);
-
-       white = bytes_per_char_h == 8 ? 0xfc : 7;
-
-       if (params->nr_pages * params->page_size < 4096*1024) error("<4M of mem\n");
-}
diff --git a/include/asm-arm/arch-ebsa110/mmap.h b/include/asm-arm/arch-ebsa110/mmap.h
deleted file mode 100644 (file)
index 2ba0c2a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * Use SRAM for cache flushing
- */
-#define SAFE_ADDR      0x40000000
index 5142e912638483fa2abc36203742f2fa70684782..f427173507880f9b17823088acd2c1e602dab6d5 100644 (file)
@@ -140,4 +140,26 @@ DECLARE_IO(long,l,"","Jr")
 #define inl_t(p)                                                               \
        (*(volatile unsigned long *)(p))
 
+/*
+ * This is not sufficient... (and it's a hack anyway)
+ */
+static inline void writeb(unsigned char b, unsigned int addr)
+{
+       *(volatile unsigned char *)(0xe0000000 + (addr)) = b;
+}
+
+static inline unsigned char readb(unsigned int addr)
+{
+       return *(volatile unsigned char *)(0xe0000000 + (addr));
+}
+
+static inline void writew(unsigned short b, unsigned int addr)
+{
+       *(volatile unsigned short *)(0xe0000000 + (addr)) = b;
+}
+
+static inline unsigned short readw(unsigned int addr)
+{
+       return *(volatile unsigned short *)(0xe0000000 + (addr));
+}
 #endif
index e4dcb27e14bc251672ce73e7d85fbcd9eacbe3ba..bf1f6d384158564572b380ac12bcfd82657bbf3c 100644 (file)
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
+#if 0
 #define TASK_UNMAPPED_BASE(off)        (TASK_SIZE / 3)
+#else
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#endif
 #define TASK_UNMAPPED_ALIGN(addr, off) PAGE_ALIGN(addr)
 
 #define INIT_MMAP \
diff --git a/include/asm-arm/arch-nexuspci/mmap.h b/include/asm-arm/arch-nexuspci/mmap.h
deleted file mode 100644 (file)
index 2ba0c2a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * Use SRAM for cache flushing
- */
-#define SAFE_ADDR      0x40000000
diff --git a/include/asm-arm/arch-nexuspci/serial.h b/include/asm-arm/arch-nexuspci/serial.h
deleted file mode 100644 (file)
index 1d41a7c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/serial.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  15-10-1996 RMK     Created
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-     /* UART CLK        PORT  IRQ     FLAGS        */
-#define RS_UARTS \
-       { 0, BASE_BAUD, 0x3F8,  1, STD_COM_FLAGS },     /* ttyS0 */     \
-       { 0, BASE_BAUD, 0x2F8,  2, STD_COM_FLAGS },     /* ttyS1 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS2 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS3 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS4 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS5 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS6 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS7 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS8 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS9 */     \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS10 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS11 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS12 */    \
-       { 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },     /* ttyS13 */
-
-#endif
-
diff --git a/include/asm-arm/arch-rpc/mmap.h b/include/asm-arm/arch-rpc/mmap.h
deleted file mode 100644 (file)
index 4a1cdea..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * linux/include/asm-arm/arch-rpc/mmap.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define HAVE_MAP_VID_MEM
-#define SAFE_ADDR 0x00000000   /* ROM */
-
-unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)
-{
-       static int updated = 0;
-       unsigned long address;
-       pgd_t *pgd;
-
-       if (updated)
-               return 0;
-       updated = update;
-
-       address = SCREEN_START | PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
-       pgd = swapper_pg_dir + (SCREEN2_BASE >> PGDIR_SHIFT);
-       pgd_val(pgd[0]) = address;
-       pgd_val(pgd[1]) = address + (1 << PGDIR_SHIFT);
-
-       if (update) {
-               unsigned long pgtable = PAGE_ALIGN(kmem), *p;
-               int i;
-
-               memzero ((void *)pgtable, 4096);
-               
-               pgd_val(pgd[-2]) = virt_to_phys(pgtable) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
-               pgd_val(pgd[-1]) = virt_to_phys(pgtable + PTRS_PER_PTE*4) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
-               p = (unsigned long *)pgtable;
-
-               i = PTRS_PER_PTE * 2 - ((SCREEN1_END - log_start) >> PAGE_SHIFT);
-               address = SCREEN_START | PTE_TYPE_SMALL | PTE_AP_WRITE;
-
-               while (i < PTRS_PER_PTE * 2) {
-                       p[i++] = address;
-                       address += PAGE_SIZE;
-               }
-
-               flush_page_to_ram(pgtable);
-
-               kmem = pgtable + PAGE_SIZE;
-       }
-       return kmem;
-}
index e6d942f71480e1ca5d7db9e59b860e10c9a2aa7a..26081088b3ceda464aa9dde9e425f56a63b05cbe 100644 (file)
@@ -53,6 +53,24 @@ extern __inline__ unsigned long ffz(unsigned long word)
         return k;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
 #ifdef __KERNEL__
 
 #define ext2_set_bit                   test_and_set_bit
diff --git a/include/asm-arm/fiq.h b/include/asm-arm/fiq.h
new file mode 100644 (file)
index 0000000..b79fe8a
--- /dev/null
@@ -0,0 +1,16 @@
+/* Support for FIQ on ARM architectures.
+ * Written by Philip Blundell <philb@gnu.org>, 1998
+ */
+
+#ifndef __ASM_FIQ_H
+#define __ASM_FIQ_H
+
+struct fiq_handler {
+        const char *name;
+        int (*callback)(void);
+};
+
+extern int claim_fiq(struct fiq_handler *f);
+extern void release_fiq(struct fiq_handler *f);
+
+#endif
index 0f385796254b771d0aa4a4ba35345dfcbc6d7889..090ec21a95e3947ded060f900ed9d82fe7b25c07 100644 (file)
@@ -9,7 +9,14 @@
 #include <asm/arch/floppy.h>
 #endif
 
-#define fd_outb(val,port)      outb((val),(port))
+#define fd_outb(val,port)                      \
+       do {                                    \
+               if ((port) == FD_DOR)           \
+                       fd_setdor((val));       \
+               else                            \
+                       outb((val),(port));     \
+       } while(0)
+
 #define fd_inb(port)           inb((port))
 #define fd_request_irq()       request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\
                                        SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL)
@@ -27,6 +34,9 @@
 #define fd_set_dma_count(len)  set_dma_count(FLOPPY_DMA, (len))
 #define fd_cacheflush(addr,sz)
 
+/* need to clean up dma.h */
+#define DMA_FLOPPYDISK         DMA_FLOPPY
+
 /* Floppy_selects is the list of DOR's to select drive fd
  *
  * On initialisation, the floppy list is scanned, and the drives allocated
@@ -40,13 +50,14 @@ static unsigned char floppy_selects[2][4] =
        { 0x10, 0x21, 0x23, 0x33 }
 };
 
-#define fd_setdor(dor)                                                                         \
-do {                                                                                           \
-       int new_dor = (dor);                                                                    \
-       if (new_dor & 0xf0)                                                                     \
-               fd_outb((new_dor & 0x0c) | floppy_selects[fdc][new_dor & 3], FD_DOR);           \
-       else                                                                                    \
-               fd_outb((new_dor & 0x0c), FD_DOR);                                              \
+#define fd_setdor(dor)                                                         \
+do {                                                                           \
+       int new_dor = (dor);                                                    \
+       if (new_dor & 0xf0)                                                     \
+               new_dor = (new_dor & 0x0c) | floppy_selects[fdc][new_dor & 3];  \
+       else                                                                    \
+               new_dor &= 0x0c;                                                \
+       outb(new_dor, FD_DOR);                                                  \
 } while (0)
 
 /*
index bd25d1838a92ae6774f6f61f4d1e8edf33fa8547..588c85894bc6c1c76f6bc7f1d451673027067913 100644 (file)
@@ -5,6 +5,12 @@
 
 extern unsigned int local_irq_count[NR_CPUS];
 
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
+
 #ifndef __SMP__
 
 #define hardirq_trylock(cpu)   (local_irq_count[cpu] == 0)
index 2451663e34c266fb23fb5c749fdd6b745950afe9..4a432c03dab793bd4031a87084c03155bfb1c4ee 100644 (file)
@@ -170,44 +170,5 @@ __IO(l,"",long)
 #undef ARCH_IO_DELAY
 #undef ARCH_IO_CONSTANT
 
-/*
- * Leftovers...
- */
-#if 0
-#define __outwc(value,port)                                            \
-({                                                                     \
-       if (port < 256)                                                 \
-               __asm__ __volatile__(                                   \
-               "strh   %0, [%1, %2]"                                   \
-               : : "r" (value), "r" (PCIO_BASE), "J" (port << 2));     \
-       else if (__PORT_PCIO(port))                                     \
-               __asm__ __volatile__(                                   \
-               "strh   %0, [%1, %2]"                                   \
-               : : "r" (value), "r" (PCIO_BASE), "r" (port << 2));     \
-       else                                                            \
-               __asm__ __volatile__(                                   \
-               "strh   %0, [%1, %2]"                                   \
-               : : "r" (value), "r" (IO_BASE), "r" (port << 2));       \
-})
-
-#define __inwc(port)                                                   \
-({                                                                     \
-       unsigned short result;                                          \
-       if (port < 256)                                                 \
-               __asm__ __volatile__(                                   \
-               "ldrh   %0, [%1, %2]"                                   \
-               : "=r" (result) : "r" (PCIO_BASE), "J" (port << 2));    \
-       else                                                            \
-       if (__PORT_PCIO(port))                                          \
-               __asm__ __volatile__(                                   \
-               "ldrh   %0, [%1, %2]"                                   \
-               : "=r" (result) : "r" (PCIO_BASE), "r" (port << 2));    \
-       else                                                            \
-               __asm__ __volatile__(                                   \
-               "ldrh   %0, [%1, %2]"                                   \
-               : "=r" (result) : "r" (IO_BASE), "r" (port << 2));      \
-       result;                                                         \
-})
-#endif
 #endif
 
index a564caf660e6a495974878b850bbff4cbcf03b2f..2cbb7d0e9dc6f1825b789754985350c60d17e448 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: ioctl.h,v 1.1 1998/01/28 09:56:22 ecd Exp $
- *
+/*
  * linux/ioctl.h for Linux by H.H. Bergman.
  */
 
diff --git a/include/asm-arm/irq-no.h b/include/asm-arm/irq-no.h
deleted file mode 100644 (file)
index 7d599cb..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * linux/include/asm-arm/irq-no.h
- *
- * Machine independent interrupt numbers
- */
-
-#include <asm/arch/irqs.h>
-
-#ifndef NR_IRQS
-#define NR_IRQS                128
-#endif
index 9d083e8c86cdaa32f1d1766a334ed06e8eaa937d..8fcd2f5cde3dec6cc6366c9ee37fa583a3235f34 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.1 1998/01/28 09:56:37 ecd Exp $
+/*
  * linux/include/asm-i386/namei.h
  *
  * Included from linux/fs/namei.c
index 1306198407b7fb2ec32f729ea4c390833d89ae62..f85e3252b98f094596f316b3150a4f8bd1545eb1 100644 (file)
@@ -50,4 +50,22 @@ extern __inline__ int test_bit(int nr, int * addr)
        mask = 1 << (nr & 0x1f);
        return ((mask & *addr) != 0);
 }
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
 #endif /* _ASM_GENERIC_BITOPS_H */
index 3b31d4f570429b5829a515182949e8470a04265e..92b5ee719e1e6a94533f3f77ab4403215ef8851c 100644 (file)
@@ -187,6 +187,33 @@ extern __inline__ unsigned long ffz(unsigned long word)
        return word;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+extern __inline__ int ffs(int x)
+{
+       int r;
+
+       __asm__("bsfl %1,%0\n\t"
+               "jnz 1f\n\t"
+               "movl $-1,%0\n"
+               "1:" : "=r" (r) : "g" (x));
+       return r+1;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
 #ifdef __KERNEL__
 
 #define ext2_set_bit                 test_and_set_bit
index 47e1d2cfc75c50e84c30b54b9fa05e20291d95f7..e7bca0700f7e2461807d5a52300ebc8a40ce1d15 100644 (file)
  * This file contains the functions and defines necessary to modify and use
  * the i386 page table tree.
  */
-
 #ifndef __ASSEMBLY__
+#include <asm/processor.h>
+#include <linux/tasks.h>
+
 /* Caches aren't brain-dead on the intel. */
 #define flush_cache_all()                      do { } while (0)
 #define flush_cache_mm(mm)                     do { } while (0)
@@ -38,7 +40,7 @@
 #define __flush_tlb() \
 do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0)
 
-#if defined(CONFIG_M386) || defined(CONFIG_AMD_K5_INVBUG)
+#ifdef CONFIG_M386
 #define __flush_tlb_one(addr) flush_tlb()
 #else
 #define __flush_tlb_one(addr) \
@@ -182,6 +184,7 @@ static inline void flush_tlb_range(struct mm_struct *mm,
 #define PTRS_PER_PTE   1024
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   1024
+#define USER_PTRS_PER_PGD      (TASK_SIZE/PGDIR_SIZE)
 
 /*
  * pgd entries used up by user/kernel:
@@ -385,85 +388,137 @@ extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
  * used to allocate a kernel page table - this turns on ASN bits
  * if any.
  */
-extern inline void pte_free_kernel(pte_t * pte)
+
+#define pgd_quicklist (current_cpu_data.pgd_quick)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (current_cpu_data.pte_quick)
+#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
+
+extern __inline__ pgd_t *get_pgd_slow(void)
 {
-       free_page((unsigned long) pte);
+       pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init;
+
+       if (ret) {
+               init = pgd_offset(&init_mm, 0);
+               memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+               memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+                       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+       }
+       return ret;
 }
 
-extern const char bad_pmd_string[];
+extern __inline__ pgd_t *get_pgd_fast(void)
+{
+       unsigned long *ret;
+
+       if((ret = pgd_quicklist) != NULL) {
+               pgd_quicklist = (unsigned long *)(*ret);
+               ret[0] = ret[1];
+               pgtable_cache_size--;
+       } else
+               ret = (unsigned long *)get_pgd_slow();
+       return (pgd_t *)ret;
+}
 
-extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
 {
-       address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-       if (pmd_none(*pmd)) {
-               pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
-               if (pmd_none(*pmd)) {
-                       if (page) {
-                               pmd_val(*pmd) = _KERNPG_TABLE + __pa(page);
-                               return page + address;
-                       }
-                       pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
-                       return NULL;
-               }
-               free_page((unsigned long) page);
-       }
-       if (pmd_bad(*pmd)) {
-               printk(bad_pmd_string, pmd_val(*pmd));
-               pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
-               return NULL;
+       *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+       pgd_quicklist = (unsigned long *) pgd;
+       pgtable_cache_size++;
+}
+
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
+{
+       free_page((unsigned long)pgd);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+       unsigned long *ret;
+
+       if((ret = (unsigned long *)pte_quicklist) != NULL) {
+               pte_quicklist = (unsigned long *)(*ret);
+               ret[0] = ret[1];
+               pgtable_cache_size--;
        }
-       return (pte_t *) pmd_page(*pmd) + address;
+       return (pte_t *)ret;
 }
 
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern inline void pmd_free_kernel(pmd_t * pmd)
+extern __inline__ void free_pte_fast(pte_t *pte)
 {
-       pmd_val(*pmd) = 0;
+       *(unsigned long *)pte = (unsigned long) pte_quicklist;
+       pte_quicklist = (unsigned long *) pte;
+       pgtable_cache_size++;
 }
 
-extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
+extern __inline__ void free_pte_slow(pte_t *pte)
 {
-       return (pmd_t *) pgd;
+       free_page((unsigned long)pte);
 }
 
-extern inline void pte_free(pte_t * pte)
+/* We don't use pmd cache, so these are dummy routines */
+extern __inline__ pmd_t *get_pmd_fast(void)
 {
-       free_page((unsigned long) pte);
+       return (pmd_t *)0;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+}
+
+extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pte_kernel(pmd_t *pmd);
+
+#define pte_free_kernel(pte)    free_pte_fast(pte)
+#define pte_free(pte)           free_pte_fast(pte)
+#define pgd_free(pgd)           free_pgd_fast(pgd)
+#define pgd_alloc()             get_pgd_fast()
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+       address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+       if (pmd_none(*pmd)) {
+               pte_t * page = (pte_t *) get_pte_fast();
+               
+               if (!page)
+                       return get_pte_kernel_slow(pmd, address);
+               pmd_val(*pmd) = _KERNPG_TABLE + __pa(page);
+               return page + address;
+       }
+       if (pmd_bad(*pmd)) {
+               __bad_pte_kernel(pmd);
+               return NULL;
+       }
+       return (pte_t *) pmd_page(*pmd) + address;
 }
 
 extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
 {
        address = (address >> (PAGE_SHIFT-2)) & 4*(PTRS_PER_PTE - 1);
 
-repeat:
        if (pmd_none(*pmd))
                goto getnew;
        if (pmd_bad(*pmd))
                goto fix;
        return (pte_t *) (pmd_page(*pmd) + address);
-       
 getnew:
 {
-       unsigned long page = __get_free_page(GFP_KERNEL);
-       if (!pmd_none(*pmd))
-               goto freenew;
+       unsigned long page = (unsigned long) get_pte_fast();
+       
        if (!page)
-               goto oom;
-       memset((void *) page, 0, PAGE_SIZE);
+               return get_pte_slow(pmd, address);
        pmd_val(*pmd) = _PAGE_TABLE + __pa(page);
        return (pte_t *) (page + address);
-freenew:
-       free_page(page);
-       goto repeat;
 }
-
 fix:
-       printk(bad_pmd_string, pmd_val(*pmd));
-oom:
-       pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+       __bad_pte(pmd);
        return NULL;
 }
 
@@ -473,7 +528,6 @@ oom:
  */
 extern inline void pmd_free(pmd_t * pmd)
 {
-       pmd_val(*pmd) = 0;
 }
 
 extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
@@ -481,14 +535,34 @@ extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
        return (pmd_t *) pgd;
 }
 
-extern inline void pgd_free(pgd_t * pgd)
-{
-       free_page((unsigned long) pgd);
-}
+#define pmd_free_kernel                pmd_free
+#define pmd_alloc_kernel       pmd_alloc
 
-extern inline pgd_t * pgd_alloc(void)
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
 {
-       return (pgd_t *) get_free_page(GFP_KERNEL);
+       struct task_struct * p;
+       pgd_t *pgd;
+#ifdef __SMP__
+       int i;
+#endif 
+        
+       read_lock(&tasklist_lock);
+       for_each_task(p) {
+               if (!p->mm)
+                       continue;
+               *pgd_offset(p->mm,address) = entry;
+       }
+       read_unlock(&tasklist_lock);
+#ifndef __SMP__
+       for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+               pgd[address >> PGDIR_SHIFT] = entry;
+#else
+       /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can
+          modify pgd caches of other CPUs as well. -jj */
+       for (i = 0; i < NR_CPUS; i++)
+               for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+                       pgd[address >> PGDIR_SHIFT] = entry;
+#endif
 }
 
 extern pgd_t swapper_pg_dir[1024];
index 33039e61b136f57e7c80121af29da0dfa5c92271..0d642dc277d79574956a367b3d420b93deb8e14c 100644 (file)
@@ -34,6 +34,9 @@ struct cpuinfo_x86 {
        int     fdiv_bug;
        int     f00f_bug;
        unsigned long loops_per_sec;
+       unsigned long *pgd_quick;
+       unsigned long *pte_quick;
+       unsigned long pgtable_cache_sz;
 };
 
 #define X86_VENDOR_INTEL 0
index caaa8d0de81acf2b66aec1c145a880f2b7b65d46..a5d1059797dd18625f233908f5540b6b4cd8d379 100644 (file)
@@ -332,4 +332,4 @@ struct tod2000 {
 #define TOD2000_HOUR1_PM       (1<<2)
 #define TOD_2000 ((struct tod2000 *)(zTwoBase+0xDC0000))
 
-#endif /* __ASMm68k_AMIGAHW_H */
+#endif /* _M68K_AMIGAHW_H */
index 0ab7c15d04e24f43ac26de4cbae29099da506d7c..481bd0e11ebeee365837f9cd81295fc01dd84bfa 100644 (file)
@@ -29,8 +29,9 @@
                                                 * clock sources */
 
 #define SCC_BAUD_BASE_MVME_PCLK        781250  /* 12.5 MHz */
-#define SCC_BAUD_BASE_BVM      460800  /* 7.3728 MHz */
 #define SCC_BAUD_BASE_MVME     625000  /* 10.000 MHz */
+#define SCC_BAUD_BASE_BVME_PCLK        781250  /* 12.5 MHz */   /* XXX ??? */
+#define SCC_BAUD_BASE_BVME     460800  /* 7.3728 MHz */
 
 /* The SCC configuration structure */
 
diff --git a/include/asm-m68k/atari_mouse.h b/include/asm-m68k/atari_mouse.h
deleted file mode 100644 (file)
index 003bf2b..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _LINUX_ATARI_MOUSE_H
-#define _LINUX_ATARI_MOUSE_H
-
-/*
- * linux/include/linux/atari_mouse.h
- * header file for Atari Mouse driver
- * by Robert de Vries (robert@and.nl) on 19Jul93
- */
-
-struct mouse_status {
-       char            buttons;
-       short           dx;
-       short           dy;
-       int             ready;
-       int             active;
-       struct wait_queue *wait;
-       struct fasync_struct *fasyncptr;
-};
-
-#endif
index b2a335a7d858e2ad7a3e972f6011518a494858f8..d4efb564d41d5693b626f60f1ae5648e52a42c28 100644 (file)
@@ -210,6 +210,23 @@ extern __inline__ unsigned long ffz(unsigned long word)
        return res ^ 31;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
 /* Bitmap functions for the minix filesystem */
 
 extern __inline__ int
diff --git a/include/asm-m68k/blinken.h b/include/asm-m68k/blinken.h
new file mode 100644 (file)
index 0000000..a6b60de
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+** asm/blinken.h -- m68k blinkenlights support (currently hp300 only)
+**
+** (c) 1998 Phil Blundell <philb@gnu.org>
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file COPYING in the main directory of this archive
+** for more details.
+**
+*/
+
+#ifndef _M68K_BLINKEN_H
+#define _M68K_BLINKEN_H
+
+#include <asm/setup.h>
+
+#define HP300_LEDS             0xf001ffff
+
+static __inline__ void blinken_leds(int x)
+{
+  if (MACH_IS_HP300)
+  {
+    *((volatile unsigned char *)HP300_LEDS) = (x);
+  }
+}
+
+#endif
index 279f82a167afe5069ade77aebdc3ce21c5613155..ff5d41ef86e868328cb225f119be874da9feec2a 100644 (file)
@@ -109,7 +109,7 @@ BIR_data    = BIR_size+2
 #define ATARI_MACH_AB40                3       /* Afterburner040 on Falcon */
 
     /*
-     *  Macintosh-specific tags
+     *  Macintosh-specific tags (all u_long)
      */
 
 #define BI_MAC_MODEL           0x8000  /* Mac Gestalt ID (model type) */
@@ -123,9 +123,37 @@ BIR_data   = BIR_size+2
 #define BI_MAC_GMTBIAS         0x8008  /* Mac GMT timezone offset */
 #define BI_MAC_MEMSIZE         0x8009  /* Mac RAM size (sanity check) */
 #define BI_MAC_CPUID           0x800a  /* Mac CPU type (sanity check) */
+#define BI_MAC_ROMBASE         0x800b  /* Mac system ROM base address */ 
+
+    /*
+     *  Macintosh hardware profile data - unused, see macintosh.h for 
+     *  resonable type values 
+     */
+
+#define BI_MAC_VIA1BASE                0x8010  /* Mac VIA1 base address (always present) */
+#define BI_MAC_VIA2BASE                0x8011  /* Mac VIA2 base address (type varies) */
+#define BI_MAC_VIA2TYPE                0x8012  /* Mac VIA2 type (VIA, RBV, OSS) */
+#define BI_MAC_ADBTYPE         0x8013  /* Mac ADB interface type */
+#define BI_MAC_ASCBASE         0x8014  /* Mac Apple Sound Chip base address */
+#define BI_MAC_SCSI5380                0x8015  /* Mac NCR 5380 SCSI (base address, multi) */
+#define BI_MAC_SCSIDMA         0x8016  /* Mac SCSI DMA (base address) */
+#define BI_MAC_SCSI5396                0x8017  /* Mac NCR 53C96 SCSI (base address, multi) */
+#define BI_MAC_IDETYPE         0x8018  /* Mac IDE interface type */
+#define BI_MAC_IDEBASE         0x8019  /* Mac IDE interface base address */
+#define BI_MAC_NUBUS           0x801a  /* Mac Nubus type (none, regular, pseudo) */
+#define BI_MAC_SLOTMASK                0x801b  /* Mac Nubus slots present */
+#define BI_MAC_SCCTYPE         0x801c  /* Mac SCC serial type (normal, IOP) */
+#define BI_MAC_ETHTYPE         0x801d  /* Mac builtin ethernet type (Sonic, MACE */
+#define BI_MAC_ETHBASE         0x801e  /* Mac builtin ethernet base address */
+#define BI_MAC_PMU             0x801f  /* Mac power managment / poweroff hardware */
+#define BI_MAC_IOP_SWIM                0x8020  /* Mac SWIM floppy IOP */
+#define BI_MAC_IOP_ADB         0x8021  /* Mac ADB IOP */
 
     /*
      * Mac: compatibility with old booter data format (temporarily)
+     * Fields unused with the new bootinfo can be deleted now; instead of
+     * adding new fields the struct might be splitted into a hardware address
+     * part and a hardware type part
      */
 
 #ifndef __ASSEMBLY__
@@ -198,6 +226,7 @@ struct bootversion {
 #define ATARI_BOOTI_VERSION    MK_BI_VERSION( 2, 1 )
 #define MAC_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
 #define MVME16x_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
+#define BVME6000_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
 
 
 #ifdef BOOTINFO_COMPAT_1_0
diff --git a/include/asm-m68k/bvme6000hw.h b/include/asm-m68k/bvme6000hw.h
new file mode 100644 (file)
index 0000000..0218c29
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef _M68K_BVME6000HW_H_
+#define _M68K_BVME6000HW_H_
+
+#include <asm/irq.h>
+
+/*
+ * PIT structure
+ */
+
+#define BVME_PIT_BASE  0xffa00000
+
+typedef struct {
+       unsigned char
+       pad_a[3], pgcr,
+       pad_b[3], psrr,
+       pad_c[3], paddr,
+       pad_d[3], pbddr,
+       pad_e[3], pcddr,
+       pad_f[3], pivr,
+       pad_g[3], pacr,
+       pad_h[3], pbcr,
+       pad_i[3], padr,
+       pad_j[3], pbdr,
+       pad_k[3], paar,
+       pad_l[3], pbar,
+       pad_m[3], pcdr,
+       pad_n[3], psr,
+       pad_o[3], res1,
+       pad_p[3], res2,
+       pad_q[3], tcr,
+       pad_r[3], tivr,
+       pad_s[3], res3,
+       pad_t[3], cprh,
+       pad_u[3], cprm,
+       pad_v[3], cprl,
+       pad_w[3], res4,
+       pad_x[3], crh,
+       pad_y[3], crm,
+       pad_z[3], crl,
+       pad_A[3], tsr,
+       pad_B[3], res5;
+} PitRegs_t, *PitRegsPtr;
+
+#define bvmepit   ((*(volatile PitRegsPtr)(BVME_PIT_BASE)))
+
+#define BVME_RTC_BASE  0xff900000
+
+typedef struct {
+       unsigned char
+       pad_a[3], msr,
+       pad_b[3], t0cr_rtmr,
+       pad_c[3], t1cr_omr,
+       pad_d[3], pfr_icr0,
+       pad_e[3], irr_icr1,
+       pad_f[3], bcd_tenms,
+       pad_g[3], bcd_sec,
+       pad_h[3], bcd_min,
+       pad_i[3], bcd_hr,
+       pad_j[3], bcd_dom,
+       pad_k[3], bcd_mth,
+       pad_l[3], bcd_year,
+       pad_m[3], bcd_ujcc,
+       pad_n[3], bcd_hjcc,
+       pad_o[3], bcd_dow,
+       pad_p[3], t0lsb,
+       pad_q[3], t0msb,
+       pad_r[3], t1lsb,
+       pad_s[3], t1msb,
+       pad_t[3], cmp_sec,
+       pad_u[3], cmp_min,
+       pad_v[3], cmp_hr,
+       pad_w[3], cmp_dom,
+       pad_x[3], cmp_mth,
+       pad_y[3], cmp_dow,
+       pad_z[3], sav_sec,
+       pad_A[3], sav_min,
+       pad_B[3], sav_hr,
+       pad_C[3], sav_dom,
+       pad_D[3], sav_mth,
+       pad_E[3], ram,
+       pad_F[3], test;
+} RtcRegs_t, *RtcPtr_t;
+
+
+#define BVME_I596_BASE 0xff100000
+
+#define BVME_ETHIRQ_REG        0xff20000b
+
+#define BVME_LOCAL_IRQ_STAT  0xff20000f
+
+#define BVME_ETHERR          0x02
+#define BVME_ABORT_STATUS    0x08
+
+#define BVME_NCR53C710_BASE    0xff000000
+
+#define BVME_SCC_A_ADDR        0xffb0000b
+#define BVME_SCC_B_ADDR        0xffb00003
+
+#define BVME_CONFIG_REG        0xff500003
+
+#define config_reg_ptr (unsigned char *)BVME_CONFIG_REG
+
+#define BVME_CONFIG_SW1        0x08
+#define BVME_CONFIG_SW2        0x04
+#define BVME_CONFIG_SW3        0x02
+#define BVME_CONFIG_SW4        0x01
+
+
+#define BVME_IRQ_TYPE_PRIO     0
+
+#define BVME_IRQ_PRN           0x54
+#define BVME_IRQ_I596          0x1a
+#define BVME_IRQ_SCSI          0x1b
+#define BVME_IRQ_TIMER         0x59
+#define BVME_IRQ_RTC           0x1e
+#define BVME_IRQ_ABORT         0x1f
+
+/* SCC interrupts */
+#define BVME_IRQ_SCC_BASE              0x40
+#define BVME_IRQ_SCCB_TX               0x40
+#define BVME_IRQ_SCCB_STAT             0x42
+#define BVME_IRQ_SCCB_RX               0x44
+#define BVME_IRQ_SCCB_SPCOND           0x46
+#define BVME_IRQ_SCCA_TX               0x48
+#define BVME_IRQ_SCCA_STAT             0x4a
+#define BVME_IRQ_SCCA_RX               0x4c
+#define BVME_IRQ_SCCA_SPCOND           0x4e
+
+#endif
index 8b7f9d16208b706e6834eb9ea5fa0b776d747138..d4a6e6fb9acf05111e1fc1bd8cd5208b8e91a393 100644 (file)
@@ -39,6 +39,10 @@ extern unsigned int
 csum_partial_copy_from_user ( const char *src, char *dst,
                              int len, int sum, int *csum_err);
 
+/* FIXME: this needs to be written to really do no check -- Cort */
+#define csum_partial_copy_nocheck(src, dst, len, sum)  \
+       csum_partial_copy((src), (dst), (len), (sum))
+
 /*
  *     This is a version of ip_compute_csum() optimized for IP headers,
  *     which always checksum on 4 octet boundaries.
index 2c318269618cec2d4603505a2807ac6438f5b6e9..613a9e6a94fdd0c2533123bcc99e5020abd1fc61 100644 (file)
@@ -54,7 +54,7 @@ LTSS_CRP      = 12
 LTSS_FPCTXT    = 24
 
 /* the following macro is used when enabling interrupts */
-#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
+#if defined(CONFIG_ATARI_ONLY) && !defined(CONFIG_HADES)
        /* block out HSYNC on the atari */
 #define ALLOWINT 0xfbff
 #define        MAX_NOINT_IPL   3
index 76968803b46519279056c2a15d37b2efb06aaae5..350fc0f699b07ce431a8f79c8851d6ab2c219b2d 100644 (file)
@@ -5,6 +5,8 @@
 
 extern unsigned int local_irq_count[NR_CPUS];
 
+#define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
+
 #define hardirq_trylock(cpu)   (++local_irq_count[cpu], (cpu) == 0)
 #define hardirq_endlock(cpu)   (--local_irq_count[cpu])
 
diff --git a/include/asm-m68k/hwtest.h b/include/asm-m68k/hwtest.h
new file mode 100644 (file)
index 0000000..17d3f0a
--- /dev/null
@@ -0,0 +1,15 @@
+/* Routines to test for presence/absence of hardware registers:
+ * see arch/m68k/mm/hwtest.c.
+ *  -- PMM <pmaydell@chiark.greenend.org.uk> 05/1998
+ *
+ * Removed initfunc from decls.  We might want them in modules, and 
+ * the code is tiny anyway.  16/5/98 pb
+ */
+
+#ifndef __ASM_HWTEST_H
+#define __ASM_HWTEST_H 
+
+extern int hwreg_present(volatile void *regp);
+extern int hwreg_write(volatile void *regp, unsigned short val);
+
+#endif
index a69ef5b180ecd820df063ad435097e6e66c5ad21..abcd0da25b17d0d687f610f132713a4c7ddd035b 100644 (file)
 #include <asm/atari_stdma.h>
 #endif
 
+#ifdef CONFIG_MAC
+#include <asm/macints.h>
+#endif
+
 typedef unsigned char * ide_ioreg_t;
 
 #ifndef MAX_HWIFS
@@ -71,6 +75,10 @@ typedef union {
        } b;
        } select_t;
 
+#ifdef CONFIG_MAC      /* MSch: Hack; wrapper for ide_intr */
+void mac_ide_intr(int irq, void *dev_id, struct pt_regs *regs);
+#endif
+
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
                        unsigned long flags, const char *device, void *dev_id)
 {
@@ -78,6 +86,14 @@ static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, voi
        if (MACH_IS_AMIGA)
                return request_irq(irq, handler, 0, device, dev_id);
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_MAC
+       if (MACH_IS_MAC)
+#if 0  /* MSch Hack: maybe later we'll call ide_intr without a wrapper */
+       return nubus_request_irq(12, dev_id, handler);
+#else
+       return nubus_request_irq(12, dev_id, mac_ide_intr);
+#endif
+#endif /* CONFIG_MAC */
        return 0;
 }
 
@@ -87,6 +103,10 @@ static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
        if (MACH_IS_AMIGA)
                free_irq(irq, dev_id);
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_MAC
+       if (MACH_IS_MAC)
+               nubus_free_irq(12);
+#endif /* CONFIG_MAC */
 }
 
 /*
@@ -117,81 +137,83 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
 #define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
 #define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
 
-#define insw(port, buf, nr) \
-    if ((nr) % 16) \
-       __asm__ __volatile__ \
-              ("movel %0,%/a0; \
-                movel %1,%/a1; \
-                movel %2,%/d6; \
-                subql #1,%/d6; \
-              1:movew %/a0@,%/a1@+; \
-                dbra %/d6,1b" : \
-               : "g" (port), "g" (buf), "g" (nr) \
-               : "a0", "a1", "d6"); \
-    else \
-       __asm__ __volatile__ \
-              ("movel %0,%/a0; \
-                movel %1,%/a1; \
-                movel %2,%/d6; \
-                lsrl  #4,%/d6; \
-                subql #1,%/d6; \
-              1:movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                movew %/a0@,%/a1@+; \
-                dbra %/d6,1b" : \
-               : "g" (port), "g" (buf), "g" (nr) \
-               : "a0", "a1", "d6")
-
-#define outsw(port, buf, nr) \
-    if ((nr) % 16) \
-       __asm__ __volatile__ \
-              ("movel %0,%/a0; \
-                movel %1,%/a1; \
-                movel %2,%/d6; \
-                subql #1,%/d6; \
-              1:movew %/a1@+,%/a0@; \
-                dbra %/d6,1b" : \
-               : "g" (port), "g" (buf), "g" (nr) \
-               : "a0", "a1", "d6"); \
-    else \
-       __asm__ __volatile__ \
-              ("movel %0,%/a0; \
-                movel %1,%/a1; \
-                movel %2,%/d6; \
-                lsrl  #4,%/d6; \
-                subql #1,%/d6; \
-              1:movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                movew %/a1@+,%/a0@; \
-                dbra %/d6,1b" : \
-               : "g" (port), "g" (buf), "g" (nr) \
-               : "a0", "a1", "d6")
+#define insw(port, buf, nr) ({                         \
+       unsigned char *_port = (unsigned char *)(port); \
+       unsigned char *_buf = (buf);                    \
+       int _nr = (nr);                                 \
+       unsigned long _tmp;                             \
+                                                       \
+       if (_nr & 15) {                                 \
+               _tmp = (_nr & 15) - 1;                  \
+               asm volatile (                          \
+                       "1: movew %2@,%3@+; dbra %4,1b" \
+                       : "=a" (_buf), "=d" (_tmp)      \
+                       : "a" (_port), "0" (_buf),      \
+                         "1" (_tmp));                  \
+       }                                               \
+       _tmp = (_nr >> 4) - 1;                          \
+       asm volatile (                                  \
+               "1: "                                   \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "movew %2@,%3@+; "                      \
+               "dbra %4,1b"                            \
+               : "=a" (_buf), "=d" (_tmp)              \
+               : "a" (_port), "0" (_buf),              \
+                 "1" (_tmp));                          \
+})
+
+#define outsw(port, buf, nr) ({                                \
+       unsigned char *_port = (unsigned char *)(port); \
+       unsigned char *_buf = (buf);                    \
+       int _nr = (nr);                                 \
+       unsigned long _tmp;                             \
+                                                       \
+       if (_nr & 15) {                                 \
+               _tmp = (_nr & 15) - 1;                  \
+               asm volatile (                          \
+                       "1: movew %3@,%2@+; dbra %4,1b" \
+                       : "=a" (_buf), "=d" (_tmp)      \
+                       : "a" (_port), "0" (_buf),      \
+                         "1" (_tmp));                  \
+       }                                               \
+       _tmp = (_nr >> 4) - 1;                          \
+       asm volatile (                                  \
+               "1: "                                   \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "movew %3@+,%2@; "                      \
+               "dbra %4,1b"                            \
+               : "=a" (_buf), "=d" (_tmp)              \
+               : "a" (_port), "0" (_buf),              \
+                 "1" (_tmp));                          \
+})
 
 #ifdef CONFIG_ATARI
 #define insl_swapw(data_reg, buffer, wcount) \
@@ -310,11 +332,11 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
 #define D_INT(cnt)      (T_INT   | (cnt))
 #define D_TEXT(cnt)     (T_TEXT  | (cnt))
 
-#ifdef CONFIG_AMIGA
+#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC)
 static u_short driveid_types[] = {
        D_SHORT(10),    /* config - vendor2 */
        D_TEXT(20),     /* serial_no */
-       D_SHORT(3),     /* buf_type - ecc_bytes */
+       D_SHORT(3),     /* buf_type, buf_size - ecc_bytes */
        D_TEXT(48),     /* fw_rev - model */
        D_CHAR(2),      /* max_multsect - vendor3 */
        D_SHORT(1),     /* dword_io */
@@ -333,12 +355,12 @@ static u_short driveid_types[] = {
 
 static __inline__ void ide_fix_driveid(struct hd_driveid *id)
 {
-#ifdef CONFIG_AMIGA
+#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC)
    u_char *p = (u_char *)id;
    int i, j, cnt;
    u_char t;
 
-   if (!MACH_IS_AMIGA)
+   if (!MACH_IS_AMIGA && !MACH_IS_MAC)
        return;
    for (i = 0; i < num_driveid_types; i++) {
       cnt = driveid_types[i] & T_MASK_COUNT;
@@ -423,7 +445,7 @@ static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *,
  * an interrupt, and in that case it does nothing. Hope that is reasonable and
  * works. (Roman)
  */
-#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA)
+#ifdef CONFIG_ATARI_ONLY
 #define        ide__sti()                                      \
     do {                                               \
        if (!in_interrupt()) __sti();                   \
index 8cee601e6cff85c659f59148414728038bc70d06..a002fe2a0318da5137752444f49baf1792d7ef71 100644 (file)
@@ -28,9 +28,9 @@
 #define readl(addr) \
     ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
 
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
 
 #define memset_io(a,b,c)       memset((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
index 4012d8111e8603677deab48f4ac1ed2b9f9eaae5..e0812e048d713d45b9533743b2f43a0040f6e339 100644 (file)
@@ -100,9 +100,16 @@ struct VIA
 # define via_1         ((*(volatile struct VIA *)VIA1_BAS))
 # define via_2         ((*(volatile struct VIA *)VIA2_BAS))
 # define via1_regp    ((volatile unsigned char *)VIA1_BAS)
-
-# define via2_regp    ((volatile unsigned char *)VIA2_BAS)
-# define via2_ci_regp ((volatile unsigned char *)VIA2_BAS_IIci)
-# define rbv_regp     ((volatile unsigned char *)VIA2_BAS_IIci)
  
+/*
+ * OSS/RBV base address 
+ */
+
+#define OSS_BAS                0x50f1a000
+#define PSC_BAS                0x50f31000
+
+/* move to oss.h?? */
+#define nIFR   0x203
+#define oIFR   0x202
+
 #endif /* linux/machw.h */
index 22db423aec18e75f22f7ada6d7a7e3bf9f48742d..a084447f53539ed011378ff36ba878b0df52178d 100644 (file)
@@ -76,6 +76,7 @@ struct mac_model
 #define MAC_SCC_II             1
 #define MAC_SCC_QUADRA         2
 #define MAC_SCC_QUADRA2                3
+#define MAC_SCC_IOP            4
 
 #define MAC_ETHER_NONE         0       
 #define MAC_ETHER_SONIC                1
@@ -94,6 +95,7 @@ struct mac_model
 #define MAC_MODEL_IICI         11
 #define MAC_MODEL_IIFX         13      /* And well numbered it is too */
 #define MAC_MODEL_IISI         18
+#define MAC_MODEL_LC           19
 #define MAC_MODEL_Q900         20
 #define MAC_MODEL_PB170                21
 #define MAC_MODEL_Q700         22
@@ -131,9 +133,11 @@ struct mac_model
 #define MAC_MODEL_PB190        85
 #define MAC_MODEL_TV           88
 #define MAC_MODEL_P475         89      /* aka: LC475, P476 */
+#define MAC_MODEL_P475F                90      /* aka: P475 w/ FPU (no LC040) */
 #define MAC_MODEL_P575         92      /* aka: LC575/580, P577/578/508 */
 #define MAC_MODEL_Q605         94
 #define MAC_MODEL_Q630         98      /* aka: LC630, P630/631/636/640 */
+#define MAC_MODEL_P588         99      /* aka: ?? */
 #define MAC_MODEL_PB280                102
 #define MAC_MODEL_PB280C       103
 #define MAC_MODEL_PB150                115
index 229b298456bc7010535c4ae0ff422b287771f0dd..e731c0e7f3ed630000b431f1c98f6c7b7c3ab02f 100644 (file)
@@ -26,9 +26,9 @@
 
 #define VIA1_SOURCE_BASE       8
 #define VIA2_SOURCE_BASE       16
-#define RBF_SOURCE_BASE                24
+#define RBV_SOURCE_BASE                24
 #define MAC_SCC_SOURCE_BASE    32
-#define NUBUS_SOURCE_BASE      40
+#define NUBUS_SOURCE_BASE      56
 #define NUBUS_MAX_SOURCES      8
 
 /* FIXME: sources not contigous ... */
  */
 #define        IRQ_IDX(irq)    (irq)
 
-#if 0
-/* convert vector number to int source number */
-#define IRQ_VECTOR_TO_SOURCE(v)        (v)
-
-/* convert irq_handler index to vector number */
-#define IRQ_SOURCE_TO_VECTOR(i)        (i)
-#endif
-
 /* interrupt service types */
 #define IRQ_TYPE_SLOW     0
 #define IRQ_TYPE_FAST     1
@@ -96,6 +88,7 @@
 #define IRQ_VIA2_6       (22)
 #define IRQ_VIA2_7        (23)
 
+#if 0
 /* RBV interrupts */
 #define IRQ_RBV_0        (24)
 #define IRQ_RBV_1        (25)
 #define IRQ_RBV_5        (29)
 #define IRQ_RBV_6        (30)
 #define IRQ_RBV_7        (31)
+#endif
+
+/* Level 3 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC3_0       (24)
+#define IRQ_MAC_MACE     IRQ_PSC3_0
+#define IRQ_PSC3_1       (25)
+#define IRQ_PSC3_2       (26)
+#define IRQ_PSC3_3       (27)
 
+/* Level 4 (SCC) interrupts */
 #define IRQ_SCC             (32)
-#define IRQ_SCCB            (32)
-#define IRQ_SCCA            (33)
+#define IRQ_SCCB            (33)
+#define IRQ_SCCA            (34)
 #if 0 /* FIXME: are there multiple interrupt conditions on the SCC ?? */
 /* SCC interrupts */
 #define IRQ_SCCB_TX         (32)
 #define IRQ_SCCA_SPCOND             (39)
 #endif
 
-#define IRQ_NUBUS_1         (40)
+/* Level 4 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC4_0       (32)
+#define IRQ_PSC4_1       (33)
+#define IRQ_PSC4_2       (34)
+#define IRQ_PSC4_3       (35)
+#define IRQ_MAC_MACE_DMA  IRQ_PSC4_3
+
+/* Level 5 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC5_0       (40)
+#define IRQ_PSC5_1       (41)
+#define IRQ_PSC5_2       (42)
+#define IRQ_PSC5_3       (43)
+
+/* Level 6 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC6_0       (48)
+#define IRQ_PSC6_1       (49)
+#define IRQ_PSC6_2       (50)
+#define IRQ_PSC6_3       (51)
+
+/* Nubus interrupts (cascaded to VIA2) */
+#define IRQ_NUBUS_1      (56)
 
 #define INT_CLK   24576            /* CLK while int_clk =2.456MHz and divide = 100 */
 #define INT_TICKS 246      /* to make sched_time = 99.902... HZ */
index dbcee26726285708aae57af980c3cdde55f8c208..75a21d8a4d9145304292f94fdd26f93af2796646 100644 (file)
@@ -34,37 +34,59 @@ typedef struct {
                spare3,
                spare4,
                data;
-} lpr_ctrl;
+} MVMElp, *MVMElpPtr;
 
-#define LPR_REGS       ((volatile lpr_ctrl *)0xfff42030)
+#define MVME_LPR_BASE  0xfff42030
 
-#define I596_BASE      0xfff46000
+#define mvmelp   ((*(volatile MVMElpPtr)(MVME_LPR_BASE)))
 
-#define SCC_A_ADDR     0xfff45005
-#define SCC_B_ADDR     0xfff45001
-
-#define IRQ_MVME162_TYPE_PRIO  0
-
-#define IRQ_MVME167_PRN                0x54
-#define IRQ_MVME16x_I596       0x57
-#define IRQ_MVME16x_SCSI       0x55
-#define IRQ_MVME16x_FLY                0x7f
-#define IRQ_MVME167_SER_ERR    0x5c
-#define IRQ_MVME167_SER_MODEM  0x5d
-#define IRQ_MVME167_SER_TX     0x5e
-#define IRQ_MVME167_SER_RX     0x5f
-#define IRQ_MVME16x_TIMER      0x59
+typedef struct {
+       unsigned char
+               ctrl,
+               bcd_sec,
+               bcd_min,
+               bcd_hr,
+               bcd_dow,
+               bcd_dom,
+               bcd_mth,
+               bcd_year;
+} MK48T08_t, *MK48T08ptr_t;
+
+#define RTC_WRITE      0x80
+#define RTC_READ       0x40
+#define RTC_STOP       0x20
+
+#define MVME_RTC_BASE  0xfffc1ff8
+
+#define MVME_I596_BASE 0xfff46000
+
+#define MVME_SCC_A_ADDR        0xfff45005
+#define MVME_SCC_B_ADDR        0xfff45001
+
+#define MVME162_IRQ_TYPE_PRIO  0
+                
+#define MVME167_IRQ_PRN                0x54
+#define MVME16x_IRQ_I596       0x57
+#define MVME16x_IRQ_SCSI       0x55
+#define MVME16x_IRQ_FLY                0x7f
+#define MVME167_IRQ_SER_ERR    0x5c
+#define MVME167_IRQ_SER_MODEM  0x5d
+#define MVME167_IRQ_SER_TX     0x5e
+#define MVME167_IRQ_SER_RX     0x5f
+#define MVME16x_IRQ_TIMER      0x59
+#define MVME167_IRQ_ABORT      0x6e
+#define MVME162_IRQ_ABORT      0x5e
 
 /* SCC interrupts, for MVME162 */
-#define IRQ_MVME162_SCC_BASE           0x40
-#define IRQ_MVME162_SCCB_TX            0x40
-#define IRQ_MVME162_SCCB_STAT          0x42
-#define IRQ_MVME162_SCCB_RX            0x44
-#define IRQ_MVME162_SCCB_SPCOND                0x46
-#define IRQ_MVME162_SCCA_TX            0x48
-#define IRQ_MVME162_SCCA_STAT          0x4a
-#define IRQ_MVME162_SCCA_RX            0x4c
-#define IRQ_MVME162_SCCA_SPCOND                0x4e
+#define MVME162_IRQ_SCC_BASE           0x40
+#define MVME162_IRQ_SCCB_TX            0x40
+#define MVME162_IRQ_SCCB_STAT          0x42
+#define MVME162_IRQ_SCCB_RX            0x44
+#define MVME162_IRQ_SCCB_SPCOND                0x46
+#define MVME162_IRQ_SCCA_TX            0x48
+#define MVME162_IRQ_SCCA_STAT          0x4a
+#define MVME162_IRQ_SCCA_RX            0x4c
+#define MVME162_IRQ_SCCA_SPCOND                0x4e
 
 /* MVME162 version register */
 
@@ -85,34 +107,4 @@ extern unsigned short mvme16x_config;
 #define MVME16x_CONFIG_GOT_SCCA                0x0400
 #define MVME16x_CONFIG_GOT_SCCB                0x0800
 
-/* Specials for the ethernet driver */
-
-#define CA()           (((struct i596_reg *)dev->base_addr)->ca = 1)
-
-#define MPU_PORT(c,x)  \
-  ((struct i596_reg *)(dev->base_addr))->porthi = ((c) | (u32)(x)) & 0xffff; \
-  ((struct i596_reg *)(dev->base_addr))->portlo = ((c) | (u32)(x)) >> 16
-
-#define SCP_SYSBUS     0x00000054
-
-#define WSWAPrfd(x)    ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPrbd(x)    ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPiscp(x)   ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPscb(x)    ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPcmd(x)    ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPtbd(x)    ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPchar(x)   ((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-
-/*
- * The MPU_PORT command allows direct access to the 82596. With PORT access
- * the following commands are available (p5-18). The 32-bit port command
- * must be word-swapped with the most significant word written first.
- */
-#define PORT_RESET     0x00    /* reset 82596 */
-#define PORT_SELFTEST  0x01    /* selftest */
-#define PORT_ALTSCP    0x02    /* alternate SCB address */
-#define PORT_ALTDUMP   0x03    /* Alternate DUMP address */
-
-#define ISCP_BUSY      0x00010000
-
-#endif /* _M68K_MVME16xHW_H_ */
+#endif
index 8b7d3c45d560709bd14fe0ead8bcfd3cc843f294..0a13816da42b4467a7277b3f1a5bc9c10ecb3aed 100644 (file)
@@ -328,6 +328,16 @@ typedef pte_table pte_tablepage[PTE_TABLES_PER_PAGE];
  * and initialized in head.S */
 extern int m68k_pgtable_cachemode;
 
+/* This is the cache mode for normal pages, for supervisor access on
+ * processors >= '040. It is used in pte_mkcache(), and the variable is
+ * defined and initialized in head.S */
+
+#if defined(CONFIG_060_WRITETHROUGH)
+extern int m68k_supervisor_cachemode;
+#else
+#define m68k_supervisor_cachemode _PAGE_CACHE040
+#endif
+
 #if defined(CPU_M68040_OR_M68060_ONLY)
 #define mm_cachebits _PAGE_CACHE040
 #elif defined(CPU_M68020_OR_M68030_ONLY)
@@ -495,7 +505,7 @@ extern inline pte_t pte_mknocache(pte_t pte)
        pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_pgtable_cachemode;
        return pte;
 }
-extern inline pte_t pte_mkcache(pte_t pte)     { pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | _PAGE_CACHE040; return pte; }
+extern inline pte_t pte_mkcache(pte_t pte)     { pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_supervisor_cachemode; return pte; }
 
 /* to set the page-dir */
 extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
index f25c9a9320383d70801508c7d68858ef89f79058..01a781c9989f76776ccc294d1faf2127fcdc39b4 100644 (file)
@@ -19,7 +19,7 @@
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_BASE(off)        0xC0000000UL
+#define TASK_UNMAPPED_BASE     0xC0000000UL
 #define TASK_UNMAPPED_ALIGN(addr, off) PAGE_ALIGN(addr)
 
 /*
@@ -72,6 +72,9 @@ static inline void release_thread(struct task_struct *dead_task)
 {
 }
 
+#define copy_segments(nr, tsk, mm)     do { } while (0)
+#define release_segments(mm)           do { } while (0)
+
 /*
  * Free current thread data structures etc..
  */
@@ -84,20 +87,17 @@ static inline void exit_thread(void)
  */
 extern inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
-       extern int sys_pause(void);
-       extern void schedule(void);
+       extern void scheduling_functions_start_here(void);
+       extern void scheduling_functions_end_here(void);
        struct switch_stack *sw = (struct switch_stack *)t->ksp;
        /* Check whether the thread is blocked in resume() */
-       if (sw->retpc >= (unsigned long)schedule &&
-           sw->retpc < (unsigned long)sys_pause)
+       if (sw->retpc > (unsigned long)scheduling_functions_start_here &&
+           sw->retpc < (unsigned long)scheduling_functions_end_here)
                return ((unsigned long *)sw->a6)[1];
        else
                return sw->retpc;
 }
 
-#define copy_segments(nr, tsk, mm)     do { } while (0)
-#define release_segments(mm)           do { } while (0)
-
 /* Allocation and freeing of basic task resources. */
 #define alloc_task_struct() \
        ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
index bc30f6e560ef4dd68b23ee9746bb10e90f90ce60..191c5d551299867c6b0105e0ed065e6a2e252128 100644 (file)
@@ -34,6 +34,8 @@
 #define SER_WHIPPET    108     /* Amiga Hisoft Whippet PCMCIA (16c550B) */
 #define SER_SCC_MVME   109     /* MVME162/MVME172 ports */
 #define SER_SCC_MAC    110     /* Macintosh SCC channel */
+#define SER_HPDCA      111     /* HP DCA serial */
+#define SER_SCC_BVME   112     /* BVME6000 ports */
 
 struct serial_struct {
        int     type;
index 16cd23c125be1d14a9eed231de194c75a3005e8b..a3084e04d37f0f3c6e40583fb33aed463b968deb 100644 (file)
@@ -38,6 +38,7 @@
 #define MACH_MVME147  6
 #define MACH_MVME16x  7
 #define MACH_BVME6000 8
+#define MACH_HP300    9
 
 #ifdef __KERNEL__
 
@@ -48,10 +49,10 @@ extern u_long m68k_machtype;
 #if !defined(CONFIG_AMIGA)
 #  define MACH_IS_AMIGA (0)
 #elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
-       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
 #  define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA)
 #else
-#  define MACH_AMIGA_ONLY
+#  define CONFIG_AMIGA_ONLY
 #  define MACH_IS_AMIGA (1)
 #  define MACH_TYPE (MACH_AMIGA)
 #endif
@@ -59,17 +60,18 @@ extern u_long m68k_machtype;
 #if !defined(CONFIG_ATARI)
 #  define MACH_IS_ATARI (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
-       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
 #  define MACH_IS_ATARI (m68k_machtype == MACH_ATARI)
 #else
-#  define MACH_ATARI_ONLY
+#  define CONFIG_ATARI_ONLY
 #  define MACH_IS_ATARI (1)
 #  define MACH_TYPE (MACH_ATARI)
 #endif
 
 #if !defined(CONFIG_MAC)
 #  define MACH_IS_MAC (0)
-#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \
+       || defined(CONFIG_HP300) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
 #  define MACH_IS_MAC (m68k_machtype == MACH_MAC)
 #else
 #  define CONFIG_MAC_ONLY
@@ -86,7 +88,7 @@ extern u_long m68k_machtype;
 #if !defined (CONFIG_APOLLO)
 #  define MACH_IS_APOLLO (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
 #  define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO)
 #else
 #  define CONFIG_APOLLO_ONLY
@@ -97,7 +99,7 @@ extern u_long m68k_machtype;
 #if !defined (CONFIG_MVME16x)
 #  define MACH_IS_MVME16x (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-       || defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)
+       || defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
 #  define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x)
 #else
 #  define CONFIG_MVME16x_ONLY
@@ -108,7 +110,7 @@ extern u_long m68k_machtype;
 #if !defined (CONFIG_BVME6000)
 #  define MACH_IS_BVME6000 (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-       || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)
+       || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_HP300)
 #  define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000)
 #else
 #  define CONFIG_BVME6000_ONLY
@@ -116,6 +118,16 @@ extern u_long m68k_machtype;
 #  define MACH_TYPE (MACH_BVME6000)
 #endif
 
+#if !defined (CONFIG_HP300)
+#  define MACH_IS_HP300 (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+       || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+#  define MAC_IS_HP300 (m68k_machtype == MACH_HP300)
+#else
+#  define CONFIG_HP300_ONLY
+#  define MACH_IS_HP300 (1)
+#  define MACH_TYPE (MACH_HP300)
+#endif
 
 #ifndef MACH_TYPE
 #  define MACH_TYPE (m68k_machtype)
index 5fa3fa67e58b441b44afbb3cb16a52d3d1097d9a..b06ef713912e9a773e2068b69ea37b267c251921 100644 (file)
@@ -142,11 +142,18 @@ struct k_sigaction {
 /* Here we must cater to libcs that poke about in kernel headers.  */
 
 struct sigaction {
-       __sighandler_t sa_handler;
+       union {
+         __sighandler_t _sa_handler;
+         void (*_sa_sigaction)(int, struct siginfo *, void *);
+       } _u;
        sigset_t sa_mask;
        unsigned long sa_flags;
        void (*sa_restorer)(void);
 };
+
+#define sa_handler     _u._sa_handler
+#define sa_sigaction   _u._sa_sigaction
+
 #endif /* __KERNEL__ */
 
 typedef struct sigaltstack {
index 76092a5423789621c2923f6f731f12116a1daf78..2e35a9e827a62b77231d5bf1c2b2abb3d9592f52 100644 (file)
@@ -38,6 +38,7 @@ struct stat {
        unsigned long  __unused5;
 };
 
+#if 0
 typedef struct {
        unsigned int    major;
        unsigned int    minor;
@@ -62,6 +63,7 @@ struct stat64 {
        unsigned long   st_blksize;
        unsigned long   __unused4;
 };
+#endif
 
 #define __XSTAT_VER_1          1
 #define __XSTAT_VER_2          2
index 729f7b34b4a51f3ac9c81095165f7baa255c8a64..cee722633163ccccafb9e8c362405bbf6224840d 100644 (file)
@@ -60,7 +60,7 @@ asmlinkage void resume(void);
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((volatile struct __xchg_dummy *)(x))
 
-#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) && !defined(CONFIG_HADES)
+#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) && !defined(CONFIG_HADES) && !defined(CONFIG_VME) && !defined(CONFIG_APOLLO)
 /* block out HSYNC on the atari */
 #define __sti() __asm__ __volatile__ ("andiw #0xfbff,%/sr": : : "memory")
 #else /* portable version */
index df55187a678916a2a9d212727e71b73eda94cfd1..34a8c6dac49a52158d7f6a7ac52a16e62591e4be 100644 (file)
 #define __NR_pread             180
 #define __NR_pwrite            181
 #define __NR_lchown            182
+#define __NR_getcwd            183
+#define __NR_capget            184
+#define __NR_capset            185
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
index 89668887e1232a195c68987fdabebeb1e21c5ff4..f7944dd081bd33d3f1991a376e8744c8129b91ad 100644 (file)
@@ -372,6 +372,23 @@ extern __inline__ unsigned long ffz(unsigned long word)
        return __res;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
 #ifdef __MIPSEB__
 /* For now I steal the Sparc C versions, no need for speed, just need to
  * get it working.
index 0a848013d3bd190d5ab202cda9b2b7dc7ef1bb13..340ef60f8b75f89b6f2d35ea742e2f66eacd9c2b 100644 (file)
@@ -96,6 +96,34 @@ extern __inline__ int ffz(unsigned int x)
        return 31 - n;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+#if 0
+/* untested, someone with PPC knowledge? */
+/* From Alexander Kjeldaas <astor@guardian.no> */
+extern __inline__ int ffs(int x)
+{
+        int result;
+        asm ("cntlzw %0,%1" : "=r" (result) : "r" (x));
+        return 32 - result; /* IBM backwards ordering of bits */
+}
+#endif
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
 /*
  * This implementation of find_{first,next}_zero_bit was stolen from
  * Linus' asm-alpha/bitops.h.
index dbc259cb6805b4c3e287c32b808a442c356df6b1..088230d2c5af66d8a604398367a742222cc39fcf 100644 (file)
@@ -182,6 +182,24 @@ extern __inline__ unsigned long ffz(unsigned long word)
        return result;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
 /* find_next_zero_bit() finds the first zero bit in a bit string of length
  * 'size' bits, starting the search at bit 'offset'. This is largely based
  * on Linus's ALPHA routines, which are pretty portable BTW.
index e8b600eb0423807b157a36f5173b30fba46e7745..dfe91d58512896068956ba12fddef2cd0a6e0437 100644 (file)
@@ -186,6 +186,53 @@ extern __inline__ unsigned long ffz(unsigned long word)
        return result;
 }
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#ifdef ULTRA_HAS_POPULATION_COUNT
+
+extern __inline__ unsigned int hweight32(unsigned int w)
+{
+       unsigned int res;
+
+       __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
+       return res;
+}
+
+extern __inline__ unsigned int hweight16(unsigned int w)
+{
+       unsigned int res;
+
+       __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
+       return res;
+}
+
+extern __inline__ unsigned int hweight8(unsigned int w)
+{
+       unsigned int res;
+
+       __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff));
+       return res;
+}
+
+#else
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+#endif
+
 /* find_next_zero_bit() finds the first zero bit in a bit string of length
  * 'size' bits, starting the search at bit 'offset'. This is largely based
  * on Linus's ALPHA routines, which are pretty portable BTW.
index 453bb9258cbad6f5df1a1f8c2010215c2d5afee8..fe4e79e4b0827e36b46aa9953dd674107e9af6ef 100644 (file)
@@ -111,30 +111,22 @@ union adfs_dirtail {
 };
 
 #ifdef __KERNEL__
-
-
 /*
  * Calculate the boot block checksum on an ADFS drive.  Note that this will
  * appear to be correct if the sector contains all zeros, so also check that
  * the disk size is non-zero!!!
  */
 extern inline int adfs_checkbblk(unsigned char *ptr)
 {
-       int i = 511;
-
-       int result = 0;
+       unsigned int result = 0;
+       unsigned char *p = ptr + 511;
 
        do {
-               result = (result & 0xff) + (result >> 8);
-               result = result + ptr[i];
-               i--;
-       }
-       while (i != 0);
-       
-       result &= 0xff;
-       return result != ptr[511];
-       return 0;
+               result = (result & 0xff) + (result >> 8);
+               result = result + *--p;
+       } while (p != ptr);
+
+       return (result & 0xff) != ptr[511];
 }
 
 /* dir.c */
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
new file mode 100644 (file)
index 0000000..ddb84dd
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef _LINUX_BITOPS_H
+#define _LINUX_BITOPS_H
+
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+extern __inline__ int generic_ffs(int x)
+{
+       int r = 1;
+
+       if (!x)
+               return 0;
+       if (!(x & 0xffff)) {
+               x >>= 16;
+               r += 16;
+       }
+       if (!(x & 0xff)) {
+               x >>= 8;
+               r += 8;
+       }
+       if (!(x & 0xf)) {
+               x >>= 4;
+               r += 4;
+       }
+       if (!(x & 3)) {
+               x >>= 2;
+               r += 2;
+       }
+       if (!(x & 1)) {
+               x >>= 1;
+               r += 1;
+       }
+       return r;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+extern __inline__ unsigned int generic_hweight32(unsigned int w)
+{
+        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+extern __inline__ unsigned int generic_hweight16(unsigned int w)
+{
+        unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
+        res = (res & 0x3333) + ((res >> 2) & 0x3333);
+        res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
+        return (res & 0x00FF) + ((res >> 8) & 0x00FF);
+}
+
+extern __inline__ unsigned int generic_hweight8(unsigned int w)
+{
+        unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
+        res = (res & 0x33) + ((res >> 2) & 0x33);
+        return (res & 0x0F) + ((res >> 4) & 0x0F);
+}
+
+#include <asm/bitops.h>
+
+
+#endif
index 65cd353bb95f2e2997d791f35d71698849e10e6a..c4a31be95a6b30607008444eec7f2d59cd135b11 100644 (file)
@@ -339,6 +339,15 @@ static void floppy_off(unsigned int nr);
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
+#elif (MAJOR_NR == MFM_ACORN_MAJOR)
+
+#define DEVICE_NAME "mfm disk"
+#define DEVICE_INTR do_mfm
+#define DEVICE_REQUEST do_mfm_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
 #elif (MAJOR_NR == NBD_MAJOR)
 
 #define DEVICE_NAME "nbd"
diff --git a/include/linux/dio.h b/include/linux/dio.h
new file mode 100644 (file)
index 0000000..087b06e
--- /dev/null
@@ -0,0 +1,204 @@
+/* header file for DIO boards for the HP300 architecture.
+ * Maybe this should handle DIO-II later?
+ * The general structure of this is vaguely based on how
+ * the Amiga port handles Zorro boards.
+ * Copyright (C) Peter Maydell 05/1998 <pmaydell@chiark.greenend.org.uk>
+ *
+ * The board IDs are from the NetBSD kernel, which for once provided
+ * helpful comments...
+ *
+ * This goes with arch/m68k/hp300/dio.c
+ */
+
+#ifndef _LINUX_DIO_H
+#define _LINUX_DIO_H
+
+/* The DIO boards in a system are distinguished by 'select codes' which 
+ * range from 0-63 (DIO) and 132-255 (DIO-II). 
+ * The DIO board with select code sc is located at physical address 
+ *     0x600000 + sc * 0x10000
+ * So DIO cards cover [0x600000-0x800000); the areas [0x200000-0x400000) and
+ * [0x800000-0x1000000) are for additional space required by things
+ * like framebuffers. [0x400000-0x600000) is for miscellaneous internal I/O.
+ * On Linux, this is currently all mapped into the virtual address space
+ * at 0xf0000000 on bootup.
+ * DIO-II boards are at 0x1000000 + (sc - 132) * 0x400000
+ * which is address range [0x1000000-0x20000000) -- too big to map completely,
+ * so currently we just don't handle DIO-II boards.  It wouldn't be hard to 
+ * do with ioremap() though.
+ */
+#ifdef __KERNEL__
+/* DIO/DIO-II boards all have the following 8bit registers.
+ * These are offsets from the base of the device.
+ */
+#define DIO_IDOFF     0x01                        /* primary device ID */
+#define DIO_IPLOFF    0x03                        /* interrupt priority level */
+#define DIO_SECIDOFF  0x15                        /* secondary device ID */
+#define DIOII_SIZEOFF 0x101                       /* device size, DIO-II only */
+
+/* The internal HPIB device is special; this is its physaddr; its select code is 7. 
+ * The reason why we have to treat it specially is because apparently it's broken:
+ * the device ID isn't consistent/reliable. *sigh*
+ */
+#define DIO_IHPIBADDR 0x47800
+#define DIO_IHPIBSCODE 7
+
+/* If we don't have the internal HPIB defined, then treat select code 7 like
+ * any other. If we *do* have internal HPIB, then we just have to assume that
+ * select code 7 is the internal HPIB regardless of the ID register :-<
+ */
+#define CONFIG_IHPIB /* hack hack : not yet a proper config option */
+#ifdef CONFIG_IHPIB
+#define DIO_ISIHPIB(scode) ((scode) == DIO_IHPIBSCODE)
+#else
+#define DIO_ISIHPIB(scode) 0
+#endif
+
+#define DIO_VIRADDRBASE 0xf0000000                /* vir addr where IOspace is mapped */
+
+#define DIO_BASE                0x600000        /* start of DIO space */
+#define DIO_END                 0x1000000       /* end of DIO space */
+#define DIO_DEVSIZE             0x10000         /* size of a DIO device */
+
+#define DIOII_BASE              0x01000000      /* start of DIO-II space */
+#define DIOII_END               0x20000000      /* end of DIO-II space */
+#define DIOII_DEVSIZE           0x00400000      /* size of a DIO-II device */
+
+/* Highest valid select code. If we add DIO-II support this should become
+ * 256 for everything except HP320, which only has DIO.
+ */
+#define DIO_SCMAX 32                             
+#define DIOII_SCBASE 132 /* lowest DIO-II select code */
+#define DIO_SCINHOLE(scode) (((scode) >= 32) && ((scode) < DIOII_SCBASE))
+
+/* macros to read device IDs, given base address */
+#define DIO_ID(baseaddr) readb((baseaddr) + DIO_IDOFF)
+#define DIO_SECID(baseaddr) readb((baseaddr) + DIO_SECIDOFF)
+
+/* extract the interrupt level */
+#define DIO_IPL(baseaddr) (((readb((baseaddr) + DIO_IPLOFF) >> 4) & 0x03) + 3)
+
+/* find the size of a DIO-II board's address space.
+ * DIO boards are all fixed length.
+ */
+#define DIOII_SIZE(baseaddr) ((readb((baseaddr) + DIOII_SIZEOFF) + 1) * 0x100000)
+
+/* general purpose macro for both DIO and DIO-II */
+#define DIO_SIZE(scode, base) (DIO_ISDIOII((scode)) ? DIOII_SIZE((base)) : DIO_DEVSIZE)
+
+/* The hardware has primary and secondary IDs; we encode these in a single
+ * int as PRIMARY ID & (SECONDARY ID << 8).
+ * In practice this is only important for framebuffers,
+ * and everybody else just sets ID fields equal to the DIO_ID_FOO value.
+ */
+#define DIO_ENCODE_ID(pr,sec) ((((int)sec & 0xff) << 8) & ((int)pr & 0xff))
+/* macro to determine whether a given primary ID requires a secondary ID byte */
+#define DIO_NEEDSSECID(id) ((id) == DIO_ID_FBUFFER)
+
+/* Now a whole slew of macros giving device IDs and descriptive strings: */
+#define DIO_ID_DCA0     0x02 /* 98644A serial */
+#define DIO_DESC_DCA0 "98644A DCA0 serial"
+#define DIO_ID_DCA0REM  0x82 /* 98644A serial */
+#define DIO_DESC_DCA0REM "98644A DCA0REM serial"
+#define DIO_ID_DCA1     0x42 /* 98644A serial */
+#define DIO_DESC_DCA1 "98644A DCA1 serial"
+#define DIO_ID_DCA1REM  0xc2 /* 98644A serial */
+#define DIO_DESC_DCA1REM "98644A DCA1REM serial"
+#define DIO_ID_DCM      0x05 /* 98642A serial MUX */
+#define DIO_DESC_DCM "98642A DCM serial MUX"
+#define DIO_ID_DCMREM   0x85 /* 98642A serial MUX */
+#define DIO_DESC_DCMREM "98642A DCMREM serial MUX"
+#define DIO_ID_LAN      0x15 /* 98643A LAN */
+#define DIO_DESC_LAN "98643A LAN"
+#define DIO_ID_FHPIB    0x08 /* 98625A/98625B fast HP-IB */
+#define DIO_DESC_FHPIB "98625A/98625B fast HPIB"
+#define DIO_ID_NHPIB    0x80 /* 98624A HP-IB (normal ie slow) */
+#define DIO_DESC_NHPIB "98624A HPIB"
+#define DIO_ID_IHPIB    0x00 /* internal HPIB (not its real ID, it hasn't got one! */
+#define DIO_DESC_IHPIB "internal HPIB"
+#define DIO_ID_SCSI0    0x07 /* 98625A SCSI */
+#define DIO_DESC_SCSI0 "98625A SCSI0"
+#define DIO_ID_SCSI1    0x27 /* ditto */
+#define DIO_DESC_SCSI1 "98625A SCSI1"
+#define DIO_ID_SCSI2    0x47 /* ditto */
+#define DIO_DESC_SCSI2 "98625A SCSI2"
+#define DIO_ID_SCSI3    0x67 /* ditto */
+#define DIO_DESC_SCSI3 "98625A SCSI3"
+#define DIO_ID_FBUFFER  0x39 /* framebuffer: flavour is distinguished by secondary ID */
+#define DIO_DESC_FBUFFER "bitmapped display"
+/* the NetBSD kernel source is a bit unsure as to what these next IDs actually do :-> */
+#define DIO_ID_MISC0    0x03 /* 98622A */
+#define DIO_DESC_MISC0 "98622A"
+#define DIO_ID_MISC1    0x04 /* 98623A */
+#define DIO_DESC_MISC1 "98623A"
+#define DIO_ID_PARALLEL 0x06 /* internal parallel */
+#define DIO_DESC_PARALLEL "internal parallel"
+#define DIO_ID_MISC2    0x09 /* 98287A keyboard */
+#define DIO_DESC_MISC2 "98287A keyboard"
+#define DIO_ID_MISC3    0x0a /* HP98635A FP accelerator */
+#define DIO_DESC_MISC3 "HP98635A FP accelerator"
+#define DIO_ID_MISC4    0x0b /* timer */
+#define DIO_DESC_MISC4 "timer"
+#define DIO_ID_MISC5    0x12 /* 98640A */
+#define DIO_DESC_MISC5 "98640A"
+#define DIO_ID_MISC6    0x16 /* 98659A */
+#define DIO_DESC_MISC6 "98659A"
+#define DIO_ID_MISC7    0x19 /* 237 display */
+#define DIO_DESC_MISC7 "237 display"
+#define DIO_ID_MISC8    0x1a /* quad-wide card */
+#define DIO_DESC_MISC8 "quad-wide card"
+#define DIO_ID_MISC9    0x1b /* 98253A */
+#define DIO_DESC_MISC9 "98253A"
+#define DIO_ID_MISC10   0x1c /* 98627A */
+#define DIO_DESC_MISC10 "98253A"
+#define DIO_ID_MISC11   0x1d /* 98633A */
+#define DIO_DESC_MISC11 "98633A"
+#define DIO_ID_MISC12   0x1e /* 98259A */
+#define DIO_DESC_MISC12 "98259A"
+#define DIO_ID_MISC13   0x1f /* 8741 */
+#define DIO_DESC_MISC13 "8741"
+#define DIO_ID_VME      0x31 /* 98577A VME adapter */
+#define DIO_DESC_VME "98577A VME adapter"
+#define DIO_ID_DCL      0x34 /* 98628A serial */
+#define DIO_DESC_DCL "98628A DCL serial"
+#define DIO_ID_DCLREM   0xb4 /* 98628A serial */
+#define DIO_DESC_DCLREM "98628A DCLREM serial"
+/* These are the secondary IDs for the framebuffers */
+#define DIO_ID2_GATORBOX    0x01 /* 98700/98710 "gatorbox" */
+#define DIO_DESC2_GATORBOX       "98700/98710 \"gatorbox\" display"
+#define DIO_ID2_TOPCAT      0x02 /* 98544/98545/98547 "topcat" */
+#define DIO_DESC2_TOPCAT         "98544/98545/98547 \"topcat\" display"
+#define DIO_ID2_RENAISSANCE 0x04 /* 98720/98721 "renaissance" */
+#define DIO_DESC2_RENAISSANCE    "98720/98721 \"renaissance\" display"
+#define DIO_ID2_LRCATSEYE   0x05 /* lowres "catseye" */
+#define DIO_DESC2_LRCATSEYE      "low-res catseye display"
+#define DIO_ID2_HRCCATSEYE  0x06 /* highres colour "catseye" */
+#define DIO_DESC2_HRCCATSEYE     "high-res color catseye display"
+#define DIO_ID2_HRMCATSEYE  0x07 /* highres mono "catseye" */
+#define DIO_DESC2_HRMCATSEYE     "high-res mono catseye display"
+#define DIO_ID2_DAVINCI     0x08 /* 98730/98731 "davinci" */
+#define DIO_DESC2_DAVINCI        "98730/98731 \"davinci\" display"
+#define DIO_ID2_XXXCATSEYE  0x09 /* "catseye" */
+#define DIO_DESC2_XXXCATSEYE     "catseye display"
+#define DIO_ID2_HYPERION    0x0e /* A1096A "hyperion" */
+#define DIO_DESC2_HYPERION       "A1096A \"hyperion\" display"
+#define DIO_ID2_XGENESIS    0x0b /* "x-genesis"; no NetBSD support */
+#define DIO_DESC2_XGENESIS       "\"x-genesis\" display"
+#define DIO_ID2_TIGER       0x0c /* "tiger"; no NetBSD support */
+#define DIO_DESC2_TIGER          "\"tiger\" display"
+#define DIO_ID2_YGENESIS    0x0d /* "y-genesis"; no NetBSD support */
+#define DIO_DESC2_YGENESIS       "\"y-genesis\" display"
+/* if you add new IDs then you should tell dio.c about them so it can
+ * identify them...
+ */
+
+extern void dio_init(void);
+extern int dio_find(int deviceid);
+extern void *dio_scodetoviraddr(int scode);
+extern int dio_scodetoipl(int scode);
+extern void dio_config_board(int scode);
+extern void dio_unconfig_board(int scode);
+
+
+#endif /* __KERNEL__ */
+#endif /* ndef _LINUX_DIO_H */
index a6445383965eac4d944422c1378bcdac541c795f..61f25c30a2a05be766bd451ee23a4e64bf4e7ca8 100644 (file)
@@ -18,7 +18,6 @@
 #define RTCF_MASQ      0x00400000
 #define RTCF_SNAT      0x00800000
 #define RTCF_DOREDIRECT 0x01000000
-#define RTCF_LOG       0x02000000
 #define RTCF_DIRECTSRC 0x04000000
 #define RTCF_DNAT      0x08000000
 #define RTCF_BROADCAST 0x10000000
index a81dc12969174a9db91390bbe445791929d1d425..30a14b169ac5c2df2e1c9062883c736405f78e11 100644 (file)
@@ -182,6 +182,7 @@ extern char * get_rock_ridge_symlink(struct inode *);
 extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *);
 
 int get_joliet_filename(struct iso_directory_record *, struct inode *, unsigned char *);
+int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
 
 /* The stuff that follows may be totally unneeded. I have not checked to see 
  which prototypes we are still using.  */
@@ -227,6 +228,3 @@ extern void leak_check_brelse(struct buffer_head * bh);
 #endif /* __KERNEL__ */
 
 #endif
-
-
-
index 834ae348bddafff6b3762782b26af644f794716b..879f8faf3e14de70ad799ec769a81b9203b5da1f 100644 (file)
@@ -30,10 +30,3 @@ struct isofs_sb_info {
 };
 
 #endif
-
-
-
-
-
-
-
index 20a8cd66da6f1dfdb0536ad1f37d896005791a9a..6b9b6d64988dfb7e3d94997f7494908a7874116d 100644 (file)
@@ -15,6 +15,7 @@
 
 /* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
 #define MINIX_LINK_MAX 250
+#define MINIX2_LINK_MAX        65530
 
 #define MINIX_I_MAP_SLOTS      8
 #define MINIX_Z_MAP_SLOTS      64
@@ -126,6 +127,7 @@ extern int minix_sync_file(struct file *, struct dentry *);
 extern struct inode_operations minix_file_inode_operations;
 extern struct inode_operations minix_dir_inode_operations;
 extern struct inode_operations minix_symlink_inode_operations;
+extern struct dentry_operations minix_dentry_operations;
 
 #endif /* __KERNEL__ */
 
index c533e63ac29872597c50c9d6d1babad9bb8aa7f5..54c82af99a8f1652a8bb03441927b3f7a152d8ad 100644 (file)
@@ -12,8 +12,9 @@ struct minix_sb_info {
                        unsigned long s_firstdatazone;
                        unsigned long s_log_zone_size;
                        unsigned long s_max_size;
-                       unsigned long s_dirsize;
-                       unsigned long s_namelen;
+                       int s_dirsize;
+                       int s_namelen;
+                       int s_link_max;
                        struct buffer_head ** s_imap;
                        struct buffer_head ** s_zmap;
                        struct buffer_head * s_sbh;
index 39baffea081fd2a482323bd8fc05f73e8560411a..0a1a5dd12e8f8d4a40dbf834dc0958b50eb5253a 100644 (file)
@@ -290,6 +290,7 @@ extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t p
 
 extern void vmtruncate(struct inode * inode, unsigned long offset);
 extern void handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
+extern void check_pgt_cache(void);
 
 extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
 extern void mem_init(unsigned long start_mem, unsigned long end_mem);
index aa9568e837f45ebf4f70cf5de1a171ec1d587efc..64470ba580f67257cabe5a9f5ae9019c07824315 100644 (file)
@@ -253,6 +253,7 @@ struct device
        
        void                    *atalk_ptr;     /* Appletalk link       */
        void                    *ip_ptr;        /* IPv4 specific data   */  
+       void                    *dn_ptr;        /* DECnet specific data */
 
        struct Qdisc            *qdisc;
        struct Qdisc            *qdisc_sleeping;
index d7f0851feb04c9655cf7749b034ed6b7d60a0ae4..aea15a68b105d2ead12f16be928f3123e81d8908 100644 (file)
@@ -60,6 +60,7 @@ struct readdir_cd {
 };
 typedef int            (*encode_dent_fn)(struct readdir_cd *, const char *,
                                                int, off_t, ino_t);
+typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
 
 /*
  * Procedure table for NFSv2
@@ -72,6 +73,8 @@ extern struct svc_program     nfsd_program;
  */
 int            nfsd_svc(unsigned short port, int nrservs);
 
+/* nfsd/vfs.c */
+int            fh_lock_parent(struct svc_fh *, struct dentry *);
 void           nfsd_racache_init(void);
 int            nfsd_lookup(struct svc_rqst *, struct svc_fh *,
                                const char *, int, struct svc_fh *);
index 82eb88260edd9cbfec61b0a8aa8fdf977d033541..91e7d88d1d3e03fe7cd02ebf0ef4735a9babc1e9 100644 (file)
@@ -106,6 +106,11 @@ struct parport_operations {
        void (*release_resources)(struct parport *);
        int (*claim_resources)(struct parport *);
 
+       void (*epp_write_data)(struct parport *, unsigned char);
+       unsigned char (*epp_read_data)(struct parport *);
+       void (*epp_write_addr)(struct parport *, unsigned char);
+       unsigned char (*epp_read_addr)(struct parport *);
+       int (*epp_check_timeout)(struct parport *);
        size_t (*epp_write_block)(struct parport *, void *, size_t);
        size_t (*epp_read_block)(struct parport *, void *, size_t);
 
@@ -330,6 +335,11 @@ extern void (*parport_probe_hook)(struct parport *port);
 #define parport_change_mode(p,m)           parport_pc_change_mode(p,m)
 #define parport_release_resources(p)       parport_pc_release_resources(p)
 #define parport_claim_resources(p)         parport_pc_claim_resources(p)
+#define parport_epp_write_data(p,x)        parport_pc_write_epp(p,x)
+#define parport_epp_read_data(p)           parport_pc_read_epp(p)
+#define parport_epp_write_addr(p,x)        parport_pc_write_epp_addr(p,x)
+#define parport_epp_read_addr(p)           parport_pc_read_epp_addr(p)
+#define parport_epp_check_timeout(p)       parport_pc_check_epp_timeout(p)
 #endif
 
 #ifdef PARPORT_NEED_GENERIC_OPS
@@ -349,6 +359,11 @@ extern void (*parport_probe_hook)(struct parport *port);
 #define parport_change_mode(p,m)           (p)->ops->change_mode(p,m)
 #define parport_release_resources(p)       (p)->ops->release_resources(p)
 #define parport_claim_resources(p)         (p)->ops->claim_resources(p)
+#define parport_epp_write_data(p,x)        (p)->ops->epp_write_data(p,x)
+#define parport_epp_read_data(p)           (p)->ops->epp_read_data(p)
+#define parport_epp_write_addr(p,x)        (p)->ops->epp_write_addr(p,x)
+#define parport_epp_read_addr(p)           (p)->ops->epp_read_addr(p)
+#define parport_epp_check_timeout(p)       (p)->ops->epp_check_timeout(p)
 #endif
 
 #endif /* __KERNEL__ */
index 86877ab86a5b46b1fc5de6ed0c1d34387de64f7b..b61a970a72b613bc0cd84bf8da3ec998ea64dd5b 100644 (file)
@@ -8,19 +8,41 @@
 #define ECONTROL 0x402
 #define CONFIGB  0x401
 #define CONFIGA  0x400
-#define EPPREG   0x4
+#define EPPDATA  0x4
+#define EPPADDR  0x3
 #define CONTROL  0x2
 #define STATUS   0x1
 #define DATA     0
 
+extern int parport_pc_epp_clear_timeout(struct parport *pb);
+
+
 extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
-       outb(d, p->base+EPPREG);
+       outb(d, p->base+EPPDATA);
 }
 
 extern __inline__ unsigned char parport_pc_read_epp(struct parport *p)
 {
-       return inb(p->base+EPPREG);
+       return inb(p->base+EPPDATA);
+}
+
+extern __inline__ void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
+{
+       outb(d, p->base+EPPADDR);
+}
+
+extern __inline__ unsigned char parport_pc_read_epp_addr(struct parport *p)
+{
+       return inb(p->base+EPPADDR);
+}
+
+extern __inline__ int parport_pc_check_epp_timeout(struct parport *p)
+{
+       if (!(inb(p->base+STATUS) & 1))
+               return 0;
+       parport_pc_epp_clear_timeout(p);
+       return 1;
 }
 
 extern __inline__ unsigned char parport_pc_read_configb(struct parport *p)
diff --git a/include/linux/pg.h b/include/linux/pg.h
new file mode 100644 (file)
index 0000000..c752a97
--- /dev/null
@@ -0,0 +1,63 @@
+/*     pg.h (c) 1998  Grant R. Guenther <grant@torque.net>
+                      Under the terms of the GNU public license
+
+
+       pg.h defines the user interface to the generic ATAPI packet
+        command driver for parallel port ATAPI devices (pg). The
+       driver is loosely modelled after the generic SCSI driver, sg,
+       although the actual interface is different.
+
+       The pg driver provides a simple character device interface for
+        sending ATAPI commands to a device.  With the exception of the
+       ATAPI reset operation, all operations are performed by a pair
+        of read and write operations to the appropriate /dev/pgN device.
+       A write operation delivers a command and any outbound data in
+        a single buffer.  Normally, the write will succeed unless the
+        device is offline or malfunctioning, or there is already another
+       command pending.  If the write succeeds, it should be followed
+        immediately by a read operation, to obtain any returned data and
+        status information.  A read will fail if there is no operation
+        in progress.
+
+       As a special case, the device can be reset with a write operation,
+        and in this case, no following read is expected, or permitted.
+
+       There are no ioctl() operations.  Any single operation
+       may transfer at most PG_MAX_DATA bytes.  Note that the driver must
+        copy the data through an internal buffer.  In keeping with all
+       current ATAPI devices, command packets are assumed to be exactly
+       12 bytes in length.
+
+       To permit future changes to this interface, the headers in the
+       read and write buffers contain a single character "magic" flag.
+        Currently this flag must be the character "P".
+
+*/
+
+#define PG_MAGIC       'P'
+#define PG_RESET       'Z'
+#define PG_COMMAND     'C'
+
+#define PG_MAX_DATA    32768
+
+struct pg_write_hdr {
+
+       char    magic;          /* == PG_MAGIC */
+       char    func;           /* PG_RESET or PG_COMMAND */
+       int     dlen;           /* number of bytes expected to transfer */
+       int     timeout;        /* number of seconds before timeout */
+       char    packet[12];     /* packet command */
+
+};
+
+struct pg_read_hdr {
+
+       char    magic;          /* == PG_MAGIC */
+       char    scsi;           /* "scsi" status == sense key */
+       int     dlen;           /* size of device transfer request */
+       int     duration;       /* time in seconds command took */
+       char    pad[12];        /* not used */
+
+};
+
+/* end of pg.h */
index b849b575163c0edb0bd7e5e6a047ca5bb95f8862..c4065bc12d77d2443c9d12afe67e999e737526d6 100644 (file)
@@ -79,8 +79,8 @@ int get_fd_set(unsigned long nr, void *ufdset, unsigned long *fdset)
        if (ufdset) {
                int error;
                error = verify_area(VERIFY_WRITE, ufdset, nr);
-               if (!error)
-                       error = __copy_from_user(fdset, ufdset, nr);
+               if (!error && __copy_from_user(fdset, ufdset, nr))
+                       error = -EFAULT;
                return error;
        }
        memset(fdset, 0, nr);
index af6c67d53c99e35ddf72c408fd71a00a6b134c9f..c7cbee88563ba9c7227d2d50de9381734a17f205 100644 (file)
@@ -49,6 +49,7 @@ enum root_directory_inos {
        PROC_SLABINFO,
        PROC_PARPORT,
        PROC_PPC_HTAB,
+       PROC_STRAM,
        PROC_SOUND,
        PROC_MTRR, /* whether enabled or not */
        PROC_FS
index b0efb81a923a92c2b9e5e1fc670039a2490934cc..4c8adc508c9c4d5379f04ccce982473a2bbac73b 100644 (file)
@@ -658,7 +658,7 @@ extern __inline__ void rtnl_shunlock(void)
        atomic_dec(&rtnl_rlockct);
        if (atomic_read(&rtnl_rlockct) <= 1) {
                wake_up(&rtnl_wait);
-               if (rtnl->receive_queue.qlen)
+               if (rtnl && rtnl->receive_queue.qlen)
                        rtnl->data_ready(rtnl, 0);
        }
 }
@@ -672,7 +672,7 @@ extern __inline__ void rtnl_shunlock(void)
        atomic_dec(&rtnl_rlockct); \
        if (atomic_read(&rtnl_rlockct) <= 1) { \
                wake_up(&rtnl_wait); \
-               if (rtnl->receive_queue.qlen) \
+               if (rtnl && rtnl->receive_queue.qlen) \
                        rtnl->data_ready(rtnl, 0); \
        } \
 })
index ff193cd24f79595660b2cfeb743769f54ce306b2..d6e82ae0535d21281de563bddc201a16f77fe7fa 100644 (file)
@@ -162,6 +162,8 @@ extern inline void sigfillset(sigset_t *set)
        }
 }
 
+extern char * render_sigset_t(sigset_t *set, char *buffer);
+
 /* Some extensions for manipulating the low 32 signals in particular.  */
 
 extern inline void sigaddsetmask(sigset_t *set, unsigned long mask)
index c407d7428988edc247ea5a63062c3f7a5eb6eb26..0c6fa215410d57f9db4fdf9dd042b77bbf206598 100644 (file)
@@ -75,6 +75,11 @@ extern struct swap_info_struct swap_info[];
 void si_swapinfo(struct sysinfo *);
 unsigned long get_swap_page(void);
 extern void FASTCALL(swap_free(unsigned long));
+struct swap_list_t {
+       int head;       /* head of priority-ordered swapfile list */
+       int next;       /* swapfile to be used next */
+};
+extern struct swap_list_t swap_list;
 
 /*
  * vm_ops not present page codes for shared memory.
index 20fe943bf6f3fd32f1bbc3d2db63e3d8972d3efb..ce33ca50f561011ef18cea422faca7912da8ac88 100644 (file)
@@ -80,7 +80,8 @@ enum
        VM_OVERCOMMIT_MEMORY,   /* Turn off the virtual memory safety limit */
        VM_BUFFERMEM,           /* struct: Set buffer memory thresholds */
        VM_PAGECACHE,           /* struct: Set cache memory thresholds */
-       VM_PAGERDAEMON          /* struct: Control kswapd behaviour */
+       VM_PAGERDAEMON,         /* struct: Control kswapd behaviour */
+       VM_PGT_CACHE            /* struct: Set page table cache parameters */
 };
 
 
index 2649014a18e9a8dcfffd72cea1525e6bbd086763..64c461b2ec6a76465913ff45401011bac970f0da 100644 (file)
@@ -71,4 +71,22 @@ extern inline void init_timer(struct timer_list * timer)
        timer->prev = NULL;
 }
 
+/*
+ *     These inlines deal with timer wrapping correctly. You are 
+ *     strongly encouraged to use them
+ *     1. Because people otherwise forget
+ *     2. Because if the timer wrap changes in future you wont have to
+ *        alter your driver code.
+ */
+
+extern inline int time_before(unsigned long a, unsigned long b)
+{
+       return((long)((a) - (b)) < 0L);
+}
+
+extern inline int time_after(unsigned long a, unsigned long b)
+{
+       return((long)((a) - (b)) > 0L);
+}
+
 #endif
index 7aef28fc3b19b997a4b96ad44543201170c01f1d..a83503f997a3518fc7b9bf9c24d998c429815387 100644 (file)
@@ -32,4 +32,5 @@ struct new_utsname {
 
 extern struct new_utsname system_utsname;
 
+extern struct semaphore uts_sem;
 #endif
index efa2e5b3e649c96efaea6b2de68bc3098ee2e15b..340544fd6e55b3100800a6fd6ab463d9d086cc0a 100644 (file)
@@ -20,20 +20,5 @@ long vread(char *buf, char *addr, unsigned long count);
 void vmfree_area_pages(unsigned long address, unsigned long size);
 int vmalloc_area_pages(unsigned long address, unsigned long size);
 
-extern inline void set_pgdir(unsigned long address, pgd_t entry)
-{
-#if !defined(__mc68000__) && !defined(__sparc_v9__)
-       struct task_struct * p;
-
-       read_lock(&tasklist_lock);
-       for_each_task(p) {
-               if (!p->mm)
-                       continue;
-               *pgd_offset(p->mm,address) = entry;
-       }
-       read_unlock(&tasklist_lock);
-#endif
-}
-
 #endif
 
index ca1240b8acafa2f0347bdf0324105a705b03338f..225d40ad09165ac3ba5cd80a06306dee0d3bf425 100644 (file)
@@ -654,17 +654,24 @@ static __inline__ unsigned int tcp_current_mss(struct sock *sk)
        return mss_now; 
 }
 
-/* Compute the actual receive window we are currently advertising. */
+/* Compute the actual receive window we are currently advertising.
+ * Rcv_nxt can be after the window if our peer push more data
+ * than the offered window.
+ */
 static __inline__ u32 tcp_receive_window(struct tcp_opt *tp)
 {
-       return tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd);
+       s32 win = tp->rcv_wup + tp->rcv_wnd - tp->rcv_nxt;
+
+       if (win < 0)
+               win = 0;
+       return (u32) win;
 }
 
 /* Choose a new window, without checks for shrinking, and without
  * scaling applied to the result.  The caller does these things
  * if necessary.  This is a "raw" window selection.
  */
-extern u32     __tcp_select_window(struct sock *sk);
+extern u32     __tcp_select_window(struct sock *sk, u32 cur_win);
 
 /* Chose a new window to advertise, update state in tcp_opt for the
  * socket, and return result with RFC1323 scaling applied.  The return
@@ -674,8 +681,8 @@ extern u32  __tcp_select_window(struct sock *sk);
 extern __inline__ u16 tcp_select_window(struct sock *sk)
 {
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-       u32 new_win = __tcp_select_window(sk);
        u32 cur_win = tcp_receive_window(tp);
+       u32 new_win = __tcp_select_window(sk, cur_win);
 
        /* Never shrink the offered window */
        if(new_win < cur_win)
@@ -694,8 +701,8 @@ extern __inline__ u16 tcp_select_window(struct sock *sk)
 extern __inline__ int tcp_raise_window(struct sock *sk)
 {
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-       u32 new_win = __tcp_select_window(sk);
        u32 cur_win = tcp_receive_window(tp);
+       u32 new_win = __tcp_select_window(sk, cur_win);
 
        return (new_win && (new_win > (cur_win << 1)));
 }
index 3895ae2a9f777cf355ac490296174d9601a0884a..956899b25e653486cf00a98acd59915e56444274 100644 (file)
 #include <linux/pci.h>
 #endif
 
+#ifdef CONFIG_DIO
+#include <linux/dio.h>
+#endif
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -76,6 +80,10 @@ extern void sysctl_init(void);
 extern void filescache_init(void);
 extern void signals_init(void);
 
+#ifdef CONFIG_ARCH_ACORN
+extern void ecard_init(void);
+#endif
+
 extern void smp_setup(char *str, int *ints);
 #ifdef __i386__
 extern void ioapic_pirq_setup(char *str, int *ints);
@@ -124,6 +132,9 @@ extern void pf_setup(char *str, int *ints);
 #ifdef CONFIG_PARIDE_PT
 extern void pt_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_PARIDE_PG
+extern void pg_setup(char *str, int *ints);
+#endif
 #ifdef CONFIG_PARIDE_PCD
 extern void pcd_setup(char *str, int *ints);
 #endif
@@ -788,6 +799,9 @@ static struct kernel_param raw_params[] __initdata = {
 #endif
 #ifdef CONFIG_PARIDE_PT
         { "pt.", pt_setup },
+#endif
+#ifdef CONFIG_PARIDE_PG
+        { "pg.", pg_setup },
 #endif
        { 0, 0 }
 };
@@ -1101,6 +1115,9 @@ __initfunc(asmlinkage void start_kernel(void))
 #ifdef CONFIG_SYSCTL
        sysctl_init();
 #endif
+#ifdef CONFIG_DIO
+       dio_init();
+#endif
 
        /*
         * Ok, at this point all CPU's should be initialized, so
@@ -1118,6 +1135,9 @@ __initfunc(asmlinkage void start_kernel(void))
 #ifdef CONFIG_MCA
        mca_init();
 #endif
+#ifdef CONFIG_ARCH_ACORN
+       ecard_init();
+#endif
 
        /* 
         *      We count on the initial thread going ok 
index 587a2ab7447f4afe0d146e0538bd9b8f2505b71e..8ef89aff2e8a293f9b9d04c10a7dd5a95eea3dfd 100644 (file)
@@ -93,7 +93,7 @@ int request_module(const char * module_name)
        int pid;
        int waitpid_result;
 
-       /* Don't allow request_mode() before the root fs is mounted!  */
+       /* Don't allow request_module() before the root fs is mounted!  */
        if ( ! current->fs->root ) {
                printk(KERN_ERR "request_module[%s]: Root fs not mounted\n",
                        module_name);
index 8110b7e7ecaaf22192a798d593d2cb03095aa21d..269a6d5b2f83dbff7960ef6978fe57a3a583a355 100644 (file)
@@ -326,7 +326,8 @@ EXPORT_SYMBOL(sprintf);
 EXPORT_SYMBOL(vsprintf);
 EXPORT_SYMBOL(kdevname);
 EXPORT_SYMBOL(simple_strtoul);
-EXPORT_SYMBOL(system_utsname);
+EXPORT_SYMBOL(system_utsname); /* UTS data */
+EXPORT_SYMBOL(uts_sem);                /* UTS semaphore */
 EXPORT_SYMBOL(sys_call_table);
 EXPORT_SYMBOL(machine_restart);
 EXPORT_SYMBOL(machine_halt);
index e8baf6ded55191d62a74f5b64267c3e19db9372f..aa943eb1aca2e9908c8a8bbd5b9531eab479b159 100644 (file)
@@ -1564,7 +1564,6 @@ static void show_task(int nr,struct task_struct * p)
                printk("\n");
 
        {
-               extern char * render_sigset_t(sigset_t *set, char *buffer);
                struct signal_queue *q;
                char s[sizeof(sigset_t)*2+1], b[sizeof(sigset_t)*2+1]; 
 
@@ -1577,6 +1576,21 @@ static void show_task(int nr,struct task_struct * p)
        }
 }
 
+char * render_sigset_t(sigset_t *set, char *buffer)
+{
+       int i = _NSIG, x;
+       do {
+               i -= 4, x = 0;
+               if (sigismember(set, i+1)) x |= 1;
+               if (sigismember(set, i+2)) x |= 2;
+               if (sigismember(set, i+3)) x |= 4;
+               if (sigismember(set, i+4)) x |= 8;
+               *buffer++ = (x < 10 ? '0' : 'a' - 10) + x;
+       } while (i >= 4);
+       *buffer = 0;
+       return buffer;
+}
+
 void show_state(void)
 {
        struct task_struct *p;
index 264431bd0443fa98600a735b62d0c5ff59c9d44a..ae8328d25475772c1eb86c43e2faec7262cad1bb 100644 (file)
@@ -55,8 +55,12 @@ extern char reboot_command [];
 extern unsigned long htab_reclaim_on, zero_paged_on;
 #endif
 
+extern int pgt_cache_water[];
+
 static int parse_table(int *, int, void *, size_t *, void *, size_t,
                       ctl_table *, void **);
+static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
+                 void *buffer, size_t *lenp);
 
 
 static ctl_table root_table[];
@@ -138,15 +142,15 @@ static ctl_table root_table[] = {
 
 static ctl_table kern_table[] = {
        {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
-        0444, NULL, &proc_dostring, &sysctl_string},
+        0444, NULL, &proc_doutsstring, &sysctl_string},
        {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
-        0444, NULL, &proc_dostring, &sysctl_string},
+        0444, NULL, &proc_doutsstring, &sysctl_string},
        {KERN_VERSION, "version", system_utsname.version, 64,
-        0444, NULL, &proc_dostring, &sysctl_string},
+        0444, NULL, &proc_doutsstring, &sysctl_string},
        {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
-        0644, NULL, &proc_dostring, &sysctl_string},
+        0644, NULL, &proc_doutsstring, &sysctl_string},
        {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
-        0644, NULL, &proc_dostring, &sysctl_string},
+        0644, NULL, &proc_doutsstring, &sysctl_string},
        {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
         0644, NULL, &proc_dointvec},
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -202,6 +206,8 @@ static ctl_table vm_table[] = {
         &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
        {VM_PAGERDAEMON, "kswapd",
         &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
+       {VM_PGT_CACHE, "pagetable_cache", 
+        &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec},
        {0}
 };
 
@@ -629,6 +635,21 @@ int proc_dostring(ctl_table *table, int write, struct file *filp,
        return 0;
 }
 
+/*
+ *     Special case of dostring for the UTS structure. This has locks
+ *     to observe. Should this be in kernel/sys.c ????
+ */
+static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
+                 void *buffer, size_t *lenp)
+{
+       int r;
+       down(&uts_sem);
+       r=proc_dostring(table,write,filp,buffer,lenp);
+       up(&uts_sem);
+       return r;
+}
+
 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
                  void *buffer, size_t *lenp, int conv)
 {
index bceea609458dd611814968feeed415cdf94633a1..4f5cc72fb69f544ec63adf7a8427b409d1e96c70 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -68,8 +70,6 @@ static inline void copy_cow_page(unsigned long from, unsigned long to)
        copy_page(to, from);
 }
 
-#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
-
 mem_map_t * mem_map = NULL;
 
 /*
@@ -163,13 +163,10 @@ void free_page_tables(struct mm_struct * mm)
 
 int new_page_tables(struct task_struct * tsk)
 {
-       pgd_t * page_dir, * new_pg;
+       pgd_t * new_pg;
 
        if (!(new_pg = pgd_alloc()))
                return -ENOMEM;
-       page_dir = pgd_offset(&init_mm, 0);
-       memcpy(new_pg + USER_PTRS_PER_PGD, page_dir + USER_PTRS_PER_PGD,
-              (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof (pgd_t));
        SET_PAGE_DIR(tsk, new_pg);
        tsk->mm->pgd = new_pg;
        return 0;
@@ -920,3 +917,22 @@ void handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma,
 no_memory:
        oom(tsk);
 }
+
+/* Low and high watermarks for page table cache.
+   The system should try to have pgt_water[0] <= cache elements <= pgt_water[1]
+ */
+int pgt_cache_water[2] = { 25, 50 };
+
+void check_pgt_cache(void)
+{
+        if(pgtable_cache_size > pgt_cache_water[0]) {
+                do {
+                        if(pgd_quicklist)
+                                free_pgd_slow(get_pgd_fast());
+                        if(pmd_quicklist)
+                                free_pmd_slow(get_pmd_fast());
+                        if(pte_quicklist)
+                                free_pte_slow(get_pte_fast());
+                } while(pgtable_cache_size > pgt_cache_water[1]);
+        }
+}
index 4653fb7c11befe937e3b9977f5d4dbae5b1baa13..763af88b0b1c90a122028f3cac3c604c8a53165a 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -110,9 +110,7 @@ asmlinkage unsigned long sys_brk(unsigned long brk)
 
        /* Check against rlimit and stack.. */
        rlim = current->rlim[RLIMIT_DATA].rlim_cur;
-       if (rlim >= RLIM_INFINITY)
-               rlim = ~0;
-       if (brk - mm->end_code > rlim)
+       if (rlim < RLIM_INFINITY && brk - mm->end_code > rlim)
                goto out;
 
        /* Check against existing mmap mappings. */
@@ -465,7 +463,7 @@ static int unmap_fixup(struct vm_area_struct *area, unsigned long addr,
 int do_munmap(unsigned long addr, size_t len)
 {
        struct mm_struct * mm;
-       struct vm_area_struct *mpnt, *next, *free, *extra;
+       struct vm_area_struct *mpnt, *free, *extra;
        int freed;
 
        if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
@@ -486,6 +484,11 @@ int do_munmap(unsigned long addr, size_t len)
        if (!mpnt)
                return 0;
 
+       /* If we'll make "hole", check the vm areas limit */
+       if ((mpnt->vm_start < addr && mpnt->vm_end > addr+len) &&
+           mm->map_count > MAX_MAP_COUNT)
+               return -ENOMEM;
+
        /*
         * We may need one additional vma to fix up the mappings ... 
         * and this is the last chance for an easy error exit.
@@ -494,9 +497,7 @@ int do_munmap(unsigned long addr, size_t len)
        if (!extra)
                return -ENOMEM;
 
-       next = mpnt->vm_next;
-
-       /* we have mpnt->vm_next = next and addr < mpnt->vm_end */
+       /* we have addr < mpnt->vm_end */
        free = NULL;
        for ( ; mpnt && mpnt->vm_start < addr+len; ) {
                struct vm_area_struct *next = mpnt->vm_next;
@@ -510,13 +511,6 @@ int do_munmap(unsigned long addr, size_t len)
                mpnt = next;
        }
 
-       if (free && (free->vm_start < addr) && (free->vm_end > addr+len)) {
-               if (mm->map_count > MAX_MAP_COUNT) {
-                       kmem_cache_free(vm_area_cachep, extra);
-                       return -ENOMEM;
-               }
-       }
-
        /* Ok - we have the memory areas we should free on the 'free' list,
         * so release them, and unmap the page range..
         * If the one of the segments is only being partially unmapped,
index 1a27f266a67cc7627bb1eb6d95e5344f1778aa55..e987469618bb5e26dec75a532ee18fc30135feac 100644 (file)
 
 unsigned int nr_swapfiles = 0;
 
-static struct {
-       int head;       /* head of priority-ordered swapfile list */
-       int next;       /* swapfile to be used next */
-} swap_list = {-1, -1};
+struct swap_list_t swap_list = {-1, -1};
 
 struct swap_info_struct swap_info[MAX_SWAPFILES];
 
@@ -595,7 +592,7 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
        p->flags = SWP_WRITEOK;
        p->pages = j;
        nr_swap_pages += j;
-       printk("Adding Swap: %dk swap-space (priority %d)\n",
+       printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
               j<<(PAGE_SHIFT-10), p->prio);
 
        /* insert swap space into swap_list: */
index 6b262b403df494876f9c64706a4ce0d41d301023..20d9ed94d2554a924a79d78694ad17549e5d414f 100644 (file)
@@ -133,12 +133,16 @@ int vmalloc_area_pages(unsigned long address, unsigned long size)
        dir = pgd_offset_k(address);
        flush_cache_all();
        while (address < end) {
-               pmd_t *pmd = pmd_alloc_kernel(dir, address);
+               pmd_t *pmd;
+               pgd_t olddir = *dir;
+               
+               pmd = pmd_alloc_kernel(dir, address);
                if (!pmd)
                        return -ENOMEM;
                if (alloc_area_pmd(pmd, address, end - address))
                        return -ENOMEM;
-               set_pgdir(address, *dir);
+               if (pgd_val(olddir) != pgd_val(*dir))
+                       set_pgdir(address, *dir);
                address = (address + PGDIR_SIZE) & PGDIR_MASK;
                dir++;
        }
@@ -155,14 +159,13 @@ struct vm_struct * get_vm_area(unsigned long size)
        if (!area)
                return NULL;
        addr = (void *) VMALLOC_START;
-       area->size = size + PAGE_SIZE;
-       area->next = NULL;
        for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
                if (size + (unsigned long) addr < (unsigned long) tmp->addr)
                        break;
                addr = (void *) (tmp->size + (unsigned long) tmp->addr);
        }
        area->addr = addr;
+       area->size = size + PAGE_SIZE;
        area->next = *p;
        *p = area;
        return area;
@@ -210,16 +213,18 @@ void * vmalloc(unsigned long size)
 
 long vread(char *buf, char *addr, unsigned long count)
 {
-       struct vm_struct **p, *tmp;
+       struct vm_struct *tmp;
        char *vaddr, *buf_start = buf;
-       int n;
+       unsigned long n;
 
        /* Don't allow overflow */
        if ((unsigned long) addr + count < count)
                count = -(unsigned long) addr;
 
-       for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+       for (tmp = vmlist; tmp; tmp = tmp->next) {
                vaddr = (char *) tmp->addr;
+               if (addr >= vaddr + tmp->size - PAGE_SIZE)
+                       continue;
                while (addr < vaddr) {
                        if (count == 0)
                                goto finished;
@@ -228,17 +233,15 @@ long vread(char *buf, char *addr, unsigned long count)
                        addr++;
                        count--;
                }
-               n = tmp->size - PAGE_SIZE;
-               if (addr > vaddr)
-                       n -= addr - vaddr;
-               while (--n >= 0) {
+               n = vaddr + tmp->size - PAGE_SIZE - addr;
+               do {
                        if (count == 0)
                                goto finished;
                        put_user(*addr, buf);
                        buf++;
                        addr++;
                        count--;
-               }
+               } while (--n > 0);
        }
 finished:
        return buf - buf_start;
index 24e7f2bd00f39ff246b7ccc815b35aa6f51d008a..3f24d4dbd1bb5276462f06f5cad362061ea28c53 100644 (file)
@@ -95,7 +95,7 @@ __initfunc(void snap_proto_init(struct net_proto *pro))
 }
 
 /*
- *     Register SNAP clients. We don't yet use this for IP or IPX.
+ *     Register SNAP clients. We don't yet use this for IP.
  */
 
 struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *))
index 69315d9483cf7c952c70a27b01a4337ce3e3a42c..cfb9298c4d254eb6d01575e5f7f3cb1d056d4619 100644 (file)
@@ -1097,7 +1097,7 @@ static int sprintf_stats(char *buffer, struct device *dev)
        int size;
        
        if (stats)
-               size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %8lu %4lu %4lu %4lu %5lu %4lu %4lu\n",
+               size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
                   dev->name,
                   stats->rx_bytes,
                   stats->rx_packets, stats->rx_errors,
@@ -1325,7 +1325,7 @@ int dev_change_flags(struct device *dev, unsigned flags)
        dev->flags = (flags & (IFF_DEBUG|IFF_NOTRAILERS|IFF_RUNNING|IFF_NOARP|
                               IFF_SLAVE|IFF_MASTER|
                               IFF_MULTICAST|IFF_PORTSEL|IFF_AUTOMEDIA)) |
-                                      (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC));
+                                      (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC|IFF_ALLMULTI));
 
        /*
         *      Load in the correct multicast list now the flags have changed.
@@ -1346,13 +1346,11 @@ int dev_change_flags(struct device *dev, unsigned flags)
 
                if (ret == 0) 
                        dev_mc_upload(dev);
-       }       
+       }
 
        if (dev->flags&IFF_UP &&
-           ((old_flags^dev->flags)&~(IFF_UP|IFF_RUNNING|IFF_PROMISC|IFF_VOLATILE))) {
-               printk(KERN_DEBUG "SIFFL %s(%s)\n", dev->name, current->comm);
+           ((old_flags^dev->flags)&~(IFF_UP|IFF_RUNNING|IFF_PROMISC|IFF_ALLMULTI|IFF_VOLATILE)))
                notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
-       }
 
        if ((flags^dev->gflags)&IFF_PROMISC) {
                int inc = (flags&IFF_PROMISC) ? +1 : -1;
@@ -1360,6 +1358,16 @@ int dev_change_flags(struct device *dev, unsigned flags)
                dev_set_promiscuity(dev, inc);
        }
 
+       /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI
+          is important. Some (broken) drivers set IFF_PROMISC, when
+          IFF_ALLMULTI is requested not asking us and not reporting.
+        */
+       if ((flags^dev->gflags)&IFF_ALLMULTI) {
+               int inc = (flags&IFF_ALLMULTI) ? +1 : -1;
+               dev->gflags ^= IFF_ALLMULTI;
+               dev_set_allmulti(dev, inc);
+       }
+
        return ret;
 }
 
@@ -1378,7 +1386,8 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
        switch(cmd) 
        {
                case SIOCGIFFLAGS:      /* Get interface flags */
-                       ifr->ifr_flags = (dev->flags&~IFF_PROMISC)|(dev->gflags&IFF_PROMISC);
+                       ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
+                               |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI));
                        return 0;
 
                case SIOCSIFFLAGS:      /* Set interface flags */
index 331a6416835f9ad1c6a58adfd6df899d378548ae..1ba8cc09bbb549704db06a430059765c6ecc9180 100644 (file)
@@ -277,7 +277,7 @@ __initfunc(int net_profile_init(void))
        printk("Evaluating net profiler cost ...");
 #if CPU == 586 || CPU == 686
        if (!(boot_cpu_data.x86_capability & 16)) {
-               printk(KERN_ERR "Sorry, you CPU does not support tsc. Net profiler is dying...\n");
+               printk(KERN_ERR "Sorry, your CPU does not support TSC. Net profiler disabled.\n");
                return -1;
        }
 #endif
index 428b4052c315856ee6898e94398d0063f1b9f015..e1d1379aa30b955e59c5194c18c1096e5dd3484b 100644 (file)
@@ -206,18 +206,14 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                        sk->broadcast=valbool;
                        break;
                case SO_SNDBUF:
-                       /*
-                        *      The spec isnt clear if ENOBUFS or EINVAL
-                        *      is best
-                        */
-                        
-                       /* printk(KERN_DEBUG "setting SO_SNDBUF %d\n", val); */
+                       /* Don't error on this BSD doesn't and if you think
+                          about it this is right. Otherwise apps have to
+                          play 'guess the biggest size' games. RCVBUF/SNDBUF
+                          are treated in BSD as hints */
+                          
                        if (val > sysctl_wmem_max)
-                               return -EINVAL;
+                               return 0;
 
-                       /* FIXME: the tcp code should be made to work even
-                        * with small sndbuf values.
-                        */
                        sk->sndbuf = max(val*2,2048);
 
                        /*
@@ -228,10 +224,13 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                        break;
 
                case SO_RCVBUF:
-                       /* printk(KERN_DEBUG "setting SO_RCVBUF %d\n", val); */
-
+                       /* Don't error on this BSD doesn't and if you think
+                          about it this is right. Otherwise apps have to
+                          play 'guess the biggest size' games. RCVBUF/SNDBUF
+                          are treated in BSD as hints */
+                         
                        if (val > sysctl_rmem_max)
-                               return -EINVAL;
+                               return 0;
 
                        /* FIXME: is this lower bound the right one? */
                        sk->rcvbuf = max(val*2,256);
@@ -480,8 +479,8 @@ struct sock *sk_alloc(int family, int priority, int zero_it)
 {
        struct sock *sk = kmem_cache_alloc(sk_cachep, priority);
 
-       if(sk && zero_it) {
-               memset(sk, 0, sizeof(struct sock));
+       if(sk) {
+               if (zero_it) memset(sk, 0, sizeof(struct sock));
                sk->family = family;
        }
 
@@ -564,15 +563,18 @@ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int
 
 void *sock_kmalloc(struct sock *sk, int size, int priority)
 {
-       void *mem = NULL;
        if (atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) {
+               void *mem;
                /* First do the add, to avoid the race if kmalloc
                 * might sleep.
                 */
                atomic_add(size, &sk->omem_alloc);
                mem = kmalloc(size, priority);
+               if (mem)
+                       return mem;
+               atomic_sub(size, &sk->omem_alloc);
        }
-       return mem;
+       return NULL;
 }
 
 void sock_kfree_s(struct sock *sk, void *mem, int size)
@@ -880,7 +882,7 @@ int sock_no_getname(struct socket *sock, struct sockaddr *saddr,
 
 unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt)
 {
-       return -EOPNOTSUPP;
+       return 0;
 }
 
 int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
index 6ef4ab65f02e1bad09437252f3697179b5736e64..d9a150218c2f29497134e68c710e1d31f2e54bd4 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             IPv4 Forwarding Information Base: FIB frontend.
  *
- * Version:    $Id: fib_frontend.c,v 1.10 1998/05/08 21:06:27 davem Exp $
+ * Version:    $Id: fib_frontend.c,v 1.11 1998/06/11 03:15:40 davem Exp $
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -271,6 +271,8 @@ int ip_rt_ioctl(unsigned int cmd, void *arg)
                                if (tb)
                                        err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
                        }
+                       if (rta.rta_mx)
+                               kfree(rta.rta_mx);
                }
                rtnl_unlock();
                return err;
index 107f07791f1a3900ef3fdaaa0ca7445fd7dd517b..5537016d2b1f9770cfc5efd73ad212d4d6cafc29 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             IPv4 Forwarding Information Base: semantics.
  *
- * Version:    $Id: fib_semantics.c,v 1.8 1998/04/28 06:21:58 davem Exp $
+ * Version:    $Id: fib_semantics.c,v 1.9 1998/06/11 03:15:41 davem Exp $
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -866,8 +866,36 @@ fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
                        *rta->rta_mtu = r->rt_mtu;
        }
 #else
-       if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT))
-           printk(KERN_DEBUG "SIOCRT*: mtu/window/irtt are not implemnted.\n");
+       if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) {
+               struct rtattr *rec;
+               struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL);
+               if (mx == NULL)
+                       return -ENOMEM;
+               rta->rta_mx = mx;
+               mx->rta_type = RTA_METRICS;
+               mx->rta_len  = RTA_LENGTH(0);
+               if (r->rt_flags&RTF_MTU) {
+                       rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+                       rec->rta_type = RTAX_MTU;
+                       rec->rta_len = RTA_LENGTH(4);
+                       mx->rta_len += RTA_LENGTH(4);
+                       *(u32*)RTA_DATA(rec) = r->rt_mtu;
+               }
+               if (r->rt_flags&RTF_WINDOW) {
+                       rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+                       rec->rta_type = RTAX_WINDOW;
+                       rec->rta_len = RTA_LENGTH(4);
+                       mx->rta_len += RTA_LENGTH(4);
+                       *(u32*)RTA_DATA(rec) = r->rt_window;
+               }
+               if (r->rt_flags&RTF_IRTT) {
+                       rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+                       rec->rta_type = RTAX_RTT;
+                       rec->rta_len = RTA_LENGTH(4);
+                       mx->rta_len += RTA_LENGTH(4);
+                       *(u32*)RTA_DATA(rec) = r->rt_irtt;
+               }
+       }
 #endif
        return 0;
 }
index 66c5cbb750a1a37de8fa818c99bac8ed0200a80b..2ec5fcc3de6ef7b20f77b1f3c74e07249eee0cc0 100644 (file)
@@ -3,7 +3,7 @@
  *     
  *             Alan Cox, <alan@cymru.net>
  *
- *     Version: $Id: icmp.c,v 1.41 1998/04/29 22:12:10 alan Exp $
+ *     Version: $Id: icmp.c,v 1.43 1998/06/11 03:15:43 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -539,7 +539,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info)
         */
        
        saddr = iph->daddr;
-       if (!(rt->rt_flags&RTCF_LOCAL))
+       if (!(rt->rt_flags & RTCF_LOCAL))
                saddr = 0;
 
        tos = icmp_pointers[type].error ?
index 1641e5c3d098055869692d321ee9fa7476247ed4..dad449980c3b677027271d48aba6f2bc51f54f5c 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The IP fragmentation functionality.
  *             
- * Version:    $Id: ip_fragment.c,v 1.36 1998/04/18 02:13:07 davem Exp $
+ * Version:    $Id: ip_fragment.c,v 1.37 1998/06/10 00:22:00 davem Exp $
  *
  * Authors:    Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *             Alan Cox <Alan.Cox@linux.org>
@@ -16,6 +16,7 @@
  *             Andi Kleen      :       Add sysctls.
  *             xxxx            :       Overlapfrag bug.
  *             Ultima          :       ip_expire() kernel panic.
+ *             Bill Hawes      :       Frag accounting and evictor fixes.
  */
 
 #include <linux/types.h>
@@ -76,8 +77,6 @@ struct ipq *ipq_hash[IPQ_HASHSZ];
 
 atomic_t ip_frag_mem = ATOMIC_INIT(0);         /* Memory used for fragments */
 
-char *in_ntoa(__u32 in);
-
 /* Memory Tracking Functions. */
 extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
 {
@@ -88,12 +87,12 @@ extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
 extern __inline__ void frag_kfree_s(void *ptr, int len)
 {
        atomic_sub(len, &ip_frag_mem);
-       kfree_s(ptr,len);
+       kfree(ptr);
 }
  
 extern __inline__ void *frag_kmalloc(int size, int pri)
 {
-       void *vp=kmalloc(size,pri);
+       void *vp = kmalloc(size, pri);
 
        if(!vp)
                return NULL;
@@ -108,10 +107,8 @@ static struct ipfrag *ip_frag_create(int offset, int end,
        struct ipfrag *fp;
 
        fp = (struct ipfrag *) frag_kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
-       if (fp == NULL) {
-               NETDEBUG(printk(KERN_ERR "IP: frag_create: no memory left !\n"));
-               return(NULL);
-       }
+       if (fp == NULL)
+               goto out_nomem;
 
        /* Fill in the structure. */
        fp->offset = offset;
@@ -125,6 +122,10 @@ static struct ipfrag *ip_frag_create(int offset, int end,
        atomic_add(skb->truesize, &ip_frag_mem);
 
        return(fp);
+
+out_nomem:
+       NETDEBUG(printk(KERN_ERR "IP: frag_create: no memory left !\n"));
+       return(NULL);
 }
 
 /* Find the correct entry in the "incomplete datagrams" queue for
@@ -139,7 +140,7 @@ static inline struct ipq *ip_find(struct iphdr *iph, struct dst_entry *dst)
        unsigned int hash = ipqhashfn(id, saddr, daddr, protocol);
        struct ipq *qp;
 
-       start_bh_atomic();
+       /* Always, we are in a BH context, so no locking.  -DaveM */
        for(qp = ipq_hash[hash]; qp; qp = qp->next) {
                if(qp->iph->id == id            &&
                   qp->iph->saddr == saddr      &&
@@ -149,13 +150,15 @@ static inline struct ipq *ip_find(struct iphdr *iph, struct dst_entry *dst)
                        break;
                }
        }
-       end_bh_atomic();
        return qp;
 }
 
 /* Remove an entry from the "incomplete datagrams" queue, either
  * because we completed, reassembled and processed it, or because
  * it timed out.
+ *
+ * This is called _only_ from BH contexts, on packet reception
+ * processing and from frag queue expiration timers.  -DaveM
  */
 static void ip_free(struct ipq *qp)
 {
@@ -165,11 +168,9 @@ static void ip_free(struct ipq *qp)
        del_timer(&qp->timer);
 
        /* Remove this entry from the "incomplete datagrams" queue. */
-       start_bh_atomic();
        if(qp->next)
                qp->next->pprev = qp->pprev;
        *qp->pprev = qp->next;
-       end_bh_atomic();
 
        /* Release all fragment data. */
        fp = qp->fragments;
@@ -188,7 +189,9 @@ static void ip_free(struct ipq *qp)
        frag_kfree_s(qp, sizeof(struct ipq));
 }
 
-/* Oops, a fragment queue timed out.  Kill it and send an ICMP reply. */
+/*
+ * Oops, a fragment queue timed out.  Kill it and send an ICMP reply.
+ */
 static void ip_expire(unsigned long arg)
 {
        struct ipq *qp = (struct ipq *) arg;
@@ -198,15 +201,15 @@ static void ip_expire(unsigned long arg)
 #ifdef IP_EXPIRE_DEBUG
                printk("warning: possible ip-expire attack\n");
 #endif
-               ip_free(qp);
-               return;
+               goto out;
        }
   
        /* Send an ICMP "Fragment Reassembly Timeout" message. */
        ip_statistics.IpReasmTimeout++;
        ip_statistics.IpReasmFails++;   
-       icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+       icmp_send(qp->fragments->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
 
+out:
        /* Nuke the fragment queue. */
        ip_free(qp);
 }
@@ -216,17 +219,30 @@ static void ip_expire(unsigned long arg)
  */
 static void ip_evictor(void)
 {
-       while(atomic_read(&ip_frag_mem)>sysctl_ipfrag_low_thresh) {
-               int i;
-
-               /* FIXME: Make LRU queue of frag heads. -DaveM */
-               for(i = 0; i < IPQ_HASHSZ; i++)
-                       if(ipq_hash[i])
-                               break;
-               if(i >= IPQ_HASHSZ)
-                       panic("ip_evictor: memcount");
-               ip_free(ipq_hash[i]);
+       int i, progress;
+
+restart:
+       progress = 0;
+       /* FIXME: Make LRU queue of frag heads. -DaveM */
+       for (i = 0; i < IPQ_HASHSZ; i++) {
+               struct ipq *qp;
+               if (atomic_read(&ip_frag_mem) <= sysctl_ipfrag_low_thresh)
+                       return;
+               /* We are in a BH context, so these queue
+                * accesses are safe.  -DaveM
+                */
+               qp = ipq_hash[i];
+               if (qp) {
+                       /* find the oldest queue for this hash bucket */
+                       while (qp->next)
+                               qp = qp->next;
+                       ip_free(qp);
+                       progress = 1;
+               }
        }
+       if (progress)
+               goto restart;
+       panic("ip_evictor: memcount");
 }
 
 /* Add an entry to the 'ipq' queue for a newly received IP datagram.
@@ -241,20 +257,15 @@ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph)
        int ihlen;
 
        qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
-       if (qp == NULL) {
-               NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
-               return(NULL);
-       }
+       if (qp == NULL)
+               goto out_nomem;
 
        /* Allocate memory for the IP header (plus 8 octets for ICMP). */
        ihlen = iph->ihl * 4;
 
        qp->iph = (struct iphdr *) frag_kmalloc(64 + 8, GFP_ATOMIC);
-       if (qp->iph == NULL) {
-               NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
-               frag_kfree_s(qp, sizeof(struct ipq));
-               return NULL;
-       }
+       if (qp->iph == NULL)
+               goto out_free;
 
        memcpy(qp->iph, iph, ihlen + 8);
        qp->len = 0;
@@ -262,24 +273,28 @@ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph)
        qp->fragments = NULL;
        qp->dev = skb->dev;
 
-       /* Start a timer for this entry. */
+       /* Initialize a timer for this entry. */
        init_timer(&qp->timer);
-       qp->timer.expires = jiffies + sysctl_ipfrag_time;       /* about 30 seconds     */
-       qp->timer.data = (unsigned long) qp;            /* pointer to queue     */
-       qp->timer.function = ip_expire;                 /* expire function      */
-       add_timer(&qp->timer);
+       qp->timer.expires = 0;                  /* (to be set later)    */
+       qp->timer.data = (unsigned long) qp;    /* pointer to queue     */
+       qp->timer.function = ip_expire;         /* expire function      */
 
        /* Add this entry to the queue. */
        hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
 
-       start_bh_atomic();
+       /* We are in a BH context, no locking necessary.  -DaveM */
        if((qp->next = ipq_hash[hash]) != NULL)
                qp->next->pprev = &qp->next;
        ipq_hash[hash] = qp;
        qp->pprev = &ipq_hash[hash];
-       end_bh_atomic();
 
        return qp;
+
+out_free:
+       frag_kfree_s(qp, sizeof(struct ipq));
+out_nomem:
+       NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
+       return(NULL);
 }
 
 /* See if a fragment queue is complete. */
@@ -323,24 +338,16 @@ static struct sk_buff *ip_glue(struct ipq *qp)
        /* Allocate a new buffer for the datagram. */
        len = qp->ihlen + qp->len;
        
-       if(len>65535) {
-               if (net_ratelimit())
-                       printk(KERN_INFO "Oversized IP packet from %d.%d.%d.%d.\n", NIPQUAD(qp->iph->saddr));
-               ip_statistics.IpReasmFails++;
-               ip_free(qp);
-               return NULL;
-       }
+       if(len > 65535)
+               goto out_oversize;
        
-       if ((skb = dev_alloc_skb(len)) == NULL) {
-               ip_statistics.IpReasmFails++;
-               NETDEBUG(printk(KERN_ERR "IP: queue_glue: no memory for gluing queue %p\n", qp));
-               ip_free(qp);
-               return NULL;
-       }
+       skb = dev_alloc_skb(len);
+       if (!skb)
+               goto out_nomem;
 
        /* Fill in the basic details. */
        skb->mac.raw = ptr = skb->data;
-       skb->nh.iph = iph = (struct iphdr*)skb_put(skb,len);
+       skb->nh.iph = iph = (struct iphdr *) skb_put(skb, len);
 
        /* Copy the original IP headers into the new buffer. */
        memcpy(ptr, qp->iph, qp->ihlen);
@@ -350,14 +357,8 @@ static struct sk_buff *ip_glue(struct ipq *qp)
        fp = qp->fragments;
        count = qp->ihlen;
        while(fp) {
-               if (fp->len < 0 || count+fp->len > skb->len) {
-                       NETDEBUG(printk(KERN_ERR "Invalid fragment list: "
-                                       "Fragment over size.\n"));
-                       ip_free(qp);
-                       kfree_skb(skb);
-                       ip_statistics.IpReasmFails++;
-                       return NULL;
-               }
+               if ((fp->len < 0) || ((count + fp->len) > skb->len))
+                       goto out_invalid;
                memcpy((ptr + fp->offset), fp->ptr, fp->len);
                if (count == qp->ihlen) {
                        skb->dst = dst_clone(fp->skb->dst);
@@ -369,26 +370,40 @@ static struct sk_buff *ip_glue(struct ipq *qp)
 
        skb->pkt_type = qp->fragments->skb->pkt_type;
        skb->protocol = qp->fragments->skb->protocol;
-       /* We glued together all fragments, so remove the queue entry. */
-       ip_free(qp);
 
        /* Done with all fragments. Fixup the new IP header. */
        iph = skb->nh.iph;
        iph->frag_off = 0;
        iph->tot_len = htons(count);
-
        ip_statistics.IpReasmOKs++;
        return skb;
+
+out_invalid:
+       NETDEBUG(printk(KERN_ERR
+                       "Invalid fragment list: Fragment over size.\n"));
+       kfree_skb(skb);
+       goto out_fail;
+out_nomem:
+       NETDEBUG(printk(KERN_ERR 
+                       "IP: queue_glue: no memory for gluing queue %p\n",
+                       qp));
+       goto out_fail;
+out_oversize:
+       if (net_ratelimit())
+               printk(KERN_INFO
+                       "Oversized IP packet from %d.%d.%d.%d.\n",
+                       NIPQUAD(qp->iph->saddr));
+out_fail:
+       ip_statistics.IpReasmFails++;
+       return NULL;
 }
 
 /* Process an incoming IP datagram fragment. */
 struct sk_buff *ip_defrag(struct sk_buff *skb)
 {
        struct iphdr *iph = skb->nh.iph;
-       struct ipfrag *prev, *next, *tmp;
-       struct ipfrag *tfp;
+       struct ipfrag *prev, *next, *tmp, *tfp;
        struct ipq *qp;
-       struct sk_buff *skb2;
        unsigned char *ptr;
        int flags, offset;
        int i, ihl, end;
@@ -396,65 +411,58 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
        ip_statistics.IpReasmReqds++;
 
        /* Start by cleaning up the memory. */
-       if(atomic_read(&ip_frag_mem)>sysctl_ipfrag_high_thresh)
+       if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh)
                ip_evictor();
 
-       /* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
+       /*
+        * Look for the entry for this IP datagram in the
+        * "incomplete datagrams" queue. If found, the
+        * timer is removed.
+        */
        qp = ip_find(iph, skb->dst);
 
        /* Is this a non-fragmented datagram? */
        offset = ntohs(iph->frag_off);
        flags = offset & ~IP_OFFSET;
        offset &= IP_OFFSET;
-       if (((flags & IP_MF) == 0) && (offset == 0)) {
-               if (qp != NULL) {
-                       /* Fragmented frame replaced by full unfragmented copy. */
-                       ip_free(qp);
-               }
-               return skb;
-       }
 
        offset <<= 3;           /* offset is in 8-byte chunks */
        ihl = iph->ihl * 4;
 
-       /* If the queue already existed, keep restarting its timer as long
-        * as we still are receiving fragments.  Otherwise, create a fresh
-        * queue entry.
+       /*
+        * Check whether to create a fresh queue entry. If the
+        * queue already exists, its timer will be restarted as
+        * long as we continue to receive fragments.
         */
        if (qp) {
                /* ANK. If the first fragment is received,
                 * we should remember the correct IP header (with options)
                 */
                if (offset == 0) {
+                       /* Fragmented frame replaced by unfragmented copy? */
+                       if ((flags & IP_MF) == 0)
+                               goto out_freequeue;
                        qp->ihlen = ihl;
-                       memcpy(qp->iph, iph, ihl+8);
+                       memcpy(qp->iph, iph, (ihl + 8));
                }
-               /* about 30 seconds */
-               mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time);
        } else {
+               /* Fragmented frame replaced by unfragmented copy? */
+               if ((offset == 0) && ((flags & IP_MF) == 0))
+                       goto out_skb;
+
                /* If we failed to create it, then discard the frame. */
-               if ((qp = ip_create(skb, iph)) == NULL) {
-                       kfree_skb(skb);
-                       ip_statistics.IpReasmFails++;
-                       return NULL;
-               }
+               qp = ip_create(skb, iph);
+               if (!qp)
+                       goto out_freeskb;
        }
        
        /* Attempt to construct an oversize packet. */
-       if(ntohs(iph->tot_len)+(int)offset>65535) {
-               if (net_ratelimit())
-                       printk(KERN_INFO "Oversized packet received from %d.%d.%d.%d\n", NIPQUAD(iph->saddr));
-               frag_kfree_skb(skb);
-               ip_statistics.IpReasmFails++;
-               return NULL;
-       }       
+       if((ntohs(iph->tot_len) + ((int) offset)) > 65535)
+               goto out_oversize;
 
        /* Determine the position of this fragment. */
        end = offset + ntohs(iph->tot_len) - ihl;
 
-       /* Point into the IP datagram 'data' part. */
-       ptr = skb->data + ihl;
-
        /* Is this the final fragment? */
        if ((flags & IP_MF) == 0)
                qp->len = end;
@@ -470,11 +478,14 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
                prev = next;
        }
 
+       /* Point into the IP datagram 'data' part. */
+       ptr = skb->data + ihl;
+
        /* We found where to put this one.  Check for overlap with
         * preceding fragment, and, if needed, align things so that
         * any overlaps are eliminated.
         */
-       if (prev != NULL && offset < prev->end) {
+       if ((prev != NULL) && (offset < prev->end)) {
                i = prev->end - offset;
                offset += i;    /* ptr into datagram */
                ptr += i;       /* ptr into fragment data */
@@ -483,14 +494,14 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
        /* Look for overlap with succeeding segments.
         * If we can merge fragments, do it.
         */
-       for(tmp=next; tmp != NULL; tmp = tfp) {
+       for (tmp = next; tmp != NULL; tmp = tfp) {
                tfp = tmp->next;
                if (tmp->offset >= end)
-                       break;          /* no overlaps at all */
+                       break;          /* no overlaps at all   */
 
-               i = end - next->offset;                 /* overlap is 'i' bytes */
-               tmp->len -= i;                          /* so reduce size of    */
-               tmp->offset += i;                       /* next fragment        */
+               i = end - next->offset; /* overlap is 'i' bytes */
+               tmp->len -= i;          /* so reduce size of    */
+               tmp->offset += i;       /* next fragment        */
                tmp->ptr += i;
 
                /* If we get a frag size of <= 0, remove it and the packet
@@ -513,15 +524,15 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
                }
        }
 
-       /* Insert this fragment in the chain of fragments. */
-       tfp = NULL;
+       /*
+        * Create a fragment to hold this skb.
+        * No memory to save the fragment? throw the lot ...
+        */
        tfp = ip_frag_create(offset, end, skb, ptr);
+       if (!tfp)
+               goto out_freeskb;
 
-       /* No memory to save the fragment - so throw the lot. */
-       if (!tfp) {
-               frag_kfree_skb(skb);
-               return NULL;
-       }
+       /* Insert this fragment in the chain of fragments. */
        tfp->prev = prev;
        tfp->next = next;
        if (prev != NULL)
@@ -538,8 +549,34 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
         */
        if (ip_done(qp)) {
                /* Glue together the fragments. */
-               skb2 = ip_glue(qp);
-               return(skb2);
+               skb = ip_glue(qp);
+               /* Free the queue entry. */
+out_freequeue:
+               ip_free(qp);
+out_skb:
+               return skb;
        }
+
+       /*
+        * The queue is still active ... reset its timer.
+        */
+out_timer:
+       mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time); /* ~ 30 seconds */
+out:
        return NULL;
+
+       /*
+        * Error exits ... we need to reset the timer if there's a queue.
+        */
+out_oversize:
+       if (net_ratelimit())
+               printk(KERN_INFO "Oversized packet received from %d.%d.%d.%d\n",
+                       NIPQUAD(iph->saddr));
+       /* the skb isn't in a fragment, so fall through to free it */
+out_freeskb:
+       kfree_skb(skb);
+       ip_statistics.IpReasmFails++;
+       if (qp)
+               goto out_timer;
+       goto out;
 }
index 05fab8b75eda495227502f140b2ee24eca394006..7160fbf8e05761b16253a56c8691498d44da0636 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * This code is heavily based on the code in ip_fw.c; see that file for
- * copyrights and attributions.  This code is basically GPL.
+ * This code is heavily based on the code on the old ip_fw.c code; see below for
+ * copyrights and attributions of the old code.  This code is basically GPL.
  *
  * 15-Aug-1997: Major changes to allow graphs for firewall rules.
  *              Paul Russell <Paul.Russell@rustcorp.com.au> and
  *              Added packet and byte counters for policy matches.
  * 26-Feb-1998: Fixed race conditions, added SMP support.
  * 18-Mar-1998: Fix SMP, fix race condition fix.
- * 1-May-1998:  Remove caching of device pointer, added caching
- *              for proc output (no longer order n^2).
+ * 1-May-1998:  Remove caching of device pointer.
+ * 12-May-1998: Allow tiny fragment case for TCP/UDP.
+ * 15-May-1998: Treat short packets as fragments, don't just block.
  */
 
+/*
+ *
+ * The origina Linux port was done Alan Cox, with changes/fixes from
+ * Pauline Middlelink, Jos Vos, Thomas Quinot, Wouter Gadeyne, Juan
+ * Jose Ciarlante, Bernd Eckenfels, Keith Owens and others.
+ * 
+ * Copyright from the original FreeBSD version follows:
+ *
+ * Copyright (c) 1993 Daniel Boulet
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.  */
+
+
 #include <linux/config.h>
 
 #include <asm/uaccess.h>
  *
  * For SMP (kernel v2.1+), multiply this by # CPUs.
  *
+ * [Note that this in not correct for 2.2 - because the socket code always
+ *  uses lock_kernel() to serialize, and bottom halves (timers and net_bhs)
+ *  only run on one CPU at a time.  This will probably change for 2.3.
+ *  It is still good to use spinlocks because that avoids the global cli() 
+ *  for updating the tables, which is rather costly in SMP kernels -AK]
+ *
  * This means counters and backchains can get corrupted if no precautions
  * are taken.
  *
@@ -573,14 +601,10 @@ ip_fw_check(struct iphdr *ip,
                return FW_BLOCK;
        }
 
-       /* Check for too-small packets (not non-first fragments).
-        * For each protocol, we assume that we can get the required
-        * information, eg. port number or ICMP type.  If this fails,
-        * reject it. 
-        * 
-        * Sizes might as well be rounded up to 8 here, since either
-        * there are more fragments to come (which must be on 8-byte
-        * boundaries), or this is a bogus packet anyway.
+       /* If we can't investigate ports, treat as fragment.  It's
+        * either a trucated whole packet, or a truncated first
+        * fragment, or a TCP first fragment of length 8-15, in which
+        * case the above rule stops reassembly.
         */
        if (offset == 0) {
                unsigned int size_req;
@@ -598,13 +622,7 @@ ip_fw_check(struct iphdr *ip,
                default:
                        size_req = 0;
                }
-               if (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req) {
-                       if (!testing && net_ratelimit()) {
-                               printk("Packet too short.\n");
-                               dump_packet(ip,rif,NULL,NULL,0,0);
-                       }
-                       return FW_BLOCK;
-               }
+               offset = (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req);
        }
 
        src = ip->saddr;
@@ -613,10 +631,10 @@ ip_fw_check(struct iphdr *ip,
        
        /*
         *      If we got interface from which packet came
-        *      we can use the address directly. This is unlike
-        *      4.4BSD derived systems that have an address chain
-        *      per device. We have a device per address with dummy
-        *      devices instead.
+        *      we can use the address directly. Linux 2.1 now uses address
+        *      chains per device too, but unlike BSD we first check if the
+        *      incoming packet matches a device address and the routing
+        *      table before calling the firewall. 
         */
         
        dprintf("Packet ");
@@ -1117,7 +1135,7 @@ static struct ip_fwkernel *convert_ipfw(struct ip_fwuser *fwuser, int *errno)
                return NULL;
        }
 
-#if DEBUG_IP_FIREWALL_USER
+#ifdef DEBUG_IP_FIREWALL_USER
        /* These are sanity checks that don't really matter.
         * We can get rid of these once testing is complete. 
         */
index 6fecdabb5a7fcf5b7323cbc1d0ec7829a6e3aa71..f56a90332d99c5ea69045b006641cbeaf809ca05 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The Internet Protocol (IP) module.
  *
- * Version:    $Id: ip_input.c,v 1.30 1998/05/08 01:54:54 davem Exp $
+ * Version:    $Id: ip_input.c,v 1.31 1998/05/17 02:19:15 freitag Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -97,7 +97,6 @@
  *             Alan Cox        :       Multicast routing hooks
  *             Jos Vos         :       Do accounting *before* call_in_firewall
  *     Willy Konynenberg       :       Transparent proxying support
- *     Mike McLagan            :       Routing by source
  *
  *  
  *
@@ -470,6 +469,15 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 
        /*
         *      See if the firewall wants to dispose of the packet. 
+        *
+        *      Note: the current standard firewall code expects that the 
+        *      destination address was already checked against the interface 
+        *      address lists.
+        *
+        *      If this code is ever moved in front of ip_route_input() you need
+        *      to fix the fw code [moving it might be a good idea anyways,
+        *      so that we can firewall against potentially bugs in the options
+        *      or routing code]
         */
        
 #ifdef CONFIG_FIREWALL
index df34efb9dafe75c2ff6978f505a604b8fb0eb736..41c66f2c3f6f291a9c2708c5e401a28e71308bcf 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The Internet Protocol (IP) output module.
  *
- * Version:    $Id: ip_output.c,v 1.57 1998/05/08 01:54:56 davem Exp $
+ * Version:    $Id: ip_output.c,v 1.58 1998/05/15 15:21:36 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -99,6 +99,7 @@ void ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
 {
        struct rtable *rt = (struct rtable *)skb->dst;
        struct iphdr *iph;
+       struct device *dev;
        
        /* Build the IP header. */
        if (opt)
@@ -126,10 +127,19 @@ void ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
                ip_options_build(skb, opt, daddr, rt, 0);
        }
 
+       dev = rt->u.dst.dev;
+
+       if (call_out_firewall(PF_INET, dev, iph, NULL, &skb) < FW_ACCEPT)
+               goto drop;
+
        ip_send_check(iph);
 
        /* Send it out. */
        skb->dst->output(skb);
+       return;
+
+drop:
+       kfree_skb(skb);
 }
 
 int __ip_finish_output(struct sk_buff *skb)
index 6ba2ab8b82610dbd925b236a04c1442b00d022bc..155b4162d40c443959f606065dd28d4c5fd13b27 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.12 1998/05/03 14:30:53 alan Exp $
+ *  $Id: ipconfig.c,v 1.13 1998/06/09 03:40:47 zaitcev Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -248,6 +248,11 @@ __initfunc(int ic_setup_routes(void))
 
 __initfunc(int ic_defaults(void))
 {
+       /*
+        *      At this point we have no userspace running so need not
+        *      claim locks on system_utsname
+        */
+        
        if (!ic_host_name_set)
                strcpy(system_utsname.nodename, in_ntoa(ic_myaddr));
 
@@ -1072,8 +1077,8 @@ __initfunc(int ip_auto_config(void))
 }
 
 /*
- *  Decode any IP configuration options in the "ipconfig" kernel command
- *  line parameter. It consists of option fields separated by colons in
+ *  Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
+ *  command line parameter. It consists of option fields separated by colons in
  *  the following order:
  *
  *  <client-ip>:<server-ip>:<gw-ip>:<netmask>:<host name>:<device>:<bootp|rarp>
index 3b8ec3b00e843d5b3d8d224d0aaccd9054351a0c..902c3983b8f86e66c87b9d9c6fcd5317853056b6 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             ROUTE - implementation of the IP router.
  *
- * Version:    $Id: route.c,v 1.50 1998/05/13 06:23:25 davem Exp $
+ * Version:    $Id: route.c,v 1.52 1998/06/11 03:15:47 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1095,11 +1095,12 @@ local_input:
        rth->rt_gateway = daddr;
        rth->rt_spec_dst= spec_dst;
        rth->u.dst.input= ip_local_deliver;
+       rth->rt_flags   = flags|RTCF_LOCAL;
        if (res.type == RTN_UNREACHABLE) {
                rth->u.dst.input= ip_error;
-               rth->u.dst.error= err;
+               rth->u.dst.error= -err;
+               rth->rt_flags   &= ~RTCF_LOCAL;
        }
-       rth->rt_flags   = flags|RTCF_LOCAL;
        rth->rt_type    = res.type;
        skb->dst = (struct dst_entry*)rt_intern_hash(hash, rth);
        return 0;
index e9465004350b083caac69577b848500c9b0532cd..c3e219d4676645708a60903abd15d2d65e0d96a2 100644 (file)
@@ -9,7 +9,7 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  * 
- *  $Id: syncookies.c,v 1.5 1998/04/03 09:49:46 freitag Exp $
+ *  $Id: syncookies.c,v 1.6 1998/06/10 07:29:22 davem Exp $
  *
  *  Missing: IPv6 support. 
  */
index fd4284af992c1fb062e6ad5244c112d1c2adc98b..094c5e4ab69f35161c63395c4603ed62e9bbf0ca 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.114 1998/04/26 01:11:33 davem Exp $
+ * Version:    $Id: tcp.c,v 1.115 1998/05/13 13:44:13 alan Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1069,6 +1069,13 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
 
        add_wait_queue(sk->sleep, &wait);
        lock_sock(sk);
+       
+       /*
+        *      BUG BUG BUG
+        *      This violates 1003.1g compliance. We must wait for 
+        *      data to exist even if we read none!
+        */
+        
        while (len > 0) {
                struct sk_buff * skb;
                u32 offset;
index 2ca11f8e461e802ab6ad0e23ada365ad8c91917d..6b62622e6f41cf1a075ee2c88abfe421e9efea57 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.118 1998/05/06 04:53:48 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.119 1998/05/23 13:10:24 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1686,8 +1686,13 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                        }
                } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una) {
                        /* Bulk data transfer: receiver */
-                       if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) 
+                       if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) {
+                               /* We must send an ACK for zero window probes. */
+                               if (!before(TCP_SKB_CB(skb)->seq,
+                                               tp->rcv_wup + tp->rcv_wnd))
+                                       tcp_send_ack(sk);
                                goto discard;
+                       }
                        
                        skb_pull(skb,th->doff*4);
 
@@ -1714,15 +1719,21 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
        }
 
        if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
-               if (!th->rst) {
-                       if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
-                               SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
-                                          TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
-                                          tp->rcv_wup, tp->rcv_wnd);
-                       }
-                       tcp_send_ack(sk);
+               /* RFC793, page 37: "In all states except SYN-SENT, all reset
+                * (RST) segments are validated by checking their SEQ-fields."
+                * And page 69: "If an incoming segment is not acceptable,
+                * an acknowledgment should be sent in reply (unless the RST bit
+                * is set, if so drop the segment and return)".
+                */
+               if (th->rst)
                        goto discard;
+               if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
+                       SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
+                                  TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
+                                  tp->rcv_wup, tp->rcv_wnd);
                }
+               tcp_send_ack(sk);
+               goto discard;
        }
 
        if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
index e318207e0bcebdc7e0115954c7862b6300000d38..4a925bd0f8e37f6137841292f1cc3af9aa25ffeb 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_output.c,v 1.90 1998/05/06 04:59:15 davem Exp $
+ * Version:    $Id: tcp_output.c,v 1.91 1998/05/23 13:10:21 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -331,16 +331,18 @@ void tcp_write_xmit(struct sock *sk)
  *
  * Note, we don't "adjust" for TIMESTAMP or SACK option bytes.
  */
-u32 __tcp_select_window(struct sock *sk)
+u32 __tcp_select_window(struct sock *sk, u32 cur_win)
 {
        struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
        unsigned int mss = sk->mss;
-       unsigned int free_space;
-       u32 window, cur_win;
+       int free_space;
+       u32 window;
 
+       /* Sometimes free_space can be < 0. */
        free_space = (sk->rcvbuf - atomic_read(&sk->rmem_alloc)) / 2;
        if (tp->window_clamp) {
-               free_space = min(tp->window_clamp, free_space);
+               if (free_space > ((int) tp->window_clamp))
+                       free_space = tp->window_clamp;
                mss = min(tp->window_clamp, mss);
        } else {
                printk("tcp_select_window: tp->window_clamp == 0.\n");
@@ -351,8 +353,7 @@ u32 __tcp_select_window(struct sock *sk)
                printk("tcp_select_window: sk->mss fell to 0.\n");
        }
        
-       cur_win = tcp_receive_window(tp);
-       if (free_space < sk->rcvbuf/4 && free_space < mss/2) {
+       if ((free_space < (sk->rcvbuf/4)) && (free_space < ((int) (mss/2)))) {
                window = 0;
        } else {
                /* Get the largest window that is a nice multiple of mss.
@@ -364,8 +365,9 @@ u32 __tcp_select_window(struct sock *sk)
                 * is too small.
                 */
                window = tp->rcv_wnd;
-               if ((window <= (free_space - mss)) || (window > free_space))
-                       window = (free_space/mss)*mss;
+               if ((((int) window) <= (free_space - ((int) mss))) ||
+                               (((int) window) > free_space))
+                       window = (((unsigned int) free_space)/mss)*mss;
        }
        return window;
 }
index 013fbb14742855e1bd3e15cf4672266b5bffec98..7e2c7bfa63d72f6a6e0b8ddde88113eba42e0281 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The User Datagram Protocol (UDP).
  *
- * Version:    $Id: udp.c,v 1.56 1998/05/08 21:06:30 davem Exp $
+ * Version:    $Id: udp.c,v 1.57 1998/05/14 06:32:44 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -57,6 +57,8 @@
  *             Andi Kleen      :       Some cleanups, cache destination entry
  *                                     for connect. 
  *     Vitaly E. Lavrov        :       Transparent proxy revived after year coma.
+ *             Melvin Smith    :       Check msg_name not msg_namelen in sendto(),
+ *                                     return ENOTCONN for unconnected sockets (POSIX)
  *
  *
  *             This program is free software; you can redistribute it and/or
@@ -657,7 +659,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
         *      Get and verify the address. 
         */
         
-       if (msg->msg_namelen) {
+       if (msg->msg_name) {
                struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;
                if (msg->msg_namelen < sizeof(*usin))
                        return(-EINVAL);
@@ -684,7 +686,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
                 */
        } else {
                if (sk->state != TCP_ESTABLISHED)
-                       return -EINVAL;
+                       return -ENOTCONN;
                ufh.daddr = sk->daddr;
                ufh.uh.dest = sk->dport;
 
index 554f990978f7db044850a28a746901707194fe85..051f9a28e28f9c64666b371dc3c0d164c2382516 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Adapted from linux/net/ipv4/af_inet.c
  *
- *     $Id: af_inet6.c,v 1.33 1998/05/08 21:06:32 davem Exp $
+ *     $Id: af_inet6.c,v 1.36 1998/06/10 07:29:25 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -422,6 +422,11 @@ int ipv6_unload(void)
 }
 #endif
 
+#if defined(MODULE) && defined(CONFIG_SYSCTL)
+extern void ipv6_sysctl_register(void);
+extern void ipv6_sysctl_unregister(void);
+#endif
+
 #ifdef MODULE
 int init_module(void)
 #else
@@ -515,7 +520,7 @@ icmp_fail:
 void cleanup_module(void)
 {
        /* First of all disallow new sockets creation. */
-       sock_unregister(AF_INET6);
+       sock_unregister(PF_INET6);
 #ifdef CONFIG_PROC_FS
        proc_net_unregister(proc_net_raw6.low_ino);
        proc_net_unregister(proc_net_tcp6.low_ino);
index eb89fd4fa274627804394c2e205172d7d36dba0e..5fa45dce559bef8ce875b12031c89a287544f081 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.81 1998/05/03 14:31:10 alan Exp $
+ *     $Id: tcp_ipv6.c,v 1.82 1998/06/11 03:15:52 davem Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
@@ -64,9 +64,7 @@ static __inline__ int tcp_v6_hashfn(struct in6_addr *laddr, u16 lport,
 {
        int hashent = (lport ^ fport);
 
-       hashent ^= (laddr->s6_addr32[0] ^ laddr->s6_addr32[1]);
-       hashent ^= (faddr->s6_addr32[0] ^ faddr->s6_addr32[1]);
-       hashent ^= (faddr->s6_addr32[2] ^ faddr->s6_addr32[3]);
+       hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
        return (hashent & ((TCP_HTABLE_SIZE/2) - 1));
 }
 
@@ -145,6 +143,13 @@ go_like_smoke:
 
 static void tcp_v6_hash(struct sock *sk)
 {
+       /* Well, I know that it is ugly...
+          All this ->prot, ->af_specific etc. need LARGE cleanup --ANK
+        */
+       if (sk->tp_pinfo.af_tcp.af_specific == &ipv6_mapped) {
+               tcp_prot.hash(sk);
+               return;
+       }
        if(sk->state != TCP_CLOSE) {
                struct sock **skp;
 
@@ -415,8 +420,14 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                if (err) {
                        sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
                        sk->backlog_rcv = tcp_v6_do_rcv;
+               } else {
+                       /* Yuup... And it is not the only place... --ANK */
+                       ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000FFFF),
+                                     sk->saddr);
+                       ipv6_addr_set(&np->rcv_saddr, 0, 0, __constant_htonl(0x0000FFFF),
+                                     sk->rcv_saddr);
                }
-               
+
                return err;
        }
 
index f75d3cd771b669769f45231bd9f80aba9a65caf1..90a59266c61d392ce3df83f08292bb06b7c93821 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Based on linux/ipv4/udp.c
  *
- *     $Id: udp.c,v 1.28 1998/05/03 14:31:12 alan Exp $
+ *     $Id: udp.c,v 1.29 1998/05/15 15:21:39 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -689,7 +689,7 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
                }
        } else {
                if (sk->state != TCP_ESTABLISHED)
-                       return(-EINVAL);
+                       return(-ENOTCONN);
                
                udh.uh.dest = sk->dport;
                daddr = &sk->net_pinfo.af_inet6.daddr;
index cc07905dedca9eebbcd54c97b860b78e62a135f1..8f50013f7fe163f820df4952fc5f5dcbba359786 100644 (file)
@@ -525,6 +525,7 @@ insert:
                                        break;
                        f->next = *fp;
                        *fp = f;
+                       *arg = (unsigned long)f;
                        return 0;
                }
        }
index dc43cdbaf8cbd40c20f35a6751bd75321634f30d..52512e87972f8d5d497343474a1f451fe20da813 100644 (file)
@@ -1435,7 +1435,7 @@ static __inline__ int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl)
 
        if (cl->police) {
                opt.police = cl->police;
-               RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt);
+               RTA_PUT(skb, TCA_CBQ_POLICE, sizeof(opt), &opt);
        }
        return skb->len;
 
index da75145238744c33e53c6a6b31a8a0eae12202cf..212e6f696adcbcc41ac6e0e1d0195c146692d3a7 100644 (file)
@@ -252,7 +252,7 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct device *dev)
                return 0;
        }
        neigh_release(n);
-       return (skb_res != NULL);
+       return (skb_res == NULL) ? -EAGAIN : 1;
 }
 
 static __inline__ int
@@ -280,7 +280,7 @@ static int teql_master_xmit(struct sk_buff *skb, struct device *dev)
 
 restart:
        nores = 0;
-       busy = 1;
+       busy = 0;
 
        if ((q = start) == NULL)
                goto drop;
@@ -288,34 +288,39 @@ restart:
        do {
                struct device *slave = q->dev;
                
-               if (!slave->tbusy && slave->qdisc_sleeping == q) {
-                       busy = 0;
-                       
-                       if (q->h.forw == NULL) {
-                               q->h.forw = qdisc_head.forw;
-                               qdisc_head.forw = &q->h;
-                       }
+               if (slave->qdisc_sleeping != q)
+                       continue;
+               if (slave->tbusy) {
+                       busy = 1;
+                       continue;
+               }
 
-                       switch (teql_resolve(skb, skb_res, slave)) {
-                       case 0:
-                               if (slave->hard_start_xmit(skb, slave) == 0) {
-                                       master->slaves = NEXT_SLAVE(q);
-                                       dev->tbusy = 0;
-                                       master->stats.tx_packets++;
-                                       master->stats.tx_bytes += len;
-                                       return 0;
-                               }
-                               break;
-                       case 1:
+               if (q->h.forw == NULL) {
+                       q->h.forw = qdisc_head.forw;
+                       qdisc_head.forw = &q->h;
+               }
+
+               switch (teql_resolve(skb, skb_res, slave)) {
+               case 0:
+                       if (slave->hard_start_xmit(skb, slave) == 0) {
                                master->slaves = NEXT_SLAVE(q);
                                dev->tbusy = 0;
-                               return 0;
-                       default:
-                               nores = 1;
-                               break;
+                               master->stats.tx_packets++;
+                               master->stats.tx_bytes += len;
+                                       return 0;
                        }
-                       __skb_pull(skb, skb->nh.raw - skb->data);
+                       if (dev->tbusy)
+                               busy = 1;
+                       break;
+               case 1:
+                       master->slaves = NEXT_SLAVE(q);
+                       dev->tbusy = 0;
+                       return 0;
+               default:
+                       nores = 1;
+                       break;
                }
+               __skb_pull(skb, skb->nh.raw - skb->data);
        } while ((q = NEXT_SLAVE(q)) != start);
 
        if (nores && skb_res == NULL) {
index 6ce6b6e411266672fc68933259eb46adbd26abd6..3742dc12cf13c76a8efdb422c8a3af99d02034d7 100644 (file)
@@ -118,7 +118,7 @@ void define_config(int convert, const char * name, int len)
 /*
  * Clear the set of configuration strings.
  */
-void clear_config( )
+void clear_config(void)
 {
        len_config = 0;
        define_config(0, "", 0);
@@ -193,7 +193,7 @@ void use_config(const char * name, int len)
  * Thus, there is one memory access per sizeof(unsigned long) characters.
  */
 
-#if defined(__alpha__) || defined(__i386__)
+#if defined(__alpha__) || defined(__i386__) || defined(__arm__)
 #define LE_MACHINE
 #endif