]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.51pre1 2.3.51pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:32:35 +0000 (15:32 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:32:35 +0000 (15:32 -0500)
223 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/networking/decnet.txt
Documentation/sound/Introduction
Documentation/sound/Maestro
Documentation/sound/OPL3-SA
Documentation/sound/Opti
Documentation/sound/README.OSS
Documentation/sound/Wavefront
Documentation/sound/via82cxxx.txt
Makefile
arch/alpha/config.in
arch/alpha/defconfig
arch/alpha/kernel/osf_sys.c
arch/arm/Makefile
arch/arm/config.in
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/acpi.c
arch/i386/kernel/pci-pc.c
arch/ia64/config.in
arch/mips/config.in
arch/mips/defconfig
arch/mips/defconfig-decstation
arch/mips/defconfig-ip22
arch/mips/kernel/sysirix.c
arch/mips64/config.in
arch/ppc/boot/Makefile
arch/ppc/chrpboot/Makefile
arch/ppc/coffboot/Makefile
arch/ppc/configs/common_defconfig
arch/ppc/defconfig
arch/ppc/kernel/chrp_time.c
arch/ppc/kernel/irq.c
arch/ppc/kernel/open_pic.c
arch/ppc/kernel/prom.c
arch/ppc/mbxboot/Makefile
arch/ppc/treeboot/Makefile
arch/ppc/xmon/xmon.c
arch/sh/config.in
arch/sh/defconfig
arch/sparc/defconfig
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sys_sunos.c
arch/sparc/lib/Makefile
arch/sparc/lib/irqlock.S [deleted file]
arch/sparc/mm/init.c
arch/sparc64/defconfig
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/sys_sunos32.c
arch/sparc64/mm/init.c
arch/sparc64/solaris/fs.c
drivers/block/DAC960.c
drivers/block/Makefile
drivers/block/aec6210.c
drivers/block/cmd64x.c
drivers/block/hpt34x.c
drivers/block/hpt366.c
drivers/block/ide-pnp.c [new file with mode: 0644]
drivers/block/ide-probe.c
drivers/block/ide.c
drivers/block/ide_modes.h
drivers/block/ll_rw_blk.c
drivers/block/pdc202xx.c
drivers/block/rd.c
drivers/block/via82cxxx.c
drivers/char/Config.in
drivers/char/mem.c
drivers/net/setup.c
drivers/net/tokenring/Makefile
drivers/net/tokenring/tms380tr.c
drivers/net/tulip/tulip_core.c
drivers/net/wan/cosa.c
drivers/net/wavelan.c
drivers/pci/pci.ids
drivers/pnp/quirks.c
drivers/scsi/3w-xxxx.c
drivers/scsi/Config.in
drivers/sound/Config.in
drivers/sound/Makefile
drivers/sound/aci.c [new file with mode: 0644]
drivers/sound/ad1816.c
drivers/sound/aedsp16.c [new file with mode: 0644]
drivers/sound/awe_hw.h [new file with mode: 0644]
drivers/sound/awe_wave.c [new file with mode: 0644]
drivers/sound/awe_wave.h [new file with mode: 0644]
drivers/sound/lowlevel/Config.in [deleted file]
drivers/sound/lowlevel/Makefile [deleted file]
drivers/sound/lowlevel/README [deleted file]
drivers/sound/lowlevel/aci.c [deleted file]
drivers/sound/lowlevel/aedsp16.c [deleted file]
drivers/sound/lowlevel/awe_compat.h [deleted file]
drivers/sound/lowlevel/awe_config.h [deleted file]
drivers/sound/lowlevel/awe_hw.h [deleted file]
drivers/sound/lowlevel/awe_version.h [deleted file]
drivers/sound/lowlevel/awe_wave.c [deleted file]
drivers/sound/lowlevel/lowlevel.h [deleted file]
drivers/sound/lowlevel/miroaci.h [deleted file]
drivers/sound/lowlevel/soundlow.c [deleted file]
drivers/sound/sb_card.c
drivers/sound/sb_common.c
drivers/usb/inode.c
drivers/video/Config.in
drivers/video/Makefile
drivers/video/amifb.c
drivers/video/aty128fb.c
drivers/video/fbcon.c
drivers/video/fbmem.c
drivers/video/fbmon.c
drivers/video/offb.c
drivers/video/vgacon.c
fs/adfs/super.c
fs/affs/namei.c
fs/affs/super.c
fs/autofs/inode.c
fs/autofs/root.c
fs/autofs4/inode.c
fs/autofs4/root.c
fs/bfs/inode.c
fs/coda/dir.c
fs/coda/inode.c
fs/cramfs/inode.c
fs/devfs/base.c
fs/devpts/inode.c
fs/efs/super.c
fs/ext2/super.c
fs/fat/inode.c
fs/filesystems.c
fs/hfs/dir.c
fs/hfs/super.c
fs/hpfs/hpfs_fn.h
fs/hpfs/namei.c
fs/hpfs/super.c
fs/inode.c
fs/isofs/inode.c
fs/lockd/lockd_syms.c
fs/lockd/svc.c
fs/lockd/xdr.c
fs/lockd/xdr4.c
fs/minix/inode.c
fs/minix/namei.c
fs/msdos/namei.c
fs/namei.c
fs/ncpfs/dir.c
fs/ncpfs/inode.c
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfsd/export.c
fs/nfsd/lockd.c
fs/nfsd/nfs3proc.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsfh.c
fs/nfsd/nfsproc.c
fs/nfsd/nfsxdr.c
fs/nfsd/vfs.c
fs/ntfs/fs.c
fs/open.c
fs/openpromfs/inode.c
fs/proc/array.c
fs/proc/inode.c
fs/qnx4/inode.c
fs/qnx4/namei.c
fs/romfs/inode.c
fs/smbfs/dir.c
fs/smbfs/inode.c
fs/super.c
fs/sysv/inode.c
fs/sysv/namei.c
fs/udf/namei.c
fs/udf/super.c
fs/ufs/super.c
fs/umsdos/namei.c
fs/umsdos/rdir.c
fs/vfat/namei.c
include/asm-i386/ide.h
include/asm-ia64/ide.h
include/asm-mips64/ide.h
include/asm-ppc/prom.h
include/asm-sparc/ide.h
include/asm-sparc/system.h
include/linux/dcache.h
include/linux/efs_fs.h
include/linux/ext2_fs.h
include/linux/fb.h
include/linux/fs.h
include/linux/ide.h
include/linux/if_ec.h
include/linux/lockd/xdr.h
include/linux/lockd/xdr4.h
include/linux/msdos_fs.h
include/linux/nfsd/nfsd.h
include/linux/nfsd/xdr.h
include/linux/pci_ids.h
include/linux/shm.h
include/linux/sysctl.h
include/net/dn_raw.h [deleted file]
include/net/tcp.h
ipc/shm.c
ipc/util.c
kernel/acct.c
kernel/ksyms.c
kernel/sysctl.c
mm/mmap.c
net/Config.in
net/decnet/Config.in
net/decnet/Makefile
net/decnet/TODO
net/decnet/af_decnet.c
net/decnet/dn_nsp_in.c
net/decnet/dn_nsp_out.c
net/decnet/dn_raw.c [deleted file]
net/decnet/dn_route.c
net/decnet/sysctl_net_decnet.c
net/econet/Makefile
net/econet/af_econet.c [new file with mode: 0644]
net/econet/econet.c [deleted file]
net/econet/sysctl_net_ec.c [new file with mode: 0644]
net/ipv4/tcp.c
net/ipv4/tcp_ipv4.c
net/ipv6/tcp_ipv6.c
net/sysctl_net.c

diff --git a/CREDITS b/CREDITS
index af4d44bab15c1711b8797fe7d72cce1102ec4ee2..9c3162b9c554fe0524323eaf4337c9944d796fe5 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -940,6 +940,13 @@ S: Frankenstra
 S: 34131 Kassel
 S: Germany
 
+N: Christoph Hellwig
+E: chhellwig@gmx.net
+D: Sound/OSS hacking
+S: Triftstraße 26
+S: 38644 Goslar
+S: Germany
+
 N: Richard Henderson
 E: rth@twiddle.net
 E: rth@cygnus.com
index ea01182b0ef3693add6b7ae39b5ab7aa4e339c2c..9be04dcd690baf08c044fccb730af4b90696b41a 100644 (file)
@@ -72,6 +72,10 @@ Upgrade notes
 General Information
 ===================
 
+   To use System V shared memory, you have to mount the shm filesystem
+somewhere and put the mountpoint into /proc/sys/kernel/shmpath.
+Default is /var/shm.
+
    <CTRL><ALT><DEL> now performs a cold reboot instead of a warm reboot
 for increased hardware compatibility.  If you want a warm reboot and
 know it works on your hardware, add a "reboot=warm" command line option
index dc7103e36d0b3878879a12c3a803e5d1c29191d9..743160c2b44e4c7a9031e249865d63f48b51d2ec 100644 (file)
@@ -648,7 +648,7 @@ CONFIG_IDEDMA_PCI_WIP
 
   It is SAFEST to say N to this question.
 
-3ware Hardware ATA-RAID support (EXPERIMENTAL)
+3ware Hardware ATA-RAID support
 CONFIG_BLK_DEV_3W_XXXX_RAID
   3ware is the only hardware ATA-Raid product in Linux to date.
   This card is 2,4, or 8 channel master mode support only.
@@ -745,9 +745,13 @@ CONFIG_BLK_DEV_HPT366
   This is an Ultra DMA chipset for ATA-66.
   
   This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. The HPT366 chipset in its current form is a non-bootable.
-  This driver requires dynamic tuning of the chipset during the
-  ide-probe at boot. It is reported to support DVD II drives, by the
+  interrupt. The HPT366 chipset in its current form is a non-bootable,
+  without special LILO commands for redirecting the reference to device 0x80.
+  The other solution is to include "CONFIG_BLK_DEV_OFFBOARD" unless your
+  mainboard has the chipset native mounted.  Regardless one should use the
+  fore mentioned option and call at LILO or include in your append-line:
+  "ide=reverse".  This driver requires dynamic tuning of the chipset during
+  the ide-probe at boot. It is reported to support DVD II drives, by the
   manufacturer.
 
   Please read the comments at the top of drivers/block/hpt366.c
@@ -2353,6 +2357,11 @@ CONFIG_FB_AMIGA
   This is the frame buffer device driver for the builtin graphics
   chipset found in Amigas.
 
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called amifb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
 Amiga OCS chipset support
 CONFIG_FB_AMIGA_OCS
   This enables support for the original Agnus and Denise video chips,
@@ -3480,15 +3489,13 @@ CONFIG_DECNET_ROUTER
    Add support for turning your DECnet Endnode into a level 1 or 2
    router. This is an unfinished option for developers only. If you do
    turn it on, then make sure that you also say Y to "Kernel/User
-   network link driver" and "Routing messages", since rtnetlink is the
-   only current method of configuration.
+   network link driver", "Routing messages" and "Network packet 
+   filtering". The first two are required to allow configuration via
+   rtnetlink (currently you need Alexey Kuznetsov's iproute2 package
+   from ftp.inr.ac.ru). The "Network packet filtering" option will
+   be required for the forthcoming routing daemon to work.
 
-DECnet Raw Socket Support
-CONFIG_DECNET_RAW
-   Add support for the SOCK_RAW type under DECnet. Used by userland
-   routing programs to receive routing messages from the kernel and
-   also as a general debugging aid to see what's going on "under the
-   hood".
+   See Documentation/networking/decnet.txt for more information.
 
 AppleTalk DDP
 CONFIG_ATALK
@@ -11779,7 +11786,7 @@ CONFIG_LOWLEVEL_SOUND
   to present you with more options. If unsure, say Y.
 
 ACI mixer (miroPCM12/PCM20)
-CONFIG_ACI_MIXER
+CONFIG_SOUND_ACI_MIXER
   ACI (Audio Command Interface) is a protocol used to communicate with
   the microcontroller on some sound cards produced by miro, e.g. the
   miroSOUND PCM12 and PCM20. The main function of the ACI is to
@@ -11791,7 +11798,7 @@ CONFIG_ACI_MIXER
   radio-miropcm20 driver.
 
 SB32/AWE support
-CONFIG_AWE32_SYNTH
+CONFIG_SOUND_AWE32_SYNTH
   Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or
   similar sound card. See Documentation/sound/README.awe,
   Documentation/sound/AWE32 and the Soundblaster-AWE mini-HOWTO,
@@ -11799,7 +11806,7 @@ CONFIG_AWE32_SYNTH
   info.
 
 Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600)
-CONFIG_AEDSP16
+CONFIG_SOUND_AEDSP16
   Answer Y if you have a Gallant's Audio Excel DSP 16 card. This
   driver supports Audio Excel DSP 16 but not the III nor PnP versions
   of this card.
@@ -11817,12 +11824,6 @@ CONFIG_AEDSP16
   Documentation/sound/AudioExcelDSP16 to get more information about
   this driver and its configuration.
 
-I/O base for Audio Excel DSP 16
-CONFIG_AEDSP16_BASE
-  This is the base I/O address of the Audio Excel DSP 16 card. It must
-  be 220 or 240. If you compiled aedsp16.o as a module you can specify
-  this parameter as 'io=0xNNN'.
-
 Audio Excel DSP 16 (SBPro emulation)
 CONFIG_AEDSP16_SBPRO
   Answer Y if you want your audio card to emulate Sound Blaster Pro.
@@ -11830,36 +11831,12 @@ CONFIG_AEDSP16_SBPRO
   (SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS
   emulation)".
 
-Audio Excel DSP 16 IRQ
-CONFIG_AEDSP16_SB_IRQ
-  This is the IRQ of the Audio Excel DSP 16 card. It must be 5, 7, 9,
-  10 or 11. If you compiled aedsp16.o as a module you can specify
-  this parameter as 'irq=NN'.
-
-Audio Excel DSP 16 DMA
-CONFIG_AEDSP16_SB_DMA
-  This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 or
-  3. If you compiled aedsp16.o as a module you can specify this
-  parameter as 'dma=NN'.
-
 Audio Excel DSP 16 (MSS emulation)
 CONFIG_AEDSP16_MSS
   Answer Y if you want your audio card to emulate Microsoft Sound
   System. You should then say Y to "Microsoft Sound System support"
   and say N to "Audio Excel DSP 16 (SBPro emulation)".
 
-Audio Excel DSP 16 IRQ
-CONFIG_AEDSP16_MSS_IRQ
-  This is the IRQ of the Audio Excel DSP 16 card. It must be 5, 7, 9,
-  10 or 11. If you compiled aedsp16.o as a module you can specify
-  this parameter as 'irq=NN'.
-
-Audio Excel DSP 16 DMA
-CONFIG_AEDSP16_MSS_DMA
-  This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 
-  or 3. If you compiled aedsp16.o as a module you can specify this
-  parameter as 'dma=NN'.
-
 SC-6600 based audio cards (new Audio Excel DSP 16)
 CONFIG_SC6600
   The SC6600 is the new version of DSP mounted on the Audio Excel DSP
@@ -11887,13 +11864,6 @@ CONFIG_AEDSP16_MPU401
   driver as a module you have to specify the MPU I/O base address with
   the parameter 'mpu_base=0xNNN'.
 
-MPU401 IRQ for Audio Excel DSP 16
-CONFIG_AEDSP16_MPU_IRQ
-  This is the IRQ of the MPU-401 emulation of your Audio Excel DSP 16
-  card. It must be 5, 7, 9, 10 or 0 (to disable MPU-401 interface). If
-  you compiled aedsp16.o as a module you can specify this parameter as
-  'mpu_irq=NN'.
-
 Ensoniq ES1370 based PCI sound cards
 CONFIG_SOUND_ES1370
   Say Y or M if you have a PCI sound card utilizing the Ensoniq
index 2ceceecb6911446bc791b53cb34acb6fbb3c4101..e09832dca079b4fb9b931982567e2f288864793a 100644 (file)
@@ -30,10 +30,10 @@ Be sure to turn on the following options:
 if you want to try out router support (not properly debugged yet)
 you'll need the following options as well...
 
-    CONFIG_DECNET_RAW (to receive routing packets)
     CONFIG_DECNET_ROUTER (to be able to add/delete routes)
     CONFIG_NETLINK (to allow rtnetlink)
     CONFIG_RTNETLINK (for communication with the kernel routing layer)
+    CONFIG_NETFILTER (will be required for the DECnet routing daemon)
 
 3) Command line options
 
@@ -93,7 +93,13 @@ a reduced functionality.
 If you want to configure a DECnet router you'll need the iproute2 package
 since its the _only_ way to add and delete routes currently. Eventually
 there will be a routing daemon to send and receive routing messages for
-each interface and update the kernel routing tables accordingly.
+each interface and update the kernel routing tables accordingly. The
+routing daemon will use netfilter to listen to routing packets, and
+rtnetlink to update the kernels routing tables. 
+
+The DECnet raw socket layer has been removed since it was there purely
+for use by the routing daemon which will now use netfilter (a much cleaner
+and more generic solution) instead.
 
 5) How can I tell if its working ?
 
index 2ab4867d9127a21295a183bdc087548d8a048517..f2ce25d6745082e59895d91b961c1ec270a078b3 100644 (file)
@@ -160,8 +160,6 @@ Sound Status:
 =============
 
 The status of sound may be read/checked by:
-       cat /proc/sound
-       cat /dev/sndstat
         cat (anyfile).au >/dev/audio
 
 The status of the modules and which modules depend on 
index f3cc4ab7753442fe19da7ca62180ceb14fd8ad80..8d0fd215da93eb52d0eae941ffae4cf93f751fbb 100644 (file)
@@ -30,8 +30,7 @@ Driver OSS Behavior
 --------------------
 
 This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec.   This driver doesn't register itself
-with /dev/sndstat, so don't expect information to appear there.
+mostly adhere to the OSS spec.
 
 The /dev/dsp device exported behaves almost as expected.  Playback is
 supported in all the various lovely formats.  8/16bit stereo/mono from
index 5e8f2f41c8f15c309f0a76e5ceac5f85b2896452..0d91c8bf3b83a2a30d865cc608b116cb2ec55f14 100644 (file)
@@ -48,33 +48,5 @@ kernel.
 
 If you chose to build it as a module, just insmod the resulting softoss2.o
 
-A 'cat /dev/sndstat' with all the above options should look similar to this:
-
-  OSS/Free:3.8s2++-971130
-  Load type: Driver loaded as a module
-  Kernel: Linux iniquity 2.1.105 #145 Mon Jun 8 11:40:47 MST 1998 i586
-  Config options: 0
-
-  Installed drivers: 
-
-  Card config: 
-
-  Audio devices:
-  0: MSS audio codec (CS4231) (DUPLEX)
-
-  Synth devices:
-  0: Yamaha OPL-3
-  1: SoftOSS
-
-  Midi devices:
-  0: OPL3-SA (MPU401)
-
-  Timers:
-  0: System clock
-  1: MSS audio codec (CS4231)
-
-  Mixers:
-  0: MSS audio codec (CS4231)
-
 Questions? Comments?
 <stiker@northlink.com>
index 07318d2435fe1bfdd8fa7b1560db2122038186c1..92f123313df6e469f6f493db8b5b6fc006179f94 100644 (file)
@@ -99,9 +99,7 @@ alias synth0 opl3
 
 When any sound device is opened the kernel requests auto-loading
 of char-major-14. There is a built-in alias that translates this
-request to loading the main sound module. The main sound module
-contains only common code which is needed by all the sound drivers,
-and the driver for /dev/sndstat.
+request to loading the main sound module.
 
 The sound module in its turn will request loading of a sub-driver
 for mixer, audio, midi or synthesizer device. The first 3 are
index 379dd3bd57b20020ffb59be5d67f3ac44e8d7bed..f594802e5c42da4dacf48349cdade56276891628 100644 (file)
@@ -147,24 +147,9 @@ If you get an error message when trying to use the driver, please look
 at /var/adm/messages for more verbose error message.
 
 
-In general the easiest way to diagnose problems is to do "cat /dev/sndstat".
-
-If you get an error message, there are some problems with the driver setup:
-
-       - "No such file or directory" tells that the device files for
-       the sound driver are missing. Use the script at the end of
-       linux/drivers/sound/Readme.linux to create them.
-
-       - "No such device" tells that the sound driver is not in the kernel.
-       You have to reconfigure and recompile the kernel to have the sound
-       driver. Compiling the driver doesn't help alone. You have to boot
-       with the newly compiled one before the driver becomes active.
-       The Linux-HOWTO should help in this step.
-
 The following errors are likely with /dev/dsp and /dev/audio.
 
-       - "No such device or address". This error message should not happen
-       with /dev/sndstat but it's possible with the other sound devices.
+       - "No such device or address".
        This error indicates that there are no suitable hardware for the
        device file or the sound driver has been compiled without support for
        this particular device. For example /dev/audio and /dev/dsp will not
@@ -180,10 +165,6 @@ The following errors are likely with /dev/dsp and /dev/audio.
        with impossible parameters. Check that the application is
        for sound driver version 2.X or later.
 
-In general the printout of /dev/sndstat should tell what is the problem.
-It's possible that there are bugs in the sound driver but 99% of the problems
-reported to me are caused by somehow incorrect setup during "make config".
-
 Linux installation
 ==================
 
@@ -226,17 +207,6 @@ Readme of sound driver version 3.0.1 if you still want to use this method.
 Problems
 --------
 
-If you have any kind of problems, there is a debugging feature which
-could help you to solve the problem. To use it, just execute the
-command:
-
-       cat /dev/sndstat 
-
-and look at the output. It should display some useful info about the
-driver configuration. If there is no /dev/sndstat 
-(/dev/sndstat: No such file or directory), ensure that you have executed the
-soundinstall script (at the end of this file).
-
 Common error messages:
 
 - /dev/???????: No such file or directory.
@@ -757,10 +727,6 @@ the kernel following instructions in the kernel README.
 The sound driver configuration dialog
 -------------------------------------
 
-If you already have the sound driver installed, consult a printout of
-"cat /dev/sndstat" when configuring the driver again. It gives the I/O,
-IRQ and DMA settings you used earlier.
-
 Sound configuration starts by making some yes/no questions. Be careful
 when answering to these questions since answering y to a question may
 prevent some later ones from being asked. For example don't answer y to
@@ -1417,8 +1383,7 @@ Cards not supported yet
 Please check the version of sound driver you are using before 
 complaining that your card is not supported. It's possible you are 
 using a driver version which was released months before your card was
-introduced.  The driver's release date is listed after its version number in a
-"cat /dev/sndstat" printout and in the file linux/drivers/sound/soundvers.h.
+introduced.
 
 First of all, there is an easy way to make most sound cards work with Linux.
 Just use the DOS based driver to initialize the card to a known state, then use
index f1dcf975f8016f98f9e8bfbe6ee43b710d491b37..5453af77f425679aec951f7585f9a64a5f4ea292 100644 (file)
@@ -293,36 +293,6 @@ warm reboots since the last firmware load).
 The "available DRAM" line will vary depending on how much added RAM
 your card has. Mine has 8MB.
 
-Next, check /dev/sndstat, which on my machine says:
----------------------------------------------------------------------
-OSS/Free:3.8s2++-971130
-Load type: Driver loaded as a module
-Kernel: Linux bd 2.1.106 #12 SMP Fri Jul 3 00:37:34 EDT 1998 i486
-Config options: 0
-
-Installed drivers: 
-
-Card config: 
-
-Audio devices:
-0: Crystal audio controller (CS4232) (DUPLEX)
-
-Synth devices:
-0: Turtle Beach WaveFront
-1: Yamaha OPL-3
-
-Midi devices:
-0: WaveFront Internal MIDI
-1: WaveFront External MIDI
-
-Timers:
-0: System clock
-1: Crystal audio controller (CS4232)
-
-Mixers:
-0: Crystal audio controller (CS4232)
------------------------------------------------------------
-
 To check basically functionality, use play(1) or splay(1) to send a
 .WAV or other audio file through the audio portion. Then use playmidi
 to play a General MIDI file. Try the "-D 0" to hear the
index 62877fd79c7088c67c17edcbee6e882d19ad0fc5..5bb587950108192bc5572ca5ad062f057752a975 100644 (file)
@@ -122,25 +122,7 @@ Native MIDI driver, as described above
 Known bugs (patches/suggestions welcome)
 ------------------------------------------------------------------------
 1) Two MIDI devices are loaded by the sound driver.  Eliminate one of them. 
-Sample /proc/sound output:
-
-       Midi devices:
-       0: Sound Blaster
-       1: VIA 82Cxxx Audio driver 1.1.2
 
 2) Two mixer devices are loaded by the sound driver.  Eliminate one of
 them.  At least one bug report says that SB mixer does not work at all,
-only AC97 mixer.  Sample /proc/sound output:
-
-       Mixers:
-       0: via82cxxxAC97Mixer
-       1: Sound Blaster
-
-3) After unloading the driver, a SoundBlaster MIDI device is still 
-listed in /proc/sound.  Investigate what is not being unloaded,
-and fix it.  Sample /proc/sound output, after 'rmmod via82cxxx':
-
-       Midi devices:
-       0: Sound Blaster
-
-
+only AC97 mixer.
index 155997f18c50ec3611b90685b6f30af147ae89a0..a37d67ff51f38d5cc25edad79982c32e8b98dc62 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 50
+SUBLEVEL = 51
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
index 1686fefbc2e161ff1be85b7a946003acfffa812f..6e760c917f1147fe37c15723e4c7d7e63081e68c 100644 (file)
@@ -270,7 +270,7 @@ source drivers/char/Config.in
 
 source drivers/usb/Config.in
 
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
 
 source fs/Config.in
 
index 9365dc4e22b03fc8423f084e33e974f856ec334e..cc244e560e747ec54a5db6018c2bb4eced1cbbcf 100644 (file)
@@ -323,10 +323,6 @@ CONFIG_PSMOUSE=y
 #
 # CONFIG_USB is not set
 
-#
-# Misc devices
-#
-
 #
 # Filesystems
 #
index 6a2ff8a9b1e4d37f9757aee8aa51cc61b0ee9ac1..091edaf3719bca2b2a9236b662642599d9378d98 100644 (file)
@@ -303,18 +303,9 @@ static int linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf
 static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsigned long bufsiz)
 {
        struct statfs linux_stat;
-       struct inode * inode = dentry->d_inode;
-       struct super_block * sb = inode->i_sb;
-       int error;
-
-       error = -ENODEV;
-       if (sb && sb->s_op && sb->s_op->statfs) {
-               set_fs(KERNEL_DS);
-               error = sb->s_op->statfs(sb, &linux_stat, sizeof(linux_stat));
-               set_fs(USER_DS);
-               if (!error)
-                       error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
-       }
+       int error = vfs_statfs(dentry->d_inode->i_sb, &linux_stat);
+       if (!error)
+               error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
        return error;   
 }
 
index bb0a34f9265ae2ef3b612d9ef4a3ec25a884aaf6..6b4033705ec9fdf7491a0f130b13fc10bb6ec5b0 100644 (file)
@@ -12,7 +12,6 @@
 #
 # Copyright (C) 1995-1999 by Russell King
 
-LD             := $(CROSS_COMPILE)ld
 OBJCOPY                := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 CPP            := $(CC) -E
 PERL           := perl
index 5e9cc8bfc72bb7f1c8c45828c237490878563526..4c7a5fe196faa6132da1d1df2d10b29ccfeedd69 100644 (file)
@@ -214,7 +214,7 @@ fi
 
 source drivers/usb/Config.in
 
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
 
 if [ "$CONFIG_VT" = "y" ]; then
    mainmenu_option next_comment
index 11a98fc58eda2a2ffd3d4c29b55ec215d999add5..beb9fa1a8a5915f50377d27277a2bfa0d05b323b 100644 (file)
@@ -142,7 +142,7 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
 bool 'Power Management support' CONFIG_PM
 
-dep_bool '  ACPI support' CONFIG_ACPI $CONFIG_PM
+dep_tristate '  ACPI support' CONFIG_ACPI $CONFIG_PM
 if [ "$CONFIG_ACPI" != "n" ]; then
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool '    Enter S1 for sleep (EXPERIMENTAL)' CONFIG_ACPI_S1_SLEEP
@@ -231,7 +231,7 @@ source drivers/char/Config.in
 
 source drivers/usb/Config.in
 
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
 
 source fs/Config.in
 
index aa04c36851bf4d4ff88921c398dadfd544c01397..e1f011e5dd528ea1d6bc76ea111fc35a7021f8f7 100644 (file)
@@ -197,6 +197,7 @@ CONFIG_SCSI_CONSTANTS=y
 #
 # SCSI low-level drivers
 #
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
@@ -402,7 +403,6 @@ CONFIG_PSMOUSE=y
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
 
 #
 # Video For Linux
@@ -432,10 +432,6 @@ CONFIG_PCMCIA_SERIAL=y
 #
 # CONFIG_USB is not set
 
-#
-# Misc devices
-#
-
 #
 # File systems
 #
index b190974203d0bed750d4873696c2c72408e5be49..d95bbe6b19654974bc1a294311566c353ed721c6 100644 (file)
@@ -50,7 +50,6 @@
  */
 extern unsigned long get_cmos_time(void);
 
-static int acpi_control_thread(void *context);
 static int acpi_do_ulong(ctl_table *ctl,
                         int write,
                         struct file *file,
@@ -72,8 +71,6 @@ static int acpi_do_sleep(ctl_table *ctl,
                         void *buffer,
                         size_t *len);
 
-DECLARE_WAIT_QUEUE_HEAD(acpi_control_wait);
-
 static struct ctl_table_header *acpi_sysctl = NULL;
 
 static struct acpi_facp *acpi_facp = NULL;
@@ -105,7 +102,15 @@ static unsigned long acpi_p_blk = 0;
 static int acpi_p_lvl2_tested = 0;
 static int acpi_p_lvl3_tested = 0;
 
-static int acpi_disabled = 0;
+enum
+{
+       ACPI_ENABLED,
+       ACPI_TABLES_ONLY,
+       ACPI_CHIPSET_ONLY,
+       ACPI_DISABLED,
+};
+
+static int acpi_enabled = ACPI_ENABLED;
 
 // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
 static unsigned long acpi_slp_typ[] = 
@@ -1296,13 +1301,21 @@ static int acpi_do_sleep(ctl_table *ctl,
  */
 static int __init acpi_init(void)
 {
-       int pid;
-
-       if (acpi_disabled)
-               return -ENODEV;
-
-       if (acpi_find_tables() && acpi_find_chipset()) {
-               // no ACPI tables and not recognized chipset
+       switch(acpi_enabled)
+       {
+       case ACPI_ENABLED:
+               if (acpi_find_tables() && acpi_find_chipset())
+                       return -ENODEV;
+               break;
+       case ACPI_TABLES_ONLY:
+               if (acpi_find_tables())
+                       return -ENODEV;
+               break;
+       case ACPI_CHIPSET_ONLY:
+               if (acpi_find_chipset())
+                       return -ENODEV;
+               break;
+       case ACPI_DISABLED:
                return -ENODEV;
        }
 
@@ -1342,10 +1355,6 @@ static int __init acpi_init(void)
 
        acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
 
-       pid = kernel_thread(acpi_control_thread,
-                           NULL,
-                           CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-
        pm_power_off = acpi_power_off;
 
        pm_active = 1;
@@ -1379,6 +1388,7 @@ err_out:
 static void __exit acpi_exit(void)
 {
        pm_idle = NULL;
+       pm_active = 0;
        pm_power_off = NULL;
 
        unregister_sysctl_table(acpi_sysctl);
@@ -1400,10 +1410,14 @@ static void __exit acpi_exit(void)
 static int __init acpi_setup(char *str)
 {
        while (str && *str) {
-               if (strncmp(str, "off", 3) == 0)
-                       acpi_disabled = 1;
-               else if (strncmp(str, "on", 2) == 0)
-                       acpi_disabled = 0;
+               if (strncmp(str, "on", 2) == 0)
+                       acpi_enabled = ACPI_ENABLED;
+               else if (strncmp(str, "tables", 6) == 0)
+                       acpi_enabled = ACPI_TABLES_ONLY;
+               else if (strncmp(str, "chipset", 7) == 0)
+                       acpi_enabled = ACPI_CHIPSET_ONLY;
+               else if (strncmp(str, "off", 3) == 0)
+                       acpi_enabled = ACPI_DISABLED;
                str = strpbrk(str, ",");
                if (str)
                        str += strspn(str, ",");
@@ -1413,24 +1427,5 @@ static int __init acpi_setup(char *str)
 
 __setup("acpi=", acpi_setup);
 
-/*
- * Manage idle devices
- */
-static int acpi_control_thread(void *context)
-{
-       exit_mm(current);
-       exit_files(current);
-       strcpy(current->comm, "acpi");
-       
-       for(;;) {
-               interruptible_sleep_on(&acpi_control_wait);
-               if (signal_pending(current))
-                       break;
-
-               // find all idle devices and set idle timer
-       }
-
-       return 0;
-}
-
-__initcall(acpi_init);
+module_init(acpi_init);
+module_exit(acpi_exit);
index a76c92d25e4d2e61a2025661c6385a730fa3c12c..e51e96e4332a50cded7c05f1851ca4f41c1e7ff6 100644 (file)
@@ -1044,17 +1044,17 @@ static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt)
                        printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i);
 }
 
-static void set_level_irq(unsigned irq)
+static void ali_set_level_irq(unsigned irq)
 {
        unsigned char mask = 1 << (irq & 7);
        unsigned int port = 0x4d0 + (irq >> 3);
        unsigned char val = inb(port);
 
        if (val & mask) {
-               printk("PCI irq %d was level\n", irq);
+               DBG("PCI irq %d was level\n", irq);
                return;
        }
-       printk("PCI irq %d was edge, turning into level-triggered\n", irq);
+       DBG("PCI irq %d was edge, turning into level-triggered\n", irq);
        outb(val | mask, port);
 }
 
@@ -1070,18 +1070,17 @@ static int ali_set_irq(struct pci_dev *router, unsigned pirq, unsigned irq)
                        unsigned offset = 0x48 + (pirq >> 1);
                        unsigned shift = (pirq & 1) << 2;
                        pci_read_config_byte(router, offset, &byte);
-                       printk("ALI: old %04x=%02x\n", offset, byte);
+                       DBG("ALI: old %04x=%02x\n", offset, byte);
                        byte &= ~(0xf << shift);
                        byte |= val << shift;
-                       printk("ALI: new %04x=%02x\n", offset, byte);
+                       DBG("ALI: new %04x=%02x\n", offset, byte);
                        pci_write_config_byte(router, offset, byte);
-                       set_level_irq(irq);
+                       ali_set_level_irq(irq);
                        return irq;
                }
        }
        return 0;
 }
-               
 
 /*
  *  In case BIOS forgets to tell us about IRQ, we try to look it up in the routing
@@ -1380,13 +1379,17 @@ int pcibios_enable_device(struct pci_dev *dev)
 
        if ((err = pcibios_enable_resources(dev)) < 0)
                return err;
-       if (!dev->irq && pirq_table) {
+       if (!dev->irq) {
                u8 pin;
                pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
                if (pin) {
-                       char *msg = pcibios_lookup_irq(dev, pirq_table, pin, 1);
-                       if (msg)
+                       char *msg;
+                       if (pirq_table && ((msg = pcibios_lookup_irq(dev, pirq_table, pin, 1))))
                                printk("PCI: Assigned IRQ %d to device %s [%s]\n", dev->irq, dev->slot_name, msg);
+                       else
+                               printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
+                                      'A' + pin - 1, dev->slot_name,
+                                      (pci_probe & PCI_BIOS_IRQ_SCAN) ? "" : " Please try using pci=biosirq.");
                }
        }
        return 0;
index 2d2388590c68f0dad93cd9d3528715987733e1f0..cf2b2c1cf7dc72a13ab820e96828d8a1ee0531f3 100644 (file)
@@ -123,7 +123,7 @@ endmenu
 
 source drivers/char/Config.in
 source drivers/usb/Config.in
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
 
 source fs/Config.in
 
index ac0da810dce1ae7ee446e4d7c67b5a8ff1fc845c..911d47baf66048ce9fa306f724a66bd477a55c12 100644 (file)
@@ -293,7 +293,7 @@ fi
 
 source drivers/usb/Config.in
 
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
 
 source fs/Config.in
 
index 5516700c13975a83d6612d3a604f526594251397..d634a050712d98c79cd4a52f2e3b2a7a92a4cea9 100644 (file)
@@ -291,10 +291,6 @@ CONFIG_PSMOUSE=y
 #
 # CONFIG_USB is not set
 
-#
-# Misc devices
-#
-
 #
 # File systems
 #
index 25612580dc17c0d882730385ce2f7891af750758..53fa16f7ed4df1ea5d15bc5d610daf6e55b73096 100644 (file)
@@ -183,10 +183,6 @@ CONFIG_SERIAL_CONSOLE=y
 #
 # CONFIG_USB is not set
 
-#
-# Misc devices
-#
-
 #
 # Filesystems
 #
index 5516700c13975a83d6612d3a604f526594251397..d634a050712d98c79cd4a52f2e3b2a7a92a4cea9 100644 (file)
@@ -291,10 +291,6 @@ CONFIG_PSMOUSE=y
 #
 # CONFIG_USB is not set
 
-#
-# Misc devices
-#
-
 #
 # File systems
 #
index 66b8ad4a210765567ff12ed9746e1822051c7206..bcb2592eebcb4f376c79acfb49f8b5b69e1d377a 100644 (file)
@@ -725,8 +725,6 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
                           int len, int fs_type)
 {
        struct dentry *dentry;
-       struct inode *inode;
-       mm_segment_t old_fs;
        struct statfs kbuf;
        int error, i;
 
@@ -745,11 +743,7 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
        if (IS_ERR(dentry))
                goto out;
 
-       inode = dentry->d_inode;
-       old_fs = get_fs(); set_fs(get_ds());
-       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
-                                         sizeof(struct statfs));
-       set_fs(old_fs);
+       error = vfs_statfs(dentry->d_inode->i_sb, &kbuf);
        if (error)
                goto dput_and_out;
 
@@ -775,9 +769,7 @@ out:
 
 asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
 {
-       struct inode *inode;
        struct statfs kbuf;
-       mm_segment_t old_fs;
        struct file *file;
        int error, i;
 
@@ -790,23 +782,7 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
                goto out;
        }
 
-       if (!(inode = file->f_dentry->d_inode)) {
-               error = -ENOENT;
-               goto out_f;
-       }
-       if (!inode->i_sb) {
-               error = -ENODEV;
-               goto out_f;
-       }
-       if (!inode->i_sb->s_op->statfs) {
-               error = -ENOSYS;
-               goto out_f;
-       }
-
-       old_fs = get_fs(); set_fs(get_ds());
-       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
-                                         sizeof(struct statfs));
-       set_fs(old_fs);
+       error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
        if (error)
                goto out_f;
 
@@ -1509,8 +1485,6 @@ struct irix_statvfs {
 asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
 {
        struct dentry *dentry;
-       struct inode *inode;
-       mm_segment_t old_fs;
        struct statfs kbuf;
        int error, i;
 
@@ -1524,16 +1498,7 @@ asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
        error = PTR_ERR(dentry);
        if(!IS_ERR(dentry))
                goto out;
-       inode = dentry->d_inode;
-
-       error = -ENOSYS;
-       if(!inode->i_sb->s_op->statfs)
-               goto dput_and_out;
-
-       old_fs = get_fs(); set_fs(get_ds());
-       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
-                                         sizeof(struct statfs));
-       set_fs(old_fs);
+       error = vfs_statfs(dentry->d_inode->i_sb, &kbuf);
        if (error)
                goto dput_and_out;
 
@@ -1568,8 +1533,6 @@ out:
 
 asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
 {
-       struct inode *inode;
-       mm_segment_t old_fs;
        struct statfs kbuf;
        struct file *file;
        int error, i;
@@ -1585,23 +1548,7 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
                error = -EBADF;
                goto out;
        }
-       if (!(inode = file->f_dentry->d_inode)) {
-               error = -ENOENT;
-               goto out_f;
-       }
-       if (!inode->i_sb) {
-               error = -ENODEV;
-               goto out_f;
-       }
-       if (!inode->i_sb->s_op->statfs) {
-               error = -ENOSYS;
-               goto out_f;
-       }
-
-       old_fs = get_fs(); set_fs(get_ds());
-       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
-                                         sizeof(struct statfs));
-       set_fs(old_fs);
+       error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
        if (error)
                goto out_f;
 
@@ -1813,8 +1760,6 @@ struct irix_statvfs64 {
 asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
 {
        struct dentry *dentry;
-       struct inode *inode;
-       mm_segment_t old_fs;
        struct statfs kbuf;
        int error, i;
 
@@ -1828,15 +1773,7 @@ asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
        error = PTR_ERR(dentry);
        if(IS_ERR(dentry))
                goto out;
-       error = -ENOSYS;
-       inode = dentry->d_inode;
-       if(!inode->i_sb->s_op->statfs)
-               goto dput_and_out;
-
-       old_fs = get_fs(); set_fs(get_ds());
-       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
-                                         sizeof(struct statfs));
-       set_fs(old_fs);
+       error = vfs_statfs(dentry->d_inode->i_sb, &kbuf);
        if (error)
                goto dput_and_out;
 
@@ -1871,8 +1808,6 @@ out:
 
 asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
 {
-       struct inode *inode;
-       mm_segment_t old_fs;
        struct statfs kbuf;
        struct file *file;
        int error, i;
@@ -1888,23 +1823,7 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
                error = -EBADF;
                goto out;
        }
-       if (!(inode = file->f_dentry->d_inode)) {
-               error = -ENOENT;
-               goto out_f;
-       }
-       if (!inode->i_sb) {
-               error = -ENODEV;
-               goto out_f;
-       }
-       if (!inode->i_sb->s_op->statfs) {
-               error = -ENOSYS;
-               goto out_f;
-       }
-
-       old_fs = get_fs(); set_fs(get_ds());
-       error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
-                                         sizeof(struct statfs));
-       set_fs(old_fs);
+       error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
        if (error)
                goto out_f;
 
index a60738800e8a0fde09a52bcdb05d604ccf7e878d..12a2c8de91901f11d37b4c3fdc2bb77af73d6d73 100644 (file)
@@ -177,7 +177,6 @@ source drivers/char/Config.in
 
 source drivers/usb/Config.in
 
-# drivers/misc has currently only i386 specific devices.
 #source drivers/misc/Config.in
 
 source fs/Config.in
index 6b83788390ce13d7307ca9d69b50e0942d3cf097..60420556591bd8a7eabb6cd04ec67e827665b133 100644 (file)
@@ -53,7 +53,6 @@ GZIP_FLAGS = -v9f
 
 OBJECTS := head.o misc.o ../coffboot/zlib.o
 CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin
-OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O elf32-powerpc
 
 OBJECTS += vreset.o kbd.o of1275.o
index 5a7f063fc1184deddea9ac31c3be8815a99395e5..216b289ed71c65fdd2cc4f0b39221b566337a757 100644 (file)
@@ -18,7 +18,6 @@
 
 CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS
 LD_ARGS = -Ttext 0x00400000
-OBJCOPY = $(CROSS_COMPILE)objcopy
 
 OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o sysmap.o
 LIBS = $(TOPDIR)/lib/lib.a
index 29a4fdc355b0eb52e545a79a0c80ba7fdbd1c070..5c46f9540c73fe7930978415febc6371d21e03fa 100644 (file)
@@ -5,14 +5,10 @@
 
 HOSTCFLAGS = -O -I$(TOPDIR)/include
 
-CC     = $(CROSS_COMPILE)gcc
-LD     = $(CROSS_COMPILE)ld
 CFLAGS = $(CPPFLAGS) -O -fno-builtin
-OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
 COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
 CHRP_LD_ARGS = -Ttext 0x00400000
-GZ = gzip -9
 
 COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o
 CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o
index c849bac82993815eb510e39c197fe0a93ffe8abe..bcab91ec6c1fa2e41ab50b192d8ef23642fd5a67 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
 #
 # CONFIG_UID16 is not set
 
@@ -33,7 +33,6 @@ CONFIG_KMOD=y
 #
 # General setup
 #
-# CONFIG_PCI is not set
 CONFIG_PCI=y
 CONFIG_PCI=y
 CONFIG_NET=y
@@ -46,6 +45,10 @@ CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PCI_NAMES is not set
 # CONFIG_HOTPLUG is not set
+
+#
+# Parallel port support
+#
 # CONFIG_PARPORT is not set
 CONFIG_VGA_CONSOLE=y
 CONFIG_FB=y
@@ -53,6 +56,7 @@ CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
 CONFIG_ADB=y
 CONFIG_ADB_CUDA=y
 CONFIG_ADB_MACIO=y
@@ -69,27 +73,21 @@ CONFIG_BOOTX_TEXT=y
 # Plug and Play configuration
 #
 # CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=y
-
-#
-# IDE chipset support/bugfixes
-#
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
@@ -108,10 +106,6 @@ CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_CPQ_DA is not set
-
-#
-# Additional Block Devices
-#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -144,18 +138,10 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
 CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
-
-#
-#  
-#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_DECNET is not set
@@ -177,10 +163,6 @@ CONFIG_ATALK=m
 # SCSI support
 #
 CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=y
@@ -189,10 +171,6 @@ CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_SR_EXTRA_DEVS=2
 CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 # CONFIG_SCSI_DEBUG_QUEUES is not set
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
@@ -272,6 +250,13 @@ CONFIG_NETDEVICES=y
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_IPDDP is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
@@ -299,6 +284,7 @@ CONFIG_PCNET32=y
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
 CONFIG_DE4X5=y
 # CONFIG_TULIP is not set
 # CONFIG_DGRS is not set
@@ -324,13 +310,6 @@ CONFIG_DE4X5=y
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
 CONFIG_PPP=y
 # CONFIG_PPP_ASYNC is not set
 # CONFIG_PPP_SYNC_TTY is not set
@@ -344,7 +323,7 @@ CONFIG_PPP=y
 # CONFIG_NET_RADIO is not set
 
 #
-# Token Ring driver support
+# Token Ring devices
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
@@ -397,7 +376,7 @@ CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 CONFIG_FB_ATY=y
-# CONFIG_FB_ATY128 is not set
+CONFIG_FB_ATY128=y
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -456,7 +435,6 @@ CONFIG_PSMOUSE=y
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
 
 #
 # Video For Linux
@@ -471,28 +449,17 @@ CONFIG_NVRAM=y
 #
 # CONFIG_FTAPE is not set
 # CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
 # CONFIG_AGP is not set
 
 #
 # USB support
 #
 CONFIG_USB=y
-
-#
-# USB Controllers
-#
 # CONFIG_USB_UHCI is not set
 # CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
-
-#
-# Miscellaneous USB options
-#
 # CONFIG_USB_DEVICEFS is not set
-
-#
-# USB Devices
-#
 # CONFIG_USB_PRINTER is not set
 # CONFIG_USB_SCANNER is not set
 # CONFIG_USB_AUDIO is not set
@@ -503,14 +470,11 @@ CONFIG_USB_OHCI=y
 # CONFIG_USB_OV511 is not set
 # CONFIG_USB_DC2XX is not set
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_USS720 is not set
 # CONFIG_USB_DABUSB is not set
 # CONFIG_USB_PLUSB is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RIO500 is not set
-
-#
-# USB HID
-#
 # CONFIG_USB_HID is not set
 CONFIG_USB_KBD=y
 CONFIG_USB_MOUSE=y
@@ -546,6 +510,7 @@ CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -559,6 +524,7 @@ CONFIG_EXT2_FS=y
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
@@ -630,7 +596,6 @@ CONFIG_DMASOUND=y
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_DMAP is not set
 # CONFIG_SOUND_AD1816 is not set
 # CONFIG_SOUND_SGALAXY is not set
 CONFIG_SOUND_CS4232=m
@@ -643,7 +608,9 @@ CONFIG_SOUND_CS4232=m
 # CONFIG_SOUND_NM256 is not set
 # CONFIG_SOUND_MAD16 is not set
 # CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
 # CONFIG_SOUND_PSS is not set
+# CONFIG_PSS_HAVE_BOOT is not set
 # CONFIG_SOUND_SOFTOSS is not set
 # CONFIG_SOUND_SB is not set
 # CONFIG_SOUND_WAVEFRONT is not set
index c849bac82993815eb510e39c197fe0a93ffe8abe..bcab91ec6c1fa2e41ab50b192d8ef23642fd5a67 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
 #
 # CONFIG_UID16 is not set
 
@@ -33,7 +33,6 @@ CONFIG_KMOD=y
 #
 # General setup
 #
-# CONFIG_PCI is not set
 CONFIG_PCI=y
 CONFIG_PCI=y
 CONFIG_NET=y
@@ -46,6 +45,10 @@ CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PCI_NAMES is not set
 # CONFIG_HOTPLUG is not set
+
+#
+# Parallel port support
+#
 # CONFIG_PARPORT is not set
 CONFIG_VGA_CONSOLE=y
 CONFIG_FB=y
@@ -53,6 +56,7 @@ CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
 CONFIG_ADB=y
 CONFIG_ADB_CUDA=y
 CONFIG_ADB_MACIO=y
@@ -69,27 +73,21 @@ CONFIG_BOOTX_TEXT=y
 # Plug and Play configuration
 #
 # CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=y
-
-#
-# IDE chipset support/bugfixes
-#
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
@@ -108,10 +106,6 @@ CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_CPQ_DA is not set
-
-#
-# Additional Block Devices
-#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -144,18 +138,10 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
 CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
-
-#
-#  
-#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_DECNET is not set
@@ -177,10 +163,6 @@ CONFIG_ATALK=m
 # SCSI support
 #
 CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=y
@@ -189,10 +171,6 @@ CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_SR_EXTRA_DEVS=2
 CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 # CONFIG_SCSI_DEBUG_QUEUES is not set
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
@@ -272,6 +250,13 @@ CONFIG_NETDEVICES=y
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_IPDDP is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
@@ -299,6 +284,7 @@ CONFIG_PCNET32=y
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
 CONFIG_DE4X5=y
 # CONFIG_TULIP is not set
 # CONFIG_DGRS is not set
@@ -324,13 +310,6 @@ CONFIG_DE4X5=y
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
 CONFIG_PPP=y
 # CONFIG_PPP_ASYNC is not set
 # CONFIG_PPP_SYNC_TTY is not set
@@ -344,7 +323,7 @@ CONFIG_PPP=y
 # CONFIG_NET_RADIO is not set
 
 #
-# Token Ring driver support
+# Token Ring devices
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
@@ -397,7 +376,7 @@ CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 CONFIG_FB_ATY=y
-# CONFIG_FB_ATY128 is not set
+CONFIG_FB_ATY128=y
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -456,7 +435,6 @@ CONFIG_PSMOUSE=y
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
 
 #
 # Video For Linux
@@ -471,28 +449,17 @@ CONFIG_NVRAM=y
 #
 # CONFIG_FTAPE is not set
 # CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
 # CONFIG_AGP is not set
 
 #
 # USB support
 #
 CONFIG_USB=y
-
-#
-# USB Controllers
-#
 # CONFIG_USB_UHCI is not set
 # CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
-
-#
-# Miscellaneous USB options
-#
 # CONFIG_USB_DEVICEFS is not set
-
-#
-# USB Devices
-#
 # CONFIG_USB_PRINTER is not set
 # CONFIG_USB_SCANNER is not set
 # CONFIG_USB_AUDIO is not set
@@ -503,14 +470,11 @@ CONFIG_USB_OHCI=y
 # CONFIG_USB_OV511 is not set
 # CONFIG_USB_DC2XX is not set
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_USS720 is not set
 # CONFIG_USB_DABUSB is not set
 # CONFIG_USB_PLUSB is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RIO500 is not set
-
-#
-# USB HID
-#
 # CONFIG_USB_HID is not set
 CONFIG_USB_KBD=y
 CONFIG_USB_MOUSE=y
@@ -546,6 +510,7 @@ CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -559,6 +524,7 @@ CONFIG_EXT2_FS=y
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
@@ -630,7 +596,6 @@ CONFIG_DMASOUND=y
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_DMAP is not set
 # CONFIG_SOUND_AD1816 is not set
 # CONFIG_SOUND_SGALAXY is not set
 CONFIG_SOUND_CS4232=m
@@ -643,7 +608,9 @@ CONFIG_SOUND_CS4232=m
 # CONFIG_SOUND_NM256 is not set
 # CONFIG_SOUND_MAD16 is not set
 # CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
 # CONFIG_SOUND_PSS is not set
+# CONFIG_PSS_HAVE_BOOT is not set
 # CONFIG_SOUND_SOFTOSS is not set
 # CONFIG_SOUND_SB is not set
 # CONFIG_SOUND_WAVEFRONT is not set
index d55fa24c0d5c2de5ff401eb8c78d1e0d54461f8a..c692b54d08b5b3cdeda2d4050e35bfcdd4bf6b66 100644 (file)
@@ -173,7 +173,7 @@ void __init chrp_calibrate_decr(void)
        }
        freq *= 30;
        divisor = 30; 
-        printk("time_init: decrementer frequency = %lu/%d (%d MHz)\n", freq,
+        printk("time_init: decrementer frequency = %lu/%d (%ld MHz)\n", freq,
               divisor, (freq/divisor)>>20);
         decrementer_count = freq / HZ / divisor;
         count_period_num = divisor;
index f8e11ecc033bfa89ead781b2e23f4f24eb26f233..e4b2790326bd0750907a292e0625b8ff68c9aa90 100644 (file)
@@ -677,7 +677,7 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer,
 
        err = parse_hex_value(buffer, count, &new_value);
 
-#if CONFIG_SMP
+#if 0/*CONFIG_SMP*/
        /*
         * Do not allow disabling IRQs completely - it's a too easy
         * way to make the system unusable accidentally :-) At least
index 301a82ba8f4cfc6d37162d89e77ae0226107280e..9438c57eea37dd79f7fabc3b574ca0a8e6a00ca0 100644 (file)
@@ -97,7 +97,7 @@ struct hw_interrupt_type open_pic = {
 #define check_arg_cpu(cpu)     do {} while (0)
 #endif
 
-static void no_action(int ir1, void *dev, struct pt_regs *regs)
+void no_action(int ir1, void *dev, struct pt_regs *regs)
 {
 }
 
@@ -301,7 +301,7 @@ void find_ISUs(void)
        NumSources = 0x10;
 #else
        /* for non-distributed OpenPIC implementations it's in the IDU -- Cort */
-       ISU = OpenPIC->Source;
+       ISU = (OpenPIC_Source *)OpenPIC->Source;
 #endif
 }
 
index 310e301e64a0d1b4d8d4e3658e757406bd3713ed..a987b8fd6980b017136eb94bf9c3406424182da0 100644 (file)
@@ -114,9 +114,6 @@ static struct device_node *allnodes = 0;
 static void clearscreen(void);
 static void flushscreen(void);
 
-void prom_drawchar(char c);
-void prom_drawstring(const char *c);
-void prom_drawhex(unsigned long v);
 static void scrollscreen(void);
 
 static void draw_byte(unsigned char c, long locX, long locY);
index 0a70462a7a6dbe225bb729f86f343b077ccc519b..59b95c5dfcf39965cd9e7a298b5d104093867b27 100644 (file)
@@ -27,11 +27,9 @@ ISZ = 0
 
 TFTPIMAGE=/tftpboot/zImage.mbx
 ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
-GZIP_FLAGS = -v9
 
 OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o
 CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx
-OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O elf32-powerpc
 
 ifeq ($(CONFIG_MBX),y)
index f84810e1ef161776cd3b892536c8ed99d8fdeb7b..7d42a674182d31ec2c6d843e7f39616da4f9cbfe 100644 (file)
 
 HOSTCFLAGS = -O -I$(TOPDIR)/include
 
-CC     = $(CROSS_COMPILE)gcc
-LD     = $(CROSS_COMPILE)ld
-OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJDUMP        = $(CROSS_COMPILE)objdump
-
 GZIP   = gzip -vf9
 RM     = rm -f
 MKEVIMG        = mkevimg -l
index 620df9aea28acdc9d03a6814440074c476bfe4d3..b81e21890c2072f941bb6d9790402dae05e4cf2c 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <asm/ptrace.h>
 #include <asm/string.h>
+#include <asm/prom.h>
 #include "nonstdio.h"
 #include "privinst.h"
 
@@ -81,7 +82,7 @@ static void insert_bpts(void);
 static struct bpt *at_breakpoint(unsigned pc);
 static void bpt_cmds(void);
 static void cacheflush(void);
-static char *pretty_lookup_name(unsigned long addr);
+static char *pretty_print_addr(unsigned long addr);
 static char *lookup_name(unsigned long addr);
 
 extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
@@ -141,7 +142,7 @@ xmon(struct pt_regs *excp)
        prom_drawstring(" msr="); prom_drawhex(excp->msr);
        prom_drawstring(" trap="); prom_drawhex(excp->trap);
        prom_drawstring(" sp="); prom_drawhex(excp->gpr[1]);
-       sp = &excp->gpr[0];
+       sp = (unsigned *)&excp->gpr[0];
        for (i = 0; i < 32; ++i) {
                if ((i & 7) == 0)
                        prom_drawstring("\n");
@@ -544,10 +545,10 @@ getsp()
 void
 excprint(struct pt_regs *fp)
 {
-       printf("vector: %x at pc = %x %s",
-              fp->trap, fp->nip, pretty_lookup_name(fp->nip));
-       printf(", msr = %x, sp = %x [%x]\n",
-              fp->msr, fp->gpr[1], fp);
+       printf("vector: %x at pc = %x",
+              fp->trap, fp->nip);
+       printf(", lr = %x, msr = %x, sp = %x [%x]\n",
+              fp->link, fp->msr, fp->gpr[1], fp);
        if (fp->trap == 0x300 || fp->trap == 0x600)
                printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
        if (current)
@@ -1385,25 +1386,14 @@ char *str;
        lineptr = str;
 }
 
-/*
- * We use this array a lot here.  We assume we don't have multiple
- * instances of xmon running and that we don't use the return value of
- * any functions other than printing them.
- *  -- Cort
- */
-char last[64];
-static char *pretty_lookup_name(unsigned long addr)
+static char *pretty_print_addr(unsigned long addr)
 {
+       printf("%08x", addr);
        if ( lookup_name(addr) )
-       {
-               sprintf(last, " (%s)", lookup_name(addr));
-               return last;
-       }
-       else
-               return NULL;
+               printf(" %s", lookup_name(addr) );
+       return NULL;
 }
 
-
 static char *lookup_name(unsigned long addr)
 {
        extern char *sysmap;
@@ -1413,11 +1403,8 @@ static char *lookup_name(unsigned long addr)
 
        if ( !sysmap || !sysmap_size )
                return NULL;
-       
-       /* adjust if addr is relative to kernelbase */
-       if ( addr < PAGE_OFFSET )
-               addr += PAGE_OFFSET;
-
+return NULL;   
+#if 0
        cmp = simple_strtoul(c, &c, 8);
        strcpy( last, strsep( &c, "\n"));
        while ( c < (sysmap+sysmap_size) )
@@ -1427,6 +1414,7 @@ static char *lookup_name(unsigned long addr)
                        break;
                strcpy( last, strsep( &c, "\n"));
        }
-       return last;
+       return NULLlast;
+#endif 
 }
 
index 8b74eeafa019fd373b896bd46558b4f4526cf90c..fd858e00e339a7988818ce9baeaa13553dd92b82 100644 (file)
@@ -155,7 +155,7 @@ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/char/pcmcia/Config.in
 fi
 
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
 
 source fs/Config.in
 
index 5fabcdedca5f7f6fcbca431357cf7744b06316b2..ea5851d3925a2be9fd8ad12f05df0665685d3893 100644 (file)
@@ -95,10 +95,6 @@ CONFIG_SERIAL_CONSOLE=y
 #
 # CONFIG_UNIX98_PTYS is not set
 
-#
-# Misc devices
-#
-
 #
 # Filesystems
 #
index 580d004d71ef365141bba79587555cdef0107e8d..e719d92142f933db6f9310266c3792823c2fcea3 100644 (file)
@@ -83,6 +83,10 @@ CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 CONFIG_SUNOS_EMUL=y
+
+#
+# Parallel port support
+#
 # CONFIG_PARPORT is not set
 # CONFIG_PRINTER is not set
 
@@ -146,7 +150,6 @@ CONFIG_ATALK=m
 CONFIG_DECNET=m
 CONFIG_DECNET_SIOCGIFCONF=y
 # CONFIG_DECNET_ROUTER is not set
-CONFIG_DECNET_RAW=y
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
index d4585d9d5b56cc5018d88f9e839397c8c1a71c2a..e0bb410452754150c188f59bd388f6db66f04cba 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.93 2000/02/26 11:02:45 anton Exp $
+/* $Id: sparc_ksyms.c,v 1.94 2000/02/28 04:00:53 anton Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -107,16 +107,10 @@ EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
 EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
 #endif
 #ifdef __SMP__
-#ifdef DEBUG_IRQLOCK
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_cli);
-#else
-EXPORT_SYMBOL_PRIVATE(_global_restore_flags);
-EXPORT_SYMBOL_PRIVATE(_global_sti);
-EXPORT_SYMBOL_PRIVATE(_global_cli);
-#endif
 #endif
 
 /* rw semaphores */
index 54c701768441c988c3589a67cf9da0d0fe41c7e7..1d6f208f66fdcb310ee6ceec95799393c3fdebd0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.113 2000/02/16 07:31:29 davem Exp $
+/* $Id: sys_sunos.c,v 1.114 2000/03/07 22:27:27 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 1a8c404e29826f3926596335e839d0db3569f55f..d269e148b2fea4ddb4dd82ee9e3d0938fe018290 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.31 1999/12/28 11:50:39 jj Exp $
+# $Id: Makefile,v 1.32 2000/02/28 04:00:48 anton Exp $
 # Makefile for Sparc library files..
 #
 
@@ -8,10 +8,6 @@ OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
        copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \
        ashldi3.o rwsem.o
 
-ifdef CONFIG_SMP
-OBJS += irqlock.o
-endif
-
 lib.a: $(OBJS)
        $(AR) rcs lib.a $(OBJS)
        sync
diff --git a/arch/sparc/lib/irqlock.S b/arch/sparc/lib/irqlock.S
deleted file mode 100644 (file)
index 4c41e98..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* $Id: irqlock.S,v 1.5 1999/04/20 13:22:37 anton Exp $
- * irqlock.S: High performance IRQ global locking and interrupt entry.
- *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/psr.h>
-#include <asm/smp.h>
-
-       .text
-       .align  4
-
-       /* Weird calling conventions... %g7=flags, %g4=%prev_o7
-        * Very clever for the __global_sti case, the inline which
-        * gets us here clears %g7 and it just works.
-        */
-       .globl  ___global_restore_flags, ___global_sti, ___global_cli
-___global_restore_flags:
-       bne,a   ___global_cli
-        rd     %tbr, %g7
-       rd      %tbr, %g2
-
-___global_sti:
-       sethi   %hi(global_irq_holder), %g1
-       sethi   %hi(global_irq_lock), %g3
-       srl     %g2, 12, %g2
-       ldub    [%g1 + %lo(global_irq_holder)], %g5
-       and     %g2, 3, %g2
-       cmp     %g5, %g2
-       bne     1f
-        mov    NO_PROC_ID, %g5
-       stb     %g5, [%g1 + %lo(global_irq_holder)]
-       stb     %g0, [%g3 + %lo(global_irq_lock)]
-1:
-       rd      %psr, %g3
-       andcc   %g7, 2, %g0
-       bne,a   1f
-        or     %g3, PSR_PIL, %g3
-       andn    %g3, PSR_PIL, %g3
-1:
-       wr      %g3, 0x0, %psr
-       nop
-__global_cli_out:                      ! All togther now... "fuuunnnnn"
-       retl
-        mov    %g4, %o7
-
-__spin_on_global_irq_lock:
-       orcc    %g2, 0x0, %g0
-       bne,a   __spin_on_global_irq_lock
-        ldub   [%g1], %g2
-       b,a     1f
-
-       /* This is a royal pain in the ass to make fast... 8-( */
-___global_cli:
-       sethi   %hi(global_irq_lock), %g5
-       srl     %g7, 12, %g7
-       sethi   %hi(global_irq_holder), %g3
-       and     %g7, 3, %g7
-       ldub    [%g3 + %lo(global_irq_holder)], %g1
-       rd      %psr, %g2
-       cmp     %g1, %g7
-       or      %g2, PSR_PIL, %g2
-       be      __global_cli_out
-        wr     %g2, 0x0, %psr                  ! XXX some sparcs may choke on this...
-       sethi   %hi(local_irq_count), %g3
-       or      %g3, %lo(local_irq_count), %g3
-       or      %g5, %lo(global_irq_lock), %g1
-1:
-       ldstub  [%g1], %g2
-       orcc    %g2, 0x0, %g0
-       bne,a   __spin_on_global_irq_lock
-        ldub   [%g1], %g2
-__wait_on_irq:
-       sll     %g7, 2, %g7
-       ld      [%g3 + %g7], %g2
-       sethi   %hi(global_irq_count), %g1
-       or      %g1, %lo(global_irq_count), %g1
-       srl     %g7, 2, %g7
-       ld      [%g1], %g5
-       sra     %g5, 8, %g5
-__wait_on_irq_loop:
-       cmp     %g5, %g2
-       sethi   %hi(global_irq_holder), %g3
-       be,a    __global_cli_out        ! Mamamia, Mamamia, this is the fast path
-        stb    %g7, [%g3 + %lo(global_irq_holder)]
-1:
-       ldstub  [%g1 + 3], %g3
-       orcc    %g3, 0x0, %g0
-       bne     1b
-        ld     [%g1], %g3
-       sra     %g3, 8, %g3
-       sub     %g3, %g2, %g3
-       sll     %g3, 8, %g3
-       st      %g3, [%g1]
-       sethi   %hi(global_irq_lock), %g3
-       stb     %g0, [%g3 + %lo(global_irq_lock)]
-0:
-       ld      [%g1], %g5
-9:
-       ldub    [%g3 + %lo(global_irq_lock)], %g3
-       sra     %g5, 8, %g5
-       orcc    %g3, %g5, %g0
-       bne     0b
-        sethi  %hi(global_irq_lock), %g3
-       ldstub  [%g3 + %lo(global_irq_lock)], %g5
-       orcc    %g5, 0x0, %g0
-       bne,a   9b
-        ld     [%g1], %g5
-1:
-       ldstub  [%g1 + 3], %g3
-       orcc    %g3, 0x0, %g0
-       bne     1b
-        ld     [%g1], %g3
-       sra     %g3, 8, %g3
-       add     %g3, %g2, %g5
-       sll     %g5, 8, %g3
-       b       __wait_on_irq_loop
-        st     %g3, [%g1]
-
-#if 0 /* XXX I'm not delirious enough to debug this yet. */
-        add    %o7, (8 + (__wait_on_irq_loop - . - 4)), %o7    ! AIEEEEE
-#endif
index 3ac49a10bfb90cd4c767dd4fd2c2f034fba37a1e..d92fbbb0b180e0e0c0068c303c42058819195526 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.81 2000/02/26 11:59:31 anton Exp $
+/*  $Id: init.c,v 1.83 2000/03/07 23:12:35 anton Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -121,8 +121,8 @@ unsigned long __init bootmem_init(void)
        int i;
 
        /* Limit maximum memory until we implement highmem for sparc */
-       if (cmdline_memory_size > 0x9000000)
-               cmdline_memory_size = 0x9000000;
+       if (!cmdline_memory_size || cmdline_memory_size > 0x0d000000)
+               cmdline_memory_size = 0x0d000000;
 
        /* XXX It is a bit ambiguous here, whether we should
         * XXX treat the user specified mem=xxx as total wanted
@@ -138,7 +138,7 @@ unsigned long __init bootmem_init(void)
                        sp_banks[i].num_bytes;
                if (cmdline_memory_size) {
                        if (end_of_phys_memory > cmdline_memory_size) {
-                               if (cmdline_memory_size > sp_banks[i].base_addr) {
+                               if (cmdline_memory_size < sp_banks[i].base_addr) {
                                        end_of_phys_memory =
                                                sp_banks[i-1].base_addr +
                                                sp_banks[i-1].num_bytes;
index 7e7a45a709230bc26914a73468f6fef177cb6675..a61d4d0498424624e8a83c0c9dafe15506dcb769 100644 (file)
@@ -97,6 +97,10 @@ CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 # CONFIG_SUNOS_EMUL is not set
 CONFIG_SOLARIS_EMUL=m
+
+#
+# Parallel port support
+#
 CONFIG_PARPORT=m
 CONFIG_PARPORT_PC=m
 CONFIG_PARPORT_PC_FIFO=y
@@ -176,7 +180,6 @@ CONFIG_ATALK=m
 CONFIG_DECNET=m
 CONFIG_DECNET_SIOCGIFCONF=y
 # CONFIG_DECNET_ROUTER is not set
-CONFIG_DECNET_RAW=y
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
index 96360b010746982568710cd938fd0c38b50d7169..b4ee5625e62fe51e27d602c2e6133869070e1257 100644 (file)
@@ -328,6 +328,7 @@ again:
        stxa    %6, [%0+%8] %3
        membar  #Sync
        stxa    %%g0, [%7] %3
+       membar  #Sync
        mov     0x20, %%g1
        ldxa    [%%g1] 0x7f, %%g0
        membar  #Sync"
index d3f02ae5407c83d83de0aa763e965a10ff9e7a16..1fc0b1ba5bf3f8e00bf43e5da7d2d35df4f85512 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.133 2000/03/01 02:53:33 davem Exp $
+/* $Id: sys_sparc32.c,v 1.134 2000/03/07 22:27:30 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
index d977c7952efa4c6f7c172498f7fafaf3dc8a5cf7..9673cdd36e9b83e8101435119966bc766f3c5894 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.39 2000/02/16 07:31:37 davem Exp $
+/* $Id: sys_sunos32.c,v 1.40 2000/03/07 22:27:31 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
index 68147d4d4107ee74240602e459397a483cc2930f..d09ac451b61206800e62da124ec8954a1fbb0bde 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.147 2000/03/03 23:48:44 davem Exp $
+/*  $Id: init.c,v 1.148 2000/03/07 07:08:31 anton Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -824,7 +824,7 @@ unsigned long __init bootmem_init(void)
                        sp_banks[i].num_bytes;
                if (cmdline_memory_size) {
                        if (end_of_phys_memory > cmdline_memory_size) {
-                               if (cmdline_memory_size > sp_banks[i].base_addr) {
+                               if (cmdline_memory_size < sp_banks[i].base_addr) {
                                        end_of_phys_memory =
                                                sp_banks[i-1].base_addr +
                                                sp_banks[i-1].num_bytes;
index e15ef157c006773a9c56ac3794a49c24bdc07e52..e0875ad360740be0bafdcad7e0e9cc3dbfd5cbd7 100644 (file)
@@ -410,17 +410,10 @@ struct sol_statvfs64 {
 static int report_statvfs(struct inode *inode, u32 buf)
 {
        struct statfs s;
-       mm_segment_t old_fs = get_fs();
        int error;
        struct sol_statvfs *ss = (struct sol_statvfs *)A(buf);
 
-       if (!inode->i_sb)
-               return -ENODEV;
-       if (!inode->i_sb->s_op->statfs)
-               return -ENOSYS;
-       set_fs (KERNEL_DS);
-       error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
-       set_fs (old_fs);
+       error = vfs_statfs(inode->i_sb, &s);
        if (!error) {
                const char *p = inode->i_sb->s_type->name;
                int i = 0;
@@ -451,17 +444,10 @@ static int report_statvfs(struct inode *inode, u32 buf)
 static int report_statvfs64(struct inode *inode, u32 buf)
 {
        struct statfs s;
-       mm_segment_t old_fs = get_fs();
        int error;
        struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf);
                        
-       if (!inode->i_sb)
-               return -ENODEV;
-       if (!inode->i_sb->s_op->statfs)
-               return -ENOSYS;
-       set_fs (KERNEL_DS);
-       error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
-       set_fs (old_fs);
+       error = vfs_statfs(inode->i_sb, &s);
        if (!error) {
                const char *p = inode->i_sb->s_type->name;
                int i = 0;
index 1495809d60866ee0ae4467d80ce374d9a86581c6..e969e2dd701786f821aac23ed89976ae3c6ab631 100644 (file)
@@ -1051,20 +1051,23 @@ static int DAC_merge_requests_fn(request_queue_t *q,
        int max_segments;
        DAC960_Controller_T * Controller = q->queuedata;
        int total_segments = req->nr_segments + next->nr_segments;
+       int same_segment;
 
        max_segments = Controller->MaxSegmentsPerRequest[MINOR(req->rq_dev)];
        if (__max_segments < max_segments)
                max_segments = __max_segments;
 
+       same_segment = 0;
        if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
        {
                total_segments--;
-               q->nr_segments--;
+               same_segment = 1;
        }
     
        if (total_segments > max_segments)
                return 0;
 
+       q->nr_segments -= same_segment;
        req->nr_segments = total_segments;
        return 1;
 }
index 9e00cfa891f219dccd55b99842aa89f9d218c230..6882d03f3969d706d1ae64e6ba78122c447b9164 100644 (file)
@@ -182,6 +182,10 @@ ifeq ($(CONFIG_BLK_DEV_IDEPCI),y)
 IDE_OBJS += ide-pci.o
 endif
 
+ifeq ($(CONFIG_BLK_DEV_ISAPNP),y)
+IDE_OBJS += ide-pnp.o
+endif
+
 ifeq ($(CONFIG_BLK_DEV_IDE_PMAC),y)
 IDE_OBJS += ide-pmac.o
 endif
index 30be6a7ccd7556f49761338504b4f26ac5667b32..cc0aca5fd9740a803c5a795b1960d461a0a1703f 100644 (file)
@@ -54,9 +54,9 @@
 
 #include "ide_modes.h"
 
-#define ACARD_DEBUG_DRIVE_INFO 1
+#define ACARD_DEBUG_DRIVE_INFO         0
 
-#define DISPLAY_AEC6210_TIMINGS
+#undef DISPLAY_AEC6210_TIMINGS
 
 #if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
index 40b5c7797fbf84c2d7b56fc12a7c9619d14bdc3a..542ad44a171a8aa96bffb429dc79ff8fffcd3e53 100644 (file)
 #include <asm/io.h>
 #include "ide_modes.h"
 
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)      ((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
 #define CMD_DEBUG 0
-#undef NO_WRITE
 
 #if CMD_DEBUG
 #define cmdprintk(x...)        printk(##x)
 #define ARTTIM23       0x57
 #define   ARTTIM23_DIS_RA2     0x04
 #define   ARTTIM23_DIS_RA3     0x08
+#define ARTTIM2                0x57
+#define ARTTIM3                0x57
 #define DRWTIM23       0x58
 #define DRWTIM2                0x58
 #define BRST           0x59
 #define DRWTIM3                0x5b
 
+#define BMIDECR0       0x70
 #define MRDMODE                0x71
+#define BMIDESR0       0x72
+#define UDIDETCR0      0x73
+#define DTPR0          0x74
+#define BMIDECR1       0x78
+#define BMIDECSR       0x79
+#define BMIDESR1       0x7A
+#define UDIDETCR1      0x7B
+#define DTPR1          0x7C
 
-#define DISPLAY_CMD64X_TIMINGS
+#undef DISPLAY_CMD64X_TIMINGS
 
 #if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
@@ -68,8 +82,11 @@ static struct pci_dev *bmide_dev;
 static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
 {
        char *p = buffer;
-       u32 bibma = bmide_dev->resource[4].start;
-       u8  c0 = 0, c1 = 0;
+       u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;  /* primary */
+       u8 reg57 = 0, reg58 = 0, reg5b;                 /* secondary */
+       u8 reg72 = 0, reg73 = 0;                        /* primary */
+       u8 reg7a = 0, reg7b = 0;                        /* secondary */
+       u8 hi_byte = 0, lo_byte = 0;
 
        switch(bmide_dev->device) {
                case PCI_DEVICE_ID_CMD_648:
@@ -85,26 +102,57 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
                        p += sprintf(p, "\n                                CMD64? Chipse.\n");
                        break;
        }
+       (void) pci_read_config_byte(bmide_dev, ARTTIM0,   &reg53);
+       (void) pci_read_config_byte(bmide_dev, DRWTIM0,   &reg54);
+       (void) pci_read_config_byte(bmide_dev, ARTTIM1,   &reg55);
+       (void) pci_read_config_byte(bmide_dev, DRWTIM1,   &reg56);
+       (void) pci_read_config_byte(bmide_dev, ARTTIM2,   &reg57);
+       (void) pci_read_config_byte(bmide_dev, DRWTIM2,   &reg58);
+       (void) pci_read_config_byte(bmide_dev, DRWTIM3,   &reg5b);
+       (void) pci_read_config_byte(bmide_dev, BMIDESR0,  &reg72);
+       (void) pci_read_config_byte(bmide_dev, UDIDETCR0, &reg73);
+       (void) pci_read_config_byte(bmide_dev, BMIDESR1,  &reg7a);
+       (void) pci_read_config_byte(bmide_dev, UDIDETCR1, &reg7b);
 
-       /*
-        * at that point bibma+0x2 et bibma+0xa are byte registers
-        * to investigate:
-        */
-       c0 = inb_p((unsigned short)bibma + 0x02);
-       c1 = inb_p((unsigned short)bibma + 0x0a);
        p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
        p += sprintf(p, "                %sabled                         %sabled\n",
-                       (c0&0x80) ? "dis" : " en",
-                       (c1&0x80) ? "dis" : " en");
+                       (reg72&0x80) ? "dis" : " en", (reg7a&0x80) ? "dis" : " en");
        p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
        p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-                       (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-                       (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
-       p += sprintf(p, "UDMA\n");
-       p += sprintf(p, "DMA\n");
+                       (reg72&0x20) ? "yes" : "no ", (reg72&0x40) ? "yes" : "no ", (reg7a&0x20) ? "yes" : "no ", (reg7a&0x40) ? "yes" : "no " );
+       p += sprintf(p, "UDMA enabled:   %s              %s             %s               %s\n",
+                       (reg73&0x01) ? "yes" : "no ", (reg73&0x02) ? "yes" : "no ", (reg7b&0x01) ? "yes" : "no ", (reg7b&0x02) ? "yes" : "no " );
+       p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
+                       (reg73&0x15) ? "4" : (reg73&0x25) ? "3" : (reg73&0x11) ? "2" : (reg73&0x21) ? "1" : (reg73&0x31) ? "0" : "X",
+                       (reg73&0x4A) ? "4" : (reg73&0x8A) ? "3" : (reg73&0x42) ? "2" : (reg73&0x82) ? "1" : (reg73&0xC2) ? "0" : "X",
+                       (reg7b&0x15) ? "4" : (reg7b&0x25) ? "3" : (reg7b&0x11) ? "2" : (reg7b&0x21) ? "1" : (reg7b&0x31) ? "0" : "X",
+                       (reg7b&0x4A) ? "4" : (reg7b&0x8A) ? "3" : (reg7b&0x42) ? "2" : (reg7b&0x82) ? "1" : (reg7b&0xC2) ? "0" : "X" );
+       p += sprintf(p, "DMA enabled:    %s                %s               %s                 %s\n",
+                       (reg73&0x10) ? "2" : (reg73&0x20) ? "1" : (reg73&0x30) ? "0" : "X",
+                       (reg73&0x40) ? "2" : (reg73&0x80) ? "1" : (reg73&0xC0) ? "0" : "X",
+                       (reg7b&0x10) ? "2" : (reg7b&0x20) ? "1" : (reg7b&0x30) ? "0" : "X",
+                       (reg7b&0x40) ? "2" : (reg7b&0x80) ? "1" : (reg7b&0xC0) ? "0" : "X" );
        p += sprintf(p, "PIO\n");
 
+       SPLIT_BYTE(reg53, hi_byte, lo_byte);
+       p += sprintf(p, "ARTTIM0   = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg53, hi_byte, lo_byte);
+       SPLIT_BYTE(reg54, hi_byte, lo_byte);
+       p += sprintf(p, "DRWTIM0   = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg54, hi_byte, lo_byte);
+       SPLIT_BYTE(reg55, hi_byte, lo_byte);
+       p += sprintf(p, "ARTTIM1   = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg55, hi_byte, lo_byte);
+       SPLIT_BYTE(reg56, hi_byte, lo_byte);
+       p += sprintf(p, "DRWTIM1   = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg56, hi_byte, lo_byte);
+       SPLIT_BYTE(reg57, hi_byte, lo_byte);
+       p += sprintf(p, "ARTTIM23  = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
+       SPLIT_BYTE(reg58, hi_byte, lo_byte);
+       p += sprintf(p, "DRWTIM2   = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg58, hi_byte, lo_byte);
+       SPLIT_BYTE(reg5b, hi_byte, lo_byte);
+       p += sprintf(p, "DRWTIM3   = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg5b, hi_byte, lo_byte);
+       SPLIT_BYTE(reg73, hi_byte, lo_byte);
+       p += sprintf(p, "UDIDETCR0 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg73, hi_byte, lo_byte);
+       SPLIT_BYTE(reg7b, hi_byte, lo_byte);
+       p += sprintf(p, "UDIDETCR1 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg7b, hi_byte, lo_byte);
+
        return p-buffer;        /* => must be less than 4k! */
 }
 #endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -176,12 +224,10 @@ static void program_drive_counts (ide_drive_t *drive, int setup_count, int activ
         * and then the active/recovery counts into the DRWTIM reg
         */
        (void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b);
-#ifndef NO_WRITE
        (void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
                ((byte) setup_count) | (temp_b & 0x3f));
        (void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave],
                (byte) ((active_count << 4) | recovery_count));
-#endif
        cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]);
        cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]);
        __restore_flags(flags);
@@ -212,7 +258,7 @@ static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
                        return;
        }
 
-       (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+       mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
        pio_mode = d.pio_mode;
        cycle_time = d.cycle_time;
 
@@ -253,12 +299,84 @@ static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
         */
        program_drive_counts (drive, setup_count, active_count, recovery_count);
 
-       printk ("%s: selected cmd646 PIO mode%d (%dns)%s, clocks=%d/%d/%d\n",
-               drive->name, pio_mode, cycle_time,
+       cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, clocks=%d/%d/%d\n",
+               drive->name, pio_mode, mode_wanted, cycle_time,
                d.overridden ? " (overriding vendor mode)" : "",
                setup_count, active_count, recovery_count);
 }
 
+static int tune_chipset_for_dma (ide_drive_t *drive, byte speed)
+{
+#if 0
+       struct hd_driveid *id   = drive->id;
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+       unsigned long dma_base  = hwif->dma_base;
+       byte unit               = (drive->select.b.unit & 0x01);
+
+       u8 reg72 = 0, reg73 = 0;        /* primary */
+       u8 reg7a = 0, reg7b = 0;        /* secondary */
+       u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+       u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
+       u8 regU = (hwif->channel) ? 2 : 0;
+       u8 regD = (hwif->channel) ? 2 : 0;
+
+       (void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
+       (void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
+       (void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
+       (void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
+
+       switch(speed) {
+               case XFER_UDMA_4:
+                       pciU = unit ? 0x4A : 0x15;
+               case XFER_UDMA_3:
+                       pciU = unit ? 0x8A : 0x25;
+               case XFER_UDMA_2:
+                       pciU = unit ? 0x42 : 0x11;
+               case XFER_UDMA_1:
+                       pciU = unit ? 0x82 : 0x21;
+               case XFER_UDMA_0:
+                       pciU = unit ? 0xC2 : 0x31
+(reg73&0x15)?"4":(reg73&0x25)?"3":(reg73&0x11)?"2":(reg73&0x21)?"1":(reg73&0x31)?"0":"X",
+(reg73&0x4A)?"4":(reg73&0x8A)?"3":(reg73&0x42)?"2":(reg73&0x82)?"1":(reg73&0xC2)?"0":"X",
+(reg7b&0x15)?"4":(reg7b&0x25)?"3":(reg7b&0x11)?"2":(reg7b&0x21)?"1":(reg7b&0x31)?"0":"X",
+(reg7b&0x4A)?"4":(reg7b&0x8A)?"3":(reg7b&0x42)?"2":(reg7b&0x82)?"1":(reg7b&0xC2)?"0":"X",
+
+               case XFER_MW_DMA_2:
+                       pciD = unit ? 0x40 : 0x10;
+               case XFER_MW_DMA_1:
+                       pciD = unit ? 0x80 : 0x20;
+               case XFER_MW_DMA_0:
+                       pciD = unit ? 0xC0 : 0x30;
+               case XFER_SW_DMA_2:
+               case XFER_SW_DMA_1:
+               case XFER_SW_DMA_0:
+(reg73&0x10)?"2":(reg73&0x20)?"1":(reg73&0x30)?"0":"X",
+(reg73&0x40)?"2":(reg73&0x80)?"1":(reg73&0xC0)?"0":"X",
+(reg7b&0x10)?"2":(reg7b&0x20)?"1":(reg7b&0x30)?"0":"X",
+(reg7b&0x40)?"2":(reg7b&0x80)?"1":(reg7b&0xC0)?"0":"X" );
+
+               default:
+                       return 1;
+       }
+
+       (void) ide_config_drive_speed(drive, speed);
+       outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+#endif
+       return 0;
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+       byte speed      = 0x00;
+       byte set_pio    = ide_get_best_pio_mode(drive, 4, 5, NULL);     
+
+       cmd64x_tuneproc(drive, set_pio);
+       speed = XFER_PIO_0 + set_pio;
+       if (set_speed)
+               (void) ide_config_drive_speed(drive, speed);
+}
+
 static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
 {
        struct hd_driveid *id   = drive->id;
@@ -268,6 +386,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
 
        byte unit               = (drive->select.b.unit & 0x01);
        byte speed              = 0x00;
+       byte set_pio            = 0x00;
        byte udma_timing_bits   = 0x00;
        byte udma_33            = ((rev >= 0x05) || (ultra_66)) ? 1 : 0;
        byte udma_66            = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
@@ -326,9 +445,19 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
        } else if (id->dma_1word & 0x0001) {
                speed = XFER_SW_DMA_0;
        } else {
-               return ((int) ide_dma_off_quietly);
+               set_pio = 1;
        }
 
+       config_chipset_for_pio(drive, set_pio);
+
+       if (set_pio)
+               return ((int) ide_dma_off_quietly);
+
+#if 1
+       /*
+        * This the alternate access method. :-(
+        * The correct method is to directly setup the pci-config space.
+        */ 
        (void) ide_config_drive_speed(drive, speed);
        outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
 
@@ -343,6 +472,10 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
                udma_ctrl |=  (udma_timing_bits << (unit * 2));
                outb(udma_ctrl, dma_base+3);
        }
+#endif
+
+       if (tune_chipset_for_dma(drive, speed))
+               return ((int) ide_dma_off);
 
        rval = (int)(   ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
                        ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
@@ -353,11 +486,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
        return rval;
 }
 
-static void config_chipset_for_pio (ide_drive_t *drive, unsigned int rev)
-{
-       cmd64x_tuneproc(drive, 5);
-}
-
 static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
 {
        struct hd_driveid *id   = drive->id;
@@ -428,7 +556,7 @@ try_dma_modes:
 fast_ata_pio:
                dma_func = ide_dma_off_quietly;
 no_dma_set:
-               config_chipset_for_pio(drive, class_rev);
+               config_chipset_for_pio(drive, 1);
        }
        return HWIF(drive)->dmaproc(dma_func, drive);
 }
@@ -476,6 +604,11 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
        class_rev &= 0xff;
 
+#if 0
+       if (dev->resource[PCI_ROM_RESOURCE].start)
+               pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+#endif
+
        switch(dev->device) {
                case PCI_DEVICE_ID_CMD_643:
                        break;
@@ -520,18 +653,19 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
         *       this point.
         */
        (void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
-#if 0
+
        /* Set reasonable active/recovery/address-setup values. */
        (void) pci_write_config_byte(dev, ARTTIM0,  0x40);
        (void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
        (void) pci_write_config_byte(dev, ARTTIM1,  0x40);
        (void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
+#ifdef __i386__
+       (void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
+#else
        (void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
+#endif
        (void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
        (void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
-#else
-       (void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
-#endif
 
 #if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
        cmd64x_proc = 1;
@@ -547,7 +681,7 @@ unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
        byte ata66 = 0;
        byte mask = (hwif->channel) ? 0x02 : 0x01;
 
-       pci_read_config_byte(hwif->pci_dev, 0x79, &ata66);
+       pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
        return (ata66 & mask) ? 1 : 0;
 }
 
@@ -560,12 +694,11 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
        class_rev &= 0xff;
 
        hwif->tuneproc = &cmd64x_tuneproc;
+       hwif->drives[0].autotune = 1;
+       hwif->drives[0].autotune = 1;
 
-       if (!hwif->dma_base) {
-               hwif->drives[0].autotune = 1;
-               hwif->drives[1].autotune = 1;
+       if (!hwif->dma_base)
                return;
-       }
 
        switch(dev->device) {
                case PCI_DEVICE_ID_CMD_643:
index 7a077368edb5f08e60fd1d3ebe7704223e149453..425ce35a4fb02f92470c6abc9909d0fb8d5783a5 100644 (file)
 #define SPLIT_BYTE(B,H,L)      ((H)=(B>>4), (L)=(B-((B>>4)<<4)))
 #endif
 
-#define HPT343_DEBUG_DRIVE_INFO                1
+#define HPT343_DEBUG_DRIVE_INFO                0
+
+#undef DISPLAY_HPT34X_TIMINGS
 
-#define DISPLAY_HPT34X_TIMINGS
 #if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
index 02c9c16dd47e654849b17e91e4a910944352b36b..d2f2fb4338843081b7ba7d4aa6c13ece6df779eb 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "ide_modes.h"
 
-#define DISPLAY_HPT366_TIMINGS
+#undef DISPLAY_HPT366_TIMINGS
 
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
@@ -241,6 +241,11 @@ static int hpt366_tune_chipset (ide_drive_t *drive, byte speed)
        /*
         * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
         */
+       if (speed >= XFER_MW_DMA_0) {
+               reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
+       } else {
+               reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
+       }       
        reg2 &= ~0x80000000;
 
        pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
@@ -270,7 +275,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
        struct hd_driveid *id   = drive->id;
        byte speed              = 0x00;
        byte reg51h             = 0;
-       unsigned int reg40      = 0;
        int  rval;
 
        if ((id->dma_ultra & 0x0010) &&
@@ -326,13 +330,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
        if (reg51h & 0x80)
                pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80);
 #endif /* CONFIG_HPT366_FIP */
-
-       /*
-        * Preserve existing PIO settings:
-        */
-       pci_read_config_dword(HWIF(drive)->pci_dev, 0x40, &reg40);
-       speed = (speed & ~0xc0000000) | (reg40 & 0xc0000000);
-
 #if HPT366_DEBUG_DRIVE_INFO
        printk("%s: config_chipset_for_dma:  speed=0x%04x\n", drive->name, speed);
 #endif /* HPT366_DEBUG_DRIVE_INFO */
@@ -355,7 +352,6 @@ static void config_chipset_for_pio (ide_drive_t *drive)
        unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
        unsigned short xfer_pio = drive->id->eide_pio_modes;
        byte                    timing, speed, pio;
-       unsigned int reg40 = 0;
 
 #if HPT366_DEBUG_DRIVE_INFO
        printk("%s: config_chipset_for_pio\n", drive->name);
@@ -389,11 +385,6 @@ static void config_chipset_for_pio (ide_drive_t *drive)
                        speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
                        break;
        }
-       /*
-        * Preserve existing DMA settings:
-        */
-       pci_read_config_dword(HWIF(drive)->pci_dev, 0x40, &reg40);
-       speed = (speed & ~0x30070000) | (reg40 & 0x30070000);
 #if HPT366_DEBUG_DRIVE_INFO
        printk("%s: config_chipset_for_pio:  speed=0x%04x\n", drive->name, speed);
 #endif /* HPT366_DEBUG_DRIVE_INFO */
diff --git a/drivers/block/ide-pnp.c b/drivers/block/ide-pnp.c
new file mode 100644 (file)
index 0000000..a2f41de
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * linux/drivers/block/ide-pnp.c
+ *
+ * This file provides autodetection for ISA PnP IDE interfaces.
+ * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
+ *
+ * Copyright (C) 2000 Andrey Panin <pazke@orbita.don.sitek.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+ */
+
+#include <linux/config.h>
+#include <linux/ide.h>
+#include <linux/isapnp.h>
+
+#ifndef PREPARE_FUNC
+#define PREPARE_FUNC(dev)  (dev->prepare)
+#define ACTIVATE_FUNC(dev)  (dev->activate)
+#define DEACTIVATE_FUNC(dev)  (dev->deactivate)
+#endif
+
+#define DEV_IO(dev, index) (dev->resource[index].start)
+#define DEV_IRQ(dev, index) (dev->irq_resource[index].start)
+
+#define DEV_NAME(dev) (dev->bus->name ? dev->bus->name : "ISA PnP")
+
+#define GENERIC_HD_DATA                0
+#define GENERIC_HD_ERROR       1
+#define GENERIC_HD_NSECTOR     2
+#define GENERIC_HD_SECTOR      3
+#define GENERIC_HD_LCYL                4
+#define GENERIC_HD_HCYL                5
+#define GENERIC_HD_SELECT      6
+#define GENERIC_HD_STATUS      7
+
+static int generic_ide_offsets[IDE_NR_PORTS] __initdata = {
+       GENERIC_HD_DATA, GENERIC_HD_ERROR, GENERIC_HD_NSECTOR, 
+       GENERIC_HD_SECTOR, GENERIC_HD_LCYL, GENERIC_HD_HCYL,
+       GENERIC_HD_SELECT, GENERIC_HD_STATUS, -1, -1
+};
+
+/* ISA PnP device table entry */
+struct pnp_dev_t {
+       unsigned int vendor, device;
+       int (*init_fn)(struct pci_dev *dev, int enable);
+};
+
+/* Generic initialisation function for ISA PnP IDE interface */
+static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
+{
+       hw_regs_t hw;
+       int index;
+
+       if (!enable)
+               return 0;
+
+       if (!(DEV_IO(dev, 0) && DEV_IO(dev, 1) && DEV_IRQ(dev, 0)))
+               return 1;
+
+       ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0),
+                       generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1),
+                       0, NULL, DEV_IRQ(dev, 0));
+
+       index = ide_register_hw(&hw, NULL);
+
+       if (index != -1) {
+               printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev));
+               return 0;
+       }
+
+       return 1;
+}
+
+/* Add your devices here :)) */
+struct pnp_dev_t idepnp_devices[] __initdata = {
+       /* Generic ESDI/IDE/ATA compatible hard disk controller\r */
+       {       ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600),
+               pnpide_generic_init },
+       {       0 }
+};
+
+#ifdef MODULE
+#define NR_PNP_DEVICES 8
+struct pnp_dev_inst {
+       struct pci_dev *dev;
+       struct pnp_dev_t *dev_type;
+};
+static struct pnp_dev_inst devices[NR_PNP_DEVICES];
+static int pnp_ide_dev_idx = 0;
+#endif
+
+/*
+ * Probe for ISA PnP IDE interfaces.
+ */
+void pnpide_init(int enable)
+{
+       struct pci_dev *dev = NULL;
+       struct pnp_dev_t *dev_type;
+
+       if (!isapnp_present())
+               return;
+
+#ifdef MODULE
+       /* Module unload, deactivate all registered devices. */
+       if (!enable) {
+               int i;
+               for (i = 0; i < pnp_ide_dev_idx; i++) {
+                       devices[i].dev_type->init_fn(dev, 0);
+
+                       if (DEACTIVATE_FUNC(devices[i].dev))
+                               DEACTIVATE_FUNC(devices[i].dev)(devices[i].dev);
+               }
+               return;
+       }
+#endif
+       for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
+               while ((dev = isapnp_find_dev(NULL, dev_type->vendor,
+                       dev_type->device, dev))) {
+
+                       if (dev->active)
+                               continue;
+
+                               if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
+                               printk("ide: %s prepare failed\n", DEV_NAME(dev));
+                               continue;
+                       }
+
+                       if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
+                               printk("ide: %s activate failed\n", DEV_NAME(dev));
+                               continue;
+                       }
+
+                       /* Call device initialization function */
+                       if (dev_type->init_fn(dev, 1)) {
+                               if (DEACTIVATE_FUNC(dev))
+                                       DEACTIVATE_FUNC(dev)(dev);
+                       } else {
+#ifdef MODULE
+                               /*
+                                * Register device in the array to
+                                * deactivate it on a module unload.
+                                */
+                               if (pnp_ide_dev_idx >= NR_PNP_DEVICES)
+                                       return;
+                               devices[pnp_ide_dev_idx].dev = dev;
+                               devices[pnp_ide_dev_idx].dev_type = dev_type;
+                               pnp_ide_dev_idx++;
+#endif
+                       }
+               }
+       }
+}
index a51d6ee15fdd3b6e8a0b252f49a6fa9862cc5de7..311bcfa25fae7c0360f6da1cbe27e4ac4c2cb74c 100644 (file)
@@ -404,6 +404,7 @@ static int hwif_check_regions (ide_hwif_t *hwif)
 {
        int region_errors = 0;
 
+       hwif->straight8 = 0;
        region_errors  = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
        region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
        region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
@@ -412,16 +413,28 @@ static int hwif_check_regions (ide_hwif_t *hwif)
        region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
        region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
        region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+
        if (hwif->io_ports[IDE_CONTROL_OFFSET])
                region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+
        if (hwif->io_ports[IDE_IRQ_OFFSET])
                region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
 
+       /*
+        * If any errors are return, we drop the hwif interface.
+        */
        return(region_errors);
 }
 
 static void hwif_register (ide_hwif_t *hwif)
 {
+       if ((hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
+           (hwif->io_ports[IDE_STATUS_OFFSET])) {
+               ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
+               hwif->straight8 = 1;
+               goto jump_straight8;
+       }
+
        if (hwif->io_ports[IDE_DATA_OFFSET])
                ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name);
        if (hwif->io_ports[IDE_ERROR_OFFSET])
@@ -438,6 +451,8 @@ static void hwif_register (ide_hwif_t *hwif)
                ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name);
        if (hwif->io_ports[IDE_STATUS_OFFSET])
                ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name);
+
+jump_straight8:
        if (hwif->io_ports[IDE_CONTROL_OFFSET])
                ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
        if (hwif->io_ports[IDE_IRQ_OFFSET])
index 987093e5615b93647be05259f247c1ebbfbd3f98..326533e7fd008d1684f568cf6dbcf2c14578e337 100644 (file)
 extern byte fifoconfig;                /* defined in via82cxxx.c used by ide_setup() */
 #endif /* CONFIG_BLK_DEV_VIA82CXXX */
 
-static const byte      ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
-                                               IDE2_MAJOR, IDE3_MAJOR,
-                                               IDE4_MAJOR, IDE5_MAJOR,
-                                               IDE6_MAJOR, IDE7_MAJOR,
-                                               IDE8_MAJOR, IDE9_MAJOR };
-
-static int     idebus_parameter; /* holds the "idebus=" parameter */
-static int     system_bus_speed; /* holds what we think is VESA/PCI bus speed */
+static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
+
+static int     idebus_parameter = 0; /* holds the "idebus=" parameter */
+static int     system_bus_speed = 0; /* holds what we think is VESA/PCI bus speed */
 static int     initializing;     /* set while initializing built-in drivers */
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
-static int ide_scan_direction = 0;     /* HELLO, comment me!! */
+static int     ide_scan_direction = 0; /* THIS was formerly 2.2.x pci=reverse */
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 
 #if defined(__mc68000__) || defined(CONFIG_APUS)
@@ -186,8 +182,8 @@ static int  ide_lock = 0;
 /*
  * ide_modules keeps track of the available IDE chipset/probe/driver modules.
  */
-ide_module_t *ide_modules = NULL;
-ide_module_t *ide_probe = NULL;
+ide_module_t *ide_modules      = NULL;
+ide_module_t *ide_probe                = NULL;
 
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
@@ -1922,6 +1918,10 @@ ide_proc_entry_t generic_subdriver_entries[] = {
  */
 void hwif_unregister (ide_hwif_t *hwif)
 {
+       if (hwif->straight8) {
+               ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
+               goto jump_eight;
+       }
        if (hwif->io_ports[IDE_DATA_OFFSET])
                ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
        if (hwif->io_ports[IDE_ERROR_OFFSET])
@@ -1938,6 +1938,7 @@ void hwif_unregister (ide_hwif_t *hwif)
                ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
        if (hwif->io_ports[IDE_STATUS_OFFSET])
                ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+jump_eight:
        if (hwif->io_ports[IDE_CONTROL_OFFSET])
                ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
        if (hwif->io_ports[IDE_IRQ_OFFSET])
@@ -2102,6 +2103,7 @@ void ide_unregister (unsigned int index)
        hwif->pci_dev           = old_hwif.pci_dev;
        hwif->pci_devid         = old_hwif.pci_devid;
 #endif /* CONFIG_BLK_DEV_IDEPCI */
+       hwif->straight8         = old_hwif.straight8;
 
 abort:
        restore_flags(flags);   /* all CPUs */
@@ -2535,6 +2537,11 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                        err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
 
                        if (!err && set_transfer(drive, args[0], args[1], args[2])) {
+#if 0
+                               /* active-retuning-calls future */
+                               if (HWIF(drive)->tune2proc)
+                                       HWIF(drive)->tune2proc(drive, args[1]);
+#endif
                                ide_driveid_update(drive);
                        }
                abort:
@@ -2796,6 +2803,7 @@ int __init ide_setup (char *s)
        const char max_hwif  = '0' + (MAX_HWIFS - 1);
 
        printk("ide_setup: %s", s);
+       init_ide_data ();
 
 #ifdef CONFIG_BLK_DEV_IDEDOUBLER
        if (!strcmp(s, "ide=doubler")) {
@@ -2815,10 +2823,6 @@ int __init ide_setup (char *s)
        }
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 
-#ifndef CONFIG_BLK_DEV_IDEPCI
-       init_ide_data ();
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-
        /*
         * Look for drive options:  "hdx="
         */
@@ -2971,9 +2975,9 @@ int __init ide_setup (char *s)
        if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') {
                if (match_parm(&s[6], NULL, vals, 1) != 1)
                        goto bad_option;
-               if (vals[0] >= 20 && vals[0] <= 66)
+               if (vals[0] >= 20 && vals[0] <= 66) {
                        idebus_parameter = vals[0];
-               else
+               else
                        printk(" -- BAD BUS SPEED! Expected value from 20 to 66");
                goto done;
        }
@@ -3216,6 +3220,12 @@ static void __init probe_for_hwifs (void)
                buddha_init();
        }
 #endif /* CONFIG_BLK_DEV_BUDDHA */
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
+       {
+               extern void pnpide_init(int enable);
+               pnpide_init(1);
+       }
+#endif /* CONFIG_BLK_DEV_ISAPNP */
 }
 
 void __init ide_init_builtin_drivers (void)
@@ -3407,6 +3417,9 @@ int ide_unregister_subdriver (ide_drive_t *drive)
                restore_flags(flags);   /* all CPUs */
                return 1;
        }
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
+       pnpide_init(0);
+#endif /* CONFIG_BLK_DEV_ISAPNP */
 #ifdef CONFIG_PROC_FS
        ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
        ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
@@ -3550,6 +3563,7 @@ int __init ide_init (void)
        if (!banner_printed) {
                printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
                ide_devfs_handle = devfs_mk_dir (NULL, "ide", 3, NULL);
+               (void) ide_system_bus_speed();
                banner_printed = 1;
        }
 
@@ -3578,6 +3592,7 @@ static void __init parse_options (char *line)
                if ((next = strchr(line,' ')) != NULL)
                        *next++ = 0;
                if (!strncmp(line,"ide",3) ||
+                   !strncmp(line,"idebus",6) ||
 #ifdef CONFIG_BLK_DEV_VIA82CXXX
                    !strncmp(line,"splitfifo",9) ||
 #endif /* CONFIG_BLK_DEV_VIA82CXXX */
index b6c28e6ab71864073b560183bf7f70ae78fe8083..f94d9131389e8136e7281de16041bea3689c43e2 100644 (file)
@@ -197,6 +197,10 @@ byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode,
                        }
                }
 
+#if 0
+               if (drive->id->major_rev_num & 0x0004) printf("ATA-2 ");
+#endif
+
                /*
                 * Conservative "downgrade" for all pre-ATA2 drives
                 */
index af5bdc3e2783a3d0f506261226a0aebb91e9da71..21ab621f6b0bcbfbee365d9092b7e892ca8edb37 100644 (file)
@@ -212,15 +212,18 @@ static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
                                struct request *next, int max_segments)
 {
        int total_segments = req->nr_segments + next->nr_segments;
+       int same_segment;
 
+       same_segment = 0;
        if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) {
                total_segments--;
-               q->nr_segments--;
+               same_segment = 1;
        }
     
        if (total_segments > max_segments)
                return 0;
 
+       q->nr_segments -= same_segment;
        req->nr_segments = total_segments;
        return 1;
 }
@@ -472,14 +475,8 @@ static inline void __elevator_merge(request_queue_t * q, struct request * req, i
        int sequence = elevator_sequence(&q->elevator, latency);
        if (after)
                sequence -= req->nr_segments;
-       if (elevator_sequence_before(sequence, req->elevator_sequence)) {
-               if (!after)
-                       printk(KERN_WARNING __FUNCTION__
-                              ": req latency %d req latency %d\n",
-                              req->elevator_sequence - q->elevator.sequence,
-                              sequence - q->elevator.sequence);
+       if (elevator_sequence_before(sequence, req->elevator_sequence))
                req->elevator_sequence = sequence;
-       }
 }
 
 static inline void elevator_queue(request_queue_t * q,
index bce80650cf4737d1748ce776f27285480200c20c..9ec7c8997e530810a2a8476bf511c530031c6e25 100644 (file)
 #define PDC202XX_DEBUG_DRIVE_INFO              0
 #define PDC202XX_DECODE_REGISTER_INFO          0
 
-#define DISPLAY_PDC202XX_TIMINGS
+#undef DISPLAY_PDC202XX_TIMINGS
+
 #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
index 9686f05b694c82d8b3c18a3ddd7c42af071ff296..a51dcd36feed51ea136260bb46b73372f0edd811 100644 (file)
@@ -99,6 +99,7 @@ static int rd_hardsec[NUM_RAMDISKS];          /* Size of real blocks in bytes */
 static int rd_blocksizes[NUM_RAMDISKS];                /* Size of 1024 byte blocks :)  */
 static int rd_kbsize[NUM_RAMDISKS];            /* Size in blocks of 1024 bytes */
 static devfs_handle_t devfs_handle = NULL;
+static struct inode *rd_inode[NUM_RAMDISKS];           /* Protected device inodes */
 
 /*
  * Parameters for the boot-loading of the RAM disk.  These are set by
@@ -169,11 +170,18 @@ static int __init ramdisk_size2(char *str)
        return ramdisk_size(str);
 }
 
+static int __init ramdisk_blocksize(char *str)
+{
+       rd_blocksize = simple_strtol(str,NULL,0);
+       return 1;
+}
+
 __setup("ramdisk_start=", ramdisk_start_setup);
 __setup("load_ramdisk=", load_ramdisk);
 __setup("prompt_ramdisk=", prompt_ramdisk);
 __setup("ramdisk=", ramdisk_size);
 __setup("ramdisk_size=", ramdisk_size2);
+__setup("ramdisk_blocksize=", ramdisk_blocksize);
 
 #endif
 
@@ -216,67 +224,16 @@ repeat:
                goto repeat;
        }
 
-       /*
-        * This has become somewhat more complicated with the addition of
-        * the page cache.  The problem is that in some cases the furnished
-        * buffer is "real", i.e., part of the existing ramdisk, while in
-        * others it is "unreal", e.g., part of a page.  In the first case
-        * not much needs to be done, while in the second, some kind of
-        * transfer is needed.
-        *
-        * The two cases are distinguished here by checking whether the
-        * real buffer is already in the buffer cache, and whether it is
-        * the same as the one supplied.
-        *
-        * There are three cases with read/write to consider:
-        *
-        * 1. Supplied buffer matched one in the buffer cache:
-        *    Read - Clear the buffer, as it wasn't already valid.
-        *    Write - Mark the buffer as "Protected".
-        *
-        * 2. Supplied buffer mismatched one in the buffer cache:
-        *    Read - Copy the data from the buffer cache entry.
-        *    Write - Copy the data to the buffer cache entry.
-        *
-        * 3  No buffer cache entry existed:
-        *    Read - Clear the supplied buffer, but do not create a real
-        *    one.
-        *    Write - Create a real buffer, copy the data to it, and mark
-        *    it as "Protected".
-        *
-        * NOTE: There seems to be some schizophrenia here - the logic
-        * using "len" seems to assume arbitrary request lengths, while
-        * the "protect" logic assumes a single buffer cache entry.
-        * This seems to be left over from the ancient contiguous ramdisk
-        * logic.
-        */
-
        sbh = CURRENT->bh;
-       rbh = get_hash_table(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
-       if (sbh == rbh) {
-               if (CURRENT->cmd == READ) 
-                       memset(CURRENT->buffer, 1, len);
-       } else if (rbh) {
-               if (CURRENT->cmd == READ)
+       rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
+       if (CURRENT->cmd == READ) {
+               if (sbh != rbh)
                        memcpy(CURRENT->buffer, rbh->b_data, rbh->b_size);
-               else
+       } else
+               if (sbh != rbh)
                        memcpy(rbh->b_data, CURRENT->buffer, rbh->b_size);
-       } else { /* !rbh */
-               if (CURRENT->cmd == READ)
-                       memset(sbh->b_data, 2, len);
-               else {
-                       rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
-                       if (rbh)
-                               memcpy(rbh->b_data, CURRENT->buffer,
-                                   rbh->b_size);
-                       else
-                               BUG();  /* No buffer, what to do here? */
-               }
-       }
-       if (rbh) {
-               mark_buffer_protected(rbh);
-               brelse(rbh);
-       }
+       mark_buffer_protected(rbh);
+       brelse(rbh);
 
        end_request(1);
        goto repeat;
@@ -372,6 +329,14 @@ static int rd_open(struct inode * inode, struct file * filp)
        if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS)
                return -ENXIO;
 
+       /*
+        * Immunize device against invalidate_buffers() and prune_icache().
+        */
+       if (rd_inode[DEVICE_NR(inode->i_rdev)] == NULL) {
+               if((rd_inode[DEVICE_NR(inode->i_rdev)] = igrab(inode)) != NULL)
+                       atomic_inc(&rd_inode[DEVICE_NR(inode->i_rdev)]->i_bdev->bd_openers);
+       }
+
        MOD_INC_USE_COUNT;
 
        return 0;
@@ -389,24 +354,31 @@ static struct block_device_operations fd_fops = {
        ioctl:          rd_ioctl,
 };
 
+#ifdef MODULE
 /* Before freeing the module, invalidate all of the protected buffers! */
 static void __exit rd_cleanup (void)
 {
        int i;
 
        for (i = 0 ; i < NUM_RAMDISKS; i++) {
-               struct block_device *bdev;
-               bdev = bdget(kdev_t_to_nr(MKDEV(MAJOR_NR,i)));
-               atomic_dec(&bdev->bd_openers);
+               if (rd_inode[i]) {
+                       /* withdraw invalidate_buffers() and prune_icache() immunity */
+                       atomic_dec(&rd_inode[i]->i_bdev->bd_openers);
+                       /* remove stale pointer to module address space */
+                       rd_inode[i]->i_bdev->bd_op = NULL;
+                       iput(rd_inode[i]);
+               }
                destroy_buffers(MKDEV(MAJOR_NR, i));
        }
 
        devfs_unregister (devfs_handle);
        unregister_blkdev( MAJOR_NR, "ramdisk" );
        blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+       hardsect_size[MAJOR_NR] = NULL;
        blksize_size[MAJOR_NR] = NULL;
        blk_size[MAJOR_NR] = NULL;
 }
+#endif
 
 /* This is the registration and initialization section of the RAM disk driver */
 int __init rd_init (void)
@@ -441,21 +413,16 @@ int __init rd_init (void)
                               S_IFBLK | S_IRUSR | S_IWUSR, 0, 0,
                               &fd_fops, NULL);
 
-       hardsect_size[MAJOR_NR] = rd_hardsec;           /* Size of the RAM disk blocks */
-       blksize_size[MAJOR_NR] = rd_blocksizes;         /* Avoid set_blocksize() check */
-
-       for (i = 0; i < NUM_RAMDISKS; i++) {
-               struct block_device *bdev;
+       for (i = 0; i < NUM_RAMDISKS; i++)
                register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &fd_fops, rd_size<<1);
-               bdev = bdget(kdev_t_to_nr(MKDEV(MAJOR_NR,i)));
-               atomic_inc(&bdev->bd_openers);  /* avoid invalidate_buffers() */
-       }
 
 #ifdef CONFIG_BLK_DEV_INITRD
        /* We ought to separate initrd operations here */
        register_disk(NULL, MKDEV(MAJOR_NR,INITRD_MINOR), 1, &fd_fops, rd_size<<1);
 #endif
 
+       hardsect_size[MAJOR_NR] = rd_hardsec;           /* Size of the RAM disk blocks */
+       blksize_size[MAJOR_NR] = rd_blocksizes;         /* Avoid set_blocksize() check */
        blk_size[MAJOR_NR] = rd_kbsize;                 /* Size of the RAM disk in kB  */
 
                /* rd_size is given in kB */
@@ -468,8 +435,8 @@ int __init rd_init (void)
 
 #ifdef MODULE
 module_init(rd_init);
-#endif
 module_exit(rd_cleanup);
+#endif
 
 /* loadable module support */
 MODULE_PARM     (rd_size, "1i");
index 54681f38c8472f3929b0a79a528acd34effddffb..c2ec24d391d6420acdec9a7b19960c32276cb99a 100644 (file)
  *  Note that by default (if no command line is provided) and if a channel
  *  has been disabled in Bios, all the fifo is given to the active channel,
  *  and its threshold is set to 3/4.
+ *
+ *  VT82c586B
+ *
+ *    Offset 4B-48 - Drive Timing Control
+ *             | pio0 | pio1 | pio2 | pio3 | pio4
+ *    25.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20 
+ *    33.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20
+ *    37.5 MHz | 0xA9 | 0x76 | 0x76 | 0x32 | 0x21
+ *
+ *    Offset 53-50 - UltraDMA Extended Timing Control
+ *      UDMA   |  NO  |   0  |   1  |   2
+ *             | 0x03 | 0x62 | 0x61 | 0x60
+ *
+ *  VT82c596B & VT82c686A
+ *
+ *    Offset 4B-48 - Drive Timing Control
+ *             | pio0 | pio1 | pio2 | pio3 | pio4
+ *    25.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20
+ *    33.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20
+ *    37.5 MHz | 0xDB | 0x87 | 0x87 | 0x42 | 0x31
+ *    41.5 MHz | 0xFE | 0xA8 | 0xA8 | 0x53 | 0x32
+ *
+ *    Offset 53-50 - UltraDMA Extended Timing Control
+ *      UDMA   |  NO  |   0  |   1  |   2
+ *    33.0 MHz | 0x03 | 0xE2 | 0xE1 | 0xE0
+ *    37.5 MHz | 0x03 | 0xE2 | 0xE2 | 0xE1   (1)
+ *
+ *    Offset 53-50 - UltraDMA Extended Timing Control
+ *      UDMA   |  NO  |   0  |   1  |   2  |   3  |   4
+ *    33.0 MHz |  (2) | 0xE6 | 0xE4 | 0xE2 | 0xE1 | 0xE0
+ *    37.5 MHz |  (2) | 0xE6 | 0xE6 | 0xE4 | 0xE2 | 0xE1   (1)
+ *
  */
 
 #include <linux/config.h>
@@ -76,6 +108,8 @@ static const struct {
        { "VT 82C691 Apollo Pro",       PCI_DEVICE_ID_VIA_82C691, },
        { "VT 82C693 Apollo Pro Plus",  PCI_DEVICE_ID_VIA_82C693, },
        { "Apollo MVP4",                PCI_DEVICE_ID_VIA_8501_0, },
+       { "VT 8371",                    PCI_DEVICE_ID_VIA_8371_0, },
+       { "VT 8601",                    PCI_DEVICE_ID_VIA_8601_0, },
 };
 
 #define NUM_APOLLO_ISA_CHIP_DEVICES    2
@@ -96,6 +130,8 @@ static const struct {
        { PCI_DEVICE_ID_VIA_82C691,     PCI_DEVICE_ID_VIA_82C596,       0 },
        { PCI_DEVICE_ID_VIA_82C693,     PCI_DEVICE_ID_VIA_82C596,       0 },
        { PCI_DEVICE_ID_VIA_8501_0,     PCI_DEVICE_ID_VIA_82C686,       VIA_FLAG_ATA_66 },
+       { PCI_DEVICE_ID_VIA_8371_0,     PCI_DEVICE_ID_VIA_82C686,       VIA_FLAG_ATA_66 },
+       { PCI_DEVICE_ID_VIA_8601_0,     PCI_DEVICE_ID_VIA_8231,         VIA_FLAG_ATA_66 },
 };
 
 #define arraysize(x)   (sizeof(x)/sizeof(*(x)))
@@ -477,6 +513,220 @@ static int via_set_fifoconfig(ide_hwif_t *hwif)
        return 0;
 }
 
+#ifdef CONFIG_VIA82CXXX_TUNING
+
+static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
+{
+       struct hd_driveid *id   = drive->id;
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+       unsigned long dma_base  = hwif->dma_base;
+       byte unit               = (drive->select.b.unit & 0x01);
+       int drive_number        = ((hwif->channel ? 2 : 0) + unit);
+
+       byte ata2_pci           = 0x00;
+       byte ata3_pci           = 0x00;
+       byte timing             = 0x00;
+       byte ultra              = 0x00;
+       int                     err;
+
+       int bus_speed           = ide_system_bus_speed();
+
+       switch(drive_number) {
+               case 0: ata2_pci = 0x48; ata3_pci = 0x50; break;
+               case 1: ata2_pci = 0x49; ata3_pci = 0x51; break;
+               case 2: ata2_pci = 0x4a; ata3_pci = 0x52; break;
+               case 3: ata2_pci = 0x4b; ata3_pci = 0x53; break;
+               default:
+                       return err;
+       }
+
+       pci_read_config_byte(dev, ata2_pci, &timing);
+       pci_read_config_byte(dev, ata3_pci, &ultra);
+
+       switch(speed) {
+               case XFER_UDMA_4:
+               case XFER_UDMA_3:
+               case XFER_UDMA_2:
+               case XFER_UDMA_1:
+               case XFER_UDMA_0:
+               case XFER_MW_DMA_2:
+               case XFER_MW_DMA_1:
+               case XFER_MW_DMA_0:
+               case XFER_SW_DMA_2:
+               case XFER_SW_DMA_1:
+               case XFER_SW_DMA_0:
+               case XFER_PIO_4:
+               case XFER_PIO_3:
+               case XFER_PIO_2:
+               case XFER_PIO_1:
+               case XFER_PIO_0:
+               case XFER_PIO_SLOW:
+               default:
+                       break;
+       }
+
+       pci_write_config_byte(dev, ata2_pci, timing);
+       pci_write_config_byte(dev, ata3_pci, ultra);
+
+       err = ide_config_drive_speed(drive, speed);
+
+       return(err);
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+       struct hd_driveid *id   = drive->id;
+       byte speed              = 0x00;
+       int  rval;
+
+       if ((id->dma_ultra & 0x0010) && (HWIF(drive)->udma_four)) {
+               speed = XFER_UDMA_4;
+       } else if ((id->dma_ultra & 0x0008) && (HWIF(drive)->udma_four)) {
+               speed = XFER_UDMA_3;
+       } else if (id->dma_ultra & 0x0004) {
+               speed = XFER_UDMA_2;
+       } else if (id->dma_ultra & 0x0002) {
+               speed = XFER_UDMA_1;
+       } else if (id->dma_ultra & 0x0001) {
+               speed = XFER_UDMA_0;
+       } else if (id->dma_mword & 0x0004) {
+               speed = XFER_MW_DMA_2;
+       } else if (id->dma_mword & 0x0002) {
+               speed = XFER_MW_DMA_1;
+       } else if (id->dma_mword & 0x0001) {
+               speed = XFER_MW_DMA_0;
+       } else if (id->dma_1word & 0x0004) {
+               speed = XFER_SW_DMA_2;
+       } else if (id->dma_1word & 0x0002) {
+               speed = XFER_SW_DMA_1;
+       } else if (id->dma_1word & 0x0001) {
+               speed = XFER_SW_DMA_0;
+       } else {
+               return ((int) ide_dma_off_quietly);
+       }
+
+       (void) via82cxxx_tune_chipset(drive, speed);
+
+       rval = (int)(   ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+                       ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+                                                    ide_dma_off_quietly);
+       return rval;
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+       unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+       unsigned short xfer_pio = drive->id->eide_pio_modes;
+       byte                    timing, speed, pio;
+
+       pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+       if (xfer_pio> 4)
+               xfer_pio = 0;
+
+       if (drive->id->eide_pio_iordy > 0) {
+               for (xfer_pio = 5;
+                       xfer_pio>0 &&
+                       drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+                       xfer_pio--);
+       } else {
+               xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+                          (drive->id->eide_pio_modes & 2) ? 0x04 :
+                          (drive->id->eide_pio_modes & 1) ? 0x03 :
+                          (drive->id->tPIO & 2) ? 0x02 :
+                          (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+       }
+
+       timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+       switch(timing) {
+               case 4: speed = XFER_PIO_4;break;
+               case 3: speed = XFER_PIO_3;break;
+               case 2: speed = XFER_PIO_2;break;
+               case 1: speed = XFER_PIO_1;break;
+               default:
+                       speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;                        break;
+       }
+       (void) via82cxxx_tune_chipset(drive, speed);
+}
+
+static void via82cxxx_tune_drive (ide_drive_t *drive, byte pio)
+{
+       byte speed;
+       switch(pio) {
+               case 4:         speed = XFER_PIO_4;break;
+               case 3:         speed = XFER_PIO_3;break;
+               case 2:         speed = XFER_PIO_2;break;
+               case 1:         speed = XFER_PIO_1;break;
+               default:        speed = XFER_PIO_0;break;
+       }
+       (void) via82cxxx_tune_chipset(drive, speed);
+}
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+       struct hd_driveid *id = drive->id;
+       ide_dma_action_t dma_func = ide_dma_on;
+
+       if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+                       dma_func = ide_dma_off;
+                       goto fast_ata_pio;
+               }
+               dma_func = ide_dma_off_quietly;
+               if (id->field_valid & 4) {
+                       if (id->dma_ultra & 0x001F) {
+                               /* Force if Capable UltraDMA */
+                               dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+                                   (dma_func != ide_dma_on))
+                                       goto try_dma_modes;
+                       }
+               } else if (id->field_valid & 2) {
+try_dma_modes:
+                       if ((id->dma_mword & 0x0007) ||
+                           (id->dma_1word & 0x0007)) {
+                               /* Force if Capable regular DMA modes */
+                               dma_func = config_chipset_for_dma(drive);
+                               if (dma_func != ide_dma_on)
+                                       goto no_dma_set;
+                       }
+               } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+                       if (id->eide_dma_time > 150) {
+                               goto no_dma_set;
+                       }
+                       /* Consult the list of known "good" drives */
+                       dma_func = config_chipset_for_dma(drive);
+                       if (dma_func != ide_dma_on)
+                               goto no_dma_set;
+               } else {
+                       goto fast_ata_pio;
+               }
+       } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+               dma_func = ide_dma_off_quietly;
+no_dma_set:
+               config_chipset_for_pio(drive);
+       }
+       return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+int via82cxxx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+       switch (func) {
+               case ide_dma_check:
+                       return config_drive_xfer_rate(drive);
+               default:
+                       break;
+       }
+       return ide_dmaproc(func, drive);        /* use standard DMA stuff */
+}
+#endif /* CONFIG_VIA82CXXX_TUNING */
+
 unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
 {
        struct pci_dev *host;
@@ -501,7 +751,7 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
                                continue;
 
                        isa = pci_find_device (PCI_VENDOR_ID_VIA,
-                                       ApolloISAChipInfo[i].isa_id,
+                                       ApolloISAChipInfo[j].isa_id,
                                        NULL);
                        if (!isa)
                                continue;
@@ -511,10 +761,10 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
                        ata33 = 1;
                        ata66 = 0;
 
-                       if (ApolloISAChipInfo[i].flags & VIA_FLAG_CHECK_REV) {
+                       if (ApolloISAChipInfo[j].flags & VIA_FLAG_CHECK_REV) {
                                pci_read_config_byte(isa_dev, 0x0d, &revision);
                                ata33 = (revision >= 0x20) ? 1 : 0;
-                       } else if (ApolloISAChipInfo[i].flags & VIA_FLAG_ATA_66) {
+                       } else if (ApolloISAChipInfo[j].flags & VIA_FLAG_ATA_66) {
                                ata33 = 0;
                                ata66 = 1;
                        }
@@ -543,7 +793,8 @@ unsigned int __init ata66_via82cxxx (ide_hwif_t *hwif)
 void __init ide_init_via82cxxx (ide_hwif_t *hwif)
 {
        set_via_timings(hwif);
-#if 0
+
+#ifdef CONFIG_VIA82CXXX_TUNING
        hwif->tuneproc = &via82cxxx_tune_drive;
        if (hwif->dma_base) {
                hwif->dmaproc = &via82cxxx_dmaproc;
@@ -552,7 +803,7 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif)
                hwif->drives[0].autotune = 1;
                hwif->drives[1].autotune = 1;
        }
-#endif
+#endif /* CONFIG_VIA82CXXX_TUNING */
 }
 
 /*
index 92054676397c430dd104dc344c848904974c3056..6825b3013dce1d28d4e4abde39192db1cb246f79 100644 (file)
@@ -140,7 +140,9 @@ fi
 
 tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
-bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
+if [ "$CONFIG_IA64" = "y" ]; then
+   bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
+fi
 if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then
    bool 'Tadpole ANA H8 Support'  CONFIG_H8
 fi
index 3c41aa732075acec32f33d2634c4fd68ca964f34..ea6c0f3c2a0c722d2943c89f572f198558eebbdd 100644 (file)
@@ -52,6 +52,7 @@ extern int videodev_init(void);
 #endif
 #ifdef CONFIG_FB
 extern void fbmem_init(void);
+extern void fbconsole_init(void);
 #endif
 #ifdef CONFIG_PROM_CONSOLE
 extern void prom_con_init(void);
@@ -617,6 +618,7 @@ int __init chr_dev_init(void)
 #endif
 #if defined (CONFIG_FB)
        fbmem_init();
+       fbconsole_init();
 #endif
 #if defined (CONFIG_PROM_CONSOLE)
        prom_con_init();
index d47b1062eb1c5e04b4cd62ae7f8d3d1edc2494c5..d9019b0465b1105377ad647436aaffac055bddcb 100644 (file)
@@ -227,7 +227,7 @@ static void special_device_init(void)
                extern int sb1000_probe(struct net_device *dev);
                static struct net_device sb1000_dev = 
                {
-                       "cm0 __PAD3", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, sb1000_probe 
+                       "cm0" __PAD3, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, sb1000_probe 
                };
                register_netdev(&sb1000_dev);
        }
index bf48c15e4de0619c9c94dc981df0b2d669fdd6d1..f90055b45df6a38bd98a03a7b9f12c6a764d0147 100644 (file)
@@ -14,7 +14,7 @@ obj-y   :=
 obj-n   :=
 obj-m   :=
 obj-    :=
-export-objs :=
+export-objs := tms380tr.o
 
 obj-$(CONFIG_IBMTR)    += ibmtr.o
 obj-$(CONFIG_IBMOL)    += olympic.o
index 417cc7c2928b20136af2d35596dbebd64c0d075d..937dfadf8a9cc06b7ca1949eba363c59e73875e8 100644 (file)
@@ -72,7 +72,6 @@ static const char *version = "tms380tr.c: v1.07 21/01/2000 by Christoph Goos, Ad
 #endif
 
 #ifdef MODULE
-#define EXPORT_SYMTAB
 #include <linux/module.h>
 #include <linux/version.h>
 #endif
index dbbaaa5d7c6f74aad40cb36a7ccb6a4495c44d6f..b82dbac5192a9ac63600f54d4ff995efdbdfa924 100644 (file)
@@ -420,8 +420,6 @@ media_picked:
        tp->timer.data = (unsigned long)dev;
        tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
        add_timer(&tp->timer);
-
-       netif_device_attach(dev);
 }
 
 
@@ -439,6 +437,8 @@ tulip_open(struct net_device *dev)
        
        tulip_up (dev);
        
+       netif_start_queue (dev);
+       
        return 0;
 }
 
@@ -652,8 +652,6 @@ static void tulip_down (struct net_device *dev)
        struct tulip_private *tp = (struct tulip_private *) dev->priv;
        unsigned long flags;
 
-       netif_device_detach (dev);
-
        del_timer (&tp->timer);
 
        spin_lock_irqsave (&tp->lock, flags);
@@ -686,6 +684,8 @@ static int tulip_close (struct net_device *dev)
        long ioaddr = dev->base_addr;
        struct tulip_private *tp = (struct tulip_private *) dev->priv;
        int i;
+       
+       netif_stop_queue (dev);
 
        tulip_down (dev);
 
@@ -1338,8 +1338,10 @@ static void tulip_suspend (struct pci_dev *pdev)
 {
        struct net_device *dev = pdev->driver_data;
 
-       if (dev && netif_device_present (dev))
+       if (dev && netif_device_present (dev)) {
+               netif_device_detach (dev);
                tulip_down (dev);
+       }
 }
 
 
@@ -1347,8 +1349,10 @@ static void tulip_resume (struct pci_dev *pdev)
 {
        struct net_device *dev = pdev->driver_data;
 
-       if (dev && !netif_device_present (dev))
+       if (dev && !netif_device_present (dev)) {
                tulip_up (dev);
+               netif_device_attach (dev);
+       }
 }
 
 
index 72aeae11225da08a8ee2c85b2f5e6cfb374357ae..633514166094675b06035180f5fc61c403537fa1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cosa.c,v 1.30 2000/02/21 15:19:49 kas Exp $ */
+/* $Id: cosa.c,v 1.31 2000/03/08 17:47:16 kas Exp $ */
 
 /*
  *  Copyright (C) 1995-1997  Jan "Yenya" Kasprzak <kas@fi.muni.cz>
@@ -373,7 +373,7 @@ static int __init cosa_init(void)
 {
        int i;
 
-       printk(KERN_INFO "cosa v1.07 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");
+       printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");
 #ifdef __SMP__
        printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
 #endif
@@ -584,6 +584,7 @@ static void sppp_channel_init(struct channel_data *chan)
        struct net_device *d;
        chan->if_ptr = &chan->pppdev;
        chan->pppdev.dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+       memset(chan->pppdev.dev, 0, sizeof(struct net_device));
        sppp_attach(&chan->pppdev);
        d=chan->pppdev.dev;
        d->name = chan->name;
@@ -599,7 +600,6 @@ static void sppp_channel_init(struct channel_data *chan)
        d->get_stats = cosa_net_stats;
        d->tx_timeout = cosa_sppp_timeout;
        d->watchdog_timeo = TX_TIMEOUT;
-       dev_init_buffers(d);
        if (register_netdev(d) == -1) {
                printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
                sppp_detach(chan->pppdev.dev);
@@ -757,7 +757,7 @@ static int sppp_tx_done(struct channel_data *chan, int size)
                chan->stats.tx_aborted_errors++;
                return 1;
        }
-       dev_kfree_skb(chan->tx_skb);
+       dev_kfree_skb_irq(chan->tx_skb);
        chan->tx_skb = 0;
        chan->stats.tx_packets++;
        chan->stats.tx_bytes += size;
index 45592eacf97134fed4240714f517f53cc63f8423..9fc75e5e65edba19cf7e443b692d0e69f9cfe755 100644 (file)
@@ -1805,6 +1805,7 @@ static int wavelan_ioctl(struct net_device *dev,  /* device on which the ioctl is
        mm_t m;
        unsigned long flags;
        int ret = 0;
+       int err = 0;
 
 #ifdef DEBUG_IOCTL_TRACE
        printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name,
@@ -1813,8 +1814,6 @@ static int wavelan_ioctl(struct net_device *dev,  /* device on which the ioctl is
 
        /* Disable interrupts and save flags. */
        wv_splhi(lp, &flags);
-       /* FIXME: can't copy*user when cli this is broken! */
-       /* Note : is it still valid ? Jean II */
        
        /* Look what is the request */
        switch (cmd) {
@@ -1945,10 +1944,12 @@ static int wavelan_ioctl(struct net_device *dev,        /* device on which the ioctl is
                        }
 
                        /* Copy the key in the driver */
-                       if (copy_from_user
-                           (psa.psa_encryption_key,
-                            wrq->u.encoding.pointer,
-                            wrq->u.encoding.length)) {
+                       wv_splx(lp, &flags);
+                       err = copy_from_user(psa.psa_encryption_key,
+                                            wrq->u.encoding.pointer,
+                                            wrq->u.encoding.length);
+                       wv_splhi(lp, &flags);
+                       if (err) {
                                ret = -EFAULT;
                                break;
                        }
@@ -2018,9 +2019,11 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
 
                        /* Copy the key to the user buffer */
                        wrq->u.encoding.length = 8;
-                       if (copy_to_user
-                           (wrq->u.encoding.pointer,
-                            psa.psa_encryption_key, 8)) ret = -EFAULT;
+                       wv_splx(lp, &flags);
+                       if (copy_to_user(wrq->u.encoding.pointer,
+                                        psa.psa_encryption_key, 8))
+                               ret = -EFAULT;
+                       wv_splhi(lp, &flags);
                }
                break;
 
@@ -2067,38 +2070,51 @@ static int wavelan_ioctl(struct net_device *dev,        /* device on which the ioctl is
                        }
 
                        /* Copy structure to the user buffer. */
-                       if (copy_to_user
-                           (wrq->u.data.pointer, &range,
-                            sizeof(struct iw_range))) ret = -EFAULT;
+                       wv_splx(lp, &flags);
+                       if (copy_to_user(wrq->u.data.pointer,
+                                        &range,
+                                        sizeof(struct iw_range)))
+                               ret = -EFAULT;
+                       wv_splhi(lp, &flags);
                }
                break;
 
        case SIOCGIWPRIV:
                /* Basic checking */
                if (wrq->u.data.pointer != (caddr_t) 0) {
-                       struct iw_priv_args priv[] = {  /* cmd,         set_args,       get_args,       name */
-                               
-                                   {SIOCSIPQTHR,
-                                IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED |
-                                    1, 0, "setqualthr"},
-                               {SIOCGIPQTHR, 0,
-                                IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED |
-                                1, "getqualthr"},
-
-                               
-                                   {SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16,
-                                0, "sethisto"},
-                               {SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16,
-                                "gethisto"},
+                       struct iw_priv_args priv[] = {
+                               /* { cmd,
+                                    set_args,
+                                    get_args,
+                                    name } */
+                               { SIOCSIPQTHR,
+                                 IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+                                 0,
+                                 "setqualthr" },
+                               { SIOCGIPQTHR,
+                                 0,
+                                 IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+                                 "getqualthr" },
+                               { SIOCSIPHISTO,
+                                 IW_PRIV_TYPE_BYTE | 16,
+                                 0,
+                                 "sethisto" },
+                               { SIOCGIPHISTO,
+                                 0,
+                                 IW_PRIV_TYPE_INT | 16,
+                                "gethisto" },
                        };
 
                        /* Set the number of available ioctls. */
                        wrq->u.data.length = 4;
 
                        /* Copy structure to the user buffer. */
-                       if (copy_to_user
-                           (wrq->u.data.pointer, (u8 *) priv,
-                            sizeof(priv))) ret = -EFAULT;
+                       wv_splx(lp, &flags);
+                       if (copy_to_user(wrq->u.data.pointer,
+                                             (u8 *) priv,
+                                             sizeof(priv)))
+                               ret = -EFAULT;
+                       wv_splhi(lp, &flags);
                }
                break;
 
@@ -2119,9 +2135,13 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
                        int i;
 
                        /* Copy addresses to the driver. */
-                       if (copy_from_user
-                           (address, wrq->u.data.pointer,
-                            sizeof(struct sockaddr) * lp->spy_number)) {
+                       wv_splx(lp, &flags);
+                       err = copy_from_user(address,
+                                            wrq->u.data.pointer,
+                                            sizeof(struct sockaddr)
+                                            * lp->spy_number);
+                       wv_splhi(lp, &flags);
+                       if (err) {
                                ret = -EFAULT;
                                break;
                        }
@@ -2175,18 +2195,20 @@ static int wavelan_ioctl(struct net_device *dev,        /* device on which the ioctl is
                        }
 
                        /* Copy addresses to the user buffer. */
-                       if (copy_to_user
-                           (wrq->u.data.pointer, address,
-                            sizeof(struct sockaddr) * lp->spy_number)) {
-                               ret = -EFAULT;
-                               break;
-                       }
+                       wv_splx(lp, &flags);
+                       err = copy_to_user(wrq->u.data.pointer,
+                                          address,
+                                          sizeof(struct sockaddr)
+                                          * lp->spy_number);
 
                        /* Copy stats to the user buffer (just after). */
-                       if (copy_to_user(wrq->u.data.pointer +
-                                        (sizeof(struct sockaddr) *
-                                         lp->spy_number), lp->spy_stat,
-                                        sizeof(iw_qual) * lp->spy_number)) {
+                       err |= copy_to_user(wrq->u.data.pointer
+                                           + (sizeof(struct sockaddr)
+                                              * lp->spy_number),
+                                           lp->spy_stat,
+                                           sizeof(iw_qual) * lp->spy_number);
+                       wv_splhi(lp, &flags);
+                       if (err) {
                                ret = -EFAULT;
                                break;
                        }
@@ -2241,9 +2263,12 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
                /* Are there addresses to copy? */
                if (lp->his_number > 0) {
                        /* Copy interval ranges to the driver */
-                       if (copy_from_user
-                           (lp->his_range, wrq->u.data.pointer,
-                            sizeof(char) * lp->his_number)) {
+                       wv_splx(lp, &flags);
+                       err = copy_from_user(lp->his_range,
+                                            wrq->u.data.pointer,
+                                            sizeof(char) * lp->his_number);
+                       wv_splhi(lp, &flags);
+                       if (err) {
                                ret = -EFAULT;
                                break;
                        }
@@ -2261,10 +2286,12 @@ static int wavelan_ioctl(struct net_device *dev,        /* device on which the ioctl is
                if ((lp->his_number > 0)
                    && (wrq->u.data.pointer != (caddr_t) 0)) {
                        /* Copy data to the user buffer. */
-                       if (copy_to_user
-                           (wrq->u.data.pointer, lp->his_sum,
-                            sizeof(long) * lp->his_number))
+                       wv_splx(lp, &flags);
+                       if (copy_to_user(wrq->u.data.pointer,
+                                        lp->his_sum,
+                                        sizeof(long) * lp->his_number);
                                ret = -EFAULT;
+                       wv_splhi(lp, &flags);
 
                }               /* if(pointer != NULL) */
                break;
@@ -2274,7 +2301,7 @@ static int wavelan_ioctl(struct net_device *dev,  /* device on which the ioctl is
 
        default:
                ret = -EOPNOTSUPP;
-       }
+       }       /* switch (cmd) */
 
        /* Enable interrupts and restore flags. */
        wv_splx(lp, &flags);
index 21a6a4ff1f3d206140a1fe6186d9d2704fdcb274..dc7cfe9e1ee1433e6d37dc5d98607a6a7310b2ee 100644 (file)
@@ -4,7 +4,7 @@
 #      Maintained by Martin Mares <pci-ids@ucw.cz>
 #      If you have any new entries, send them to the maintainer.
 #
-#      $Id: pci.ids,v 1.50 2000/01/23 05:57:06 mj Exp $
+#      $Id: pci.ids,v 1.53 2000/03/09 08:19:20 mj Exp $
 #
 
 # Vendors, devices and subsystems. Please keep sorted.
        0026  DECchip 21154
        0045  DECchip 21553
        0046  DECchip 21554
+               9005 1364  Dell PowerEdge RAID Controller 2
+               9005 1365  Dell PowerEdge RAID Controller 2
 1012  Micronics Computers Inc
 1013  Cirrus Logic
        0038  GD 7548
        1489  M1489
        1511  M1511
        1513  M1513
-       1531  M1531
-       1533  M1533
+       1531  M1531 Northbridge [Aladdin IV/IV+]
+       1533  M1533 PCI-to-ISA Bridge
+       1535  M1535 PCI Bridge + Super I/O + FIR
+       1541  M1541 Northbridge [Aladdin V]
+       1542  M1542 Northbridge [Aladdin V]
+       1543  M1543 PCI-to-ISA Bridge + Super I/O + FIR
+       1561  M1561 Northbridge [Aladdin 7]
+       1621  M1621 Northbridge [Aladdin-Pro II]
+       1631  M1631 Northbridge+3D Graphics [Aladdin TNT2]
+       1641  M1641 Northbridge [Aladdin-Pro IV]
        3141  M3141
        3143  M3143
        3145  M3145
        3147  M3147
        3149  M3149
        3151  M3151
+       3307  M3307 MPEG-I Video Controller
+       3309  M3309 MPEG-II Video w/ Software Audio Decoder
+       3321  M3321 MPEG-II Audio/Video Decoder
        5217  M5217H
        5219  M5219
        5225  M5225
        5229  M5229
        5235  M5235
+       5251  M5251 P1394 OHCI Controller
 1028  Dell Computer Corporation
+       0001  PowerEdge Expandable RAID Controller 2/Si
+       0002  PowerEdge Expandable RAID Controller 3/Di
+       0003  PowerEdge Expandable RAID Controller 3/Si
 1029  Siemens Nixdorf IS
 102a  LSI Logic
        0000  HYDRA
 10a8  Sierra Semiconductor
        0000  STB Horizon 64
 10a9  Silicon Graphics, Inc.
-       0003  IOC3
+       0001  Crosstalk to PCI Bridge
+       0002  Linc I/O controller
+       0003  IOC3 I/O controller
+       0004  O2 MACE
        0005  RAD Audio
+       0006  HPCEX
+       0007  RPCEX
+       0008  DiVO VIP
        0009  Alteon Gigabit Ethernet
+       0010  AMP Video I/O
+       0011  GRIP
+       0012  SGH PSHAC GSN
+       1001  Magic Carpet
+       1002  Lithium
+       1003  Dual JPEG 1
+       1004  Dual JPEG 2
+       1005  Dual JPEG 3
+       1006  Dual JPEG 4
+       1007  Dual JPEG 5
+       1008  Cesium
+       2001  Fibre Channel
+       2002  ASDE
+       8001  O2 1394
+       8002  G-net NT
 10aa  ACC Microelectronics
        0000  ACCM 2188
 10ab  Digicom
        1077  VScom 400 4 port serial adaptor
        9036  9036
        9050  PCI <-> IOBus Bridge
+               d84d 4006  EX-4006 1P
+               d84d 4008  EX-4008 1P EPP/ECP
+               d84d 4014  EX-4014 2P
+               d84d 4018  EX-4018 3P EPP/ECP
+               d84d 4025  EX-4025 1S(16C550) RS-232
+               d84d 4027  EX-4027 1S(16C650) RS-232
+               d84d 4028  EX-4028 1S(16C850) RS-232
+               d84d 4036  EX-4036 2S(16C650) RS-232
+               d84d 4037  EX-4037 2S(16C650) RS-232
+               d84d 4038  EX-4038 2S(16C850) RS-232
+               d84d 4052  EX-4052 1S(16C550) RS-422/485
+               d84d 4053  EX-4053 2S(16C550) RS-422/485
+               d84d 4055  EX-4055 4S(16C550) RS-232
+               d84d 4058  EX-4055 4S(16C650) RS-232
+               d84d 4065  EX-4065 8S(16C550) RS-232
+               d84d 4068  EX-4068 8S(16C650) RS-232
+               d84d 4078  EX-4078 2S(16C552) RS-232+1P
        9060  9060
        906d  9060SD
                125c 0640  Aries 16000P
        10dc  ATT2C15-3 FPGA
 10dd  Evans & Sutherland
 10de  nVidia Corporation
-       0008  NV1 EDGE 3D
-       0009  NV1 EDGE 3D
-       0020  Riva TNT 128
+       0008  EDGE 3D [NV1]
+       0009  EDGE 3D [NV1]
+       0010  Mutara V08 [NV2]
+       0020  Riva TnT 128 [NV04]
                1043 0200  V3400 TNT
                1092 0550  Viper V550
                1092 0552  Viper V550
                1092 4904  Viper V550 
                1092 4914  Viper V550 
                1092 8225  Viper V550
-       0028  Riva TNT2
+       0028  Riva TnT2 [NV5]
                1043 0200  AGP-V3800 SGRAM
                1092 4804  Viper V770
                1092 4a00  Viper V770
                1092 7a02  Viper V770 Ultra
                1102 1020  3D Blaster RIVA TNT2
                14af 5810  Maxi Gamer Xentor
-       0029  Riva TNT2 Ultra
+       0029  Riva TnT2 Ultra [NV5]
                1043 0200  AGP-V3800 Deluxe
                1102 1021  3D Blaster RIVA TNT2 Ultra
                14af 5820  Maxi Gamer Xentor 32
-       002c  Vanta
+       002a  Riva TnT2 [NV5]
+       002b  Riva TnT2 [NV5]
+       002c  Vanta [NV6]
                1043 0200  AGP-V3800 Combat SDRAM
                1092 6820  Viper V730
                14af 5008  Maxi Gamer Phoenix 2
-       002d  Riva TNT2 Model 64
+       002d  Vanta [NV6]
                1043 0200  AGP-V3800M
+       002e  Vanta [NV6]
+       002f  Vanta [NV6]
        00a0  Riva TNT2
                14af 5810  Maxi Gamer Xentor
 10df  Emulex Corporation
        0101  3GA
        8111  Twist3 Frame Grabber
 10ec  Realtek Semiconductor Co., Ltd.
-       8029  RT8029(AS)
+       8029  RTL-8029(AS)
                10b8 2011  EZ-Card
                10ec 8029  RT8029(AS)
                1113 1208  EN1208
                1186 0300  DE-528
                1259 2400  AT-2400
-       8129  RT8129
-       8139  RT8139
+       8129  RTL-8129
+       8139  RTL-8139
                1025 8920  ALN-325
                1025 8921  ALN-325
                10bd 0320  EP-320X-R
                2646 0001  EtheRx
                8e2e 7000  KF-230TX
                8e2e 7100  KF-230TX/2
+               a0a0 0007  ALN-325C
 10ed  Ascii Corporation
        7310  V7310
 10ee  Xilinx, Inc.
+       3fc0  RME Digi96
+       3fc1  RME Digi96/8
+       3fc2  RME Digi96/8 Pro
+       3fc3  RME Digi96/8 Pad
 10ef  Racore Computer Products, Inc.
        8154  M815x Token Ring Adapter
 10f0  Peritek Corporation
 10ff  NCube
 1100  Jazz Multimedia
 1101  Initio Corporation
+       1060  INI-A100U2W
        9100  INI-9100/9100W
        9400  INI-940
        9401  INI-950
 1105  Sigma Designs, Inc.
        8300  REALmagic Hollywood Plus DVD Decoder
 1106  VIA Technologies, Inc.
+       0391  VT8371 [KX133]
        0501  VT8501
+       0601  VT8601
        0505  VT82C505
        0561  VT82C561
        0571  VT82C586 IDE [Apollo]
        3068  VT82C686 [Apollo Super AC97/Modem]
        5030  VT82C596 ACPI [Apollo PRO]
        6100  VT85C100A [Rhine II]
+       8231  VT8231 [PCI-to-ISA Bridge]
+       8391  VT8371 [PCI-PCI Bridge]
        8501  VT8501
        8596  VT82C596 [Apollo PRO AGP]
        8597  VT82C597 [Apollo VP3 AGP]
        8598  VT82C598 [Apollo MVP3 AGP]
        8691  VT82C691 [Apollo Pro]
+       8601  VT8601
 1107  Stratus Computers
        0576  VIA VT82C570MV [Apollo] (Wrong vendor ID!)
 1108  Proteon, Inc.
        0000  155P-MF1 (FPGA)
        0002  155P-MF1 (ASIC)
        0003  ENI-25P ATM Adapter
-       0005  ENI-25P ATM Adapter
+       0005  Speedstream 30xx ATM Adapter
 111b  Teledyne Electronic Systems
 111c  Tricord Systems Inc.
        0001  Powerbis Bridge
        1968  ES1968 Maestro 2
        1969  ES1969 Solo-1 Audiodrive
        1978  ES1978 Maestro 2E
+       1988  ES1988 Allegro-1
        2808  ES336H Fax Modem (Later Model)
        2898  ES2898 Modem
 125e  Specialvideo Engineering SRL
        0100  CM8338A
        0101  CM8338B
        0111  CM8738
+       0211  CM8738
 13f7  Wildfire Communications
 13f8  Ad Lib Multimedia Inc
 13f9  NTT Advanced Technology Corp.
 145d  Gallant Computer Inc
 145e  Aashima Technology B.V.
 145f  Baldor Electric Company
+       0001  NextMove PCI
 1460  DYNARC INC
 1461  Avermedia Technologies Inc
 1462  Micro-star International Co Ltd
 14b1  Nextcom K.K.
 14b2  ENNOVATE Networks Inc
 14b3  XPEED Inc
+       0000  DSL NIC
 14b4  PHILIPS Business Electronics B.V.
 14b5  Creamware GmBH
 14b6  Quantum Data Corp.
 14d9  Alpha Processor Inc
 14da  National Aerospace Laboratories
 14db  AFAVLAB Technology Inc
+       2120  TK9902
 14dc  Amplicon Liveline Ltd
+       0000  PCI230
+       0001  PCI242
+       0002  PCI244
+       0003  PCI247
+       0004  PCI248
+       0005  PCI249
+       0006  PCI260
+       0007  PCI224
+       0008  PCI234
+       0009  PCI236
 14dd  Boulder Design Labs Inc
 14de  Applied Integration Corporation
 14df  ASIC Communications Corp
 1d44  DPT
        a400  PM2x24/PM3224
 1de1  Tekram Technology Co.,Ltd.
+       0391  TRM-S1040
        2020  DC-390
        690c  690c
        dc29  DC290
@@ -3571,6 +3658,7 @@ c0fe  Motion Engineering, Inc.
 cafe  Chrysalis-ITS
 cccc  Catapult Communications
 d4d4  Dy4 Systems Inc
+d84d  Exsys
 e000  Winbond
        e000  W89C940
 e159  Tiger Jet Network Inc.
index aeca7fc3cd186735e80ee9786c5e884cb5409864..12a82eba5814a5af56400f282616a3e300d3b02b 100644 (file)
@@ -48,6 +48,25 @@ static void __init quirk_awe32_resources(struct pci_dev *dev)
        printk(KERN_INFO "isapnp: AWE32 quirk - adding two ports\n");
 }
 
+static void __init quirk_cmi8330_resources(struct pci_dev *dev)
+{
+       struct isapnp_resources *res = dev->sysdata;
+
+       for ( ; res ; res = res->alt ) {
+
+               struct isapnp_irq *irq;
+               struct isapnp_dma *dma;
+       
+               for( irq = res->irq; irq; irq = irq->next )     // Valid irqs are 5, 7, 10
+                       irq->map = 0x04A0;                                              // 0000 0100 1010 0000
+
+               for( dma = res->dma; dma; dma = dma->next ) // Valid 8bit dma channels are 1,3
+                       if( ( dma->flags & IORESOURCE_DMA_TYPE_MASK ) == IORESOURCE_DMA_8BIT )
+                               dma->map = 0x000A;
+       }
+       printk(KERN_INFO "isapnp: CMI8330 quirk - fixing interrupts and dma\n");
+}
+
 
 /*
  *  ISAPnP Quirks
@@ -61,6 +80,8 @@ static struct isapnp_fixup isapnp_fixups[] __initdata = {
                quirk_awe32_resources },
        { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0023),
                quirk_awe32_resources },
+       { ISAPNP_VENDOR('@','X','@'), ISAPNP_DEVICE(0x0001), // CMI8330 
+               quirk_cmi8330_resources },
        { 0 }
 };
 
index 42b86930db9cbc62ce71b36e55f0a643757aa0fd..31adb57fad202489a98a47d6233fab74199e33ff 100644 (file)
@@ -85,7 +85,7 @@ static void tw_copy_mem_info(TW_Info *info, char *data, int len);
 static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 
 /* Globals */
-char *tw_driver_version="1.0.000";
+char *tw_driver_version="1.1.000";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -2051,7 +2051,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
        command_packet->status = 0;
        command_packet->flags = 0;
 
-       if ((srb->cmnd[0] == WRITE_6) || (srb->cmnd[0] == WRITE_10)) {
+       if (srb->cmnd[0] == WRITE_10) {
                if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10))
                        command_packet->flags = 1;
        }
index ea0102938ba622068303098fb2bd5c2c25fc1d54..b064b6fbf955fc55729cc00df17e8570fccb82e8 100644 (file)
@@ -44,8 +44,8 @@ if [ "$CONFIG_DECSTATION" = "y" ]; then
    dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI
 fi
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   dep_tristate '3ware Hardware ATA-RAID support (EXPERIMENTAL)' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI
+if [ "$CONFIG_PCI" = "y" ]; then
+   dep_tristate '3ware Hardware ATA-RAID support' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI
 fi
 dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
 dep_tristate 'ACARD SCSI support' CONFIG_SCSI_ACARD $CONFIG_SCSI
index 30ffe5cc089a03426c57035125baf1bba6907f25..1d74abb5073e70436c828951c2ebac73c52a76ae 100644 (file)
@@ -86,6 +86,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
    fi
 
    dep_tristate '    Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
+   dep_tristate '    ACI mixer (miroPCM12)' CONFIG_SOUND_ACI_MIXER $CONFIG_SOUND_OSS
    dep_tristate '    Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND_OSS
    dep_tristate '    Ensoniq SoundScape support' CONFIG_SOUND_SSCAPE $CONFIG_SOUND_OSS
    dep_tristate '    Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS
@@ -115,10 +116,10 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
    dep_tristate '    PSS (AD1848, ADSP-2115, ESC614) support' CONFIG_SOUND_PSS $CONFIG_SOUND_OSS
    if [ "$CONFIG_SOUND_PSS" = "y" -o "$CONFIG_SOUND_PSS" = "m" ]; then
       bool '      Enable PSS mixer (Beethoven ADSP-16 and other compatibile)' CONFIG_PSS_MIXER
-   fi
-   bool '      Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT
-   if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then
-      string '  Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld
+      bool '      Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT
+      if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then
+         string '        Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld
+      fi
    fi
 
    dep_tristate '    SoftOSS software wave table engine' CONFIG_SOUND_SOFTOSS $CONFIG_SOUND_OSS
@@ -128,6 +129,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
    fi
   
    dep_tristate '    100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SOUND_SB $CONFIG_SOUND_OSS
+   dep_tristate '    AWE32 synth' CONFIG_SOUND_AWE32_SYNTH $CONFIG_SOUND_OSS
    dep_tristate '    Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards' CONFIG_SOUND_WAVEFRONT $CONFIG_SOUND_OSS m
    dep_tristate '    Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND_OSS
    if [ "$CONFIG_SOUND_MAUI" = "y" ]; then
@@ -143,20 +145,33 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
    dep_tristate '    Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
    dep_tristate '    6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND_OSS
   
+   dep_tristate '    Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_SOUND_AEDSP16 $CONFIG_SOUND_OSS
+   if [ "$CONFIG_SOUND_AEDSP16" = "y" -o "$CONFIG_SOUND_AEDSP16" = "m" ]; then
+      bool '      SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600
+      if [ "$CONFIG_SC6600" = "y" ]; then
+         bool '        Activate SC-6600 Joystick Interface' CONFIG_SC6600_JOY
+         int '        SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)' CONFIG_SC6600_CDROM 4
+         hex '        SC-6600 CDROM Interface I/O Address' CONFIG_SC6600_CDROMBASE 0
+      fi
+      if [ "$CONFIG_SOUND_SB" = "y" -o "$CONFIG_SOUND_SB" = "m" ]; then
+         if [ "$CONFIG_AEDSP16_MSS" != "y" ]; then
+            bool '      Audio Excel DSP 16 (SBPro emulation)' CONFIG_AEDSP16_SBPRO
+         fi
+      fi
+      if [ "$CONFIG_SOUND_MSS" = "y" -o "$CONFIG_SOUND_MSS" = "m" ]; then
+         if [ "$CONFIG_AEDSP16_SBPRO" != "y" ]; then
+            bool '      Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS
+         fi
+      fi
+      if [ "$CONFIG_SOUND_MPU401" = "y" -o "$CONFIG_SOUND_MPU401" = "m" ]; then
+         bool '      Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401
+      fi
+   fi
+        
    if [ "$CONFIG_ARM" = "y" ]; then
       dep_tristate '    VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
       dep_tristate '    Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS
    fi
-  
-  
-   # Additional low level drivers.
-  
-   mainmenu_option next_comment
-   comment 'Additional low level sound drivers'
-   bool 'Additional low level sound drivers' CONFIG_LOWLEVEL_SOUND $CONFIG_SOUND_OSS
-   if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
-      source drivers/sound/lowlevel/Config.in
-   fi
-   endmenu
+
 fi
 
index 2c5df3f1477e96c66c944eb5a3644ce7f398d2b0..6a3576df07db5a997660e3f2600243548b247df9 100644 (file)
 SUB_DIRS       := 
 MOD_SUB_DIRS   :=
 MOD_IN_SUB_DIRS        :=
-ALL_SUB_DIRS   := $(SUB_DIRS) lowlevel
-
-ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
-    SUB_DIRS           += lowlevel
-    MOD_IN_SUB_DIRS    += lowlevel
-endif
-
+ALL_SUB_DIRS   := $(SUB_DIRS)
 
 
 # All of the (potential) objects that export symbols.
@@ -47,6 +41,7 @@ obj-$(CONFIG_SOUND_CS4232)    += cs4232.o ad1848.o
 
 # Please leave it as is, cause the link order is significant !
 
+obj-$(CONFIG_SOUND_AEDSP16)    += aedsp16.o
 obj-$(CONFIG_SOUND_PSS)                += pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)       += trix.o ad1848.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_OPL3SA1)     += opl3sa.o ad1848.o uart401.o
@@ -69,6 +64,8 @@ obj-$(CONFIG_SOUND_VIDC)        += vidc_mod.o
 obj-$(CONFIG_SOUND_WAVEARTIST)  += waveartist.o
 obj-$(CONFIG_SOUND_SGALAXY)     += sgalaxy.o ad1848.o
 obj-$(CONFIG_SOUND_AD1816)      += ad1816.o
+obj-$(CONFIG_SOUND_ACI_MIXER)  += aci.o
+obj-$(CONFIG_SOUND_AWE32_SYNTH)        += awe_wave.o
 
 obj-$(CONFIG_SOUND_VIA82CXXX)  += via82cxxx_audio.o sb_lib.o uart401.o ac97.o
 obj-$(CONFIG_SOUND_MSNDCLAS)   += msnd.o msnd_classic.o
@@ -85,7 +82,7 @@ obj-$(CONFIG_SOUND_TRIDENT)   += trident.o ac97_codec.o
 
 # Declare multi-part drivers.
 
-list-multi     := sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o \
+list-multi     := sound.o gus.o pas2.o sb.o sb_lib.o softoss2.o vidc_mod.o \
     soundcore.o wavefront.o
 
 sound-objs     :=                                                      \
@@ -137,8 +134,8 @@ O_OBJS              := $(filter-out $(export-objs), $(obj-y))
 OX_OBJS                := $(filter     $(export-objs), $(obj-y))
 M_OBJS         := $(sort $(filter-out $(export-objs), $(obj-m)))
 MX_OBJS                := $(sort $(filter     $(export-objs), $(obj-m)))
-#MI_OBJS               := $(sort $(filter-out $(export-objs), $(int-m)))
-#MIX_OBJS      := $(sort $(filter     $(export-objs), $(int-m)))
+MI_OBJS                := $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS       := $(sort $(filter     $(export-objs), $(int-m)))
 
 ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
     O_OBJS     += lowlevel/lowlevel.o
diff --git a/drivers/sound/aci.c b/drivers/sound/aci.c
new file mode 100644 (file)
index 0000000..6970bec
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * Audio Command Interface (ACI) driver (sound/aci.c)
+ *
+ * ACI is a protocol used to communicate with the microcontroller on
+ * some sound cards produced by miro, e.g. the miroSOUND PCM12 and
+ * PCM20. The ACI has been developed for miro by Norberto Pellicci
+ * <pellicci@home.com>. Special thanks to both him and miro for
+ * providing the ACI specification.
+ *
+ * The main function of the ACI is to control the mixer and to get a
+ * product identification. On the PCM20, ACI also controls the radio
+ * tuner on this card, this is supported in the Video for Linux 
+ * radio-miropcm20 driver.
+ * 
+ * This Voxware ACI driver currently only supports the ACI functions
+ * on the miroSOUND PCM12 and PCM20 card. Support for miro sound cards 
+ * with additional ACI functions can easily be added later.
+ *
+ * / NOTE / When compiling as a module, make sure to load the module 
+ * after loading the mad16 module. The initialisation code expects the
+ * MAD16 default mixer to be already available.
+ *
+ * Revision history:
+ *
+ *   1995-11-10  Markus Kuhn <mskuhn@cip.informatik.uni-erlangen.de>
+ *        First version written.
+ *   1995-12-31  Markus Kuhn
+ *        Second revision, general code cleanup.
+ *   1996-05-16         Hannu Savolainen
+ *       Integrated with other parts of the driver.
+ *   1996-05-28  Markus Kuhn
+ *        Initialize CS4231A mixer, make ACI first mixer,
+ *        use new private mixer API for solo mode.
+ *   1998-08-18  Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
+ *       Small modification to export ACI functions and 
+ *       complete modularisation.
+ */
+
+/*
+ * Some driver specific information and features:
+ *
+ * This mixer driver identifies itself to applications as "ACI" in
+ * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info).
+ *
+ * Proprietary mixer features that go beyond the standard OSS mixer
+ * interface are:
+ * 
+ * Full duplex solo configuration:
+ *
+ *   int solo_mode;
+ *   ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode);
+ *
+ *   solo_mode = 0: deactivate solo mode (default)
+ *   solo_mode > 0: activate solo mode
+ *                  With activated solo mode, the PCM input can not any
+ *                  longer hear the signals produced by the PCM output.
+ *                  Activating solo mode is important in duplex mode in order
+ *                  to avoid feedback distortions.
+ *   solo_mode < 0: do not change solo mode (just retrieve the status)
+ *
+ *   When the ioctl() returns 0, solo_mode contains the previous
+ *   status (0 = deactivated, 1 = activated). If solo mode is not
+ *   implemented on this card, ioctl() returns -1 and sets errno to
+ *   EINVAL.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h> 
+
+#include "sound_config.h"
+
+#undef  DEBUG          /* if defined, produce a verbose report via syslog */
+
+int aci_port = 0x354;  /* as determined by bit 4 in the OPTi 929 MC4 register */
+unsigned char aci_idcode[2] = {0, 0};  /* manufacturer and product ID */
+unsigned char aci_version = 0;         /* ACI firmware version */
+int aci_solo;          /* status bit of the card that can't be         *
+                        * checked with ACI versions prior to 0xb0      */
+
+static int aci_present = 0;
+
+#ifdef MODULE                  /* Whether the aci mixer is to be reset.    */
+int aci_reset = 0;             /* Default: don't reset if the driver is a  */
+MODULE_PARM(aci_reset,"i");
+#else                          /* module; use "insmod aci.o aci_reset=1" */
+int aci_reset = 1;             /* to override.                             */
+#endif
+
+
+#define COMMAND_REGISTER    (aci_port)
+#define STATUS_REGISTER     (aci_port + 1)
+#define BUSY_REGISTER       (aci_port + 2)
+
+/*
+ * Wait until the ACI microcontroller has set the READYFLAG in the
+ * Busy/IRQ Source Register to 0. This is required to avoid
+ * overrunning the sound card microcontroller. We do a busy wait here,
+ * because the microcontroller is not supposed to signal a busy
+ * condition for more than a few clock cycles. In case of a time-out,
+ * this function returns -1.
+ *
+ * This busy wait code normally requires less than 15 loops and
+ * practically always less than 100 loops on my i486/DX2 66 MHz.
+ *
+ * Warning: Waiting on the general status flag after reseting the MUTE
+ * function can take a VERY long time, because the PCM12 does some kind
+ * of fade-in effect. For this reason, access to the MUTE function has
+ * not been implemented at all.
+ */
+
+static int busy_wait(void)
+{
+       long timeout;
+
+       for (timeout = 0; timeout < 10000000L; timeout++)
+               if ((inb_p(BUSY_REGISTER) & 1) == 0)
+                       return 0;
+
+#ifdef DEBUG
+       printk("ACI: READYFLAG timed out.\n");
+#endif
+
+       return -1;
+}
+
+
+/*
+ * Read the GENERAL STATUS register.
+ */
+
+static int read_general_status(void)
+{
+       unsigned long flags;
+       int status;
+
+       save_flags(flags);
+       cli();
+       
+       if (busy_wait()) {
+               restore_flags(flags);
+               return -1;
+       }
+       
+       status = (unsigned) inb_p(STATUS_REGISTER);
+       restore_flags(flags);
+       return status;
+}
+
+
+/*
+ * The four ACI command types (implied, write, read and indexed) can
+ * be sent to the microcontroller using the following four functions.
+ * If a problem occurred, they return -1.
+ */
+
+int aci_implied_cmd(unsigned char opcode)
+{
+       unsigned long flags;
+
+#ifdef DEBUG
+       printk("ACI: aci_implied_cmd(0x%02x)\n", opcode);
+#endif
+
+       save_flags(flags);
+       cli();
+  
+       if (read_general_status() < 0 || busy_wait()) {
+               restore_flags(flags);
+               return -1;
+       }
+       
+       outb_p(opcode, COMMAND_REGISTER);
+
+       restore_flags(flags);
+       return 0;
+}
+
+
+int aci_write_cmd(unsigned char opcode, unsigned char parameter)
+{
+       unsigned long flags;
+       int status;
+
+#ifdef DEBUG
+       printk("ACI: aci_write_cmd(0x%02x, 0x%02x)\n", opcode, parameter);
+#endif
+
+       save_flags(flags);
+       cli();
+       
+       if (read_general_status() < 0 || busy_wait()) {
+               restore_flags(flags);
+               return -1;
+       }
+
+       outb_p(opcode, COMMAND_REGISTER);
+       if (busy_wait()) {
+               restore_flags(flags);
+               return -1;
+       }
+
+       outb_p(parameter, COMMAND_REGISTER);
+
+       if ((status = read_general_status()) < 0) {
+               restore_flags(flags);
+               return -1;
+       }
+
+       /* polarity of the INVALID flag depends on ACI version */
+       if ((aci_version <  0xb0 && (status & 0x40) != 0) ||
+         (aci_version >= 0xb0 && (status & 0x40) == 0)) {
+               restore_flags(flags);
+               printk("ACI: invalid write command 0x%02x, 0x%02x.\n",
+                       opcode, parameter);
+               return -1;
+       }
+
+       restore_flags(flags);
+       return 0;
+}
+
+/*
+ * This write command send 2 parameters instead of one.
+ * Only used in PCM20 radio frequency tuning control
+ */
+
+int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2)
+{
+       unsigned long flags;
+       int status;
+
+#ifdef DEBUG
+       printk("ACI: aci_write_cmd_d(0x%02x, 0x%02x)\n", opcode, parameter, parameter2);
+#endif
+
+       save_flags(flags);
+       cli();
+       
+       if (read_general_status() < 0 || busy_wait()) {
+               restore_flags(flags);
+               return -1;
+       }
+
+       outb_p(opcode, COMMAND_REGISTER);
+       if (busy_wait()) {
+               restore_flags(flags);
+               return -1;
+       }
+
+       outb_p(parameter, COMMAND_REGISTER);
+       if (busy_wait()) {
+               restore_flags(flags);
+               return -1;
+       }
+       
+       outb_p(parameter2, COMMAND_REGISTER);
+       
+       if ((status = read_general_status()) < 0) {
+               restore_flags(flags);
+               return -1;
+       }
+       
+       /* polarity of the INVALID flag depends on ACI version */
+       if ((aci_version <  0xb0 && (status & 0x40) != 0) ||
+         (aci_version >= 0xb0 && (status & 0x40) == 0)) {
+               restore_flags(flags);
+#if 0  /* Frequency tuning works, but the INVALID flag is set ??? */
+               printk("ACI: invalid write (double) command 0x%02x, 0x%02x, 0x%02x.\n",
+                       opcode, parameter, parameter2);
+#endif
+               return -1;
+       }
+       
+       restore_flags(flags);
+       return 0;
+}
+
+int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter)
+{
+       unsigned long flags;
+       int i = 0;
+       
+       save_flags(flags);
+       cli();
+       if (read_general_status() < 0) {
+               restore_flags(flags);
+               return -1;
+       }
+       while (i < length) {
+               if (busy_wait()) {
+                       restore_flags(flags);
+                       return -1;
+               }
+                       
+               outb_p(opcode, COMMAND_REGISTER);
+               if (busy_wait()) {
+                       restore_flags(flags);
+                       return -1;
+               }
+                       
+               parameter[i++] = inb_p(STATUS_REGISTER);
+#ifdef DEBUG
+               if (i == 1)
+                       printk("ACI: aci_read_cmd(0x%02x, %d) = 0x%02x\n",
+                               opcode, length, parameter[i-1]);
+               else
+                       printk("ACI: aci_read_cmd cont.: 0x%02x\n", parameter[i-1]);
+#endif
+       }
+
+       restore_flags(flags);
+       return 0;
+}
+
+
+int aci_indexed_cmd(unsigned char opcode, unsigned char index,
+                      unsigned char *parameter)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+  
+       if (read_general_status() < 0 || busy_wait()) {
+               restore_flags(flags);
+               return -1;
+       }
+       
+       outb_p(opcode, COMMAND_REGISTER);
+       if (busy_wait()) {
+               restore_flags(flags);
+               return -1;
+       }
+       
+       outb_p(index, COMMAND_REGISTER);
+       if (busy_wait()) {
+               restore_flags(flags);
+               return -1;
+       }
+       
+       *parameter = inb_p(STATUS_REGISTER);
+#ifdef DEBUG
+       printk("ACI: aci_indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index,
+               *parameter);
+#endif
+
+       restore_flags(flags);
+       return 0;
+}
+
+
+/*
+ * The following macro SCALE can be used to scale one integer volume
+ * value into another one using only integer arithmetic. If the input
+ * value x is in the range 0 <= x <= xmax, then the result will be in
+ * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
+ *
+ * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
+ * following nice properties:
+ *
+ * - SCALE(xmax,ymax,xmax) = ymax
+ * - SCALE(xmax,ymax,0) = 0
+ * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
+ *
+ * In addition, the rounding error is minimal and nicely distributed.
+ * The proofs are left as an exercise to the reader.
+ */
+
+#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
+
+
+static int getvolume(caddr_t arg,
+                    unsigned char left_index, unsigned char right_index)
+{
+       int vol;
+       unsigned char buf;
+
+       /* left channel */
+       if (aci_indexed_cmd(0xf0, left_index, &buf))
+               return -EIO;
+       vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
+       
+       /* right channel */
+       if (aci_indexed_cmd(0xf0, right_index, &buf))
+               return -EIO;
+       vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
+
+       return (*(int *) arg = vol);
+}
+
+
+static int setvolume(caddr_t arg, 
+                    unsigned char left_index, unsigned char right_index)
+{
+       int vol, ret;
+
+       /* left channel */
+       vol = *(int *)arg & 0xff;
+       if (vol > 100)
+               vol = 100;
+       vol = SCALE(100, 0x20, vol);
+       if (aci_write_cmd(left_index, 0x20 - vol))
+               return -EIO;
+       ret = SCALE(0x20, 100, vol);
+
+
+       /* right channel */
+       vol = (*(int *)arg >> 8) & 0xff;
+       if (vol > 100)
+               vol = 100;
+       vol = SCALE(100, 0x20, vol);
+       if (aci_write_cmd(right_index, 0x20 - vol))
+               return -EIO;
+       ret |= SCALE(0x20, 100, vol) << 8;
+       return (*(int *) arg = ret);
+}
+
+
+static int
+aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
+{
+       int status, vol;
+       unsigned char buf;
+
+       /* handle solo mode control */
+       if (cmd == SOUND_MIXER_PRIVATE1) {
+               if (*(int *) arg >= 0) {
+                       aci_solo = !!*(int *) arg;
+                       if (aci_write_cmd(0xd2, aci_solo))
+                               return -EIO;
+               } else if (aci_version >= 0xb0) {
+                       if ((status = read_general_status()) < 0)
+                               return -EIO;
+                       return (*(int *) arg = (status & 0x20) == 0);
+               }
+               
+               return (*(int *) arg = aci_solo);
+       }
+       
+       if (((cmd >> 8) & 0xff) == 'M') {
+               if (cmd & IOC_IN)
+                       /* read and write */
+                       switch (cmd & 0xff) {
+                               case SOUND_MIXER_VOLUME:
+                                       return setvolume(arg, 0x01, 0x00);
+                               case SOUND_MIXER_CD:
+                                       return setvolume(arg, 0x3c, 0x34);
+                               case SOUND_MIXER_MIC:
+                                       return setvolume(arg, 0x38, 0x30);
+                               case SOUND_MIXER_LINE:
+                                       return setvolume(arg, 0x39, 0x31);
+                               case SOUND_MIXER_SYNTH:
+                                       return setvolume(arg, 0x3b, 0x33);
+                               case SOUND_MIXER_PCM:
+                                       return setvolume(arg, 0x3a, 0x32);
+                               case SOUND_MIXER_LINE1:  /* AUX1 */
+                                       return setvolume(arg, 0x3d, 0x35);
+                               case SOUND_MIXER_LINE2:  /* AUX2 */
+                                       return setvolume(arg, 0x3e, 0x36);
+                               case SOUND_MIXER_IGAIN:  /* MIC pre-amp */
+                                       vol = *(int *) arg & 0xff;
+                                       if (vol > 100)
+                                               vol = 100;
+                                       vol = SCALE(100, 3, vol);
+                                       if (aci_write_cmd(0x03, vol))
+                                               return -EIO;
+                                       vol = SCALE(3, 100, vol);
+                                       return (*(int *) arg = vol | (vol << 8));
+                               case SOUND_MIXER_RECSRC:
+                                       return (*(int *) arg = 0);
+                                       break;
+                               default:
+                                       return -EINVAL;
+                       }
+               else
+                       /* only read */
+                       switch (cmd & 0xff) {
+                               case SOUND_MIXER_DEVMASK:
+                                       return (*(int *) arg =
+                                SOUND_MASK_VOLUME | SOUND_MASK_CD    |
+                                SOUND_MASK_MIC    | SOUND_MASK_LINE  |
+                                SOUND_MASK_SYNTH  | SOUND_MASK_PCM   |
+#if 0
+                                SOUND_MASK_IGAIN  |
+#endif
+                                SOUND_MASK_LINE1  | SOUND_MASK_LINE2);
+                                       break;
+                               case SOUND_MIXER_STEREODEVS:
+                                       return (*(int *) arg =
+                                SOUND_MASK_VOLUME | SOUND_MASK_CD   |
+                                SOUND_MASK_MIC    | SOUND_MASK_LINE |
+                                SOUND_MASK_SYNTH  | SOUND_MASK_PCM  |
+                                SOUND_MASK_LINE1  | SOUND_MASK_LINE2);
+                                       break;
+                               case SOUND_MIXER_RECMASK:
+                                       return (*(int *) arg = 0);
+                                       break;
+                               case SOUND_MIXER_RECSRC:
+                                       return (*(int *) arg = 0);
+                                       break;
+                               case SOUND_MIXER_CAPS:
+                                       return (*(int *) arg = 0);
+                                       break;
+                               case SOUND_MIXER_VOLUME:
+                                       return getvolume(arg, 0x04, 0x03);
+                               case SOUND_MIXER_CD:
+                                       return getvolume(arg, 0x0a, 0x09);
+                               case SOUND_MIXER_MIC:
+                                       return getvolume(arg, 0x06, 0x05);
+                               case SOUND_MIXER_LINE:
+                                       return getvolume(arg, 0x08, 0x07);
+                               case SOUND_MIXER_SYNTH:
+                                       return getvolume(arg, 0x0c, 0x0b);
+                               case SOUND_MIXER_PCM:
+                                       return getvolume(arg, 0x0e, 0x0d);
+                               case SOUND_MIXER_LINE1:  /* AUX1 */
+                                       return getvolume(arg, 0x11, 0x10);
+                               case SOUND_MIXER_LINE2:  /* AUX2 */
+                                       return getvolume(arg, 0x13, 0x12);
+                               case SOUND_MIXER_IGAIN:  /* MIC pre-amp */
+                                       if (aci_indexed_cmd(0xf0, 0x21, &buf))
+                                               return -EIO;
+                                       vol = SCALE(3, 100, buf <= 3 ? buf : 3);
+                                       vol |= vol << 8;
+                                       return (*(int *) arg = vol);
+                               default:
+                                       return -EINVAL;
+                       }
+       }
+       
+       return -EINVAL;
+}
+
+
+static struct mixer_operations aci_mixer_operations =
+{
+       "ACI",
+       "ACI mixer",
+       aci_mixer_ioctl,
+       NULL
+};
+
+static unsigned char
+mad_read (int port)
+{
+       outb (0xE3, 0xf8f); /* Write MAD16 password */
+       return inb (port);  /* Read from port */
+}
+
+
+/*
+ * Check, whether there actually is any ACI port operational and if
+ * one was found, then initialize the ACI interface, reserve the I/O
+ * addresses and attach the new mixer to the relevant VoxWare data
+ * structures.
+ *
+ * Returns:  1   ACI mixer detected
+ *           0   nothing there
+ *
+ * There is also an internal mixer in the codec (CS4231A or AD1845),
+ * that deserves no purpose in an ACI based system which uses an
+ * external ACI controlled stereo mixer. Make sure that this codec
+ * mixer has the AUX1 input selected as the recording source, that the
+ * input gain is set near maximum and that the other channels going
+ * from the inputs to the codec output are muted.
+ */
+
+static int __init attach_aci(void)
+{
+       char *boardname = "unknown";
+       int volume;
+
+#define MC4_PORT       0xf90
+
+       aci_port =
+               (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354;
+
+       if (check_region(aci_port, 3)) {
+#ifdef DEBUG
+               printk("ACI: I/O area 0x%03x-0x%03x already used.\n",
+                       aci_port, aci_port+2);
+#endif
+               return 0;
+       }
+       
+       if (aci_read_cmd(0xf2, 2, aci_idcode)) {
+#ifdef DEBUG
+               printk("ACI: Failed to read idcode.\n");
+#endif
+               return 0;
+       }
+       
+       if (aci_read_cmd(0xf1, 1, &aci_version)) {
+#ifdef DEBUG
+               printk("ACI: Failed to read version.\n");
+#endif
+               return 0;
+       }
+
+       if (aci_idcode[0] == 0x6d) {
+               /* It looks like a miro sound card. */
+               switch (aci_idcode[1]) {
+                       case 0x41:
+                               boardname = "PCM1 pro / early PCM12";
+                               break;
+                       case 0x42:
+                               boardname = "PCM12";
+                               break;
+                       case 0x43:
+                               boardname = "PCM20";
+                               break;
+                       default:
+                               boardname = "unknown miro";
+               }
+       } else
+#ifndef DEBUG
+       return 0;
+#endif
+  
+       printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n",
+               aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port);
+
+       if (aci_reset) {
+               /* initialize ACI mixer */
+               aci_implied_cmd(0xff);
+               aci_solo = 0;
+       }
+
+       /* attach the mixer */
+       request_region(aci_port, 3, "sound mixer (ACI)");
+       if (num_mixers < MAX_MIXER_DEV) {
+               if (num_mixers > 0 &&
+                 !strncmp("MAD16 WSS", mixer_devs[num_mixers-1]->name, 9)) {
+                       /*
+                        * The previously registered mixer device is the CS4231A which
+                        * has no function on an ACI card. Make the ACI mixer the first
+                        * of the two mixer devices.
+                        */
+                       mixer_devs[num_mixers] = mixer_devs[num_mixers-1];
+                       mixer_devs[num_mixers-1] = &aci_mixer_operations;
+                       /*
+                        * Initialize the CS4231A mixer with reasonable values. It is
+                        * unlikely that the user ever will want to change these as all
+                        * channels can be mixed via ACI.
+                        */
+                       volume = 0x6464;
+                       mixer_devs[num_mixers]->ioctl(num_mixers,
+                               SOUND_MIXER_WRITE_PCM, (caddr_t) &volume);
+                       volume = 0x6464;
+                       mixer_devs[num_mixers]->ioctl(num_mixers,
+                               SOUND_MIXER_WRITE_IGAIN,   (caddr_t) &volume);
+                       volume = 0;
+                       mixer_devs[num_mixers]->ioctl(num_mixers,
+                               SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume);
+                       volume = 0;
+                       mixer_devs[num_mixers]->ioctl(num_mixers,
+                               SOUND_MIXER_WRITE_MIC, (caddr_t) &volume);
+                       volume = 0;
+                       mixer_devs[num_mixers]->ioctl(num_mixers,
+                               SOUND_MIXER_WRITE_IMIX, (caddr_t) &volume);
+                       volume = 0;
+                       mixer_devs[num_mixers]->ioctl(num_mixers,
+                               SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume);
+                       volume = 0;
+                       mixer_devs[num_mixers]->ioctl(num_mixers,
+                               SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume);
+                       volume = 0;
+                       mixer_devs[num_mixers]->ioctl(num_mixers,
+                               SOUND_MIXER_WRITE_LINE3, (caddr_t) &volume);
+                       volume = SOUND_MASK_LINE1;
+                       mixer_devs[num_mixers]->ioctl(num_mixers,
+                               SOUND_MIXER_WRITE_RECSRC, (caddr_t) &volume);
+                       num_mixers++;
+               } else
+                       mixer_devs[num_mixers++] = &aci_mixer_operations;
+       }
+
+       /* Just do something; otherwise the first write command fails, at
+        * least with my PCM20.
+        */
+       aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_READ_VOLUME, (caddr_t) &volume);
+       
+       if (aci_reset) {
+               /* Initialize ACI mixer with reasonable power-up values */
+               volume = 0x3232;
+               aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume);
+               volume = 0x3232;
+               aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH,  (caddr_t) &volume);
+               volume = 0x3232;
+               aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM,    (caddr_t) &volume);
+               volume = 0x3232;
+               aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE,   (caddr_t) &volume);
+               volume = 0x3232;
+               aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC,    (caddr_t) &volume);
+               volume = 0x3232;
+               aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD,     (caddr_t) &volume);
+               volume = 0x3232;
+               aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1,  (caddr_t) &volume);
+               volume = 0x3232;
+               aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2,  (caddr_t) &volume);
+       }
+
+       aci_present = 1;
+
+       return 1;
+}
+
+static void __exit unload_aci(void)
+{
+       if (aci_present)
+               release_region(aci_port, 3);
+}
+
+module_init(attach_aci);
+module_exit(unload_aci);
index d44cf1389d49afa6a7e2896e6c4e3bd14f650eb1..8bd68c4dcb37c9afbe062f17303e8d6aa8d75fe0 100644 (file)
@@ -1386,7 +1386,7 @@ static int __init setup_ad1816(char *str)
        io      = ints[1];
        irq     = ints[2];
        dma     = ints[3];
-       dma16   = ints[4];
+       dma   = ints[4];
 
        return 1;
 }
diff --git a/drivers/sound/aedsp16.c b/drivers/sound/aedsp16.c
new file mode 100644 (file)
index 0000000..74b9615
--- /dev/null
@@ -0,0 +1,1389 @@
+/*
+   drivers/sound/lowlevel/aedsp16.c
+
+   Audio Excel DSP 16 software configuration routines
+   Copyright (C) 1995,1996,1997,1998  Riccardo Facchetti (fizban@tin.it)
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+/*
+ * Include the main OSS Lite header file. It include all the os, OSS Lite, etc
+ * headers needed by this source.
+ */
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include "sound_config.h"
+#include "soundmodule.h"
+
+/*
+ * Sanity checks
+ */
+
+#if defined(CONFIG_SOUND_AEDSP16_SBPRO) && defined(CONFIG_SOUND_AEDSP16_MSS)
+#error You have to enable only one of the MSS and SBPRO emulations.
+#endif
+
+/*
+
+   READ THIS
+
+   This module started to configure the Audio Excel DSP 16 Sound Card.
+   Now works with the SC-6000 (old aedsp16) and new SC-6600 based cards.
+
+   NOTE: I have NO idea about Audio Excel DSP 16 III. If someone owns this
+   audio card and want to see the kernel support for it, please contact me.
+
+   Audio Excel DSP 16 is an SB pro II, Microsoft Sound System and MPU-401
+   compatible card.
+   It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq),
+   so before this module, the only way to configure the DSP under linux was
+   boot the MS-DOS loading the sound.sys device driver (this driver soft-
+   configure the sound board hardware by massaging someone of its registers),
+   and then ctrl-alt-del to boot linux with the DSP configured by the DOS
+   driver.
+
+   This module works configuring your Audio Excel DSP 16's irq, dma and
+   mpu-401-irq. The OSS Lite routines rely on the fact that if the
+   hardware is there, they can detect it. The problem with AEDSP16 is
+   that no hardware can be found by the probe routines if the sound card
+   is not configured properly. Sometimes the kernel probe routines can find
+   an SBPRO even when the card is not configured (this is the standard setup
+   of the card), but the SBPRO emulation don't work well if the card is not
+   properly initialized. For this reason
+
+   aedsp16_init_board()
+
+   routine is called before the OSS Lite probe routines try to detect the
+   hardware.
+
+   NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS)
+
+   NOTE: Now it works with SC-6000 and SC-6600 based audio cards. The new cards
+   have no jumper switch at all. No more WSS or MPU-401 I/O port switches. They
+   have to be configured by software.
+
+   NOTE: The driver is merged with the new OSS Lite sound driver. It works
+   as a lowlevel driver.
+
+   The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS;
+   the OSS Lite sound driver can be configured for SBPRO and MSS cards
+   at the same time, but the aedsp16 can't be two cards!!
+   When we configure it, we have to choose the SBPRO or the MSS emulation
+   for AEDSP16. We also can install a *REAL* card of the other type (see [1]).
+
+   NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO
+   please let me know if it works.
+
+   The MPU-401 support can be compiled in together with one of the other
+   two operating modes.
+
+   NOTE: This is something like plug-and-play: we have only to plug
+   the AEDSP16 board in the socket, and then configure and compile
+   a kernel that uses the AEDSP16 software configuration capability.
+   No jumper setting is needed!
+
+   For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3
+   you have just to make config the OSS Lite package, configuring
+   the AEDSP16 sound card, then activating the SBPro emulation mode
+   and at last configuring IRQ and DMA.
+   Compile the kernel and run it.
+
+   NOTE: This means for SC-6000 cards that you can choose irq and dma,
+   but not the I/O addresses. To change I/O addresses you have to set
+   them with jumpers. For SC-6600 cards you have no jumpers so you have
+   to set up your full card configuration in the make config.
+
+   You can change the irq/dma/mirq settings WITHOUT THE NEED to open
+   your computer and massage the jumpers (there are no irq/dma/mirq
+   jumpers to be configured anyway, only I/O BASE values have to be
+   configured with jumpers)
+
+   For some ununderstandable reason, the card default of irq 7, dma 1,
+   don't work for me. Seems to be an IRQ or DMA conflict. Under heavy
+   HDD work, the kernel start to erupt out a lot of messages like:
+
+   'Sound: DMA timed out - IRQ/DRQ config error?'
+
+   For what I can say, I have NOT any conflict at irq 7 (under linux I'm
+   using the lp polling driver), and dma line 1 is unused as stated by
+   /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so
+   I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows!
+   Anyway a setting of irq 10, dma 3 works really fine.
+
+   NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know
+   the emulation mode, all the installed hardware and the hardware
+   configuration (irq and dma settings of all the hardware).
+
+   This init module should work with SBPRO+MSS, when one of the two is
+   the AEDSP16 emulation and the other the real card. (see [1])
+   For example:
+
+   AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other
+   AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other
+
+   MPU401 should work. (see [2])
+
+   [1]
+       ---
+       Date: Mon, 29 Jul 1997 08:35:40 +0100
+       From: Mr S J Greenaway <sjg95@unixfe.rl.ac.uk>
+
+       [...]
+       Just to let you know got my Audio Excel (emulating a MSS) working
+       with my original SB16, thanks for the driver!
+       [...]
+       ---
+
+   [2] Not tested by me for lack of hardware.
+
+   TODO, WISHES AND TECH
+
+   - About I/O ports allocation -
+
+   Request the 2x0h region (port base) in any case if we are using this card.
+
+   NOTE: the "aedsp16 (base)" string with which we are requesting the aedsp16
+   port base region (see code) does not mean necessarily that we are emulating
+   sbpro.  Even if this region is the sbpro I/O ports region, we use this
+   region to access the control registers of the card, and if emulating
+   sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro
+   registers are not used, in no way, to emulate an sbpro: they are
+   used only for configuration purposes.
+
+   Started Fri Mar 17 16:13:18 MET 1995
+
+   v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c)
+   - Initial code.
+   v0.2 (ALPHA)
+   - Cleanups.
+   - Integrated with Linux voxware v 2.90-2 kernel sound driver.
+   - SoundBlaster Pro mode configuration.
+   - Microsoft Sound System mode configuration.
+   - MPU-401 mode configuration.
+   v0.3 (ALPHA)
+   - Cleanups.
+   - Rearranged the code to let aedsp16_init_board be more general.
+   - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h
+   inclusion too. We rely on os.h
+   - Used the  to get a variable
+   len string (we are not sure about the len of Copyright string).
+   This works with any SB and compatible.
+   - Added the code to request_region at device init (should go in
+   the main body of voxware).
+   v0.4 (BETA)
+   - Better configure.c patch for aedsp16 configuration (better
+   logic of inclusion of AEDSP16 support)
+   - Modified the conditional compilation to better support more than
+   one sound card of the emulated type (read the NOTES above)
+   - Moved the sb init routine from the attach to the very first
+   probe in sb_card.c
+   - Rearrangements and cleanups
+   - Wiped out some unnecessary code and variables: this is kernel
+   code so it is better save some TEXT and DATA
+   - Fixed the request_region code. We must allocate the aedsp16 (sbpro)
+   I/O ports in any case because they are used to access the DSP
+   configuration registers and we can not allow anyone to get them.
+   v0.5
+   - cleanups on comments
+   - prep for diffs against v3.0-proto-950402
+   v0.6
+   - removed the request_region()s when compiling the MODULE sound.o
+   because we are not allowed (by the actual voxware structure) to
+   release_region()
+   v0.7 (pre ALPHA, not distributed)
+   - started porting this module to kernel 1.3.84. Dummy probe/attach
+   routines.
+   v0.8 (ALPHA)
+   - attached all the init routines.
+   v0.9 (BETA)
+   - Integrated with linux-pre2.0.7
+   - Integrated with configuration scripts.
+   - Cleaned up and beautyfied the code.
+   v0.9.9 (BETA)
+   - Thanks to Piercarlo Grandi: corrected the conditonal compilation code.
+     Now only the code configured is compiled in, with some memory saving.
+   v0.9.10
+   - Integration into the sound/lowlevel/ section of the sound driver.
+   - Re-organized the code.
+   v0.9.11 (not distributed)
+   - Rewritten the init interface-routines to initialize the AEDSP16 in
+     one shot.
+   - More cosmetics.
+   - SC-6600 support.
+   - More soft/hard configuration.
+   v0.9.12
+   - Refined the v0.9.11 code with conditional compilation to distinguish
+     between SC-6000 and SC-6600 code.
+   v1.0.0
+   - Prep for merging with OSS Lite and Linux kernel 2.1.13
+   - Corrected a bug in request/check/release region calls (thanks to the
+     new kernel exception handling).
+   v1.1
+   - Revamped for integration with new modularized sound drivers: to enhance
+     the flexibility of modular version, I have removed all the conditional
+     compilation for SBPRO, MPU and MSS code. Now it is all managed with
+     the ae_config structure.
+   v1.2
+   - Module informations added.
+   - Removed aedsp16_delay_10msec(), now using mdelay(10)
+   - All data and funcs moved to .*.init section.
+
+   Known Problems:
+   - Audio Excel DSP 16 III don't work with this driver.
+
+   Credits:
+   Many thanks to Gerald Britton <gbritton@CapAccess.org>. He helped me a
+   lot in testing the 0.9.11 and 0.9.12 versions of this driver.
+
+ */
+
+
+#define VERSION "1.2"          /* Version of Audio Excel DSP 16 driver */
+
+#undef AEDSP16_DEBUG 1         /* Define this to enable debug code     */
+#undef AEDSP16_DEBUG_MORE 1    /* Define this to enable more debug     */
+#undef AEDSP16_INFO  1         /* Define this to enable info code      */
+
+#if defined(AEDSP16_DEBUG)
+# define DBG(x)  printk x
+# if defined(AEDSP16_DEBUG_MORE)
+#  define DBG1(x) printk x
+# else
+#  define DBG1(x)
+# endif
+#else
+# define DBG(x)
+# define DBG1(x)
+#endif
+
+/*
+ * Misc definitions
+ */
+#define TRUE   1
+#define FALSE  0
+
+/*
+ * Region Size for request/check/release region.
+ */
+#define IOBASE_REGION_SIZE     0x10
+
+/*
+ * Hardware related defaults
+ */
+#define DEF_AEDSP16_IOB 0x220   /* 0x220(default) 0x240                 */
+#define DEF_AEDSP16_IRQ 7      /* 5 7(default) 9 10 11                 */
+#define DEF_AEDSP16_MRQ 0      /* 5 7 9 10 0(default), 0 means disable */
+#define DEF_AEDSP16_DMA 1      /* 0 1(default) 3                       */
+
+/*
+ * Commands of AEDSP16's DSP (SBPRO+special).
+ * Some of them are COMMAND_xx, in the future they may change.
+ */
+#define WRITE_MDIRQ_CFG   0x50 /* Set M&I&DRQ mask (the real config)   */
+#define COMMAND_52        0x52 /*                                      */
+#define READ_HARD_CFG     0x58 /* Read Hardware Config (I/O base etc)  */
+#define COMMAND_5C        0x5c /*                                      */
+#define COMMAND_60        0x60 /*                                      */
+#define COMMAND_66        0x66 /*                                      */
+#define COMMAND_6C        0x6c /*                                      */
+#define COMMAND_6E        0x6e /*                                      */
+#define COMMAND_88        0x88 /*                                      */
+#define DSP_INIT_MSS      0x8c /* Enable Microsoft Sound System mode   */
+#define COMMAND_C5        0xc5 /*                                      */
+#define GET_DSP_VERSION   0xe1 /* Get DSP Version                      */
+#define GET_DSP_COPYRIGHT 0xe3 /* Get DSP Copyright                    */
+
+/*
+ * Offsets of AEDSP16 DSP I/O ports. The offset is added to base I/O port
+ * to have the actual I/O port.
+ * Register permissions are:
+ * (wo) == Write Only
+ * (ro) == Read  Only
+ * (w-) == Write
+ * (r-) == Read
+ */
+#define DSP_RESET    0x06      /* offset of DSP RESET             (wo) */
+#define DSP_READ     0x0a      /* offset of DSP READ              (ro) */
+#define DSP_WRITE    0x0c      /* offset of DSP WRITE             (w-) */
+#define DSP_COMMAND  0x0c      /* offset of DSP COMMAND           (w-) */
+#define DSP_STATUS   0x0c      /* offset of DSP STATUS            (r-) */
+#define DSP_DATAVAIL 0x0e      /* offset of DSP DATA AVAILABLE    (ro) */
+
+
+#define RETRY           10     /* Various retry values on I/O opera-   */
+#define STATUSRETRY   1000     /* tions. Sometimes we have to          */
+#define HARDRETRY   500000     /* wait for previous cmd to complete    */
+
+/*
+ * Size of character arrays that store name and version of sound card
+ */
+#define CARDNAMELEN 15         /* Size of the card's name in chars     */
+#define CARDVERLEN  2          /* Size of the card's version in chars  */
+
+#if defined(CONFIG_SC6600)
+/*
+ * Bitmapped flags of hard configuration
+ */
+/*
+ * Decode macros (xl == low byte, xh = high byte)
+ */
+#define IOBASE(xl)             ((xl & 0x01)?0x240:0x220)
+#define JOY(xl)                (xl & 0x02)
+#define MPUADDR(xl)            (                       \
+                               (xl & 0x0C)?0x330:      \
+                               (xl & 0x08)?0x320:      \
+                               (xl & 0x04)?0x310:      \
+                                               0x300)
+#define WSSADDR(xl)            ((xl & 0x10)?0xE80:0x530)
+#define CDROM(xh)              (xh & 0x20)
+#define CDROMADDR(xh)          (((xh & 0x1F) << 4) + 0x200)
+/*
+ * Encode macros
+ */
+#define BLDIOBASE(xl, val) {           \
+       xl &= ~0x01;                    \
+       if (val == 0x240)               \
+               xl |= 0x01;             \
+       }
+#define BLDJOY(xl, val) {              \
+       xl &= ~0x02;                    \
+       if (val == 1)                   \
+               xl |= 0x02;             \
+       }
+#define BLDMPUADDR(xl, val) {          \
+       xl &= ~0x0C;                    \
+       switch (val) {                  \
+               case 0x330:             \
+                       xl |= 0x0C;     \
+                       break;          \
+               case 0x320:             \
+                       xl |= 0x08;     \
+                       break;          \
+               case 0x310:             \
+                       xl |= 0x04;     \
+                       break;          \
+               case 0x300:             \
+                       xl |= 0x00;     \
+                       break;          \
+               default:                \
+                       xl |= 0x00;     \
+                       break;          \
+               }                       \
+       }
+#define BLDWSSADDR(xl, val) {          \
+       xl &= ~0x10;                    \
+       if (val == 0xE80)               \
+               xl |= 0x10;             \
+       }
+#define BLDCDROM(xh, val) {            \
+       xh &= ~0x20;                    \
+       if (val == 1)                   \
+               xh |= 0x20;             \
+       }
+#define BLDCDROMADDR(xh, val) {                \
+       int tmp = val;                  \
+       tmp -= 0x200;                   \
+       tmp >>= 4;                      \
+       tmp &= 0x1F;                    \
+       xh |= tmp;                      \
+       xh &= 0x7F;                     \
+       xh |= 0x40;                     \
+       }
+#endif /* CONFIG_SC6600 */
+
+/*
+ * Bit mapped flags for calling aedsp16_init_board(), and saving the current
+ * emulation mode.
+ */
+#define INIT_NONE   (0   )
+#define INIT_SBPRO  (1<<0)
+#define INIT_MSS    (1<<1)
+#define INIT_MPU401 (1<<2)
+
+static int      soft_cfg __initdata = 0;       /* bitmapped config */
+static int      soft_cfg_mss __initdata = 0;   /* bitmapped mss config */
+static int      ver[CARDVERLEN] __initdata = {0, 0};   /* DSP Ver:
+                                                  hi->ver[0] lo->ver[1] */
+
+#if defined(CONFIG_SC6600)
+static int     hard_cfg[2]     /* lo<-hard_cfg[0] hi<-hard_cfg[1]      */
+                     __initdata = { 0, 0};
+#endif /* CONFIG_SC6600 */
+
+#if defined(CONFIG_SC6600)
+/* Decoded hard configuration */
+struct d_hcfg {
+       int iobase;
+       int joystick;
+       int mpubase;
+       int wssbase;
+       int cdrom;
+       int cdrombase;
+};
+
+struct d_hcfg decoded_hcfg __initdata = {0, };
+
+#endif /* CONFIG_SC6600 */
+
+/* orVals contain the values to be or'ed                                       */
+struct orVals {
+       int     val;            /* irq|mirq|dma                         */
+       int     or;             /* soft_cfg |= TheStruct.or             */
+};
+
+/* aedsp16_info contain the audio card configuration                  */
+struct aedsp16_info {
+       int base_io;            /* base I/O address for accessing card  */
+       int irq;                /* irq value for DSP I/O                */
+       int mpu_irq;            /* irq for mpu401 interface I/O         */
+       int dma;                /* dma value for DSP I/O                */
+       int mss_base;           /* base I/O for Microsoft Sound System  */
+       int mpu_base;           /* base I/O for MPU-401 emulation       */
+       int init;               /* Initialization status of the card    */
+};
+
+/*
+ * Magic values that the DSP will eat when configuring irq/mirq/dma
+ */
+/* DSP IRQ conversion array             */
+static struct orVals orIRQ[] __initdata = {
+       {0x05, 0x28},
+       {0x07, 0x08},
+       {0x09, 0x10},
+       {0x0a, 0x18},
+       {0x0b, 0x20},
+       {0x00, 0x00}
+};
+
+/* MPU-401 IRQ conversion array         */
+static struct orVals orMIRQ[] __initdata = {
+       {0x05, 0x04},
+       {0x07, 0x44},
+       {0x09, 0x84},
+       {0x0a, 0xc4},
+       {0x00, 0x00}
+};
+
+/* DMA Channels conversion array        */
+static struct orVals orDMA[] __initdata = {
+       {0x00, 0x01},
+       {0x01, 0x02},
+       {0x03, 0x03},
+       {0x00, 0x00}
+};
+
+static struct aedsp16_info ae_config __initdata = {
+       DEF_AEDSP16_IOB,
+       DEF_AEDSP16_IRQ,
+       DEF_AEDSP16_MRQ,
+       DEF_AEDSP16_DMA,
+       -1,
+       -1,
+       INIT_NONE
+};
+
+/*
+ * Buffers to store audio card informations
+ */
+static char     DSPCopyright[CARDNAMELEN + 1] __initdata = {0, };
+static char     DSPVersion[CARDVERLEN + 1] __initdata = {0, };
+
+static int __init aedsp16_wait_data(int port)
+{
+       int             loop = STATUSRETRY;
+       unsigned char   ret = 0;
+
+       DBG1(("aedsp16_wait_data (0x%x): ", port));
+
+       do {
+                 ret = inb(port + DSP_DATAVAIL);
+       /*
+        * Wait for data available (bit 7 of ret == 1)
+        */
+         } while (!(ret & 0x80) && loop--);
+
+       if (ret & 0x80) {
+               DBG1(("success.\n"));
+               return TRUE;
+       }
+
+       DBG1(("failure.\n"));
+       return FALSE;
+}
+
+static int __init aedsp16_read(int port)
+{
+       int inbyte;
+
+       DBG(("    Read DSP Byte (0x%x): ", port));
+
+       if (aedsp16_wait_data(port) == FALSE) {
+               DBG(("failure.\n"));
+               return -1;
+       }
+
+       inbyte = inb(port + DSP_READ);
+
+       DBG(("read [0x%x]/{%c}.\n", inbyte, inbyte));
+
+       return inbyte;
+}
+
+static int __init aedsp16_test_dsp(int port)
+{
+       return ((aedsp16_read(port) == 0xaa) ? TRUE : FALSE);
+}
+
+static int __init aedsp16_dsp_reset(int port)
+{
+       /*
+        * Reset DSP
+        */
+
+       DBG(("Reset DSP:\n"));
+
+       outb(1, (port + DSP_RESET));
+       udelay(10);
+       outb(0, (port + DSP_RESET));
+       udelay(10);
+       udelay(10);
+       if (aedsp16_test_dsp(port) == TRUE) {
+               DBG(("success.\n"));
+               return TRUE;
+       } else
+               DBG(("failure.\n"));
+       return FALSE;
+}
+
+static int __init aedsp16_write(int port, int cmd)
+{
+       unsigned char   ret;
+       int             loop = HARDRETRY;
+
+       DBG(("    Write DSP Byte (0x%x) [0x%x]: ", port, cmd));
+
+       do {
+               ret = inb(port + DSP_STATUS);
+               /*
+                * DSP ready to receive data if bit 7 of ret == 0
+                */
+               if (!(ret & 0x80)) {
+                       outb(cmd, port + DSP_COMMAND);
+                       DBG(("success.\n"));
+                       return 0;
+               }
+       } while (loop--);
+
+       DBG(("timeout.\n"));
+       printk("[AEDSP16] DSP Command (0x%x) timeout.\n", cmd);
+
+       return -1;
+}
+
+#if defined(CONFIG_SC6600)
+
+#if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG)
+void __init aedsp16_pinfo(void) {
+       DBG(("\n Base address:  %x\n", decoded_hcfg.iobase));
+       DBG((" Joystick    : %s present\n", decoded_hcfg.joystick?"":" not"));
+       DBG((" WSS addr    :  %x\n", decoded_hcfg.wssbase));
+       DBG((" MPU-401 addr:  %x\n", decoded_hcfg.mpubase));
+       DBG((" CDROM       : %s present\n", (decoded_hcfg.cdrom!=4)?"":" not"));
+       DBG((" CDROMADDR   :  %x\n\n", decoded_hcfg.cdrombase));
+}
+#endif
+
+void __init aedsp16_hard_decode(void) {
+
+       DBG((" aedsp16_hard_decode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1]));
+
+/*
+ * Decode Cfg Bytes.
+ */
+       decoded_hcfg.iobase     = IOBASE(hard_cfg[0]);
+       decoded_hcfg.joystick   = JOY(hard_cfg[0]);
+       decoded_hcfg.wssbase    = WSSADDR(hard_cfg[0]);
+       decoded_hcfg.mpubase    = MPUADDR(hard_cfg[0]);
+       decoded_hcfg.cdrom      = CDROM(hard_cfg[1]);
+       decoded_hcfg.cdrombase  = CDROMADDR(hard_cfg[1]);
+
+#if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG)
+       printk(" Original sound card configuration:\n");
+       aedsp16_pinfo();
+#endif
+
+/*
+ * Now set up the real kernel configuration.
+ */
+       decoded_hcfg.iobase     = ae_config.base_io;
+       decoded_hcfg.wssbase    = ae_config.mss_base;
+       decoded_hcfg.mpubase    = ae_config.mpu_base;
+
+#if defined(CONFIG_SC6600_JOY)
+       decoded_hcfg.joystick   = CONFIG_SC6600_JOY; /* Enable */
+#endif
+#if defined(CONFIG_SC6600_CDROM)
+       decoded_hcfg.cdrom      = CONFIG_SC6600_CDROM; /* 4:N-3:I-2:G-1:P-0:S */
+#endif
+#if defined(CONFIG_SC6600_CDROMBASE)
+       decoded_hcfg.cdrombase  = CONFIG_SC6600_CDROMBASE; /* 0 Disable */
+#endif
+
+#if defined(AEDSP16_DEBUG)
+       DBG((" New Values:\n"));
+       aedsp16_pinfo();
+#endif
+
+       DBG(("success.\n"));
+}
+
+void __init aedsp16_hard_encode(void) {
+
+       DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1]));
+
+       hard_cfg[0] = 0;
+       hard_cfg[1] = 0;
+
+       hard_cfg[0] |= 0x20;
+
+       BLDIOBASE (hard_cfg[0], decoded_hcfg.iobase);
+       BLDWSSADDR(hard_cfg[0], decoded_hcfg.wssbase);
+       BLDMPUADDR(hard_cfg[0], decoded_hcfg.mpubase);
+       BLDJOY(hard_cfg[0], decoded_hcfg.joystick);
+       BLDCDROM(hard_cfg[1], decoded_hcfg.cdrom);
+       BLDCDROMADDR(hard_cfg[1], decoded_hcfg.cdrombase);
+
+#if defined(AEDSP16_DEBUG)
+       aedsp16_pinfo();
+#endif
+
+       DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1]));
+       DBG(("success.\n"));
+
+}
+
+static int __init aedsp16_hard_write(int port) {
+
+       DBG(("aedsp16_hard_write:\n"));
+
+       if (aedsp16_write(port, COMMAND_6C)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_6C);
+               DBG(("failure.\n"));
+               return FALSE;
+       }
+       if (aedsp16_write(port, COMMAND_5C)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C);
+               DBG(("failure.\n"));
+               return FALSE;
+       }
+       if (aedsp16_write(port, hard_cfg[0])) {
+               printk("[AEDSP16] DATA 0x%x: failed!\n", hard_cfg[0]);
+               DBG(("failure.\n"));
+               return FALSE;
+       }
+       if (aedsp16_write(port, hard_cfg[1])) {
+               printk("[AEDSP16] DATA 0x%x: failed!\n", hard_cfg[1]);
+               DBG(("failure.\n"));
+               return FALSE;
+       }
+       if (aedsp16_write(port, COMMAND_C5)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_C5);
+               DBG(("failure.\n"));
+               return FALSE;
+       }
+
+       DBG(("success.\n"));
+
+       return TRUE;
+}
+
+static int __init aedsp16_hard_read(int port) {
+
+       DBG(("aedsp16_hard_read:\n"));
+
+       if (aedsp16_write(port, READ_HARD_CFG)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", READ_HARD_CFG);
+               DBG(("failure.\n"));
+               return FALSE;
+       }
+
+       if ((hard_cfg[0] = aedsp16_read(port)) == -1) {
+               printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
+                       READ_HARD_CFG);
+               DBG(("failure.\n"));
+               return FALSE;
+       }
+       if ((hard_cfg[1] = aedsp16_read(port)) == -1) {
+               printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
+                       READ_HARD_CFG);
+               DBG(("failure.\n"));
+               return FALSE;
+       }
+       if (aedsp16_read(port) == -1) {
+               printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
+                       READ_HARD_CFG);
+               DBG(("failure.\n"));
+               return FALSE;
+       }
+
+       DBG(("success.\n"));
+
+       return TRUE;
+}
+
+static int __init aedsp16_ext_cfg_write(int port) {
+
+       int extcfg, val;
+
+       if (aedsp16_write(port, COMMAND_66)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_66);
+               return FALSE;
+       }
+
+       extcfg = 7;
+       if (decoded_hcfg.cdrom != 2)
+               extcfg = 0x0F;
+       if ((decoded_hcfg.cdrom == 4) ||
+           (decoded_hcfg.cdrom == 3))
+               extcfg &= ~2;
+       if (decoded_hcfg.cdrombase == 0)
+               extcfg &= ~2;
+       if (decoded_hcfg.mpubase == 0)
+               extcfg &= ~1;
+
+       if (aedsp16_write(port, extcfg)) {
+               printk("[AEDSP16] Write extcfg: failed!\n");
+               return FALSE;
+       }
+       if (aedsp16_write(port, 0)) {
+               printk("[AEDSP16] Write extcfg: failed!\n");
+               return FALSE;
+       }
+       if (decoded_hcfg.cdrom == 3) {
+               if (aedsp16_write(port, COMMAND_52)) {
+                       printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_52);
+                       return FALSE;
+               }
+               if ((val = aedsp16_read(port)) == -1) {
+                       printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n"
+                                       , COMMAND_52);
+                       return FALSE;
+               }
+               val &= 0x7F;
+               if (aedsp16_write(port, COMMAND_60)) {
+                       printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_60);
+                       return FALSE;
+               }
+               if (aedsp16_write(port, val)) {
+                       printk("[AEDSP16] Write val: failed!\n");
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+#endif /* CONFIG_SC6600 */
+
+static int __init aedsp16_cfg_write(int port) {
+       if (aedsp16_write(port, WRITE_MDIRQ_CFG)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG);
+               return FALSE;
+       }
+       if (aedsp16_write(port, soft_cfg)) {
+               printk("[AEDSP16] Initialization of (M)IRQ and DMA: failed!\n");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static int __init aedsp16_init_mss(int port)
+{
+       DBG(("aedsp16_init_mss:\n"));
+
+       mdelay(10);
+
+       if (aedsp16_write(port, DSP_INIT_MSS)) {
+               printk("[AEDSP16] aedsp16_init_mss [0x%x]: failed!\n",
+                               DSP_INIT_MSS);
+               DBG(("failure.\n"));
+               return FALSE;
+       }
+       
+       mdelay(10);
+
+       if (aedsp16_cfg_write(port) == FALSE)
+               return FALSE;
+
+       outb(soft_cfg_mss, ae_config.mss_base);
+
+       DBG(("success.\n"));
+
+       return TRUE;
+}
+
+static int __init aedsp16_setup_board(int port) {
+       int     loop = RETRY;
+
+#if defined(CONFIG_SC6600)
+       int     val = 0;
+
+       if (aedsp16_hard_read(port) == FALSE) {
+               printk("[AEDSP16] aedsp16_hard_read: failed!\n");
+               return FALSE;
+       }
+
+       if (aedsp16_write(port, COMMAND_52)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_52);
+               return FALSE;
+       }
+
+       if ((val = aedsp16_read(port)) == -1) {
+               printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
+                               COMMAND_52);
+               return FALSE;
+       }
+#endif
+
+       do {
+               if (aedsp16_write(port, COMMAND_88)) {
+                       printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_88);
+                       return FALSE;
+               }
+               mdelay(10);
+       } while ((aedsp16_wait_data(port) == FALSE) && loop--);
+
+       if (aedsp16_read(port) == -1) {
+               printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
+                               COMMAND_88);
+               return FALSE;
+       }
+
+#if !defined(CONFIG_SC6600)
+       if (aedsp16_write(port, COMMAND_5C)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C);
+               return FALSE;
+       }
+#endif
+
+       if (aedsp16_cfg_write(port) == FALSE)
+               return FALSE;
+
+#if defined(CONFIG_SC6600)
+       if (aedsp16_write(port, COMMAND_60)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_60);
+               return FALSE;
+       }
+       if (aedsp16_write(port, val)) {
+               printk("[AEDSP16] DATA 0x%x: failed!\n", val);
+               return FALSE;
+       }
+       if (aedsp16_write(port, COMMAND_6E)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_6E);
+               return FALSE;
+       }
+       if (aedsp16_write(port, ver[0])) {
+               printk("[AEDSP16] DATA 0x%x: failed!\n", ver[0]);
+               return FALSE;
+       }
+       if (aedsp16_write(port, ver[1])) {
+               printk("[AEDSP16] DATA 0x%x: failed!\n", ver[1]);
+               return FALSE;
+       }
+
+       if (aedsp16_hard_write(port) == FALSE) {
+               printk("[AEDSP16] aedsp16_hard_write: failed!\n");
+               return FALSE;
+       }
+
+       if (aedsp16_write(port, COMMAND_5C)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C);
+               return FALSE;
+       }
+
+#if defined(THIS_IS_A_THING_I_HAVE_NOT_TESTED_YET)
+       if (aedsp16_cfg_write(port) == FALSE)
+               return FALSE;
+#endif
+
+#endif
+
+       return TRUE;
+}
+
+static int __init aedsp16_stdcfg(int port) {
+       if (aedsp16_write(port, WRITE_MDIRQ_CFG)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG);
+               return FALSE;
+       }
+       /*
+        * 0x0A == (IRQ 7, DMA 1, MIRQ 0)
+        */
+       if (aedsp16_write(port, 0x0A)) {
+               printk("[AEDSP16] aedsp16_stdcfg: failed!\n");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static int __init aedsp16_dsp_version(int port)
+{
+       int             len = 0;
+       int             ret;
+
+       DBG(("Get DSP Version:\n"));
+
+       if (aedsp16_write(ae_config.base_io, GET_DSP_VERSION)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", GET_DSP_VERSION);
+               DBG(("failed.\n"));
+               return FALSE;
+       }
+
+       do {
+               if ((ret = aedsp16_read(port)) == -1) {
+                       DBG(("failed.\n"));
+                       return FALSE;
+               }
+       /*
+        * We already know how many int are stored (2), so we know when the
+        * string is finished.
+        */
+               ver[len++] = ret;
+         } while (len < CARDVERLEN);
+       sprintf(DSPVersion, "%d.%d", ver[0], ver[1]);
+
+       DBG(("success.\n"));
+
+       return TRUE;
+}
+
+static int __init aedsp16_dsp_copyright(int port)
+{
+       int             len = 0;
+       int             ret;
+
+       DBG(("Get DSP Copyright:\n"));
+
+       if (aedsp16_write(ae_config.base_io, GET_DSP_COPYRIGHT)) {
+               printk("[AEDSP16] CMD 0x%x: failed!\n", GET_DSP_COPYRIGHT);
+               DBG(("failed.\n"));
+               return FALSE;
+       }
+
+       do {
+               if ((ret = aedsp16_read(port)) == -1) {
+       /*
+        * If no more data available, return to the caller, no error if len>0.
+        * We have no other way to know when the string is finished.
+        */
+                       if (len)
+                               break;
+                       else {
+                               DBG(("failed.\n"));
+                               return FALSE;
+                       }
+               }
+
+               DSPCopyright[len++] = ret;
+
+         } while (len < CARDNAMELEN);
+
+       DBG(("success.\n"));
+
+       return TRUE;
+}
+
+static void __init aedsp16_init_tables(void)
+{
+       int i = 0;
+
+       memset(DSPCopyright, 0, CARDNAMELEN + 1);
+       memset(DSPVersion, 0, CARDVERLEN + 1);
+
+       for (i = 0; orIRQ[i].or; i++)
+               if (orIRQ[i].val == ae_config.irq) {
+                       soft_cfg |= orIRQ[i].or;
+                       soft_cfg_mss |= orIRQ[i].or;
+               }
+
+       for (i = 0; orMIRQ[i].or; i++)
+               if (orMIRQ[i].or == ae_config.mpu_irq)
+                       soft_cfg |= orMIRQ[i].or;
+
+       for (i = 0; orDMA[i].or; i++)
+               if (orDMA[i].val == ae_config.dma) {
+                       soft_cfg |= orDMA[i].or;
+                       soft_cfg_mss |= orDMA[i].or;
+               }
+}
+
+static int __init aedsp16_init_board(void)
+{
+       aedsp16_init_tables();
+
+       if (aedsp16_dsp_reset(ae_config.base_io) == FALSE) {
+               printk("[AEDSP16] aedsp16_dsp_reset: failed!\n");
+               return FALSE;
+       }
+       if (aedsp16_dsp_copyright(ae_config.base_io) == FALSE) {
+               printk("[AEDSP16] aedsp16_dsp_copyright: failed!\n");
+               return FALSE;
+       }
+
+       /*
+        * My AEDSP16 card return SC-6000 in DSPCopyright, so
+        * if we have something different, we have to be warned.
+        */
+       if (strcmp("SC-6000", DSPCopyright))
+               printk("[AEDSP16] Warning: non SC-6000 audio card!\n");
+
+       if (aedsp16_dsp_version(ae_config.base_io) == FALSE) {
+               printk("[AEDSP16] aedsp16_dsp_version: failed!\n");
+               return FALSE;
+       }
+
+       if (aedsp16_stdcfg(ae_config.base_io) == FALSE) {
+               printk("[AEDSP16] aedsp16_stdcfg: failed!\n");
+               return FALSE;
+       }
+
+#if defined(CONFIG_SC6600)
+       if (aedsp16_hard_read(ae_config.base_io) == FALSE) {
+               printk("[AEDSP16] aedsp16_hard_read: failed!\n");
+               return FALSE;
+       }
+
+       aedsp16_hard_decode();
+
+       aedsp16_hard_encode();
+
+       if (aedsp16_hard_write(ae_config.base_io) == FALSE) {
+               printk("[AEDSP16] aedsp16_hard_write: failed!\n");
+               return FALSE;
+       }
+
+       if (aedsp16_ext_cfg_write(ae_config.base_io) == FALSE) {
+               printk("[AEDSP16] aedsp16_ext_cfg_write: failed!\n");
+               return FALSE;
+       }
+#endif /* CONFIG_SC6600 */
+
+       if (aedsp16_setup_board(ae_config.base_io) == FALSE) {
+               printk("[AEDSP16] aedsp16_setup_board: failed!\n");
+               return FALSE;
+       }
+
+       if (ae_config.mss_base != -1) {
+               if (ae_config.init & INIT_MSS) {
+                       if (aedsp16_init_mss(ae_config.base_io) == FALSE) {
+                               printk("[AEDSP16] Can not initialize"
+                                      "Microsoft Sound System mode.\n");
+                               return FALSE;
+                       }
+               }
+       }
+
+#if !defined(MODULE) || defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG)
+
+       printk("Audio Excel DSP 16 init v%s (%s %s) [",
+               VERSION, DSPCopyright,
+               DSPVersion);
+
+       if (ae_config.mpu_base != -1) {
+               if (ae_config.init & INIT_MPU401) {
+                       printk("MPU401");
+                       if ((ae_config.init & INIT_MSS) ||
+                           (ae_config.init & INIT_SBPRO))
+                               printk(" ");
+               }
+       }
+
+       if (ae_config.mss_base == -1) {
+               if (ae_config.init & INIT_SBPRO) {
+                       printk("SBPro");
+                       if (ae_config.init & INIT_MSS)
+                               printk(" ");
+               }
+       }
+
+       if (ae_config.mss_base != -1)
+               if (ae_config.init & INIT_MSS)
+                       printk("MSS");
+
+       printk("]\n");
+#endif /* MODULE || AEDSP16_INFO || AEDSP16_DEBUG */
+
+       mdelay(10);
+
+       return TRUE;
+}
+
+static int __init init_aedsp16_sb(void)
+{
+       DBG(("init_aedsp16_sb: "));
+
+/*
+ * If the card is already init'ed MSS, we can not init it to SBPRO too
+ * because the board can not emulate simultaneously MSS and SBPRO.
+ */
+       if (ae_config.init & INIT_MSS)
+               return FALSE;
+       if (ae_config.init & INIT_SBPRO)
+               return FALSE;
+
+       ae_config.init |= INIT_SBPRO;
+
+       DBG(("done.\n"));
+
+       return TRUE;
+}
+
+static void __init uninit_aedsp16_sb(void)
+{
+       DBG(("uninit_aedsp16_sb: "));
+
+       ae_config.init &= ~INIT_SBPRO;
+
+       DBG(("done.\n"));
+}
+
+static int __init init_aedsp16_mss(void)
+{
+       DBG(("init_aedsp16_mss: "));
+
+/*
+ * If the card is already init'ed SBPRO, we can not init it to MSS too
+ * because the board can not emulate simultaneously MSS and SBPRO.
+ */
+       if (ae_config.init & INIT_SBPRO)
+               return FALSE;
+       if (ae_config.init & INIT_MSS)
+               return FALSE;
+/*
+ * We must check the CONFIG_AEDSP16_BASE region too because these are the I/O 
+ * ports to access card's control registers.
+ */
+       if (!(ae_config.init & INIT_MPU401)) {
+               if (check_region(ae_config.base_io, IOBASE_REGION_SIZE)) {
+                       printk(
+                       "AEDSP16 BASE I/O port region is already in use.\n");
+                       return FALSE;
+               }
+       }
+
+/*
+ * We must allocate the CONFIG_AEDSP16_BASE region too because these are the 
+ * I/O ports to access card's control registers.
+ */
+       if (!(ae_config.init & INIT_MPU401))
+               request_region(ae_config.base_io, IOBASE_REGION_SIZE,
+                               "aedsp16 (base)");
+
+       ae_config.init |= INIT_MSS;
+
+       DBG(("done.\n"));
+
+       return TRUE;
+}
+
+static void __init uninit_aedsp16_mss(void)
+{
+       DBG(("uninit_aedsp16_mss: "));
+
+       if ((!(ae_config.init & INIT_MPU401)) &&
+          (ae_config.init & INIT_MSS)) {
+               release_region(ae_config.base_io, IOBASE_REGION_SIZE);
+               DBG(("AEDSP16 base region released.\n"));
+       }
+
+       ae_config.init &= ~INIT_MSS;
+       DBG(("done.\n"));
+}
+
+static int __init init_aedsp16_mpu(void)
+{
+       DBG(("init_aedsp16_mpu: "));
+
+       if (ae_config.init & INIT_MPU401)
+               return FALSE;
+
+/*
+ * We must check the CONFIG_AEDSP16_BASE region too because these are the I/O 
+ * ports to access card's control registers.
+ */
+       if (!(ae_config.init & (INIT_MSS | INIT_SBPRO))) {
+               if (check_region(ae_config.base_io, IOBASE_REGION_SIZE)) {
+                       printk(
+                       "AEDSP16 BASE I/O port region is already in use.\n");
+                       return FALSE;
+               }
+       }
+
+       if (!(ae_config.init & (INIT_MSS | INIT_SBPRO)))
+               request_region(ae_config.base_io, IOBASE_REGION_SIZE,
+                               "aedsp16 (base)");
+
+       ae_config.init |= INIT_MPU401;
+
+       DBG(("done.\n"));
+
+       return TRUE;
+}
+
+static void __init uninit_aedsp16_mpu(void)
+{
+       DBG(("uninit_aedsp16_mpu: "));
+
+       if ((!(ae_config.init & (INIT_MSS | INIT_SBPRO))) &&
+          (ae_config.init & INIT_MPU401)) {
+               release_region(ae_config.base_io, IOBASE_REGION_SIZE);
+               DBG(("AEDSP16 base region released.\n"));
+       }
+
+       ae_config.init &= ~INIT_MPU401;
+
+       DBG(("done.\n"));
+}
+
+int __init init_aedsp16(void)
+{
+       int initialized = FALSE;
+
+       DBG(("Initializing BASE[0x%x] IRQ[%d] DMA[%d] MIRQ[%d]\n",
+            ae_config.base_io,ae_config.irq,ae_config.dma,ae_config.mpu_irq));
+
+       if (ae_config.mss_base == -1) {
+               if (init_aedsp16_sb() == FALSE) {
+                       uninit_aedsp16_sb();
+               } else {
+                       initialized = TRUE;
+               }
+       }
+
+       if (ae_config.mpu_base != -1) {
+               if (init_aedsp16_mpu() == FALSE) {
+                       uninit_aedsp16_mpu();
+               } else {
+                       initialized = TRUE;
+               }
+       }
+
+/*
+ * In the sequence of init routines, the MSS init MUST be the last!
+ * This because of the special register programming the MSS mode needs.
+ * A board reset would disable the MSS mode restoring the default SBPRO
+ * mode.
+ */
+       if (ae_config.mss_base != -1) {
+               if (init_aedsp16_mss() == FALSE) {
+                       uninit_aedsp16_mss();
+               } else {
+                       initialized = TRUE;
+               }
+       }
+
+       if (initialized)
+               initialized = aedsp16_init_board();
+       return initialized;
+}
+
+void __init uninit_aedsp16(void)
+{
+       if (ae_config.mss_base != -1)
+               uninit_aedsp16_mss();
+       else
+               uninit_aedsp16_sb();
+       if (ae_config.mpu_base != -1)
+               uninit_aedsp16_mpu();
+}
+
+static int __initdata io = -1;
+static int __initdata irq = -1;
+static int __initdata dma = -1;
+static int __initdata mpu_irq = -1;
+static int __initdata mss_base = -1;
+static int __initdata mpu_base = -1;
+
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O base address (0x220 0x240)");
+MODULE_PARM(irq, "i");
+MODULE_PARM_DESC(irq, "IRQ line (5 7 9 10 11)");
+MODULE_PARM(dma, "i");
+MODULE_PARM_DESC(dma, "dma line (0 1 3)");
+MODULE_PARM(mpu_irq, "i");
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ line (5 7 9 10 0)");
+MODULE_PARM(mss_base, "i");
+MODULE_PARM_DESC(mss_base, "MSS emulation I/O base address (0x530 0xE80)");
+MODULE_PARM(mpu_base, "i");
+MODULE_PARM_DESC(mpu_base,"MPU-401 I/O base address (0x300 0x310 0x320 0x330)");
+MODULE_AUTHOR("Riccardo Facchetti <fizban@tin.it>");
+MODULE_DESCRIPTION("Audio Excel DSP 16 Driver Version " VERSION);
+
+static int __init do_init_aedsp16(void) {
+       printk("Audio Excel DSP 16 init driver Copyright (C) Riccardo Facchetti 1995-98\n");
+       if (io == -1 || dma == -1 || irq == -1) {
+               printk(KERN_INFO "aedsp16: I/O, IRQ and DMA are mandatory\n");
+               return -EINVAL;
+       }
+
+       ae_config.base_io = io;
+       ae_config.irq = irq;
+       ae_config.dma = dma;
+
+       ae_config.mss_base = mss_base;
+       ae_config.mpu_base = mpu_base;
+       ae_config.mpu_irq = mpu_irq;
+
+       if (init_aedsp16() == FALSE) {
+               printk(KERN_ERR "aedsp16: initialization failed\n");
+               /*
+                * XXX
+                * What error should we return here ?
+                */
+               return -EINVAL;
+       }
+       SOUND_LOCK;
+       return 0;
+}
+
+static void __exit cleanup_aedsp16(void) {
+       uninit_aedsp16();
+       SOUND_LOCK_END;
+}
+
+module_init(do_init_aedsp16);
+module_exit(cleanup_aedsp16);
+
+#ifndef MODULE
+static int __init setup_aedsp16(char *str)
+{
+       /* io, irq, dma, mss_io, mpu_io, mpu_irq */
+       int ints[7];
+       
+       str = get_options(str, ARRAY_SIZE(ints), ints);
+
+       io       = ints[1];
+       irq      = ints[2];
+       dma      = ints[3];
+       mss_base = ints[4];
+       mpu_base = ints[5];
+       mpu_irq  = ints[6];
+}
+
+__setup("aedsp16=", setup_aedsp16);
+#endif
diff --git a/drivers/sound/awe_hw.h b/drivers/sound/awe_hw.h
new file mode 100644 (file)
index 0000000..c7dde26
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * sound/awe_hw.h
+ *
+ * Access routines and definitions for the low level driver for the 
+ * Creative AWE32/SB32/AWE64 wave table synth.
+ *   version 0.4.3; Mar. 1, 1998
+ *
+ * Copyright (C) 1996-1998 Takashi Iwai
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef AWE_HW_H_DEF
+#define AWE_HW_H_DEF
+
+/*
+ * Emu-8000 control registers
+ * name(channel)       reg, port
+ */
+
+#define awe_cmd_idx(reg,ch)    (((reg)<< 5) | (ch))
+
+#define Data0    0             /* 0x620: doubleword r/w */
+#define Data1    1             /* 0xA20: doubleword r/w */
+#define Data2    2             /* 0xA22: word r/w */
+#define Data3    3             /* 0xE20: word r/w */
+#define Pointer  4             /* 0xE22 register pointer r/w */
+
+#define AWE_CPF(ch)    awe_cmd_idx(0,ch), Data0        /* DW: current pitch and fractional address */
+#define AWE_PTRX(ch)   awe_cmd_idx(1,ch), Data0        /* DW: pitch target and reverb send */
+#define AWE_CVCF(ch)   awe_cmd_idx(2,ch), Data0        /* DW: current volume and filter cutoff */
+#define AWE_VTFT(ch)   awe_cmd_idx(3,ch), Data0        /* DW: volume and filter cutoff targets */
+#define AWE_0080(ch)   awe_cmd_idx(4,ch), Data0        /* DW: ?? */
+#define AWE_00A0(ch)   awe_cmd_idx(5,ch), Data0        /* DW: ?? */
+#define AWE_PSST(ch)   awe_cmd_idx(6,ch), Data0        /* DW: pan send and loop start address */
+#define AWE_CSL(ch)    awe_cmd_idx(7,ch), Data0        /* DW: chorus send and loop end address */
+#define AWE_CCCA(ch)   awe_cmd_idx(0,ch), Data1        /* DW: Q, control bits, and current address */
+#define AWE_HWCF4      awe_cmd_idx(1,9),  Data1        /* DW: config dw 4 */
+#define AWE_HWCF5      awe_cmd_idx(1,10), Data1        /* DW: config dw 5 */
+#define AWE_HWCF6      awe_cmd_idx(1,13), Data1        /* DW: config dw 6 */
+#define AWE_HWCF7      awe_cmd_idx(1,14), Data1        /* DW: config dw 7? (not documented) */
+#define AWE_SMALR      awe_cmd_idx(1,20), Data1        /* DW: sound memory address for left read */
+#define AWE_SMARR      awe_cmd_idx(1,21), Data1        /* DW:    for right read */
+#define AWE_SMALW      awe_cmd_idx(1,22), Data1        /* DW: sound memory address for left write */
+#define AWE_SMARW      awe_cmd_idx(1,23), Data1        /* DW:    for right write */
+#define AWE_SMLD       awe_cmd_idx(1,26), Data1        /* W: sound memory left data */
+#define AWE_SMRD       awe_cmd_idx(1,26), Data2        /* W:    right data */
+#define AWE_WC         awe_cmd_idx(1,27), Data2        /* W: sample counter */
+#define AWE_WC_Cmd     awe_cmd_idx(1,27)
+#define AWE_WC_Port    Data2
+#define AWE_HWCF1      awe_cmd_idx(1,29), Data1        /* W: config w 1 */
+#define AWE_HWCF2      awe_cmd_idx(1,30), Data1        /* W: config w 2 */
+#define AWE_HWCF3      awe_cmd_idx(1,31), Data1        /* W: config w 3 */
+#define AWE_INIT1(ch)  awe_cmd_idx(2,ch), Data1        /* W: init array 1 */
+#define AWE_INIT2(ch)  awe_cmd_idx(2,ch), Data2        /* W: init array 2 */
+#define AWE_INIT3(ch)  awe_cmd_idx(3,ch), Data1        /* W: init array 3 */
+#define AWE_INIT4(ch)  awe_cmd_idx(3,ch), Data2        /* W: init array 4 */
+#define AWE_ENVVOL(ch) awe_cmd_idx(4,ch), Data1        /* W: volume envelope delay */
+#define AWE_DCYSUSV(ch)        awe_cmd_idx(5,ch), Data1        /* W: volume envelope sustain and decay */
+#define AWE_ENVVAL(ch) awe_cmd_idx(6,ch), Data1        /* W: modulation envelope delay */
+#define AWE_DCYSUS(ch) awe_cmd_idx(7,ch), Data1        /* W: modulation envelope sustain and decay */
+#define AWE_ATKHLDV(ch)        awe_cmd_idx(4,ch), Data2        /* W: volume envelope attack and hold */
+#define AWE_LFO1VAL(ch)        awe_cmd_idx(5,ch), Data2        /* W: LFO#1 Delay */
+#define AWE_ATKHLD(ch) awe_cmd_idx(6,ch), Data2        /* W: modulation envelope attack and hold */
+#define AWE_LFO2VAL(ch)        awe_cmd_idx(7,ch), Data2        /* W: LFO#2 Delay */
+#define AWE_IP(ch)     awe_cmd_idx(0,ch), Data3        /* W: initial pitch */
+#define AWE_IFATN(ch)  awe_cmd_idx(1,ch), Data3        /* W: initial filter cutoff and attenuation */
+#define AWE_PEFE(ch)   awe_cmd_idx(2,ch), Data3        /* W: pitch and filter envelope heights */
+#define AWE_FMMOD(ch)  awe_cmd_idx(3,ch), Data3        /* W: vibrato and filter modulation freq */
+#define AWE_TREMFRQ(ch)        awe_cmd_idx(4,ch), Data3        /* W: LFO#1 tremolo amount and freq */
+#define AWE_FM2FRQ2(ch)        awe_cmd_idx(5,ch), Data3        /* W: LFO#2 vibrato amount and freq */
+
+/* used during detection (returns ROM version?; not documented in ADIP) */
+#define AWE_U1         0xE0, Data3       /* (R)(W) used in initialization */
+#define AWE_U2(ch)     0xC0+(ch), Data3  /* (W)(W) used in init envelope  */
+
+
+#define AWE_MAX_VOICES         32
+#define AWE_NORMAL_VOICES      30      /*30&31 are reserved for DRAM refresh*/
+
+#define AWE_MAX_CHANNELS       32      /* max midi channels (must >= voices) */
+#define AWE_MAX_LAYERS AWE_MAX_VOICES  /* maximum number of multiple layers */
+
+#define AWE_DRAM_OFFSET                0x200000
+#define AWE_MAX_DRAM_SIZE      (28 * 1024)     /* 28 MB is max onboard memory */
+
+#endif
diff --git a/drivers/sound/awe_wave.c b/drivers/sound/awe_wave.c
new file mode 100644 (file)
index 0000000..bedebb3
--- /dev/null
@@ -0,0 +1,6118 @@
+/*
+ * sound/awe_wave.c
+ *
+ * The low level driver for the AWE32/SB32/AWE64 wave table synth.
+ *   version 0.4.3; Feb. 1, 1999
+ *
+ * Copyright (C) 1996-1999 Takashi Iwai
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/awe_voice.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include "sound_config.h"
+#include "soundmodule.h"
+
+#include "awe_wave.h"
+#include "awe_hw.h"
+
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+#include "tuning.h"
+#include <linux/ultrasound.h>
+#endif
+
+/*
+ * debug message
+ */
+
+/* do not allocate buffer at beginning */
+#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;}
+
+#ifdef AWE_DEBUG_ON
+#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }}
+#define ERRMSG(XXX)    {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }}
+#define FATALERR(XXX)  XXX
+#else
+#define DEBUG(LVL,XXX) /**/
+#define ERRMSG(XXX)    XXX
+#define FATALERR(XXX)  XXX
+#endif
+
+/*
+ * bank and voice record
+ */
+
+/* soundfont record */
+typedef struct _sf_list {
+       unsigned short sf_id;
+       unsigned short type;
+       int num_info;           /* current info table index */
+       int num_sample;         /* current sample table index */
+       int mem_ptr;            /* current word byte pointer */
+       int infos;
+       int samples;
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+       int shared;             /* shared index */
+       unsigned char name[AWE_PATCH_NAME_LEN];
+#endif
+} sf_list;
+
+/* bank record */
+typedef struct _awe_voice_list {
+       int next;       /* linked list with same sf_id */
+       unsigned char bank, instr;      /* preset number information */
+       char type, disabled;    /* type=normal/mapped, disabled=boolean */
+       awe_voice_info v;       /* voice information */
+       int next_instr; /* preset table list */
+       int next_bank;  /* preset table list */
+} awe_voice_list;
+
+/* voice list type */
+#define V_ST_NORMAL    0
+#define V_ST_MAPPED    1
+
+typedef struct _awe_sample_list {
+       int next;       /* linked list with same sf_id */
+       awe_sample_info v;      /* sample information */
+} awe_sample_list;
+
+/* sample and information table */
+static int current_sf_id = 0;
+static int locked_sf_id = 0;
+static int max_sfs;
+static sf_list *sflists = NULL;
+
+#define awe_free_mem_ptr() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].mem_ptr)
+#define awe_free_info() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_info)
+#define awe_free_sample() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_sample)
+
+static int max_samples;
+static awe_sample_list *samples = NULL;
+
+static int max_infos;
+static awe_voice_list *infos = NULL;
+
+
+#define AWE_MAX_PRESETS                256
+#define AWE_DEFAULT_PRESET     0
+#define AWE_DEFAULT_BANK       0
+#define AWE_DEFAULT_DRUM       0
+#define AWE_DRUM_BANK          128
+
+#define MAX_LAYERS     AWE_MAX_VOICES
+
+/* preset table index */
+static int preset_table[AWE_MAX_PRESETS];
+
+/*
+ * voice table
+ */
+
+/* effects table */
+typedef        struct FX_Rec { /* channel effects */
+       unsigned char flags[AWE_FX_END];
+       short val[AWE_FX_END];
+} FX_Rec;
+
+
+/* channel parameters */
+typedef struct _awe_chan_info {
+       int channel;            /* channel number */
+       int bank;               /* current tone bank */
+       int instr;              /* current program */
+       int bender;             /* midi pitchbend (-8192 - 8192) */
+       int bender_range;       /* midi bender range (x100) */
+       int panning;            /* panning (0-127) */
+       int main_vol;           /* channel volume (0-127) */
+       int expression_vol;     /* midi expression (0-127) */
+       int chan_press;         /* channel pressure */
+       int vrec;               /* instrument list */
+       int def_vrec;           /* default instrument list */
+       int sustained;          /* sustain status in MIDI */
+       FX_Rec fx;              /* effects */
+       FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */
+} awe_chan_info;
+
+/* voice parameters */
+typedef struct _voice_info {
+       int state;
+#define AWE_ST_OFF             (1<<0)  /* no sound */
+#define AWE_ST_ON              (1<<1)  /* playing */
+#define AWE_ST_STANDBY         (1<<2)  /* stand by for playing */
+#define AWE_ST_SUSTAINED       (1<<3)  /* sustained */
+#define AWE_ST_MARK            (1<<4)  /* marked for allocation */
+#define AWE_ST_DRAM            (1<<5)  /* DRAM read/write */
+#define AWE_ST_FM              (1<<6)  /* reserved for FM */
+#define AWE_ST_RELEASED                (1<<7)  /* released */
+
+       int ch;                 /* midi channel */
+       int key;                /* internal key for search */
+       int layer;              /* layer number (for channel mode only) */
+       int time;               /* allocated time */
+       awe_chan_info   *cinfo; /* channel info */
+
+       int note;               /* midi key (0-127) */
+       int velocity;           /* midi velocity (0-127) */
+       int sostenuto;          /* sostenuto on/off */
+       awe_voice_info *sample; /* assigned voice */
+
+       /* EMU8000 parameters */
+       int apitch;             /* pitch parameter */
+       int avol;               /* volume parameter */
+       int apan;               /* panning parameter */
+       int acutoff;            /* cutoff parameter */
+       short aaux;             /* aux word */
+} voice_info;
+
+/* voice information */
+static voice_info voices[AWE_MAX_VOICES];
+
+#define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED))
+#define IS_NO_EFFECT(v)        (voices[v].state != AWE_ST_ON)
+#define IS_PLAYING(v)  (voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED))
+#define IS_EMPTY(v)    (voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM))
+
+
+/* MIDI channel effects information (for hw control) */
+static awe_chan_info channels[AWE_MAX_CHANNELS];
+
+
+/*----------------------------------------------------------------
+ * global variables
+ *----------------------------------------------------------------*/
+
+#ifndef AWE_DEFAULT_BASE_ADDR
+#define AWE_DEFAULT_BASE_ADDR  0       /* autodetect */
+#endif
+
+#ifndef AWE_DEFAULT_MEM_SIZE
+#define AWE_DEFAULT_MEM_SIZE   -1      /* autodetect */
+#endif
+
+#define awe_port       io
+#define awe_mem_size   memsize
+int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */
+int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */
+
+MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>");
+MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "base i/o port of Emu8000");
+MODULE_PARM(memsize, "i");
+MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes");
+EXPORT_NO_SYMBOLS;
+
+/* DRAM start offset */
+static int awe_mem_start = AWE_DRAM_OFFSET;
+
+/* maximum channels for playing */
+static int awe_max_voices = AWE_MAX_VOICES;
+
+static int patch_opened = 0;           /* sample already loaded? */
+
+static char atten_relative = FALSE;
+static short atten_offset = 0;
+
+static int awe_present = FALSE;                /* awe device present? */
+static int awe_busy = FALSE;           /* awe device opened? */
+
+static int my_dev = -1;                        
+
+#define DEFAULT_DRUM_FLAGS     ((1 << 9) | (1 << 25))
+#define IS_DRUM_CHANNEL(c)     (drum_flags & (1 << (c)))
+#define DRUM_CHANNEL_ON(c)     (drum_flags |= (1 << (c)))
+#define DRUM_CHANNEL_OFF(c)    (drum_flags &= ~(1 << (c)))
+static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */
+
+static int playing_mode = AWE_PLAY_INDIRECT;
+#define SINGLE_LAYER_MODE()    (playing_mode == AWE_PLAY_INDIRECT || playing_mode == AWE_PLAY_DIRECT)
+#define MULTI_LAYER_MODE()     (playing_mode == AWE_PLAY_MULTI || playing_mode == AWE_PLAY_MULTI2)
+
+static int current_alloc_time = 0;     /* voice allocation index for channel mode */
+
+static struct synth_info awe_info = {
+       "AWE32 Synth",          /* name */
+       0,                      /* device */
+       SYNTH_TYPE_SAMPLE,      /* synth_type */
+       SAMPLE_TYPE_AWE32,      /* synth_subtype */
+       0,                      /* perc_mode (obsolete) */
+       AWE_MAX_VOICES,         /* nr_voices */
+       0,                      /* nr_drums (obsolete) */
+       AWE_MAX_INFOS           /* instr_bank_size */
+};
+
+
+static struct voice_alloc_info *voice_alloc;   /* set at initialization */
+
+
+/*
+ * function prototypes
+ */
+
+static int awe_check_port(void);
+static void awe_request_region(void);
+static void awe_release_region(void);
+
+static void awe_reset_samples(void);
+/* emu8000 chip i/o access */
+static void setup_ports(int p1, int p2, int p3);
+static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data);
+static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data);
+static unsigned short awe_peek(unsigned short cmd, unsigned short port);
+static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port);
+static void awe_wait(unsigned short delay);
+
+/* initialize emu8000 chip */
+static int _attach_awe(void);
+static void _unload_awe(void);
+static void awe_initialize(void);
+
+/* set voice parameters */
+static void awe_init_ctrl_parms(int init_all);
+static void awe_init_voice_info(awe_voice_info *vp);
+static void awe_init_voice_parm(awe_voice_parm *pp);
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+static int freq_to_note(int freq);
+static int calc_rate_offset(int Hz);
+/*static int calc_parm_delay(int msec);*/
+static int calc_parm_hold(int msec);
+static int calc_parm_attack(int msec);
+static int calc_parm_decay(int msec);
+static int calc_parm_search(int msec, short *table);
+#endif /* gus compat */
+
+/* turn on/off note */
+static void awe_note_on(int voice);
+static void awe_note_off(int voice);
+static void awe_terminate(int voice);
+static void awe_exclusive_off(int voice);
+static void awe_note_off_all(int do_sustain);
+
+/* calculate voice parameters */
+typedef void (*fx_affect_func)(int voice, int forced);
+static void awe_set_pitch(int voice, int forced);
+static void awe_set_voice_pitch(int voice, int forced);
+static void awe_set_volume(int voice, int forced);
+static void awe_set_voice_vol(int voice, int forced);
+static void awe_set_pan(int voice, int forced);
+static void awe_fx_fmmod(int voice, int forced);
+static void awe_fx_tremfrq(int voice, int forced);
+static void awe_fx_fm2frq2(int voice, int forced);
+static void awe_fx_filterQ(int voice, int forced);
+static void awe_calc_pitch(int voice);
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+static void awe_calc_pitch_from_freq(int voice, int freq);
+#endif
+static void awe_calc_volume(int voice);
+static void awe_update_volume(void);
+static void awe_change_master_volume(short val);
+static void awe_voice_init(int voice, int init_all);
+static void awe_channel_init(int ch, int init_all);
+static void awe_fx_init(int ch);
+static void awe_send_effect(int voice, int layer, int type, int val);
+static void awe_modwheel_change(int voice, int value);
+
+/* sequencer interface */
+static int awe_open(int dev, int mode);
+static void awe_close(int dev);
+static int awe_ioctl(int dev, unsigned int cmd, caddr_t arg);
+static int awe_kill_note(int dev, int voice, int note, int velocity);
+static int awe_start_note(int dev, int v, int note_num, int volume);
+static int awe_set_instr(int dev, int voice, int instr_no);
+static int awe_set_instr_2(int dev, int voice, int instr_no);
+static void awe_reset(int dev);
+static void awe_hw_control(int dev, unsigned char *event);
+static int awe_load_patch(int dev, int format, const char *addr,
+                         int offs, int count, int pmgr_flag);
+static void awe_aftertouch(int dev, int voice, int pressure);
+static void awe_controller(int dev, int voice, int ctrl_num, int value);
+static void awe_panning(int dev, int voice, int value);
+static void awe_volume_method(int dev, int mode);
+static void awe_bender(int dev, int voice, int value);
+static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc);
+static void awe_setup_voice(int dev, int voice, int chn);
+
+#define awe_key_pressure(dev,voice,key,press) awe_start_note(dev,voice,(key)+128,press)
+
+/* hardware controls */
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+static void awe_hw_gus_control(int dev, int cmd, unsigned char *event);
+#endif
+static void awe_hw_awe_control(int dev, int cmd, unsigned char *event);
+static void awe_voice_change(int voice, fx_affect_func func);
+static void awe_sostenuto_on(int voice, int forced);
+static void awe_sustain_off(int voice, int forced);
+static void awe_terminate_and_init(int voice, int forced);
+
+/* voice search */
+static int awe_search_instr(int bank, int preset);
+static int awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist);
+static void awe_alloc_multi_voices(int ch, int note, int velocity, int key);
+static void awe_alloc_one_voice(int voice, int note, int velocity);
+static int awe_clear_voice(void);
+
+/* load / remove patches */
+static int awe_open_patch(awe_patch_info *patch, const char *addr, int count);
+static int awe_close_patch(awe_patch_info *patch, const char *addr, int count);
+static int awe_unload_patch(awe_patch_info *patch, const char *addr, int count);
+static int awe_load_info(awe_patch_info *patch, const char *addr, int count);
+static int awe_load_data(awe_patch_info *patch, const char *addr, int count);
+static int awe_replace_data(awe_patch_info *patch, const char *addr, int count);
+static int awe_load_map(awe_patch_info *patch, const char *addr, int count);
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+static int awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag);
+#endif
+/*static int awe_probe_info(awe_patch_info *patch, const char *addr, int count);*/
+static int awe_probe_data(awe_patch_info *patch, const char *addr, int count);
+static int check_patch_opened(int type, char *name);
+static int awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels);
+static void add_sf_info(int rec);
+static void add_sf_sample(int rec);
+static void purge_old_list(int rec, int next);
+static void add_info_list(int rec);
+static void awe_remove_samples(int sf_id);
+static void rebuild_preset_list(void);
+static short awe_set_sample(awe_voice_info *vp);
+static int search_sample_index(int sf, int sample, int level);
+
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+static int is_identical_id(int id1, int id2);
+static int is_identical_name(unsigned char *name, int id);
+static int is_shared_sf(unsigned char *name);
+static int info_duplicated(awe_voice_list *rec);
+#endif /* allow sharing */
+
+/* lowlevel functions */
+static void awe_init_audio(void);
+static void awe_init_dma(void);
+static void awe_init_array(void);
+static void awe_send_array(unsigned short *data);
+static void awe_tweak_voice(int voice);
+static void awe_tweak(void);
+static void awe_init_fm(void);
+static int awe_open_dram_for_write(int offset, int channels);
+static void awe_open_dram_for_check(void);
+static void awe_close_dram(void);
+static void awe_write_dram(unsigned short c);
+static int awe_detect_base(int addr);
+static int awe_detect(void);
+static void awe_check_dram(void);
+static int awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count);
+static void awe_set_chorus_mode(int mode);
+static void awe_update_chorus_mode(void);
+static int awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count);
+static void awe_set_reverb_mode(int mode);
+static void awe_update_reverb_mode(void);
+static void awe_equalizer(int bass, int treble);
+static void awe_update_equalizer(void);
+
+#ifdef CONFIG_AWE32_MIXER
+static void attach_mixer(void);
+static void unload_mixer(void);
+#endif
+
+#ifdef CONFIG_AWE32_MIDIEMU
+static void attach_midiemu(void);
+static void unload_midiemu(void);
+#endif
+
+#define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b)
+
+/*
+ * control parameters
+ */
+
+
+#ifdef AWE_USE_NEW_VOLUME_CALC
+#define DEF_VOLUME_CALC        TRUE
+#else
+#define DEF_VOLUME_CALC        FALSE
+#endif /* new volume */
+
+#define DEF_ZERO_ATTEN         32      /* 12dB below */
+#define DEF_MOD_SENSE          18
+#define DEF_CHORUS_MODE                2
+#define DEF_REVERB_MODE                4
+#define DEF_BASS_LEVEL         5
+#define DEF_TREBLE_LEVEL       9
+
+static struct CtrlParmsDef {
+       int value;
+       int init_each_time;
+       void (*update)(void);
+} ctrl_parms[AWE_MD_END] = {
+       {0,0, NULL}, {0,0, NULL}, /* <-- not used */
+       {AWE_VERSION_NUMBER, FALSE, NULL},
+       {TRUE, FALSE, NULL}, /* exclusive */
+       {TRUE, FALSE, NULL}, /* realpan */
+       {AWE_DEFAULT_BANK, FALSE, NULL}, /* gusbank */
+       {FALSE, TRUE, NULL}, /* keep effect */
+       {DEF_ZERO_ATTEN, FALSE, awe_update_volume}, /* zero_atten */
+       {FALSE, FALSE, NULL}, /* chn_prior */
+       {DEF_MOD_SENSE, FALSE, NULL}, /* modwheel sense */
+       {AWE_DEFAULT_PRESET, FALSE, NULL}, /* def_preset */
+       {AWE_DEFAULT_BANK, FALSE, NULL}, /* def_bank */
+       {AWE_DEFAULT_DRUM, FALSE, NULL}, /* def_drum */
+       {FALSE, FALSE, NULL}, /* toggle_drum_bank */
+       {DEF_VOLUME_CALC, FALSE, awe_update_volume}, /* new_volume_calc */
+       {DEF_CHORUS_MODE, FALSE, awe_update_chorus_mode}, /* chorus mode */
+       {DEF_REVERB_MODE, FALSE, awe_update_reverb_mode}, /* reverb mode */
+       {DEF_BASS_LEVEL, FALSE, awe_update_equalizer}, /* bass level */
+       {DEF_TREBLE_LEVEL, FALSE, awe_update_equalizer}, /* treble level */
+       {0, FALSE, NULL},       /* debug mode */
+       {FALSE, FALSE, NULL}, /* pan exchange */
+};
+
+static int ctrls[AWE_MD_END];
+
+
+/*----------------------------------------------------------------
+ * synth operation table
+ *----------------------------------------------------------------*/
+
+static struct synth_operations awe_operations =
+{
+       "EMU8K",
+       &awe_info,
+       0,
+       SYNTH_TYPE_SAMPLE,
+       SAMPLE_TYPE_AWE32,
+       awe_open,
+       awe_close,
+       awe_ioctl,
+       awe_kill_note,
+       awe_start_note,
+       awe_set_instr_2,
+       awe_reset,
+       awe_hw_control,
+       awe_load_patch,
+       awe_aftertouch,
+       awe_controller,
+       awe_panning,
+       awe_volume_method,
+       awe_bender,
+       awe_alloc,
+       awe_setup_voice
+};
+
+
+/*================================================================
+ * General attach / unload interface
+ *================================================================*/
+
+static int _attach_awe(void)
+{
+       if (awe_present) return 0; /* for OSS38.. called twice? */
+
+       /* check presence of AWE32 card */
+       if (! awe_detect()) {
+               printk(KERN_WARNING "AWE32: not detected\n");
+               return 0;
+       }
+
+       /* check AWE32 ports are available */
+       if (awe_check_port()) {
+               printk(KERN_WARNING "AWE32: I/O area already used.\n");
+               return 0;
+       }
+
+       /* set buffers to NULL */
+       sflists = NULL;
+       samples = NULL;
+       infos = NULL;
+
+       /* allocate sample tables */
+       INIT_TABLE(sflists, max_sfs, AWE_MAX_SF_LISTS, sf_list);
+       INIT_TABLE(samples, max_samples, AWE_MAX_SAMPLES, awe_sample_list);
+       INIT_TABLE(infos, max_infos, AWE_MAX_INFOS, awe_voice_list);
+
+       my_dev = sound_alloc_synthdev();
+       if (my_dev == -1) {
+               printk(KERN_WARNING "AWE32 Error: too many synthesizers\n");
+               return 0;
+       }
+
+       voice_alloc = &awe_operations.alloc;
+       voice_alloc->max_voice = awe_max_voices;
+       synth_devs[my_dev] = &awe_operations;
+
+#ifdef CONFIG_AWE32_MIXER
+       attach_mixer();
+#endif
+#ifdef CONFIG_AWE32_MIDIEMU
+       attach_midiemu();
+#endif
+
+       /* reserve I/O ports for awedrv */
+       awe_request_region();
+
+       /* clear all samples */
+       awe_reset_samples();
+
+       /* intialize AWE32 hardware */
+       awe_initialize();
+
+       sprintf(awe_info.name, "AWE32-%s (RAM%dk)",
+               AWEDRV_VERSION, awe_mem_size/1024);
+       printk("<SoundBlaster EMU8000 (RAM%dk)>\n", awe_mem_size/1024);
+
+       awe_present = TRUE;
+
+       SOUND_LOCK;
+
+       return 1;
+}
+
+
+static void free_tables(void)
+{
+       if(sflists)
+               vfree(sflists);
+       sflists = NULL; max_sfs = 0;
+       if (samples)
+               vfree(samples);
+       samples = NULL; max_samples = 0;
+       if (infos)
+               vfree(infos);
+       infos = NULL; max_infos = 0;
+}
+
+static void *realloc_block(void *buf, int oldsize, int size)
+{
+       void *ptr;
+       if (oldsize == size)
+               return buf;
+       if ((ptr = vmalloc(size)) == NULL)
+               return NULL;
+       if (oldsize && size)
+               memcpy(ptr, buf, ((oldsize < size) ? oldsize : size) );
+       if (buf)
+               vfree(buf);
+       return ptr;
+}
+
+
+static void _unload_awe(void)
+{
+       if (awe_present) {
+               awe_reset_samples();
+               awe_release_region();
+               free_tables();
+#ifdef CONFIG_AWE32_MIXER
+               unload_mixer();
+#endif
+#ifdef CONFIG_AWE32_MIDIEMU
+               unload_midiemu();
+#endif
+               sound_unload_synthdev(my_dev);
+               awe_present = FALSE;
+               SOUND_LOCK_END;
+       }
+}
+
+/*
+ * Linux PnP driver support
+ */
+
+#ifdef CONFIG_PNP_DRV
+
+#include <linux/pnp.h>
+
+static int pnp = 1;    /* use PnP as default */
+
+#define AWE_NUM_CHIPS  3
+static unsigned int pnp_ids[AWE_NUM_CHIPS] = {
+       PNP_EISAID('C','T','L',0x0021),
+       PNP_EISAID('C','T','L',0x0022),
+       PNP_EISAID('C','T','L',0x0023),
+};
+static struct pnp_driver pnp_awe[AWE_NUM_CHIPS];
+static int awe_pnp_ok = 0;
+
+static void awe_pnp_config(struct pnp_device *d)
+{
+       struct pnp_resource *r;
+       int port[3];
+       int nio = 0;
+
+       port[0] = port[1] = port[2] = 0;
+       for (r = d->res; r != NULL; r = r->next) {
+               if (r->type == PNP_RES_IO) {
+                       if (nio >= 0 && nio < 3)
+                               port[nio] = r->start;
+                       nio++;
+               }
+       }
+       setup_ports(port[0], port[1], port[2]);
+       DEBUG(0,printk("AWE32: PnP setup ports: %x:%x:%x\n", port[0], port[1], port[2]));
+}
+
+static int awe_pnp_event (struct pnp_device *d, struct pnp_drv_event *e)
+{
+       struct pnp_driver *drv = d->l.k.driver;
+
+       switch (e->type) {
+       case PNP_DRV_ALLOC:
+               drv->flags |= PNP_DRV_INUSE;
+               awe_pnp_ok = 1;
+               awe_pnp_config(d);
+               _attach_awe();
+               break;
+
+       case PNP_DRV_DISABLE:
+       case PNP_DRV_EMERGSTOP:
+               drv->flags &= ~PNP_DRV_INUSE;
+               awe_pnp_ok = 0;
+               _unload_awe();
+               break;
+
+       case PNP_DRV_CONFIG:
+               if (awe_busy) return 1; /* used now */
+               awe_release_region();
+               awe_pnp_config(d);
+               awe_request_region();
+               break;
+               
+       case PNP_DRV_RECONFIG:
+               break;
+       }
+       return 0;
+}
+
+static int awe_initpnp (void)
+{
+       int i;
+       for (i = 0; i < AWE_NUM_CHIPS; i++) {
+               pnp_awe[i].id.type = PNP_HDL_ISA;
+               pnp_awe[i].id.t.isa.id = pnp_ids[i];
+               pnp_awe[i].id.next = NULL;
+               pnp_awe[i].name = "Soundblaster AWE32/AWE64 PnP";
+               pnp_awe[i].event = awe_pnp_event;
+               pnp_register_driver(&pnp_awe[i], 1);
+       }
+       return 0;
+}
+
+static void awe_unload_pnp (void)
+{
+       int i;
+       for (i = 0; i < AWE_NUM_CHIPS; i++)
+               pnp_unregister_driver(&pnp_awe[i]);
+}
+#endif /* PnP support */
+
+/*
+ * clear sample tables 
+ */
+
+static void
+awe_reset_samples(void)
+{
+       int i;
+
+       /* free all bank tables */
+       for (i = 0; i < AWE_MAX_PRESETS; i++)
+               preset_table[i] = -1;
+
+       free_tables();
+
+       current_sf_id = 0;
+       locked_sf_id = 0;
+       patch_opened = 0;
+}
+
+
+/*
+ * EMU register access
+ */
+
+/* select a given AWE32 pointer */
+static int awe_ports[5];
+static int port_setuped = FALSE;
+static int awe_cur_cmd = -1;
+#define awe_set_cmd(cmd) \
+if (awe_cur_cmd != cmd) { outw(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; }
+
+/* store values to i/o port array */
+static void setup_ports(int port1, int port2, int port3)
+{
+       awe_ports[0] = port1;
+       if (port2 == 0)
+               port2 = port1 + 0x400;
+       awe_ports[1] = port2;
+       awe_ports[2] = port2 + 2;
+       if (port3 == 0)
+               port3 = port1 + 0x800;
+       awe_ports[3] = port3;
+       awe_ports[4] = port3 + 2;
+
+       port_setuped = TRUE;
+}
+
+/* write 16bit data */
+static inline void
+awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
+{
+       awe_set_cmd(cmd);
+       outw(data, awe_ports[port]);
+}
+
+/* write 32bit data */
+static inline void
+awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
+{
+       unsigned short addr = awe_ports[port];
+       awe_set_cmd(cmd);
+       outw(data, addr);               /* write lower 16 bits */
+       outw(data >> 16, addr + 2);     /* write higher 16 bits */
+}
+
+/* read 16bit data */
+static inline unsigned short
+awe_peek(unsigned short cmd, unsigned short port)
+{
+       unsigned short k;
+       awe_set_cmd(cmd);
+       k = inw(awe_ports[port]);
+       return k;
+}
+
+/* read 32bit data */
+static inline unsigned int
+awe_peek_dw(unsigned short cmd, unsigned short port)
+{
+       unsigned int k1, k2;
+       unsigned short addr = awe_ports[port];
+       awe_set_cmd(cmd);
+       k1 = inw(addr);
+       k2 = inw(addr + 2);
+       k1 |= k2 << 16;
+       return k1;
+}
+
+/* wait delay number of AWE32 44100Hz clocks */
+#ifdef WAIT_BY_LOOP /* wait by loop -- that's not good.. */
+static void
+awe_wait(unsigned short delay)
+{
+       unsigned short clock, target;
+       unsigned short port = awe_ports[AWE_WC_Port];
+       int counter;
+  
+       /* sample counter */
+       awe_set_cmd(AWE_WC_Cmd);
+       clock = (unsigned short)inw(port);
+       target = clock + delay;
+       counter = 0;
+       if (target < clock) {
+               for (; (unsigned short)inw(port) > target; counter++)
+                       if (counter > 65536)
+                               break;
+       }
+       for (; (unsigned short)inw(port) < target; counter++)
+               if (counter > 65536)
+                       break;
+}
+#else
+
+static void awe_wait(unsigned short delay)
+{
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout((HZ*(unsigned long)delay + 44099)/44100);
+}
+#endif /* wait by loop */
+
+/* write a word data */
+static inline void
+awe_write_dram(unsigned short c)
+{
+       awe_poke(AWE_SMLD, c);
+}
+
+
+/*
+ * port check / request
+ *  0x620-623, 0xA20-A23, 0xE20-E23
+ */
+
+static int
+awe_check_port(void)
+{
+       if (! port_setuped) return 0;
+       return (check_region(awe_ports[0], 4) ||
+               check_region(awe_ports[1], 4) ||
+               check_region(awe_ports[3], 4));
+}
+
+static void
+awe_request_region(void)
+{
+       if (! port_setuped) return;
+       request_region(awe_ports[0], 4, "sound driver (AWE32)");
+       request_region(awe_ports[1], 4, "sound driver (AWE32)");
+       request_region(awe_ports[3], 4, "sound driver (AWE32)");
+}
+
+static void
+awe_release_region(void)
+{
+       if (! port_setuped) return;
+       release_region(awe_ports[0], 4);
+       release_region(awe_ports[1], 4);
+       release_region(awe_ports[3], 4);
+}
+
+/*
+ * AWE32 initialization
+ */
+static void
+awe_initialize(void)
+{
+       DEBUG(0,printk("AWE32: initializing..\n"));
+
+       /* initialize hardware configuration */
+       awe_poke(AWE_HWCF1, 0x0059);
+       awe_poke(AWE_HWCF2, 0x0020);
+
+       /* disable audio; this seems to reduce a clicking noise a bit.. */
+       awe_poke(AWE_HWCF3, 0);
+
+       /* initialize audio channels */
+       awe_init_audio();
+
+       /* initialize DMA */
+       awe_init_dma();
+
+       /* initialize init array */
+       awe_init_array();
+
+       /* check DRAM memory size */
+       awe_check_dram();
+
+       /* initialize the FM section of the AWE32 */
+       awe_init_fm();
+
+       /* set up voice envelopes */
+       awe_tweak();
+
+       /* enable audio */
+       awe_poke(AWE_HWCF3, 0x0004);
+
+       /* set default values */
+       awe_init_ctrl_parms(TRUE);
+
+       /* set equalizer */
+       awe_update_equalizer();
+
+       /* set reverb & chorus modes */
+       awe_update_reverb_mode();
+       awe_update_chorus_mode();
+}
+
+
+/*
+ * AWE32 voice parameters
+ */
+
+/* initialize voice_info record */
+static void
+awe_init_voice_info(awe_voice_info *vp)
+{
+       vp->sf_id = 0; /* normal mode */
+       vp->sample = 0;
+       vp->rate_offset = 0;
+
+       vp->start = 0;
+       vp->end = 0;
+       vp->loopstart = 0;
+       vp->loopend = 0;
+       vp->mode = 0;
+       vp->root = 60;
+       vp->tune = 0;
+       vp->low = 0;
+       vp->high = 127;
+       vp->vellow = 0;
+       vp->velhigh = 127;
+
+       vp->fixkey = -1;
+       vp->fixvel = -1;
+       vp->fixpan = -1;
+       vp->pan = -1;
+
+       vp->exclusiveClass = 0;
+       vp->amplitude = 127;
+       vp->attenuation = 0;
+       vp->scaleTuning = 100;
+
+       awe_init_voice_parm(&vp->parm);
+}
+
+/* initialize voice_parm record:
+ * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0.
+ * Vibrato and Tremolo effects are zero.
+ * Cutoff is maximum.
+ * Chorus and Reverb effects are zero.
+ */
+static void
+awe_init_voice_parm(awe_voice_parm *pp)
+{
+       pp->moddelay = 0x8000;
+       pp->modatkhld = 0x7f7f;
+       pp->moddcysus = 0x7f7f;
+       pp->modrelease = 0x807f;
+       pp->modkeyhold = 0;
+       pp->modkeydecay = 0;
+
+       pp->voldelay = 0x8000;
+       pp->volatkhld = 0x7f7f;
+       pp->voldcysus = 0x7f7f;
+       pp->volrelease = 0x807f;
+       pp->volkeyhold = 0;
+       pp->volkeydecay = 0;
+
+       pp->lfo1delay = 0x8000;
+       pp->lfo2delay = 0x8000;
+       pp->pefe = 0;
+
+       pp->fmmod = 0;
+       pp->tremfrq = 0;
+       pp->fm2frq2 = 0;
+
+       pp->cutoff = 0xff;
+       pp->filterQ = 0;
+
+       pp->chorus = 0;
+       pp->reverb = 0;
+}      
+
+
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+
+/* convert frequency mHz to abstract cents (= midi key * 100) */
+static int
+freq_to_note(int mHz)
+{
+       /* abscents = log(mHz/8176) / log(2) * 1200 */
+       unsigned int max_val = (unsigned int)0xffffffff / 10000;
+       int i, times;
+       unsigned int base;
+       unsigned int freq;
+       int note, tune;
+
+       if (mHz == 0)
+               return 0;
+       if (mHz < 0)
+               return 12799; /* maximum */
+
+       freq = mHz;
+       note = 0;
+       for (base = 8176 * 2; freq >= base; base *= 2) {
+               note += 12;
+               if (note >= 128) /* over maximum */
+                       return 12799;
+       }
+       base /= 2;
+
+       /* to avoid overflow... */
+       times = 10000;
+       while (freq > max_val) {
+               max_val *= 10;
+               times /= 10;
+               base /= 10;
+       }
+
+       freq = freq * times / base;
+       for (i = 0; i < 12; i++) {
+               if (freq < semitone_tuning[i+1])
+                       break;
+               note++;
+       }
+
+       tune = 0;
+       freq = freq * 10000 / semitone_tuning[i];
+       for (i = 0; i < 100; i++) {
+               if (freq < cent_tuning[i+1])
+                       break;
+               tune++;
+       }
+
+       return note * 100 + tune;
+}
+
+
+/* convert Hz to AWE32 rate offset:
+ * sample pitch offset for the specified sample rate
+ * rate=44100 is no offset, each 4096 is 1 octave (twice).
+ * eg, when rate is 22050, this offset becomes -4096.
+ */
+static int
+calc_rate_offset(int Hz)
+{
+       /* offset = log(Hz / 44100) / log(2) * 4096 */
+       int freq, base, i;
+
+       /* maybe smaller than max (44100Hz) */
+       if (Hz <= 0 || Hz >= 44100) return 0;
+
+       base = 0;
+       for (freq = Hz * 2; freq < 44100; freq *= 2)
+               base++;
+       base *= 1200;
+
+       freq = 44100 * 10000 / (freq/2);
+       for (i = 0; i < 12; i++) {
+               if (freq < semitone_tuning[i+1])
+                       break;
+               base += 100;
+       }
+       freq = freq * 10000 / semitone_tuning[i];
+       for (i = 0; i < 100; i++) {
+               if (freq < cent_tuning[i+1])
+                       break;
+               base++;
+       }
+       return -base * 4096 / 1200;
+}
+
+
+/*
+ * convert envelope time parameter to AWE32 raw parameter
+ */
+
+/* attack & decay/release time table (msec) */
+static short attack_time_tbl[128] = {
+32767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816,
+707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377,
+361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188,
+180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94,
+90, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47,
+45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23,
+22, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
+11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0,
+};
+
+static short decay_time_tbl[128] = {
+32767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082,
+2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507,
+1443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722,
+691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361,
+345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180,
+172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90,
+86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45,
+43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22,
+};
+
+#define calc_parm_delay(msec) (0x8000 - (msec) * 1000 / 725);
+
+/* delay time = 0x8000 - msec/92 */
+static int
+calc_parm_hold(int msec)
+{
+       int val = (0x7f * 92 - msec) / 92;
+       if (val < 1) val = 1;
+       if (val > 127) val = 127;
+       return val;
+}
+
+/* attack time: search from time table */
+static int
+calc_parm_attack(int msec)
+{
+       return calc_parm_search(msec, attack_time_tbl);
+}
+
+/* decay/release time: search from time table */
+static int
+calc_parm_decay(int msec)
+{
+       return calc_parm_search(msec, decay_time_tbl);
+}
+
+/* search an index for specified time from given time table */
+static int
+calc_parm_search(int msec, short *table)
+{
+       int left = 1, right = 127, mid;
+       while (left < right) {
+               mid = (left + right) / 2;
+               if (msec < (int)table[mid])
+                       left = mid + 1;
+               else
+                       right = mid;
+       }
+       return left;
+}
+#endif /* AWE_HAS_GUS_COMPATIBILITY */
+
+
+/*
+ * effects table
+ */
+
+/* set an effect value */
+#define FX_FLAG_OFF    0
+#define FX_FLAG_SET    1
+#define FX_FLAG_ADD    2
+
+#define FX_SET(rec,type,value) \
+       ((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value))
+#define FX_ADD(rec,type,value) \
+       ((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value))
+#define FX_UNSET(rec,type) \
+       ((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0)
+
+/* check the effect value is set */
+#define FX_ON(rec,type)        ((rec)->flags[type])
+
+#define PARM_BYTE      0
+#define PARM_WORD      1
+#define PARM_SIGN      2
+
+static struct PARM_DEFS {
+       int type;       /* byte or word */
+       int low, high;  /* value range */
+       fx_affect_func realtime;        /* realtime paramater change */
+} parm_defs[] = {
+       {PARM_WORD, 0, 0x8000, NULL},   /* env1 delay */
+       {PARM_BYTE, 1, 0x7f, NULL},     /* env1 attack */
+       {PARM_BYTE, 0, 0x7e, NULL},     /* env1 hold */
+       {PARM_BYTE, 1, 0x7f, NULL},     /* env1 decay */
+       {PARM_BYTE, 1, 0x7f, NULL},     /* env1 release */
+       {PARM_BYTE, 0, 0x7f, NULL},     /* env1 sustain */
+       {PARM_BYTE, 0, 0xff, NULL},     /* env1 pitch */
+       {PARM_BYTE, 0, 0xff, NULL},     /* env1 cutoff */
+
+       {PARM_WORD, 0, 0x8000, NULL},   /* env2 delay */
+       {PARM_BYTE, 1, 0x7f, NULL},     /* env2 attack */
+       {PARM_BYTE, 0, 0x7e, NULL},     /* env2 hold */
+       {PARM_BYTE, 1, 0x7f, NULL},     /* env2 decay */
+       {PARM_BYTE, 1, 0x7f, NULL},     /* env2 release */
+       {PARM_BYTE, 0, 0x7f, NULL},     /* env2 sustain */
+
+       {PARM_WORD, 0, 0x8000, NULL},   /* lfo1 delay */
+       {PARM_BYTE, 0, 0xff, awe_fx_tremfrq},   /* lfo1 freq */
+       {PARM_SIGN, -128, 127, awe_fx_tremfrq}, /* lfo1 volume */
+       {PARM_SIGN, -128, 127, awe_fx_fmmod},   /* lfo1 pitch */
+       {PARM_BYTE, 0, 0xff, awe_fx_fmmod},     /* lfo1 cutoff */
+
+       {PARM_WORD, 0, 0x8000, NULL},   /* lfo2 delay */
+       {PARM_BYTE, 0, 0xff, awe_fx_fm2frq2},   /* lfo2 freq */
+       {PARM_SIGN, -128, 127, awe_fx_fm2frq2}, /* lfo2 pitch */
+
+       {PARM_WORD, 0, 0xffff, awe_set_voice_pitch},    /* initial pitch */
+       {PARM_BYTE, 0, 0xff, NULL},     /* chorus */
+       {PARM_BYTE, 0, 0xff, NULL},     /* reverb */
+       {PARM_BYTE, 0, 0xff, awe_set_volume},   /* initial cutoff */
+       {PARM_BYTE, 0, 15, awe_fx_filterQ},     /* initial resonance */
+
+       {PARM_WORD, 0, 0xffff, NULL},   /* sample start */
+       {PARM_WORD, 0, 0xffff, NULL},   /* loop start */
+       {PARM_WORD, 0, 0xffff, NULL},   /* loop end */
+       {PARM_WORD, 0, 0xffff, NULL},   /* coarse sample start */
+       {PARM_WORD, 0, 0xffff, NULL},   /* coarse loop start */
+       {PARM_WORD, 0, 0xffff, NULL},   /* coarse loop end */
+       {PARM_BYTE, 0, 0xff, awe_set_volume},   /* initial attenuation */
+};
+
+
+static unsigned char
+FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value)
+{
+       int effect = 0;
+       int on = 0;
+       if (lay && (on = FX_ON(lay, type)) != 0)
+               effect = lay->val[type];
+       if (!on && (on = FX_ON(rec, type)) != 0)
+               effect = rec->val[type];
+       if (on == FX_FLAG_ADD) {
+               if (parm_defs[type].type == PARM_SIGN) {
+                       if (value > 0x7f)
+                               effect += (int)value - 0x100;
+                       else
+                               effect += (int)value;
+               } else {
+                       effect += (int)value;
+               }
+       }
+       if (on) {
+               if (effect < parm_defs[type].low)
+                       effect = parm_defs[type].low;
+               else if (effect > parm_defs[type].high)
+                       effect = parm_defs[type].high;
+               return (unsigned char)effect;
+       }
+       return value;
+}
+
+/* get word effect value */
+static unsigned short
+FX_WORD(FX_Rec *rec, FX_Rec *lay, int type, unsigned short value)
+{
+       int effect = 0;
+       int on = 0;
+       if (lay && (on = FX_ON(lay, type)) != 0)
+               effect = lay->val[type];
+       if (!on && (on = FX_ON(rec, type)) != 0)
+               effect = rec->val[type];
+       if (on == FX_FLAG_ADD)
+               effect += (int)value;
+       if (on) {
+               if (effect < parm_defs[type].low)
+                       effect = parm_defs[type].low;
+               else if (effect > parm_defs[type].high)
+                       effect = parm_defs[type].high;
+               return (unsigned short)effect;
+       }
+       return value;
+}
+
+/* get word (upper=type1/lower=type2) effect value */
+static unsigned short
+FX_COMB(FX_Rec *rec, FX_Rec *lay, int type1, int type2, unsigned short value)
+{
+       unsigned short tmp;
+       tmp = FX_BYTE(rec, lay, type1, (unsigned char)(value >> 8));
+       tmp <<= 8;
+       tmp |= FX_BYTE(rec, lay, type2, (unsigned char)(value & 0xff));
+       return tmp;
+}
+
+/* address offset */
+static int
+FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode)
+{
+       int addr = 0;
+       if (lay && FX_ON(lay, hi))
+               addr = (short)lay->val[hi];
+       else if (FX_ON(rec, hi))
+               addr = (short)rec->val[hi];
+       addr = addr << 15;
+       if (lay && FX_ON(lay, lo))
+               addr += (short)lay->val[lo];
+       else if (FX_ON(rec, lo))
+               addr += (short)rec->val[lo];
+       if (!(mode & AWE_SAMPLE_8BITS))
+               addr /= 2;
+       return addr;
+}
+
+
+/*
+ * turn on/off sample
+ */
+
+/* table for volume target calculation */
+static unsigned short voltarget[16] = { 
+   0xEAC0, 0XE0C8, 0XD740, 0XCE20, 0XC560, 0XBD08, 0XB500, 0XAD58,
+   0XA5F8, 0X9EF0, 0X9830, 0X91C0, 0X8B90, 0X85A8, 0X8000, 0X7A90
+};
+
+static void
+awe_note_on(int voice)
+{
+       unsigned int temp;
+       int addr;
+       int vtarget, ftarget, ptarget, pitch;
+       awe_voice_info *vp;
+       awe_voice_parm_block *parm;
+       FX_Rec *fx = &voices[voice].cinfo->fx;
+       FX_Rec *fx_lay = NULL;
+       if (voices[voice].layer < MAX_LAYERS)
+               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+
+       /* A voice sample must assigned before calling */
+       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+               return;
+
+       parm = (awe_voice_parm_block*)&vp->parm;
+
+       /* channel to be silent and idle */
+       awe_poke(AWE_DCYSUSV(voice), 0x0080);
+       awe_poke(AWE_VTFT(voice), 0x0000FFFF);
+       awe_poke(AWE_CVCF(voice), 0x0000FFFF);
+       awe_poke(AWE_PTRX(voice), 0);
+       awe_poke(AWE_CPF(voice), 0);
+
+       /* set pitch offset */
+       awe_set_pitch(voice, TRUE);
+
+       /* modulation & volume envelope */
+       if (parm->modatk >= 0x80 && parm->moddelay >= 0x8000) {
+               awe_poke(AWE_ENVVAL(voice), 0xBFFF);
+               pitch = (parm->env1pit<<4) + voices[voice].apitch;
+               if (pitch > 0xffff) pitch = 0xffff;
+               /* calculate filter target */
+               ftarget = parm->cutoff + parm->env1fc;
+               limitvalue(ftarget, 0, 255);
+               ftarget <<= 8;
+       } else {
+               awe_poke(AWE_ENVVAL(voice),
+                        FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, parm->moddelay));
+               ftarget = parm->cutoff;
+               ftarget <<= 8;
+               pitch = voices[voice].apitch;
+       }
+
+       /* calcualte pitch target */
+       if (pitch != 0xffff) {
+               ptarget = 1 << (pitch >> 12);
+               if (pitch & 0x800) ptarget += (ptarget*0x102e)/0x2710;
+               if (pitch & 0x400) ptarget += (ptarget*0x764)/0x2710;
+               if (pitch & 0x200) ptarget += (ptarget*0x389)/0x2710;
+               ptarget += (ptarget>>1);
+               if (ptarget > 0xffff) ptarget = 0xffff;
+
+       } else ptarget = 0xffff;
+       if (parm->modatk >= 0x80)
+               awe_poke(AWE_ATKHLD(voice),
+                        FX_BYTE(fx, fx_lay, AWE_FX_ENV1_HOLD, parm->modhld) << 8 | 0x7f);
+       else
+               awe_poke(AWE_ATKHLD(voice),
+                        FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK,
+                                vp->parm.modatkhld));
+       awe_poke(AWE_DCYSUS(voice),
+                FX_COMB(fx, fx_lay, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY,
+                         vp->parm.moddcysus));
+
+       if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) {
+               awe_poke(AWE_ENVVOL(voice), 0xBFFF);
+               vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4);
+       } else {
+               awe_poke(AWE_ENVVOL(voice),
+                        FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay));
+               vtarget = 0;
+       }
+       if (parm->volatk >= 0x80)
+               awe_poke(AWE_ATKHLDV(voice),
+                        FX_BYTE(fx, fx_lay, AWE_FX_ENV2_HOLD, parm->volhld) << 8 | 0x7f);
+       else
+               awe_poke(AWE_ATKHLDV(voice),
+                        FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK,
+                        vp->parm.volatkhld));
+       /* decay/sustain parameter for volume envelope must be set at last */
+
+       /* cutoff and volume */
+       awe_set_volume(voice, TRUE);
+
+       /* modulation envelope heights */
+       awe_poke(AWE_PEFE(voice),
+                FX_COMB(fx, fx_lay, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF,
+                        vp->parm.pefe));
+
+       /* lfo1/2 delay */
+       awe_poke(AWE_LFO1VAL(voice),
+                FX_WORD(fx, fx_lay, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay));
+       awe_poke(AWE_LFO2VAL(voice),
+                FX_WORD(fx, fx_lay, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay));
+
+       /* lfo1 pitch & cutoff shift */
+       awe_fx_fmmod(voice, TRUE);
+       /* lfo1 volume & freq */
+       awe_fx_tremfrq(voice, TRUE);
+       /* lfo2 pitch & freq */
+       awe_fx_fm2frq2(voice, TRUE);
+       /* pan & loop start */
+       awe_set_pan(voice, TRUE);
+
+       /* chorus & loop end (chorus 8bit, MSB) */
+       addr = vp->loopend - 1;
+       addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_END,
+                         AWE_FX_COARSE_LOOP_END, vp->mode);
+       temp = FX_BYTE(fx, fx_lay, AWE_FX_CHORUS, vp->parm.chorus);
+       temp = (temp <<24) | (unsigned int)addr;
+       awe_poke_dw(AWE_CSL(voice), temp);
+       DEBUG(4,printk("AWE32: [-- loopend=%x/%x]\n", vp->loopend, addr));
+
+       /* Q & current address (Q 4bit value, MSB) */
+       addr = vp->start - 1;
+       addr += FX_OFFSET(fx, fx_lay, AWE_FX_SAMPLE_START,
+                         AWE_FX_COARSE_SAMPLE_START, vp->mode);
+       temp = FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ);
+       temp = (temp<<28) | (unsigned int)addr;
+       awe_poke_dw(AWE_CCCA(voice), temp);
+       DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", vp->start, addr));
+
+       /* clear unknown registers */
+       awe_poke_dw(AWE_00A0(voice), 0);
+       awe_poke_dw(AWE_0080(voice), 0);
+
+       /* reset volume */
+       awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget);
+       awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget);
+
+       /* turn on envelope */
+       awe_poke(AWE_DCYSUSV(voice),
+                FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
+                         vp->parm.voldcysus));
+       /* set reverb */
+       temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb);
+       temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux;
+       awe_poke_dw(AWE_PTRX(voice), temp);
+       awe_poke_dw(AWE_CPF(voice), ptarget << 16);
+
+       voices[voice].state = AWE_ST_ON;
+
+       /* clear voice position for the next note on this channel */
+       if (SINGLE_LAYER_MODE()) {
+               FX_UNSET(fx, AWE_FX_SAMPLE_START);
+               FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START);
+       }
+}
+
+
+/* turn off the voice */
+static void
+awe_note_off(int voice)
+{
+       awe_voice_info *vp;
+       unsigned short tmp;
+       FX_Rec *fx = &voices[voice].cinfo->fx;
+       FX_Rec *fx_lay = NULL;
+       if (voices[voice].layer < MAX_LAYERS)
+               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+
+       if ((vp = voices[voice].sample) == NULL) {
+               voices[voice].state = AWE_ST_OFF;
+               return;
+       }
+
+       tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV1_RELEASE,
+                              (unsigned char)vp->parm.modrelease);
+       awe_poke(AWE_DCYSUS(voice), tmp);
+       tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE,
+                              (unsigned char)vp->parm.volrelease);
+       awe_poke(AWE_DCYSUSV(voice), tmp);
+       voices[voice].state = AWE_ST_RELEASED;
+}
+
+/* force to terminate the voice (no releasing echo) */
+static void
+awe_terminate(int voice)
+{
+       awe_poke(AWE_DCYSUSV(voice), 0x807F);
+       awe_tweak_voice(voice);
+       voices[voice].state = AWE_ST_OFF;
+}
+
+/* turn off other voices with the same exclusive class (for drums) */
+static void
+awe_exclusive_off(int voice)
+{
+       int i, exclass;
+
+       if (voices[voice].sample == NULL)
+               return;
+       if ((exclass = voices[voice].sample->exclusiveClass) == 0)
+               return; /* not exclusive */
+
+       /* turn off voices with the same class */
+       for (i = 0; i < awe_max_voices; i++) {
+               if (i != voice && IS_PLAYING(i) &&
+                   voices[i].sample && voices[i].ch == voices[voice].ch &&
+                   voices[i].sample->exclusiveClass == exclass) {
+                       DEBUG(4,printk("AWE32: [exoff(%d)]\n", i));
+                       awe_terminate(i);
+                       awe_voice_init(i, TRUE);
+               }
+       }
+}
+
+
+/*
+ * change the parameters of an audible voice
+ */
+
+/* change pitch */
+static void
+awe_set_pitch(int voice, int forced)
+{
+       if (IS_NO_EFFECT(voice) && !forced) return;
+       awe_poke(AWE_IP(voice), voices[voice].apitch);
+       DEBUG(3,printk("AWE32: [-- pitch=%x]\n", voices[voice].apitch));
+}
+
+/* calculate & change pitch */
+static void
+awe_set_voice_pitch(int voice, int forced)
+{
+       awe_calc_pitch(voice);
+       awe_set_pitch(voice, forced);
+}
+
+/* change volume & cutoff */
+static void
+awe_set_volume(int voice, int forced)
+{
+       awe_voice_info *vp;
+       unsigned short tmp2;
+       FX_Rec *fx = &voices[voice].cinfo->fx;
+       FX_Rec *fx_lay = NULL;
+       if (voices[voice].layer < MAX_LAYERS)
+               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+
+       if (!IS_PLAYING(voice) && !forced) return;
+       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+               return;
+
+       tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF,
+                      (unsigned char)voices[voice].acutoff);
+       tmp2 = (tmp2 << 8);
+       tmp2 |= FX_BYTE(fx, fx_lay, AWE_FX_ATTEN,
+                       (unsigned char)voices[voice].avol);
+       awe_poke(AWE_IFATN(voice), tmp2);
+}
+
+/* calculate & change volume */
+static void
+awe_set_voice_vol(int voice, int forced)
+{
+       if (IS_EMPTY(voice))
+               return;
+       awe_calc_volume(voice);
+       awe_set_volume(voice, forced);
+}
+
+
+/* change pan; this could make a click noise.. */
+static void
+awe_set_pan(int voice, int forced)
+{
+       unsigned int temp;
+       int addr;
+       awe_voice_info *vp;
+       FX_Rec *fx = &voices[voice].cinfo->fx;
+       FX_Rec *fx_lay = NULL;
+       if (voices[voice].layer < MAX_LAYERS)
+               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+
+       if (IS_NO_EFFECT(voice) && !forced) return;
+       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+               return;
+
+       /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
+       if (vp->fixpan > 0)     /* 0-127 */
+               temp = 255 - (int)vp->fixpan * 2;
+       else {
+               int pos = 0;
+               if (vp->pan >= 0) /* 0-127 */
+                       pos = (int)vp->pan * 2 - 128;
+               pos += voices[voice].cinfo->panning; /* -128 - 127 */
+               temp = 127 - pos;
+       }
+       limitvalue(temp, 0, 255);
+       if (ctrls[AWE_MD_PAN_EXCHANGE]) {
+               temp = 255 - temp;
+       }
+       if (forced || temp != voices[voice].apan) {
+               voices[voice].apan = temp;
+               addr = vp->loopstart - 1;
+               addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START,
+                                 AWE_FX_COARSE_LOOP_START, vp->mode);
+               temp = (temp<<24) | (unsigned int)addr;
+               awe_poke_dw(AWE_PSST(voice), temp);
+               DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr));
+               if (temp == 0) voices[voice].aaux = 0xff;
+               else voices[voice].aaux = (-temp)&0xff;
+       }
+}
+
+/* effects change during playing */
+static void
+awe_fx_fmmod(int voice, int forced)
+{
+       awe_voice_info *vp;
+       FX_Rec *fx = &voices[voice].cinfo->fx;
+       FX_Rec *fx_lay = NULL;
+       if (voices[voice].layer < MAX_LAYERS)
+               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+
+       if (IS_NO_EFFECT(voice) && !forced) return;
+       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+               return;
+       awe_poke(AWE_FMMOD(voice),
+                FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF,
+                        vp->parm.fmmod));
+}
+
+/* set tremolo (lfo1) volume & frequency */
+static void
+awe_fx_tremfrq(int voice, int forced)
+{
+       awe_voice_info *vp;
+       FX_Rec *fx = &voices[voice].cinfo->fx;
+       FX_Rec *fx_lay = NULL;
+       if (voices[voice].layer < MAX_LAYERS)
+               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+
+       if (IS_NO_EFFECT(voice) && !forced) return;
+       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+               return;
+       awe_poke(AWE_TREMFRQ(voice),
+                FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ,
+                        vp->parm.tremfrq));
+}
+
+/* set lfo2 pitch & frequency */
+static void
+awe_fx_fm2frq2(int voice, int forced)
+{
+       awe_voice_info *vp;
+       FX_Rec *fx = &voices[voice].cinfo->fx;
+       FX_Rec *fx_lay = NULL;
+       if (voices[voice].layer < MAX_LAYERS)
+               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+
+       if (IS_NO_EFFECT(voice) && !forced) return;
+       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+               return;
+       awe_poke(AWE_FM2FRQ2(voice),
+                FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ,
+                        vp->parm.fm2frq2));
+}
+
+
+/* Q & current address (Q 4bit value, MSB) */
+static void
+awe_fx_filterQ(int voice, int forced)
+{
+       unsigned int addr;
+       awe_voice_info *vp;
+       FX_Rec *fx = &voices[voice].cinfo->fx;
+       FX_Rec *fx_lay = NULL;
+       if (voices[voice].layer < MAX_LAYERS)
+               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+
+       if (IS_NO_EFFECT(voice) && !forced) return;
+       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+               return;
+
+       addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff;
+       addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28);
+       awe_poke_dw(AWE_CCCA(voice), addr);
+}
+
+/*================================================================
+ * calculate pitch offset
+ *----------------------------------------------------------------
+ * 0xE000 is no pitch offset at 44100Hz sample.
+ * Every 4096 is one octave.
+ *================================================================*/
+
+static void
+awe_calc_pitch(int voice)
+{
+       voice_info *vp = &voices[voice];
+       awe_voice_info *ap;
+       awe_chan_info *cp = voices[voice].cinfo;
+       int offset;
+
+       /* search voice information */
+       if ((ap = vp->sample) == NULL)
+                       return;
+       if (ap->index < 0) {
+               DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
+               if (awe_set_sample(ap) < 0)
+                       return;
+       }
+
+       /* calculate offset */
+       if (ap->fixkey >= 0) {
+               DEBUG(3,printk("AWE32: p-> fixkey(%d) tune(%d)\n", ap->fixkey, ap->tune));
+               offset = (ap->fixkey - ap->root) * 4096 / 12;
+       } else {
+               DEBUG(3,printk("AWE32: p(%d)-> root(%d) tune(%d)\n", vp->note, ap->root, ap->tune));
+               offset = (vp->note - ap->root) * 4096 / 12;
+               DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset));
+       }
+       offset = (offset * ap->scaleTuning) / 100;
+       DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset));
+       offset += ap->tune * 4096 / 1200;
+       DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset));
+       if (cp->bender != 0) {
+               DEBUG(3,printk("AWE32: p-> bend(%d) %d\n", voice, cp->bender));
+               /* (819200: 1 semitone) ==> (4096: 12 semitones) */
+               offset += cp->bender * cp->bender_range / 2400;
+       }
+
+       /* add initial pitch correction */
+       if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH))
+               offset += cp->fx_layer[vp->layer].val[AWE_FX_INIT_PITCH];
+       else if (FX_ON(&cp->fx, AWE_FX_INIT_PITCH))
+               offset += cp->fx.val[AWE_FX_INIT_PITCH];
+
+       /* 0xe000: root pitch */
+       vp->apitch = 0xe000 + ap->rate_offset + offset;
+       DEBUG(4,printk("AWE32: p-> sum aofs=%x, rate_ofs=%d\n", vp->apitch, ap->rate_offset));
+       if (vp->apitch > 0xffff)
+               vp->apitch = 0xffff;
+       if (vp->apitch < 0)
+               vp->apitch = 0;
+}
+
+
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+/* calculate MIDI key and semitone from the specified frequency */
+static void
+awe_calc_pitch_from_freq(int voice, int freq)
+{
+       voice_info *vp = &voices[voice];
+       awe_voice_info *ap;
+       FX_Rec *fx = &voices[voice].cinfo->fx;
+       FX_Rec *fx_lay = NULL;
+       int offset;
+       int note;
+
+       if (voices[voice].layer < MAX_LAYERS)
+               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
+
+       /* search voice information */
+       if ((ap = vp->sample) == NULL)
+               return;
+       if (ap->index < 0) {
+               DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
+               if (awe_set_sample(ap) < 0)
+                       return;
+       }
+       note = freq_to_note(freq);
+       offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200;
+       offset = (offset * ap->scaleTuning) / 100;
+       if (fx_lay && FX_ON(fx_lay, AWE_FX_INIT_PITCH))
+               offset += fx_lay->val[AWE_FX_INIT_PITCH];
+       else if (FX_ON(fx, AWE_FX_INIT_PITCH))
+               offset += fx->val[AWE_FX_INIT_PITCH];
+       vp->apitch = 0xe000 + ap->rate_offset + offset;
+       if (vp->apitch > 0xffff)
+               vp->apitch = 0xffff;
+       if (vp->apitch < 0)
+               vp->apitch = 0;
+}
+#endif /* AWE_HAS_GUS_COMPATIBILITY */
+
+
+/*================================================================
+ * calculate volume attenuation
+ *----------------------------------------------------------------
+ * Voice volume is controlled by volume attenuation parameter.
+ * So volume becomes maximum when avol is 0 (no attenuation), and
+ * minimum when 255 (-96dB or silence).
+ *================================================================*/
+
+static int vol_table[128] = {
+       255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,
+       47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32,
+       31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22,
+       22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16,
+       15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,
+       10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6,
+       6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3,
+       2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,
+};
+
+/* tables for volume->attenuation calculation */
+static unsigned char voltab1[128] = {
+   0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+   0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22,
+   0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
+   0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14,
+   0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10,
+   0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d,
+   0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b,
+   0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+   0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
+   0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04,
+   0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
+   0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
+   0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned char voltab2[128] = {
+   0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a,
+   0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21,
+   0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a,
+   0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15,
+   0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10,
+   0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d,
+   0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a,
+   0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08,
+   0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
+   0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+   0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
+   0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
+   0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned char expressiontab[128] = {
+   0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42,
+   0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30,
+   0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25,
+   0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e,
+   0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18,
+   0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13,
+   0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f,
+   0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c,
+   0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09,
+   0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
+   0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
+   0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
+   0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static void
+awe_calc_volume(int voice)
+{
+       voice_info *vp = &voices[voice];
+       awe_voice_info *ap;
+       awe_chan_info *cp = voices[voice].cinfo;
+       int vol;
+
+       /* search voice information */
+       if ((ap = vp->sample) == NULL)
+               return;
+
+       ap = vp->sample;
+       if (ap->index < 0) {
+               DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
+               if (awe_set_sample(ap) < 0)
+                       return;
+       }
+       
+       if (ctrls[AWE_MD_NEW_VOLUME_CALC]) {
+               int main_vol = cp->main_vol * ap->amplitude / 127;
+               limitvalue(vp->velocity, 0, 127);
+               limitvalue(main_vol, 0, 127);
+               limitvalue(cp->expression_vol, 0, 127);
+
+               vol = voltab1[main_vol] + voltab2[vp->velocity];
+               vol = (vol * 8) / 3;
+               vol += ap->attenuation;
+               if (cp->expression_vol < 127)
+                       vol += ((0x100 - vol) * expressiontab[cp->expression_vol])/128;
+               vol += atten_offset;
+               if (atten_relative)
+                       vol += ctrls[AWE_MD_ZERO_ATTEN];
+               limitvalue(vol, 0, 255);
+               vp->avol = vol;
+               
+       } else {
+               /* 0 - 127 */
+               vol = (vp->velocity * cp->main_vol * cp->expression_vol) / (127*127);
+               vol = vol * ap->amplitude / 127;
+
+               if (vol < 0) vol = 0;
+               if (vol > 127) vol = 127;
+
+               /* calc to attenuation */
+               vol = vol_table[vol];
+               vol += (int)ap->attenuation;
+               vol += atten_offset;
+               if (atten_relative)
+                       vol += ctrls[AWE_MD_ZERO_ATTEN];
+               if (vol > 255) vol = 255;
+
+               vp->avol = vol;
+       }
+       if (cp->bank !=  AWE_DRUM_BANK && ((awe_voice_parm_block*)(&ap->parm))->volatk < 0x7d) {
+               int atten;
+               if (vp->velocity < 70) atten = 70;
+               else atten = vp->velocity;
+               vp->acutoff = (atten * ap->parm.cutoff + 0xa0) >> 7;
+       } else {
+               vp->acutoff = ap->parm.cutoff;
+       }
+       DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol));
+}
+
+/* change master volume */
+static void
+awe_change_master_volume(short val)
+{
+       limitvalue(val, 0, 127);
+       atten_offset = vol_table[val];
+       atten_relative = TRUE;
+       awe_update_volume();
+}
+
+/* update volumes of all available channels */
+static void awe_update_volume(void)
+{
+       int i;
+       for (i = 0; i < awe_max_voices; i++)
+               awe_set_voice_vol(i, TRUE);
+}
+
+/* set sostenuto on */
+static void awe_sostenuto_on(int voice, int forced)
+{
+       if (IS_NO_EFFECT(voice) && !forced) return;
+       voices[voice].sostenuto = 127;
+}
+
+
+/* drop sustain */
+static void awe_sustain_off(int voice, int forced)
+{
+       if (voices[voice].state == AWE_ST_SUSTAINED) {
+               awe_note_off(voice);
+               awe_fx_init(voices[voice].ch);
+               awe_voice_init(voice, FALSE);
+       }
+}
+
+
+/* terminate and initialize voice */
+static void awe_terminate_and_init(int voice, int forced)
+{
+       awe_terminate(voice);
+       awe_fx_init(voices[voice].ch);
+       awe_voice_init(voice, TRUE);
+}
+
+
+/*
+ * synth operation routines
+ */
+
+#define AWE_VOICE_KEY(v)       (0x8000 | (v))
+#define AWE_CHAN_KEY(c,n)      (((c) << 8) | ((n) + 1))
+#define KEY_CHAN_MATCH(key,c)  (((key) >> 8) == (c))
+
+/* initialize the voice */
+static void
+awe_voice_init(int voice, int init_all)
+{
+       voice_info *vp = &voices[voice];
+
+       /* reset voice search key */
+       if (playing_mode == AWE_PLAY_DIRECT)
+               vp->key = AWE_VOICE_KEY(voice);
+       else
+               vp->key = 0;
+
+       /* clear voice mapping */
+       voice_alloc->map[voice] = 0;
+
+       /* touch the timing flag */
+       vp->time = current_alloc_time;
+
+       /* initialize other parameters if necessary */
+       if (init_all) {
+               vp->note = -1;
+               vp->velocity = 0;
+               vp->sostenuto = 0;
+
+               vp->sample = NULL;
+               vp->cinfo = &channels[voice];
+               vp->ch = voice;
+               vp->state = AWE_ST_OFF;
+
+               /* emu8000 parameters */
+               vp->apitch = 0;
+               vp->avol = 255;
+               vp->apan = -1;
+       }
+}
+
+/* clear effects */
+static void awe_fx_init(int ch)
+{
+       if (SINGLE_LAYER_MODE() && !ctrls[AWE_MD_KEEP_EFFECT]) {
+               memset(&channels[ch].fx, 0, sizeof(channels[ch].fx));
+               memset(&channels[ch].fx_layer, 0, sizeof(&channels[ch].fx_layer));
+       }
+}
+
+/* initialize channel info */
+static void awe_channel_init(int ch, int init_all)
+{
+       awe_chan_info *cp = &channels[ch];
+       cp->channel = ch;
+       if (init_all) {
+               cp->panning = 0; /* zero center */
+               cp->bender_range = 200; /* sense * 100 */
+               cp->main_vol = 127;
+               if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) {
+                       cp->instr = ctrls[AWE_MD_DEF_DRUM];
+                       cp->bank = AWE_DRUM_BANK;
+               } else {
+                       cp->instr = ctrls[AWE_MD_DEF_PRESET];
+                       cp->bank = ctrls[AWE_MD_DEF_BANK];
+               }
+               cp->vrec = -1;
+               cp->def_vrec = -1;
+       }
+
+       cp->bender = 0; /* zero tune skew */
+       cp->expression_vol = 127;
+       cp->chan_press = 0;
+       cp->sustained = 0;
+
+       if (! ctrls[AWE_MD_KEEP_EFFECT]) {
+               memset(&cp->fx, 0, sizeof(cp->fx));
+               memset(&cp->fx_layer, 0, sizeof(cp->fx_layer));
+       }
+}
+
+
+/* change the voice parameters; voice = channel */
+static void awe_voice_change(int voice, fx_affect_func func)
+{
+       int i; 
+       switch (playing_mode) {
+       case AWE_PLAY_DIRECT:
+               func(voice, FALSE);
+               break;
+       case AWE_PLAY_INDIRECT:
+               for (i = 0; i < awe_max_voices; i++)
+                       if (voices[i].key == AWE_VOICE_KEY(voice))
+                               func(i, FALSE);
+               break;
+       default:
+               for (i = 0; i < awe_max_voices; i++)
+                       if (KEY_CHAN_MATCH(voices[i].key, voice))
+                               func(i, FALSE);
+               break;
+       }
+}
+
+
+/*----------------------------------------------------------------
+ * device open / close
+ *----------------------------------------------------------------*/
+
+/* open device:
+ *   reset status of all voices, and clear sample position flag
+ */
+static int
+awe_open(int dev, int mode)
+{
+       if (awe_busy)
+               return -EBUSY;
+
+       awe_busy = TRUE;
+
+       /* set default mode */
+       awe_init_ctrl_parms(FALSE);
+       atten_relative = TRUE;
+       atten_offset = 0;
+       drum_flags = DEFAULT_DRUM_FLAGS;
+       playing_mode = AWE_PLAY_INDIRECT;
+
+       /* reset voices & channels */
+       awe_reset(dev);
+
+       patch_opened = 0;
+
+       return 0;
+}
+
+
+/* close device:
+ *   reset all voices again (terminate sounds)
+ */
+static void
+awe_close(int dev)
+{
+       awe_reset(dev);
+       awe_busy = FALSE;
+}
+
+
+/* set miscellaneous mode parameters
+ */
+static void
+awe_init_ctrl_parms(int init_all)
+{
+       int i;
+       for (i = 0; i < AWE_MD_END; i++) {
+               if (init_all || ctrl_parms[i].init_each_time)
+                       ctrls[i] = ctrl_parms[i].value;
+       }
+}
+
+
+/* sequencer I/O control:
+ */
+static int
+awe_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+       switch (cmd) {
+       case SNDCTL_SYNTH_INFO:
+               if (playing_mode == AWE_PLAY_DIRECT)
+                       awe_info.nr_voices = awe_max_voices;
+               else
+                       awe_info.nr_voices = AWE_MAX_CHANNELS;
+               memcpy((char*)arg, &awe_info + 0, sizeof(awe_info));
+               return 0;
+               break;
+
+       case SNDCTL_SEQ_RESETSAMPLES:
+               awe_reset_samples();
+               awe_reset(dev);
+               return 0;
+               break;
+
+       case SNDCTL_SEQ_PERCMODE:
+               /* what's this? */
+               return 0;
+               break;
+
+       case SNDCTL_SYNTH_MEMAVL:
+               return awe_mem_size - awe_free_mem_ptr() * 2;
+
+       default:
+               printk("AWE32: unsupported ioctl %d\n", cmd);
+               return -EINVAL;
+       }
+}
+
+
+static int voice_in_range(int voice)
+{
+       if (playing_mode == AWE_PLAY_DIRECT) {
+               if (voice < 0 || voice >= awe_max_voices)
+                       return FALSE;
+       } else {
+               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+static void release_voice(int voice, int do_sustain)
+{
+       if (IS_NO_SOUND(voice))
+               return;
+       if (do_sustain && (voices[voice].cinfo->sustained == 127 ||
+                           voices[voice].sostenuto == 127))
+               voices[voice].state = AWE_ST_SUSTAINED;
+       else {
+               awe_note_off(voice);
+               awe_fx_init(voices[voice].ch);
+               awe_voice_init(voice, FALSE);
+       }
+}
+
+/* release all notes */
+static void awe_note_off_all(int do_sustain)
+{
+       int i;
+       for (i = 0; i < awe_max_voices; i++)
+               release_voice(i, do_sustain);
+}
+
+/* kill a voice:
+ *   not terminate, just release the voice.
+ */
+static int
+awe_kill_note(int dev, int voice, int note, int velocity)
+{
+       int i, v2, key;
+
+       DEBUG(2,printk("AWE32: [off(%d) nt=%d vl=%d]\n", voice, note, velocity));
+       if (! voice_in_range(voice))
+               return -EINVAL;
+
+       switch (playing_mode) {
+       case AWE_PLAY_DIRECT:
+       case AWE_PLAY_INDIRECT:
+               key = AWE_VOICE_KEY(voice);
+               break;
+
+       case AWE_PLAY_MULTI2:
+               v2 = voice_alloc->map[voice] >> 8;
+               voice_alloc->map[voice] = 0;
+               voice = v2;
+               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+                       return -EINVAL;
+               /* continue to below */
+       default:
+               key = AWE_CHAN_KEY(voice, note);
+               break;
+       }
+
+       for (i = 0; i < awe_max_voices; i++) {
+               if (voices[i].key == key)
+                       release_voice(i, TRUE);
+       }
+       return 0;
+}
+
+
+static void start_or_volume_change(int voice, int velocity)
+{
+       voices[voice].velocity = velocity;
+       awe_calc_volume(voice);
+       if (voices[voice].state == AWE_ST_STANDBY)
+               awe_note_on(voice);
+       else if (voices[voice].state == AWE_ST_ON)
+               awe_set_volume(voice, FALSE);
+}
+
+static void set_and_start_voice(int voice, int state)
+{
+       /* calculate pitch & volume parameters */
+       voices[voice].state = state;
+       awe_calc_pitch(voice);
+       awe_calc_volume(voice);
+       if (state == AWE_ST_ON)
+               awe_note_on(voice);
+}
+
+/* start a voice:
+ *   if note is 255, identical with aftertouch function.
+ *   Otherwise, start a voice with specified not and volume.
+ */
+static int
+awe_start_note(int dev, int voice, int note, int velocity)
+{
+       int i, key, state, volonly;
+
+       DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", voice, note, velocity));
+       if (! voice_in_range(voice))
+               return -EINVAL;
+           
+       if (velocity == 0)
+               state = AWE_ST_STANDBY; /* stand by for playing */
+       else
+               state = AWE_ST_ON;      /* really play */
+       volonly = FALSE;
+
+       switch (playing_mode) {
+       case AWE_PLAY_DIRECT:
+       case AWE_PLAY_INDIRECT:
+               key = AWE_VOICE_KEY(voice);
+               if (note == 255)
+                       volonly = TRUE;
+               break;
+
+       case AWE_PLAY_MULTI2:
+               voice = voice_alloc->map[voice] >> 8;
+               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+                       return -EINVAL;
+               /* continue to below */
+       default:
+               if (note >= 128) { /* key volume mode */
+                       note -= 128;
+                       volonly = TRUE;
+               }
+               key = AWE_CHAN_KEY(voice, note);
+               break;
+       }
+
+       /* dynamic volume change */
+       if (volonly) {
+               for (i = 0; i < awe_max_voices; i++) {
+                       if (voices[i].key == key)
+                               start_or_volume_change(i, velocity);
+               }
+               return 0;
+       }
+
+       /* if the same note still playing, stop it */
+       if (playing_mode != AWE_PLAY_DIRECT || ctrls[AWE_MD_EXCLUSIVE_SOUND]) {
+               for (i = 0; i < awe_max_voices; i++)
+                       if (voices[i].key == key) {
+                               if (voices[i].state == AWE_ST_ON) {
+                                       awe_note_off(i);
+                                       awe_voice_init(i, FALSE);
+                               } else if (voices[i].state == AWE_ST_STANDBY)
+                                       awe_voice_init(i, TRUE);
+                       }
+       }
+
+       /* allocate voices */
+       if (playing_mode == AWE_PLAY_DIRECT)
+               awe_alloc_one_voice(voice, note, velocity);
+       else
+               awe_alloc_multi_voices(voice, note, velocity, key);
+
+       /* turn off other voices exlusively (for drums) */
+       for (i = 0; i < awe_max_voices; i++)
+               if (voices[i].key == key)
+                       awe_exclusive_off(i);
+
+       /* set up pitch and volume parameters */
+       for (i = 0; i < awe_max_voices; i++) {
+               if (voices[i].key == key && voices[i].state == AWE_ST_OFF)
+                       set_and_start_voice(i, state);
+       }
+
+       return 0;
+}
+
+
+/* search instrument from preset table with the specified bank */
+static int
+awe_search_instr(int bank, int preset)
+{
+       int i;
+
+       limitvalue(preset, 0, AWE_MAX_PRESETS-1);
+       for (i = preset_table[preset]; i >= 0; i = infos[i].next_bank) {
+               if (infos[i].bank == bank)
+                       return i;
+       }
+       return -1;
+}
+
+
+/* assign the instrument to a voice */
+static int
+awe_set_instr_2(int dev, int voice, int instr_no)
+{
+       if (playing_mode == AWE_PLAY_MULTI2) {
+               voice = voice_alloc->map[voice] >> 8;
+               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+                       return -EINVAL;
+       }
+       return awe_set_instr(dev, voice, instr_no);
+}
+
+/* assign the instrument to a channel; voice is the channel number */
+static int
+awe_set_instr(int dev, int voice, int instr_no)
+{
+       awe_chan_info *cinfo;
+       int def_bank;
+
+       if (! voice_in_range(voice))
+               return -EINVAL;
+
+       if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS)
+               return -EINVAL;
+
+       cinfo = &channels[voice];
+
+       if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
+               def_bank = AWE_DRUM_BANK; /* always search drumset */
+       else
+               def_bank = cinfo->bank;
+
+       cinfo->vrec = -1;
+       cinfo->def_vrec = -1;
+       cinfo->vrec = awe_search_instr(def_bank, instr_no);
+       if (def_bank == AWE_DRUM_BANK)  /* search default drumset */
+               cinfo->def_vrec = awe_search_instr(def_bank, ctrls[AWE_MD_DEF_DRUM]);
+       else    /* search default preset */
+               cinfo->def_vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr_no);
+
+       if (cinfo->vrec < 0 && cinfo->def_vrec < 0) {
+               DEBUG(1,printk("AWE32 Warning: can't find instrument %d\n", instr_no));
+       }
+
+       cinfo->instr = instr_no;
+       DEBUG(2,printk("AWE32: [program(%d) %d/%d]\n", voice, instr_no, def_bank));
+
+       return 0;
+}
+
+
+/* reset all voices; terminate sounds and initialize parameters */
+static void
+awe_reset(int dev)
+{
+       int i;
+       current_alloc_time = 0;
+       /* don't turn off voice 31 and 32.  they are used also for FM voices */
+       for (i = 0; i < awe_max_voices; i++) {
+               awe_terminate(i);
+               awe_voice_init(i, TRUE);
+       }
+       for (i = 0; i < AWE_MAX_CHANNELS; i++)
+               awe_channel_init(i, TRUE);
+       for (i = 0; i < 16; i++) {
+               awe_operations.chn_info[i].controllers[CTL_MAIN_VOLUME] = 127;
+               awe_operations.chn_info[i].controllers[CTL_EXPRESSION] = 127;
+       }
+       awe_init_fm();
+       awe_tweak();
+}
+
+
+/* hardware specific control:
+ *   GUS specific and AWE32 specific controls are available.
+ */
+static void
+awe_hw_control(int dev, unsigned char *event)
+{
+       int cmd = event[2];
+       if (cmd & _AWE_MODE_FLAG)
+               awe_hw_awe_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+       else
+               awe_hw_gus_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
+#endif
+}
+
+
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+
+/* GUS compatible controls */
+static void
+awe_hw_gus_control(int dev, int cmd, unsigned char *event)
+{
+       int voice, i, key;
+       unsigned short p1;
+       short p2;
+       int plong;
+
+       if (MULTI_LAYER_MODE())
+               return;
+       if (cmd == _GUS_NUMVOICES)
+               return;
+
+       voice = event[3];
+       if (! voice_in_range(voice))
+               return;
+
+       p1 = *(unsigned short *) &event[4];
+       p2 = *(short *) &event[6];
+       plong = *(int*) &event[4];
+
+       switch (cmd) {
+       case _GUS_VOICESAMPLE:
+               awe_set_instr(dev, voice, p1);
+               return;
+
+       case _GUS_VOICEBALA:
+               /* 0 to 15 --> -128 to 127 */
+               awe_panning(dev, voice, ((int)p1 << 4) - 128);
+               return;
+
+       case _GUS_VOICEVOL:
+       case _GUS_VOICEVOL2:
+               /* not supported yet */
+               return;
+
+       case _GUS_RAMPRANGE:
+       case _GUS_RAMPRATE:
+       case _GUS_RAMPMODE:
+       case _GUS_RAMPON:
+       case _GUS_RAMPOFF:
+               /* volume ramping not supported */
+               return;
+
+       case _GUS_VOLUME_SCALE:
+               return;
+
+       case _GUS_VOICE_POS:
+               FX_SET(&channels[voice].fx, AWE_FX_SAMPLE_START,
+                      (short)(plong & 0x7fff));
+               FX_SET(&channels[voice].fx, AWE_FX_COARSE_SAMPLE_START,
+                      (plong >> 15) & 0xffff);
+               return;
+       }
+
+       key = AWE_VOICE_KEY(voice);
+       for (i = 0; i < awe_max_voices; i++) {
+               if (voices[i].key == key) {
+                       switch (cmd) {
+                       case _GUS_VOICEON:
+                               awe_note_on(i);
+                               break;
+
+                       case _GUS_VOICEOFF:
+                               awe_terminate(i);
+                               awe_fx_init(voices[i].ch);
+                               awe_voice_init(i, TRUE);
+                               break;
+
+                       case _GUS_VOICEFADE:
+                               awe_note_off(i);
+                               awe_fx_init(voices[i].ch);
+                               awe_voice_init(i, FALSE);
+                               break;
+
+                       case _GUS_VOICEFREQ:
+                               awe_calc_pitch_from_freq(i, plong);
+                               break;
+                       }
+               }
+       }
+}
+
+#endif /* gus_compat */
+
+
+/* AWE32 specific controls */
+static void
+awe_hw_awe_control(int dev, int cmd, unsigned char *event)
+{
+       int voice;
+       unsigned short p1;
+       short p2;
+       int i;
+
+       voice = event[3];
+       if (! voice_in_range(voice))
+               return;
+
+       if (playing_mode == AWE_PLAY_MULTI2) {
+               voice = voice_alloc->map[voice] >> 8;
+               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+                       return;
+       }
+
+       p1 = *(unsigned short *) &event[4];
+       p2 = *(short *) &event[6];
+
+       switch (cmd) {
+       case _AWE_DEBUG_MODE:
+               ctrls[AWE_MD_DEBUG_MODE] = p1;
+               printk("AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]);
+               break;
+       case _AWE_REVERB_MODE:
+               ctrls[AWE_MD_REVERB_MODE] = p1;
+               awe_update_reverb_mode();
+               break;
+
+       case _AWE_CHORUS_MODE:
+               ctrls[AWE_MD_CHORUS_MODE] = p1;
+               awe_update_chorus_mode();
+               break;
+                     
+       case _AWE_REMOVE_LAST_SAMPLES:
+               DEBUG(0,printk("AWE32: remove last samples\n"));
+               if (locked_sf_id > 0)
+                       awe_remove_samples(locked_sf_id);
+               break;
+
+       case _AWE_INITIALIZE_CHIP:
+               awe_initialize();
+               break;
+
+       case _AWE_SEND_EFFECT:
+               i = -1;
+               if (p1 >= 0x100) {
+                       i = (p1 >> 8);
+                       if (i < 0 || i >= MAX_LAYERS)
+                               break;
+               }
+               awe_send_effect(voice, i, p1, p2);
+               break;
+
+       case _AWE_RESET_CHANNEL:
+               awe_channel_init(voice, !p1);
+               break;
+               
+       case _AWE_TERMINATE_ALL:
+               awe_reset(0);
+               break;
+
+       case _AWE_TERMINATE_CHANNEL:
+               awe_voice_change(voice, awe_terminate_and_init);
+               break;
+
+       case _AWE_RELEASE_ALL:
+               awe_note_off_all(FALSE);
+               break;
+       case _AWE_NOTEOFF_ALL:
+               awe_note_off_all(TRUE);
+               break;
+
+       case _AWE_INITIAL_VOLUME:
+               DEBUG(0,printk("AWE32: init attenuation %d\n", p1));
+               atten_relative = (char)p2;
+               atten_offset = (short)p1;
+               awe_update_volume();
+               break;
+
+       case _AWE_CHN_PRESSURE:
+               channels[voice].chan_press = p1;
+               awe_modwheel_change(voice, p1);
+               break;
+
+       case _AWE_CHANNEL_MODE:
+               DEBUG(0,printk("AWE32: channel mode = %d\n", p1));
+               playing_mode = p1;
+               awe_reset(0);
+               break;
+
+       case _AWE_DRUM_CHANNELS:
+               DEBUG(0,printk("AWE32: drum flags = %x\n", p1));
+               drum_flags = *(unsigned int*)&event[4];
+               break;
+
+       case _AWE_MISC_MODE:
+               DEBUG(0,printk("AWE32: ctrl parms = %d %d\n", p1, p2));
+               if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) {
+                       ctrls[p1] = p2;
+                       if (ctrl_parms[p1].update)
+                               ctrl_parms[p1].update();
+               }
+               break;
+
+       case _AWE_EQUALIZER:
+               ctrls[AWE_MD_BASS_LEVEL] = p1;
+               ctrls[AWE_MD_TREBLE_LEVEL] = p2;
+               awe_update_equalizer();
+               break;
+
+       default:
+               DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice));
+               break;
+       }
+}
+
+
+/* change effects */
+static void
+awe_send_effect(int voice, int layer, int type, int val)
+{
+       awe_chan_info *cinfo;
+       FX_Rec *fx;
+       int mode;
+
+       cinfo = &channels[voice];
+       if (layer >= 0 && layer < MAX_LAYERS)
+               fx = &cinfo->fx_layer[layer];
+       else
+               fx = &cinfo->fx;
+
+       if (type & 0x40)
+               mode = FX_FLAG_OFF;
+       else if (type & 0x80)
+               mode = FX_FLAG_ADD;
+       else
+               mode = FX_FLAG_SET;
+       type &= 0x3f;
+
+       if (type >= 0 && type < AWE_FX_END) {
+               DEBUG(2,printk("AWE32: effects (%d) %d %d\n", voice, type, val));
+               if (mode == FX_FLAG_SET)
+                       FX_SET(fx, type, val);
+               else if (mode == FX_FLAG_ADD)
+                       FX_ADD(fx, type, val);
+               else
+                       FX_UNSET(fx, type);
+               if (mode != FX_FLAG_OFF && parm_defs[type].realtime) {
+                       DEBUG(2,printk("AWE32: fx_realtime (%d)\n", voice));
+                       awe_voice_change(voice, parm_defs[type].realtime);
+               }
+       }
+}
+
+
+/* change modulation wheel; voice is already mapped on multi2 mode */
+static void
+awe_modwheel_change(int voice, int value)
+{
+       int i;
+       awe_chan_info *cinfo;
+
+       cinfo = &channels[voice];
+       i = value * ctrls[AWE_MD_MOD_SENSE] / 1200;
+       FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i);
+       awe_voice_change(voice, awe_fx_fmmod);
+       FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i);
+       awe_voice_change(voice, awe_fx_fm2frq2);
+}
+
+
+/* voice pressure change */
+static void
+awe_aftertouch(int dev, int voice, int pressure)
+{
+       int note;
+
+       DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure));
+       if (! voice_in_range(voice))
+               return;
+
+       switch (playing_mode) {
+       case AWE_PLAY_DIRECT:
+       case AWE_PLAY_INDIRECT:
+               awe_start_note(dev, voice, 255, pressure);
+               break;
+       case AWE_PLAY_MULTI2:
+               note = (voice_alloc->map[voice] & 0xff) - 1;
+               awe_key_pressure(dev, voice, note + 0x80, pressure);
+               break;
+       }
+}
+
+
+/* voice control change */
+static void
+awe_controller(int dev, int voice, int ctrl_num, int value)
+{
+       awe_chan_info *cinfo;
+
+       if (! voice_in_range(voice))
+               return;
+
+       if (playing_mode == AWE_PLAY_MULTI2) {
+               voice = voice_alloc->map[voice] >> 8;
+               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+                       return;
+       }
+
+       cinfo = &channels[voice];
+
+       switch (ctrl_num) {
+       case CTL_BANK_SELECT: /* MIDI control #0 */
+               DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value));
+               if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) &&
+                   !ctrls[AWE_MD_TOGGLE_DRUM_BANK])
+                       break;
+               cinfo->bank = value;
+               if (cinfo->bank == AWE_DRUM_BANK)
+                       DRUM_CHANNEL_ON(cinfo->channel);
+               else
+                       DRUM_CHANNEL_OFF(cinfo->channel);
+               awe_set_instr(dev, voice, cinfo->instr);
+               break;
+
+       case CTL_MODWHEEL: /* MIDI control #1 */
+               DEBUG(2,printk("AWE32: [modwheel(%d) %d]\n", voice, value));
+               awe_modwheel_change(voice, value);
+               break;
+
+       case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */
+               DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value));
+               /* zero centered */
+               cinfo->bender = value;
+               awe_voice_change(voice, awe_set_voice_pitch);
+               break;
+
+       case CTRL_PITCH_BENDER_RANGE: /* SEQ1 V2 control */
+               DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value));
+               /* value = sense x 100 */
+               cinfo->bender_range = value;
+               /* no audible pitch change yet.. */
+               break;
+
+       case CTL_EXPRESSION: /* MIDI control #11 */
+               if (SINGLE_LAYER_MODE())
+                       value /= 128;
+       case CTRL_EXPRESSION: /* SEQ1 V2 control */
+               DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value));
+               /* 0 - 127 */
+               cinfo->expression_vol = value;
+               awe_voice_change(voice, awe_set_voice_vol);
+               break;
+
+       case CTL_PAN:   /* MIDI control #10 */
+               DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value));
+               /* (0-127) -> signed 8bit */
+               cinfo->panning = value * 2 - 128;
+               if (ctrls[AWE_MD_REALTIME_PAN])
+                       awe_voice_change(voice, awe_set_pan);
+               break;
+
+       case CTL_MAIN_VOLUME:   /* MIDI control #7 */
+               if (SINGLE_LAYER_MODE())
+                       value = (value * 100) / 16383;
+       case CTRL_MAIN_VOLUME:  /* SEQ1 V2 control */
+               DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value));
+               /* 0 - 127 */
+               cinfo->main_vol = value;
+               awe_voice_change(voice, awe_set_voice_vol);
+               break;
+
+       case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */
+               DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value));
+               FX_SET(&cinfo->fx, AWE_FX_REVERB, value * 2);
+               break;
+
+       case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */
+               DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value));
+               FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2);
+               break;
+
+       case 120:  /* all sounds off */
+               awe_note_off_all(FALSE);
+               break;
+       case 123:  /* all notes off */
+               awe_note_off_all(TRUE);
+               break;
+
+       case CTL_SUSTAIN: /* MIDI control #64 */
+               cinfo->sustained = value;
+               if (value != 127)
+                       awe_voice_change(voice, awe_sustain_off);
+               break;
+
+       case CTL_SOSTENUTO: /* MIDI control #66 */
+               if (value == 127)
+                       awe_voice_change(voice, awe_sostenuto_on);
+               else
+                       awe_voice_change(voice, awe_sustain_off);
+               break;
+
+       default:
+               DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n",
+                          voice, ctrl_num, value));
+               break;
+       }
+}
+
+
+/* voice pan change (value = -128 - 127) */
+static void
+awe_panning(int dev, int voice, int value)
+{
+       awe_chan_info *cinfo;
+
+       if (! voice_in_range(voice))
+               return;
+
+       if (playing_mode == AWE_PLAY_MULTI2) {
+               voice = voice_alloc->map[voice] >> 8;
+               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+                       return;
+       }
+
+       cinfo = &channels[voice];
+       cinfo->panning = value;
+       DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning));
+       if (ctrls[AWE_MD_REALTIME_PAN])
+               awe_voice_change(voice, awe_set_pan);
+}
+
+
+/* volume mode change */
+static void
+awe_volume_method(int dev, int mode)
+{
+       /* not impremented */
+       DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode));
+}
+
+
+/* pitch wheel change: 0-16384 */
+static void
+awe_bender(int dev, int voice, int value)
+{
+       awe_chan_info *cinfo;
+
+       if (! voice_in_range(voice))
+               return;
+
+       if (playing_mode == AWE_PLAY_MULTI2) {
+               voice = voice_alloc->map[voice] >> 8;
+               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
+                       return;
+       }
+
+       /* convert to zero centered value */
+       cinfo = &channels[voice];
+       cinfo->bender = value - 8192;
+       DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, cinfo->bender));
+       awe_voice_change(voice, awe_set_voice_pitch);
+}
+
+
+/*----------------------------------------------------------------
+ * load a sound patch:
+ *   three types of patches are accepted: AWE, GUS, and SYSEX.
+ *----------------------------------------------------------------*/
+
+static int
+awe_load_patch(int dev, int format, const char *addr,
+              int offs, int count, int pmgr_flag)
+{
+       awe_patch_info patch;
+       int rc = 0;
+
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+       if (format == GUS_PATCH) {
+               return awe_load_guspatch(addr, offs, count, pmgr_flag);
+       } else
+#endif
+       if (format == SYSEX_PATCH) {
+               /* no system exclusive message supported yet */
+               return 0;
+       } else if (format != AWE_PATCH) {
+               printk("AWE32 Error: Invalid patch format (key) 0x%x\n", format);
+               return -EINVAL;
+       }
+       
+       if (count < AWE_PATCH_INFO_SIZE) {
+               printk("AWE32 Error: Patch header too short\n");
+               return -EINVAL;
+       }
+       copy_from_user(((char*)&patch) + offs, addr + offs, 
+                      AWE_PATCH_INFO_SIZE - offs);
+
+       count -= AWE_PATCH_INFO_SIZE;
+       if (count < patch.len) {
+               printk("AWE32: sample: Patch record too short (%d<%d)\n",
+                      count, patch.len);
+               return -EINVAL;
+       }
+       
+       switch (patch.type) {
+       case AWE_LOAD_INFO:
+               rc = awe_load_info(&patch, addr, count);
+               break;
+       case AWE_LOAD_DATA:
+               rc = awe_load_data(&patch, addr, count);
+               break;
+       case AWE_OPEN_PATCH:
+               rc = awe_open_patch(&patch, addr, count);
+               break;
+       case AWE_CLOSE_PATCH:
+               rc = awe_close_patch(&patch, addr, count);
+               break;
+       case AWE_UNLOAD_PATCH:
+               rc = awe_unload_patch(&patch, addr, count);
+               break;
+       case AWE_REPLACE_DATA:
+               rc = awe_replace_data(&patch, addr, count);
+               break;
+       case AWE_MAP_PRESET:
+               rc = awe_load_map(&patch, addr, count);
+               break;
+       /* case AWE_PROBE_INFO:
+               rc = awe_probe_info(&patch, addr, count);
+               break;*/
+       case AWE_PROBE_DATA:
+               rc = awe_probe_data(&patch, addr, count);
+               break;
+       case AWE_LOAD_CHORUS_FX:
+               rc = awe_load_chorus_fx(&patch, addr, count);
+               break;
+       case AWE_LOAD_REVERB_FX:
+               rc = awe_load_reverb_fx(&patch, addr, count);
+               break;
+
+       default:
+               printk("AWE32 Error: unknown patch format type %d\n",
+                      patch.type);
+               rc = -EINVAL;
+       }
+
+       return rc;
+}
+
+
+/* create an sflist record */
+static int
+awe_create_sf(int type, char *name)
+{
+       sf_list *rec;
+
+       /* terminate sounds */
+       awe_reset(0);
+       if (current_sf_id >= max_sfs) {
+               int newsize = max_sfs + AWE_MAX_SF_LISTS;
+               sf_list *newlist = realloc_block(sflists, sizeof(sf_list)*max_sfs,
+                                                sizeof(sf_list)*newsize);
+               if (newlist == NULL)
+                       return 1;
+               sflists = newlist;
+               max_sfs = newsize;
+       }
+       rec = &sflists[current_sf_id];
+       rec->sf_id = current_sf_id + 1;
+       rec->type = type;
+       if (current_sf_id == 0 || (type & AWE_PAT_LOCKED) != 0)
+               locked_sf_id = current_sf_id + 1;
+       rec->num_info = awe_free_info();
+       rec->num_sample = awe_free_sample();
+       rec->mem_ptr = awe_free_mem_ptr();
+       rec->infos = -1;
+       rec->samples = -1;
+
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+       rec->shared = 0;
+       if (name)
+               memcpy(rec->name, name, AWE_PATCH_NAME_LEN);
+       else
+               strcpy(rec->name, "*TEMPORARY*");
+       if (current_sf_id > 0 && name && (type & AWE_PAT_SHARED) != 0) {
+               /* is the current font really a shared font? */
+               if (is_shared_sf(rec->name)) {
+                       /* check if the shared font is already installed */
+                       int i;
+                       for (i = current_sf_id; i > 0; i--) {
+                               if (is_identical_name(rec->name, i)) {
+                                       rec->shared = i;
+                                       break;
+                               }
+                       }
+               }
+       }
+#endif /* allow sharing */
+
+       current_sf_id++;
+
+       return 0;
+}
+
+
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+
+/* check if the given name is a valid shared name */
+#define ASC_TO_KEY(c) ((c) - 'A' + 1)
+static int is_shared_sf(unsigned char *name)
+{
+       static unsigned char id_head[6] = {
+               ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'),
+               AWE_MAJOR_VERSION,
+               AWE_MINOR_VERSION,
+               AWE_TINY_VERSION,
+       };
+       if (memcmp(name, id_head, 6) == 0)
+               return TRUE;
+       return FALSE;
+}
+
+/* check if the given name matches to the existing list */
+static int is_identical_name(unsigned char *name, int sf) 
+{
+       char *id = sflists[sf-1].name;
+       if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0)
+               return TRUE;
+       return FALSE;
+}
+
+/* check if the given voice info exists */
+static int info_duplicated(awe_voice_list *rec)
+{
+       int j, sf_id;
+       sf_list *sf;
+
+       /* search for all sharing lists */
+       for (sf_id = rec->v.sf_id; sf_id > 0 && sf_id <= current_sf_id; sf_id = sf->shared) {
+               sf = &sflists[sf_id - 1];
+               for (j = sf->infos; j >= 0; j = infos[j].next) {
+                       awe_voice_list *p = &infos[j];
+                       if (p->type == V_ST_NORMAL &&
+                           p->bank == rec->bank &&
+                           p->instr == rec->instr &&
+                           p->v.low == rec->v.low &&
+                           p->v.high == rec->v.high &&
+                           p->v.sample == rec->v.sample)
+                               return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+#endif /* AWE_ALLOW_SAMPLE_SHARING */
+
+
+/* open patch; create sf list and set opened flag */
+static int
+awe_open_patch(awe_patch_info *patch, const char *addr, int count)
+{
+       awe_open_parm parm;
+       int shared;
+
+       copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm));
+       shared = FALSE;
+
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+       if (current_sf_id > 0 && (parm.type & AWE_PAT_SHARED) != 0) {
+               /* is the previous font the same font? */
+               if (is_identical_name(parm.name, current_sf_id)) {
+                       /* then append to the previous */
+                       shared = TRUE;
+                       awe_reset(0);
+                       if (parm.type & AWE_PAT_LOCKED)
+                               locked_sf_id = current_sf_id;
+               }
+       }
+#endif /* allow sharing */
+       if (! shared) {
+               if (awe_create_sf(parm.type, parm.name)) {
+                       printk("AWE32: can't open: failed to alloc new list\n");
+                       return -ENOSPC;
+               }
+       }
+       patch_opened = TRUE;
+       return current_sf_id;
+}
+
+/* check if the patch is already opened */
+static int
+check_patch_opened(int type, char *name)
+{
+       if (! patch_opened) {
+               if (awe_create_sf(type, name)) {
+                       printk("AWE32: failed to alloc new list\n");
+                       return -ENOSPC;
+               }
+               patch_opened = TRUE;
+               return current_sf_id;
+       }
+       return current_sf_id;
+}
+
+/* close the patch; if no voice is loaded, remove the patch */
+static int
+awe_close_patch(awe_patch_info *patch, const char *addr, int count)
+{
+       if (patch_opened && current_sf_id > 0) {
+               /* if no voice is loaded, release the current patch */
+               if (sflists[current_sf_id-1].infos == -1)
+                       awe_remove_samples(current_sf_id - 1);
+       }
+       patch_opened = 0;
+       return 0;
+}
+
+
+/* remove the latest patch */
+static int
+awe_unload_patch(awe_patch_info *patch, const char *addr, int count)
+{
+       if (current_sf_id > 0 && current_sf_id > locked_sf_id)
+               awe_remove_samples(current_sf_id - 1);
+       return 0;
+}
+
+/* allocate voice info list records */
+static int alloc_new_info(int nvoices)
+{
+       int newsize, free_info;
+       awe_voice_list *newlist;
+       free_info = awe_free_info();
+       if (free_info + nvoices >= max_infos) {
+               do {
+                       newsize = max_infos + AWE_MAX_INFOS;
+               } while (free_info + nvoices >= newsize);
+               newlist = realloc_block(infos, sizeof(awe_voice_list)*max_infos,
+                                       sizeof(awe_voice_list)*newsize);
+               if (newlist == NULL) {
+                       printk("AWE32: can't alloc info table\n");
+                       return -ENOSPC;
+               }
+               infos = newlist;
+               max_infos = newsize;
+       }
+       return 0;
+}
+
+/* allocate sample info list records */
+static int alloc_new_sample(void)
+{
+       int newsize, free_sample;
+       awe_sample_list *newlist;
+       free_sample = awe_free_sample();
+       if (free_sample >= max_samples) {
+               newsize = max_samples + AWE_MAX_SAMPLES;
+               newlist = realloc_block(samples,
+                                       sizeof(awe_sample_list)*max_samples,
+                                       sizeof(awe_sample_list)*newsize);
+               if (newlist == NULL) {
+                       printk("AWE32: can't alloc sample table\n");
+                       return -ENOSPC;
+               }
+               samples = newlist;
+               max_samples = newsize;
+       }
+       return 0;
+}
+
+/* load voice map */
+static int
+awe_load_map(awe_patch_info *patch, const char *addr, int count)
+{
+       awe_voice_map map;
+       awe_voice_list *rec;
+       int p, free_info;
+
+       /* get the link info */
+       if (count < sizeof(map)) {
+               printk("AWE32 Error: invalid patch info length\n");
+               return -EINVAL;
+       }
+       copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map));
+       
+       /* check if the identical mapping already exists */
+       p = awe_search_instr(map.map_bank, map.map_instr);
+       for (; p >= 0; p = infos[p].next_instr) {
+               if (p >= 0 && infos[p].type == V_ST_MAPPED &&
+                   infos[p].v.low == map.map_key &&
+                   infos[p].v.start == map.src_instr &&
+                   infos[p].v.end == map.src_bank &&
+                   infos[p].v.fixkey == map.src_key)
+                       return 0; /* already present! */
+       }
+
+       if (check_patch_opened(AWE_PAT_TYPE_MAP, NULL) < 0)
+               return -ENOSPC;
+
+       if (alloc_new_info(1) < 0)
+               return -ENOSPC;
+
+       free_info = awe_free_info();
+       rec = &infos[free_info];
+       rec->bank = map.map_bank;
+       rec->instr = map.map_instr;
+       rec->type = V_ST_MAPPED;
+       rec->disabled = FALSE;
+       awe_init_voice_info(&rec->v);
+       if (map.map_key >= 0) {
+               rec->v.low = map.map_key;
+               rec->v.high = map.map_key;
+       }
+       rec->v.start = map.src_instr;
+       rec->v.end = map.src_bank;
+       rec->v.fixkey = map.src_key;
+       rec->v.sf_id = current_sf_id;
+       add_info_list(free_info);
+       add_sf_info(free_info);
+
+       return 0;
+}
+
+#if 0
+/* probe preset in the current list -- nothing to be loaded */
+static int
+awe_probe_info(awe_patch_info *patch, const char *addr, int count)
+{
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+       awe_voice_map map;
+       int p;
+
+       if (! patch_opened)
+               return -EINVAL;
+
+       /* get the link info */
+       if (count < sizeof(map)) {
+               printk("AWE32 Error: invalid patch info length\n");
+               return -EINVAL;
+       }
+       copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map));
+       
+       /* check if the identical mapping already exists */
+       p = awe_search_instr(map.src_bank, map.src_instr);
+       for (; p >= 0; p = infos[p].next_instr) {
+               if (p >= 0 && infos[p].type == V_ST_NORMAL &&
+                   is_identical_id(infos[p].v.sf_id, current_sf_id) &&
+                   infos[p].v.low <= map.src_key &&
+                   infos[p].v.high >= map.src_key)
+                       return 0; /* already present! */
+       }
+#endif /* allow sharing */
+       return -EINVAL;
+}
+#endif
+
+/* probe sample in the current list -- nothing to be loaded */
+static int
+awe_probe_data(awe_patch_info *patch, const char *addr, int count)
+{
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+       if (! patch_opened)
+               return -EINVAL;
+
+       /* search the specified sample by optarg */
+       if (search_sample_index(current_sf_id, patch->optarg, 0) >= 0)
+               return 0;
+#endif /* allow sharing */
+       return -EINVAL;
+}
+
+/* load voice information data */
+static int
+awe_load_info(awe_patch_info *patch, const char *addr, int count)
+{
+       int offset;
+       awe_voice_rec_hdr hdr;
+       int i;
+       int total_size;
+
+       if (count < AWE_VOICE_REC_SIZE) {
+               printk("AWE32 Error: invalid patch info length\n");
+               return -EINVAL;
+       }
+
+       offset = AWE_PATCH_INFO_SIZE;
+       copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE);
+       offset += AWE_VOICE_REC_SIZE;
+
+       if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
+               printk("AWE32 Error: Illegal voice number %d\n", hdr.nvoices);
+               return -EINVAL;
+       }
+       total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices;
+       if (count < total_size) {
+               printk("AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
+                      count, hdr.nvoices);
+               return -EINVAL;
+       }
+
+       if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0)
+               return -ENOSPC;
+
+#if 0 /* it looks like not so useful.. */
+       /* check if the same preset already exists in the info list */
+       for (i = sflists[current_sf_id-1].infos; i >= 0; i = infos[i].next) {
+               if (infos[i].disabled) continue;
+               if (infos[i].bank == hdr.bank && infos[i].instr == hdr.instr) {
+                       /* in exclusive mode, do skip loading this */
+                       if (hdr.write_mode == AWE_WR_EXCLUSIVE)
+                               return 0;
+                       /* in replace mode, disable the old data */
+                       else if (hdr.write_mode == AWE_WR_REPLACE)
+                               infos[i].disabled = TRUE;
+               }
+       }
+       if (hdr.write_mode == AWE_WR_REPLACE)
+               rebuild_preset_list();
+#endif
+
+       if (alloc_new_info(hdr.nvoices) < 0)
+               return -ENOSPC;
+
+       for (i = 0; i < hdr.nvoices; i++) {
+               int rec = awe_free_info();
+
+               infos[rec].bank = hdr.bank;
+               infos[rec].instr = hdr.instr;
+               infos[rec].type = V_ST_NORMAL;
+               infos[rec].disabled = FALSE;
+
+               /* copy awe_voice_info parameters */
+               copy_from_user(&infos[rec].v, addr + offset, AWE_VOICE_INFO_SIZE);
+               offset += AWE_VOICE_INFO_SIZE;
+               infos[rec].v.sf_id = current_sf_id;
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+               if (sflists[current_sf_id-1].shared) {
+                       if (info_duplicated(&infos[rec]))
+                               continue;
+               }
+#endif /* allow sharing */
+               if (infos[rec].v.mode & AWE_MODE_INIT_PARM)
+                       awe_init_voice_parm(&infos[rec].v.parm);
+               awe_set_sample(&infos[rec].v);
+               add_info_list(rec);
+               add_sf_info(rec);
+       }
+
+       return 0;
+}
+
+
+/* load wave sample data */
+static int
+awe_load_data(awe_patch_info *patch, const char *addr, int count)
+{
+       int offset, size;
+       int rc, free_sample;
+       awe_sample_info tmprec, *rec;
+
+       if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0)
+               return -ENOSPC;
+
+       size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
+       offset = AWE_PATCH_INFO_SIZE;
+       copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE);
+       offset += AWE_SAMPLE_INFO_SIZE;
+       if (size != tmprec.size) {
+               printk("AWE32: load: sample size differed (%d != %d)\n",
+                      tmprec.size, size);
+               return -EINVAL;
+       }
+
+       if (search_sample_index(current_sf_id, tmprec.sample, 0) >= 0) {
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+               /* if shared sample, skip this data */
+               if (sflists[current_sf_id-1].type & AWE_PAT_SHARED)
+                       return 0;
+#endif /* allow sharing */
+               DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample));
+               return -EINVAL;
+       }
+
+       if (alloc_new_sample() < 0)
+               return -ENOSPC;
+
+       free_sample = awe_free_sample();
+       rec = &samples[free_sample].v;
+       *rec = tmprec;
+
+       if (rec->size > 0)
+               if ((rc = awe_write_wave_data(addr, offset, rec, -1)) != 0)
+                       return rc;
+
+       rec->sf_id = current_sf_id;
+
+       add_sf_sample(free_sample);
+
+       return 0;
+}
+
+
+/* replace wave sample data */
+static int
+awe_replace_data(awe_patch_info *patch, const char *addr, int count)
+{
+       int offset;
+       int size;
+       int rc, i;
+       int channels;
+       awe_sample_info cursmp;
+       int save_mem_ptr;
+
+       if (! patch_opened) {
+               printk("AWE32: replace: patch not opened\n");
+               return -EINVAL;
+       }
+
+       size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
+       offset = AWE_PATCH_INFO_SIZE;
+       copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE);
+       offset += AWE_SAMPLE_INFO_SIZE;
+       if (cursmp.size == 0 || size != cursmp.size) {
+               printk("AWE32: replace: illegal sample size (%d!=%d)\n",
+                      cursmp.size, size);
+               return -EINVAL;
+       }
+       channels = patch->optarg;
+       if (channels <= 0 || channels > AWE_NORMAL_VOICES) {
+               printk("AWE32: replace: illegal channels %d\n", channels);
+               return -EINVAL;
+       }
+
+       for (i = sflists[current_sf_id-1].samples;
+            i >= 0; i = samples[i].next) {
+               if (samples[i].v.sample == cursmp.sample)
+                       break;
+       }
+       if (i < 0) {
+               printk("AWE32: replace: cannot find existing sample data %d\n",
+                      cursmp.sample);
+               return -EINVAL;
+       }
+               
+       if (samples[i].v.size != cursmp.size) {
+               printk("AWE32: replace: exiting size differed (%d!=%d)\n",
+                      samples[i].v.size, cursmp.size);
+               return -EINVAL;
+       }
+
+       save_mem_ptr = awe_free_mem_ptr();
+       sflists[current_sf_id-1].mem_ptr = samples[i].v.start - awe_mem_start;
+       memcpy(&samples[i].v, &cursmp, sizeof(cursmp));
+       if ((rc = awe_write_wave_data(addr, offset, &samples[i].v, channels)) != 0)
+               return rc;
+       sflists[current_sf_id-1].mem_ptr = save_mem_ptr;
+       samples[i].v.sf_id = current_sf_id;
+
+       return 0;
+}
+
+
+/*----------------------------------------------------------------*/
+
+static const char *readbuf_addr;
+static int readbuf_offs;
+static int readbuf_flags;
+#ifdef MALLOC_LOOP_DATA
+static unsigned short *readbuf_loop;
+static int readbuf_loopstart, readbuf_loopend;
+#endif
+
+/* initialize read buffer */
+static int
+readbuf_init(const char *addr, int offset, awe_sample_info *sp)
+{
+#ifdef MALLOC_LOOP_DATA
+       readbuf_loop = NULL;
+       readbuf_loopstart = sp->loopstart;
+       readbuf_loopend = sp->loopend;
+       if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) {
+               int looplen = sp->loopend - sp->loopstart;
+               readbuf_loop = vmalloc(looplen * 2);
+               if (readbuf_loop == NULL) {
+                       printk("AWE32: can't malloc temp buffer\n");
+                       return -ENOSPC;
+               }
+       }
+#endif
+       readbuf_addr = addr;
+       readbuf_offs = offset;
+       readbuf_flags = sp->mode_flags;
+       return 0;
+}
+
+/* read directly from user buffer */
+static unsigned short
+readbuf_word(int pos)
+{
+       unsigned short c;
+       /* read from user buffer */
+       if (readbuf_flags & AWE_SAMPLE_8BITS) {
+               unsigned char cc;
+               get_user(cc, (unsigned char*)&(readbuf_addr)[readbuf_offs + pos]);
+               c = cc << 8; /* convert 8bit -> 16bit */
+       } else {
+               get_user(c, (unsigned short*)&(readbuf_addr)[readbuf_offs + pos * 2]);
+       }
+       if (readbuf_flags & AWE_SAMPLE_UNSIGNED)
+               c ^= 0x8000; /* unsigned -> signed */
+#ifdef MALLOC_LOOP_DATA
+       /* write on cache for reverse loop */
+       if (readbuf_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) {
+               if (pos >= readbuf_loopstart && pos < readbuf_loopend)
+                       readbuf_loop[pos - readbuf_loopstart] = c;
+       }
+#endif
+       return c;
+}
+
+#ifdef MALLOC_LOOP_DATA
+/* read from cache */
+static unsigned short
+readbuf_word_cache(int pos)
+{
+       if (pos >= readbuf_loopstart && pos < readbuf_loopend)
+               return readbuf_loop[pos - readbuf_loopstart];
+       return 0;
+}
+
+static void
+readbuf_end(void)
+{
+       if (readbuf_loop)
+               vfree(readbuf_loop);
+       readbuf_loop = NULL;
+}
+
+#else
+
+#define readbuf_word_cache     readbuf_word
+#define readbuf_end()          /**/
+
+#endif
+
+/*----------------------------------------------------------------*/
+
+#define BLANK_LOOP_START       8
+#define BLANK_LOOP_END         40
+#define BLANK_LOOP_SIZE                48
+
+/* loading onto memory */
+static int 
+awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels)
+{
+       int i, truesize, dram_offset;
+       int rc;
+
+       /* be sure loop points start < end */
+       if (sp->loopstart > sp->loopend) {
+               int tmp = sp->loopstart;
+               sp->loopstart = sp->loopend;
+               sp->loopend = tmp;
+       }
+
+       /* compute true data size to be loaded */
+       truesize = sp->size;
+       if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP)
+               truesize += sp->loopend - sp->loopstart;
+       if (sp->mode_flags & AWE_SAMPLE_NO_BLANK)
+               truesize += BLANK_LOOP_SIZE;
+       if (awe_free_mem_ptr() + truesize >= awe_mem_size/2) {
+               DEBUG(-1,printk("AWE32 Error: Sample memory full\n"));
+               return -ENOSPC;
+       }
+
+       /* recalculate address offset */
+       sp->end -= sp->start;
+       sp->loopstart -= sp->start;
+       sp->loopend -= sp->start;
+
+       dram_offset = awe_free_mem_ptr() + awe_mem_start;
+       sp->start = dram_offset;
+       sp->end += dram_offset;
+       sp->loopstart += dram_offset;
+       sp->loopend += dram_offset;
+
+       /* set the total size (store onto obsolete checksum value) */
+       if (sp->size == 0)
+               sp->checksum = 0;
+       else
+               sp->checksum = truesize;
+
+       if ((rc = awe_open_dram_for_write(dram_offset, channels)) != 0)
+               return rc;
+
+       if (readbuf_init(addr, offset, sp) < 0)
+               return -ENOSPC;
+
+       for (i = 0; i < sp->size; i++) {
+               unsigned short c;
+               c = readbuf_word(i);
+               awe_write_dram(c);
+               if (i == sp->loopend &&
+                   (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))) {
+                       int looplen = sp->loopend - sp->loopstart;
+                       /* copy reverse loop */
+                       int k;
+                       for (k = 1; k <= looplen; k++) {
+                               c = readbuf_word_cache(i - k);
+                               awe_write_dram(c);
+                       }
+                       if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) {
+                               sp->end += looplen;
+                       } else {
+                               sp->start += looplen;
+                               sp->end += looplen;
+                       }
+               }
+       }
+       readbuf_end();
+
+       /* if no blank loop is attached in the sample, add it */
+       if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) {
+               for (i = 0; i < BLANK_LOOP_SIZE; i++)
+                       awe_write_dram(0);
+               if (sp->mode_flags & AWE_SAMPLE_SINGLESHOT) {
+                       sp->loopstart = sp->end + BLANK_LOOP_START;
+                       sp->loopend = sp->end + BLANK_LOOP_END;
+               }
+       }
+
+       sflists[current_sf_id-1].mem_ptr += truesize;
+       awe_close_dram();
+
+       /* initialize FM */
+       awe_init_fm();
+
+       return 0;
+}
+
+
+/*----------------------------------------------------------------*/
+
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+
+/* calculate GUS envelope time:
+ * is this correct?  i have no idea..
+ */
+static int
+calc_gus_envelope_time(int rate, int start, int end)
+{
+       int r, p, t;
+       r = (3 - ((rate >> 6) & 3)) * 3;
+       p = rate & 0x3f;
+       t = end - start;
+       if (t < 0) t = -t;
+       if (13 > r)
+               t = t << (13 - r);
+       else
+               t = t >> (r - 13);
+       return (t * 10) / (p * 441);
+}
+
+#define calc_gus_sustain(val)  (0x7f - vol_table[(val)/2])
+#define calc_gus_attenuation(val)      vol_table[(val)/2]
+
+/* load GUS patch */
+static int
+awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
+{
+       struct patch_info patch;
+       awe_voice_info *rec;
+       awe_sample_info *smp;
+       int sizeof_patch;
+       int note, free_sample, free_info;
+       int rc;
+
+       sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */
+       if (size < sizeof_patch) {
+               printk("AWE32 Error: Patch header too short\n");
+               return -EINVAL;
+       }
+       copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs);
+       size -= sizeof_patch;
+       if (size < patch.len) {
+               printk("AWE32 Warning: Patch record too short (%d<%d)\n",
+                      size, patch.len);
+               return -EINVAL;
+       }
+       if (check_patch_opened(AWE_PAT_TYPE_GUS, NULL) < 0)
+               return -ENOSPC;
+       if (alloc_new_sample() < 0)
+               return -ENOSPC;
+       if (alloc_new_info(1))
+               return -ENOSPC;
+
+       free_sample = awe_free_sample();
+       smp = &samples[free_sample].v;
+
+       smp->sample = free_sample;
+       smp->start = 0;
+       smp->end = patch.len;
+       smp->loopstart = patch.loop_start;
+       smp->loopend = patch.loop_end;
+       smp->size = patch.len;
+
+       /* set up mode flags */
+       smp->mode_flags = 0;
+       if (!(patch.mode & WAVE_16_BITS))
+               smp->mode_flags |= AWE_SAMPLE_8BITS;
+       if (patch.mode & WAVE_UNSIGNED)
+               smp->mode_flags |= AWE_SAMPLE_UNSIGNED;
+       smp->mode_flags |= AWE_SAMPLE_NO_BLANK;
+       if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK)))
+               smp->mode_flags |= AWE_SAMPLE_SINGLESHOT;
+       if (patch.mode & WAVE_BIDIR_LOOP)
+               smp->mode_flags |= AWE_SAMPLE_BIDIR_LOOP;
+       if (patch.mode & WAVE_LOOP_BACK)
+               smp->mode_flags |= AWE_SAMPLE_REVERSE_LOOP;
+
+       DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, smp->mode_flags));
+       if (patch.mode & WAVE_16_BITS) {
+               /* convert to word offsets */
+               smp->size /= 2;
+               smp->end /= 2;
+               smp->loopstart /= 2;
+               smp->loopend /= 2;
+       }
+       smp->checksum_flag = 0;
+       smp->checksum = 0;
+
+       if ((rc = awe_write_wave_data(addr, sizeof_patch, smp, -1)) != 0)
+               return rc;
+
+       smp->sf_id = current_sf_id;
+       add_sf_sample(free_sample);
+
+       /* set up voice info */
+       free_info = awe_free_info();
+       rec = &infos[free_info].v;
+       awe_init_voice_info(rec);
+       rec->sample = free_sample; /* the last sample */
+       rec->rate_offset = calc_rate_offset(patch.base_freq);
+       note = freq_to_note(patch.base_note);
+       rec->root = note / 100;
+       rec->tune = -(note % 100);
+       rec->low = freq_to_note(patch.low_note) / 100;
+       rec->high = freq_to_note(patch.high_note) / 100;
+       DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n",
+                      rec->rate_offset, note,
+                      rec->low, rec->high,
+             patch.low_note, patch.high_note));
+       /* panning position; -128 - 127 => 0-127 */
+       rec->pan = (patch.panning + 128) / 2;
+
+       /* detuning is ignored */
+       /* 6points volume envelope */
+       if (patch.mode & WAVE_ENVELOPES) {
+               int attack, hold, decay, release;
+               attack = calc_gus_envelope_time
+                       (patch.env_rate[0], 0, patch.env_offset[0]);
+               hold = calc_gus_envelope_time
+                       (patch.env_rate[1], patch.env_offset[0],
+                        patch.env_offset[1]);
+               decay = calc_gus_envelope_time
+                       (patch.env_rate[2], patch.env_offset[1],
+                        patch.env_offset[2]);
+               release = calc_gus_envelope_time
+                       (patch.env_rate[3], patch.env_offset[1],
+                        patch.env_offset[4]);
+               release += calc_gus_envelope_time
+                       (patch.env_rate[4], patch.env_offset[3],
+                        patch.env_offset[4]);
+               release += calc_gus_envelope_time
+                       (patch.env_rate[5], patch.env_offset[4],
+                        patch.env_offset[5]);
+               rec->parm.volatkhld = (calc_parm_attack(attack) << 8) |
+                       calc_parm_hold(hold);
+               rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |
+                       calc_parm_decay(decay);
+               rec->parm.volrelease = 0x8000 | calc_parm_decay(release);
+               DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release));
+               rec->attenuation = calc_gus_attenuation(patch.env_offset[0]);
+       }
+
+       /* tremolo effect */
+       if (patch.mode & WAVE_TREMOLO) {
+               int rate = (patch.tremolo_rate * 1000 / 38) / 42;
+               rec->parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate;
+               DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n",
+                              patch.tremolo_rate, patch.tremolo_depth,
+                              rec->parm.tremfrq));
+       }
+       /* vibrato effect */
+       if (patch.mode & WAVE_VIBRATO) {
+               int rate = (patch.vibrato_rate * 1000 / 38) / 42;
+               rec->parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate;
+               DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n",
+                              patch.tremolo_rate, patch.tremolo_depth,
+                              rec->parm.tremfrq));
+       }
+       
+       /* scale_freq, scale_factor, volume, and fractions not implemented */
+
+       /* append to the tail of the list */
+       infos[free_info].bank = ctrls[AWE_MD_GUS_BANK];
+       infos[free_info].instr = patch.instr_no;
+       infos[free_info].disabled = FALSE;
+       infos[free_info].type = V_ST_NORMAL;
+       infos[free_info].v.sf_id = current_sf_id;
+
+       add_info_list(free_info);
+       add_sf_info(free_info);
+
+       /* set the voice index */
+       awe_set_sample(rec);
+
+       return 0;
+}
+
+#endif  /* AWE_HAS_GUS_COMPATIBILITY */
+
+/*
+ * sample and voice list handlers
+ */
+
+/* append this to the sf list */
+static void add_sf_info(int rec)
+{
+       int sf_id = infos[rec].v.sf_id;
+       if (sf_id <= 0) return;
+       sf_id--;
+       if (sflists[sf_id].infos < 0)
+               sflists[sf_id].infos = rec;
+       else {
+               int i, prev;
+               prev = sflists[sf_id].infos;
+               while ((i = infos[prev].next) >= 0)
+                       prev = i;
+               infos[prev].next = rec;
+       }
+       infos[rec].next = -1;
+       sflists[sf_id].num_info++;
+}
+
+/* prepend this sample to sf list */
+static void add_sf_sample(int rec)
+{
+       int sf_id = samples[rec].v.sf_id;
+       if (sf_id <= 0) return;
+       sf_id--;
+       samples[rec].next = sflists[sf_id].samples;
+       sflists[sf_id].samples = rec;
+       sflists[sf_id].num_sample++;
+}
+
+/* purge the old records which don't belong with the same file id */
+static void purge_old_list(int rec, int next)
+{
+       infos[rec].next_instr = next;
+       if (infos[rec].bank == AWE_DRUM_BANK) {
+               /* remove samples with the same note range */
+               int cur, *prevp = &infos[rec].next_instr;
+               int low = infos[rec].v.low;
+               int high = infos[rec].v.high;
+               for (cur = next; cur >= 0; cur = infos[cur].next_instr) {
+                       if (infos[cur].v.low == low &&
+                           infos[cur].v.high == high &&
+                           ! is_identical_id(infos[cur].v.sf_id, infos[rec].v.sf_id))
+                               *prevp = infos[cur].next_instr;
+                       prevp = &infos[cur].next_instr;
+               }
+       } else {
+               if (! is_identical_id(infos[next].v.sf_id, infos[rec].v.sf_id))
+                       infos[rec].next_instr = -1;
+       }
+}
+
+/* prepend to top of the preset table */
+static void add_info_list(int rec)
+{
+       int *prevp, cur;
+       int instr;
+       int bank;
+
+       if (infos[rec].disabled)
+               return;
+
+       instr = infos[rec].instr;
+       bank = infos[rec].bank;
+       limitvalue(instr, 0, AWE_MAX_PRESETS-1);
+       prevp = &preset_table[instr];
+       cur = *prevp;
+       while (cur >= 0) {
+               /* search the first record with the same bank number */
+               if (infos[cur].bank == bank) {
+                       /* replace the list with the new record */
+                       infos[rec].next_bank = infos[cur].next_bank;
+                       *prevp = rec;
+                       purge_old_list(rec, cur);
+                       return;
+               }
+               prevp = &infos[cur].next_bank;
+               cur = infos[cur].next_bank;
+       }
+
+       /* this is the first bank record.. just add this */
+       infos[rec].next_instr = -1;
+       infos[rec].next_bank = preset_table[instr];
+       preset_table[instr] = rec;
+}
+
+/* remove samples later than the specified sf_id */
+static void
+awe_remove_samples(int sf_id)
+{
+       if (sf_id <= 0) {
+               awe_reset_samples();
+               return;
+       }
+       /* already removed? */
+       if (current_sf_id <= sf_id)
+               return;
+
+       current_sf_id = sf_id;
+       if (locked_sf_id > sf_id)
+               locked_sf_id = sf_id;
+
+       rebuild_preset_list();
+}
+
+/* rebuild preset search list */
+static void rebuild_preset_list(void)
+{
+       int i, j;
+
+       for (i = 0; i < AWE_MAX_PRESETS; i++)
+               preset_table[i] = -1;
+
+       for (i = 0; i < current_sf_id; i++) {
+               for (j = sflists[i].infos; j >= 0; j = infos[j].next)
+                       add_info_list(j);
+       }
+}
+
+/* compare the given sf_id pair */
+static int is_identical_id(int id1, int id2)
+{
+       if (id1 == id2)
+               return TRUE;
+       if (id1 <= 0 || id2 <= 0) /* this must not happen.. */
+               return FALSE;
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+       {
+               /* compare with the sharing id */
+               int i;
+               if (id1 < id2) { /* make sure id1 > id2 */
+                       int tmp; tmp = id1; id1 = id2; id2 = tmp;
+               }
+               for (i = sflists[id1-1].shared; i > 0 && i <= current_sf_id; i = sflists[i-1].shared) {
+                       if (i == id2)
+                               return TRUE;
+               }
+       }
+#endif /* allow sharing */
+       return FALSE;
+}
+
+/* search the sample index matching with the given sample id */
+static int search_sample_index(int sf, int sample, int level)
+{
+       int i;
+
+       if (sf <= 0 || sf > current_sf_id)
+               return -1; /* this must not happen */
+
+       for (i = sflists[sf-1].samples; i >= 0; i = samples[i].next) {
+               if (samples[i].v.sample == sample)
+                       return i;
+       }
+#ifdef AWE_ALLOW_SAMPLE_SHARING
+       if ((i = sflists[sf-1].shared) > 0 && i <= current_sf_id) { /* search recursively */
+               if (level > current_sf_id)
+                       return -1; /* strange sharing loop.. quit */
+               return search_sample_index(i, sample, level + 1);
+       }
+#endif
+       return -1;
+}
+
+/* search the specified sample */
+static short
+awe_set_sample(awe_voice_info *vp)
+{
+       int i;
+
+       vp->index = -1;
+       if ((i = search_sample_index(vp->sf_id, vp->sample, 0)) < 0)
+               return -1;
+
+       /* set the actual sample offsets */
+       vp->start += samples[i].v.start;
+       vp->end += samples[i].v.end;
+       vp->loopstart += samples[i].v.loopstart;
+       vp->loopend += samples[i].v.loopend;
+       /* copy mode flags */
+       vp->mode = samples[i].v.mode_flags;
+       /* set index */
+       vp->index = i;
+
+       return i;
+}
+
+
+/*----------------------------------------------------------------
+ * voice allocation
+ *----------------------------------------------------------------*/
+
+/* look for all voices associated with the specified note & velocity */
+static int
+awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist)
+{
+       int nvoices;
+
+       nvoices = 0;
+       for (; rec >= 0; rec = infos[rec].next_instr) {
+               if (note >= infos[rec].v.low &&
+                   note <= infos[rec].v.high &&
+                   velocity >= infos[rec].v.vellow &&
+                   velocity <= infos[rec].v.velhigh) {
+                       if (infos[rec].type == V_ST_MAPPED) {
+                               /* mapper */
+                               vlist[0] = &infos[rec].v;
+                               return -1;
+                       }
+                       vlist[nvoices++] = &infos[rec].v;
+                       if (nvoices >= AWE_MAX_VOICES)
+                               break;
+               }
+       }
+       return nvoices; 
+}
+
+/* store the voice list from the specified note and velocity.
+   if the preset is mapped, seek for the destination preset, and rewrite
+   the note number if necessary.
+   */
+static int
+really_alloc_voices(int vrec, int def_vrec, int *note, int velocity, awe_voice_info **vlist, int level)
+{
+       int nvoices;
+
+       nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
+       if (nvoices == 0)
+               nvoices = awe_search_multi_voices(def_vrec, *note, velocity, vlist);
+       if (nvoices < 0) { /* mapping */
+               int preset = vlist[0]->start;
+               int bank = vlist[0]->end;
+               int key = vlist[0]->fixkey;
+               if (level > 5) {
+                       printk("AWE32: too deep mapping level\n");
+                       return 0;
+               }
+               vrec = awe_search_instr(bank, preset);
+               if (bank == AWE_DRUM_BANK)
+                       def_vrec = awe_search_instr(bank, 0);
+               else
+                       def_vrec = awe_search_instr(0, preset);
+               if (key >= 0)
+                       *note = key;
+               return really_alloc_voices(vrec, def_vrec, note, velocity, vlist, level+1);
+       }
+
+       return nvoices;
+}
+
+/* allocate voices corresponding note and velocity; supports multiple insts. */
+static void
+awe_alloc_multi_voices(int ch, int note, int velocity, int key)
+{
+       int i, v, nvoices;
+       awe_voice_info *vlist[AWE_MAX_VOICES];
+
+       if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0)
+               awe_set_instr(0, ch, channels[ch].instr);
+
+       /* check the possible voices; note may be changeable if mapped */
+       nvoices = really_alloc_voices(channels[ch].vrec, channels[ch].def_vrec,
+                                     &note, velocity, vlist, 0);
+
+       /* set the voices */
+       current_alloc_time++;
+       for (i = 0; i < nvoices; i++) {
+               v = awe_clear_voice();
+               voices[v].key = key;
+               voices[v].ch = ch;
+               voices[v].note = note;
+               voices[v].velocity = velocity;
+               voices[v].time = current_alloc_time;
+               voices[v].cinfo = &channels[ch];
+               voices[v].sample = vlist[i];
+               voices[v].state = AWE_ST_MARK;
+               voices[v].layer = nvoices - i - 1;  /* in reverse order */
+       }
+
+       /* clear the mark in allocated voices */
+       for (i = 0; i < awe_max_voices; i++) {
+               if (voices[i].state == AWE_ST_MARK)
+                       voices[i].state = AWE_ST_OFF;
+                       
+       }
+}
+
+
+/* search the best voice from the specified status condition */
+static int
+search_best_voice(int condition)
+{
+       int i, time, best;
+       int vtarget = 0xffff, min_vtarget = 0xffff;
+
+       best = -1;
+       time = current_alloc_time + 1;
+       for (i = 0; i < awe_max_voices; i++) {
+               if (! (voices[i].state & condition))
+                       continue;
+#ifdef AWE_CHECK_VTARGET
+               /* get current volume */
+               vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff;
+#endif
+               if (best < 0 || vtarget < min_vtarget ||
+                   (vtarget == min_vtarget && voices[i].time < time)) {
+                       best = i;
+                       time = voices[i].time;
+                       min_vtarget = vtarget;
+               }
+       }
+       /* clear voice */
+       if (best >= 0) {
+               if (voices[best].state != AWE_ST_OFF)
+                       awe_terminate(best);
+               awe_voice_init(best, TRUE);
+       }
+
+       return best;
+}
+
+/* search an empty voice.
+   if no empty voice is found, at least terminate a voice
+   */
+static int
+awe_clear_voice(void)
+{
+       int best;
+
+       /* looking for the oldest empty voice */
+       if ((best = search_best_voice(AWE_ST_OFF)) >= 0)
+               return best;
+       if ((best = search_best_voice(AWE_ST_RELEASED)) >= 0)
+               return best;
+       /* looking for the oldest sustained voice */
+       if ((best = search_best_voice(AWE_ST_SUSTAINED)) >= 0)
+               return best;
+
+       if (MULTI_LAYER_MODE() && ctrls[AWE_MD_CHN_PRIOR]) {
+               int ch = -1;
+               int time = current_alloc_time + 1;
+               int i;
+               /* looking for the voices from high channel (except drum ch) */
+               for (i = 0; i < awe_max_voices; i++) {
+                       if (IS_DRUM_CHANNEL(voices[i].ch)) continue;
+                       if (voices[i].ch < ch) continue;
+                       if (voices[i].state != AWE_ST_MARK &&
+                           (voices[i].ch > ch || voices[i].time < time)) {
+                               best = i;
+                               time = voices[i].time;
+                               ch = voices[i].ch;
+                       }
+               }
+       }
+       if (best < 0)
+               best = search_best_voice(~AWE_ST_MARK);
+
+       if (best >= 0)
+               return best;
+
+       return 0;
+}
+
+
+/* search sample for the specified note & velocity and set it on the voice;
+ * note that voice is the voice index (not channel index)
+ */
+static void
+awe_alloc_one_voice(int voice, int note, int velocity)
+{
+       int ch, nvoices;
+       awe_voice_info *vlist[AWE_MAX_VOICES];
+
+       ch = voices[voice].ch;
+       if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0)
+               awe_set_instr(0, ch, channels[ch].instr);
+
+       nvoices = really_alloc_voices(voices[voice].cinfo->vrec,
+                                     voices[voice].cinfo->def_vrec,
+                                     &note, velocity, vlist, 0);
+       if (nvoices > 0) {
+               voices[voice].time = ++current_alloc_time;
+               voices[voice].sample = vlist[0]; /* use the first one */
+               voices[voice].layer = 0;
+               voices[voice].note = note;
+               voices[voice].velocity = velocity;
+       }
+}
+
+
+/*----------------------------------------------------------------
+ * sequencer2 functions
+ *----------------------------------------------------------------*/
+
+/* search an empty voice; used by sequencer2 */
+static int
+awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
+{
+       playing_mode = AWE_PLAY_MULTI2;
+       awe_info.nr_voices = AWE_MAX_CHANNELS;
+       return awe_clear_voice();
+}
+
+
+/* set up voice; used by sequencer2 */
+static void
+awe_setup_voice(int dev, int voice, int chn)
+{
+       struct channel_info *info;
+       if (synth_devs[dev] == NULL ||
+           (info = &synth_devs[dev]->chn_info[chn]) == NULL)
+               return;
+
+       if (voice < 0 || voice >= awe_max_voices)
+               return;
+
+       DEBUG(2,printk("AWE32: [setup(%d) ch=%d]\n", voice, chn));
+       channels[chn].expression_vol = info->controllers[CTL_EXPRESSION];
+       channels[chn].main_vol = info->controllers[CTL_MAIN_VOLUME];
+       channels[chn].panning =
+               info->controllers[CTL_PAN] * 2 - 128; /* signed 8bit */
+       channels[chn].bender = info->bender_value; /* zero center */
+       channels[chn].bank = info->controllers[CTL_BANK_SELECT];
+       channels[chn].sustained = info->controllers[CTL_SUSTAIN];
+       if (info->controllers[CTL_EXT_EFF_DEPTH]) {
+               FX_SET(&channels[chn].fx, AWE_FX_REVERB,
+                      info->controllers[CTL_EXT_EFF_DEPTH] * 2);
+       }
+       if (info->controllers[CTL_CHORUS_DEPTH]) {
+               FX_SET(&channels[chn].fx, AWE_FX_CHORUS,
+                      info->controllers[CTL_CHORUS_DEPTH] * 2);
+       }
+       awe_set_instr(dev, chn, info->pgm_num);
+}
+
+
+#ifdef CONFIG_AWE32_MIXER
+/*
+ * AWE32 mixer device control
+ */
+
+static int awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg);
+
+static int my_mixerdev = -1;
+
+static struct mixer_operations awe_mixer_operations = {
+       "AWE32 Equalizer",
+       awe_mixer_ioctl,
+};
+
+static void attach_mixer(void)
+{
+       if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) {
+               mixer_devs[my_mixerdev] = &awe_mixer_operations;
+       }
+}
+
+static void unload_mixer(void)
+{
+       if (my_mixerdev >= 0)
+               sound_unload_mixerdev(my_mixerdev);
+}
+
+static int
+awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+       int i, level, value;
+
+       if (((cmd >> 8) & 0xff) != 'M')
+               return -EINVAL;
+
+       level = (int) *(int *)arg;
+       level = ((level & 0xff) + (level >> 8)) / 2;
+       DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level));
+
+       if (_SIOC_DIR(cmd) & _IOC_WRITE) {
+               switch (cmd & 0xff) {
+               case SOUND_MIXER_BASS:
+                       value = level * 12 / 100;
+                       if (value >= 12)
+                               value = 11;
+                       ctrls[AWE_MD_BASS_LEVEL] = value;
+                       awe_update_equalizer();
+                       break;
+               case SOUND_MIXER_TREBLE:
+                       value = level * 12 / 100;
+                       if (value >= 12)
+                               value = 11;
+                       ctrls[AWE_MD_TREBLE_LEVEL] = value;
+                       awe_update_equalizer();
+                       break;
+               case SOUND_MIXER_VOLUME:
+                       level = level * 127 / 100;
+                       if (level >= 128) level = 127;
+                       atten_relative = FALSE;
+                       atten_offset = vol_table[level];
+                       awe_update_volume();
+                       break;
+               }
+       }
+       switch (cmd & 0xff) {
+       case SOUND_MIXER_BASS:
+               level = ctrls[AWE_MD_BASS_LEVEL] * 100 / 24;
+               level = (level << 8) | level;
+               break;
+       case SOUND_MIXER_TREBLE:
+               level = ctrls[AWE_MD_TREBLE_LEVEL] * 100 / 24;
+               level = (level << 8) | level;
+               break;
+       case SOUND_MIXER_VOLUME:
+               value = atten_offset;
+               if (atten_relative)
+                       value += ctrls[AWE_MD_ZERO_ATTEN];
+               for (i = 127; i > 0; i--) {
+                       if (value <= vol_table[i])
+                               break;
+               }
+               level = i * 100 / 127;
+               level = (level << 8) | level;
+               break;
+       case SOUND_MIXER_DEVMASK:
+               level = SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_VOLUME;
+               break;
+       default:
+               level = 0;
+               break;
+       }
+       return *(int *)arg = level;
+}
+#endif /* CONFIG_AWE32_MIXER */
+
+
+/*
+ * initialization of AWE32
+ */
+
+/* intiailize audio channels */
+static void
+awe_init_audio(void)
+{
+       int ch;
+
+       /* turn off envelope engines */
+       for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
+               awe_poke(AWE_DCYSUSV(ch), 0x80);
+       }
+  
+       /* reset all other parameters to zero */
+       for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
+               awe_poke(AWE_ENVVOL(ch), 0);
+               awe_poke(AWE_ENVVAL(ch), 0);
+               awe_poke(AWE_DCYSUS(ch), 0);
+               awe_poke(AWE_ATKHLDV(ch), 0);
+               awe_poke(AWE_LFO1VAL(ch), 0);
+               awe_poke(AWE_ATKHLD(ch), 0);
+               awe_poke(AWE_LFO2VAL(ch), 0);
+               awe_poke(AWE_IP(ch), 0);
+               awe_poke(AWE_IFATN(ch), 0);
+               awe_poke(AWE_PEFE(ch), 0);
+               awe_poke(AWE_FMMOD(ch), 0);
+               awe_poke(AWE_TREMFRQ(ch), 0);
+               awe_poke(AWE_FM2FRQ2(ch), 0);
+               awe_poke_dw(AWE_PTRX(ch), 0);
+               awe_poke_dw(AWE_VTFT(ch), 0);
+               awe_poke_dw(AWE_PSST(ch), 0);
+               awe_poke_dw(AWE_CSL(ch), 0);
+               awe_poke_dw(AWE_CCCA(ch), 0);
+       }
+
+       for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
+               awe_poke_dw(AWE_CPF(ch), 0);
+               awe_poke_dw(AWE_CVCF(ch), 0);
+       }
+}
+
+
+/* initialize DMA address */
+static void
+awe_init_dma(void)
+{
+       awe_poke_dw(AWE_SMALR, 0);
+       awe_poke_dw(AWE_SMARR, 0);
+       awe_poke_dw(AWE_SMALW, 0);
+       awe_poke_dw(AWE_SMARW, 0);
+}
+
+
+/* initialization arrays; from ADIP */
+
+static unsigned short init1[128] = {
+       0x03ff, 0x0030,  0x07ff, 0x0130, 0x0bff, 0x0230,  0x0fff, 0x0330,
+       0x13ff, 0x0430,  0x17ff, 0x0530, 0x1bff, 0x0630,  0x1fff, 0x0730,
+       0x23ff, 0x0830,  0x27ff, 0x0930, 0x2bff, 0x0a30,  0x2fff, 0x0b30,
+       0x33ff, 0x0c30,  0x37ff, 0x0d30, 0x3bff, 0x0e30,  0x3fff, 0x0f30,
+
+       0x43ff, 0x0030,  0x47ff, 0x0130, 0x4bff, 0x0230,  0x4fff, 0x0330,
+       0x53ff, 0x0430,  0x57ff, 0x0530, 0x5bff, 0x0630,  0x5fff, 0x0730,
+       0x63ff, 0x0830,  0x67ff, 0x0930, 0x6bff, 0x0a30,  0x6fff, 0x0b30,
+       0x73ff, 0x0c30,  0x77ff, 0x0d30, 0x7bff, 0x0e30,  0x7fff, 0x0f30,
+
+       0x83ff, 0x0030,  0x87ff, 0x0130, 0x8bff, 0x0230,  0x8fff, 0x0330,
+       0x93ff, 0x0430,  0x97ff, 0x0530, 0x9bff, 0x0630,  0x9fff, 0x0730,
+       0xa3ff, 0x0830,  0xa7ff, 0x0930, 0xabff, 0x0a30,  0xafff, 0x0b30,
+       0xb3ff, 0x0c30,  0xb7ff, 0x0d30, 0xbbff, 0x0e30,  0xbfff, 0x0f30,
+
+       0xc3ff, 0x0030,  0xc7ff, 0x0130, 0xcbff, 0x0230,  0xcfff, 0x0330,
+       0xd3ff, 0x0430,  0xd7ff, 0x0530, 0xdbff, 0x0630,  0xdfff, 0x0730,
+       0xe3ff, 0x0830,  0xe7ff, 0x0930, 0xebff, 0x0a30,  0xefff, 0x0b30,
+       0xf3ff, 0x0c30,  0xf7ff, 0x0d30, 0xfbff, 0x0e30,  0xffff, 0x0f30,
+};
+
+static unsigned short init2[128] = {
+       0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
+       0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
+       0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
+       0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
+
+       0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
+       0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
+       0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
+       0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
+
+       0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
+       0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
+       0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
+       0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
+
+       0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
+       0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
+       0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
+       0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
+};
+
+static unsigned short init3[128] = {
+       0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
+       0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
+       0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
+       0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
+
+       0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
+       0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
+       0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
+       0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
+
+       0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
+       0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
+       0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
+       0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
+
+       0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
+       0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
+       0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
+       0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
+};
+
+static unsigned short init4[128] = {
+       0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
+       0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
+       0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
+       0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
+
+       0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
+       0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
+       0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
+       0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
+
+       0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
+       0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
+       0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
+       0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
+
+       0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
+       0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
+       0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
+       0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
+};
+
+
+/* send initialization arrays to start up */
+static void
+awe_init_array(void)
+{
+       awe_send_array(init1);
+       awe_wait(1024);
+       awe_send_array(init2);
+       awe_send_array(init3);
+       awe_poke_dw(AWE_HWCF4, 0);
+       awe_poke_dw(AWE_HWCF5, 0x83);
+       awe_poke_dw(AWE_HWCF6, 0x8000);
+       awe_send_array(init4);
+}
+
+/* send an initialization array */
+static void
+awe_send_array(unsigned short *data)
+{
+       int i;
+       unsigned short *p;
+
+       p = data;
+       for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+               awe_poke(AWE_INIT1(i), *p);
+       for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+               awe_poke(AWE_INIT2(i), *p);
+       for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+               awe_poke(AWE_INIT3(i), *p);
+       for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+               awe_poke(AWE_INIT4(i), *p);
+}
+
+
+/*
+ * set up awe32 channels to some known state.
+ */
+
+/* set the envelope & LFO parameters to the default values; see ADIP */
+static void
+awe_tweak_voice(int i)
+{
+       /* set all mod/vol envelope shape to minimum */
+       awe_poke(AWE_ENVVOL(i), 0x8000);
+       awe_poke(AWE_ENVVAL(i), 0x8000);
+       awe_poke(AWE_DCYSUS(i), 0x7F7F);
+       awe_poke(AWE_ATKHLDV(i), 0x7F7F);
+       awe_poke(AWE_ATKHLD(i), 0x7F7F);
+       awe_poke(AWE_PEFE(i), 0);  /* mod envelope height to zero */
+       awe_poke(AWE_LFO1VAL(i), 0x8000); /* no delay for LFO1 */
+       awe_poke(AWE_LFO2VAL(i), 0x8000);
+       awe_poke(AWE_IP(i), 0xE000);    /* no pitch shift */
+       awe_poke(AWE_IFATN(i), 0xFF00); /* volume to minimum */
+       awe_poke(AWE_FMMOD(i), 0);
+       awe_poke(AWE_TREMFRQ(i), 0);
+       awe_poke(AWE_FM2FRQ2(i), 0);
+}
+
+static void
+awe_tweak(void)
+{
+       int i;
+       /* reset all channels */
+       for (i = 0; i < awe_max_voices; i++)
+               awe_tweak_voice(i);
+}
+
+
+/*
+ *  initializes the FM section of AWE32;
+ *   see Vince Vu's unofficial AWE32 programming guide
+ */
+
+static void
+awe_init_fm(void)
+{
+#ifndef AWE_ALWAYS_INIT_FM
+       /* if no extended memory is on board.. */
+       if (awe_mem_size <= 0)
+               return;
+#endif
+       DEBUG(3,printk("AWE32: initializing FM\n"));
+
+       /* Initialize the last two channels for DRAM refresh and producing
+          the reverb and chorus effects for Yamaha OPL-3 synthesizer */
+
+       /* 31: FM left channel, 0xffffe0-0xffffe8 */
+       awe_poke(AWE_DCYSUSV(30), 0x80);
+       awe_poke_dw(AWE_PSST(30), 0xFFFFFFE0); /* full left */
+       awe_poke_dw(AWE_CSL(30), 0x00FFFFE8 |
+                   (DEF_FM_CHORUS_DEPTH << 24));
+       awe_poke_dw(AWE_PTRX(30), (DEF_FM_REVERB_DEPTH << 8));
+       awe_poke_dw(AWE_CPF(30), 0);
+       awe_poke_dw(AWE_CCCA(30), 0x00FFFFE3);
+
+       /* 32: FM right channel, 0xfffff0-0xfffff8 */
+       awe_poke(AWE_DCYSUSV(31), 0x80);
+       awe_poke_dw(AWE_PSST(31), 0x00FFFFF0); /* full right */
+       awe_poke_dw(AWE_CSL(31), 0x00FFFFF8 |
+                   (DEF_FM_CHORUS_DEPTH << 24));
+       awe_poke_dw(AWE_PTRX(31), (DEF_FM_REVERB_DEPTH << 8));
+       awe_poke_dw(AWE_CPF(31), 0x8000);
+       awe_poke_dw(AWE_CCCA(31), 0x00FFFFF3);
+
+       /* skew volume & cutoff */
+       awe_poke_dw(AWE_VTFT(30), 0x8000FFFF);
+       awe_poke_dw(AWE_VTFT(31), 0x8000FFFF);
+
+       voices[30].state = AWE_ST_FM;
+       voices[31].state = AWE_ST_FM;
+
+       /* change maximum channels to 30 */
+       awe_max_voices = AWE_NORMAL_VOICES;
+       if (playing_mode == AWE_PLAY_DIRECT)
+               awe_info.nr_voices = awe_max_voices;
+       else
+               awe_info.nr_voices = AWE_MAX_CHANNELS;
+       voice_alloc->max_voice = awe_max_voices;
+}
+
+/*
+ *  AWE32 DRAM access routines
+ */
+
+/* open DRAM write accessing mode */
+static int
+awe_open_dram_for_write(int offset, int channels)
+{
+       int vidx[AWE_NORMAL_VOICES];
+       int i;
+
+       if (channels < 0 || channels >= AWE_NORMAL_VOICES) {
+               channels = AWE_NORMAL_VOICES;
+               for (i = 0; i < AWE_NORMAL_VOICES; i++)
+                       vidx[i] = i;
+       } else {
+               for (i = 0; i < channels; i++) {
+                       vidx[i] = awe_clear_voice();
+                       voices[vidx[i]].state = AWE_ST_MARK;
+               }
+       }
+
+       /* use all channels for DMA transfer */
+       for (i = 0; i < channels; i++) {
+               if (vidx[i] < 0) continue;
+               awe_poke(AWE_DCYSUSV(vidx[i]), 0x80);
+               awe_poke_dw(AWE_VTFT(vidx[i]), 0);
+               awe_poke_dw(AWE_CVCF(vidx[i]), 0);
+               awe_poke_dw(AWE_PTRX(vidx[i]), 0x40000000);
+               awe_poke_dw(AWE_CPF(vidx[i]), 0x40000000);
+               awe_poke_dw(AWE_PSST(vidx[i]), 0);
+               awe_poke_dw(AWE_CSL(vidx[i]), 0);
+               awe_poke_dw(AWE_CCCA(vidx[i]), 0x06000000);
+               voices[vidx[i]].state = AWE_ST_DRAM;
+       }
+       /* point channels 31 & 32 to ROM samples for DRAM refresh */
+       awe_poke_dw(AWE_VTFT(30), 0);
+       awe_poke_dw(AWE_PSST(30), 0x1d8);
+       awe_poke_dw(AWE_CSL(30), 0x1e0);
+       awe_poke_dw(AWE_CCCA(30), 0x1d8);
+       awe_poke_dw(AWE_VTFT(31), 0);
+       awe_poke_dw(AWE_PSST(31), 0x1d8);
+       awe_poke_dw(AWE_CSL(31), 0x1e0);
+       awe_poke_dw(AWE_CCCA(31), 0x1d8);
+       voices[30].state = AWE_ST_FM;
+       voices[31].state = AWE_ST_FM;
+
+       /* if full bit is on, not ready to write on */
+       if (awe_peek_dw(AWE_SMALW) & 0x80000000) {
+               for (i = 0; i < channels; i++) {
+                       awe_poke_dw(AWE_CCCA(vidx[i]), 0);
+                       voices[vidx[i]].state = AWE_ST_OFF;
+               }
+               return -ENOSPC;
+       }
+
+       /* set address to write */
+       awe_poke_dw(AWE_SMALW, offset);
+
+       return 0;
+}
+
+/* open DRAM for RAM size detection */
+static void
+awe_open_dram_for_check(void)
+{
+       int i;
+       for (i = 0; i < AWE_NORMAL_VOICES; i++) {
+               awe_poke(AWE_DCYSUSV(i), 0x80);
+               awe_poke_dw(AWE_VTFT(i), 0);
+               awe_poke_dw(AWE_CVCF(i), 0);
+               awe_poke_dw(AWE_PTRX(i), 0x40000000);
+               awe_poke_dw(AWE_CPF(i), 0x40000000);
+               awe_poke_dw(AWE_PSST(i), 0);
+               awe_poke_dw(AWE_CSL(i), 0);
+               if (i & 1) /* DMA write */
+                       awe_poke_dw(AWE_CCCA(i), 0x06000000);
+               else       /* DMA read */
+                       awe_poke_dw(AWE_CCCA(i), 0x04000000);
+               voices[i].state = AWE_ST_DRAM;
+       }
+}
+
+
+/* close dram access */
+static void
+awe_close_dram(void)
+{
+       int i;
+       /* wait until FULL bit in SMAxW register be false */
+       for (i = 0; i < 10000; i++) {
+               if (!(awe_peek_dw(AWE_SMALW) & 0x80000000))
+                       break;
+               awe_wait(10);
+       }
+
+       for (i = 0; i < AWE_NORMAL_VOICES; i++) {
+               if (voices[i].state == AWE_ST_DRAM) {
+                       awe_poke_dw(AWE_CCCA(i), 0);
+                       awe_poke(AWE_DCYSUSV(i), 0x807F);
+                       voices[i].state = AWE_ST_OFF;
+               }
+       }
+}
+
+
+/*================================================================
+ * detect presence of AWE32 and check memory size
+ *================================================================*/
+
+/* detect emu8000 chip on the specified address; from VV's guide */
+
+static int
+awe_detect_base(int addr)
+{
+       setup_ports(addr, 0, 0);
+       if ((awe_peek(AWE_U1) & 0x000F) != 0x000C)
+               return 0;
+       if ((awe_peek(AWE_HWCF1) & 0x007E) != 0x0058)
+               return 0;
+       if ((awe_peek(AWE_HWCF2) & 0x0003) != 0x0003)
+               return 0;
+        DEBUG(0,printk("AWE32 found at %x\n", addr));
+       return 1;
+}
+       
+static int
+awe_detect(void)
+{
+       int base;
+
+       if (port_setuped) /* already initialized by PnP */
+               return 1;
+
+       if (awe_port) /* use default i/o port value */
+               setup_ports(awe_port, 0, 0);
+       else { /* probe it */
+               for (base = 0x620; base <= 0x680; base += 0x20)
+                       if (awe_detect_base(base))
+                               return 1;
+               DEBUG(0,printk("AWE32 not found\n"));
+               return 0;
+       }
+
+       return 1;
+}
+
+
+/*================================================================
+ * check dram size on AWE board
+ *================================================================*/
+
+/* any three numbers you like */
+#define UNIQUE_ID1     0x1234
+#define UNIQUE_ID2     0x4321
+#define UNIQUE_ID3     0xFFFF
+
+static void
+awe_check_dram(void)
+{
+       if (awe_present) /* already initialized */
+               return;
+
+       if (awe_mem_size >= 0) { /* given by config file or module option */
+               awe_mem_size *= 1024; /* convert to Kbytes */
+               return;
+       }
+
+       awe_open_dram_for_check();
+
+       awe_mem_size = 0;
+
+       /* set up unique two id numbers */
+       awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET);
+       awe_poke(AWE_SMLD, UNIQUE_ID1);
+       awe_poke(AWE_SMLD, UNIQUE_ID2);
+
+       while (awe_mem_size < AWE_MAX_DRAM_SIZE) {
+               awe_wait(5);
+               /* read a data on the DRAM start address */
+               awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET);
+               awe_peek(AWE_SMLD); /* discard stale data  */
+               if (awe_peek(AWE_SMLD) != UNIQUE_ID1)
+                       break;
+               if (awe_peek(AWE_SMLD) != UNIQUE_ID2)
+                       break;
+               awe_mem_size += 512;  /* increment 512kbytes */
+               /* Write a unique data on the test address;
+                * if the address is out of range, the data is written on
+                * 0x200000(=AWE_DRAM_OFFSET).  Then the two id words are
+                * broken by this data.
+                */
+               awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + awe_mem_size*512L);
+               awe_poke(AWE_SMLD, UNIQUE_ID3);
+               awe_wait(5);
+               /* read a data on the just written DRAM address */
+               awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + awe_mem_size*512L);
+               awe_peek(AWE_SMLD); /* discard stale data  */
+               if (awe_peek(AWE_SMLD) != UNIQUE_ID3)
+                       break;
+       }
+       awe_close_dram();
+
+       DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", awe_mem_size));
+
+       /* convert to Kbytes */
+       awe_mem_size *= 1024;
+}
+
+
+/*================================================================
+ * chorus and reverb controls; from VV's guide
+ *================================================================*/
+
+/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
+static char chorus_defined[AWE_CHORUS_NUMBERS];
+static awe_chorus_fx_rec chorus_parm[AWE_CHORUS_NUMBERS] = {
+       {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
+       {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
+       {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
+       {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
+       {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
+       {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
+       {0xE600, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay */
+       {0xE6C0, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay + feedback */
+};
+
+static int
+awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count)
+{
+       if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) {
+               printk("AWE32 Error: illegal chorus mode %d for uploading\n", patch->optarg);
+               return -EINVAL;
+       }
+       if (count < sizeof(awe_chorus_fx_rec)) {
+               printk("AWE32 Error: too short chorus fx parameters\n");
+               return -EINVAL;
+       }
+       copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
+                      sizeof(awe_chorus_fx_rec));
+       chorus_defined[patch->optarg] = TRUE;
+       return 0;
+}
+
+static void
+awe_set_chorus_mode(int effect)
+{
+       if (effect < 0 || effect >= AWE_CHORUS_NUMBERS ||
+           (effect >= AWE_CHORUS_PREDEFINED && !chorus_defined[effect]))
+               return;
+       awe_poke(AWE_INIT3(9), chorus_parm[effect].feedback);
+       awe_poke(AWE_INIT3(12), chorus_parm[effect].delay_offset);
+       awe_poke(AWE_INIT4(3), chorus_parm[effect].lfo_depth);
+       awe_poke_dw(AWE_HWCF4, chorus_parm[effect].delay);
+       awe_poke_dw(AWE_HWCF5, chorus_parm[effect].lfo_freq);
+       awe_poke_dw(AWE_HWCF6, 0x8000);
+       awe_poke_dw(AWE_HWCF7, 0x0000);
+}
+
+static void
+awe_update_chorus_mode(void)
+{
+       awe_set_chorus_mode(ctrls[AWE_MD_CHORUS_MODE]);
+}
+
+/*----------------------------------------------------------------*/
+
+/* reverb mode settings; write the following 28 data of 16 bit length
+ *   on the corresponding ports in the reverb_cmds array
+ */
+static char reverb_defined[AWE_CHORUS_NUMBERS];
+static awe_reverb_fx_rec reverb_parm[AWE_REVERB_NUMBERS] = {
+{{  /* room 1 */
+       0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
+       0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
+       0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
+       0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
+}},
+{{  /* room 2 */
+       0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
+       0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
+       0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
+       0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
+}},
+{{  /* room 3 */
+       0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
+       0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
+       0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
+       0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
+}},
+{{  /* hall 1 */
+       0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
+       0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
+       0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
+       0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
+}},
+{{  /* hall 2 */
+       0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
+       0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
+       0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
+       0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
+}},
+{{  /* plate */
+       0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
+       0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
+       0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
+       0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
+}},
+{{  /* delay */
+       0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
+       0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
+       0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
+       0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
+}},
+{{  /* panning delay */
+       0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
+       0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
+       0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
+       0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
+}},
+};
+
+static struct ReverbCmdPair {
+       unsigned short cmd, port;
+} reverb_cmds[28] = {
+  {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
+  {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
+  {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
+  {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
+  {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
+  {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
+  {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
+};
+
+static int
+awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count)
+{
+       if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) {
+               printk("AWE32 Error: illegal reverb mode %d for uploading\n", patch->optarg);
+               return -EINVAL;
+       }
+       if (count < sizeof(awe_reverb_fx_rec)) {
+               printk("AWE32 Error: too short reverb fx parameters\n");
+               return -EINVAL;
+       }
+       copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
+                      sizeof(awe_reverb_fx_rec));
+       reverb_defined[patch->optarg] = TRUE;
+       return 0;
+}
+
+static void
+awe_set_reverb_mode(int effect)
+{
+       int i;
+       if (effect < 0 || effect >= AWE_REVERB_NUMBERS ||
+           (effect >= AWE_REVERB_PREDEFINED && !reverb_defined[effect]))
+               return;
+       for (i = 0; i < 28; i++)
+               awe_poke(reverb_cmds[i].cmd, reverb_cmds[i].port,
+                        reverb_parm[effect].parms[i]);
+}
+
+static void
+awe_update_reverb_mode(void)
+{
+       awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]);
+}
+
+/*================================================================
+ * treble/bass equalizer control
+ *================================================================*/
+
+static unsigned short bass_parm[12][3] = {
+       {0xD26A, 0xD36A, 0x0000}, /* -12 dB */
+       {0xD25B, 0xD35B, 0x0000}, /*  -8 */
+       {0xD24C, 0xD34C, 0x0000}, /*  -6 */
+       {0xD23D, 0xD33D, 0x0000}, /*  -4 */
+       {0xD21F, 0xD31F, 0x0000}, /*  -2 */
+       {0xC208, 0xC308, 0x0001}, /*   0 (HW default) */
+       {0xC219, 0xC319, 0x0001}, /*  +2 */
+       {0xC22A, 0xC32A, 0x0001}, /*  +4 */
+       {0xC24C, 0xC34C, 0x0001}, /*  +6 */
+       {0xC26E, 0xC36E, 0x0001}, /*  +8 */
+       {0xC248, 0xC348, 0x0002}, /* +10 */
+       {0xC26A, 0xC36A, 0x0002}, /* +12 dB */
+};
+
+static unsigned short treble_parm[12][9] = {
+       {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
+       {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
+       {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
+       {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
+       {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
+       {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
+       {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
+       {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
+       {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
+       {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
+       {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
+       {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +12 dB */
+};
+
+
+/*
+ * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
+ */
+static void
+awe_equalizer(int bass, int treble)
+{
+       unsigned short w;
+
+       if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
+               return;
+       awe_poke(AWE_INIT4(0x01), bass_parm[bass][0]);
+       awe_poke(AWE_INIT4(0x11), bass_parm[bass][1]);
+       awe_poke(AWE_INIT3(0x11), treble_parm[treble][0]);
+       awe_poke(AWE_INIT3(0x13), treble_parm[treble][1]);
+       awe_poke(AWE_INIT3(0x1B), treble_parm[treble][2]);
+       awe_poke(AWE_INIT4(0x07), treble_parm[treble][3]);
+       awe_poke(AWE_INIT4(0x0B), treble_parm[treble][4]);
+       awe_poke(AWE_INIT4(0x0D), treble_parm[treble][5]);
+       awe_poke(AWE_INIT4(0x17), treble_parm[treble][6]);
+       awe_poke(AWE_INIT4(0x19), treble_parm[treble][7]);
+       w = bass_parm[bass][2] + treble_parm[treble][8];
+       awe_poke(AWE_INIT4(0x15), (unsigned short)(w + 0x0262));
+       awe_poke(AWE_INIT4(0x1D), (unsigned short)(w + 0x8362));
+}
+
+static void awe_update_equalizer(void)
+{
+       awe_equalizer(ctrls[AWE_MD_BASS_LEVEL], ctrls[AWE_MD_TREBLE_LEVEL]);
+}
+
+
+#ifdef CONFIG_AWE32_MIDIEMU
+
+/*================================================================
+ * Emu8000 MIDI Emulation
+ *================================================================*/
+
+/*================================================================
+ * midi queue record
+ *================================================================*/
+
+/* queue type */
+enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, };
+
+#define MAX_MIDIBUF    64
+
+/* midi status */
+typedef struct MidiStatus {
+       int queue;      /* queue type */
+       int qlen;       /* queue length */
+       int read;       /* chars read */
+       int status;     /* current status */
+       int chan;       /* current channel */
+       unsigned char buf[MAX_MIDIBUF];
+} MidiStatus;
+
+/* MIDI mode type */
+enum { MODE_GM, MODE_GS, MODE_XG, };
+
+/* NRPN / CC -> Emu8000 parameter converter */
+typedef struct {
+       int control;
+       int awe_effect;
+       unsigned short (*convert)(int val);
+} ConvTable;
+
+
+/*================================================================
+ * prototypes
+ *================================================================*/
+
+static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int));
+static void awe_midi_close(int dev);
+static int awe_midi_ioctl(int dev, unsigned cmd, caddr_t arg);
+static int awe_midi_outputc(int dev, unsigned char midi_byte);
+
+static void init_midi_status(MidiStatus *st);
+static void clear_rpn(void);
+static void get_midi_char(MidiStatus *st, int c);
+/*static void queue_varlen(MidiStatus *st, int c);*/
+static void special_event(MidiStatus *st, int c);
+static void queue_read(MidiStatus *st, int c);
+static void midi_note_on(MidiStatus *st);
+static void midi_note_off(MidiStatus *st);
+static void midi_key_pressure(MidiStatus *st);
+static void midi_channel_pressure(MidiStatus *st);
+static void midi_pitch_wheel(MidiStatus *st);
+static void midi_program_change(MidiStatus *st);
+static void midi_control_change(MidiStatus *st);
+static void midi_select_bank(MidiStatus *st, int val);
+static void midi_nrpn_event(MidiStatus *st);
+static void midi_rpn_event(MidiStatus *st);
+static void midi_detune(int chan, int coarse, int fine);
+static void midi_system_exclusive(MidiStatus *st);
+static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
+static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
+static int xg_control_change(MidiStatus *st, int cmd, int val);
+
+#define numberof(ary)  (sizeof(ary)/sizeof(ary[0]))
+
+
+/*================================================================
+ * OSS Midi device record
+ *================================================================*/
+
+static struct midi_operations awe_midi_operations =
+{
+       {"AWE Midi Emu", 0, 0, SNDCARD_SB},
+       NULL /*&std_midi_synth*/,
+       {0}, /* input_info */
+       awe_midi_open, /*open*/
+       awe_midi_close, /*close*/
+       awe_midi_ioctl, /*ioctl*/
+       awe_midi_outputc, /*outputc*/
+       NULL /*start_read*/,
+       NULL /*end_read*/,
+       NULL, /* kick */
+       NULL, /* command */
+};
+
+static int my_mididev = -1;
+
+static void attach_midiemu(void)
+{
+       if ((my_mididev = sound_alloc_mididev()) < 0)
+               printk ("Sound: Too many midi devices detected\n");
+       else
+               midi_devs[my_mididev] = &awe_midi_operations;
+}
+
+static void unload_midiemu(void)
+{
+       if (my_mididev >= 0)
+               sound_unload_mididev(my_mididev);
+}
+
+
+/*
+ * open/close midi device
+ */
+
+static int midi_opened = FALSE;
+
+static int midi_mode;
+static int coarsetune = 0, finetune = 0;
+
+static int xg_mapping = TRUE;
+static int xg_bankmode = 0;
+
+/* effect sensitivity */
+
+#define FX_CUTOFF      0
+#define FX_RESONANCE   1
+#define FX_ATTACK      2
+#define FX_RELEASE     3
+#define FX_VIBRATE     4
+#define FX_VIBDEPTH    5
+#define FX_VIBDELAY    6
+#define FX_NUMS                7
+
+#define DEF_FX_CUTOFF          170
+#define DEF_FX_RESONANCE       6
+#define DEF_FX_ATTACK          50
+#define DEF_FX_RELEASE         50
+#define DEF_FX_VIBRATE         30
+#define DEF_FX_VIBDEPTH                4
+#define DEF_FX_VIBDELAY                1500
+
+/* effect sense: */
+static int gs_sense[] = 
+{
+       DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
+       DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
+};
+static int xg_sense[] = 
+{
+       DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
+       DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
+};
+
+
+/* current status */
+static MidiStatus curst;
+
+
+static int
+awe_midi_open (int dev, int mode,
+              void (*input)(int,unsigned char),
+              void (*output)(int))
+{
+       if (midi_opened)
+               return -EBUSY;
+
+       midi_opened = TRUE;
+
+       midi_mode = MODE_GM;
+
+       curst.queue = Q_NONE;
+       curst.qlen = 0;
+       curst.read = 0;
+       curst.status = 0;
+       curst.chan = 0;
+       memset(curst.buf, 0, sizeof(curst.buf));
+
+       init_midi_status(&curst);
+
+       return 0;
+}
+
+static void
+awe_midi_close (int dev)
+{
+       midi_opened = FALSE;
+}
+
+
+static int
+awe_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
+{
+       return -EPERM;
+}
+
+static int
+awe_midi_outputc (int dev, unsigned char midi_byte)
+{
+       if (! midi_opened)
+               return 1;
+
+       /* force to change playing mode */
+       playing_mode = AWE_PLAY_MULTI;
+
+       get_midi_char(&curst, midi_byte);
+       return 1;
+}
+
+
+/*
+ * initialize
+ */
+
+static void init_midi_status(MidiStatus *st)
+{
+       clear_rpn();
+       coarsetune = 0;
+       finetune = 0;
+}
+
+
+/*
+ * RPN & NRPN
+ */
+
+#define MAX_MIDI_CHANNELS      16
+
+/* RPN & NRPN */
+static unsigned char nrpn[MAX_MIDI_CHANNELS];  /* current event is NRPN? */
+static int msb_bit;  /* current event is msb for RPN/NRPN */
+/* RPN & NRPN indeces */
+static unsigned char rpn_msb[MAX_MIDI_CHANNELS], rpn_lsb[MAX_MIDI_CHANNELS];
+/* RPN & NRPN values */
+static int rpn_val[MAX_MIDI_CHANNELS];
+
+static void clear_rpn(void)
+{
+       int i;
+       for (i = 0; i < MAX_MIDI_CHANNELS; i++) {
+               nrpn[i] = 0;
+               rpn_msb[i] = 127;
+               rpn_lsb[i] = 127;
+               rpn_val[i] = 0;
+       }
+       msb_bit = 0;
+}
+
+
+/*
+ * process midi queue
+ */
+
+/* status event types */
+typedef void (*StatusEvent)(MidiStatus *st);
+static struct StatusEventList {
+       StatusEvent process;
+       int qlen;
+} status_event[8] = {
+       {midi_note_off, 2},
+       {midi_note_on, 2},
+       {midi_key_pressure, 2},
+       {midi_control_change, 2},
+       {midi_program_change, 1},
+       {midi_channel_pressure, 1},
+       {midi_pitch_wheel, 2},
+       {NULL, 0},
+};
+
+
+/* read a char from fifo and process it */
+static void get_midi_char(MidiStatus *st, int c)
+{
+       if (c == 0xfe) {
+               /* ignore active sense */
+               st->queue = Q_NONE;
+               return;
+       }
+
+       switch (st->queue) {
+       /* case Q_VARLEN: queue_varlen(st, c); break;*/
+       case Q_READ:
+       case Q_SYSEX:
+               queue_read(st, c);
+               break;
+       case Q_NONE:
+               st->read = 0;
+               if ((c & 0xf0) == 0xf0) {
+                       special_event(st, c);
+               } else if (c & 0x80) { /* status change */
+                       st->status = (c >> 4) & 0x07;
+                       st->chan = c & 0x0f;
+                       st->queue = Q_READ;
+                       st->qlen = status_event[st->status].qlen;
+                       if (st->qlen == 0)
+                               st->queue = Q_NONE;
+               }
+               break;
+       }
+}
+
+/* 0xfx events */
+static void special_event(MidiStatus *st, int c)
+{
+       switch (c) {
+       case 0xf0: /* system exclusive */
+               st->queue = Q_SYSEX;
+               st->qlen = 0;
+               break;
+       case 0xf1: /* MTC quarter frame */
+       case 0xf3: /* song select */
+               st->queue = Q_READ;
+               st->qlen = 1;
+               break;
+       case 0xf2: /* song position */
+               st->queue = Q_READ;
+               st->qlen = 2;
+               break;
+       }
+}
+
+#if 0
+/* read variable length value */
+static void queue_varlen(MidiStatus *st, int c)
+{
+       st->qlen += (c & 0x7f);
+       if (c & 0x80) {
+               st->qlen <<= 7;
+               return;
+       }
+       if (st->qlen <= 0) {
+               st->qlen = 0;
+               st->queue = Q_NONE;
+       }
+       st->queue = Q_READ;
+       st->read = 0;
+}
+#endif
+
+
+/* read a char */
+static void queue_read(MidiStatus *st, int c)
+{
+       if (st->read < MAX_MIDIBUF) {
+               if (st->queue != Q_SYSEX)
+                       c &= 0x7f;
+               st->buf[st->read] = (unsigned char)c;
+       }
+       st->read++;
+       if (st->queue == Q_SYSEX && c == 0xf7) {
+               midi_system_exclusive(st);
+               st->queue = Q_NONE;
+       } else if (st->queue == Q_READ && st->read >= st->qlen) {
+               if (status_event[st->status].process)
+                       status_event[st->status].process(st);
+               st->queue = Q_NONE;
+       }
+}
+
+
+/*
+ * status events
+ */
+
+/* note on */
+static void midi_note_on(MidiStatus *st)
+{
+       DEBUG(2,printk("midi: note_on (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
+       if (st->buf[1] == 0)
+               midi_note_off(st);
+       else
+               awe_start_note(0, st->chan, st->buf[0], st->buf[1]);
+}
+
+/* note off */
+static void midi_note_off(MidiStatus *st)
+{
+       DEBUG(2,printk("midi: note_off (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
+       awe_kill_note(0, st->chan, st->buf[0], st->buf[1]);
+}
+
+/* key pressure change */
+static void midi_key_pressure(MidiStatus *st)
+{
+       awe_key_pressure(0, st->chan, st->buf[0], st->buf[1]);
+}
+
+/* channel pressure change */
+static void midi_channel_pressure(MidiStatus *st)
+{
+       channels[st->chan].chan_press = st->buf[0];
+       awe_modwheel_change(st->chan, st->buf[0]);
+}
+
+/* pitch wheel change */
+static void midi_pitch_wheel(MidiStatus *st)
+{
+       int val = (int)st->buf[1] * 128 + st->buf[0];
+       awe_bender(0, st->chan, val);
+}
+
+/* program change */
+static void midi_program_change(MidiStatus *st)
+{
+       int preset;
+       preset = st->buf[0];
+       if (midi_mode == MODE_GS && IS_DRUM_CHANNEL(st->chan) && preset == 127)
+               preset = 0;
+       else if (midi_mode == MODE_XG && xg_mapping && IS_DRUM_CHANNEL(st->chan))
+               preset += 64;
+
+       awe_set_instr(0, st->chan, preset);
+}
+
+#define send_effect(chan,type,val) awe_send_effect(chan,-1,type,val)
+#define add_effect(chan,type,val) awe_send_effect(chan,-1,(type)|0x80,val)
+#define unset_effect(chan,type) awe_send_effect(chan,-1,(type)|0x40,0)
+
+/* midi control change */
+static void midi_control_change(MidiStatus *st)
+{
+       int cmd = st->buf[0];
+       int val = st->buf[1];
+
+       DEBUG(2,printk("midi: control (%d) %d %d\n", st->chan, cmd, val));
+       if (midi_mode == MODE_XG) {
+               if (xg_control_change(st, cmd, val))
+                       return;
+       }
+
+       /* controls #31 - #64 are LSB of #0 - #31 */
+       msb_bit = 1;
+       if (cmd >= 0x20 && cmd < 0x40) {
+               msb_bit = 0;
+               cmd -= 0x20;
+       }
+
+       switch (cmd) {
+       case CTL_SOFT_PEDAL:
+               if (val == 127)
+                       add_effect(st->chan, AWE_FX_CUTOFF, -160);
+               else
+                       unset_effect(st->chan, AWE_FX_CUTOFF);
+               break;
+
+       case CTL_BANK_SELECT:
+               midi_select_bank(st, val);
+               break;
+               
+       /* set RPN/NRPN parameter */
+       case CTL_REGIST_PARM_NUM_MSB:
+               nrpn[st->chan]=0; rpn_msb[st->chan]=val;
+               break;
+       case CTL_REGIST_PARM_NUM_LSB:
+               nrpn[st->chan]=0; rpn_lsb[st->chan]=val;
+               break;
+       case CTL_NONREG_PARM_NUM_MSB:
+               nrpn[st->chan]=1; rpn_msb[st->chan]=val;
+               break;
+       case CTL_NONREG_PARM_NUM_LSB:
+               nrpn[st->chan]=1; rpn_lsb[st->chan]=val;
+               break;
+
+       /* send RPN/NRPN entry */
+       case CTL_DATA_ENTRY:
+               if (msb_bit)
+                       rpn_val[st->chan] = val * 128;
+               else
+                       rpn_val[st->chan] |= val;
+               if (nrpn[st->chan])
+                       midi_nrpn_event(st);
+               else
+                       midi_rpn_event(st);
+               break;
+
+       /* increase/decrease data entry */
+       case CTL_DATA_INCREMENT:
+               rpn_val[st->chan]++;
+               midi_rpn_event(st);
+               break;
+       case CTL_DATA_DECREMENT:
+               rpn_val[st->chan]--;
+               midi_rpn_event(st);
+               break;
+
+       /* default */
+       default:
+               awe_controller(0, st->chan, cmd, val);
+               break;
+       }
+}
+
+/* tone bank change */
+static void midi_select_bank(MidiStatus *st, int val)
+{
+       if (midi_mode == MODE_XG && msb_bit) {
+               xg_bankmode = val;
+               /* XG MSB value; not normal bank selection */
+               switch (val) {
+               case 127: /* remap to drum channel */
+                       awe_controller(0, st->chan, CTL_BANK_SELECT, 128);
+                       break;
+               default: /* remap to normal channel */
+                       awe_controller(0, st->chan, CTL_BANK_SELECT, val);
+                       break;
+               }
+               return;
+       } else if (midi_mode == MODE_GS && !msb_bit)
+               /* ignore LSB bank in GS mode (used for mapping) */
+               return;
+
+       /* normal bank controls; accept both MSB and LSB */
+       if (! IS_DRUM_CHANNEL(st->chan)) {
+               if (midi_mode == MODE_XG) {
+                       if (xg_bankmode) return;
+                       if (val == 64 || val == 126)
+                               val = 0;
+               } else if (midi_mode == MODE_GS && val == 127)
+                       val = 0;
+               awe_controller(0, st->chan, CTL_BANK_SELECT, val);
+       }
+}
+
+
+/*================================================================
+ * RPN events
+ *================================================================*/
+
+static void midi_rpn_event(MidiStatus *st)
+{
+       int type;
+       type = (rpn_msb[st->chan]<<8) | rpn_lsb[st->chan];
+       switch (type) {
+       case 0x0000: /* Pitch bend sensitivity */
+               /* MSB only / 1 semitone per 128 */
+               if (msb_bit) {
+                       channels[st->chan].bender_range = 
+                               rpn_val[st->chan] * 100 / 128;
+               }
+               break;
+                                       
+       case 0x0001: /* fine tuning: */
+               /* MSB/LSB, 8192=center, 100/8192 cent step */
+               finetune = rpn_val[st->chan] - 8192;
+               midi_detune(st->chan, coarsetune, finetune);
+               break;
+
+       case 0x0002: /* coarse tuning */
+               /* MSB only / 8192=center, 1 semitone per 128 */
+               if (msb_bit) {
+                       coarsetune = rpn_val[st->chan] - 8192;
+                       midi_detune(st->chan, coarsetune, finetune);
+               }
+               break;
+
+       case 0x7F7F: /* "lock-in" RPN */
+               break;
+       }
+}
+
+
+/* tuning:
+ *   coarse = -8192 to 8192 (100 cent per 128)
+ *   fine = -8192 to 8192 (max=100cent)
+ */
+static void midi_detune(int chan, int coarse, int fine)
+{
+       /* 4096 = 1200 cents in AWE parameter */
+       int val;
+       val = coarse * 4096 / (12 * 128);
+       val += fine / 24;
+       if (val)
+               send_effect(chan, AWE_FX_INIT_PITCH, val);
+       else
+               unset_effect(chan, AWE_FX_INIT_PITCH);
+}
+
+
+/*================================================================
+ * system exclusive message
+ * GM/GS/XG macros are accepted
+ *================================================================*/
+
+static void midi_system_exclusive(MidiStatus *st)
+{
+       /* GM on */
+       static unsigned char gm_on_macro[] = {
+               0x7e,0x7f,0x09,0x01,
+       };
+       /* XG on */
+       static unsigned char xg_on_macro[] = {
+               0x43,0x10,0x4c,0x00,0x00,0x7e,0x00,
+       };
+       /* GS prefix
+        * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off
+        * reverb mode: XX=0x01, YY=0x30, ZZ=0-7
+        * chorus mode: XX=0x01, YY=0x38, ZZ=0-7
+        */
+       static unsigned char gs_pfx_macro[] = {
+               0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/
+       };
+
+#if 0
+       /* SC88 system mode set
+        * single module mode: XX=1
+        * double module mode: XX=0
+        */
+       static unsigned char gs_mode_macro[] = {
+               0x41,0x10,0x42,0x12,0x00,0x00,0x7F,/*ZZ*/
+       };
+       /* SC88 display macro: XX=01:bitmap, 00:text
+        */
+       static unsigned char gs_disp_macro[] = {
+               0x41,0x10,0x45,0x12,0x10,/*XX,00*/
+       };
+#endif
+
+       /* GM on */
+       if (memcmp(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) {
+               if (midi_mode != MODE_GS && midi_mode != MODE_XG)
+                       midi_mode = MODE_GM;
+               init_midi_status(st);
+       }
+
+       /* GS macros */
+       else if (memcmp(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) {
+               if (midi_mode != MODE_GS && midi_mode != MODE_XG)
+                       midi_mode = MODE_GS;
+
+               if (st->buf[5] == 0x00 && st->buf[6] == 0x7f && st->buf[7] == 0x00) {
+                       /* GS reset */
+                       init_midi_status(st);
+               }
+
+               else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x15) {
+                       /* drum pattern */
+                       int p = st->buf[5] & 0x0f;
+                       if (p == 0) p = 9;
+                       else if (p < 10) p--;
+                       if (st->buf[7] == 0)
+                               DRUM_CHANNEL_OFF(p);
+                       else
+                               DRUM_CHANNEL_ON(p);
+
+               } else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x21) {
+                       /* program */
+                       int p = st->buf[5] & 0x0f;
+                       if (p == 0) p = 9;
+                       else if (p < 10) p--;
+                       if (! IS_DRUM_CHANNEL(p))
+                               awe_set_instr(0, p, st->buf[7]);
+
+               } else if (st->buf[5] == 0x01 && st->buf[6] == 0x30) {
+                       /* reverb mode */
+                       awe_set_reverb_mode(st->buf[7]);
+
+               } else if (st->buf[5] == 0x01 && st->buf[6] == 0x38) {
+                       /* chorus mode */
+                       awe_set_chorus_mode(st->buf[7]);
+
+               } else if (st->buf[5] == 0x00 && st->buf[6] == 0x04) {
+                       /* master volume */
+                       awe_change_master_volume(st->buf[7]);
+
+               }
+       }
+
+       /* XG on */
+       else if (memcmp(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) {
+               midi_mode = MODE_XG;
+               xg_mapping = TRUE;
+               xg_bankmode = 0;
+       }
+}
+
+
+/*
+ * convert NRPN/control values
+ */
+
+static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
+{
+       int i, cval;
+       for (i = 0; i < num_tables; i++) {
+               if (table[i].control == type) {
+                       cval = table[i].convert(val);
+                       send_effect(st->chan, table[i].awe_effect, cval);
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
+{
+       int i, cval;
+       for (i = 0; i < num_tables; i++) {
+               if (table[i].control == type) {
+                       cval = table[i].convert(val);
+                       add_effect(st->chan, table[i].awe_effect|0x80, cval);
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+
+/*
+ * AWE32 NRPN effects
+ */
+
+static unsigned short fx_delay(int val);
+static unsigned short fx_attack(int val);
+static unsigned short fx_hold(int val);
+static unsigned short fx_decay(int val);
+static unsigned short fx_the_value(int val);
+static unsigned short fx_twice_value(int val);
+static unsigned short fx_conv_pitch(int val);
+static unsigned short fx_conv_Q(int val);
+
+/* function for each NRPN */           /* [range]  units */
+#define fx_env1_delay  fx_delay        /* [0,5900] 4msec */
+#define fx_env1_attack fx_attack       /* [0,5940] 1msec */
+#define fx_env1_hold   fx_hold         /* [0,8191] 1msec */
+#define fx_env1_decay  fx_decay        /* [0,5940] 4msec */
+#define fx_env1_release        fx_decay        /* [0,5940] 4msec */
+#define fx_env1_sustain        fx_the_value    /* [0,127] 0.75dB */
+#define fx_env1_pitch  fx_the_value    /* [-127,127] 9.375cents */
+#define fx_env1_cutoff fx_the_value    /* [-127,127] 56.25cents */
+
+#define fx_env2_delay  fx_delay        /* [0,5900] 4msec */
+#define fx_env2_attack fx_attack       /* [0,5940] 1msec */
+#define fx_env2_hold   fx_hold         /* [0,8191] 1msec */
+#define fx_env2_decay  fx_decay        /* [0,5940] 4msec */
+#define fx_env2_release        fx_decay        /* [0,5940] 4msec */
+#define fx_env2_sustain        fx_the_value    /* [0,127] 0.75dB */
+
+#define fx_lfo1_delay  fx_delay        /* [0,5900] 4msec */
+#define fx_lfo1_freq   fx_twice_value  /* [0,127] 84mHz */
+#define fx_lfo1_volume fx_twice_value  /* [0,127] 0.1875dB */
+#define fx_lfo1_pitch  fx_the_value    /* [-127,127] 9.375cents */
+#define fx_lfo1_cutoff fx_twice_value  /* [-64,63] 56.25cents */
+
+#define fx_lfo2_delay  fx_delay        /* [0,5900] 4msec */
+#define fx_lfo2_freq   fx_twice_value  /* [0,127] 84mHz */
+#define fx_lfo2_pitch  fx_the_value    /* [-127,127] 9.375cents */
+
+#define fx_init_pitch  fx_conv_pitch   /* [-8192,8192] cents */
+#define fx_chorus      fx_the_value    /* [0,255] -- */
+#define fx_reverb      fx_the_value    /* [0,255] -- */
+#define fx_cutoff      fx_twice_value  /* [0,127] 62Hz */
+#define fx_filterQ     fx_conv_Q       /* [0,127] -- */
+
+static unsigned short fx_delay(int val)
+{
+       return (unsigned short)calc_parm_delay(val);
+}
+
+static unsigned short fx_attack(int val)
+{
+       return (unsigned short)calc_parm_attack(val);
+}
+
+static unsigned short fx_hold(int val)
+{
+       return (unsigned short)calc_parm_hold(val);
+}
+
+static unsigned short fx_decay(int val)
+{
+       return (unsigned short)calc_parm_decay(val);
+}
+
+static unsigned short fx_the_value(int val)
+{
+       return (unsigned short)(val & 0xff);
+}
+
+static unsigned short fx_twice_value(int val)
+{
+       return (unsigned short)((val * 2) & 0xff);
+}
+
+static unsigned short fx_conv_pitch(int val)
+{
+       return (short)(val * 4096 / 1200);
+}
+
+static unsigned short fx_conv_Q(int val)
+{
+       return (unsigned short)((val / 8) & 0xff);
+}
+
+
+static ConvTable awe_effects[] =
+{
+       { 0, AWE_FX_LFO1_DELAY, fx_lfo1_delay},
+       { 1, AWE_FX_LFO1_FREQ,  fx_lfo1_freq},
+       { 2, AWE_FX_LFO2_DELAY, fx_lfo2_delay},
+       { 3, AWE_FX_LFO2_FREQ,  fx_lfo2_freq},
+
+       { 4, AWE_FX_ENV1_DELAY, fx_env1_delay},
+       { 5, AWE_FX_ENV1_ATTACK,fx_env1_attack},
+       { 6, AWE_FX_ENV1_HOLD,  fx_env1_hold},
+       { 7, AWE_FX_ENV1_DECAY, fx_env1_decay},
+       { 8, AWE_FX_ENV1_SUSTAIN,       fx_env1_sustain},
+       { 9, AWE_FX_ENV1_RELEASE,       fx_env1_release},
+
+       {10, AWE_FX_ENV2_DELAY, fx_env2_delay},
+       {11, AWE_FX_ENV2_ATTACK,        fx_env2_attack},
+       {12, AWE_FX_ENV2_HOLD,  fx_env2_hold},
+       {13, AWE_FX_ENV2_DECAY, fx_env2_decay},
+       {14, AWE_FX_ENV2_SUSTAIN,       fx_env2_sustain},
+       {15, AWE_FX_ENV2_RELEASE,       fx_env2_release},
+
+       {16, AWE_FX_INIT_PITCH, fx_init_pitch},
+       {17, AWE_FX_LFO1_PITCH, fx_lfo1_pitch},
+       {18, AWE_FX_LFO2_PITCH, fx_lfo2_pitch},
+       {19, AWE_FX_ENV1_PITCH, fx_env1_pitch},
+       {20, AWE_FX_LFO1_VOLUME,        fx_lfo1_volume},
+       {21, AWE_FX_CUTOFF,             fx_cutoff},
+       {22, AWE_FX_FILTERQ,    fx_filterQ},
+       {23, AWE_FX_LFO1_CUTOFF,        fx_lfo1_cutoff},
+       {24, AWE_FX_ENV1_CUTOFF,        fx_env1_cutoff},
+       {25, AWE_FX_CHORUS,             fx_chorus},
+       {26, AWE_FX_REVERB,             fx_reverb},
+};
+
+static int num_awe_effects = numberof(awe_effects);
+
+
+/*
+ * GS(SC88) NRPN effects; still experimental
+ */
+
+/* cutoff: quarter semitone step, max=255 */
+static unsigned short gs_cutoff(int val)
+{
+       return (val - 64) * gs_sense[FX_CUTOFF] / 50;
+}
+
+/* resonance: 0 to 15(max) */
+static unsigned short gs_filterQ(int val)
+{
+       return (val - 64) * gs_sense[FX_RESONANCE] / 50;
+}
+
+/* attack: */
+static unsigned short gs_attack(int val)
+{
+       return -(val - 64) * gs_sense[FX_ATTACK] / 50;
+}
+
+/* decay: */
+static unsigned short gs_decay(int val)
+{
+       return -(val - 64) * gs_sense[FX_RELEASE] / 50;
+}
+
+/* release: */
+static unsigned short gs_release(int val)
+{
+       return -(val - 64) * gs_sense[FX_RELEASE] / 50;
+}
+
+/* vibrato freq: 0.042Hz step, max=255 */
+static unsigned short gs_vib_rate(int val)
+{
+       return (val - 64) * gs_sense[FX_VIBRATE] / 50;
+}
+
+/* vibrato depth: max=127, 1 octave */
+static unsigned short gs_vib_depth(int val)
+{
+       return (val - 64) * gs_sense[FX_VIBDEPTH] / 50;
+}
+
+/* vibrato delay: -0.725msec step */
+static unsigned short gs_vib_delay(int val)
+{
+       return -(val - 64) * gs_sense[FX_VIBDELAY] / 50;
+}
+
+static ConvTable gs_effects[] =
+{
+       {32, AWE_FX_CUTOFF,     gs_cutoff},
+       {33, AWE_FX_FILTERQ,    gs_filterQ},
+       {99, AWE_FX_ENV2_ATTACK, gs_attack},
+       {100, AWE_FX_ENV2_DECAY, gs_decay},
+       {102, AWE_FX_ENV2_RELEASE, gs_release},
+       {8, AWE_FX_LFO1_FREQ, gs_vib_rate},
+       {9, AWE_FX_LFO1_VOLUME, gs_vib_depth},
+       {10, AWE_FX_LFO1_DELAY, gs_vib_delay},
+};
+
+static int num_gs_effects = numberof(gs_effects);
+
+
+/*================================================================
+ * NRPN events: accept as AWE32/SC88 specific controls
+ *================================================================*/
+
+static void midi_nrpn_event(MidiStatus *st)
+{
+       if (rpn_msb[st->chan] == 127 && rpn_lsb[st->chan] <= 26) {
+               if (! msb_bit) /* both MSB/LSB necessary */
+                       send_converted_effect(awe_effects, num_awe_effects,
+                                             st, rpn_lsb[st->chan],
+                                             rpn_val[st->chan] - 8192);
+       } else if (rpn_msb[st->chan] == 1) {
+               if (msb_bit) /* only MSB is valid */
+                       add_converted_effect(gs_effects, num_gs_effects,
+                                            st, rpn_lsb[st->chan],
+                                            rpn_val[st->chan] / 128);
+       }
+}
+
+
+/*----------------------------------------------------------------
+ * XG control effects; still experimental
+ *----------------------------------------------------------------*/
+
+/* cutoff: quarter semitone step, max=255 */
+static unsigned short xg_cutoff(int val)
+{
+       return (val - 64) * xg_sense[FX_CUTOFF] / 64;
+}
+
+/* resonance: 0(open) to 15(most nasal) */
+static unsigned short xg_filterQ(int val)
+{
+       return (val - 64) * xg_sense[FX_RESONANCE] / 64;
+}
+
+/* attack: */
+static unsigned short xg_attack(int val)
+{
+       return -(val - 64) * xg_sense[FX_ATTACK] / 64;
+}
+
+/* release: */
+static unsigned short xg_release(int val)
+{
+       return -(val - 64) * xg_sense[FX_RELEASE] / 64;
+}
+
+static ConvTable xg_effects[] =
+{
+       {71, AWE_FX_CUTOFF,     xg_cutoff},
+       {74, AWE_FX_FILTERQ,    xg_filterQ},
+       {72, AWE_FX_ENV2_RELEASE, xg_release},
+       {73, AWE_FX_ENV2_ATTACK, xg_attack},
+};
+
+static int num_xg_effects = numberof(xg_effects);
+
+static int xg_control_change(MidiStatus *st, int cmd, int val)
+{
+       return add_converted_effect(xg_effects, num_xg_effects, st, cmd, val);
+}
+
+#endif /* CONFIG_AWE32_MIDIEMU */
+
+/* new type interface */
+static int __init attach_awe(void)
+{
+#ifdef CONFIG_PNP_DRV
+       if (pnp) {
+               awe_initpnp();
+               if (awe_pnp_ok)
+                       return 0;
+       }
+#endif /* pnp */
+       
+       _attach_awe();
+       
+       return 0;
+}                                                                      
+
+static void __exit unload_awe(void)                                                            
+{
+#ifdef CONFIG_PNP_DRV
+       if (pnp)
+               awe_unload_pnp();
+#endif
+       
+       _unload_awe();
+}
+
+module_init(attach_awe);
+module_exit(unload_awe);
+
+#ifndef MODULE
+static int __init setup_awe(char *str)
+{
+       /* io, memsize */
+       int ints[3];
+
+       str = get_options(str, ARRAY_SIZE(ints), ints);
+
+       io = ints[1];
+       memsize = ints[2];
+
+       return 1;
+}
+
+__setup("awe=", setup_awe);
+#endif
diff --git a/drivers/sound/awe_wave.h b/drivers/sound/awe_wave.h
new file mode 100644 (file)
index 0000000..0984da7
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * sound/awe_config.h
+ *
+ * Configuration of AWE32/SB32/AWE64 wave table synth driver.
+ *   version 0.4.3; Mar. 1, 1998
+ *
+ * Copyright (C) 1996-1998 Takashi Iwai
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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.
+ */
+
+/*
+ * chorus & reverb effects send for FM chip: from 0 to 0xff
+ * larger numbers often cause weird sounds.
+ */
+
+#define DEF_FM_CHORUS_DEPTH    0x10
+#define DEF_FM_REVERB_DEPTH    0x10
+
+
+/*
+ * other compile conditions
+ */
+
+/* initialize FM passthrough even without extended RAM */
+#undef AWE_ALWAYS_INIT_FM
+
+/* debug on */
+#define AWE_DEBUG_ON
+
+/* GUS compatible mode */
+#define AWE_HAS_GUS_COMPATIBILITY
+
+/* add MIDI emulation by wavetable */
+#define CONFIG_AWE32_MIDIEMU
+
+/* add mixer control of emu8000 equalizer */
+#undef CONFIG_AWE32_MIXER
+
+/* use new volume calculation method as default */
+#define AWE_USE_NEW_VOLUME_CALC
+
+/* check current volume target for searching empty voices */
+#define AWE_CHECK_VTARGET
+
+/* allow sample sharing */
+#define AWE_ALLOW_SAMPLE_SHARING
+
+/*
+ * AWE32 card configuration:
+ * uncomment the following lines *ONLY* when auto detection doesn't
+ * work properly on your machine.
+ */
+
+/*#define AWE_DEFAULT_BASE_ADDR        0x620*/ /* base port address */
+/*#define AWE_DEFAULT_MEM_SIZE 512*/   /* kbytes */
+
+/*
+ * maximum size of soundfont list table
+ */
+
+#define AWE_MAX_SF_LISTS 16
+
+/*
+ * chunk size of sample and voice tables
+ */
+
+#define AWE_MAX_SAMPLES 400
+#define AWE_MAX_INFOS 800
+
+#define AWE_MAJOR_VERSION      0
+#define AWE_MINOR_VERSION      4
+#define AWE_TINY_VERSION       3
+#define AWE_VERSION_NUMBER     ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION)
+#define AWEDRV_VERSION         "0.4.3"
diff --git a/drivers/sound/lowlevel/Config.in b/drivers/sound/lowlevel/Config.in
deleted file mode 100644 (file)
index 091a8df..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-dep_tristate '  ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND_OSS
-
-dep_tristate '  AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND_OSS
-
-if [ "$CONFIG_AWE32_SYNTH" = "y" -o "$CONFIG_AWE32_SYNTH" = "m" ]; then
-   comment 'AWE32 PnP-ISA Cards are not always setup correctly'
-   bool 'Configure AWE32 synth Base Address and Default Memory Size' CONFIG_AWE32_SYNTH_DEFAULTS
-   if [ "$CONFIG_AWE32_SYNTH_DEFAULTS" = "y" ]; then
-      hex 'AWE32 synth Base Address 620' AWE_DEFAULT_BASE_ADDR 620
-      int 'AWE32 synth Default Memory Size 512 1024 or 4096' AWE_DEFAULT_MEM_SIZE 512
-   fi
-fi
-
-if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND" = "m" ]; then
-   dep_tristate '  Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND_OSS
-   if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
-      hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
-      hex 'I/O base for MPU401 Check from manual of the card' CONFIG_MPU_BASE 330
-   fi
-
-   if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
-      comment 'SC-6600 Audio Cards have no jumper switches at all'
-      bool '    SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600
-      if [ "$CONFIG_SC6600" = "y" ]; then
-        comment 'SC-6600 specific configuration'
-        bool '      Activate SC-6600 Joystick Interface' CONFIG_SC6600_JOY
-        int 'SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)' CONFIG_SC6600_CDROM 4
-        hex 'SC-6600 CDROM Interface I/O Address' CONFIG_SC6600_CDROMBASE 0
-      fi
-
-      if [ "$CONFIG_SOUND_SB" = "y" -o "$CONFIG_SOUND_SB" = "m" ]; then
-        if [ "$CONFIG_AEDSP16_MSS" != "y" ]; then
-           bool 'Audio Excel DSP 16 (SBPro emulation)' CONFIG_AEDSP16_SBPRO
-           if [ "$CONFIG_AEDSP16_SBPRO" = "y" ]; then
-              comment 'Audio Excel DSP 16 [Sound Blaster Pro]'
-              hex 'I/O base for Audio Excel DSP 16 220, 240' CONFIG_AEDSP16_BASE $CONFIG_SB_BASE 220
-              int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ 5
-              int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA 0
-           fi
-        fi
-      fi
-
-      if [ "$CONFIG_SOUND_MSS" = "y" -o "$CONFIG_SOUND_MSS" = "m" ]; then
-        if [ "$CONFIG_AEDSP16_SBPRO" != "y" ]; then
-           bool '    Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS
-           if [ "$CONFIG_AEDSP16_MSS" = "y" ]; then
-              comment 'Audio Excel DSP 16 [Microsoft Sound System]'
-              hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
-              int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ 5
-              int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA 1
-           fi
-        fi
-      fi
-
-      if [ "$CONFIG_SOUND_MPU401" = "y" -o "$CONFIG_SOUND_MPU401" = "m" ]; then
-        bool 'Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401
-        if [ "$CONFIG_AEDSP16_MPU401" = "y" ]; then
-           comment 'Audio Excel DSP 16 [MPU-401]'
-           if [ "$CONFIG_AEDSP16_SBPRO" != "y" -a "$CONFIG_AEDSP16_MSS" != "y" ]; then
-              hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
-           fi
-           int 'MPU401 IRQ for Audio Excel DSP 16 5, 7, 9, 10 or 0 (disable)' CONFIG_AEDSP16_MPU_IRQ $CONFIG_MPU_IRQ
-        fi
-      fi
-   fi
-fi
diff --git a/drivers/sound/lowlevel/Makefile b/drivers/sound/lowlevel/Makefile
deleted file mode 100644 (file)
index 921f103..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# Makefile for the Linux low-level sound card drivers.
-#
-# 11 Feb 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net>
-# Rewritten to use lists instead of if statements.
-
-export-objs                    := soundlow.o
-
-list-y                         :=
-list-m                         :=
-list-n                         :=
-list-                          :=
-
-obj-$(CONFIG_SOUND_OSS)                += soundlow.o
-obj-$(CONFIG_ACI_MIXER)                += aci.o
-obj-$(CONFIG_AEDSP16)          += aedsp16.o
-obj-$(CONFIG_AWE32_SYNTH)      += awe_wave.o
-
-O_TARGET       := lowlevel.o
-O_OBJS         := $(sort $(filter-out $(export-objs), $(obj-y)))
-OX_OBJS                := $(sort $(filter     $(export-objs), $(obj-y)))
-M_OBJS         := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS                := $(sort $(filter     $(export-objs), $(obj-m)))
-
-include $(TOPDIR)/Rules.make
diff --git a/drivers/sound/lowlevel/README b/drivers/sound/lowlevel/README
deleted file mode 100644 (file)
index da66e33..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Additional low level sound drivers for Linux
-============================================
-
-This directory contains some low level sound drivers.
-These drivers are used to be (when Linux sound drivers was OSS/Lite) external
-drivers, not maintained by Hannu Savolainen and not touched by him.
-Now things are changed: the new Linux sound driver code maintained by Alan Cox
-include these lowlevel drivers and they are no more neglected (thanks Alan).
-
-The following low level drivers are included:
-
-- ACI MIXER for miroPCM12 by Markus Kuhn
-  (mskuhn@cip.informatik.uni-erlangen.de).
-- Audio Excel DSP 16 initialization driver by Riccardo Facchetti
-  (fizban@tin.it)
-- SB32/AWE synthesizer driver (Emu8000) by Takashi Iwai
-  (iwai@dragon.mm.t.u-tokyo.ac.jp).
-
-You can find documentation for these drivers in the Documentation/sound
-directory.
-
-[ File edited 17.01.1999 - Riccardo Facchetti ]
diff --git a/drivers/sound/lowlevel/aci.c b/drivers/sound/lowlevel/aci.c
deleted file mode 100644 (file)
index fc71be4..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * Audio Command Interface (ACI) driver (sound/aci.c)
- *
- * ACI is a protocol used to communicate with the microcontroller on
- * some sound cards produced by miro, e.g. the miroSOUND PCM12 and
- * PCM20. The ACI has been developed for miro by Norberto Pellicci
- * <pellicci@home.com>. Special thanks to both him and miro for
- * providing the ACI specification.
- *
- * The main function of the ACI is to control the mixer and to get a
- * product identification. On the PCM20, ACI also controls the radio
- * tuner on this card, this is supported in the Video for Linux 
- * radio-miropcm20 driver.
- * 
- * This Voxware ACI driver currently only supports the ACI functions
- * on the miroSOUND PCM12 and PCM20 card. Support for miro sound cards 
- * with additional ACI functions can easily be added later.
- *
- * / NOTE / When compiling as a module, make sure to load the module 
- * after loading the mad16 module. The initialisation code expects the
- * MAD16 default mixer to be already available.
- *
- * / NOTE / When compiling as a module, make sure to load the module 
- * after loading the mad16 module. The initialisation code expects the
- * MAD16 default mixer to be already available.
- *
- * Revision history:
- *
- *   1995-11-10  Markus Kuhn <mskuhn@cip.informatik.uni-erlangen.de>
- *        First version written.
- *   1995-12-31  Markus Kuhn
- *        Second revision, general code cleanup.
- *   1996-05-16         Hannu Savolainen
- *       Integrated with other parts of the driver.
- *   1996-05-28  Markus Kuhn
- *        Initialize CS4231A mixer, make ACI first mixer,
- *        use new private mixer API for solo mode.
- *   1998-08-18  Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- *       Small modification to export ACI functions and 
- *       complete modularisation.
- */
-
-/*
- * Some driver specific information and features:
- *
- * This mixer driver identifies itself to applications as "ACI" in
- * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info).
- *
- * Proprietary mixer features that go beyond the standard OSS mixer
- * interface are:
- * 
- * Full duplex solo configuration:
- *
- *   int solo_mode;
- *   ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode);
- *
- *   solo_mode = 0: deactivate solo mode (default)
- *   solo_mode > 0: activate solo mode
- *                  With activated solo mode, the PCM input can not any
- *                  longer hear the signals produced by the PCM output.
- *                  Activating solo mode is important in duplex mode in order
- *                  to avoid feedback distortions.
- *   solo_mode < 0: do not change solo mode (just retrieve the status)
- *
- *   When the ioctl() returns 0, solo_mode contains the previous
- *   status (0 = deactivated, 1 = activated). If solo mode is not
- *   implemented on this card, ioctl() returns -1 and sets errno to
- *   EINVAL.
- *
- */
-
-#include <linux/config.h> /* for CONFIG_ACI_MIXER */
-#include <linux/module.h> 
-#include "lowlevel.h"
-#include "../sound_config.h"
-
-#if defined(CONFIG_ACI_MIXER) || defined(CONFIG_ACI_MIXER_MODULE)
-
-#undef  DEBUG             /* if defined, produce a verbose report via syslog */
-
-int aci_port = 0x354; /* as determined by bit 4 in the OPTi 929 MC4 register */
-unsigned char aci_idcode[2] = {0, 0};         /* manufacturer and product ID */
-unsigned char aci_version = 0;                       /* ACI firmware version */
-int aci_solo;                     /* status bit of the card that can't be    *
-                                   * checked with ACI versions prior to 0xb0 */
-
-static int aci_present = 0;
-
-#ifdef MODULE                  /* Whether the aci mixer is to be reset.    */
-int aci_reset = 0;             /* Default: don't reset if the driver is a  */
-MODULE_PARM(aci_reset,"i");
-#else                          /* module; use "insmod aci.o aci_reset=1" */
-int aci_reset = 1;             /* to override.                             */
-#endif
-
-
-#define COMMAND_REGISTER    (aci_port)
-#define STATUS_REGISTER     (aci_port + 1)
-#define BUSY_REGISTER       (aci_port + 2)
-
-/*
- * Wait until the ACI microcontroller has set the READYFLAG in the
- * Busy/IRQ Source Register to 0. This is required to avoid
- * overrunning the sound card microcontroller. We do a busy wait here,
- * because the microcontroller is not supposed to signal a busy
- * condition for more than a few clock cycles. In case of a time-out,
- * this function returns -1.
- *
- * This busy wait code normally requires less than 15 loops and
- * practically always less than 100 loops on my i486/DX2 66 MHz.
- *
- * Warning: Waiting on the general status flag after reseting the MUTE
- * function can take a VERY long time, because the PCM12 does some kind
- * of fade-in effect. For this reason, access to the MUTE function has
- * not been implemented at all.
- */
-
-static int busy_wait(void)
-{
-  long timeout;
-
-  for (timeout = 0; timeout < 10000000L; timeout++)
-    if ((inb_p(BUSY_REGISTER) & 1) == 0)
-      return 0;
-
-#ifdef DEBUG
-  printk("ACI: READYFLAG timed out.\n");
-#endif
-
-  return -1;
-}
-
-
-/*
- * Read the GENERAL STATUS register.
- */
-
-static int read_general_status(void)
-{
-  unsigned long flags;
-  int status;
-
-  save_flags(flags);
-  cli();
-  if (busy_wait()) { restore_flags(flags); return -1; }
-  status = (unsigned) inb_p(STATUS_REGISTER);
-  restore_flags(flags);
-  return status;
-}
-
-
-/*
- * The four ACI command types (implied, write, read and indexed) can
- * be sent to the microcontroller using the following four functions.
- * If a problem occurred, they return -1.
- */
-
-int aci_implied_cmd(unsigned char opcode)
-{
-  unsigned long flags;
-
-#ifdef DEBUG
-  printk("ACI: aci_implied_cmd(0x%02x)\n", opcode);
-#endif
-
-  save_flags(flags);
-  cli();
-  
-  if (read_general_status() < 0 || busy_wait()) {
-    restore_flags(flags);
-    return -1;
-  }
-  outb_p(opcode, COMMAND_REGISTER);
-
-  restore_flags(flags);
-  return 0;
-}
-
-
-int aci_write_cmd(unsigned char opcode, unsigned char parameter)
-{
-  unsigned long flags;
-  int status;
-
-#ifdef DEBUG
-  printk("ACI: aci_write_cmd(0x%02x, 0x%02x)\n", opcode, parameter);
-#endif
-
-  save_flags(flags);
-  cli();
-  
-  if (read_general_status() < 0 || busy_wait()) {
-    restore_flags(flags);
-    return -1;
-  }
-  outb_p(opcode, COMMAND_REGISTER);
-  if (busy_wait()) { restore_flags(flags); return -1; }
-  outb_p(parameter, COMMAND_REGISTER);
-
-  if ((status = read_general_status()) < 0) {
-    restore_flags(flags);
-    return -1;
-  }
-  /* polarity of the INVALID flag depends on ACI version */
-  if ((aci_version <  0xb0 && (status & 0x40) != 0) ||
-      (aci_version >= 0xb0 && (status & 0x40) == 0)) {
-    restore_flags(flags);
-    printk("ACI: invalid write command 0x%02x, 0x%02x.\n",
-          opcode, parameter);
-    return -1;
-  }
-
-  restore_flags(flags);
-  return 0;
-}
-
-/*
- * This write command send 2 parameters instead of one.
- * Only used in PCM20 radio frequency tuning control
- */
-
-int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2)
-{
-  unsigned long flags;
-  int status;
-
-#ifdef DEBUG
-  printk("ACI: aci_write_cmd_d(0x%02x, 0x%02x)\n", opcode, parameter, parameter2);
-#endif
-
-  save_flags(flags);
-  cli();
-  
-  if (read_general_status() < 0 || busy_wait()) {
-    restore_flags(flags);
-    return -1;
-  }
-  outb_p(opcode, COMMAND_REGISTER);
-  if (busy_wait()) { restore_flags(flags); return -1; }
-  outb_p(parameter, COMMAND_REGISTER);
-  if (busy_wait()) { restore_flags(flags); return -1; }
-  outb_p(parameter2, COMMAND_REGISTER);
-
-  if ((status = read_general_status()) < 0) {
-    restore_flags(flags);
-    return -1;
-  }
-  /* polarity of the INVALID flag depends on ACI version */
-  if ((aci_version <  0xb0 && (status & 0x40) != 0) ||
-      (aci_version >= 0xb0 && (status & 0x40) == 0)) {
-    restore_flags(flags);
-#if 0  /* Frequency tuning works, but the INVALID flag is set ??? */
-    printk("ACI: invalid write (double) command 0x%02x, 0x%02x, 0x%02x.\n",
-          opcode, parameter, parameter2);
-#endif
-    return -1;
-  }
-
-  restore_flags(flags);
-  return 0;
-}
-
-int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter)
-{
-  unsigned long flags;
-  int i = 0;
-
-  save_flags(flags);
-  cli();
-  
-  if (read_general_status() < 0) { restore_flags(flags); return -1; }
-  while (i < length) {
-    if (busy_wait()) { restore_flags(flags); return -1; }
-    outb_p(opcode, COMMAND_REGISTER);
-    if (busy_wait()) { restore_flags(flags); return -1; }
-    parameter[i++] = inb_p(STATUS_REGISTER);
-#ifdef DEBUG
-    if (i == 1)
-      printk("ACI: aci_read_cmd(0x%02x, %d) = 0x%02x\n", opcode, length,
-            parameter[i-1]);
-    else
-      printk("ACI: aci_read_cmd cont.: 0x%02x\n", parameter[i-1]);
-#endif
-  }
-
-  restore_flags(flags);
-  return 0;
-}
-
-
-int aci_indexed_cmd(unsigned char opcode, unsigned char index,
-                      unsigned char *parameter)
-{
-  unsigned long flags;
-
-  save_flags(flags);
-  cli();
-  
-  if (read_general_status() < 0 || busy_wait()) {
-    restore_flags(flags);
-    return -1;
-  }
-  outb_p(opcode, COMMAND_REGISTER);
-  if (busy_wait()) { restore_flags(flags); return -1; }
-  outb_p(index, COMMAND_REGISTER);
-  if (busy_wait()) { restore_flags(flags); return -1; }
-  *parameter = inb_p(STATUS_REGISTER);
-#ifdef DEBUG
-  printk("ACI: aci_indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index,
-        *parameter);
-#endif
-
-  restore_flags(flags);
-  return 0;
-}
-
-
-/*
- * The following macro SCALE can be used to scale one integer volume
- * value into another one using only integer arithmetic. If the input
- * value x is in the range 0 <= x <= xmax, then the result will be in
- * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
- *
- * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
- * following nice properties:
- *
- * - SCALE(xmax,ymax,xmax) = ymax
- * - SCALE(xmax,ymax,0) = 0
- * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
- *
- * In addition, the rounding error is minimal and nicely distributed.
- * The proofs are left as an exercise to the reader.
- */
-
-#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
-
-
-static int getvolume(caddr_t arg,
-                    unsigned char left_index, unsigned char right_index)
-{
-  int vol;
-  unsigned char buf;
-
-  /* left channel */
-  if (aci_indexed_cmd(0xf0, left_index, &buf)) return -EIO;
-  vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
-  /* right channel */
-  if (aci_indexed_cmd(0xf0, right_index, &buf)) return -EIO;
-  vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
-
-  return (*(int *) arg = vol);
-}
-
-
-static int setvolume(caddr_t arg, 
-                    unsigned char left_index, unsigned char right_index)
-{
-  int vol, ret;
-
-  /* left channel */
-  vol = *(int *)arg & 0xff;
-  if (vol > 100) vol = 100;
-  vol = SCALE(100, 0x20, vol);
-  if (aci_write_cmd(left_index, 0x20 - vol)) return -EIO;
-  ret = SCALE(0x20, 100, vol);
-  /* right channel */
-  vol = (*(int *)arg >> 8) & 0xff;
-  if (vol > 100) vol = 100;
-  vol = SCALE(100, 0x20, vol);
-  if (aci_write_cmd(right_index, 0x20 - vol)) return -EIO;
-  ret |= SCALE(0x20, 100, vol) << 8;
-  return (*(int *) arg = ret);
-}
-
-
-static int
-aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
-{
-  int status, vol;
-  unsigned char buf;
-
-  /* handle solo mode control */
-  if (cmd == SOUND_MIXER_PRIVATE1) {
-    if (*(int *) arg >= 0) {
-      aci_solo = !!*(int *) arg;
-      if (aci_write_cmd(0xd2, aci_solo)) return -EIO;
-    } else if (aci_version >= 0xb0) {
-      if ((status = read_general_status()) < 0) return -EIO;
-      return (*(int *) arg = (status & 0x20) == 0);
-    }
-    return (*(int *) arg = aci_solo);
-  }
-
-  if (((cmd >> 8) & 0xff) == 'M') {
-    if (cmd & IOC_IN)
-      /* read and write */
-      switch (cmd & 0xff) {
-      case SOUND_MIXER_VOLUME:
-       return setvolume(arg, 0x01, 0x00);
-      case SOUND_MIXER_CD:
-       return setvolume(arg, 0x3c, 0x34);
-      case SOUND_MIXER_MIC:
-       return setvolume(arg, 0x38, 0x30);
-      case SOUND_MIXER_LINE:
-       return setvolume(arg, 0x39, 0x31);
-      case SOUND_MIXER_SYNTH:
-       return setvolume(arg, 0x3b, 0x33);
-      case SOUND_MIXER_PCM:
-       return setvolume(arg, 0x3a, 0x32);
-      case SOUND_MIXER_LINE1:  /* AUX1 */
-       return setvolume(arg, 0x3d, 0x35);
-      case SOUND_MIXER_LINE2:  /* AUX2 */
-       return setvolume(arg, 0x3e, 0x36);
-      case SOUND_MIXER_IGAIN:  /* MIC pre-amp */
-       vol = *(int *) arg & 0xff;
-       if (vol > 100) vol = 100;
-       vol = SCALE(100, 3, vol);
-       if (aci_write_cmd(0x03, vol)) return -EIO;
-       vol = SCALE(3, 100, vol);
-       return (*(int *) arg = vol | (vol << 8));
-      case SOUND_MIXER_RECSRC:
-       return (*(int *) arg = 0);
-       break;
-      default:
-       return -EINVAL;
-      }
-    else
-      /* only read */
-      switch (cmd & 0xff) {
-      case SOUND_MIXER_DEVMASK:
-       return (*(int *) arg =
-                                SOUND_MASK_VOLUME | SOUND_MASK_CD    |
-                                SOUND_MASK_MIC    | SOUND_MASK_LINE  |
-                                SOUND_MASK_SYNTH  | SOUND_MASK_PCM   |
-#if 0
-                                SOUND_MASK_IGAIN  |
-#endif
-                                SOUND_MASK_LINE1  | SOUND_MASK_LINE2);
-       break;
-      case SOUND_MIXER_STEREODEVS:
-       return (*(int *) arg =
-                                SOUND_MASK_VOLUME | SOUND_MASK_CD   |
-                                SOUND_MASK_MIC    | SOUND_MASK_LINE |
-                                SOUND_MASK_SYNTH  | SOUND_MASK_PCM  |
-                                SOUND_MASK_LINE1  | SOUND_MASK_LINE2);
-       break;
-      case SOUND_MIXER_RECMASK:
-       return (*(int *) arg = 0);
-       break;
-      case SOUND_MIXER_RECSRC:
-       return (*(int *) arg = 0);
-       break;
-      case SOUND_MIXER_CAPS:
-       return (*(int *) arg = 0);
-       break;
-      case SOUND_MIXER_VOLUME:
-       return getvolume(arg, 0x04, 0x03);
-      case SOUND_MIXER_CD:
-       return getvolume(arg, 0x0a, 0x09);
-      case SOUND_MIXER_MIC:
-       return getvolume(arg, 0x06, 0x05);
-      case SOUND_MIXER_LINE:
-       return getvolume(arg, 0x08, 0x07);
-      case SOUND_MIXER_SYNTH:
-       return getvolume(arg, 0x0c, 0x0b);
-      case SOUND_MIXER_PCM:
-       return getvolume(arg, 0x0e, 0x0d);
-      case SOUND_MIXER_LINE1:  /* AUX1 */
-       return getvolume(arg, 0x11, 0x10);
-      case SOUND_MIXER_LINE2:  /* AUX2 */
-       return getvolume(arg, 0x13, 0x12);
-      case SOUND_MIXER_IGAIN:  /* MIC pre-amp */
-       if (aci_indexed_cmd(0xf0, 0x21, &buf)) return -EIO;
-       vol = SCALE(3, 100, buf <= 3 ? buf : 3);
-       vol |= vol << 8;
-       return (*(int *) arg = vol);
-      default:
-       return -EINVAL;
-      }
-  }
-
-  return -EINVAL;
-}
-
-
-static struct mixer_operations aci_mixer_operations =
-{
-  "ACI",
-  "ACI mixer",
-  aci_mixer_ioctl,
-  NULL
-};
-
-static unsigned char
-mad_read (int port)
-{
-  outb (0xE3, 0xf8f); /* Write MAD16 password */
-  return inb (port);  /* Read from port */
-}
-
-
-/*
- * Check, whether there actually is any ACI port operational and if
- * one was found, then initialize the ACI interface, reserve the I/O
- * addresses and attach the new mixer to the relevant VoxWare data
- * structures.
- *
- * Returns:  1   ACI mixer detected
- *           0   nothing there
- *
- * There is also an internal mixer in the codec (CS4231A or AD1845),
- * that deserves no purpose in an ACI based system which uses an
- * external ACI controlled stereo mixer. Make sure that this codec
- * mixer has the AUX1 input selected as the recording source, that the
- * input gain is set near maximum and that the other channels going
- * from the inputs to the codec output are muted.
- */
-
-int attach_aci(void)
-{
-  char *boardname = "unknown";
-  int volume;
-
-#define MC4_PORT       0xf90
-
-  aci_port =
-      (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354;
-
-  if (check_region(aci_port, 3)) {
-#ifdef DEBUG
-    printk("ACI: I/O area 0x%03x-0x%03x already used.\n",
-           aci_port, aci_port+2);
-#endif
-    return 0;
-  }
-
-  if (aci_read_cmd(0xf2, 2, aci_idcode)) {
-#ifdef DEBUG
-    printk("ACI: Failed to read idcode.\n");
-#endif
-    return 0;
-  }
-  if (aci_read_cmd(0xf1, 1, &aci_version)) {
-#ifdef DEBUG
-    printk("ACI: Failed to read version.\n");
-#endif
-    return 0;
-  }
-
-  if (aci_idcode[0] == 0x6d) {
-    /* It looks like a miro sound card. */
-    switch (aci_idcode[1]) {
-    case 0x41:
-      boardname = "PCM1 pro / early PCM12";
-      break;
-    case 0x42:
-      boardname = "PCM12";
-      break;
-    case 0x43:
-      boardname = "PCM20";
-      break;
-    default:
-      boardname = "unknown miro";
-    }
-  } else
-#ifndef DEBUG
-    return 0;
-#endif
-  
-  printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n",
-        aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port);
-
-  if (aci_reset) {
-    /* initialize ACI mixer */
-    aci_implied_cmd(0xff);
-    aci_solo = 0;
-  }
-
-  /* attach the mixer */
-  request_region(aci_port, 3, "sound mixer (ACI)");
-  if (num_mixers < MAX_MIXER_DEV) {
-    if (num_mixers > 0 &&
-        !strncmp("MAD16 WSS", mixer_devs[num_mixers-1]->name, 9)) {
-      /*
-       * The previously registered mixer device is the CS4231A which
-       * has no function on an ACI card. Make the ACI mixer the first
-       * of the two mixer devices.
-       */
-      mixer_devs[num_mixers] = mixer_devs[num_mixers-1];
-      mixer_devs[num_mixers-1] = &aci_mixer_operations;
-      /*
-       * Initialize the CS4231A mixer with reasonable values. It is
-       * unlikely that the user ever will want to change these as all
-       * channels can be mixed via ACI.
-       */
-      volume = 0x6464;
-      mixer_devs[num_mixers]->
-        ioctl(num_mixers, SOUND_MIXER_WRITE_PCM,     (caddr_t) &volume);
-      volume = 0x6464;
-      mixer_devs[num_mixers]->
-        ioctl(num_mixers, SOUND_MIXER_WRITE_IGAIN,   (caddr_t) &volume);
-      volume = 0;
-      mixer_devs[num_mixers]->
-        ioctl(num_mixers, SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume);
-      volume = 0;
-      mixer_devs[num_mixers]->
-        ioctl(num_mixers, SOUND_MIXER_WRITE_MIC,     (caddr_t) &volume);
-      volume = 0;
-      mixer_devs[num_mixers]->
-        ioctl(num_mixers, SOUND_MIXER_WRITE_IMIX,    (caddr_t) &volume);
-      volume = 0;
-      mixer_devs[num_mixers]->
-        ioctl(num_mixers, SOUND_MIXER_WRITE_LINE1,   (caddr_t) &volume);
-      volume = 0;
-      mixer_devs[num_mixers]->
-        ioctl(num_mixers, SOUND_MIXER_WRITE_LINE2,   (caddr_t) &volume);
-      volume = 0;
-      mixer_devs[num_mixers]->
-        ioctl(num_mixers, SOUND_MIXER_WRITE_LINE3,   (caddr_t) &volume);
-      volume = SOUND_MASK_LINE1;
-      mixer_devs[num_mixers]->
-        ioctl(num_mixers, SOUND_MIXER_WRITE_RECSRC,  (caddr_t) &volume);
-      num_mixers++;
-    } else
-      mixer_devs[num_mixers++] = &aci_mixer_operations;
-  }
-
-  /* Just do something; otherwise the first write command fails, at
-   * least with my PCM20.
-   */
-  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_READ_VOLUME, (caddr_t) &volume);
-
-  if (aci_reset) {
-    /* Initialize ACI mixer with reasonable power-up values */
-    volume = 0x3232;
-    aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume);
-    volume = 0x3232;
-    aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH,  (caddr_t) &volume);
-    volume = 0x3232;
-    aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM,    (caddr_t) &volume);
-    volume = 0x3232;
-    aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE,   (caddr_t) &volume);
-    volume = 0x3232;
-    aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC,    (caddr_t) &volume);
-    volume = 0x3232;
-    aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD,     (caddr_t) &volume);
-    volume = 0x3232;
-    aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1,  (caddr_t) &volume);
-    volume = 0x3232;
-    aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2,  (caddr_t) &volume);
-  }
-  
-  aci_present = 1;
-
-  return 1;
-}
-
-void unload_aci(void)
-{
-  if (aci_present)
-    release_region(aci_port, 3);
-}
-
-#endif
-
-#if defined(MODULE)
-
-int init_module(void) {
-       attach_aci();
-       return(0);
-}
-
-void cleanup_module(void) {
-       unload_aci();
-}
-
-#endif /* MODULE */
\ No newline at end of file
diff --git a/drivers/sound/lowlevel/aedsp16.c b/drivers/sound/lowlevel/aedsp16.c
deleted file mode 100644 (file)
index 48ef93f..0000000
+++ /dev/null
@@ -1,1400 +0,0 @@
-/*
-   drivers/sound/lowlevel/aedsp16.c
-
-   Audio Excel DSP 16 software configuration routines
-   Copyright (C) 1995,1996,1997,1998  Riccardo Facchetti (fizban@tin.it)
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-/*
- * Include the main OSS Lite header file. It include all the os, OSS Lite, etc
- * headers needed by this source.
- */
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include "../sound_config.h"
-#include "../soundmodule.h"
-
-/*
- * Sanity checks
- */
-
-#if !defined(CONFIG_AEDSP16_BASE)
-# undef CONFIG_AEDSP16
-#else
-# if defined(MODULE) && defined(CONFIG_AEDSP16_MODULE)
-#  define CONFIG_AEDSP16 1
-# endif
-#endif
-
-
-#if defined(CONFIG_AEDSP16)
-
-#if defined(CONFIG_AEDSP16_SBPRO) && defined(CONFIG_AEDSP16_MSS)
-#error You have to enable only one of the MSS and SBPRO emulations.
-#endif
-
-/*
-
-   READ THIS
-
-   This module started to configure the Audio Excel DSP 16 Sound Card.
-   Now works with the SC-6000 (old aedsp16) and new SC-6600 based cards.
-
-   NOTE: I have NO idea about Audio Excel DSP 16 III. If someone owns this
-   audio card and want to see the kernel support for it, please contact me.
-
-   Audio Excel DSP 16 is an SB pro II, Microsoft Sound System and MPU-401
-   compatible card.
-   It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq),
-   so before this module, the only way to configure the DSP under linux was
-   boot the MS-DOS loading the sound.sys device driver (this driver soft-
-   configure the sound board hardware by massaging someone of its registers),
-   and then ctrl-alt-del to boot linux with the DSP configured by the DOS
-   driver.
-
-   This module works configuring your Audio Excel DSP 16's irq, dma and
-   mpu-401-irq. The OSS Lite routines rely on the fact that if the
-   hardware is there, they can detect it. The problem with AEDSP16 is
-   that no hardware can be found by the probe routines if the sound card
-   is not configured properly. Sometimes the kernel probe routines can find
-   an SBPRO even when the card is not configured (this is the standard setup
-   of the card), but the SBPRO emulation don't work well if the card is not
-   properly initialized. For this reason
-
-   aedsp16_init_board()
-
-   routine is called before the OSS Lite probe routines try to detect the
-   hardware.
-
-   NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS)
-
-   NOTE: Now it works with SC-6000 and SC-6600 based audio cards. The new cards
-   have no jumper switch at all. No more WSS or MPU-401 I/O port switches. They
-   have to be configured by software.
-
-   NOTE: The driver is merged with the new OSS Lite sound driver. It works
-   as a lowlevel driver.
-
-   The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS;
-   the OSS Lite sound driver can be configured for SBPRO and MSS cards
-   at the same time, but the aedsp16 can't be two cards!!
-   When we configure it, we have to choose the SBPRO or the MSS emulation
-   for AEDSP16. We also can install a *REAL* card of the other type (see [1]).
-
-   NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO
-   please let me know if it works.
-
-   The MPU-401 support can be compiled in together with one of the other
-   two operating modes.
-
-   NOTE: This is something like plug-and-play: we have only to plug
-   the AEDSP16 board in the socket, and then configure and compile
-   a kernel that uses the AEDSP16 software configuration capability.
-   No jumper setting is needed!
-
-   For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3
-   you have just to make config the OSS Lite package, configuring
-   the AEDSP16 sound card, then activating the SBPro emulation mode
-   and at last configuring IRQ and DMA.
-   Compile the kernel and run it.
-
-   NOTE: This means for SC-6000 cards that you can choose irq and dma,
-   but not the I/O addresses. To change I/O addresses you have to set
-   them with jumpers. For SC-6600 cards you have no jumpers so you have
-   to set up your full card configuration in the make config.
-
-   You can change the irq/dma/mirq settings WITHOUT THE NEED to open
-   your computer and massage the jumpers (there are no irq/dma/mirq
-   jumpers to be configured anyway, only I/O BASE values have to be
-   configured with jumpers)
-
-   For some ununderstandable reason, the card default of irq 7, dma 1,
-   don't work for me. Seems to be an IRQ or DMA conflict. Under heavy
-   HDD work, the kernel start to erupt out a lot of messages like:
-
-   'Sound: DMA timed out - IRQ/DRQ config error?'
-
-   For what I can say, I have NOT any conflict at irq 7 (under linux I'm
-   using the lp polling driver), and dma line 1 is unused as stated by
-   /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so
-   I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows!
-   Anyway a setting of irq 10, dma 3 works really fine.
-
-   NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know
-   the emulation mode, all the installed hardware and the hardware
-   configuration (irq and dma settings of all the hardware).
-
-   This init module should work with SBPRO+MSS, when one of the two is
-   the AEDSP16 emulation and the other the real card. (see [1])
-   For example:
-
-   AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other
-   AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other
-
-   MPU401 should work. (see [2])
-
-   [1]
-       ---
-       Date: Mon, 29 Jul 1997 08:35:40 +0100
-       From: Mr S J Greenaway <sjg95@unixfe.rl.ac.uk>
-
-       [...]
-       Just to let you know got my Audio Excel (emulating a MSS) working
-       with my original SB16, thanks for the driver!
-       [...]
-       ---
-
-   [2] Not tested by me for lack of hardware.
-
-   TODO, WISHES AND TECH
-
-   - About I/O ports allocation -
-
-   Request the 2x0h region (port base) in any case if we are using this card.
-
-   NOTE: the "aedsp16 (base)" string with which we are requesting the aedsp16
-   port base region (see code) does not mean necessarily that we are emulating
-   sbpro.  Even if this region is the sbpro I/O ports region, we use this
-   region to access the control registers of the card, and if emulating
-   sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro
-   registers are not used, in no way, to emulate an sbpro: they are
-   used only for configuration purposes.
-
-   Started Fri Mar 17 16:13:18 MET 1995
-
-   v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c)
-   - Initial code.
-   v0.2 (ALPHA)
-   - Cleanups.
-   - Integrated with Linux voxware v 2.90-2 kernel sound driver.
-   - SoundBlaster Pro mode configuration.
-   - Microsoft Sound System mode configuration.
-   - MPU-401 mode configuration.
-   v0.3 (ALPHA)
-   - Cleanups.
-   - Rearranged the code to let aedsp16_init_board be more general.
-   - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h
-   inclusion too. We rely on os.h
-   - Used the  to get a variable
-   len string (we are not sure about the len of Copyright string).
-   This works with any SB and compatible.
-   - Added the code to request_region at device init (should go in
-   the main body of voxware).
-   v0.4 (BETA)
-   - Better configure.c patch for aedsp16 configuration (better
-   logic of inclusion of AEDSP16 support)
-   - Modified the conditional compilation to better support more than
-   one sound card of the emulated type (read the NOTES above)
-   - Moved the sb init routine from the attach to the very first
-   probe in sb_card.c
-   - Rearrangements and cleanups
-   - Wiped out some unnecessary code and variables: this is kernel
-   code so it is better save some TEXT and DATA
-   - Fixed the request_region code. We must allocate the aedsp16 (sbpro)
-   I/O ports in any case because they are used to access the DSP
-   configuration registers and we can not allow anyone to get them.
-   v0.5
-   - cleanups on comments
-   - prep for diffs against v3.0-proto-950402
-   v0.6
-   - removed the request_region()s when compiling the MODULE sound.o
-   because we are not allowed (by the actual voxware structure) to
-   release_region()
-   v0.7 (pre ALPHA, not distributed)
-   - started porting this module to kernel 1.3.84. Dummy probe/attach
-   routines.
-   v0.8 (ALPHA)
-   - attached all the init routines.
-   v0.9 (BETA)
-   - Integrated with linux-pre2.0.7
-   - Integrated with configuration scripts.
-   - Cleaned up and beautyfied the code.
-   v0.9.9 (BETA)
-   - Thanks to Piercarlo Grandi: corrected the conditonal compilation code.
-     Now only the code configured is compiled in, with some memory saving.
-   v0.9.10
-   - Integration into the sound/lowlevel/ section of the sound driver.
-   - Re-organized the code.
-   v0.9.11 (not distributed)
-   - Rewritten the init interface-routines to initialize the AEDSP16 in
-     one shot.
-   - More cosmetics.
-   - SC-6600 support.
-   - More soft/hard configuration.
-   v0.9.12
-   - Refined the v0.9.11 code with conditional compilation to distinguish
-     between SC-6000 and SC-6600 code.
-   v1.0.0
-   - Prep for merging with OSS Lite and Linux kernel 2.1.13
-   - Corrected a bug in request/check/release region calls (thanks to the
-     new kernel exception handling).
-   v1.1
-   - Revamped for integration with new modularized sound drivers: to enhance
-     the flexibility of modular version, I have removed all the conditional
-     compilation for SBPRO, MPU and MSS code. Now it is all managed with
-     the ae_config structure.
-   v1.2
-   - Module informations added.
-   - Removed aedsp16_delay_10msec(), now using mdelay(10)
-   - All data and funcs moved to .*.init section.
-
-   Known Problems:
-   - Audio Excel DSP 16 III don't work with this driver.
-
-   Credits:
-   Many thanks to Gerald Britton <gbritton@CapAccess.org>. He helped me a
-   lot in testing the 0.9.11 and 0.9.12 versions of this driver.
-
- */
-
-
-#define VERSION "1.2"          /* Version of Audio Excel DSP 16 driver */
-
-#undef AEDSP16_DEBUG 1         /* Define this to enable debug code     */
-#undef AEDSP16_DEBUG_MORE 1    /* Define this to enable more debug     */
-#undef AEDSP16_INFO  1         /* Define this to enable info code      */
-
-#if defined(AEDSP16_DEBUG)
-# define DBG(x)  printk x
-# if defined(AEDSP16_DEBUG_MORE)
-#  define DBG1(x) printk x
-# else
-#  define DBG1(x)
-# endif
-#else
-# define DBG(x)
-# define DBG1(x)
-#endif
-
-/*
- * Misc definitions
- */
-#define TRUE   1
-#define FALSE  0
-
-/*
- * Region Size for request/check/release region.
- */
-#define IOBASE_REGION_SIZE     0x10
-
-/*
- * Hardware related defaults
- */
-#define DEF_AEDSP16_IOB 0x220   /* 0x220(default) 0x240                 */
-#define DEF_AEDSP16_IRQ 7      /* 5 7(default) 9 10 11                 */
-#define DEF_AEDSP16_MRQ 0      /* 5 7 9 10 0(default), 0 means disable */
-#define DEF_AEDSP16_DMA 1      /* 0 1(default) 3                       */
-
-/*
- * Commands of AEDSP16's DSP (SBPRO+special).
- * Some of them are COMMAND_xx, in the future they may change.
- */
-#define WRITE_MDIRQ_CFG   0x50 /* Set M&I&DRQ mask (the real config)   */
-#define COMMAND_52        0x52 /*                                      */
-#define READ_HARD_CFG     0x58 /* Read Hardware Config (I/O base etc)  */
-#define COMMAND_5C        0x5c /*                                      */
-#define COMMAND_60        0x60 /*                                      */
-#define COMMAND_66        0x66 /*                                      */
-#define COMMAND_6C        0x6c /*                                      */
-#define COMMAND_6E        0x6e /*                                      */
-#define COMMAND_88        0x88 /*                                      */
-#define DSP_INIT_MSS      0x8c /* Enable Microsoft Sound System mode   */
-#define COMMAND_C5        0xc5 /*                                      */
-#define GET_DSP_VERSION   0xe1 /* Get DSP Version                      */
-#define GET_DSP_COPYRIGHT 0xe3 /* Get DSP Copyright                    */
-
-/*
- * Offsets of AEDSP16 DSP I/O ports. The offset is added to base I/O port
- * to have the actual I/O port.
- * Register permissions are:
- * (wo) == Write Only
- * (ro) == Read  Only
- * (w-) == Write
- * (r-) == Read
- */
-#define DSP_RESET    0x06      /* offset of DSP RESET             (wo) */
-#define DSP_READ     0x0a      /* offset of DSP READ              (ro) */
-#define DSP_WRITE    0x0c      /* offset of DSP WRITE             (w-) */
-#define DSP_COMMAND  0x0c      /* offset of DSP COMMAND           (w-) */
-#define DSP_STATUS   0x0c      /* offset of DSP STATUS            (r-) */
-#define DSP_DATAVAIL 0x0e      /* offset of DSP DATA AVAILABLE    (ro) */
-
-
-#define RETRY           10     /* Various retry values on I/O opera-   */
-#define STATUSRETRY   1000     /* tions. Sometimes we have to          */
-#define HARDRETRY   500000     /* wait for previous cmd to complete    */
-
-/*
- * Size of character arrays that store name and version of sound card
- */
-#define CARDNAMELEN 15         /* Size of the card's name in chars     */
-#define CARDVERLEN  2          /* Size of the card's version in chars  */
-
-#if defined(CONFIG_SC6600)
-/*
- * Bitmapped flags of hard configuration
- */
-/*
- * Decode macros (xl == low byte, xh = high byte)
- */
-#define IOBASE(xl)             ((xl & 0x01)?0x240:0x220)
-#define JOY(xl)                (xl & 0x02)
-#define MPUADDR(xl)            (                       \
-                               (xl & 0x0C)?0x330:      \
-                               (xl & 0x08)?0x320:      \
-                               (xl & 0x04)?0x310:      \
-                                               0x300)
-#define WSSADDR(xl)            ((xl & 0x10)?0xE80:0x530)
-#define CDROM(xh)              (xh & 0x20)
-#define CDROMADDR(xh)          (((xh & 0x1F) << 4) + 0x200)
-/*
- * Encode macros
- */
-#define BLDIOBASE(xl, val) {           \
-       xl &= ~0x01;                    \
-       if (val == 0x240)               \
-               xl |= 0x01;             \
-       }
-#define BLDJOY(xl, val) {              \
-       xl &= ~0x02;                    \
-       if (val == 1)                   \
-               xl |= 0x02;             \
-       }
-#define BLDMPUADDR(xl, val) {          \
-       xl &= ~0x0C;                    \
-       switch (val) {                  \
-               case 0x330:             \
-                       xl |= 0x0C;     \
-                       break;          \
-               case 0x320:             \
-                       xl |= 0x08;     \
-                       break;          \
-               case 0x310:             \
-                       xl |= 0x04;     \
-                       break;          \
-               case 0x300:             \
-                       xl |= 0x00;     \
-                       break;          \
-               default:                \
-                       xl |= 0x00;     \
-                       break;          \
-               }                       \
-       }
-#define BLDWSSADDR(xl, val) {          \
-       xl &= ~0x10;                    \
-       if (val == 0xE80)               \
-               xl |= 0x10;             \
-       }
-#define BLDCDROM(xh, val) {            \
-       xh &= ~0x20;                    \
-       if (val == 1)                   \
-               xh |= 0x20;             \
-       }
-#define BLDCDROMADDR(xh, val) {                \
-       int tmp = val;                  \
-       tmp -= 0x200;                   \
-       tmp >>= 4;                      \
-       tmp &= 0x1F;                    \
-       xh |= tmp;                      \
-       xh &= 0x7F;                     \
-       xh |= 0x40;                     \
-       }
-#endif /* CONFIG_SC6600 */
-
-/*
- * Bit mapped flags for calling aedsp16_init_board(), and saving the current
- * emulation mode.
- */
-#define INIT_NONE   (0   )
-#define INIT_SBPRO  (1<<0)
-#define INIT_MSS    (1<<1)
-#define INIT_MPU401 (1<<2)
-
-static int      soft_cfg __initdata = 0;       /* bitmapped config */
-static int      soft_cfg_mss __initdata = 0;   /* bitmapped mss config */
-static int      ver[CARDVERLEN] __initdata = {0, 0};   /* DSP Ver:
-                                                  hi->ver[0] lo->ver[1] */
-
-#if defined(CONFIG_SC6600)
-static int     hard_cfg[2]     /* lo<-hard_cfg[0] hi<-hard_cfg[1]      */
-                     __initdata = { 0, 0};
-#endif /* CONFIG_SC6600 */
-
-#if defined(CONFIG_SC6600)
-/* Decoded hard configuration */
-struct d_hcfg {
-       int iobase;
-       int joystick;
-       int mpubase;
-       int wssbase;
-       int cdrom;
-       int cdrombase;
-};
-
-struct d_hcfg decoded_hcfg __initdata = {0, };
-
-#endif /* CONFIG_SC6600 */
-
-/* orVals contain the values to be or'ed                                       */
-struct orVals {
-       int     val;            /* irq|mirq|dma                         */
-       int     or;             /* soft_cfg |= TheStruct.or             */
-};
-
-/* aedsp16_info contain the audio card configuration                  */
-struct aedsp16_info {
-       int base_io;            /* base I/O address for accessing card  */
-       int irq;                /* irq value for DSP I/O                */
-       int mpu_irq;            /* irq for mpu401 interface I/O         */
-       int dma;                /* dma value for DSP I/O                */
-       int mss_base;           /* base I/O for Microsoft Sound System  */
-       int mpu_base;           /* base I/O for MPU-401 emulation       */
-       int init;               /* Initialization status of the card    */
-};
-
-/*
- * Magic values that the DSP will eat when configuring irq/mirq/dma
- */
-/* DSP IRQ conversion array             */
-static struct orVals orIRQ[] __initdata = {
-       {0x05, 0x28},
-       {0x07, 0x08},
-       {0x09, 0x10},
-       {0x0a, 0x18},
-       {0x0b, 0x20},
-       {0x00, 0x00}
-};
-
-/* MPU-401 IRQ conversion array         */
-static struct orVals orMIRQ[] __initdata = {
-       {0x05, 0x04},
-       {0x07, 0x44},
-       {0x09, 0x84},
-       {0x0a, 0xc4},
-       {0x00, 0x00}
-};
-
-/* DMA Channels conversion array        */
-static struct orVals orDMA[] __initdata = {
-       {0x00, 0x01},
-       {0x01, 0x02},
-       {0x03, 0x03},
-       {0x00, 0x00}
-};
-
-static struct aedsp16_info ae_config __initdata = {
-       DEF_AEDSP16_IOB,
-       DEF_AEDSP16_IRQ,
-       DEF_AEDSP16_MRQ,
-       DEF_AEDSP16_DMA,
-       -1,
-       -1,
-       INIT_NONE
-};
-
-/*
- * Buffers to store audio card informations
- */
-static char     DSPCopyright[CARDNAMELEN + 1] __initdata = {0, };
-static char     DSPVersion[CARDVERLEN + 1] __initdata = {0, };
-
-static int __init aedsp16_wait_data(int port)
-{
-       int             loop = STATUSRETRY;
-       unsigned char   ret = 0;
-
-       DBG1(("aedsp16_wait_data (0x%x): ", port));
-
-       do {
-                 ret = inb(port + DSP_DATAVAIL);
-       /*
-        * Wait for data available (bit 7 of ret == 1)
-        */
-         } while (!(ret & 0x80) && loop--);
-
-       if (ret & 0x80) {
-               DBG1(("success.\n"));
-               return TRUE;
-       }
-
-       DBG1(("failure.\n"));
-       return FALSE;
-}
-
-static int __init aedsp16_read(int port)
-{
-       int inbyte;
-
-       DBG(("    Read DSP Byte (0x%x): ", port));
-
-       if (aedsp16_wait_data(port) == FALSE) {
-               DBG(("failure.\n"));
-               return -1;
-       }
-
-       inbyte = inb(port + DSP_READ);
-
-       DBG(("read [0x%x]/{%c}.\n", inbyte, inbyte));
-
-       return inbyte;
-}
-
-static int __init aedsp16_test_dsp(int port)
-{
-       return ((aedsp16_read(port) == 0xaa) ? TRUE : FALSE);
-}
-
-static int __init aedsp16_dsp_reset(int port)
-{
-       /*
-        * Reset DSP
-        */
-
-       DBG(("Reset DSP:\n"));
-
-       outb(1, (port + DSP_RESET));
-       udelay(10);
-       outb(0, (port + DSP_RESET));
-       udelay(10);
-       udelay(10);
-       if (aedsp16_test_dsp(port) == TRUE) {
-               DBG(("success.\n"));
-               return TRUE;
-       } else
-               DBG(("failure.\n"));
-       return FALSE;
-}
-
-static int __init aedsp16_write(int port, int cmd)
-{
-       unsigned char   ret;
-       int             loop = HARDRETRY;
-
-       DBG(("    Write DSP Byte (0x%x) [0x%x]: ", port, cmd));
-
-       do {
-               ret = inb(port + DSP_STATUS);
-               /*
-                * DSP ready to receive data if bit 7 of ret == 0
-                */
-               if (!(ret & 0x80)) {
-                       outb(cmd, port + DSP_COMMAND);
-                       DBG(("success.\n"));
-                       return 0;
-               }
-       } while (loop--);
-
-       DBG(("timeout.\n"));
-       printk("[AEDSP16] DSP Command (0x%x) timeout.\n", cmd);
-
-       return -1;
-}
-
-#if defined(CONFIG_SC6600)
-
-#if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG)
-void __init aedsp16_pinfo(void) {
-       DBG(("\n Base address:  %x\n", decoded_hcfg.iobase));
-       DBG((" Joystick    : %s present\n", decoded_hcfg.joystick?"":" not"));
-       DBG((" WSS addr    :  %x\n", decoded_hcfg.wssbase));
-       DBG((" MPU-401 addr:  %x\n", decoded_hcfg.mpubase));
-       DBG((" CDROM       : %s present\n", (decoded_hcfg.cdrom!=4)?"":" not"));
-       DBG((" CDROMADDR   :  %x\n\n", decoded_hcfg.cdrombase));
-}
-#endif
-
-void __init aedsp16_hard_decode(void) {
-
-       DBG((" aedsp16_hard_decode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1]));
-
-/*
- * Decode Cfg Bytes.
- */
-       decoded_hcfg.iobase     = IOBASE(hard_cfg[0]);
-       decoded_hcfg.joystick   = JOY(hard_cfg[0]);
-       decoded_hcfg.wssbase    = WSSADDR(hard_cfg[0]);
-       decoded_hcfg.mpubase    = MPUADDR(hard_cfg[0]);
-       decoded_hcfg.cdrom      = CDROM(hard_cfg[1]);
-       decoded_hcfg.cdrombase  = CDROMADDR(hard_cfg[1]);
-
-#if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG)
-       printk(" Original sound card configuration:\n");
-       aedsp16_pinfo();
-#endif
-
-/*
- * Now set up the real kernel configuration.
- */
-       decoded_hcfg.iobase     = ae_config.base_io;
-       decoded_hcfg.wssbase    = ae_config.mss_base;
-       decoded_hcfg.mpubase    = ae_config.mpu_base;
-
-#if defined(CONFIG_SC6600_JOY)
-       decoded_hcfg.joystick   = CONFIG_SC6600_JOY; /* Enable */
-#endif
-#if defined(CONFIG_SC6600_CDROM)
-       decoded_hcfg.cdrom      = CONFIG_SC6600_CDROM; /* 4:N-3:I-2:G-1:P-0:S */
-#endif
-#if defined(CONFIG_SC6600_CDROMBASE)
-       decoded_hcfg.cdrombase  = CONFIG_SC6600_CDROMBASE; /* 0 Disable */
-#endif
-
-#if defined(AEDSP16_DEBUG)
-       DBG((" New Values:\n"));
-       aedsp16_pinfo();
-#endif
-
-       DBG(("success.\n"));
-}
-
-void __init aedsp16_hard_encode(void) {
-
-       DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1]));
-
-       hard_cfg[0] = 0;
-       hard_cfg[1] = 0;
-
-       hard_cfg[0] |= 0x20;
-
-       BLDIOBASE (hard_cfg[0], decoded_hcfg.iobase);
-       BLDWSSADDR(hard_cfg[0], decoded_hcfg.wssbase);
-       BLDMPUADDR(hard_cfg[0], decoded_hcfg.mpubase);
-       BLDJOY(hard_cfg[0], decoded_hcfg.joystick);
-       BLDCDROM(hard_cfg[1], decoded_hcfg.cdrom);
-       BLDCDROMADDR(hard_cfg[1], decoded_hcfg.cdrombase);
-
-#if defined(AEDSP16_DEBUG)
-       aedsp16_pinfo();
-#endif
-
-       DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1]));
-       DBG(("success.\n"));
-
-}
-
-static int __init aedsp16_hard_write(int port) {
-
-       DBG(("aedsp16_hard_write:\n"));
-
-       if (aedsp16_write(port, COMMAND_6C)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_6C);
-               DBG(("failure.\n"));
-               return FALSE;
-       }
-       if (aedsp16_write(port, COMMAND_5C)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C);
-               DBG(("failure.\n"));
-               return FALSE;
-       }
-       if (aedsp16_write(port, hard_cfg[0])) {
-               printk("[AEDSP16] DATA 0x%x: failed!\n", hard_cfg[0]);
-               DBG(("failure.\n"));
-               return FALSE;
-       }
-       if (aedsp16_write(port, hard_cfg[1])) {
-               printk("[AEDSP16] DATA 0x%x: failed!\n", hard_cfg[1]);
-               DBG(("failure.\n"));
-               return FALSE;
-       }
-       if (aedsp16_write(port, COMMAND_C5)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_C5);
-               DBG(("failure.\n"));
-               return FALSE;
-       }
-
-       DBG(("success.\n"));
-
-       return TRUE;
-}
-
-static int __init aedsp16_hard_read(int port) {
-
-       DBG(("aedsp16_hard_read:\n"));
-
-       if (aedsp16_write(port, READ_HARD_CFG)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", READ_HARD_CFG);
-               DBG(("failure.\n"));
-               return FALSE;
-       }
-
-       if ((hard_cfg[0] = aedsp16_read(port)) == -1) {
-               printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
-                       READ_HARD_CFG);
-               DBG(("failure.\n"));
-               return FALSE;
-       }
-       if ((hard_cfg[1] = aedsp16_read(port)) == -1) {
-               printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
-                       READ_HARD_CFG);
-               DBG(("failure.\n"));
-               return FALSE;
-       }
-       if (aedsp16_read(port) == -1) {
-               printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
-                       READ_HARD_CFG);
-               DBG(("failure.\n"));
-               return FALSE;
-       }
-
-       DBG(("success.\n"));
-
-       return TRUE;
-}
-
-static int __init aedsp16_ext_cfg_write(int port) {
-
-       int extcfg, val;
-
-       if (aedsp16_write(port, COMMAND_66)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_66);
-               return FALSE;
-       }
-
-       extcfg = 7;
-       if (decoded_hcfg.cdrom != 2)
-               extcfg = 0x0F;
-       if ((decoded_hcfg.cdrom == 4) ||
-           (decoded_hcfg.cdrom == 3))
-               extcfg &= ~2;
-       if (decoded_hcfg.cdrombase == 0)
-               extcfg &= ~2;
-       if (decoded_hcfg.mpubase == 0)
-               extcfg &= ~1;
-
-       if (aedsp16_write(port, extcfg)) {
-               printk("[AEDSP16] Write extcfg: failed!\n");
-               return FALSE;
-       }
-       if (aedsp16_write(port, 0)) {
-               printk("[AEDSP16] Write extcfg: failed!\n");
-               return FALSE;
-       }
-       if (decoded_hcfg.cdrom == 3) {
-               if (aedsp16_write(port, COMMAND_52)) {
-                       printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_52);
-                       return FALSE;
-               }
-               if ((val = aedsp16_read(port)) == -1) {
-                       printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n"
-                                       , COMMAND_52);
-                       return FALSE;
-               }
-               val &= 0x7F;
-               if (aedsp16_write(port, COMMAND_60)) {
-                       printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_60);
-                       return FALSE;
-               }
-               if (aedsp16_write(port, val)) {
-                       printk("[AEDSP16] Write val: failed!\n");
-                       return FALSE;
-               }
-       }
-
-       return TRUE;
-}
-
-#endif /* CONFIG_SC6600 */
-
-static int __init aedsp16_cfg_write(int port) {
-       if (aedsp16_write(port, WRITE_MDIRQ_CFG)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG);
-               return FALSE;
-       }
-       if (aedsp16_write(port, soft_cfg)) {
-               printk("[AEDSP16] Initialization of (M)IRQ and DMA: failed!\n");
-               return FALSE;
-       }
-       return TRUE;
-}
-
-static int __init aedsp16_init_mss(int port)
-{
-       DBG(("aedsp16_init_mss:\n"));
-
-       mdelay(10);
-
-       if (aedsp16_write(port, DSP_INIT_MSS)) {
-               printk("[AEDSP16] aedsp16_init_mss [0x%x]: failed!\n",
-                               DSP_INIT_MSS);
-               DBG(("failure.\n"));
-               return FALSE;
-       }
-       
-       mdelay(10);
-
-       if (aedsp16_cfg_write(port) == FALSE)
-               return FALSE;
-
-       outb(soft_cfg_mss, ae_config.mss_base);
-
-       DBG(("success.\n"));
-
-       return TRUE;
-}
-
-static int __init aedsp16_setup_board(int port) {
-       int     loop = RETRY;
-
-#if defined(CONFIG_SC6600)
-       int     val = 0;
-
-       if (aedsp16_hard_read(port) == FALSE) {
-               printk("[AEDSP16] aedsp16_hard_read: failed!\n");
-               return FALSE;
-       }
-
-       if (aedsp16_write(port, COMMAND_52)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_52);
-               return FALSE;
-       }
-
-       if ((val = aedsp16_read(port)) == -1) {
-               printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
-                               COMMAND_52);
-               return FALSE;
-       }
-#endif
-
-       do {
-               if (aedsp16_write(port, COMMAND_88)) {
-                       printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_88);
-                       return FALSE;
-               }
-               mdelay(10);
-       } while ((aedsp16_wait_data(port) == FALSE) && loop--);
-
-       if (aedsp16_read(port) == -1) {
-               printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
-                               COMMAND_88);
-               return FALSE;
-       }
-
-#if !defined(CONFIG_SC6600)
-       if (aedsp16_write(port, COMMAND_5C)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C);
-               return FALSE;
-       }
-#endif
-
-       if (aedsp16_cfg_write(port) == FALSE)
-               return FALSE;
-
-#if defined(CONFIG_SC6600)
-       if (aedsp16_write(port, COMMAND_60)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_60);
-               return FALSE;
-       }
-       if (aedsp16_write(port, val)) {
-               printk("[AEDSP16] DATA 0x%x: failed!\n", val);
-               return FALSE;
-       }
-       if (aedsp16_write(port, COMMAND_6E)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_6E);
-               return FALSE;
-       }
-       if (aedsp16_write(port, ver[0])) {
-               printk("[AEDSP16] DATA 0x%x: failed!\n", ver[0]);
-               return FALSE;
-       }
-       if (aedsp16_write(port, ver[1])) {
-               printk("[AEDSP16] DATA 0x%x: failed!\n", ver[1]);
-               return FALSE;
-       }
-
-       if (aedsp16_hard_write(port) == FALSE) {
-               printk("[AEDSP16] aedsp16_hard_write: failed!\n");
-               return FALSE;
-       }
-
-       if (aedsp16_write(port, COMMAND_5C)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C);
-               return FALSE;
-       }
-
-#if defined(THIS_IS_A_THING_I_HAVE_NOT_TESTED_YET)
-       if (aedsp16_cfg_write(port) == FALSE)
-               return FALSE;
-#endif
-
-#endif
-
-       return TRUE;
-}
-
-static int __init aedsp16_stdcfg(int port) {
-       if (aedsp16_write(port, WRITE_MDIRQ_CFG)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG);
-               return FALSE;
-       }
-       /*
-        * 0x0A == (IRQ 7, DMA 1, MIRQ 0)
-        */
-       if (aedsp16_write(port, 0x0A)) {
-               printk("[AEDSP16] aedsp16_stdcfg: failed!\n");
-               return FALSE;
-       }
-       return TRUE;
-}
-
-static int __init aedsp16_dsp_version(int port)
-{
-       int             len = 0;
-       int             ret;
-
-       DBG(("Get DSP Version:\n"));
-
-       if (aedsp16_write(ae_config.base_io, GET_DSP_VERSION)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", GET_DSP_VERSION);
-               DBG(("failed.\n"));
-               return FALSE;
-       }
-
-       do {
-               if ((ret = aedsp16_read(port)) == -1) {
-                       DBG(("failed.\n"));
-                       return FALSE;
-               }
-       /*
-        * We already know how many int are stored (2), so we know when the
-        * string is finished.
-        */
-               ver[len++] = ret;
-         } while (len < CARDVERLEN);
-       sprintf(DSPVersion, "%d.%d", ver[0], ver[1]);
-
-       DBG(("success.\n"));
-
-       return TRUE;
-}
-
-static int __init aedsp16_dsp_copyright(int port)
-{
-       int             len = 0;
-       int             ret;
-
-       DBG(("Get DSP Copyright:\n"));
-
-       if (aedsp16_write(ae_config.base_io, GET_DSP_COPYRIGHT)) {
-               printk("[AEDSP16] CMD 0x%x: failed!\n", GET_DSP_COPYRIGHT);
-               DBG(("failed.\n"));
-               return FALSE;
-       }
-
-       do {
-               if ((ret = aedsp16_read(port)) == -1) {
-       /*
-        * If no more data available, return to the caller, no error if len>0.
-        * We have no other way to know when the string is finished.
-        */
-                       if (len)
-                               break;
-                       else {
-                               DBG(("failed.\n"));
-                               return FALSE;
-                       }
-               }
-
-               DSPCopyright[len++] = ret;
-
-         } while (len < CARDNAMELEN);
-
-       DBG(("success.\n"));
-
-       return TRUE;
-}
-
-static void __init aedsp16_init_tables(void)
-{
-       int i = 0;
-
-       memset(DSPCopyright, 0, CARDNAMELEN + 1);
-       memset(DSPVersion, 0, CARDVERLEN + 1);
-
-       for (i = 0; orIRQ[i].or; i++)
-               if (orIRQ[i].val == ae_config.irq) {
-                       soft_cfg |= orIRQ[i].or;
-                       soft_cfg_mss |= orIRQ[i].or;
-               }
-
-       for (i = 0; orMIRQ[i].or; i++)
-               if (orMIRQ[i].or == ae_config.mpu_irq)
-                       soft_cfg |= orMIRQ[i].or;
-
-       for (i = 0; orDMA[i].or; i++)
-               if (orDMA[i].val == ae_config.dma) {
-                       soft_cfg |= orDMA[i].or;
-                       soft_cfg_mss |= orDMA[i].or;
-               }
-}
-
-static int __init aedsp16_init_board(void)
-{
-       aedsp16_init_tables();
-
-       if (aedsp16_dsp_reset(ae_config.base_io) == FALSE) {
-               printk("[AEDSP16] aedsp16_dsp_reset: failed!\n");
-               return FALSE;
-       }
-       if (aedsp16_dsp_copyright(ae_config.base_io) == FALSE) {
-               printk("[AEDSP16] aedsp16_dsp_copyright: failed!\n");
-               return FALSE;
-       }
-
-       /*
-        * My AEDSP16 card return SC-6000 in DSPCopyright, so
-        * if we have something different, we have to be warned.
-        */
-       if (strcmp("SC-6000", DSPCopyright))
-               printk("[AEDSP16] Warning: non SC-6000 audio card!\n");
-
-       if (aedsp16_dsp_version(ae_config.base_io) == FALSE) {
-               printk("[AEDSP16] aedsp16_dsp_version: failed!\n");
-               return FALSE;
-       }
-
-       if (aedsp16_stdcfg(ae_config.base_io) == FALSE) {
-               printk("[AEDSP16] aedsp16_stdcfg: failed!\n");
-               return FALSE;
-       }
-
-#if defined(CONFIG_SC6600)
-       if (aedsp16_hard_read(ae_config.base_io) == FALSE) {
-               printk("[AEDSP16] aedsp16_hard_read: failed!\n");
-               return FALSE;
-       }
-
-       aedsp16_hard_decode();
-
-       aedsp16_hard_encode();
-
-       if (aedsp16_hard_write(ae_config.base_io) == FALSE) {
-               printk("[AEDSP16] aedsp16_hard_write: failed!\n");
-               return FALSE;
-       }
-
-       if (aedsp16_ext_cfg_write(ae_config.base_io) == FALSE) {
-               printk("[AEDSP16] aedsp16_ext_cfg_write: failed!\n");
-               return FALSE;
-       }
-#endif /* CONFIG_SC6600 */
-
-       if (aedsp16_setup_board(ae_config.base_io) == FALSE) {
-               printk("[AEDSP16] aedsp16_setup_board: failed!\n");
-               return FALSE;
-       }
-
-       if (ae_config.mss_base != -1) {
-               if (ae_config.init & INIT_MSS) {
-                       if (aedsp16_init_mss(ae_config.base_io) == FALSE) {
-                               printk("[AEDSP16] Can not initialize"
-                                      "Microsoft Sound System mode.\n");
-                               return FALSE;
-                       }
-               }
-       }
-
-#if !defined(MODULE) || defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG)
-
-       printk("Audio Excel DSP 16 init v%s (%s %s) [",
-               VERSION, DSPCopyright,
-               DSPVersion);
-
-       if (ae_config.mpu_base != -1) {
-               if (ae_config.init & INIT_MPU401) {
-                       printk("MPU401");
-                       if ((ae_config.init & INIT_MSS) ||
-                           (ae_config.init & INIT_SBPRO))
-                               printk(" ");
-               }
-       }
-
-       if (ae_config.mss_base == -1) {
-               if (ae_config.init & INIT_SBPRO) {
-                       printk("SBPro");
-                       if (ae_config.init & INIT_MSS)
-                               printk(" ");
-               }
-       }
-
-       if (ae_config.mss_base != -1)
-               if (ae_config.init & INIT_MSS)
-                       printk("MSS");
-
-       printk("]\n");
-#endif /* MODULE || AEDSP16_INFO || AEDSP16_DEBUG */
-
-       mdelay(10);
-
-       return TRUE;
-}
-
-static int __init init_aedsp16_sb(void)
-{
-       DBG(("init_aedsp16_sb: "));
-
-/*
- * If the card is already init'ed MSS, we can not init it to SBPRO too
- * because the board can not emulate simultaneously MSS and SBPRO.
- */
-       if (ae_config.init & INIT_MSS)
-               return FALSE;
-       if (ae_config.init & INIT_SBPRO)
-               return FALSE;
-
-       ae_config.init |= INIT_SBPRO;
-
-       DBG(("done.\n"));
-
-       return TRUE;
-}
-
-static void __init uninit_aedsp16_sb(void)
-{
-       DBG(("uninit_aedsp16_sb: "));
-
-       ae_config.init &= ~INIT_SBPRO;
-
-       DBG(("done.\n"));
-}
-
-static int __init init_aedsp16_mss(void)
-{
-       DBG(("init_aedsp16_mss: "));
-
-/*
- * If the card is already init'ed SBPRO, we can not init it to MSS too
- * because the board can not emulate simultaneously MSS and SBPRO.
- */
-       if (ae_config.init & INIT_SBPRO)
-               return FALSE;
-       if (ae_config.init & INIT_MSS)
-               return FALSE;
-/*
- * We must check the CONFIG_AEDSP16_BASE region too because these are the I/O 
- * ports to access card's control registers.
- */
-       if (!(ae_config.init & INIT_MPU401)) {
-               if (check_region(ae_config.base_io, IOBASE_REGION_SIZE)) {
-                       printk(
-                       "AEDSP16 BASE I/O port region is already in use.\n");
-                       return FALSE;
-               }
-       }
-
-/*
- * We must allocate the CONFIG_AEDSP16_BASE region too because these are the 
- * I/O ports to access card's control registers.
- */
-       if (!(ae_config.init & INIT_MPU401))
-               request_region(ae_config.base_io, IOBASE_REGION_SIZE,
-                               "aedsp16 (base)");
-
-       ae_config.init |= INIT_MSS;
-
-       DBG(("done.\n"));
-
-       return TRUE;
-}
-
-static void __init uninit_aedsp16_mss(void)
-{
-       DBG(("uninit_aedsp16_mss: "));
-
-       if ((!(ae_config.init & INIT_MPU401)) &&
-          (ae_config.init & INIT_MSS)) {
-               release_region(ae_config.base_io, IOBASE_REGION_SIZE);
-               DBG(("AEDSP16 base region released.\n"));
-       }
-
-       ae_config.init &= ~INIT_MSS;
-       DBG(("done.\n"));
-}
-
-static int __init init_aedsp16_mpu(void)
-{
-       DBG(("init_aedsp16_mpu: "));
-
-       if (ae_config.init & INIT_MPU401)
-               return FALSE;
-
-/*
- * We must check the CONFIG_AEDSP16_BASE region too because these are the I/O 
- * ports to access card's control registers.
- */
-       if (!(ae_config.init & (INIT_MSS | INIT_SBPRO))) {
-               if (check_region(ae_config.base_io, IOBASE_REGION_SIZE)) {
-                       printk(
-                       "AEDSP16 BASE I/O port region is already in use.\n");
-                       return FALSE;
-               }
-       }
-
-       if (!(ae_config.init & (INIT_MSS | INIT_SBPRO)))
-               request_region(ae_config.base_io, IOBASE_REGION_SIZE,
-                               "aedsp16 (base)");
-
-       ae_config.init |= INIT_MPU401;
-
-       DBG(("done.\n"));
-
-       return TRUE;
-}
-
-static void __init uninit_aedsp16_mpu(void)
-{
-       DBG(("uninit_aedsp16_mpu: "));
-
-       if ((!(ae_config.init & (INIT_MSS | INIT_SBPRO))) &&
-          (ae_config.init & INIT_MPU401)) {
-               release_region(ae_config.base_io, IOBASE_REGION_SIZE);
-               DBG(("AEDSP16 base region released.\n"));
-       }
-
-       ae_config.init &= ~INIT_MPU401;
-
-       DBG(("done.\n"));
-}
-
-int __init init_aedsp16(void)
-{
-       int initialized = FALSE;
-
-#if !defined(MODULE)
-       ae_config.base_io = CONFIG_AEDSP16_BASE;
-#if defined(CONFIG_AEDSP16_SBPRO)
-       ae_config.irq = CONFIG_AEDSP16_SB_IRQ;
-       ae_config.dma = CONFIG_AEDSP16_SB_DMA;
-#endif
-#if defined(CONFIG_AEDSP16_MSS)
-       ae_config.mss_base = CONFIG_MSS_BASE;
-       ae_config.irq = CONFIG_AEDSP16_MSS_IRQ;
-       ae_config.dma = CONFIG_AEDSP16_MSS_DMA;
-#endif
-#if defined(CONFIG_AEDSP16_MPU401)
-       ae_config.mpu_base = CONFIG_MPU_BASE;
-       ae_config.mpu_irq = CONFIG_AEDSP16_MPU_IRQ;
-#endif
-#endif /* !MODULE */
-       DBG(("Initializing BASE[0x%x] IRQ[%d] DMA[%d] MIRQ[%d]\n",
-            ae_config.base_io,ae_config.irq,ae_config.dma,ae_config.mpu_irq));
-
-       if (ae_config.mss_base == -1) {
-               if (init_aedsp16_sb() == FALSE) {
-                       uninit_aedsp16_sb();
-               } else {
-                       initialized = TRUE;
-               }
-       }
-
-       if (ae_config.mpu_base != -1) {
-               if (init_aedsp16_mpu() == FALSE) {
-                       uninit_aedsp16_mpu();
-               } else {
-                       initialized = TRUE;
-               }
-       }
-
-/*
- * In the sequence of init routines, the MSS init MUST be the last!
- * This because of the special register programming the MSS mode needs.
- * A board reset would disable the MSS mode restoring the default SBPRO
- * mode.
- */
-       if (ae_config.mss_base != -1) {
-               if (init_aedsp16_mss() == FALSE) {
-                       uninit_aedsp16_mss();
-               } else {
-                       initialized = TRUE;
-               }
-       }
-
-       if (initialized)
-               initialized = aedsp16_init_board();
-       return initialized;
-}
-
-void __init uninit_aedsp16(void)
-{
-       if (ae_config.mss_base != -1)
-               uninit_aedsp16_mss();
-       else
-               uninit_aedsp16_sb();
-       if (ae_config.mpu_base != -1)
-               uninit_aedsp16_mpu();
-}
-
-#if defined(MODULE)
-
-int io = -1;
-int irq = -1;
-int dma = -1;
-int mpu_irq = -1;
-int mss_base = -1;
-int mpu_base = -1;
-
-
-MODULE_PARM(io, "i");
-MODULE_PARM_DESC(io, "I/O base address (0x220 0x240)");
-MODULE_PARM(irq, "i");
-MODULE_PARM_DESC(irq, "IRQ line (5 7 9 10 11)");
-MODULE_PARM(dma, "i");
-MODULE_PARM_DESC(dma, "dma line (0 1 3)");
-MODULE_PARM(mpu_irq, "i");
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ line (5 7 9 10 0)");
-MODULE_PARM(mss_base, "i");
-MODULE_PARM_DESC(mss_base, "MSS emulation I/O base address (0x530 0xE80)");
-MODULE_PARM(mpu_base, "i");
-MODULE_PARM_DESC(mpu_base,"MPU-401 I/O base address (0x300 0x310 0x320 0x330)");
-MODULE_AUTHOR("Riccardo Facchetti <fizban@tin.it>");
-MODULE_DESCRIPTION("Audio Excel DSP 16 Driver Version " VERSION);
-
-int init_module(void) {
-       printk("Audio Excel DSP 16 init driver Copyright (C) Riccardo Facchetti 1995-98\n");
-       if (io == -1 || dma == -1 || irq == -1) {
-               printk(KERN_INFO "aedsp16: I/O, IRQ and DMA are mandatory\n");
-               return -EINVAL;
-       }
-
-       ae_config.base_io = io;
-       ae_config.irq = irq;
-       ae_config.dma = dma;
-
-       ae_config.mss_base = mss_base;
-       ae_config.mpu_base = mpu_base;
-       ae_config.mpu_irq = mpu_irq;
-
-       if (init_aedsp16() == FALSE) {
-               printk(KERN_ERR "aedsp16: initialization failed\n");
-               /*
-                * XXX
-                * What error should we return here ?
-                */
-               return -EINVAL;
-       }
-       SOUND_LOCK;
-       return 0;
-}
-
-void cleanup_module(void) {
-       uninit_aedsp16();
-       SOUND_LOCK_END;
-}
-#endif /* MODULE */
-
-#endif /* CONFIG_AEDSP16 */
diff --git a/drivers/sound/lowlevel/awe_compat.h b/drivers/sound/lowlevel/awe_compat.h
deleted file mode 100644 (file)
index 6ced8d6..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * sound/awe_compat.h
- *
- * Compat defines for the AWE32/SB32/AWE64 wave table synth driver.
- *   version 0.4.3; Oct. 1, 1998
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef AWE_COMPAT_H_DEF
-#define AWE_COMPAT_H_DEF
-
-/*================================================================
- * version check
- *================================================================*/
-
-#include "awe_config.h"
-
-#define ASC_LINUX_VERSION(V,P,S)    (((V) * 65536) + ((P) * 256) + (S))
-
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-/* linux version check */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-#define AWE_OBSOLETE_VOXWARE
-#endif
-
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
-#define AWE_NEW_KERNEL_INTERFACE
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,80)
-#define AWE_MODULE_SUPPORT
-#endif
-#endif
-
-#ifdef AWE_OBSOLETE_VOXWARE
-#include "soundvers.h"
-#else
-#include "../soundvers.h"
-#endif
-
-#if defined(SOUND_INTERNAL_VERSION) && SOUND_INTERNAL_VERSION >= 0x30803
-/* OSS/Free-3.8 */
-#define AWE_NO_PATCHMGR
-#define AWE_OSS38
-#define HAS_LOWLEVEL_H
-#endif
-
-/*================================================================
- * INCLUDE OTHER HEADER FILES
- *================================================================*/
-
-/* set up module */
-
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include "../soundmodule.h"
-#endif
-
-
-/* reading configuration of sound driver */
-
-#ifdef AWE_OBSOLETE_VOXWARE
-
-#include "sound_config.h"
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32)
-#define CONFIG_AWE32_SYNTH
-#endif
-
-#else /* AWE_OBSOLETE_VOXWARE */
-
-#ifdef HAS_LOWLEVEL_H
-#include "lowlevel.h"
-#endif
-
-#include "../sound_config.h"
-
-#endif /* AWE_OBSOLETE_VOXWARE */
-
-
-/*================================================================
- * include AWE header files
- *================================================================*/
-
-#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE)
-
-#include "awe_hw.h"
-#include "awe_version.h"
-#include <linux/awe_voice.h>
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-/* include finetune table */
-#ifdef AWE_OBSOLETE_VOXWARE
-#  include "tuning.h"
-#else
-#  include "../tuning.h"
-#endif
-#include <linux/ultrasound.h>
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*----------------------------------------------------------------
- * compatibility macros for AWE32 driver
- *----------------------------------------------------------------*/
-
-/* redefine following macros */
-#undef IOCTL_IN
-#undef IOCTL_OUT
-#undef OUTW
-#undef COPY_FROM_USER
-#undef COPY_TO_USER
-#undef GET_BYTE_FROM_USER
-#undef GET_SHORT_FROM_USER
-#undef IOCTL_TO_USER
-  
-/* use inline prefix */
-#define INLINE /*inline*/
-
-/*----------------------------------------------------------------
- * memory management for linux
- *----------------------------------------------------------------*/
-
-#ifdef AWE_OBSOLETE_VOXWARE
-/* old type linux system */
-
-/* i/o requests; nothing */
-#define awe_check_port()       0       /* always false */
-#define awe_request_region()   /* nothing */
-#define awe_release_region()   /* nothing */
-
-static int _mem_start;  /* memory pointer for permanent buffers */
-
-#define my_malloc_init(memptr) _mem_start = (memptr)
-#define my_malloc_memptr()     _mem_start
-#define my_free(ptr)   /* do nothing */
-
-/* allocate buffer only once */
-#define INIT_TABLE(buffer,index,nums,type) {\
-PERMANENT_MALLOC(buffer, char*, size, _mem_start); index = (nums);\
-}
-
-#else
-
-#define AWE_DYNAMIC_BUFFER
-
-#define my_malloc_init(ptr)    /* nothing */
-#define my_malloc_memptr()     0
-#define my_malloc(size)                vmalloc(size)
-#define my_free(ptr)           if (ptr) {vfree(ptr);}
-
-/* do not allocate buffer at beginning */
-#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;}
-
-/* old type macro */
-#define RET_ERROR(err)         -err
-
-#endif
-
-/*----------------------------------------------------------------
- * i/o interfaces for linux
- *----------------------------------------------------------------*/
-
-#define OUTW(data,addr)                outw(data, addr)
-
-#ifdef AWE_NEW_KERNEL_INTERFACE
-#define COPY_FROM_USER(target,source,offs,count) \
-       copy_from_user(target, (source)+(offs), count)
-#define GET_BYTE_FROM_USER(target,addr,offs) \
-       get_user(target, (unsigned char*)&((addr)[offs]))
-#define GET_SHORT_FROM_USER(target,addr,offs) \
-       get_user(target, (unsigned short*)&((addr)[offs]))
-#ifdef AWE_OSS38
-#define IOCTL_TO_USER(target,offs,source,count) \
-       memcpy(target, (source)+(offs), count)
-#define IO_WRITE_CHECK(cmd)    (_SIOC_DIR(cmd) & _IOC_WRITE)
-#else
-#define IOCTL_TO_USER(target,offs,source,count) \
-       copy_to_user(target, (source)+(offs), count)
-#define IO_WRITE_CHECK(cmd)    (_IOC_DIR(cmd) & _IOC_WRITE)
-#endif /* AWE_OSS38 */
-#define COPY_TO_USER   IOCTL_TO_USER
-#define IOCTL_IN(arg)  (*(int*)(arg))
-#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val))
-
-#else /* old type i/o */
-#define COPY_FROM_USER(target,source,offs,count) \
-       memcpy_fromfs(target, (source)+(offs), (count))
-#define GET_BYTE_FROM_USER(target,addr,offs) \
-       *((char  *)&(target)) = get_fs_byte((addr)+(offs))
-#define GET_SHORT_FROM_USER(target,addr,offs) \
-       *((short *)&(target)) = get_fs_word((addr)+(offs))
-#ifdef AWE_OSS38
-#define IOCTL_TO_USER(target,offs,source,count) \
-       memcpy(target, (source)+(offs), count)
-#define COPY_TO_USER(target,offs,source,count)  \
-       memcpy_tofs(target, (source)+(offs), (count))
-#define IOCTL_IN(arg)  (*(int*)(arg))
-#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val))
-#define IO_WRITE_CHECK(cmd)    (_SIOC_DIR(cmd) & _IOC_WRITE)
-#else /* AWE_OSS38 */
-#define IOCTL_TO_USER(target,offs,source,count) \
-       memcpy_tofs(target, (source)+(offs), (count))
-#define COPY_TO_USER   IOCTL_TO_USER
-#define IOCTL_IN(arg)          get_fs_long((long *)(arg))
-#define IOCTL_OUT(arg,ret)     snd_ioctl_return((int *)arg, ret)
-#define IO_WRITE_CHECK(cmd)    (cmd & IOC_IN)
-#endif /* AWE_OSS38 */
-
-#endif /* AWE_NEW_KERNEL_INTERFACE */
-
-#define BZERO(target,len)      memset(target, 0, len)
-#define MEMCPY(dst,src,len)    memcpy(dst, src, len)
-#define MEMCMP(p1,p2,len)      memcmp(p1, p2, len)
-
-/* old style device tables (not modulized) */
-#ifndef AWE_MODULE_SUPPORT
-
-#define sound_alloc_synthdev() \
-       (num_synths >= MAX_SYNTH_DEV ? -1 : num_synths++)
-#define sound_alloc_mixerdev() \
-       (num_mixers >= MAX_MIXER_DEV ? -1 : num_mixers++)
-#define sound_alloc_mididev() \
-       (num_midis >= MAX_MIXER_DEV ? -1 : num_midis++)
-#define sound_unload_synthdev(dev)     /**/
-#define sound_unload_mixerdev(dev)     /**/
-#define sound_unload_mididev(dev)      /**/
-
-#endif /* AWE_MODULE_SUPPORT */
-
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
-inline static void interruptible_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout)
-{
-       current->timeout = jiffies + timeout;
-       interruptible_sleep_on(q);
-}
-#endif
-
-#endif /* CONFIG_AWE32_SYNTH */
-
-#endif /* AWE_COMPAT_H_DEF */
diff --git a/drivers/sound/lowlevel/awe_config.h b/drivers/sound/lowlevel/awe_config.h
deleted file mode 100644 (file)
index ffb958d..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * sound/awe_config.h
- *
- * Configuration of AWE32/SB32/AWE64 wave table synth driver.
- *   version 0.4.3; Mar. 1, 1998
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef AWE_CONFIG_H_DEF
-#define AWE_CONFIG_H_DEF
-
-/*----------------------------------------------------------------
- * system configuration
- *----------------------------------------------------------------*/
-
-/* if your kernel support module for each soundcard, define this.
- * NOTE: it will be automatically set on linux-2.1.x kernels.
- *       only define here if you have moduler sound system on
- *       2.0.x kernel (like RedHat).
- */
-#undef AWE_MODULE_SUPPORT
-
-
-/*----------------------------------------------------------------
- * chorus & reverb effects send for FM chip: from 0 to 0xff
- * larger numbers often cause weird sounds.
- *----------------------------------------------------------------*/
-
-#define DEF_FM_CHORUS_DEPTH    0x10
-#define DEF_FM_REVERB_DEPTH    0x10
-
-
-/*----------------------------------------------------------------*
- * other compile conditions
- *----------------------------------------------------------------*/
-
-/* initialize FM passthrough even without extended RAM */
-#undef AWE_ALWAYS_INIT_FM
-
-/* debug on */
-#define AWE_DEBUG_ON
-
-/* GUS compatible mode */
-#define AWE_HAS_GUS_COMPATIBILITY
-
-/* add MIDI emulation by wavetable */
-#define CONFIG_AWE32_MIDIEMU
-
-/* add mixer control of emu8000 equalizer */
-#undef CONFIG_AWE32_MIXER
-
-/* use new volume calculation method as default */
-#define AWE_USE_NEW_VOLUME_CALC
-
-/* check current volume target for searching empty voices */
-#define AWE_CHECK_VTARGET
-
-/* allow sample sharing */
-#define AWE_ALLOW_SAMPLE_SHARING
-
-/*================================================================
- * Usually, you don't have to touch the following options.
- *================================================================*/
-
-/*----------------------------------------------------------------
- * AWE32 card configuration:
- * uncomment the following lines *ONLY* when auto detection doesn't
- * work properly on your machine.
- *----------------------------------------------------------------*/
-
-/*#define AWE_DEFAULT_BASE_ADDR        0x620*/ /* base port address */
-/*#define AWE_DEFAULT_MEM_SIZE 512*/   /* kbytes */
-
-/*----------------------------------------------------------------
- * maximum size of soundfont list table
- *----------------------------------------------------------------*/
-
-#define AWE_MAX_SF_LISTS 16
-
-/*----------------------------------------------------------------
- * chunk size of sample and voice tables
- *----------------------------------------------------------------*/
-
-#define AWE_MAX_SAMPLES 400
-#define AWE_MAX_INFOS 800
-
-#endif  /* AWE_CONFIG_H_DEF */
diff --git a/drivers/sound/lowlevel/awe_hw.h b/drivers/sound/lowlevel/awe_hw.h
deleted file mode 100644 (file)
index c7dde26..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * sound/awe_hw.h
- *
- * Access routines and definitions for the low level driver for the 
- * Creative AWE32/SB32/AWE64 wave table synth.
- *   version 0.4.3; Mar. 1, 1998
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef AWE_HW_H_DEF
-#define AWE_HW_H_DEF
-
-/*
- * Emu-8000 control registers
- * name(channel)       reg, port
- */
-
-#define awe_cmd_idx(reg,ch)    (((reg)<< 5) | (ch))
-
-#define Data0    0             /* 0x620: doubleword r/w */
-#define Data1    1             /* 0xA20: doubleword r/w */
-#define Data2    2             /* 0xA22: word r/w */
-#define Data3    3             /* 0xE20: word r/w */
-#define Pointer  4             /* 0xE22 register pointer r/w */
-
-#define AWE_CPF(ch)    awe_cmd_idx(0,ch), Data0        /* DW: current pitch and fractional address */
-#define AWE_PTRX(ch)   awe_cmd_idx(1,ch), Data0        /* DW: pitch target and reverb send */
-#define AWE_CVCF(ch)   awe_cmd_idx(2,ch), Data0        /* DW: current volume and filter cutoff */
-#define AWE_VTFT(ch)   awe_cmd_idx(3,ch), Data0        /* DW: volume and filter cutoff targets */
-#define AWE_0080(ch)   awe_cmd_idx(4,ch), Data0        /* DW: ?? */
-#define AWE_00A0(ch)   awe_cmd_idx(5,ch), Data0        /* DW: ?? */
-#define AWE_PSST(ch)   awe_cmd_idx(6,ch), Data0        /* DW: pan send and loop start address */
-#define AWE_CSL(ch)    awe_cmd_idx(7,ch), Data0        /* DW: chorus send and loop end address */
-#define AWE_CCCA(ch)   awe_cmd_idx(0,ch), Data1        /* DW: Q, control bits, and current address */
-#define AWE_HWCF4      awe_cmd_idx(1,9),  Data1        /* DW: config dw 4 */
-#define AWE_HWCF5      awe_cmd_idx(1,10), Data1        /* DW: config dw 5 */
-#define AWE_HWCF6      awe_cmd_idx(1,13), Data1        /* DW: config dw 6 */
-#define AWE_HWCF7      awe_cmd_idx(1,14), Data1        /* DW: config dw 7? (not documented) */
-#define AWE_SMALR      awe_cmd_idx(1,20), Data1        /* DW: sound memory address for left read */
-#define AWE_SMARR      awe_cmd_idx(1,21), Data1        /* DW:    for right read */
-#define AWE_SMALW      awe_cmd_idx(1,22), Data1        /* DW: sound memory address for left write */
-#define AWE_SMARW      awe_cmd_idx(1,23), Data1        /* DW:    for right write */
-#define AWE_SMLD       awe_cmd_idx(1,26), Data1        /* W: sound memory left data */
-#define AWE_SMRD       awe_cmd_idx(1,26), Data2        /* W:    right data */
-#define AWE_WC         awe_cmd_idx(1,27), Data2        /* W: sample counter */
-#define AWE_WC_Cmd     awe_cmd_idx(1,27)
-#define AWE_WC_Port    Data2
-#define AWE_HWCF1      awe_cmd_idx(1,29), Data1        /* W: config w 1 */
-#define AWE_HWCF2      awe_cmd_idx(1,30), Data1        /* W: config w 2 */
-#define AWE_HWCF3      awe_cmd_idx(1,31), Data1        /* W: config w 3 */
-#define AWE_INIT1(ch)  awe_cmd_idx(2,ch), Data1        /* W: init array 1 */
-#define AWE_INIT2(ch)  awe_cmd_idx(2,ch), Data2        /* W: init array 2 */
-#define AWE_INIT3(ch)  awe_cmd_idx(3,ch), Data1        /* W: init array 3 */
-#define AWE_INIT4(ch)  awe_cmd_idx(3,ch), Data2        /* W: init array 4 */
-#define AWE_ENVVOL(ch) awe_cmd_idx(4,ch), Data1        /* W: volume envelope delay */
-#define AWE_DCYSUSV(ch)        awe_cmd_idx(5,ch), Data1        /* W: volume envelope sustain and decay */
-#define AWE_ENVVAL(ch) awe_cmd_idx(6,ch), Data1        /* W: modulation envelope delay */
-#define AWE_DCYSUS(ch) awe_cmd_idx(7,ch), Data1        /* W: modulation envelope sustain and decay */
-#define AWE_ATKHLDV(ch)        awe_cmd_idx(4,ch), Data2        /* W: volume envelope attack and hold */
-#define AWE_LFO1VAL(ch)        awe_cmd_idx(5,ch), Data2        /* W: LFO#1 Delay */
-#define AWE_ATKHLD(ch) awe_cmd_idx(6,ch), Data2        /* W: modulation envelope attack and hold */
-#define AWE_LFO2VAL(ch)        awe_cmd_idx(7,ch), Data2        /* W: LFO#2 Delay */
-#define AWE_IP(ch)     awe_cmd_idx(0,ch), Data3        /* W: initial pitch */
-#define AWE_IFATN(ch)  awe_cmd_idx(1,ch), Data3        /* W: initial filter cutoff and attenuation */
-#define AWE_PEFE(ch)   awe_cmd_idx(2,ch), Data3        /* W: pitch and filter envelope heights */
-#define AWE_FMMOD(ch)  awe_cmd_idx(3,ch), Data3        /* W: vibrato and filter modulation freq */
-#define AWE_TREMFRQ(ch)        awe_cmd_idx(4,ch), Data3        /* W: LFO#1 tremolo amount and freq */
-#define AWE_FM2FRQ2(ch)        awe_cmd_idx(5,ch), Data3        /* W: LFO#2 vibrato amount and freq */
-
-/* used during detection (returns ROM version?; not documented in ADIP) */
-#define AWE_U1         0xE0, Data3       /* (R)(W) used in initialization */
-#define AWE_U2(ch)     0xC0+(ch), Data3  /* (W)(W) used in init envelope  */
-
-
-#define AWE_MAX_VOICES         32
-#define AWE_NORMAL_VOICES      30      /*30&31 are reserved for DRAM refresh*/
-
-#define AWE_MAX_CHANNELS       32      /* max midi channels (must >= voices) */
-#define AWE_MAX_LAYERS AWE_MAX_VOICES  /* maximum number of multiple layers */
-
-#define AWE_DRAM_OFFSET                0x200000
-#define AWE_MAX_DRAM_SIZE      (28 * 1024)     /* 28 MB is max onboard memory */
-
-#endif
diff --git a/drivers/sound/lowlevel/awe_version.h b/drivers/sound/lowlevel/awe_version.h
deleted file mode 100644 (file)
index a012d73..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * sound/awe_version.h
- *
- * Version defines for the AWE32/SB32/AWE64 wave table synth driver.
- *   version 0.4.3; Mar. 1, 1998
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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.
- */
-
-/* AWE32 driver version number */
-
-#ifndef AWE_VERSION_H_DEF
-#define AWE_VERSION_H_DEF
-
-#define AWE_MAJOR_VERSION      0
-#define AWE_MINOR_VERSION      4
-#define AWE_TINY_VERSION       3
-#define AWE_VERSION_NUMBER     ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION)
-#define AWEDRV_VERSION         "0.4.3"
-
-#endif
diff --git a/drivers/sound/lowlevel/awe_wave.c b/drivers/sound/lowlevel/awe_wave.c
deleted file mode 100644 (file)
index 8608e17..0000000
+++ /dev/null
@@ -1,6255 +0,0 @@
-/*
- * sound/awe_wave.c
- *
- * The low level driver for the AWE32/SB32/AWE64 wave table synth.
- *   version 0.4.3; Feb. 1, 1999
- *
- * Copyright (C) 1996-1999 Takashi Iwai
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* include initial header files and compatibility macros */
-#ifdef __FreeBSD__
-#  include <i386/isa/sound/awe_compat.h>
-#else
-#  include "awe_compat.h"
-#endif /* FreeBSD */
-#ifdef __linux__
-#  include <linux/config.h>
-#endif
-
-/*----------------------------------------------------------------*/
-
-#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE)
-
-/*----------------------------------------------------------------
- * debug message
- *----------------------------------------------------------------*/
-
-#ifdef AWE_DEBUG_ON
-#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }}
-#define ERRMSG(XXX)    {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }}
-#define FATALERR(XXX)  XXX
-#else
-#define DEBUG(LVL,XXX) /**/
-#define ERRMSG(XXX)    XXX
-#define FATALERR(XXX)  XXX
-#endif
-
-/*----------------------------------------------------------------
- * bank and voice record
- *----------------------------------------------------------------*/
-
-/* soundfont record */
-typedef struct _sf_list {
-       unsigned short sf_id;
-       unsigned short type;
-       int num_info;           /* current info table index */
-       int num_sample;         /* current sample table index */
-       int mem_ptr;            /* current word byte pointer */
-       int infos;
-       int samples;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-       int shared;             /* shared index */
-       unsigned char name[AWE_PATCH_NAME_LEN];
-#endif
-} sf_list;
-
-/* bank record */
-typedef struct _awe_voice_list {
-       int next;       /* linked list with same sf_id */
-       unsigned char bank, instr;      /* preset number information */
-       char type, disabled;    /* type=normal/mapped, disabled=boolean */
-       awe_voice_info v;       /* voice information */
-       int next_instr; /* preset table list */
-       int next_bank;  /* preset table list */
-} awe_voice_list;
-
-/* voice list type */
-#define V_ST_NORMAL    0
-#define V_ST_MAPPED    1
-
-typedef struct _awe_sample_list {
-       int next;       /* linked list with same sf_id */
-       awe_sample_info v;      /* sample information */
-} awe_sample_list;
-
-/* sample and information table */
-static int current_sf_id = 0;
-static int locked_sf_id = 0;
-static int max_sfs;
-static sf_list *sflists = NULL;
-
-#define awe_free_mem_ptr() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].mem_ptr)
-#define awe_free_info() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_info)
-#define awe_free_sample() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_sample)
-
-static int max_samples;
-static awe_sample_list *samples = NULL;
-
-static int max_infos;
-static awe_voice_list *infos = NULL;
-
-
-#define AWE_MAX_PRESETS                256
-#define AWE_DEFAULT_PRESET     0
-#define AWE_DEFAULT_BANK       0
-#define AWE_DEFAULT_DRUM       0
-#define AWE_DRUM_BANK          128
-
-#define MAX_LAYERS     AWE_MAX_VOICES
-
-/* preset table index */
-static int preset_table[AWE_MAX_PRESETS];
-
-/*----------------------------------------------------------------
- * voice table
- *----------------------------------------------------------------*/
-
-/* effects table */
-typedef        struct FX_Rec { /* channel effects */
-       unsigned char flags[AWE_FX_END];
-       short val[AWE_FX_END];
-} FX_Rec;
-
-
-/* channel parameters */
-typedef struct _awe_chan_info {
-       int channel;            /* channel number */
-       int bank;               /* current tone bank */
-       int instr;              /* current program */
-       int bender;             /* midi pitchbend (-8192 - 8192) */
-       int bender_range;       /* midi bender range (x100) */
-       int panning;            /* panning (0-127) */
-       int main_vol;           /* channel volume (0-127) */
-       int expression_vol;     /* midi expression (0-127) */
-       int chan_press;         /* channel pressure */
-       int vrec;               /* instrument list */
-       int def_vrec;           /* default instrument list */
-       int sustained;          /* sustain status in MIDI */
-       FX_Rec fx;              /* effects */
-       FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */
-} awe_chan_info;
-
-/* voice parameters */
-typedef struct _voice_info {
-       int state;
-#define AWE_ST_OFF             (1<<0)  /* no sound */
-#define AWE_ST_ON              (1<<1)  /* playing */
-#define AWE_ST_STANDBY         (1<<2)  /* stand by for playing */
-#define AWE_ST_SUSTAINED       (1<<3)  /* sustained */
-#define AWE_ST_MARK            (1<<4)  /* marked for allocation */
-#define AWE_ST_DRAM            (1<<5)  /* DRAM read/write */
-#define AWE_ST_FM              (1<<6)  /* reserved for FM */
-#define AWE_ST_RELEASED                (1<<7)  /* released */
-
-       int ch;                 /* midi channel */
-       int key;                /* internal key for search */
-       int layer;              /* layer number (for channel mode only) */
-       int time;               /* allocated time */
-       awe_chan_info   *cinfo; /* channel info */
-
-       int note;               /* midi key (0-127) */
-       int velocity;           /* midi velocity (0-127) */
-       int sostenuto;          /* sostenuto on/off */
-       awe_voice_info *sample; /* assigned voice */
-
-       /* EMU8000 parameters */
-       int apitch;             /* pitch parameter */
-       int avol;               /* volume parameter */
-       int apan;               /* panning parameter */
-       int acutoff;            /* cutoff parameter */
-       short aaux;             /* aux word */
-} voice_info;
-
-/* voice information */
-static voice_info voices[AWE_MAX_VOICES];
-
-#define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED))
-#define IS_NO_EFFECT(v)        (voices[v].state != AWE_ST_ON)
-#define IS_PLAYING(v)  (voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED))
-#define IS_EMPTY(v)    (voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM))
-
-
-/* MIDI channel effects information (for hw control) */
-static awe_chan_info channels[AWE_MAX_CHANNELS];
-
-
-/*----------------------------------------------------------------
- * global variables
- *----------------------------------------------------------------*/
-
-#ifndef AWE_DEFAULT_BASE_ADDR
-#define AWE_DEFAULT_BASE_ADDR  0       /* autodetect */
-#endif
-
-#ifndef AWE_DEFAULT_MEM_SIZE
-#define AWE_DEFAULT_MEM_SIZE   -1      /* autodetect */
-#endif
-
-/* set variables */
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
-/* replace awe_port variable with exported variable */
-#define awe_port       io
-#define awe_mem_size   memsize
-int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */
-int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */
-#ifdef MODULE_PARM
-MODULE_PARM(io, "i");
-MODULE_PARM_DESC(io, "base i/o port of Emu8000");
-MODULE_PARM(memsize, "i");
-MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes");
-#endif
-#else
-static int awe_port = AWE_DEFAULT_BASE_ADDR;
-static int awe_mem_size = AWE_DEFAULT_MEM_SIZE;
-#endif /* module */
-
-/* DRAM start offset */
-static int awe_mem_start = AWE_DRAM_OFFSET;
-
-/* maximum channels for playing */
-static int awe_max_voices = AWE_MAX_VOICES;
-
-static int patch_opened = 0;           /* sample already loaded? */
-
-static char atten_relative = FALSE;
-static short atten_offset = 0;
-
-static int awe_present = FALSE;                /* awe device present? */
-static int awe_busy = FALSE;           /* awe device opened? */
-
-static int my_dev = -1;                        
-
-#define DEFAULT_DRUM_FLAGS     ((1 << 9) | (1 << 25))
-#define IS_DRUM_CHANNEL(c)     (drum_flags & (1 << (c)))
-#define DRUM_CHANNEL_ON(c)     (drum_flags |= (1 << (c)))
-#define DRUM_CHANNEL_OFF(c)    (drum_flags &= ~(1 << (c)))
-static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */
-
-static int playing_mode = AWE_PLAY_INDIRECT;
-#define SINGLE_LAYER_MODE()    (playing_mode == AWE_PLAY_INDIRECT || playing_mode == AWE_PLAY_DIRECT)
-#define MULTI_LAYER_MODE()     (playing_mode == AWE_PLAY_MULTI || playing_mode == AWE_PLAY_MULTI2)
-
-static int current_alloc_time = 0;     /* voice allocation index for channel mode */
-
-static struct synth_info awe_info = {
-       "AWE32 Synth",          /* name */
-       0,                      /* device */
-       SYNTH_TYPE_SAMPLE,      /* synth_type */
-       SAMPLE_TYPE_AWE32,      /* synth_subtype */
-       0,                      /* perc_mode (obsolete) */
-       AWE_MAX_VOICES,         /* nr_voices */
-       0,                      /* nr_drums (obsolete) */
-       AWE_MAX_INFOS           /* instr_bank_size */
-};
-
-
-static struct voice_alloc_info *voice_alloc;   /* set at initialization */
-
-
-/*----------------------------------------------------------------
- * function prototypes
- *----------------------------------------------------------------*/
-
-#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE)
-static int awe_check_port(void);
-static void awe_request_region(void);
-static void awe_release_region(void);
-#endif /* linux & obsolete */
-
-static void awe_reset_samples(void);
-/* emu8000 chip i/o access */
-static void setup_ports(int p1, int p2, int p3);
-static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data);
-static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data);
-static unsigned short awe_peek(unsigned short cmd, unsigned short port);
-static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port);
-static void awe_wait(unsigned short delay);
-
-/* initialize emu8000 chip */
-static int _attach_awe(void);
-static void _unload_awe(void);
-static void awe_initialize(void);
-
-/* set voice parameters */
-static void awe_init_ctrl_parms(int init_all);
-static void awe_init_voice_info(awe_voice_info *vp);
-static void awe_init_voice_parm(awe_voice_parm *pp);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static int freq_to_note(int freq);
-static int calc_rate_offset(int Hz);
-/*static int calc_parm_delay(int msec);*/
-static int calc_parm_hold(int msec);
-static int calc_parm_attack(int msec);
-static int calc_parm_decay(int msec);
-static int calc_parm_search(int msec, short *table);
-#endif /* gus compat */
-
-/* turn on/off note */
-static void awe_note_on(int voice);
-static void awe_note_off(int voice);
-static void awe_terminate(int voice);
-static void awe_exclusive_off(int voice);
-static void awe_note_off_all(int do_sustain);
-
-/* calculate voice parameters */
-typedef void (*fx_affect_func)(int voice, int forced);
-static void awe_set_pitch(int voice, int forced);
-static void awe_set_voice_pitch(int voice, int forced);
-static void awe_set_volume(int voice, int forced);
-static void awe_set_voice_vol(int voice, int forced);
-static void awe_set_pan(int voice, int forced);
-static void awe_fx_fmmod(int voice, int forced);
-static void awe_fx_tremfrq(int voice, int forced);
-static void awe_fx_fm2frq2(int voice, int forced);
-static void awe_fx_filterQ(int voice, int forced);
-static void awe_calc_pitch(int voice);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static void awe_calc_pitch_from_freq(int voice, int freq);
-#endif
-static void awe_calc_volume(int voice);
-static void awe_update_volume(void);
-static void awe_change_master_volume(short val);
-static void awe_voice_init(int voice, int init_all);
-static void awe_channel_init(int ch, int init_all);
-static void awe_fx_init(int ch);
-static void awe_send_effect(int voice, int layer, int type, int val);
-static void awe_modwheel_change(int voice, int value);
-
-/* sequencer interface */
-static int awe_open(int dev, int mode);
-static void awe_close(int dev);
-static int awe_ioctl(int dev, unsigned int cmd, caddr_t arg);
-static int awe_kill_note(int dev, int voice, int note, int velocity);
-static int awe_start_note(int dev, int v, int note_num, int volume);
-static int awe_set_instr(int dev, int voice, int instr_no);
-static int awe_set_instr_2(int dev, int voice, int instr_no);
-static void awe_reset(int dev);
-static void awe_hw_control(int dev, unsigned char *event);
-static int awe_load_patch(int dev, int format, const char *addr,
-                         int offs, int count, int pmgr_flag);
-static void awe_aftertouch(int dev, int voice, int pressure);
-static void awe_controller(int dev, int voice, int ctrl_num, int value);
-static void awe_panning(int dev, int voice, int value);
-static void awe_volume_method(int dev, int mode);
-#ifndef AWE_NO_PATCHMGR
-static int awe_patchmgr(int dev, struct patmgr_info *rec);
-#endif
-static void awe_bender(int dev, int voice, int value);
-static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc);
-static void awe_setup_voice(int dev, int voice, int chn);
-
-#define awe_key_pressure(dev,voice,key,press) awe_start_note(dev,voice,(key)+128,press)
-
-/* hardware controls */
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static void awe_hw_gus_control(int dev, int cmd, unsigned char *event);
-#endif
-static void awe_hw_awe_control(int dev, int cmd, unsigned char *event);
-static void awe_voice_change(int voice, fx_affect_func func);
-static void awe_sostenuto_on(int voice, int forced);
-static void awe_sustain_off(int voice, int forced);
-static void awe_terminate_and_init(int voice, int forced);
-
-/* voice search */
-static int awe_search_instr(int bank, int preset);
-static int awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist);
-static void awe_alloc_multi_voices(int ch, int note, int velocity, int key);
-static void awe_alloc_one_voice(int voice, int note, int velocity);
-static int awe_clear_voice(void);
-
-/* load / remove patches */
-static int awe_open_patch(awe_patch_info *patch, const char *addr, int count);
-static int awe_close_patch(awe_patch_info *patch, const char *addr, int count);
-static int awe_unload_patch(awe_patch_info *patch, const char *addr, int count);
-static int awe_load_info(awe_patch_info *patch, const char *addr, int count);
-static int awe_load_data(awe_patch_info *patch, const char *addr, int count);
-static int awe_replace_data(awe_patch_info *patch, const char *addr, int count);
-static int awe_load_map(awe_patch_info *patch, const char *addr, int count);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static int awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag);
-#endif
-/*static int awe_probe_info(awe_patch_info *patch, const char *addr, int count);*/
-static int awe_probe_data(awe_patch_info *patch, const char *addr, int count);
-static int check_patch_opened(int type, char *name);
-static int awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels);
-static void add_sf_info(int rec);
-static void add_sf_sample(int rec);
-static void purge_old_list(int rec, int next);
-static void add_info_list(int rec);
-static void awe_remove_samples(int sf_id);
-static void rebuild_preset_list(void);
-static short awe_set_sample(awe_voice_info *vp);
-static int search_sample_index(int sf, int sample, int level);
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-static int is_identical_id(int id1, int id2);
-static int is_identical_name(unsigned char *name, int id);
-static int is_shared_sf(unsigned char *name);
-static int info_duplicated(awe_voice_list *rec);
-#endif /* allow sharing */
-
-/* lowlevel functions */
-static void awe_init_audio(void);
-static void awe_init_dma(void);
-static void awe_init_array(void);
-static void awe_send_array(unsigned short *data);
-static void awe_tweak_voice(int voice);
-static void awe_tweak(void);
-static void awe_init_fm(void);
-static int awe_open_dram_for_write(int offset, int channels);
-static void awe_open_dram_for_check(void);
-static void awe_close_dram(void);
-static void awe_write_dram(unsigned short c);
-static int awe_detect_base(int addr);
-static int awe_detect(void);
-static void awe_check_dram(void);
-static int awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count);
-static void awe_set_chorus_mode(int mode);
-static void awe_update_chorus_mode(void);
-static int awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count);
-static void awe_set_reverb_mode(int mode);
-static void awe_update_reverb_mode(void);
-static void awe_equalizer(int bass, int treble);
-static void awe_update_equalizer(void);
-
-#ifdef CONFIG_AWE32_MIXER
-static void attach_mixer(void);
-static void unload_mixer(void);
-#endif
-
-#ifdef CONFIG_AWE32_MIDIEMU
-static void attach_midiemu(void);
-static void unload_midiemu(void);
-#endif
-
-#define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b)
-
-#ifdef __FreeBSD__
-/* FIXME */
-#define MALLOC_LOOP_DATA
-#define WAIT_BY_LOOP
-#endif
-
-/*----------------------------------------------------------------
- * control parameters
- *----------------------------------------------------------------*/
-
-
-#ifdef AWE_USE_NEW_VOLUME_CALC
-#define DEF_VOLUME_CALC        TRUE
-#else
-#define DEF_VOLUME_CALC        FALSE
-#endif /* new volume */
-
-#define DEF_ZERO_ATTEN         32      /* 12dB below */
-#define DEF_MOD_SENSE          18
-#define DEF_CHORUS_MODE                2
-#define DEF_REVERB_MODE                4
-#define DEF_BASS_LEVEL         5
-#define DEF_TREBLE_LEVEL       9
-
-static struct CtrlParmsDef {
-       int value;
-       int init_each_time;
-       void (*update)(void);
-} ctrl_parms[AWE_MD_END] = {
-       {0,0, NULL}, {0,0, NULL}, /* <-- not used */
-       {AWE_VERSION_NUMBER, FALSE, NULL},
-       {TRUE, FALSE, NULL}, /* exclusive */
-       {TRUE, FALSE, NULL}, /* realpan */
-       {AWE_DEFAULT_BANK, FALSE, NULL}, /* gusbank */
-       {FALSE, TRUE, NULL}, /* keep effect */
-       {DEF_ZERO_ATTEN, FALSE, awe_update_volume}, /* zero_atten */
-       {FALSE, FALSE, NULL}, /* chn_prior */
-       {DEF_MOD_SENSE, FALSE, NULL}, /* modwheel sense */
-       {AWE_DEFAULT_PRESET, FALSE, NULL}, /* def_preset */
-       {AWE_DEFAULT_BANK, FALSE, NULL}, /* def_bank */
-       {AWE_DEFAULT_DRUM, FALSE, NULL}, /* def_drum */
-       {FALSE, FALSE, NULL}, /* toggle_drum_bank */
-       {DEF_VOLUME_CALC, FALSE, awe_update_volume}, /* new_volume_calc */
-       {DEF_CHORUS_MODE, FALSE, awe_update_chorus_mode}, /* chorus mode */
-       {DEF_REVERB_MODE, FALSE, awe_update_reverb_mode}, /* reverb mode */
-       {DEF_BASS_LEVEL, FALSE, awe_update_equalizer}, /* bass level */
-       {DEF_TREBLE_LEVEL, FALSE, awe_update_equalizer}, /* treble level */
-       {0, FALSE, NULL},       /* debug mode */
-       {FALSE, FALSE, NULL}, /* pan exchange */
-};
-
-static int ctrls[AWE_MD_END];
-
-
-/*----------------------------------------------------------------
- * synth operation table
- *----------------------------------------------------------------*/
-
-static struct synth_operations awe_operations =
-{
-#ifdef AWE_OSS38
-       "EMU8K",
-#endif
-       &awe_info,
-       0,
-       SYNTH_TYPE_SAMPLE,
-       SAMPLE_TYPE_AWE32,
-       awe_open,
-       awe_close,
-       awe_ioctl,
-       awe_kill_note,
-       awe_start_note,
-       awe_set_instr_2,
-       awe_reset,
-       awe_hw_control,
-       awe_load_patch,
-       awe_aftertouch,
-       awe_controller,
-       awe_panning,
-       awe_volume_method,
-#ifndef AWE_NO_PATCHMGR
-       awe_patchmgr,
-#endif
-       awe_bender,
-       awe_alloc,
-       awe_setup_voice
-};
-
-
-/*================================================================
- * General attach / unload interface
- *================================================================*/
-
-static int _attach_awe(void)
-{
-       if (awe_present) return 0; /* for OSS38.. called twice? */
-
-       /* check presence of AWE32 card */
-       if (! awe_detect()) {
-               printk(KERN_WARNING "AWE32: not detected\n");
-               return 0;
-       }
-
-       /* check AWE32 ports are available */
-#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE)
-       if (awe_check_port()) {
-               printk(KERN_WARNING "AWE32: I/O area already used.\n");
-               return 0;
-       }
-#endif
-
-       /* set buffers to NULL */
-       sflists = NULL;
-       samples = NULL;
-       infos = NULL;
-
-       /* allocate sample tables */
-       INIT_TABLE(sflists, max_sfs, AWE_MAX_SF_LISTS, sf_list);
-       INIT_TABLE(samples, max_samples, AWE_MAX_SAMPLES, awe_sample_list);
-       INIT_TABLE(infos, max_infos, AWE_MAX_INFOS, awe_voice_list);
-
-       my_dev = sound_alloc_synthdev();
-       if (my_dev == -1) {
-               printk(KERN_WARNING "AWE32 Error: too many synthesizers\n");
-               return 0;
-       }
-
-       voice_alloc = &awe_operations.alloc;
-       voice_alloc->max_voice = awe_max_voices;
-       synth_devs[my_dev] = &awe_operations;
-
-#ifdef CONFIG_AWE32_MIXER
-       attach_mixer();
-#endif
-#ifdef CONFIG_AWE32_MIDIEMU
-       attach_midiemu();
-#endif
-
-#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE)
-       /* reserve I/O ports for awedrv */
-       awe_request_region();
-#endif
-
-       /* clear all samples */
-       awe_reset_samples();
-
-       /* intialize AWE32 hardware */
-       awe_initialize();
-
-       sprintf(awe_info.name, "AWE32-%s (RAM%dk)",
-               AWEDRV_VERSION, awe_mem_size/1024);
-       printk("<SoundBlaster EMU8000 (RAM%dk)>\n", awe_mem_size/1024);
-
-       awe_present = TRUE;
-
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
-       SOUND_LOCK;
-#endif
-
-       return 1;
-}
-
-
-#ifdef AWE_DYNAMIC_BUFFER
-static void free_tables(void)
-{
-       if (sflists)
-               my_free(sflists);
-       sflists = NULL; max_sfs = 0;
-       if (samples)
-               my_free(samples);
-       samples = NULL; max_samples = 0;
-       if (infos)
-               my_free(infos);
-       infos = NULL; max_infos = 0;
-}
-
-static void *realloc_block(void *buf, int oldsize, int size)
-{
-       void *ptr;
-       if (oldsize == size)
-               return buf;
-       if ((ptr = my_malloc(size)) == NULL)
-               return NULL;
-       if (oldsize && size)
-               MEMCPY(ptr, buf, ((oldsize < size) ? oldsize : size) );
-       if (buf)
-               my_free(buf);
-       return ptr;
-}
-
-
-#else /* dynamic buffer */
-
-#define free_buffers() /**/
-
-#endif /* dynamic_buffer */
-
-
-static void _unload_awe(void)
-{
-       if (awe_present) {
-               awe_reset_samples();
-               awe_release_region();
-               free_tables();
-#ifdef CONFIG_AWE32_MIXER
-               unload_mixer();
-#endif
-#ifdef CONFIG_AWE32_MIDIEMU
-               unload_midiemu();
-#endif
-               sound_unload_synthdev(my_dev);
-               awe_present = FALSE;
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
-               SOUND_LOCK_END;
-#endif
-       }
-}
-
-
-/*================================================================
- * Linux interface
- *================================================================*/
-
-#ifdef linux
-
-/*----------------------------------------------------------------
- * Linux PnP driver support
- *----------------------------------------------------------------*/
-
-#ifdef CONFIG_PNP_DRV
-
-#include <linux/pnp.h>
-
-static int pnp = 1;    /* use PnP as default */
-
-#define AWE_NUM_CHIPS  3
-static unsigned int pnp_ids[AWE_NUM_CHIPS] = {
-       PNP_EISAID('C','T','L',0x0021),
-       PNP_EISAID('C','T','L',0x0022),
-       PNP_EISAID('C','T','L',0x0023),
-};
-static struct pnp_driver pnp_awe[AWE_NUM_CHIPS];
-static int awe_pnp_ok = 0;
-
-static void awe_pnp_config(struct pnp_device *d)
-{
-       struct pnp_resource *r;
-       int port[3];
-       int nio = 0;
-
-       port[0] = port[1] = port[2] = 0;
-       for (r = d->res; r != NULL; r = r->next) {
-               if (r->type == PNP_RES_IO) {
-                       if (nio >= 0 && nio < 3)
-                               port[nio] = r->start;
-                       nio++;
-               }
-       }
-       setup_ports(port[0], port[1], port[2]);
-       DEBUG(0,printk("AWE32: PnP setup ports: %x:%x:%x\n", port[0], port[1], port[2]));
-}
-
-static int awe_pnp_event (struct pnp_device *d, struct pnp_drv_event *e)
-{
-       struct pnp_driver *drv = d->l.k.driver;
-
-       switch (e->type) {
-       case PNP_DRV_ALLOC:
-               drv->flags |= PNP_DRV_INUSE;
-               awe_pnp_ok = 1;
-               awe_pnp_config(d);
-               _attach_awe();
-               break;
-
-       case PNP_DRV_DISABLE:
-       case PNP_DRV_EMERGSTOP:
-               drv->flags &= ~PNP_DRV_INUSE;
-               awe_pnp_ok = 0;
-               _unload_awe();
-               break;
-
-       case PNP_DRV_CONFIG:
-               if (awe_busy) return 1; /* used now */
-               awe_release_region();
-               awe_pnp_config(d);
-               awe_request_region();
-               break;
-               
-       case PNP_DRV_RECONFIG:
-               break;
-       }
-       return 0;
-}
-
-static int awe_initpnp (void)
-{
-       int i;
-       for (i = 0; i < AWE_NUM_CHIPS; i++) {
-               pnp_awe[i].id.type = PNP_HDL_ISA;
-               pnp_awe[i].id.t.isa.id = pnp_ids[i];
-               pnp_awe[i].id.next = NULL;
-               pnp_awe[i].name = "Soundblaster AWE32/AWE64 PnP";
-               pnp_awe[i].event = awe_pnp_event;
-               pnp_register_driver(&pnp_awe[i], 1);
-       }
-       return 0;
-}
-
-static void awe_unload_pnp (void)
-{
-       int i;
-       for (i = 0; i < AWE_NUM_CHIPS; i++)
-               pnp_unregister_driver(&pnp_awe[i]);
-}
-#endif /* PnP support */
-
-/*----------------------------------------------------------------
- * device / lowlevel (module) interface
- *----------------------------------------------------------------*/
-
-#ifdef AWE_OBSOLETEL_VOXWARE
-
-/* old type interface */
-int attach_awe_obsolete(int mem_start, struct address_info *hw_config)
-{
-       my_malloc_init(mem_start);
-       if (! _attach_awe())
-               return 0;
-       return my_malloc_memptr();
-}
-
-int probe_awe_obsolete(struct address_info *hw_config)
-{
-       return 1;
-       /*return awe_detect();*/
-}
-
-#else /* !obsolete */
-
-/* new type interface */
-int attach_awe(void)
-{
-#ifdef CONFIG_PNP_DRV
-       if (pnp) {
-               awe_initpnp();
-               if (awe_pnp_ok)
-                       return 0;
-       }
-#endif /* pnp */
-       _attach_awe();
-       return 0;
-}
-
-void unload_awe(void)
-{
-#ifdef CONFIG_PNP_DRV
-       if (pnp)
-               awe_unload_pnp();
-#endif /* pnp */
-       _unload_awe();
-}
-
-/* module interface */
-
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
-int init_module(void)
-{
-       return attach_awe();
-}
-
-void cleanup_module(void)
-{
-       unload_awe();
-}
-
-#ifdef MODULE_PARM
-EXPORT_NO_SYMBOLS;
-MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>");
-MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");
-MODULE_SUPPORTED_DEVICE("sound");
-#endif
-
-#endif /* module */
-
-#endif /* AWE_OBSOLETE_VOXWARE */
-
-#endif /* linux */
-
-
-/*================================================================
- * FreeBSD interface
- *================================================================*/
-
-#ifdef __FreeBSD__
-
-#ifdef AWE_OBSOLETE_VOXWARE
-long attach_awe_obsolete(long mem_start, struct address_info *hw_config)
-{
-       _attach_awe();
-       return 0;
-}
-
-int probe_awe_obsolete(struct address_info *hw_config)
-{
-       return 1;
-}
-
-#else /* !obsolete */
-
-/* new type interface */
-void attach_awe(struct address_info *hw_config)
-{
-       _attach_awe();
-}
-
-int probe_awe(struct address_info *hw_config)
-{
-       return 1;
-}
-
-#endif /* obsolete */
-
-#endif /* FreeBSD */
-
-
-/*================================================================
- * clear sample tables 
- *================================================================*/
-
-static void
-awe_reset_samples(void)
-{
-       int i;
-
-       /* free all bank tables */
-       for (i = 0; i < AWE_MAX_PRESETS; i++)
-               preset_table[i] = -1;
-
-       free_tables();
-
-       current_sf_id = 0;
-       locked_sf_id = 0;
-       patch_opened = 0;
-}
-
-
-/*================================================================
- * EMU register access
- *================================================================*/
-
-/* select a given AWE32 pointer */
-static int awe_ports[5];
-static int port_setuped = FALSE;
-static int awe_cur_cmd = -1;
-#define awe_set_cmd(cmd) \
-if (awe_cur_cmd != cmd) { OUTW(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; }
-
-/* store values to i/o port array */
-static void setup_ports(int port1, int port2, int port3)
-{
-       awe_ports[0] = port1;
-       if (port2 == 0)
-               port2 = port1 + 0x400;
-       awe_ports[1] = port2;
-       awe_ports[2] = port2 + 2;
-       if (port3 == 0)
-               port3 = port1 + 0x800;
-       awe_ports[3] = port3;
-       awe_ports[4] = port3 + 2;
-
-       port_setuped = TRUE;
-}
-
-/* write 16bit data */
-INLINE static void
-awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
-{
-       awe_set_cmd(cmd);
-       OUTW(data, awe_ports[port]);
-}
-
-/* write 32bit data */
-INLINE static void
-awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
-{
-       unsigned short addr = awe_ports[port];
-       awe_set_cmd(cmd);
-       OUTW(data, addr);               /* write lower 16 bits */
-       OUTW(data >> 16, addr + 2);     /* write higher 16 bits */
-}
-
-/* read 16bit data */
-INLINE static unsigned short
-awe_peek(unsigned short cmd, unsigned short port)
-{
-       unsigned short k;
-       awe_set_cmd(cmd);
-       k = inw(awe_ports[port]);
-       return k;
-}
-
-/* read 32bit data */
-INLINE static unsigned int
-awe_peek_dw(unsigned short cmd, unsigned short port)
-{
-       unsigned int k1, k2;
-       unsigned short addr = awe_ports[port];
-       awe_set_cmd(cmd);
-       k1 = inw(addr);
-       k2 = inw(addr + 2);
-       k1 |= k2 << 16;
-       return k1;
-}
-
-/* wait delay number of AWE32 44100Hz clocks */
-#ifdef WAIT_BY_LOOP /* wait by loop -- that's not good.. */
-static void
-awe_wait(unsigned short delay)
-{
-       unsigned short clock, target;
-       unsigned short port = awe_ports[AWE_WC_Port];
-       int counter;
-  
-       /* sample counter */
-       awe_set_cmd(AWE_WC_Cmd);
-       clock = (unsigned short)inw(port);
-       target = clock + delay;
-       counter = 0;
-       if (target < clock) {
-               for (; (unsigned short)inw(port) > target; counter++)
-                       if (counter > 65536)
-                               break;
-       }
-       for (; (unsigned short)inw(port) < target; counter++)
-               if (counter > 65536)
-                       break;
-}
-#else
-
-static void awe_wait(unsigned short delay)
-{
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout((HZ*(unsigned long)delay + 44099)/44100);
-}
-#endif /* wait by loop */
-
-/* write a word data */
-INLINE static void
-awe_write_dram(unsigned short c)
-{
-       awe_poke(AWE_SMLD, c);
-}
-
-
-#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE)
-
-/*================================================================
- * port check / request
- *  0x620-623, 0xA20-A23, 0xE20-E23
- *================================================================*/
-
-static int
-awe_check_port(void)
-{
-       if (! port_setuped) return 0;
-       return (check_region(awe_ports[0], 4) ||
-               check_region(awe_ports[1], 4) ||
-               check_region(awe_ports[3], 4));
-}
-
-static void
-awe_request_region(void)
-{
-       if (! port_setuped) return;
-       request_region(awe_ports[0], 4, "sound driver (AWE32)");
-       request_region(awe_ports[1], 4, "sound driver (AWE32)");
-       request_region(awe_ports[3], 4, "sound driver (AWE32)");
-}
-
-static void
-awe_release_region(void)
-{
-       if (! port_setuped) return;
-       release_region(awe_ports[0], 4);
-       release_region(awe_ports[1], 4);
-       release_region(awe_ports[3], 4);
-}
-
-#endif /* linux && !AWE_OBSOLETE_VOXWARE */
-
-
-/*================================================================
- * AWE32 initialization
- *================================================================*/
-static void
-awe_initialize(void)
-{
-       DEBUG(0,printk("AWE32: initializing..\n"));
-
-       /* initialize hardware configuration */
-       awe_poke(AWE_HWCF1, 0x0059);
-       awe_poke(AWE_HWCF2, 0x0020);
-
-       /* disable audio; this seems to reduce a clicking noise a bit.. */
-       awe_poke(AWE_HWCF3, 0);
-
-       /* initialize audio channels */
-       awe_init_audio();
-
-       /* initialize DMA */
-       awe_init_dma();
-
-       /* initialize init array */
-       awe_init_array();
-
-       /* check DRAM memory size */
-       awe_check_dram();
-
-       /* initialize the FM section of the AWE32 */
-       awe_init_fm();
-
-       /* set up voice envelopes */
-       awe_tweak();
-
-       /* enable audio */
-       awe_poke(AWE_HWCF3, 0x0004);
-
-       /* set default values */
-       awe_init_ctrl_parms(TRUE);
-
-       /* set equalizer */
-       awe_update_equalizer();
-
-       /* set reverb & chorus modes */
-       awe_update_reverb_mode();
-       awe_update_chorus_mode();
-}
-
-
-/*================================================================
- * AWE32 voice parameters
- *================================================================*/
-
-/* initialize voice_info record */
-static void
-awe_init_voice_info(awe_voice_info *vp)
-{
-       vp->sf_id = 0; /* normal mode */
-       vp->sample = 0;
-       vp->rate_offset = 0;
-
-       vp->start = 0;
-       vp->end = 0;
-       vp->loopstart = 0;
-       vp->loopend = 0;
-       vp->mode = 0;
-       vp->root = 60;
-       vp->tune = 0;
-       vp->low = 0;
-       vp->high = 127;
-       vp->vellow = 0;
-       vp->velhigh = 127;
-
-       vp->fixkey = -1;
-       vp->fixvel = -1;
-       vp->fixpan = -1;
-       vp->pan = -1;
-
-       vp->exclusiveClass = 0;
-       vp->amplitude = 127;
-       vp->attenuation = 0;
-       vp->scaleTuning = 100;
-
-       awe_init_voice_parm(&vp->parm);
-}
-
-/* initialize voice_parm record:
- * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0.
- * Vibrato and Tremolo effects are zero.
- * Cutoff is maximum.
- * Chorus and Reverb effects are zero.
- */
-static void
-awe_init_voice_parm(awe_voice_parm *pp)
-{
-       pp->moddelay = 0x8000;
-       pp->modatkhld = 0x7f7f;
-       pp->moddcysus = 0x7f7f;
-       pp->modrelease = 0x807f;
-       pp->modkeyhold = 0;
-       pp->modkeydecay = 0;
-
-       pp->voldelay = 0x8000;
-       pp->volatkhld = 0x7f7f;
-       pp->voldcysus = 0x7f7f;
-       pp->volrelease = 0x807f;
-       pp->volkeyhold = 0;
-       pp->volkeydecay = 0;
-
-       pp->lfo1delay = 0x8000;
-       pp->lfo2delay = 0x8000;
-       pp->pefe = 0;
-
-       pp->fmmod = 0;
-       pp->tremfrq = 0;
-       pp->fm2frq2 = 0;
-
-       pp->cutoff = 0xff;
-       pp->filterQ = 0;
-
-       pp->chorus = 0;
-       pp->reverb = 0;
-}      
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* convert frequency mHz to abstract cents (= midi key * 100) */
-static int
-freq_to_note(int mHz)
-{
-       /* abscents = log(mHz/8176) / log(2) * 1200 */
-       unsigned int max_val = (unsigned int)0xffffffff / 10000;
-       int i, times;
-       unsigned int base;
-       unsigned int freq;
-       int note, tune;
-
-       if (mHz == 0)
-               return 0;
-       if (mHz < 0)
-               return 12799; /* maximum */
-
-       freq = mHz;
-       note = 0;
-       for (base = 8176 * 2; freq >= base; base *= 2) {
-               note += 12;
-               if (note >= 128) /* over maximum */
-                       return 12799;
-       }
-       base /= 2;
-
-       /* to avoid overflow... */
-       times = 10000;
-       while (freq > max_val) {
-               max_val *= 10;
-               times /= 10;
-               base /= 10;
-       }
-
-       freq = freq * times / base;
-       for (i = 0; i < 12; i++) {
-               if (freq < semitone_tuning[i+1])
-                       break;
-               note++;
-       }
-
-       tune = 0;
-       freq = freq * 10000 / semitone_tuning[i];
-       for (i = 0; i < 100; i++) {
-               if (freq < cent_tuning[i+1])
-                       break;
-               tune++;
-       }
-
-       return note * 100 + tune;
-}
-
-
-/* convert Hz to AWE32 rate offset:
- * sample pitch offset for the specified sample rate
- * rate=44100 is no offset, each 4096 is 1 octave (twice).
- * eg, when rate is 22050, this offset becomes -4096.
- */
-static int
-calc_rate_offset(int Hz)
-{
-       /* offset = log(Hz / 44100) / log(2) * 4096 */
-       int freq, base, i;
-
-       /* maybe smaller than max (44100Hz) */
-       if (Hz <= 0 || Hz >= 44100) return 0;
-
-       base = 0;
-       for (freq = Hz * 2; freq < 44100; freq *= 2)
-               base++;
-       base *= 1200;
-
-       freq = 44100 * 10000 / (freq/2);
-       for (i = 0; i < 12; i++) {
-               if (freq < semitone_tuning[i+1])
-                       break;
-               base += 100;
-       }
-       freq = freq * 10000 / semitone_tuning[i];
-       for (i = 0; i < 100; i++) {
-               if (freq < cent_tuning[i+1])
-                       break;
-               base++;
-       }
-       return -base * 4096 / 1200;
-}
-
-
-/*----------------------------------------------------------------
- * convert envelope time parameter to AWE32 raw parameter
- *----------------------------------------------------------------*/
-
-/* attack & decay/release time table (msec) */
-static short attack_time_tbl[128] = {
-32767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816,
-707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377,
-361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188,
-180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94,
-90, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47,
-45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23,
-22, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
-11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0,
-};
-
-static short decay_time_tbl[128] = {
-32767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082,
-2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507,
-1443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722,
-691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361,
-345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180,
-172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90,
-86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45,
-43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22,
-};
-
-#define calc_parm_delay(msec) (0x8000 - (msec) * 1000 / 725);
-
-/* delay time = 0x8000 - msec/92 */
-static int
-calc_parm_hold(int msec)
-{
-       int val = (0x7f * 92 - msec) / 92;
-       if (val < 1) val = 1;
-       if (val > 127) val = 127;
-       return val;
-}
-
-/* attack time: search from time table */
-static int
-calc_parm_attack(int msec)
-{
-       return calc_parm_search(msec, attack_time_tbl);
-}
-
-/* decay/release time: search from time table */
-static int
-calc_parm_decay(int msec)
-{
-       return calc_parm_search(msec, decay_time_tbl);
-}
-
-/* search an index for specified time from given time table */
-static int
-calc_parm_search(int msec, short *table)
-{
-       int left = 1, right = 127, mid;
-       while (left < right) {
-               mid = (left + right) / 2;
-               if (msec < (int)table[mid])
-                       left = mid + 1;
-               else
-                       right = mid;
-       }
-       return left;
-}
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*================================================================
- * effects table
- *================================================================*/
-
-/* set an effect value */
-#define FX_FLAG_OFF    0
-#define FX_FLAG_SET    1
-#define FX_FLAG_ADD    2
-
-#define FX_SET(rec,type,value) \
-       ((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value))
-#define FX_ADD(rec,type,value) \
-       ((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value))
-#define FX_UNSET(rec,type) \
-       ((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0)
-
-/* check the effect value is set */
-#define FX_ON(rec,type)        ((rec)->flags[type])
-
-#define PARM_BYTE      0
-#define PARM_WORD      1
-#define PARM_SIGN      2
-
-static struct PARM_DEFS {
-       int type;       /* byte or word */
-       int low, high;  /* value range */
-       fx_affect_func realtime;        /* realtime paramater change */
-} parm_defs[] = {
-       {PARM_WORD, 0, 0x8000, NULL},   /* env1 delay */
-       {PARM_BYTE, 1, 0x7f, NULL},     /* env1 attack */
-       {PARM_BYTE, 0, 0x7e, NULL},     /* env1 hold */
-       {PARM_BYTE, 1, 0x7f, NULL},     /* env1 decay */
-       {PARM_BYTE, 1, 0x7f, NULL},     /* env1 release */
-       {PARM_BYTE, 0, 0x7f, NULL},     /* env1 sustain */
-       {PARM_BYTE, 0, 0xff, NULL},     /* env1 pitch */
-       {PARM_BYTE, 0, 0xff, NULL},     /* env1 cutoff */
-
-       {PARM_WORD, 0, 0x8000, NULL},   /* env2 delay */
-       {PARM_BYTE, 1, 0x7f, NULL},     /* env2 attack */
-       {PARM_BYTE, 0, 0x7e, NULL},     /* env2 hold */
-       {PARM_BYTE, 1, 0x7f, NULL},     /* env2 decay */
-       {PARM_BYTE, 1, 0x7f, NULL},     /* env2 release */
-       {PARM_BYTE, 0, 0x7f, NULL},     /* env2 sustain */
-
-       {PARM_WORD, 0, 0x8000, NULL},   /* lfo1 delay */
-       {PARM_BYTE, 0, 0xff, awe_fx_tremfrq},   /* lfo1 freq */
-       {PARM_SIGN, -128, 127, awe_fx_tremfrq}, /* lfo1 volume */
-       {PARM_SIGN, -128, 127, awe_fx_fmmod},   /* lfo1 pitch */
-       {PARM_BYTE, 0, 0xff, awe_fx_fmmod},     /* lfo1 cutoff */
-
-       {PARM_WORD, 0, 0x8000, NULL},   /* lfo2 delay */
-       {PARM_BYTE, 0, 0xff, awe_fx_fm2frq2},   /* lfo2 freq */
-       {PARM_SIGN, -128, 127, awe_fx_fm2frq2}, /* lfo2 pitch */
-
-       {PARM_WORD, 0, 0xffff, awe_set_voice_pitch},    /* initial pitch */
-       {PARM_BYTE, 0, 0xff, NULL},     /* chorus */
-       {PARM_BYTE, 0, 0xff, NULL},     /* reverb */
-       {PARM_BYTE, 0, 0xff, awe_set_volume},   /* initial cutoff */
-       {PARM_BYTE, 0, 15, awe_fx_filterQ},     /* initial resonance */
-
-       {PARM_WORD, 0, 0xffff, NULL},   /* sample start */
-       {PARM_WORD, 0, 0xffff, NULL},   /* loop start */
-       {PARM_WORD, 0, 0xffff, NULL},   /* loop end */
-       {PARM_WORD, 0, 0xffff, NULL},   /* coarse sample start */
-       {PARM_WORD, 0, 0xffff, NULL},   /* coarse loop start */
-       {PARM_WORD, 0, 0xffff, NULL},   /* coarse loop end */
-       {PARM_BYTE, 0, 0xff, awe_set_volume},   /* initial attenuation */
-};
-
-
-static unsigned char
-FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value)
-{
-       int effect = 0;
-       int on = 0;
-       if (lay && (on = FX_ON(lay, type)) != 0)
-               effect = lay->val[type];
-       if (!on && (on = FX_ON(rec, type)) != 0)
-               effect = rec->val[type];
-       if (on == FX_FLAG_ADD) {
-               if (parm_defs[type].type == PARM_SIGN) {
-                       if (value > 0x7f)
-                               effect += (int)value - 0x100;
-                       else
-                               effect += (int)value;
-               } else {
-                       effect += (int)value;
-               }
-       }
-       if (on) {
-               if (effect < parm_defs[type].low)
-                       effect = parm_defs[type].low;
-               else if (effect > parm_defs[type].high)
-                       effect = parm_defs[type].high;
-               return (unsigned char)effect;
-       }
-       return value;
-}
-
-/* get word effect value */
-static unsigned short
-FX_WORD(FX_Rec *rec, FX_Rec *lay, int type, unsigned short value)
-{
-       int effect = 0;
-       int on = 0;
-       if (lay && (on = FX_ON(lay, type)) != 0)
-               effect = lay->val[type];
-       if (!on && (on = FX_ON(rec, type)) != 0)
-               effect = rec->val[type];
-       if (on == FX_FLAG_ADD)
-               effect += (int)value;
-       if (on) {
-               if (effect < parm_defs[type].low)
-                       effect = parm_defs[type].low;
-               else if (effect > parm_defs[type].high)
-                       effect = parm_defs[type].high;
-               return (unsigned short)effect;
-       }
-       return value;
-}
-
-/* get word (upper=type1/lower=type2) effect value */
-static unsigned short
-FX_COMB(FX_Rec *rec, FX_Rec *lay, int type1, int type2, unsigned short value)
-{
-       unsigned short tmp;
-       tmp = FX_BYTE(rec, lay, type1, (unsigned char)(value >> 8));
-       tmp <<= 8;
-       tmp |= FX_BYTE(rec, lay, type2, (unsigned char)(value & 0xff));
-       return tmp;
-}
-
-/* address offset */
-static int
-FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode)
-{
-       int addr = 0;
-       if (lay && FX_ON(lay, hi))
-               addr = (short)lay->val[hi];
-       else if (FX_ON(rec, hi))
-               addr = (short)rec->val[hi];
-       addr = addr << 15;
-       if (lay && FX_ON(lay, lo))
-               addr += (short)lay->val[lo];
-       else if (FX_ON(rec, lo))
-               addr += (short)rec->val[lo];
-       if (!(mode & AWE_SAMPLE_8BITS))
-               addr /= 2;
-       return addr;
-}
-
-
-/*================================================================
- * turn on/off sample
- *================================================================*/
-
-/* table for volume target calculation */
-static unsigned short voltarget[16] = { 
-   0xEAC0, 0XE0C8, 0XD740, 0XCE20, 0XC560, 0XBD08, 0XB500, 0XAD58,
-   0XA5F8, 0X9EF0, 0X9830, 0X91C0, 0X8B90, 0X85A8, 0X8000, 0X7A90
-};
-
-static void
-awe_note_on(int voice)
-{
-       unsigned int temp;
-       int addr;
-       int vtarget, ftarget, ptarget, pitch;
-       awe_voice_info *vp;
-       awe_voice_parm_block *parm;
-       FX_Rec *fx = &voices[voice].cinfo->fx;
-       FX_Rec *fx_lay = NULL;
-       if (voices[voice].layer < MAX_LAYERS)
-               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-       /* A voice sample must assigned before calling */
-       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
-               return;
-
-       parm = (awe_voice_parm_block*)&vp->parm;
-
-       /* channel to be silent and idle */
-       awe_poke(AWE_DCYSUSV(voice), 0x0080);
-       awe_poke(AWE_VTFT(voice), 0x0000FFFF);
-       awe_poke(AWE_CVCF(voice), 0x0000FFFF);
-       awe_poke(AWE_PTRX(voice), 0);
-       awe_poke(AWE_CPF(voice), 0);
-
-       /* set pitch offset */
-       awe_set_pitch(voice, TRUE);
-
-       /* modulation & volume envelope */
-       if (parm->modatk >= 0x80 && parm->moddelay >= 0x8000) {
-               awe_poke(AWE_ENVVAL(voice), 0xBFFF);
-               pitch = (parm->env1pit<<4) + voices[voice].apitch;
-               if (pitch > 0xffff) pitch = 0xffff;
-               /* calculate filter target */
-               ftarget = parm->cutoff + parm->env1fc;
-               limitvalue(ftarget, 0, 255);
-               ftarget <<= 8;
-       } else {
-               awe_poke(AWE_ENVVAL(voice),
-                        FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, parm->moddelay));
-               ftarget = parm->cutoff;
-               ftarget <<= 8;
-               pitch = voices[voice].apitch;
-       }
-
-       /* calcualte pitch target */
-       if (pitch != 0xffff) {
-               ptarget = 1 << (pitch >> 12);
-               if (pitch & 0x800) ptarget += (ptarget*0x102e)/0x2710;
-               if (pitch & 0x400) ptarget += (ptarget*0x764)/0x2710;
-               if (pitch & 0x200) ptarget += (ptarget*0x389)/0x2710;
-               ptarget += (ptarget>>1);
-               if (ptarget > 0xffff) ptarget = 0xffff;
-
-       } else ptarget = 0xffff;
-       if (parm->modatk >= 0x80)
-               awe_poke(AWE_ATKHLD(voice),
-                        FX_BYTE(fx, fx_lay, AWE_FX_ENV1_HOLD, parm->modhld) << 8 | 0x7f);
-       else
-               awe_poke(AWE_ATKHLD(voice),
-                        FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK,
-                                vp->parm.modatkhld));
-       awe_poke(AWE_DCYSUS(voice),
-                FX_COMB(fx, fx_lay, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY,
-                         vp->parm.moddcysus));
-
-       if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) {
-               awe_poke(AWE_ENVVOL(voice), 0xBFFF);
-               vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4);
-       } else {
-               awe_poke(AWE_ENVVOL(voice),
-                        FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay));
-               vtarget = 0;
-       }
-       if (parm->volatk >= 0x80)
-               awe_poke(AWE_ATKHLDV(voice),
-                        FX_BYTE(fx, fx_lay, AWE_FX_ENV2_HOLD, parm->volhld) << 8 | 0x7f);
-       else
-               awe_poke(AWE_ATKHLDV(voice),
-                        FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK,
-                        vp->parm.volatkhld));
-       /* decay/sustain parameter for volume envelope must be set at last */
-
-       /* cutoff and volume */
-       awe_set_volume(voice, TRUE);
-
-       /* modulation envelope heights */
-       awe_poke(AWE_PEFE(voice),
-                FX_COMB(fx, fx_lay, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF,
-                        vp->parm.pefe));
-
-       /* lfo1/2 delay */
-       awe_poke(AWE_LFO1VAL(voice),
-                FX_WORD(fx, fx_lay, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay));
-       awe_poke(AWE_LFO2VAL(voice),
-                FX_WORD(fx, fx_lay, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay));
-
-       /* lfo1 pitch & cutoff shift */
-       awe_fx_fmmod(voice, TRUE);
-       /* lfo1 volume & freq */
-       awe_fx_tremfrq(voice, TRUE);
-       /* lfo2 pitch & freq */
-       awe_fx_fm2frq2(voice, TRUE);
-       /* pan & loop start */
-       awe_set_pan(voice, TRUE);
-
-       /* chorus & loop end (chorus 8bit, MSB) */
-       addr = vp->loopend - 1;
-       addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_END,
-                         AWE_FX_COARSE_LOOP_END, vp->mode);
-       temp = FX_BYTE(fx, fx_lay, AWE_FX_CHORUS, vp->parm.chorus);
-       temp = (temp <<24) | (unsigned int)addr;
-       awe_poke_dw(AWE_CSL(voice), temp);
-       DEBUG(4,printk("AWE32: [-- loopend=%x/%x]\n", vp->loopend, addr));
-
-       /* Q & current address (Q 4bit value, MSB) */
-       addr = vp->start - 1;
-       addr += FX_OFFSET(fx, fx_lay, AWE_FX_SAMPLE_START,
-                         AWE_FX_COARSE_SAMPLE_START, vp->mode);
-       temp = FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ);
-       temp = (temp<<28) | (unsigned int)addr;
-       awe_poke_dw(AWE_CCCA(voice), temp);
-       DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", vp->start, addr));
-
-       /* clear unknown registers */
-       awe_poke_dw(AWE_00A0(voice), 0);
-       awe_poke_dw(AWE_0080(voice), 0);
-
-       /* reset volume */
-       awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget);
-       awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget);
-
-       /* turn on envelope */
-       awe_poke(AWE_DCYSUSV(voice),
-                FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
-                         vp->parm.voldcysus));
-       /* set reverb */
-       temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb);
-       temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux;
-       awe_poke_dw(AWE_PTRX(voice), temp);
-       awe_poke_dw(AWE_CPF(voice), ptarget << 16);
-
-       voices[voice].state = AWE_ST_ON;
-
-       /* clear voice position for the next note on this channel */
-       if (SINGLE_LAYER_MODE()) {
-               FX_UNSET(fx, AWE_FX_SAMPLE_START);
-               FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START);
-       }
-}
-
-
-/* turn off the voice */
-static void
-awe_note_off(int voice)
-{
-       awe_voice_info *vp;
-       unsigned short tmp;
-       FX_Rec *fx = &voices[voice].cinfo->fx;
-       FX_Rec *fx_lay = NULL;
-       if (voices[voice].layer < MAX_LAYERS)
-               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-       if ((vp = voices[voice].sample) == NULL) {
-               voices[voice].state = AWE_ST_OFF;
-               return;
-       }
-
-       tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV1_RELEASE,
-                              (unsigned char)vp->parm.modrelease);
-       awe_poke(AWE_DCYSUS(voice), tmp);
-       tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE,
-                              (unsigned char)vp->parm.volrelease);
-       awe_poke(AWE_DCYSUSV(voice), tmp);
-       voices[voice].state = AWE_ST_RELEASED;
-}
-
-/* force to terminate the voice (no releasing echo) */
-static void
-awe_terminate(int voice)
-{
-       awe_poke(AWE_DCYSUSV(voice), 0x807F);
-       awe_tweak_voice(voice);
-       voices[voice].state = AWE_ST_OFF;
-}
-
-/* turn off other voices with the same exclusive class (for drums) */
-static void
-awe_exclusive_off(int voice)
-{
-       int i, exclass;
-
-       if (voices[voice].sample == NULL)
-               return;
-       if ((exclass = voices[voice].sample->exclusiveClass) == 0)
-               return; /* not exclusive */
-
-       /* turn off voices with the same class */
-       for (i = 0; i < awe_max_voices; i++) {
-               if (i != voice && IS_PLAYING(i) &&
-                   voices[i].sample && voices[i].ch == voices[voice].ch &&
-                   voices[i].sample->exclusiveClass == exclass) {
-                       DEBUG(4,printk("AWE32: [exoff(%d)]\n", i));
-                       awe_terminate(i);
-                       awe_voice_init(i, TRUE);
-               }
-       }
-}
-
-
-/*================================================================
- * change the parameters of an audible voice
- *================================================================*/
-
-/* change pitch */
-static void
-awe_set_pitch(int voice, int forced)
-{
-       if (IS_NO_EFFECT(voice) && !forced) return;
-       awe_poke(AWE_IP(voice), voices[voice].apitch);
-       DEBUG(3,printk("AWE32: [-- pitch=%x]\n", voices[voice].apitch));
-}
-
-/* calculate & change pitch */
-static void
-awe_set_voice_pitch(int voice, int forced)
-{
-       awe_calc_pitch(voice);
-       awe_set_pitch(voice, forced);
-}
-
-/* change volume & cutoff */
-static void
-awe_set_volume(int voice, int forced)
-{
-       awe_voice_info *vp;
-       unsigned short tmp2;
-       FX_Rec *fx = &voices[voice].cinfo->fx;
-       FX_Rec *fx_lay = NULL;
-       if (voices[voice].layer < MAX_LAYERS)
-               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-       if (!IS_PLAYING(voice) && !forced) return;
-       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
-               return;
-
-       tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF,
-                      (unsigned char)voices[voice].acutoff);
-       tmp2 = (tmp2 << 8);
-       tmp2 |= FX_BYTE(fx, fx_lay, AWE_FX_ATTEN,
-                       (unsigned char)voices[voice].avol);
-       awe_poke(AWE_IFATN(voice), tmp2);
-}
-
-/* calculate & change volume */
-static void
-awe_set_voice_vol(int voice, int forced)
-{
-       if (IS_EMPTY(voice))
-               return;
-       awe_calc_volume(voice);
-       awe_set_volume(voice, forced);
-}
-
-
-/* change pan; this could make a click noise.. */
-static void
-awe_set_pan(int voice, int forced)
-{
-       unsigned int temp;
-       int addr;
-       awe_voice_info *vp;
-       FX_Rec *fx = &voices[voice].cinfo->fx;
-       FX_Rec *fx_lay = NULL;
-       if (voices[voice].layer < MAX_LAYERS)
-               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-       if (IS_NO_EFFECT(voice) && !forced) return;
-       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
-               return;
-
-       /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
-       if (vp->fixpan > 0)     /* 0-127 */
-               temp = 255 - (int)vp->fixpan * 2;
-       else {
-               int pos = 0;
-               if (vp->pan >= 0) /* 0-127 */
-                       pos = (int)vp->pan * 2 - 128;
-               pos += voices[voice].cinfo->panning; /* -128 - 127 */
-               temp = 127 - pos;
-       }
-       limitvalue(temp, 0, 255);
-       if (ctrls[AWE_MD_PAN_EXCHANGE]) {
-               temp = 255 - temp;
-       }
-       if (forced || temp != voices[voice].apan) {
-               voices[voice].apan = temp;
-               addr = vp->loopstart - 1;
-               addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START,
-                                 AWE_FX_COARSE_LOOP_START, vp->mode);
-               temp = (temp<<24) | (unsigned int)addr;
-               awe_poke_dw(AWE_PSST(voice), temp);
-               DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr));
-               if (temp == 0) voices[voice].aaux = 0xff;
-               else voices[voice].aaux = (-temp)&0xff;
-       }
-}
-
-/* effects change during playing */
-static void
-awe_fx_fmmod(int voice, int forced)
-{
-       awe_voice_info *vp;
-       FX_Rec *fx = &voices[voice].cinfo->fx;
-       FX_Rec *fx_lay = NULL;
-       if (voices[voice].layer < MAX_LAYERS)
-               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-       if (IS_NO_EFFECT(voice) && !forced) return;
-       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
-               return;
-       awe_poke(AWE_FMMOD(voice),
-                FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF,
-                        vp->parm.fmmod));
-}
-
-/* set tremolo (lfo1) volume & frequency */
-static void
-awe_fx_tremfrq(int voice, int forced)
-{
-       awe_voice_info *vp;
-       FX_Rec *fx = &voices[voice].cinfo->fx;
-       FX_Rec *fx_lay = NULL;
-       if (voices[voice].layer < MAX_LAYERS)
-               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-       if (IS_NO_EFFECT(voice) && !forced) return;
-       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
-               return;
-       awe_poke(AWE_TREMFRQ(voice),
-                FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ,
-                        vp->parm.tremfrq));
-}
-
-/* set lfo2 pitch & frequency */
-static void
-awe_fx_fm2frq2(int voice, int forced)
-{
-       awe_voice_info *vp;
-       FX_Rec *fx = &voices[voice].cinfo->fx;
-       FX_Rec *fx_lay = NULL;
-       if (voices[voice].layer < MAX_LAYERS)
-               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-       if (IS_NO_EFFECT(voice) && !forced) return;
-       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
-               return;
-       awe_poke(AWE_FM2FRQ2(voice),
-                FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ,
-                        vp->parm.fm2frq2));
-}
-
-
-/* Q & current address (Q 4bit value, MSB) */
-static void
-awe_fx_filterQ(int voice, int forced)
-{
-       unsigned int addr;
-       awe_voice_info *vp;
-       FX_Rec *fx = &voices[voice].cinfo->fx;
-       FX_Rec *fx_lay = NULL;
-       if (voices[voice].layer < MAX_LAYERS)
-               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-       if (IS_NO_EFFECT(voice) && !forced) return;
-       if ((vp = voices[voice].sample) == NULL || vp->index < 0)
-               return;
-
-       addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff;
-       addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28);
-       awe_poke_dw(AWE_CCCA(voice), addr);
-}
-
-/*================================================================
- * calculate pitch offset
- *----------------------------------------------------------------
- * 0xE000 is no pitch offset at 44100Hz sample.
- * Every 4096 is one octave.
- *================================================================*/
-
-static void
-awe_calc_pitch(int voice)
-{
-       voice_info *vp = &voices[voice];
-       awe_voice_info *ap;
-       awe_chan_info *cp = voices[voice].cinfo;
-       int offset;
-
-       /* search voice information */
-       if ((ap = vp->sample) == NULL)
-                       return;
-       if (ap->index < 0) {
-               DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
-               if (awe_set_sample(ap) < 0)
-                       return;
-       }
-
-       /* calculate offset */
-       if (ap->fixkey >= 0) {
-               DEBUG(3,printk("AWE32: p-> fixkey(%d) tune(%d)\n", ap->fixkey, ap->tune));
-               offset = (ap->fixkey - ap->root) * 4096 / 12;
-       } else {
-               DEBUG(3,printk("AWE32: p(%d)-> root(%d) tune(%d)\n", vp->note, ap->root, ap->tune));
-               offset = (vp->note - ap->root) * 4096 / 12;
-               DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset));
-       }
-       offset = (offset * ap->scaleTuning) / 100;
-       DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset));
-       offset += ap->tune * 4096 / 1200;
-       DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset));
-       if (cp->bender != 0) {
-               DEBUG(3,printk("AWE32: p-> bend(%d) %d\n", voice, cp->bender));
-               /* (819200: 1 semitone) ==> (4096: 12 semitones) */
-               offset += cp->bender * cp->bender_range / 2400;
-       }
-
-       /* add initial pitch correction */
-       if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH))
-               offset += cp->fx_layer[vp->layer].val[AWE_FX_INIT_PITCH];
-       else if (FX_ON(&cp->fx, AWE_FX_INIT_PITCH))
-               offset += cp->fx.val[AWE_FX_INIT_PITCH];
-
-       /* 0xe000: root pitch */
-       vp->apitch = 0xe000 + ap->rate_offset + offset;
-       DEBUG(4,printk("AWE32: p-> sum aofs=%x, rate_ofs=%d\n", vp->apitch, ap->rate_offset));
-       if (vp->apitch > 0xffff)
-               vp->apitch = 0xffff;
-       if (vp->apitch < 0)
-               vp->apitch = 0;
-}
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-/* calculate MIDI key and semitone from the specified frequency */
-static void
-awe_calc_pitch_from_freq(int voice, int freq)
-{
-       voice_info *vp = &voices[voice];
-       awe_voice_info *ap;
-       FX_Rec *fx = &voices[voice].cinfo->fx;
-       FX_Rec *fx_lay = NULL;
-       int offset;
-       int note;
-
-       if (voices[voice].layer < MAX_LAYERS)
-               fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-       /* search voice information */
-       if ((ap = vp->sample) == NULL)
-               return;
-       if (ap->index < 0) {
-               DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
-               if (awe_set_sample(ap) < 0)
-                       return;
-       }
-       note = freq_to_note(freq);
-       offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200;
-       offset = (offset * ap->scaleTuning) / 100;
-       if (fx_lay && FX_ON(fx_lay, AWE_FX_INIT_PITCH))
-               offset += fx_lay->val[AWE_FX_INIT_PITCH];
-       else if (FX_ON(fx, AWE_FX_INIT_PITCH))
-               offset += fx->val[AWE_FX_INIT_PITCH];
-       vp->apitch = 0xe000 + ap->rate_offset + offset;
-       if (vp->apitch > 0xffff)
-               vp->apitch = 0xffff;
-       if (vp->apitch < 0)
-               vp->apitch = 0;
-}
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*================================================================
- * calculate volume attenuation
- *----------------------------------------------------------------
- * Voice volume is controlled by volume attenuation parameter.
- * So volume becomes maximum when avol is 0 (no attenuation), and
- * minimum when 255 (-96dB or silence).
- *================================================================*/
-
-static int vol_table[128] = {
-       255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,
-       47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32,
-       31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22,
-       22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16,
-       15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,
-       10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6,
-       6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3,
-       2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,
-};
-
-/* tables for volume->attenuation calculation */
-static unsigned char voltab1[128] = {
-   0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-   0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22,
-   0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
-   0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14,
-   0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10,
-   0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d,
-   0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b,
-   0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
-   0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
-   0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04,
-   0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
-   0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
-   0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char voltab2[128] = {
-   0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a,
-   0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21,
-   0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a,
-   0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15,
-   0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10,
-   0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d,
-   0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a,
-   0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08,
-   0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
-   0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
-   0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
-   0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
-   0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char expressiontab[128] = {
-   0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42,
-   0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30,
-   0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25,
-   0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e,
-   0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18,
-   0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13,
-   0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f,
-   0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c,
-   0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09,
-   0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
-   0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
-   0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
-   0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static void
-awe_calc_volume(int voice)
-{
-       voice_info *vp = &voices[voice];
-       awe_voice_info *ap;
-       awe_chan_info *cp = voices[voice].cinfo;
-       int vol;
-
-       /* search voice information */
-       if ((ap = vp->sample) == NULL)
-               return;
-
-       ap = vp->sample;
-       if (ap->index < 0) {
-               DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
-               if (awe_set_sample(ap) < 0)
-                       return;
-       }
-       
-       if (ctrls[AWE_MD_NEW_VOLUME_CALC]) {
-               int main_vol = cp->main_vol * ap->amplitude / 127;
-               limitvalue(vp->velocity, 0, 127);
-               limitvalue(main_vol, 0, 127);
-               limitvalue(cp->expression_vol, 0, 127);
-
-               vol = voltab1[main_vol] + voltab2[vp->velocity];
-               vol = (vol * 8) / 3;
-               vol += ap->attenuation;
-               if (cp->expression_vol < 127)
-                       vol += ((0x100 - vol) * expressiontab[cp->expression_vol])/128;
-               vol += atten_offset;
-               if (atten_relative)
-                       vol += ctrls[AWE_MD_ZERO_ATTEN];
-               limitvalue(vol, 0, 255);
-               vp->avol = vol;
-               
-       } else {
-               /* 0 - 127 */
-               vol = (vp->velocity * cp->main_vol * cp->expression_vol) / (127*127);
-               vol = vol * ap->amplitude / 127;
-
-               if (vol < 0) vol = 0;
-               if (vol > 127) vol = 127;
-
-               /* calc to attenuation */
-               vol = vol_table[vol];
-               vol += (int)ap->attenuation;
-               vol += atten_offset;
-               if (atten_relative)
-                       vol += ctrls[AWE_MD_ZERO_ATTEN];
-               if (vol > 255) vol = 255;
-
-               vp->avol = vol;
-       }
-       if (cp->bank !=  AWE_DRUM_BANK && ((awe_voice_parm_block*)(&ap->parm))->volatk < 0x7d) {
-               int atten;
-               if (vp->velocity < 70) atten = 70;
-               else atten = vp->velocity;
-               vp->acutoff = (atten * ap->parm.cutoff + 0xa0) >> 7;
-       } else {
-               vp->acutoff = ap->parm.cutoff;
-       }
-       DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol));
-}
-
-/* change master volume */
-static void
-awe_change_master_volume(short val)
-{
-       limitvalue(val, 0, 127);
-       atten_offset = vol_table[val];
-       atten_relative = TRUE;
-       awe_update_volume();
-}
-
-/* update volumes of all available channels */
-static void awe_update_volume(void)
-{
-       int i;
-       for (i = 0; i < awe_max_voices; i++)
-               awe_set_voice_vol(i, TRUE);
-}
-
-/* set sostenuto on */
-static void awe_sostenuto_on(int voice, int forced)
-{
-       if (IS_NO_EFFECT(voice) && !forced) return;
-       voices[voice].sostenuto = 127;
-}
-
-
-/* drop sustain */
-static void awe_sustain_off(int voice, int forced)
-{
-       if (voices[voice].state == AWE_ST_SUSTAINED) {
-               awe_note_off(voice);
-               awe_fx_init(voices[voice].ch);
-               awe_voice_init(voice, FALSE);
-       }
-}
-
-
-/* terminate and initialize voice */
-static void awe_terminate_and_init(int voice, int forced)
-{
-       awe_terminate(voice);
-       awe_fx_init(voices[voice].ch);
-       awe_voice_init(voice, TRUE);
-}
-
-
-/*================================================================
- * synth operation routines
- *================================================================*/
-
-#define AWE_VOICE_KEY(v)       (0x8000 | (v))
-#define AWE_CHAN_KEY(c,n)      (((c) << 8) | ((n) + 1))
-#define KEY_CHAN_MATCH(key,c)  (((key) >> 8) == (c))
-
-/* initialize the voice */
-static void
-awe_voice_init(int voice, int init_all)
-{
-       voice_info *vp = &voices[voice];
-
-       /* reset voice search key */
-       if (playing_mode == AWE_PLAY_DIRECT)
-               vp->key = AWE_VOICE_KEY(voice);
-       else
-               vp->key = 0;
-
-       /* clear voice mapping */
-       voice_alloc->map[voice] = 0;
-
-       /* touch the timing flag */
-       vp->time = current_alloc_time;
-
-       /* initialize other parameters if necessary */
-       if (init_all) {
-               vp->note = -1;
-               vp->velocity = 0;
-               vp->sostenuto = 0;
-
-               vp->sample = NULL;
-               vp->cinfo = &channels[voice];
-               vp->ch = voice;
-               vp->state = AWE_ST_OFF;
-
-               /* emu8000 parameters */
-               vp->apitch = 0;
-               vp->avol = 255;
-               vp->apan = -1;
-       }
-}
-
-/* clear effects */
-static void awe_fx_init(int ch)
-{
-       if (SINGLE_LAYER_MODE() && !ctrls[AWE_MD_KEEP_EFFECT]) {
-               BZERO(&channels[ch].fx, sizeof(channels[ch].fx));
-               BZERO(&channels[ch].fx_layer, sizeof(&channels[ch].fx_layer));
-       }
-}
-
-/* initialize channel info */
-static void awe_channel_init(int ch, int init_all)
-{
-       awe_chan_info *cp = &channels[ch];
-       cp->channel = ch;
-       if (init_all) {
-               cp->panning = 0; /* zero center */
-               cp->bender_range = 200; /* sense * 100 */
-               cp->main_vol = 127;
-               if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) {
-                       cp->instr = ctrls[AWE_MD_DEF_DRUM];
-                       cp->bank = AWE_DRUM_BANK;
-               } else {
-                       cp->instr = ctrls[AWE_MD_DEF_PRESET];
-                       cp->bank = ctrls[AWE_MD_DEF_BANK];
-               }
-               cp->vrec = -1;
-               cp->def_vrec = -1;
-       }
-
-       cp->bender = 0; /* zero tune skew */
-       cp->expression_vol = 127;
-       cp->chan_press = 0;
-       cp->sustained = 0;
-
-       if (! ctrls[AWE_MD_KEEP_EFFECT]) {
-               BZERO(&cp->fx, sizeof(cp->fx));
-               BZERO(&cp->fx_layer, sizeof(cp->fx_layer));
-       }
-}
-
-
-/* change the voice parameters; voice = channel */
-static void awe_voice_change(int voice, fx_affect_func func)
-{
-       int i; 
-       switch (playing_mode) {
-       case AWE_PLAY_DIRECT:
-               func(voice, FALSE);
-               break;
-       case AWE_PLAY_INDIRECT:
-               for (i = 0; i < awe_max_voices; i++)
-                       if (voices[i].key == AWE_VOICE_KEY(voice))
-                               func(i, FALSE);
-               break;
-       default:
-               for (i = 0; i < awe_max_voices; i++)
-                       if (KEY_CHAN_MATCH(voices[i].key, voice))
-                               func(i, FALSE);
-               break;
-       }
-}
-
-
-/*----------------------------------------------------------------
- * device open / close
- *----------------------------------------------------------------*/
-
-/* open device:
- *   reset status of all voices, and clear sample position flag
- */
-static int
-awe_open(int dev, int mode)
-{
-       if (awe_busy)
-               return RET_ERROR(EBUSY);
-
-       awe_busy = TRUE;
-
-       /* set default mode */
-       awe_init_ctrl_parms(FALSE);
-       atten_relative = TRUE;
-       atten_offset = 0;
-       drum_flags = DEFAULT_DRUM_FLAGS;
-       playing_mode = AWE_PLAY_INDIRECT;
-
-       /* reset voices & channels */
-       awe_reset(dev);
-
-       patch_opened = 0;
-
-       return 0;
-}
-
-
-/* close device:
- *   reset all voices again (terminate sounds)
- */
-static void
-awe_close(int dev)
-{
-       awe_reset(dev);
-       awe_busy = FALSE;
-}
-
-
-/* set miscellaneous mode parameters
- */
-static void
-awe_init_ctrl_parms(int init_all)
-{
-       int i;
-       for (i = 0; i < AWE_MD_END; i++) {
-               if (init_all || ctrl_parms[i].init_each_time)
-                       ctrls[i] = ctrl_parms[i].value;
-       }
-}
-
-
-/* sequencer I/O control:
- */
-static int
-awe_ioctl(int dev, unsigned int cmd, caddr_t arg)
-{
-       switch (cmd) {
-       case SNDCTL_SYNTH_INFO:
-               if (playing_mode == AWE_PLAY_DIRECT)
-                       awe_info.nr_voices = awe_max_voices;
-               else
-                       awe_info.nr_voices = AWE_MAX_CHANNELS;
-               IOCTL_TO_USER((char*)arg, 0, &awe_info, sizeof(awe_info));
-               return 0;
-               break;
-
-       case SNDCTL_SEQ_RESETSAMPLES:
-               awe_reset_samples();
-               awe_reset(dev);
-               return 0;
-               break;
-
-       case SNDCTL_SEQ_PERCMODE:
-               /* what's this? */
-               return 0;
-               break;
-
-       case SNDCTL_SYNTH_MEMAVL:
-               return awe_mem_size - awe_free_mem_ptr() * 2;
-
-       default:
-               printk("AWE32: unsupported ioctl %d\n", cmd);
-               return RET_ERROR(EINVAL);
-       }
-}
-
-
-static int voice_in_range(int voice)
-{
-       if (playing_mode == AWE_PLAY_DIRECT) {
-               if (voice < 0 || voice >= awe_max_voices)
-                       return FALSE;
-       } else {
-               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-                       return FALSE;
-       }
-       return TRUE;
-}
-
-static void release_voice(int voice, int do_sustain)
-{
-       if (IS_NO_SOUND(voice))
-               return;
-       if (do_sustain && (voices[voice].cinfo->sustained == 127 ||
-                           voices[voice].sostenuto == 127))
-               voices[voice].state = AWE_ST_SUSTAINED;
-       else {
-               awe_note_off(voice);
-               awe_fx_init(voices[voice].ch);
-               awe_voice_init(voice, FALSE);
-       }
-}
-
-/* release all notes */
-static void awe_note_off_all(int do_sustain)
-{
-       int i;
-       for (i = 0; i < awe_max_voices; i++)
-               release_voice(i, do_sustain);
-}
-
-/* kill a voice:
- *   not terminate, just release the voice.
- */
-static int
-awe_kill_note(int dev, int voice, int note, int velocity)
-{
-       int i, v2, key;
-
-       DEBUG(2,printk("AWE32: [off(%d) nt=%d vl=%d]\n", voice, note, velocity));
-       if (! voice_in_range(voice))
-               return RET_ERROR(EINVAL);
-
-       switch (playing_mode) {
-       case AWE_PLAY_DIRECT:
-       case AWE_PLAY_INDIRECT:
-               key = AWE_VOICE_KEY(voice);
-               break;
-
-       case AWE_PLAY_MULTI2:
-               v2 = voice_alloc->map[voice] >> 8;
-               voice_alloc->map[voice] = 0;
-               voice = v2;
-               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-                       return RET_ERROR(EINVAL);
-               /* continue to below */
-       default:
-               key = AWE_CHAN_KEY(voice, note);
-               break;
-       }
-
-       for (i = 0; i < awe_max_voices; i++) {
-               if (voices[i].key == key)
-                       release_voice(i, TRUE);
-       }
-       return 0;
-}
-
-
-static void start_or_volume_change(int voice, int velocity)
-{
-       voices[voice].velocity = velocity;
-       awe_calc_volume(voice);
-       if (voices[voice].state == AWE_ST_STANDBY)
-               awe_note_on(voice);
-       else if (voices[voice].state == AWE_ST_ON)
-               awe_set_volume(voice, FALSE);
-}
-
-static void set_and_start_voice(int voice, int state)
-{
-       /* calculate pitch & volume parameters */
-       voices[voice].state = state;
-       awe_calc_pitch(voice);
-       awe_calc_volume(voice);
-       if (state == AWE_ST_ON)
-               awe_note_on(voice);
-}
-
-/* start a voice:
- *   if note is 255, identical with aftertouch function.
- *   Otherwise, start a voice with specified not and volume.
- */
-static int
-awe_start_note(int dev, int voice, int note, int velocity)
-{
-       int i, key, state, volonly;
-
-       DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", voice, note, velocity));
-       if (! voice_in_range(voice))
-               return RET_ERROR(EINVAL);
-           
-       if (velocity == 0)
-               state = AWE_ST_STANDBY; /* stand by for playing */
-       else
-               state = AWE_ST_ON;      /* really play */
-       volonly = FALSE;
-
-       switch (playing_mode) {
-       case AWE_PLAY_DIRECT:
-       case AWE_PLAY_INDIRECT:
-               key = AWE_VOICE_KEY(voice);
-               if (note == 255)
-                       volonly = TRUE;
-               break;
-
-       case AWE_PLAY_MULTI2:
-               voice = voice_alloc->map[voice] >> 8;
-               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-                       return RET_ERROR(EINVAL);
-               /* continue to below */
-       default:
-               if (note >= 128) { /* key volume mode */
-                       note -= 128;
-                       volonly = TRUE;
-               }
-               key = AWE_CHAN_KEY(voice, note);
-               break;
-       }
-
-       /* dynamic volume change */
-       if (volonly) {
-               for (i = 0; i < awe_max_voices; i++) {
-                       if (voices[i].key == key)
-                               start_or_volume_change(i, velocity);
-               }
-               return 0;
-       }
-
-       /* if the same note still playing, stop it */
-       if (playing_mode != AWE_PLAY_DIRECT || ctrls[AWE_MD_EXCLUSIVE_SOUND]) {
-               for (i = 0; i < awe_max_voices; i++)
-                       if (voices[i].key == key) {
-                               if (voices[i].state == AWE_ST_ON) {
-                                       awe_note_off(i);
-                                       awe_voice_init(i, FALSE);
-                               } else if (voices[i].state == AWE_ST_STANDBY)
-                                       awe_voice_init(i, TRUE);
-                       }
-       }
-
-       /* allocate voices */
-       if (playing_mode == AWE_PLAY_DIRECT)
-               awe_alloc_one_voice(voice, note, velocity);
-       else
-               awe_alloc_multi_voices(voice, note, velocity, key);
-
-       /* turn off other voices exlusively (for drums) */
-       for (i = 0; i < awe_max_voices; i++)
-               if (voices[i].key == key)
-                       awe_exclusive_off(i);
-
-       /* set up pitch and volume parameters */
-       for (i = 0; i < awe_max_voices; i++) {
-               if (voices[i].key == key && voices[i].state == AWE_ST_OFF)
-                       set_and_start_voice(i, state);
-       }
-
-       return 0;
-}
-
-
-/* search instrument from preset table with the specified bank */
-static int
-awe_search_instr(int bank, int preset)
-{
-       int i;
-
-       limitvalue(preset, 0, AWE_MAX_PRESETS-1);
-       for (i = preset_table[preset]; i >= 0; i = infos[i].next_bank) {
-               if (infos[i].bank == bank)
-                       return i;
-       }
-       return -1;
-}
-
-
-/* assign the instrument to a voice */
-static int
-awe_set_instr_2(int dev, int voice, int instr_no)
-{
-       if (playing_mode == AWE_PLAY_MULTI2) {
-               voice = voice_alloc->map[voice] >> 8;
-               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-                       return RET_ERROR(EINVAL);
-       }
-       return awe_set_instr(dev, voice, instr_no);
-}
-
-/* assign the instrument to a channel; voice is the channel number */
-static int
-awe_set_instr(int dev, int voice, int instr_no)
-{
-       awe_chan_info *cinfo;
-       int def_bank;
-
-       if (! voice_in_range(voice))
-               return RET_ERROR(EINVAL);
-
-       if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS)
-               return RET_ERROR(EINVAL);
-
-       cinfo = &channels[voice];
-
-       if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
-               def_bank = AWE_DRUM_BANK; /* always search drumset */
-       else
-               def_bank = cinfo->bank;
-
-       cinfo->vrec = -1;
-       cinfo->def_vrec = -1;
-       cinfo->vrec = awe_search_instr(def_bank, instr_no);
-       if (def_bank == AWE_DRUM_BANK)  /* search default drumset */
-               cinfo->def_vrec = awe_search_instr(def_bank, ctrls[AWE_MD_DEF_DRUM]);
-       else    /* search default preset */
-               cinfo->def_vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr_no);
-
-       if (cinfo->vrec < 0 && cinfo->def_vrec < 0) {
-               DEBUG(1,printk("AWE32 Warning: can't find instrument %d\n", instr_no));
-       }
-
-       cinfo->instr = instr_no;
-       DEBUG(2,printk("AWE32: [program(%d) %d/%d]\n", voice, instr_no, def_bank));
-
-       return 0;
-}
-
-
-/* reset all voices; terminate sounds and initialize parameters */
-static void
-awe_reset(int dev)
-{
-       int i;
-       current_alloc_time = 0;
-       /* don't turn off voice 31 and 32.  they are used also for FM voices */
-       for (i = 0; i < awe_max_voices; i++) {
-               awe_terminate(i);
-               awe_voice_init(i, TRUE);
-       }
-       for (i = 0; i < AWE_MAX_CHANNELS; i++)
-               awe_channel_init(i, TRUE);
-       for (i = 0; i < 16; i++) {
-               awe_operations.chn_info[i].controllers[CTL_MAIN_VOLUME] = 127;
-               awe_operations.chn_info[i].controllers[CTL_EXPRESSION] = 127;
-       }
-       awe_init_fm();
-       awe_tweak();
-}
-
-
-/* hardware specific control:
- *   GUS specific and AWE32 specific controls are available.
- */
-static void
-awe_hw_control(int dev, unsigned char *event)
-{
-       int cmd = event[2];
-       if (cmd & _AWE_MODE_FLAG)
-               awe_hw_awe_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-       else
-               awe_hw_gus_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
-#endif
-}
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* GUS compatible controls */
-static void
-awe_hw_gus_control(int dev, int cmd, unsigned char *event)
-{
-       int voice, i, key;
-       unsigned short p1;
-       short p2;
-       int plong;
-
-       if (MULTI_LAYER_MODE())
-               return;
-       if (cmd == _GUS_NUMVOICES)
-               return;
-
-       voice = event[3];
-       if (! voice_in_range(voice))
-               return;
-
-       p1 = *(unsigned short *) &event[4];
-       p2 = *(short *) &event[6];
-       plong = *(int*) &event[4];
-
-       switch (cmd) {
-       case _GUS_VOICESAMPLE:
-               awe_set_instr(dev, voice, p1);
-               return;
-
-       case _GUS_VOICEBALA:
-               /* 0 to 15 --> -128 to 127 */
-               awe_panning(dev, voice, ((int)p1 << 4) - 128);
-               return;
-
-       case _GUS_VOICEVOL:
-       case _GUS_VOICEVOL2:
-               /* not supported yet */
-               return;
-
-       case _GUS_RAMPRANGE:
-       case _GUS_RAMPRATE:
-       case _GUS_RAMPMODE:
-       case _GUS_RAMPON:
-       case _GUS_RAMPOFF:
-               /* volume ramping not supported */
-               return;
-
-       case _GUS_VOLUME_SCALE:
-               return;
-
-       case _GUS_VOICE_POS:
-               FX_SET(&channels[voice].fx, AWE_FX_SAMPLE_START,
-                      (short)(plong & 0x7fff));
-               FX_SET(&channels[voice].fx, AWE_FX_COARSE_SAMPLE_START,
-                      (plong >> 15) & 0xffff);
-               return;
-       }
-
-       key = AWE_VOICE_KEY(voice);
-       for (i = 0; i < awe_max_voices; i++) {
-               if (voices[i].key == key) {
-                       switch (cmd) {
-                       case _GUS_VOICEON:
-                               awe_note_on(i);
-                               break;
-
-                       case _GUS_VOICEOFF:
-                               awe_terminate(i);
-                               awe_fx_init(voices[i].ch);
-                               awe_voice_init(i, TRUE);
-                               break;
-
-                       case _GUS_VOICEFADE:
-                               awe_note_off(i);
-                               awe_fx_init(voices[i].ch);
-                               awe_voice_init(i, FALSE);
-                               break;
-
-                       case _GUS_VOICEFREQ:
-                               awe_calc_pitch_from_freq(i, plong);
-                               break;
-                       }
-               }
-       }
-}
-
-#endif /* gus_compat */
-
-
-/* AWE32 specific controls */
-static void
-awe_hw_awe_control(int dev, int cmd, unsigned char *event)
-{
-       int voice;
-       unsigned short p1;
-       short p2;
-       int i;
-
-       voice = event[3];
-       if (! voice_in_range(voice))
-               return;
-
-       if (playing_mode == AWE_PLAY_MULTI2) {
-               voice = voice_alloc->map[voice] >> 8;
-               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-                       return;
-       }
-
-       p1 = *(unsigned short *) &event[4];
-       p2 = *(short *) &event[6];
-
-       switch (cmd) {
-       case _AWE_DEBUG_MODE:
-               ctrls[AWE_MD_DEBUG_MODE] = p1;
-               printk("AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]);
-               break;
-       case _AWE_REVERB_MODE:
-               ctrls[AWE_MD_REVERB_MODE] = p1;
-               awe_update_reverb_mode();
-               break;
-
-       case _AWE_CHORUS_MODE:
-               ctrls[AWE_MD_CHORUS_MODE] = p1;
-               awe_update_chorus_mode();
-               break;
-                     
-       case _AWE_REMOVE_LAST_SAMPLES:
-               DEBUG(0,printk("AWE32: remove last samples\n"));
-               if (locked_sf_id > 0)
-                       awe_remove_samples(locked_sf_id);
-               break;
-
-       case _AWE_INITIALIZE_CHIP:
-               awe_initialize();
-               break;
-
-       case _AWE_SEND_EFFECT:
-               i = -1;
-               if (p1 >= 0x100) {
-                       i = (p1 >> 8);
-                       if (i < 0 || i >= MAX_LAYERS)
-                               break;
-               }
-               awe_send_effect(voice, i, p1, p2);
-               break;
-
-       case _AWE_RESET_CHANNEL:
-               awe_channel_init(voice, !p1);
-               break;
-               
-       case _AWE_TERMINATE_ALL:
-               awe_reset(0);
-               break;
-
-       case _AWE_TERMINATE_CHANNEL:
-               awe_voice_change(voice, awe_terminate_and_init);
-               break;
-
-       case _AWE_RELEASE_ALL:
-               awe_note_off_all(FALSE);
-               break;
-       case _AWE_NOTEOFF_ALL:
-               awe_note_off_all(TRUE);
-               break;
-
-       case _AWE_INITIAL_VOLUME:
-               DEBUG(0,printk("AWE32: init attenuation %d\n", p1));
-               atten_relative = (char)p2;
-               atten_offset = (short)p1;
-               awe_update_volume();
-               break;
-
-       case _AWE_CHN_PRESSURE:
-               channels[voice].chan_press = p1;
-               awe_modwheel_change(voice, p1);
-               break;
-
-       case _AWE_CHANNEL_MODE:
-               DEBUG(0,printk("AWE32: channel mode = %d\n", p1));
-               playing_mode = p1;
-               awe_reset(0);
-               break;
-
-       case _AWE_DRUM_CHANNELS:
-               DEBUG(0,printk("AWE32: drum flags = %x\n", p1));
-               drum_flags = *(unsigned int*)&event[4];
-               break;
-
-       case _AWE_MISC_MODE:
-               DEBUG(0,printk("AWE32: ctrl parms = %d %d\n", p1, p2));
-               if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) {
-                       ctrls[p1] = p2;
-                       if (ctrl_parms[p1].update)
-                               ctrl_parms[p1].update();
-               }
-               break;
-
-       case _AWE_EQUALIZER:
-               ctrls[AWE_MD_BASS_LEVEL] = p1;
-               ctrls[AWE_MD_TREBLE_LEVEL] = p2;
-               awe_update_equalizer();
-               break;
-
-       default:
-               DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice));
-               break;
-       }
-}
-
-
-/* change effects */
-static void
-awe_send_effect(int voice, int layer, int type, int val)
-{
-       awe_chan_info *cinfo;
-       FX_Rec *fx;
-       int mode;
-
-       cinfo = &channels[voice];
-       if (layer >= 0 && layer < MAX_LAYERS)
-               fx = &cinfo->fx_layer[layer];
-       else
-               fx = &cinfo->fx;
-
-       if (type & 0x40)
-               mode = FX_FLAG_OFF;
-       else if (type & 0x80)
-               mode = FX_FLAG_ADD;
-       else
-               mode = FX_FLAG_SET;
-       type &= 0x3f;
-
-       if (type >= 0 && type < AWE_FX_END) {
-               DEBUG(2,printk("AWE32: effects (%d) %d %d\n", voice, type, val));
-               if (mode == FX_FLAG_SET)
-                       FX_SET(fx, type, val);
-               else if (mode == FX_FLAG_ADD)
-                       FX_ADD(fx, type, val);
-               else
-                       FX_UNSET(fx, type);
-               if (mode != FX_FLAG_OFF && parm_defs[type].realtime) {
-                       DEBUG(2,printk("AWE32: fx_realtime (%d)\n", voice));
-                       awe_voice_change(voice, parm_defs[type].realtime);
-               }
-       }
-}
-
-
-/* change modulation wheel; voice is already mapped on multi2 mode */
-static void
-awe_modwheel_change(int voice, int value)
-{
-       int i;
-       awe_chan_info *cinfo;
-
-       cinfo = &channels[voice];
-       i = value * ctrls[AWE_MD_MOD_SENSE] / 1200;
-       FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i);
-       awe_voice_change(voice, awe_fx_fmmod);
-       FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i);
-       awe_voice_change(voice, awe_fx_fm2frq2);
-}
-
-
-/* voice pressure change */
-static void
-awe_aftertouch(int dev, int voice, int pressure)
-{
-       int note;
-
-       DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure));
-       if (! voice_in_range(voice))
-               return;
-
-       switch (playing_mode) {
-       case AWE_PLAY_DIRECT:
-       case AWE_PLAY_INDIRECT:
-               awe_start_note(dev, voice, 255, pressure);
-               break;
-       case AWE_PLAY_MULTI2:
-               note = (voice_alloc->map[voice] & 0xff) - 1;
-               awe_key_pressure(dev, voice, note + 0x80, pressure);
-               break;
-       }
-}
-
-
-/* voice control change */
-static void
-awe_controller(int dev, int voice, int ctrl_num, int value)
-{
-       awe_chan_info *cinfo;
-
-       if (! voice_in_range(voice))
-               return;
-
-       if (playing_mode == AWE_PLAY_MULTI2) {
-               voice = voice_alloc->map[voice] >> 8;
-               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-                       return;
-       }
-
-       cinfo = &channels[voice];
-
-       switch (ctrl_num) {
-       case CTL_BANK_SELECT: /* MIDI control #0 */
-               DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value));
-               if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) &&
-                   !ctrls[AWE_MD_TOGGLE_DRUM_BANK])
-                       break;
-               cinfo->bank = value;
-               if (cinfo->bank == AWE_DRUM_BANK)
-                       DRUM_CHANNEL_ON(cinfo->channel);
-               else
-                       DRUM_CHANNEL_OFF(cinfo->channel);
-               awe_set_instr(dev, voice, cinfo->instr);
-               break;
-
-       case CTL_MODWHEEL: /* MIDI control #1 */
-               DEBUG(2,printk("AWE32: [modwheel(%d) %d]\n", voice, value));
-               awe_modwheel_change(voice, value);
-               break;
-
-       case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */
-               DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value));
-               /* zero centered */
-               cinfo->bender = value;
-               awe_voice_change(voice, awe_set_voice_pitch);
-               break;
-
-       case CTRL_PITCH_BENDER_RANGE: /* SEQ1 V2 control */
-               DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value));
-               /* value = sense x 100 */
-               cinfo->bender_range = value;
-               /* no audible pitch change yet.. */
-               break;
-
-       case CTL_EXPRESSION: /* MIDI control #11 */
-               if (SINGLE_LAYER_MODE())
-                       value /= 128;
-       case CTRL_EXPRESSION: /* SEQ1 V2 control */
-               DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value));
-               /* 0 - 127 */
-               cinfo->expression_vol = value;
-               awe_voice_change(voice, awe_set_voice_vol);
-               break;
-
-       case CTL_PAN:   /* MIDI control #10 */
-               DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value));
-               /* (0-127) -> signed 8bit */
-               cinfo->panning = value * 2 - 128;
-               if (ctrls[AWE_MD_REALTIME_PAN])
-                       awe_voice_change(voice, awe_set_pan);
-               break;
-
-       case CTL_MAIN_VOLUME:   /* MIDI control #7 */
-               if (SINGLE_LAYER_MODE())
-                       value = (value * 100) / 16383;
-       case CTRL_MAIN_VOLUME:  /* SEQ1 V2 control */
-               DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value));
-               /* 0 - 127 */
-               cinfo->main_vol = value;
-               awe_voice_change(voice, awe_set_voice_vol);
-               break;
-
-       case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */
-               DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value));
-               FX_SET(&cinfo->fx, AWE_FX_REVERB, value * 2);
-               break;
-
-       case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */
-               DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value));
-               FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2);
-               break;
-
-       case 120:  /* all sounds off */
-               awe_note_off_all(FALSE);
-               break;
-       case 123:  /* all notes off */
-               awe_note_off_all(TRUE);
-               break;
-
-       case CTL_SUSTAIN: /* MIDI control #64 */
-               cinfo->sustained = value;
-               if (value != 127)
-                       awe_voice_change(voice, awe_sustain_off);
-               break;
-
-       case CTL_SOSTENUTO: /* MIDI control #66 */
-               if (value == 127)
-                       awe_voice_change(voice, awe_sostenuto_on);
-               else
-                       awe_voice_change(voice, awe_sustain_off);
-               break;
-
-       default:
-               DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n",
-                          voice, ctrl_num, value));
-               break;
-       }
-}
-
-
-/* voice pan change (value = -128 - 127) */
-static void
-awe_panning(int dev, int voice, int value)
-{
-       awe_chan_info *cinfo;
-
-       if (! voice_in_range(voice))
-               return;
-
-       if (playing_mode == AWE_PLAY_MULTI2) {
-               voice = voice_alloc->map[voice] >> 8;
-               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-                       return;
-       }
-
-       cinfo = &channels[voice];
-       cinfo->panning = value;
-       DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning));
-       if (ctrls[AWE_MD_REALTIME_PAN])
-               awe_voice_change(voice, awe_set_pan);
-}
-
-
-/* volume mode change */
-static void
-awe_volume_method(int dev, int mode)
-{
-       /* not impremented */
-       DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode));
-}
-
-
-#ifndef AWE_NO_PATCHMGR
-/* patch manager */
-static int
-awe_patchmgr(int dev, struct patmgr_info *rec)
-{
-       printk("AWE32 Warning: patch manager control not supported\n");
-       return 0;
-}
-#endif
-
-
-/* pitch wheel change: 0-16384 */
-static void
-awe_bender(int dev, int voice, int value)
-{
-       awe_chan_info *cinfo;
-
-       if (! voice_in_range(voice))
-               return;
-
-       if (playing_mode == AWE_PLAY_MULTI2) {
-               voice = voice_alloc->map[voice] >> 8;
-               if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-                       return;
-       }
-
-       /* convert to zero centered value */
-       cinfo = &channels[voice];
-       cinfo->bender = value - 8192;
-       DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, cinfo->bender));
-       awe_voice_change(voice, awe_set_voice_pitch);
-}
-
-
-/*----------------------------------------------------------------
- * load a sound patch:
- *   three types of patches are accepted: AWE, GUS, and SYSEX.
- *----------------------------------------------------------------*/
-
-static int
-awe_load_patch(int dev, int format, const char *addr,
-              int offs, int count, int pmgr_flag)
-{
-       awe_patch_info patch;
-       int rc = 0;
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-       if (format == GUS_PATCH) {
-               return awe_load_guspatch(addr, offs, count, pmgr_flag);
-       } else
-#endif
-       if (format == SYSEX_PATCH) {
-               /* no system exclusive message supported yet */
-               return 0;
-       } else if (format != AWE_PATCH) {
-               printk("AWE32 Error: Invalid patch format (key) 0x%x\n", format);
-               return RET_ERROR(EINVAL);
-       }
-       
-       if (count < AWE_PATCH_INFO_SIZE) {
-               printk("AWE32 Error: Patch header too short\n");
-               return RET_ERROR(EINVAL);
-       }
-       COPY_FROM_USER(((char*)&patch) + offs, addr, offs, 
-                      AWE_PATCH_INFO_SIZE - offs);
-
-       count -= AWE_PATCH_INFO_SIZE;
-       if (count < patch.len) {
-               printk("AWE32: sample: Patch record too short (%d<%d)\n",
-                      count, patch.len);
-               return RET_ERROR(EINVAL);
-       }
-       
-       switch (patch.type) {
-       case AWE_LOAD_INFO:
-               rc = awe_load_info(&patch, addr, count);
-               break;
-       case AWE_LOAD_DATA:
-               rc = awe_load_data(&patch, addr, count);
-               break;
-       case AWE_OPEN_PATCH:
-               rc = awe_open_patch(&patch, addr, count);
-               break;
-       case AWE_CLOSE_PATCH:
-               rc = awe_close_patch(&patch, addr, count);
-               break;
-       case AWE_UNLOAD_PATCH:
-               rc = awe_unload_patch(&patch, addr, count);
-               break;
-       case AWE_REPLACE_DATA:
-               rc = awe_replace_data(&patch, addr, count);
-               break;
-       case AWE_MAP_PRESET:
-               rc = awe_load_map(&patch, addr, count);
-               break;
-       /* case AWE_PROBE_INFO:
-               rc = awe_probe_info(&patch, addr, count);
-               break;*/
-       case AWE_PROBE_DATA:
-               rc = awe_probe_data(&patch, addr, count);
-               break;
-       case AWE_LOAD_CHORUS_FX:
-               rc = awe_load_chorus_fx(&patch, addr, count);
-               break;
-       case AWE_LOAD_REVERB_FX:
-               rc = awe_load_reverb_fx(&patch, addr, count);
-               break;
-
-       default:
-               printk("AWE32 Error: unknown patch format type %d\n",
-                      patch.type);
-               rc = RET_ERROR(EINVAL);
-       }
-
-       return rc;
-}
-
-
-/* create an sflist record */
-static int
-awe_create_sf(int type, char *name)
-{
-       sf_list *rec;
-
-       /* terminate sounds */
-       awe_reset(0);
-       if (current_sf_id >= max_sfs) {
-#ifndef AWE_DYNAMIC_BUFFER
-               return 1;
-#else
-               int newsize = max_sfs + AWE_MAX_SF_LISTS;
-               sf_list *newlist = realloc_block(sflists, sizeof(sf_list)*max_sfs,
-                                                sizeof(sf_list)*newsize);
-               if (newlist == NULL)
-                       return 1;
-               sflists = newlist;
-               max_sfs = newsize;
-#endif /* dynamic buffer */
-       }
-       rec = &sflists[current_sf_id];
-       rec->sf_id = current_sf_id + 1;
-       rec->type = type;
-       if (current_sf_id == 0 || (type & AWE_PAT_LOCKED) != 0)
-               locked_sf_id = current_sf_id + 1;
-       rec->num_info = awe_free_info();
-       rec->num_sample = awe_free_sample();
-       rec->mem_ptr = awe_free_mem_ptr();
-       rec->infos = -1;
-       rec->samples = -1;
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-       rec->shared = 0;
-       if (name)
-               memcpy(rec->name, name, AWE_PATCH_NAME_LEN);
-       else
-               strcpy(rec->name, "*TEMPORARY*");
-       if (current_sf_id > 0 && name && (type & AWE_PAT_SHARED) != 0) {
-               /* is the current font really a shared font? */
-               if (is_shared_sf(rec->name)) {
-                       /* check if the shared font is already installed */
-                       int i;
-                       for (i = current_sf_id; i > 0; i--) {
-                               if (is_identical_name(rec->name, i)) {
-                                       rec->shared = i;
-                                       break;
-                               }
-                       }
-               }
-       }
-#endif /* allow sharing */
-
-       current_sf_id++;
-
-       return 0;
-}
-
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-
-/* check if the given name is a valid shared name */
-#define ASC_TO_KEY(c) ((c) - 'A' + 1)
-static int is_shared_sf(unsigned char *name)
-{
-       static unsigned char id_head[6] = {
-               ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'),
-               AWE_MAJOR_VERSION,
-               AWE_MINOR_VERSION,
-               AWE_TINY_VERSION,
-       };
-       if (MEMCMP(name, id_head, 6) == 0)
-               return TRUE;
-       return FALSE;
-}
-
-/* check if the given name matches to the existing list */
-static int is_identical_name(unsigned char *name, int sf) 
-{
-       char *id = sflists[sf-1].name;
-       if (is_shared_sf(id) && MEMCMP(id, name, AWE_PATCH_NAME_LEN) == 0)
-               return TRUE;
-       return FALSE;
-}
-
-/* check if the given voice info exists */
-static int info_duplicated(awe_voice_list *rec)
-{
-       int j, sf_id;
-       sf_list *sf;
-
-       /* search for all sharing lists */
-       for (sf_id = rec->v.sf_id; sf_id > 0 && sf_id <= current_sf_id; sf_id = sf->shared) {
-               sf = &sflists[sf_id - 1];
-               for (j = sf->infos; j >= 0; j = infos[j].next) {
-                       awe_voice_list *p = &infos[j];
-                       if (p->type == V_ST_NORMAL &&
-                           p->bank == rec->bank &&
-                           p->instr == rec->instr &&
-                           p->v.low == rec->v.low &&
-                           p->v.high == rec->v.high &&
-                           p->v.sample == rec->v.sample)
-                               return TRUE;
-               }
-       }
-       return FALSE;
-}
-
-#endif /* AWE_ALLOW_SAMPLE_SHARING */
-
-
-/* open patch; create sf list and set opened flag */
-static int
-awe_open_patch(awe_patch_info *patch, const char *addr, int count)
-{
-       awe_open_parm parm;
-       int shared;
-
-       COPY_FROM_USER(&parm, addr, AWE_PATCH_INFO_SIZE, sizeof(parm));
-       shared = FALSE;
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-       if (current_sf_id > 0 && (parm.type & AWE_PAT_SHARED) != 0) {
-               /* is the previous font the same font? */
-               if (is_identical_name(parm.name, current_sf_id)) {
-                       /* then append to the previous */
-                       shared = TRUE;
-                       awe_reset(0);
-                       if (parm.type & AWE_PAT_LOCKED)
-                               locked_sf_id = current_sf_id;
-               }
-       }
-#endif /* allow sharing */
-       if (! shared) {
-               if (awe_create_sf(parm.type, parm.name)) {
-                       printk("AWE32: can't open: failed to alloc new list\n");
-                       return RET_ERROR(ENOSPC);
-               }
-       }
-       patch_opened = TRUE;
-       return current_sf_id;
-}
-
-/* check if the patch is already opened */
-static int
-check_patch_opened(int type, char *name)
-{
-       if (! patch_opened) {
-               if (awe_create_sf(type, name)) {
-                       printk("AWE32: failed to alloc new list\n");
-                       return RET_ERROR(ENOSPC);
-               }
-               patch_opened = TRUE;
-               return current_sf_id;
-       }
-       return current_sf_id;
-}
-
-/* close the patch; if no voice is loaded, remove the patch */
-static int
-awe_close_patch(awe_patch_info *patch, const char *addr, int count)
-{
-       if (patch_opened && current_sf_id > 0) {
-               /* if no voice is loaded, release the current patch */
-               if (sflists[current_sf_id-1].infos == -1)
-                       awe_remove_samples(current_sf_id - 1);
-       }
-       patch_opened = 0;
-       return 0;
-}
-
-
-/* remove the latest patch */
-static int
-awe_unload_patch(awe_patch_info *patch, const char *addr, int count)
-{
-       if (current_sf_id > 0 && current_sf_id > locked_sf_id)
-               awe_remove_samples(current_sf_id - 1);
-       return 0;
-}
-
-/* allocate voice info list records */
-static int alloc_new_info(int nvoices)
-{
-       int newsize, free_info;
-       awe_voice_list *newlist;
-       free_info = awe_free_info();
-       if (free_info + nvoices >= max_infos) {
-#ifndef AWE_DYNAMIC_BUFFER
-               printk("AWE32: can't alloc info table\n");
-               return RET_ERROR(ENOSPC);
-#else
-               do {
-                       newsize = max_infos + AWE_MAX_INFOS;
-               } while (free_info + nvoices >= newsize);
-               newlist = realloc_block(infos, sizeof(awe_voice_list)*max_infos,
-                                       sizeof(awe_voice_list)*newsize);
-               if (newlist == NULL) {
-                       printk("AWE32: can't alloc info table\n");
-                       return RET_ERROR(ENOSPC);
-               }
-               infos = newlist;
-               max_infos = newsize;
-#endif
-       }
-       return 0;
-}
-
-/* allocate sample info list records */
-static int alloc_new_sample(void)
-{
-       int newsize, free_sample;
-       awe_sample_list *newlist;
-       free_sample = awe_free_sample();
-       if (free_sample >= max_samples) {
-#ifndef AWE_DYNAMIC_BUFFER
-               printk("AWE32: can't alloc sample table\n");
-               return RET_ERROR(ENOSPC);
-#else
-               newsize = max_samples + AWE_MAX_SAMPLES;
-               newlist = realloc_block(samples,
-                                       sizeof(awe_sample_list)*max_samples,
-                                       sizeof(awe_sample_list)*newsize);
-               if (newlist == NULL) {
-                       printk("AWE32: can't alloc sample table\n");
-                       return RET_ERROR(ENOSPC);
-               }
-               samples = newlist;
-               max_samples = newsize;
-#endif
-       }
-       return 0;
-}
-
-/* load voice map */
-static int
-awe_load_map(awe_patch_info *patch, const char *addr, int count)
-{
-       awe_voice_map map;
-       awe_voice_list *rec;
-       int p, free_info;
-
-       /* get the link info */
-       if (count < sizeof(map)) {
-               printk("AWE32 Error: invalid patch info length\n");
-               return RET_ERROR(EINVAL);
-       }
-       COPY_FROM_USER(&map, addr, AWE_PATCH_INFO_SIZE, sizeof(map));
-       
-       /* check if the identical mapping already exists */
-       p = awe_search_instr(map.map_bank, map.map_instr);
-       for (; p >= 0; p = infos[p].next_instr) {
-               if (p >= 0 && infos[p].type == V_ST_MAPPED &&
-                   infos[p].v.low == map.map_key &&
-                   infos[p].v.start == map.src_instr &&
-                   infos[p].v.end == map.src_bank &&
-                   infos[p].v.fixkey == map.src_key)
-                       return 0; /* already present! */
-       }
-
-       if (check_patch_opened(AWE_PAT_TYPE_MAP, NULL) < 0)
-               return RET_ERROR(ENOSPC);
-
-       if (alloc_new_info(1) < 0)
-               return RET_ERROR(ENOSPC);
-
-       free_info = awe_free_info();
-       rec = &infos[free_info];
-       rec->bank = map.map_bank;
-       rec->instr = map.map_instr;
-       rec->type = V_ST_MAPPED;
-       rec->disabled = FALSE;
-       awe_init_voice_info(&rec->v);
-       if (map.map_key >= 0) {
-               rec->v.low = map.map_key;
-               rec->v.high = map.map_key;
-       }
-       rec->v.start = map.src_instr;
-       rec->v.end = map.src_bank;
-       rec->v.fixkey = map.src_key;
-       rec->v.sf_id = current_sf_id;
-       add_info_list(free_info);
-       add_sf_info(free_info);
-
-       return 0;
-}
-
-#if 0
-/* probe preset in the current list -- nothing to be loaded */
-static int
-awe_probe_info(awe_patch_info *patch, const char *addr, int count)
-{
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-       awe_voice_map map;
-       int p;
-
-       if (! patch_opened)
-               return RET_ERROR(EINVAL);
-
-       /* get the link info */
-       if (count < sizeof(map)) {
-               printk("AWE32 Error: invalid patch info length\n");
-               return RET_ERROR(EINVAL);
-       }
-       COPY_FROM_USER(&map, addr, AWE_PATCH_INFO_SIZE, sizeof(map));
-       
-       /* check if the identical mapping already exists */
-       p = awe_search_instr(map.src_bank, map.src_instr);
-       for (; p >= 0; p = infos[p].next_instr) {
-               if (p >= 0 && infos[p].type == V_ST_NORMAL &&
-                   is_identical_id(infos[p].v.sf_id, current_sf_id) &&
-                   infos[p].v.low <= map.src_key &&
-                   infos[p].v.high >= map.src_key)
-                       return 0; /* already present! */
-       }
-#endif /* allow sharing */
-       return RET_ERROR(EINVAL);
-}
-#endif
-
-/* probe sample in the current list -- nothing to be loaded */
-static int
-awe_probe_data(awe_patch_info *patch, const char *addr, int count)
-{
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-       if (! patch_opened)
-               return RET_ERROR(EINVAL);
-
-       /* search the specified sample by optarg */
-       if (search_sample_index(current_sf_id, patch->optarg, 0) >= 0)
-               return 0;
-#endif /* allow sharing */
-       return RET_ERROR(EINVAL);
-}
-
-/* load voice information data */
-static int
-awe_load_info(awe_patch_info *patch, const char *addr, int count)
-{
-       int offset;
-       awe_voice_rec_hdr hdr;
-       int i;
-       int total_size;
-
-       if (count < AWE_VOICE_REC_SIZE) {
-               printk("AWE32 Error: invalid patch info length\n");
-               return RET_ERROR(EINVAL);
-       }
-
-       offset = AWE_PATCH_INFO_SIZE;
-       COPY_FROM_USER((char*)&hdr, addr, offset, AWE_VOICE_REC_SIZE);
-       offset += AWE_VOICE_REC_SIZE;
-
-       if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
-               printk("AWE32 Error: Illegal voice number %d\n", hdr.nvoices);
-               return RET_ERROR(EINVAL);
-       }
-       total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices;
-       if (count < total_size) {
-               printk("AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
-                      count, hdr.nvoices);
-               return RET_ERROR(EINVAL);
-       }
-
-       if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0)
-               return RET_ERROR(ENOSPC);
-
-#if 0 /* it looks like not so useful.. */
-       /* check if the same preset already exists in the info list */
-       for (i = sflists[current_sf_id-1].infos; i >= 0; i = infos[i].next) {
-               if (infos[i].disabled) continue;
-               if (infos[i].bank == hdr.bank && infos[i].instr == hdr.instr) {
-                       /* in exclusive mode, do skip loading this */
-                       if (hdr.write_mode == AWE_WR_EXCLUSIVE)
-                               return 0;
-                       /* in replace mode, disable the old data */
-                       else if (hdr.write_mode == AWE_WR_REPLACE)
-                               infos[i].disabled = TRUE;
-               }
-       }
-       if (hdr.write_mode == AWE_WR_REPLACE)
-               rebuild_preset_list();
-#endif
-
-       if (alloc_new_info(hdr.nvoices) < 0)
-               return RET_ERROR(ENOSPC);
-
-       for (i = 0; i < hdr.nvoices; i++) {
-               int rec = awe_free_info();
-
-               infos[rec].bank = hdr.bank;
-               infos[rec].instr = hdr.instr;
-               infos[rec].type = V_ST_NORMAL;
-               infos[rec].disabled = FALSE;
-
-               /* copy awe_voice_info parameters */
-               COPY_FROM_USER(&infos[rec].v, addr, offset, AWE_VOICE_INFO_SIZE);
-               offset += AWE_VOICE_INFO_SIZE;
-               infos[rec].v.sf_id = current_sf_id;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-               if (sflists[current_sf_id-1].shared) {
-                       if (info_duplicated(&infos[rec]))
-                               continue;
-               }
-#endif /* allow sharing */
-               if (infos[rec].v.mode & AWE_MODE_INIT_PARM)
-                       awe_init_voice_parm(&infos[rec].v.parm);
-               awe_set_sample(&infos[rec].v);
-               add_info_list(rec);
-               add_sf_info(rec);
-       }
-
-       return 0;
-}
-
-
-/* load wave sample data */
-static int
-awe_load_data(awe_patch_info *patch, const char *addr, int count)
-{
-       int offset, size;
-       int rc, free_sample;
-       awe_sample_info tmprec, *rec;
-
-       if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0)
-               return RET_ERROR(ENOSPC);
-
-       size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
-       offset = AWE_PATCH_INFO_SIZE;
-       COPY_FROM_USER(&tmprec, addr, offset, AWE_SAMPLE_INFO_SIZE);
-       offset += AWE_SAMPLE_INFO_SIZE;
-       if (size != tmprec.size) {
-               printk("AWE32: load: sample size differed (%d != %d)\n",
-                      tmprec.size, size);
-               return RET_ERROR(EINVAL);
-       }
-
-       if (search_sample_index(current_sf_id, tmprec.sample, 0) >= 0) {
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-               /* if shared sample, skip this data */
-               if (sflists[current_sf_id-1].type & AWE_PAT_SHARED)
-                       return 0;
-#endif /* allow sharing */
-               DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample));
-               return RET_ERROR(EINVAL);
-       }
-
-       if (alloc_new_sample() < 0)
-               return RET_ERROR(ENOSPC);
-
-       free_sample = awe_free_sample();
-       rec = &samples[free_sample].v;
-       *rec = tmprec;
-
-       if (rec->size > 0)
-               if ((rc = awe_write_wave_data(addr, offset, rec, -1)) != 0)
-                       return rc;
-
-       rec->sf_id = current_sf_id;
-
-       add_sf_sample(free_sample);
-
-       return 0;
-}
-
-
-/* replace wave sample data */
-static int
-awe_replace_data(awe_patch_info *patch, const char *addr, int count)
-{
-       int offset;
-       int size;
-       int rc, i;
-       int channels;
-       awe_sample_info cursmp;
-       int save_mem_ptr;
-
-       if (! patch_opened) {
-               printk("AWE32: replace: patch not opened\n");
-               return RET_ERROR(EINVAL);
-       }
-
-       size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
-       offset = AWE_PATCH_INFO_SIZE;
-       COPY_FROM_USER(&cursmp, addr, offset, AWE_SAMPLE_INFO_SIZE);
-       offset += AWE_SAMPLE_INFO_SIZE;
-       if (cursmp.size == 0 || size != cursmp.size) {
-               printk("AWE32: replace: illegal sample size (%d!=%d)\n",
-                      cursmp.size, size);
-               return RET_ERROR(EINVAL);
-       }
-       channels = patch->optarg;
-       if (channels <= 0 || channels > AWE_NORMAL_VOICES) {
-               printk("AWE32: replace: illegal channels %d\n", channels);
-               return RET_ERROR(EINVAL);
-       }
-
-       for (i = sflists[current_sf_id-1].samples;
-            i >= 0; i = samples[i].next) {
-               if (samples[i].v.sample == cursmp.sample)
-                       break;
-       }
-       if (i < 0) {
-               printk("AWE32: replace: cannot find existing sample data %d\n",
-                      cursmp.sample);
-               return RET_ERROR(EINVAL);
-       }
-               
-       if (samples[i].v.size != cursmp.size) {
-               printk("AWE32: replace: exiting size differed (%d!=%d)\n",
-                      samples[i].v.size, cursmp.size);
-               return RET_ERROR(EINVAL);
-       }
-
-       save_mem_ptr = awe_free_mem_ptr();
-       sflists[current_sf_id-1].mem_ptr = samples[i].v.start - awe_mem_start;
-       MEMCPY(&samples[i].v, &cursmp, sizeof(cursmp));
-       if ((rc = awe_write_wave_data(addr, offset, &samples[i].v, channels)) != 0)
-               return rc;
-       sflists[current_sf_id-1].mem_ptr = save_mem_ptr;
-       samples[i].v.sf_id = current_sf_id;
-
-       return 0;
-}
-
-
-/*----------------------------------------------------------------*/
-
-static const char *readbuf_addr;
-static int readbuf_offs;
-static int readbuf_flags;
-#ifdef MALLOC_LOOP_DATA
-static unsigned short *readbuf_loop;
-static int readbuf_loopstart, readbuf_loopend;
-#endif
-
-/* initialize read buffer */
-static int
-readbuf_init(const char *addr, int offset, awe_sample_info *sp)
-{
-#ifdef MALLOC_LOOP_DATA
-       readbuf_loop = NULL;
-       readbuf_loopstart = sp->loopstart;
-       readbuf_loopend = sp->loopend;
-       if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) {
-               int looplen = sp->loopend - sp->loopstart;
-               readbuf_loop = my_malloc(looplen * 2);
-               if (readbuf_loop == NULL) {
-                       printk("AWE32: can't malloc temp buffer\n");
-                       return RET_ERROR(ENOSPC);
-               }
-       }
-#endif
-       readbuf_addr = addr;
-       readbuf_offs = offset;
-       readbuf_flags = sp->mode_flags;
-       return 0;
-}
-
-/* read directly from user buffer */
-static unsigned short
-readbuf_word(int pos)
-{
-       unsigned short c;
-       /* read from user buffer */
-       if (readbuf_flags & AWE_SAMPLE_8BITS) {
-               unsigned char cc;
-               GET_BYTE_FROM_USER(cc, readbuf_addr, readbuf_offs + pos);
-               c = cc << 8; /* convert 8bit -> 16bit */
-       } else {
-               GET_SHORT_FROM_USER(c, readbuf_addr, readbuf_offs + pos * 2);
-       }
-       if (readbuf_flags & AWE_SAMPLE_UNSIGNED)
-               c ^= 0x8000; /* unsigned -> signed */
-#ifdef MALLOC_LOOP_DATA
-       /* write on cache for reverse loop */
-       if (readbuf_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) {
-               if (pos >= readbuf_loopstart && pos < readbuf_loopend)
-                       readbuf_loop[pos - readbuf_loopstart] = c;
-       }
-#endif
-       return c;
-}
-
-#ifdef MALLOC_LOOP_DATA
-/* read from cache */
-static unsigned short
-readbuf_word_cache(int pos)
-{
-       if (pos >= readbuf_loopstart && pos < readbuf_loopend)
-               return readbuf_loop[pos - readbuf_loopstart];
-       return 0;
-}
-
-static void
-readbuf_end(void)
-{
-       if (readbuf_loop) {
-               my_free(readbuf_loop);
-       }
-       readbuf_loop = NULL;
-}
-
-#else
-
-#define readbuf_word_cache     readbuf_word
-#define readbuf_end()          /**/
-
-#endif
-
-/*----------------------------------------------------------------*/
-
-#define BLANK_LOOP_START       8
-#define BLANK_LOOP_END         40
-#define BLANK_LOOP_SIZE                48
-
-/* loading onto memory */
-static int 
-awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels)
-{
-       int i, truesize, dram_offset;
-       int rc;
-
-       /* be sure loop points start < end */
-       if (sp->loopstart > sp->loopend) {
-               int tmp = sp->loopstart;
-               sp->loopstart = sp->loopend;
-               sp->loopend = tmp;
-       }
-
-       /* compute true data size to be loaded */
-       truesize = sp->size;
-       if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP)
-               truesize += sp->loopend - sp->loopstart;
-       if (sp->mode_flags & AWE_SAMPLE_NO_BLANK)
-               truesize += BLANK_LOOP_SIZE;
-       if (awe_free_mem_ptr() + truesize >= awe_mem_size/2) {
-               DEBUG(-1,printk("AWE32 Error: Sample memory full\n"));
-               return RET_ERROR(ENOSPC);
-       }
-
-       /* recalculate address offset */
-       sp->end -= sp->start;
-       sp->loopstart -= sp->start;
-       sp->loopend -= sp->start;
-
-       dram_offset = awe_free_mem_ptr() + awe_mem_start;
-       sp->start = dram_offset;
-       sp->end += dram_offset;
-       sp->loopstart += dram_offset;
-       sp->loopend += dram_offset;
-
-       /* set the total size (store onto obsolete checksum value) */
-       if (sp->size == 0)
-               sp->checksum = 0;
-       else
-               sp->checksum = truesize;
-
-       if ((rc = awe_open_dram_for_write(dram_offset, channels)) != 0)
-               return rc;
-
-       if (readbuf_init(addr, offset, sp) < 0)
-               return RET_ERROR(ENOSPC);
-
-       for (i = 0; i < sp->size; i++) {
-               unsigned short c;
-               c = readbuf_word(i);
-               awe_write_dram(c);
-               if (i == sp->loopend &&
-                   (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))) {
-                       int looplen = sp->loopend - sp->loopstart;
-                       /* copy reverse loop */
-                       int k;
-                       for (k = 1; k <= looplen; k++) {
-                               c = readbuf_word_cache(i - k);
-                               awe_write_dram(c);
-                       }
-                       if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) {
-                               sp->end += looplen;
-                       } else {
-                               sp->start += looplen;
-                               sp->end += looplen;
-                       }
-               }
-       }
-       readbuf_end();
-
-       /* if no blank loop is attached in the sample, add it */
-       if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) {
-               for (i = 0; i < BLANK_LOOP_SIZE; i++)
-                       awe_write_dram(0);
-               if (sp->mode_flags & AWE_SAMPLE_SINGLESHOT) {
-                       sp->loopstart = sp->end + BLANK_LOOP_START;
-                       sp->loopend = sp->end + BLANK_LOOP_END;
-               }
-       }
-
-       sflists[current_sf_id-1].mem_ptr += truesize;
-       awe_close_dram();
-
-       /* initialize FM */
-       awe_init_fm();
-
-       return 0;
-}
-
-
-/*----------------------------------------------------------------*/
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* calculate GUS envelope time:
- * is this correct?  i have no idea..
- */
-static int
-calc_gus_envelope_time(int rate, int start, int end)
-{
-       int r, p, t;
-       r = (3 - ((rate >> 6) & 3)) * 3;
-       p = rate & 0x3f;
-       t = end - start;
-       if (t < 0) t = -t;
-       if (13 > r)
-               t = t << (13 - r);
-       else
-               t = t >> (r - 13);
-       return (t * 10) / (p * 441);
-}
-
-#define calc_gus_sustain(val)  (0x7f - vol_table[(val)/2])
-#define calc_gus_attenuation(val)      vol_table[(val)/2]
-
-/* load GUS patch */
-static int
-awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
-{
-       struct patch_info patch;
-       awe_voice_info *rec;
-       awe_sample_info *smp;
-       int sizeof_patch;
-       int note, free_sample, free_info;
-       int rc;
-
-       sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */
-       if (size < sizeof_patch) {
-               printk("AWE32 Error: Patch header too short\n");
-               return RET_ERROR(EINVAL);
-       }
-       COPY_FROM_USER(((char*)&patch) + offs, addr, offs, sizeof_patch - offs);
-       size -= sizeof_patch;
-       if (size < patch.len) {
-               printk("AWE32 Warning: Patch record too short (%d<%d)\n",
-                      size, patch.len);
-               return RET_ERROR(EINVAL);
-       }
-       if (check_patch_opened(AWE_PAT_TYPE_GUS, NULL) < 0)
-               return RET_ERROR(ENOSPC);
-       if (alloc_new_sample() < 0)
-               return RET_ERROR(ENOSPC);
-       if (alloc_new_info(1))
-               return RET_ERROR(ENOSPC);
-
-       free_sample = awe_free_sample();
-       smp = &samples[free_sample].v;
-
-       smp->sample = free_sample;
-       smp->start = 0;
-       smp->end = patch.len;
-       smp->loopstart = patch.loop_start;
-       smp->loopend = patch.loop_end;
-       smp->size = patch.len;
-
-       /* set up mode flags */
-       smp->mode_flags = 0;
-       if (!(patch.mode & WAVE_16_BITS))
-               smp->mode_flags |= AWE_SAMPLE_8BITS;
-       if (patch.mode & WAVE_UNSIGNED)
-               smp->mode_flags |= AWE_SAMPLE_UNSIGNED;
-       smp->mode_flags |= AWE_SAMPLE_NO_BLANK;
-       if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK)))
-               smp->mode_flags |= AWE_SAMPLE_SINGLESHOT;
-       if (patch.mode & WAVE_BIDIR_LOOP)
-               smp->mode_flags |= AWE_SAMPLE_BIDIR_LOOP;
-       if (patch.mode & WAVE_LOOP_BACK)
-               smp->mode_flags |= AWE_SAMPLE_REVERSE_LOOP;
-
-       DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, smp->mode_flags));
-       if (patch.mode & WAVE_16_BITS) {
-               /* convert to word offsets */
-               smp->size /= 2;
-               smp->end /= 2;
-               smp->loopstart /= 2;
-               smp->loopend /= 2;
-       }
-       smp->checksum_flag = 0;
-       smp->checksum = 0;
-
-       if ((rc = awe_write_wave_data(addr, sizeof_patch, smp, -1)) != 0)
-               return rc;
-
-       smp->sf_id = current_sf_id;
-       add_sf_sample(free_sample);
-
-       /* set up voice info */
-       free_info = awe_free_info();
-       rec = &infos[free_info].v;
-       awe_init_voice_info(rec);
-       rec->sample = free_sample; /* the last sample */
-       rec->rate_offset = calc_rate_offset(patch.base_freq);
-       note = freq_to_note(patch.base_note);
-       rec->root = note / 100;
-       rec->tune = -(note % 100);
-       rec->low = freq_to_note(patch.low_note) / 100;
-       rec->high = freq_to_note(patch.high_note) / 100;
-       DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n",
-                      rec->rate_offset, note,
-                      rec->low, rec->high,
-             patch.low_note, patch.high_note));
-       /* panning position; -128 - 127 => 0-127 */
-       rec->pan = (patch.panning + 128) / 2;
-
-       /* detuning is ignored */
-       /* 6points volume envelope */
-       if (patch.mode & WAVE_ENVELOPES) {
-               int attack, hold, decay, release;
-               attack = calc_gus_envelope_time
-                       (patch.env_rate[0], 0, patch.env_offset[0]);
-               hold = calc_gus_envelope_time
-                       (patch.env_rate[1], patch.env_offset[0],
-                        patch.env_offset[1]);
-               decay = calc_gus_envelope_time
-                       (patch.env_rate[2], patch.env_offset[1],
-                        patch.env_offset[2]);
-               release = calc_gus_envelope_time
-                       (patch.env_rate[3], patch.env_offset[1],
-                        patch.env_offset[4]);
-               release += calc_gus_envelope_time
-                       (patch.env_rate[4], patch.env_offset[3],
-                        patch.env_offset[4]);
-               release += calc_gus_envelope_time
-                       (patch.env_rate[5], patch.env_offset[4],
-                        patch.env_offset[5]);
-               rec->parm.volatkhld = (calc_parm_attack(attack) << 8) |
-                       calc_parm_hold(hold);
-               rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |
-                       calc_parm_decay(decay);
-               rec->parm.volrelease = 0x8000 | calc_parm_decay(release);
-               DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release));
-               rec->attenuation = calc_gus_attenuation(patch.env_offset[0]);
-       }
-
-       /* tremolo effect */
-       if (patch.mode & WAVE_TREMOLO) {
-               int rate = (patch.tremolo_rate * 1000 / 38) / 42;
-               rec->parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate;
-               DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n",
-                              patch.tremolo_rate, patch.tremolo_depth,
-                              rec->parm.tremfrq));
-       }
-       /* vibrato effect */
-       if (patch.mode & WAVE_VIBRATO) {
-               int rate = (patch.vibrato_rate * 1000 / 38) / 42;
-               rec->parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate;
-               DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n",
-                              patch.tremolo_rate, patch.tremolo_depth,
-                              rec->parm.tremfrq));
-       }
-       
-       /* scale_freq, scale_factor, volume, and fractions not implemented */
-
-       /* append to the tail of the list */
-       infos[free_info].bank = ctrls[AWE_MD_GUS_BANK];
-       infos[free_info].instr = patch.instr_no;
-       infos[free_info].disabled = FALSE;
-       infos[free_info].type = V_ST_NORMAL;
-       infos[free_info].v.sf_id = current_sf_id;
-
-       add_info_list(free_info);
-       add_sf_info(free_info);
-
-       /* set the voice index */
-       awe_set_sample(rec);
-
-       return 0;
-}
-
-#endif  /* AWE_HAS_GUS_COMPATIBILITY */
-
-/*----------------------------------------------------------------
- * sample and voice list handlers
- *----------------------------------------------------------------*/
-
-/* append this to the sf list */
-static void add_sf_info(int rec)
-{
-       int sf_id = infos[rec].v.sf_id;
-       if (sf_id <= 0) return;
-       sf_id--;
-       if (sflists[sf_id].infos < 0)
-               sflists[sf_id].infos = rec;
-       else {
-               int i, prev;
-               prev = sflists[sf_id].infos;
-               while ((i = infos[prev].next) >= 0)
-                       prev = i;
-               infos[prev].next = rec;
-       }
-       infos[rec].next = -1;
-       sflists[sf_id].num_info++;
-}
-
-/* prepend this sample to sf list */
-static void add_sf_sample(int rec)
-{
-       int sf_id = samples[rec].v.sf_id;
-       if (sf_id <= 0) return;
-       sf_id--;
-       samples[rec].next = sflists[sf_id].samples;
-       sflists[sf_id].samples = rec;
-       sflists[sf_id].num_sample++;
-}
-
-/* purge the old records which don't belong with the same file id */
-static void purge_old_list(int rec, int next)
-{
-       infos[rec].next_instr = next;
-       if (infos[rec].bank == AWE_DRUM_BANK) {
-               /* remove samples with the same note range */
-               int cur, *prevp = &infos[rec].next_instr;
-               int low = infos[rec].v.low;
-               int high = infos[rec].v.high;
-               for (cur = next; cur >= 0; cur = infos[cur].next_instr) {
-                       if (infos[cur].v.low == low &&
-                           infos[cur].v.high == high &&
-                           ! is_identical_id(infos[cur].v.sf_id, infos[rec].v.sf_id))
-                               *prevp = infos[cur].next_instr;
-                       prevp = &infos[cur].next_instr;
-               }
-       } else {
-               if (! is_identical_id(infos[next].v.sf_id, infos[rec].v.sf_id))
-                       infos[rec].next_instr = -1;
-       }
-}
-
-/* prepend to top of the preset table */
-static void add_info_list(int rec)
-{
-       int *prevp, cur;
-       int instr;
-       int bank;
-
-       if (infos[rec].disabled)
-               return;
-
-       instr = infos[rec].instr;
-       bank = infos[rec].bank;
-       limitvalue(instr, 0, AWE_MAX_PRESETS-1);
-       prevp = &preset_table[instr];
-       cur = *prevp;
-       while (cur >= 0) {
-               /* search the first record with the same bank number */
-               if (infos[cur].bank == bank) {
-                       /* replace the list with the new record */
-                       infos[rec].next_bank = infos[cur].next_bank;
-                       *prevp = rec;
-                       purge_old_list(rec, cur);
-                       return;
-               }
-               prevp = &infos[cur].next_bank;
-               cur = infos[cur].next_bank;
-       }
-
-       /* this is the first bank record.. just add this */
-       infos[rec].next_instr = -1;
-       infos[rec].next_bank = preset_table[instr];
-       preset_table[instr] = rec;
-}
-
-/* remove samples later than the specified sf_id */
-static void
-awe_remove_samples(int sf_id)
-{
-       if (sf_id <= 0) {
-               awe_reset_samples();
-               return;
-       }
-       /* already removed? */
-       if (current_sf_id <= sf_id)
-               return;
-
-       current_sf_id = sf_id;
-       if (locked_sf_id > sf_id)
-               locked_sf_id = sf_id;
-
-       rebuild_preset_list();
-}
-
-/* rebuild preset search list */
-static void rebuild_preset_list(void)
-{
-       int i, j;
-
-       for (i = 0; i < AWE_MAX_PRESETS; i++)
-               preset_table[i] = -1;
-
-       for (i = 0; i < current_sf_id; i++) {
-               for (j = sflists[i].infos; j >= 0; j = infos[j].next)
-                       add_info_list(j);
-       }
-}
-
-/* compare the given sf_id pair */
-static int is_identical_id(int id1, int id2)
-{
-       if (id1 == id2)
-               return TRUE;
-       if (id1 <= 0 || id2 <= 0) /* this must not happen.. */
-               return FALSE;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-       {
-               /* compare with the sharing id */
-               int i;
-               if (id1 < id2) { /* make sure id1 > id2 */
-                       int tmp; tmp = id1; id1 = id2; id2 = tmp;
-               }
-               for (i = sflists[id1-1].shared; i > 0 && i <= current_sf_id; i = sflists[i-1].shared) {
-                       if (i == id2)
-                               return TRUE;
-               }
-       }
-#endif /* allow sharing */
-       return FALSE;
-}
-
-/* search the sample index matching with the given sample id */
-static int search_sample_index(int sf, int sample, int level)
-{
-       int i;
-
-       if (sf <= 0 || sf > current_sf_id)
-               return -1; /* this must not happen */
-
-       for (i = sflists[sf-1].samples; i >= 0; i = samples[i].next) {
-               if (samples[i].v.sample == sample)
-                       return i;
-       }
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-       if ((i = sflists[sf-1].shared) > 0 && i <= current_sf_id) { /* search recursively */
-               if (level > current_sf_id)
-                       return -1; /* strange sharing loop.. quit */
-               return search_sample_index(i, sample, level + 1);
-       }
-#endif
-       return -1;
-}
-
-/* search the specified sample */
-static short
-awe_set_sample(awe_voice_info *vp)
-{
-       int i;
-
-       vp->index = -1;
-       if ((i = search_sample_index(vp->sf_id, vp->sample, 0)) < 0)
-               return -1;
-
-       /* set the actual sample offsets */
-       vp->start += samples[i].v.start;
-       vp->end += samples[i].v.end;
-       vp->loopstart += samples[i].v.loopstart;
-       vp->loopend += samples[i].v.loopend;
-       /* copy mode flags */
-       vp->mode = samples[i].v.mode_flags;
-       /* set index */
-       vp->index = i;
-
-       return i;
-}
-
-
-/*----------------------------------------------------------------
- * voice allocation
- *----------------------------------------------------------------*/
-
-/* look for all voices associated with the specified note & velocity */
-static int
-awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist)
-{
-       int nvoices;
-
-       nvoices = 0;
-       for (; rec >= 0; rec = infos[rec].next_instr) {
-               if (note >= infos[rec].v.low &&
-                   note <= infos[rec].v.high &&
-                   velocity >= infos[rec].v.vellow &&
-                   velocity <= infos[rec].v.velhigh) {
-                       if (infos[rec].type == V_ST_MAPPED) {
-                               /* mapper */
-                               vlist[0] = &infos[rec].v;
-                               return -1;
-                       }
-                       vlist[nvoices++] = &infos[rec].v;
-                       if (nvoices >= AWE_MAX_VOICES)
-                               break;
-               }
-       }
-       return nvoices; 
-}
-
-/* store the voice list from the specified note and velocity.
-   if the preset is mapped, seek for the destination preset, and rewrite
-   the note number if necessary.
-   */
-static int
-really_alloc_voices(int vrec, int def_vrec, int *note, int velocity, awe_voice_info **vlist, int level)
-{
-       int nvoices;
-
-       nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
-       if (nvoices == 0)
-               nvoices = awe_search_multi_voices(def_vrec, *note, velocity, vlist);
-       if (nvoices < 0) { /* mapping */
-               int preset = vlist[0]->start;
-               int bank = vlist[0]->end;
-               int key = vlist[0]->fixkey;
-               if (level > 5) {
-                       printk("AWE32: too deep mapping level\n");
-                       return 0;
-               }
-               vrec = awe_search_instr(bank, preset);
-               if (bank == AWE_DRUM_BANK)
-                       def_vrec = awe_search_instr(bank, 0);
-               else
-                       def_vrec = awe_search_instr(0, preset);
-               if (key >= 0)
-                       *note = key;
-               return really_alloc_voices(vrec, def_vrec, note, velocity, vlist, level+1);
-       }
-
-       return nvoices;
-}
-
-/* allocate voices corresponding note and velocity; supports multiple insts. */
-static void
-awe_alloc_multi_voices(int ch, int note, int velocity, int key)
-{
-       int i, v, nvoices;
-       awe_voice_info *vlist[AWE_MAX_VOICES];
-
-       if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0)
-               awe_set_instr(0, ch, channels[ch].instr);
-
-       /* check the possible voices; note may be changeable if mapped */
-       nvoices = really_alloc_voices(channels[ch].vrec, channels[ch].def_vrec,
-                                     &note, velocity, vlist, 0);
-
-       /* set the voices */
-       current_alloc_time++;
-       for (i = 0; i < nvoices; i++) {
-               v = awe_clear_voice();
-               voices[v].key = key;
-               voices[v].ch = ch;
-               voices[v].note = note;
-               voices[v].velocity = velocity;
-               voices[v].time = current_alloc_time;
-               voices[v].cinfo = &channels[ch];
-               voices[v].sample = vlist[i];
-               voices[v].state = AWE_ST_MARK;
-               voices[v].layer = nvoices - i - 1;  /* in reverse order */
-       }
-
-       /* clear the mark in allocated voices */
-       for (i = 0; i < awe_max_voices; i++) {
-               if (voices[i].state == AWE_ST_MARK)
-                       voices[i].state = AWE_ST_OFF;
-                       
-       }
-}
-
-
-/* search the best voice from the specified status condition */
-static int
-search_best_voice(int condition)
-{
-       int i, time, best;
-       int vtarget = 0xffff, min_vtarget = 0xffff;
-
-       best = -1;
-       time = current_alloc_time + 1;
-       for (i = 0; i < awe_max_voices; i++) {
-               if (! (voices[i].state & condition))
-                       continue;
-#ifdef AWE_CHECK_VTARGET
-               /* get current volume */
-               vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff;
-#endif
-               if (best < 0 || vtarget < min_vtarget ||
-                   (vtarget == min_vtarget && voices[i].time < time)) {
-                       best = i;
-                       time = voices[i].time;
-                       min_vtarget = vtarget;
-               }
-       }
-       /* clear voice */
-       if (best >= 0) {
-               if (voices[best].state != AWE_ST_OFF)
-                       awe_terminate(best);
-               awe_voice_init(best, TRUE);
-       }
-
-       return best;
-}
-
-/* search an empty voice.
-   if no empty voice is found, at least terminate a voice
-   */
-static int
-awe_clear_voice(void)
-{
-       int best;
-
-       /* looking for the oldest empty voice */
-       if ((best = search_best_voice(AWE_ST_OFF)) >= 0)
-               return best;
-       if ((best = search_best_voice(AWE_ST_RELEASED)) >= 0)
-               return best;
-       /* looking for the oldest sustained voice */
-       if ((best = search_best_voice(AWE_ST_SUSTAINED)) >= 0)
-               return best;
-
-       if (MULTI_LAYER_MODE() && ctrls[AWE_MD_CHN_PRIOR]) {
-               int ch = -1;
-               int time = current_alloc_time + 1;
-               int i;
-               /* looking for the voices from high channel (except drum ch) */
-               for (i = 0; i < awe_max_voices; i++) {
-                       if (IS_DRUM_CHANNEL(voices[i].ch)) continue;
-                       if (voices[i].ch < ch) continue;
-                       if (voices[i].state != AWE_ST_MARK &&
-                           (voices[i].ch > ch || voices[i].time < time)) {
-                               best = i;
-                               time = voices[i].time;
-                               ch = voices[i].ch;
-                       }
-               }
-       }
-       if (best < 0)
-               best = search_best_voice(~AWE_ST_MARK);
-
-       if (best >= 0)
-               return best;
-
-       return 0;
-}
-
-
-/* search sample for the specified note & velocity and set it on the voice;
- * note that voice is the voice index (not channel index)
- */
-static void
-awe_alloc_one_voice(int voice, int note, int velocity)
-{
-       int ch, nvoices;
-       awe_voice_info *vlist[AWE_MAX_VOICES];
-
-       ch = voices[voice].ch;
-       if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0)
-               awe_set_instr(0, ch, channels[ch].instr);
-
-       nvoices = really_alloc_voices(voices[voice].cinfo->vrec,
-                                     voices[voice].cinfo->def_vrec,
-                                     &note, velocity, vlist, 0);
-       if (nvoices > 0) {
-               voices[voice].time = ++current_alloc_time;
-               voices[voice].sample = vlist[0]; /* use the first one */
-               voices[voice].layer = 0;
-               voices[voice].note = note;
-               voices[voice].velocity = velocity;
-       }
-}
-
-
-/*----------------------------------------------------------------
- * sequencer2 functions
- *----------------------------------------------------------------*/
-
-/* search an empty voice; used by sequencer2 */
-static int
-awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
-{
-       playing_mode = AWE_PLAY_MULTI2;
-       awe_info.nr_voices = AWE_MAX_CHANNELS;
-       return awe_clear_voice();
-}
-
-
-/* set up voice; used by sequencer2 */
-static void
-awe_setup_voice(int dev, int voice, int chn)
-{
-       struct channel_info *info;
-       if (synth_devs[dev] == NULL ||
-           (info = &synth_devs[dev]->chn_info[chn]) == NULL)
-               return;
-
-       if (voice < 0 || voice >= awe_max_voices)
-               return;
-
-       DEBUG(2,printk("AWE32: [setup(%d) ch=%d]\n", voice, chn));
-       channels[chn].expression_vol = info->controllers[CTL_EXPRESSION];
-       channels[chn].main_vol = info->controllers[CTL_MAIN_VOLUME];
-       channels[chn].panning =
-               info->controllers[CTL_PAN] * 2 - 128; /* signed 8bit */
-       channels[chn].bender = info->bender_value; /* zero center */
-       channels[chn].bank = info->controllers[CTL_BANK_SELECT];
-       channels[chn].sustained = info->controllers[CTL_SUSTAIN];
-       if (info->controllers[CTL_EXT_EFF_DEPTH]) {
-               FX_SET(&channels[chn].fx, AWE_FX_REVERB,
-                      info->controllers[CTL_EXT_EFF_DEPTH] * 2);
-       }
-       if (info->controllers[CTL_CHORUS_DEPTH]) {
-               FX_SET(&channels[chn].fx, AWE_FX_CHORUS,
-                      info->controllers[CTL_CHORUS_DEPTH] * 2);
-       }
-       awe_set_instr(dev, chn, info->pgm_num);
-}
-
-
-#ifdef CONFIG_AWE32_MIXER
-/*================================================================
- * AWE32 mixer device control
- *================================================================*/
-
-static int awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg);
-
-static int my_mixerdev = -1;
-
-static struct mixer_operations awe_mixer_operations = {
-#ifndef __FreeBSD__
-       "AWE32",
-#endif
-       "AWE32 Equalizer",
-       awe_mixer_ioctl,
-};
-
-static void attach_mixer(void)
-{
-       if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) {
-               mixer_devs[my_mixerdev] = &awe_mixer_operations;
-       }
-}
-
-static void unload_mixer(void)
-{
-       if (my_mixerdev >= 0)
-               sound_unload_mixerdev(my_mixerdev);
-}
-
-static int
-awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
-{
-       int i, level, value;
-
-       if (((cmd >> 8) & 0xff) != 'M')
-               return RET_ERROR(EINVAL);
-
-       level = (int)IOCTL_IN(arg);
-       level = ((level & 0xff) + (level >> 8)) / 2;
-       DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level));
-
-       if (IO_WRITE_CHECK(cmd)) {
-               switch (cmd & 0xff) {
-               case SOUND_MIXER_BASS:
-                       value = level * 12 / 100;
-                       if (value >= 12)
-                               value = 11;
-                       ctrls[AWE_MD_BASS_LEVEL] = value;
-                       awe_update_equalizer();
-                       break;
-               case SOUND_MIXER_TREBLE:
-                       value = level * 12 / 100;
-                       if (value >= 12)
-                               value = 11;
-                       ctrls[AWE_MD_TREBLE_LEVEL] = value;
-                       awe_update_equalizer();
-                       break;
-               case SOUND_MIXER_VOLUME:
-                       level = level * 127 / 100;
-                       if (level >= 128) level = 127;
-                       atten_relative = FALSE;
-                       atten_offset = vol_table[level];
-                       awe_update_volume();
-                       break;
-               }
-       }
-       switch (cmd & 0xff) {
-       case SOUND_MIXER_BASS:
-               level = ctrls[AWE_MD_BASS_LEVEL] * 100 / 24;
-               level = (level << 8) | level;
-               break;
-       case SOUND_MIXER_TREBLE:
-               level = ctrls[AWE_MD_TREBLE_LEVEL] * 100 / 24;
-               level = (level << 8) | level;
-               break;
-       case SOUND_MIXER_VOLUME:
-               value = atten_offset;
-               if (atten_relative)
-                       value += ctrls[AWE_MD_ZERO_ATTEN];
-               for (i = 127; i > 0; i--) {
-                       if (value <= vol_table[i])
-                               break;
-               }
-               level = i * 100 / 127;
-               level = (level << 8) | level;
-               break;
-       case SOUND_MIXER_DEVMASK:
-               level = SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_VOLUME;
-               break;
-       default:
-               level = 0;
-               break;
-       }
-       return IOCTL_OUT(arg, level);
-}
-#endif /* CONFIG_AWE32_MIXER */
-
-
-/*================================================================
- * initialization of AWE32
- *================================================================*/
-
-/* intiailize audio channels */
-static void
-awe_init_audio(void)
-{
-       int ch;
-
-       /* turn off envelope engines */
-       for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
-               awe_poke(AWE_DCYSUSV(ch), 0x80);
-       }
-  
-       /* reset all other parameters to zero */
-       for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
-               awe_poke(AWE_ENVVOL(ch), 0);
-               awe_poke(AWE_ENVVAL(ch), 0);
-               awe_poke(AWE_DCYSUS(ch), 0);
-               awe_poke(AWE_ATKHLDV(ch), 0);
-               awe_poke(AWE_LFO1VAL(ch), 0);
-               awe_poke(AWE_ATKHLD(ch), 0);
-               awe_poke(AWE_LFO2VAL(ch), 0);
-               awe_poke(AWE_IP(ch), 0);
-               awe_poke(AWE_IFATN(ch), 0);
-               awe_poke(AWE_PEFE(ch), 0);
-               awe_poke(AWE_FMMOD(ch), 0);
-               awe_poke(AWE_TREMFRQ(ch), 0);
-               awe_poke(AWE_FM2FRQ2(ch), 0);
-               awe_poke_dw(AWE_PTRX(ch), 0);
-               awe_poke_dw(AWE_VTFT(ch), 0);
-               awe_poke_dw(AWE_PSST(ch), 0);
-               awe_poke_dw(AWE_CSL(ch), 0);
-               awe_poke_dw(AWE_CCCA(ch), 0);
-       }
-
-       for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
-               awe_poke_dw(AWE_CPF(ch), 0);
-               awe_poke_dw(AWE_CVCF(ch), 0);
-       }
-}
-
-
-/* initialize DMA address */
-static void
-awe_init_dma(void)
-{
-       awe_poke_dw(AWE_SMALR, 0);
-       awe_poke_dw(AWE_SMARR, 0);
-       awe_poke_dw(AWE_SMALW, 0);
-       awe_poke_dw(AWE_SMARW, 0);
-}
-
-
-/* initialization arrays; from ADIP */
-
-static unsigned short init1[128] = {
-       0x03ff, 0x0030,  0x07ff, 0x0130, 0x0bff, 0x0230,  0x0fff, 0x0330,
-       0x13ff, 0x0430,  0x17ff, 0x0530, 0x1bff, 0x0630,  0x1fff, 0x0730,
-       0x23ff, 0x0830,  0x27ff, 0x0930, 0x2bff, 0x0a30,  0x2fff, 0x0b30,
-       0x33ff, 0x0c30,  0x37ff, 0x0d30, 0x3bff, 0x0e30,  0x3fff, 0x0f30,
-
-       0x43ff, 0x0030,  0x47ff, 0x0130, 0x4bff, 0x0230,  0x4fff, 0x0330,
-       0x53ff, 0x0430,  0x57ff, 0x0530, 0x5bff, 0x0630,  0x5fff, 0x0730,
-       0x63ff, 0x0830,  0x67ff, 0x0930, 0x6bff, 0x0a30,  0x6fff, 0x0b30,
-       0x73ff, 0x0c30,  0x77ff, 0x0d30, 0x7bff, 0x0e30,  0x7fff, 0x0f30,
-
-       0x83ff, 0x0030,  0x87ff, 0x0130, 0x8bff, 0x0230,  0x8fff, 0x0330,
-       0x93ff, 0x0430,  0x97ff, 0x0530, 0x9bff, 0x0630,  0x9fff, 0x0730,
-       0xa3ff, 0x0830,  0xa7ff, 0x0930, 0xabff, 0x0a30,  0xafff, 0x0b30,
-       0xb3ff, 0x0c30,  0xb7ff, 0x0d30, 0xbbff, 0x0e30,  0xbfff, 0x0f30,
-
-       0xc3ff, 0x0030,  0xc7ff, 0x0130, 0xcbff, 0x0230,  0xcfff, 0x0330,
-       0xd3ff, 0x0430,  0xd7ff, 0x0530, 0xdbff, 0x0630,  0xdfff, 0x0730,
-       0xe3ff, 0x0830,  0xe7ff, 0x0930, 0xebff, 0x0a30,  0xefff, 0x0b30,
-       0xf3ff, 0x0c30,  0xf7ff, 0x0d30, 0xfbff, 0x0e30,  0xffff, 0x0f30,
-};
-
-static unsigned short init2[128] = {
-       0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
-       0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
-       0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
-       0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
-
-       0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
-       0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
-       0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
-       0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
-
-       0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
-       0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
-       0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
-       0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
-
-       0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
-       0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
-       0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
-       0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
-};
-
-static unsigned short init3[128] = {
-       0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
-       0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
-       0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
-       0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
-
-       0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
-       0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
-       0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
-       0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
-
-       0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
-       0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
-       0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
-       0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
-
-       0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
-       0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
-       0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
-       0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
-};
-
-static unsigned short init4[128] = {
-       0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
-       0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
-       0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
-       0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
-
-       0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
-       0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
-       0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
-       0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
-
-       0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
-       0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
-       0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
-       0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
-
-       0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
-       0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
-       0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
-       0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
-};
-
-
-/* send initialization arrays to start up */
-static void
-awe_init_array(void)
-{
-       awe_send_array(init1);
-       awe_wait(1024);
-       awe_send_array(init2);
-       awe_send_array(init3);
-       awe_poke_dw(AWE_HWCF4, 0);
-       awe_poke_dw(AWE_HWCF5, 0x83);
-       awe_poke_dw(AWE_HWCF6, 0x8000);
-       awe_send_array(init4);
-}
-
-/* send an initialization array */
-static void
-awe_send_array(unsigned short *data)
-{
-       int i;
-       unsigned short *p;
-
-       p = data;
-       for (i = 0; i < AWE_MAX_VOICES; i++, p++)
-               awe_poke(AWE_INIT1(i), *p);
-       for (i = 0; i < AWE_MAX_VOICES; i++, p++)
-               awe_poke(AWE_INIT2(i), *p);
-       for (i = 0; i < AWE_MAX_VOICES; i++, p++)
-               awe_poke(AWE_INIT3(i), *p);
-       for (i = 0; i < AWE_MAX_VOICES; i++, p++)
-               awe_poke(AWE_INIT4(i), *p);
-}
-
-
-/*
- * set up awe32 channels to some known state.
- */
-
-/* set the envelope & LFO parameters to the default values; see ADIP */
-static void
-awe_tweak_voice(int i)
-{
-       /* set all mod/vol envelope shape to minimum */
-       awe_poke(AWE_ENVVOL(i), 0x8000);
-       awe_poke(AWE_ENVVAL(i), 0x8000);
-       awe_poke(AWE_DCYSUS(i), 0x7F7F);
-       awe_poke(AWE_ATKHLDV(i), 0x7F7F);
-       awe_poke(AWE_ATKHLD(i), 0x7F7F);
-       awe_poke(AWE_PEFE(i), 0);  /* mod envelope height to zero */
-       awe_poke(AWE_LFO1VAL(i), 0x8000); /* no delay for LFO1 */
-       awe_poke(AWE_LFO2VAL(i), 0x8000);
-       awe_poke(AWE_IP(i), 0xE000);    /* no pitch shift */
-       awe_poke(AWE_IFATN(i), 0xFF00); /* volume to minimum */
-       awe_poke(AWE_FMMOD(i), 0);
-       awe_poke(AWE_TREMFRQ(i), 0);
-       awe_poke(AWE_FM2FRQ2(i), 0);
-}
-
-static void
-awe_tweak(void)
-{
-       int i;
-       /* reset all channels */
-       for (i = 0; i < awe_max_voices; i++)
-               awe_tweak_voice(i);
-}
-
-
-/*
- *  initializes the FM section of AWE32;
- *   see Vince Vu's unofficial AWE32 programming guide
- */
-
-static void
-awe_init_fm(void)
-{
-#ifndef AWE_ALWAYS_INIT_FM
-       /* if no extended memory is on board.. */
-       if (awe_mem_size <= 0)
-               return;
-#endif
-       DEBUG(3,printk("AWE32: initializing FM\n"));
-
-       /* Initialize the last two channels for DRAM refresh and producing
-          the reverb and chorus effects for Yamaha OPL-3 synthesizer */
-
-       /* 31: FM left channel, 0xffffe0-0xffffe8 */
-       awe_poke(AWE_DCYSUSV(30), 0x80);
-       awe_poke_dw(AWE_PSST(30), 0xFFFFFFE0); /* full left */
-       awe_poke_dw(AWE_CSL(30), 0x00FFFFE8 |
-                   (DEF_FM_CHORUS_DEPTH << 24));
-       awe_poke_dw(AWE_PTRX(30), (DEF_FM_REVERB_DEPTH << 8));
-       awe_poke_dw(AWE_CPF(30), 0);
-       awe_poke_dw(AWE_CCCA(30), 0x00FFFFE3);
-
-       /* 32: FM right channel, 0xfffff0-0xfffff8 */
-       awe_poke(AWE_DCYSUSV(31), 0x80);
-       awe_poke_dw(AWE_PSST(31), 0x00FFFFF0); /* full right */
-       awe_poke_dw(AWE_CSL(31), 0x00FFFFF8 |
-                   (DEF_FM_CHORUS_DEPTH << 24));
-       awe_poke_dw(AWE_PTRX(31), (DEF_FM_REVERB_DEPTH << 8));
-       awe_poke_dw(AWE_CPF(31), 0x8000);
-       awe_poke_dw(AWE_CCCA(31), 0x00FFFFF3);
-
-       /* skew volume & cutoff */
-       awe_poke_dw(AWE_VTFT(30), 0x8000FFFF);
-       awe_poke_dw(AWE_VTFT(31), 0x8000FFFF);
-
-       voices[30].state = AWE_ST_FM;
-       voices[31].state = AWE_ST_FM;
-
-       /* change maximum channels to 30 */
-       awe_max_voices = AWE_NORMAL_VOICES;
-       if (playing_mode == AWE_PLAY_DIRECT)
-               awe_info.nr_voices = awe_max_voices;
-       else
-               awe_info.nr_voices = AWE_MAX_CHANNELS;
-       voice_alloc->max_voice = awe_max_voices;
-}
-
-/*
- *  AWE32 DRAM access routines
- */
-
-/* open DRAM write accessing mode */
-static int
-awe_open_dram_for_write(int offset, int channels)
-{
-       int vidx[AWE_NORMAL_VOICES];
-       int i;
-
-       if (channels < 0 || channels >= AWE_NORMAL_VOICES) {
-               channels = AWE_NORMAL_VOICES;
-               for (i = 0; i < AWE_NORMAL_VOICES; i++)
-                       vidx[i] = i;
-       } else {
-               for (i = 0; i < channels; i++) {
-                       vidx[i] = awe_clear_voice();
-                       voices[vidx[i]].state = AWE_ST_MARK;
-               }
-       }
-
-       /* use all channels for DMA transfer */
-       for (i = 0; i < channels; i++) {
-               if (vidx[i] < 0) continue;
-               awe_poke(AWE_DCYSUSV(vidx[i]), 0x80);
-               awe_poke_dw(AWE_VTFT(vidx[i]), 0);
-               awe_poke_dw(AWE_CVCF(vidx[i]), 0);
-               awe_poke_dw(AWE_PTRX(vidx[i]), 0x40000000);
-               awe_poke_dw(AWE_CPF(vidx[i]), 0x40000000);
-               awe_poke_dw(AWE_PSST(vidx[i]), 0);
-               awe_poke_dw(AWE_CSL(vidx[i]), 0);
-               awe_poke_dw(AWE_CCCA(vidx[i]), 0x06000000);
-               voices[vidx[i]].state = AWE_ST_DRAM;
-       }
-       /* point channels 31 & 32 to ROM samples for DRAM refresh */
-       awe_poke_dw(AWE_VTFT(30), 0);
-       awe_poke_dw(AWE_PSST(30), 0x1d8);
-       awe_poke_dw(AWE_CSL(30), 0x1e0);
-       awe_poke_dw(AWE_CCCA(30), 0x1d8);
-       awe_poke_dw(AWE_VTFT(31), 0);
-       awe_poke_dw(AWE_PSST(31), 0x1d8);
-       awe_poke_dw(AWE_CSL(31), 0x1e0);
-       awe_poke_dw(AWE_CCCA(31), 0x1d8);
-       voices[30].state = AWE_ST_FM;
-       voices[31].state = AWE_ST_FM;
-
-       /* if full bit is on, not ready to write on */
-       if (awe_peek_dw(AWE_SMALW) & 0x80000000) {
-               for (i = 0; i < channels; i++) {
-                       awe_poke_dw(AWE_CCCA(vidx[i]), 0);
-                       voices[vidx[i]].state = AWE_ST_OFF;
-               }
-               return RET_ERROR(ENOSPC);
-       }
-
-       /* set address to write */
-       awe_poke_dw(AWE_SMALW, offset);
-
-       return 0;
-}
-
-/* open DRAM for RAM size detection */
-static void
-awe_open_dram_for_check(void)
-{
-       int i;
-       for (i = 0; i < AWE_NORMAL_VOICES; i++) {
-               awe_poke(AWE_DCYSUSV(i), 0x80);
-               awe_poke_dw(AWE_VTFT(i), 0);
-               awe_poke_dw(AWE_CVCF(i), 0);
-               awe_poke_dw(AWE_PTRX(i), 0x40000000);
-               awe_poke_dw(AWE_CPF(i), 0x40000000);
-               awe_poke_dw(AWE_PSST(i), 0);
-               awe_poke_dw(AWE_CSL(i), 0);
-               if (i & 1) /* DMA write */
-                       awe_poke_dw(AWE_CCCA(i), 0x06000000);
-               else       /* DMA read */
-                       awe_poke_dw(AWE_CCCA(i), 0x04000000);
-               voices[i].state = AWE_ST_DRAM;
-       }
-}
-
-
-/* close dram access */
-static void
-awe_close_dram(void)
-{
-       int i;
-       /* wait until FULL bit in SMAxW register be false */
-       for (i = 0; i < 10000; i++) {
-               if (!(awe_peek_dw(AWE_SMALW) & 0x80000000))
-                       break;
-               awe_wait(10);
-       }
-
-       for (i = 0; i < AWE_NORMAL_VOICES; i++) {
-               if (voices[i].state == AWE_ST_DRAM) {
-                       awe_poke_dw(AWE_CCCA(i), 0);
-                       awe_poke(AWE_DCYSUSV(i), 0x807F);
-                       voices[i].state = AWE_ST_OFF;
-               }
-       }
-}
-
-
-/*================================================================
- * detect presence of AWE32 and check memory size
- *================================================================*/
-
-/* detect emu8000 chip on the specified address; from VV's guide */
-
-static int
-awe_detect_base(int addr)
-{
-       setup_ports(addr, 0, 0);
-       if ((awe_peek(AWE_U1) & 0x000F) != 0x000C)
-               return 0;
-       if ((awe_peek(AWE_HWCF1) & 0x007E) != 0x0058)
-               return 0;
-       if ((awe_peek(AWE_HWCF2) & 0x0003) != 0x0003)
-               return 0;
-        DEBUG(0,printk("AWE32 found at %x\n", addr));
-       return 1;
-}
-       
-static int
-awe_detect(void)
-{
-       int base;
-
-       if (port_setuped) /* already initialized by PnP */
-               return 1;
-
-       if (awe_port) /* use default i/o port value */
-               setup_ports(awe_port, 0, 0);
-       else { /* probe it */
-               for (base = 0x620; base <= 0x680; base += 0x20)
-                       if (awe_detect_base(base))
-                               return 1;
-               DEBUG(0,printk("AWE32 not found\n"));
-               return 0;
-       }
-
-       return 1;
-}
-
-
-/*================================================================
- * check dram size on AWE board
- *================================================================*/
-
-/* any three numbers you like */
-#define UNIQUE_ID1     0x1234
-#define UNIQUE_ID2     0x4321
-#define UNIQUE_ID3     0xFFFF
-
-static void
-awe_check_dram(void)
-{
-       if (awe_present) /* already initialized */
-               return;
-
-       if (awe_mem_size >= 0) { /* given by config file or module option */
-               awe_mem_size *= 1024; /* convert to Kbytes */
-               return;
-       }
-
-       awe_open_dram_for_check();
-
-       awe_mem_size = 0;
-
-       /* set up unique two id numbers */
-       awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET);
-       awe_poke(AWE_SMLD, UNIQUE_ID1);
-       awe_poke(AWE_SMLD, UNIQUE_ID2);
-
-       while (awe_mem_size < AWE_MAX_DRAM_SIZE) {
-               awe_wait(5);
-               /* read a data on the DRAM start address */
-               awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET);
-               awe_peek(AWE_SMLD); /* discard stale data  */
-               if (awe_peek(AWE_SMLD) != UNIQUE_ID1)
-                       break;
-               if (awe_peek(AWE_SMLD) != UNIQUE_ID2)
-                       break;
-               awe_mem_size += 512;  /* increment 512kbytes */
-               /* Write a unique data on the test address;
-                * if the address is out of range, the data is written on
-                * 0x200000(=AWE_DRAM_OFFSET).  Then the two id words are
-                * broken by this data.
-                */
-               awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + awe_mem_size*512L);
-               awe_poke(AWE_SMLD, UNIQUE_ID3);
-               awe_wait(5);
-               /* read a data on the just written DRAM address */
-               awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + awe_mem_size*512L);
-               awe_peek(AWE_SMLD); /* discard stale data  */
-               if (awe_peek(AWE_SMLD) != UNIQUE_ID3)
-                       break;
-       }
-       awe_close_dram();
-
-       DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", awe_mem_size));
-
-       /* convert to Kbytes */
-       awe_mem_size *= 1024;
-}
-
-
-/*================================================================
- * chorus and reverb controls; from VV's guide
- *================================================================*/
-
-/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
-static char chorus_defined[AWE_CHORUS_NUMBERS];
-static awe_chorus_fx_rec chorus_parm[AWE_CHORUS_NUMBERS] = {
-       {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
-       {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
-       {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
-       {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
-       {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
-       {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
-       {0xE600, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay */
-       {0xE6C0, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay + feedback */
-};
-
-static int
-awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count)
-{
-       if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) {
-               printk("AWE32 Error: illegal chorus mode %d for uploading\n", patch->optarg);
-               return RET_ERROR(EINVAL);
-       }
-       if (count < sizeof(awe_chorus_fx_rec)) {
-               printk("AWE32 Error: too short chorus fx parameters\n");
-               return RET_ERROR(EINVAL);
-       }
-       COPY_FROM_USER(&chorus_parm[patch->optarg], addr, AWE_PATCH_INFO_SIZE,
-                      sizeof(awe_chorus_fx_rec));
-       chorus_defined[patch->optarg] = TRUE;
-       return 0;
-}
-
-static void
-awe_set_chorus_mode(int effect)
-{
-       if (effect < 0 || effect >= AWE_CHORUS_NUMBERS ||
-           (effect >= AWE_CHORUS_PREDEFINED && !chorus_defined[effect]))
-               return;
-       awe_poke(AWE_INIT3(9), chorus_parm[effect].feedback);
-       awe_poke(AWE_INIT3(12), chorus_parm[effect].delay_offset);
-       awe_poke(AWE_INIT4(3), chorus_parm[effect].lfo_depth);
-       awe_poke_dw(AWE_HWCF4, chorus_parm[effect].delay);
-       awe_poke_dw(AWE_HWCF5, chorus_parm[effect].lfo_freq);
-       awe_poke_dw(AWE_HWCF6, 0x8000);
-       awe_poke_dw(AWE_HWCF7, 0x0000);
-}
-
-static void
-awe_update_chorus_mode(void)
-{
-       awe_set_chorus_mode(ctrls[AWE_MD_CHORUS_MODE]);
-}
-
-/*----------------------------------------------------------------*/
-
-/* reverb mode settings; write the following 28 data of 16 bit length
- *   on the corresponding ports in the reverb_cmds array
- */
-static char reverb_defined[AWE_CHORUS_NUMBERS];
-static awe_reverb_fx_rec reverb_parm[AWE_REVERB_NUMBERS] = {
-{{  /* room 1 */
-       0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
-       0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
-       0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
-       0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{  /* room 2 */
-       0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
-       0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
-       0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
-       0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{  /* room 3 */
-       0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
-       0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
-       0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
-       0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
-}},
-{{  /* hall 1 */
-       0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
-       0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
-       0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
-       0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
-}},
-{{  /* hall 2 */
-       0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
-       0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
-       0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
-       0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{  /* plate */
-       0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
-       0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
-       0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
-       0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{  /* delay */
-       0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
-       0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
-       0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
-       0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
-}},
-{{  /* panning delay */
-       0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
-       0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
-       0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
-       0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
-}},
-};
-
-static struct ReverbCmdPair {
-       unsigned short cmd, port;
-} reverb_cmds[28] = {
-  {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
-  {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
-  {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
-  {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
-  {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
-  {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
-  {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
-};
-
-static int
-awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count)
-{
-       if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) {
-               printk("AWE32 Error: illegal reverb mode %d for uploading\n", patch->optarg);
-               return RET_ERROR(EINVAL);
-       }
-       if (count < sizeof(awe_reverb_fx_rec)) {
-               printk("AWE32 Error: too short reverb fx parameters\n");
-               return RET_ERROR(EINVAL);
-       }
-       COPY_FROM_USER(&reverb_parm[patch->optarg], addr, AWE_PATCH_INFO_SIZE,
-                      sizeof(awe_reverb_fx_rec));
-       reverb_defined[patch->optarg] = TRUE;
-       return 0;
-}
-
-static void
-awe_set_reverb_mode(int effect)
-{
-       int i;
-       if (effect < 0 || effect >= AWE_REVERB_NUMBERS ||
-           (effect >= AWE_REVERB_PREDEFINED && !reverb_defined[effect]))
-               return;
-       for (i = 0; i < 28; i++)
-               awe_poke(reverb_cmds[i].cmd, reverb_cmds[i].port,
-                        reverb_parm[effect].parms[i]);
-}
-
-static void
-awe_update_reverb_mode(void)
-{
-       awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]);
-}
-
-/*================================================================
- * treble/bass equalizer control
- *================================================================*/
-
-static unsigned short bass_parm[12][3] = {
-       {0xD26A, 0xD36A, 0x0000}, /* -12 dB */
-       {0xD25B, 0xD35B, 0x0000}, /*  -8 */
-       {0xD24C, 0xD34C, 0x0000}, /*  -6 */
-       {0xD23D, 0xD33D, 0x0000}, /*  -4 */
-       {0xD21F, 0xD31F, 0x0000}, /*  -2 */
-       {0xC208, 0xC308, 0x0001}, /*   0 (HW default) */
-       {0xC219, 0xC319, 0x0001}, /*  +2 */
-       {0xC22A, 0xC32A, 0x0001}, /*  +4 */
-       {0xC24C, 0xC34C, 0x0001}, /*  +6 */
-       {0xC26E, 0xC36E, 0x0001}, /*  +8 */
-       {0xC248, 0xC348, 0x0002}, /* +10 */
-       {0xC26A, 0xC36A, 0x0002}, /* +12 dB */
-};
-
-static unsigned short treble_parm[12][9] = {
-       {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
-       {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
-       {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
-       {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
-       {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
-       {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
-       {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
-       {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
-       {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
-       {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
-       {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
-       {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +12 dB */
-};
-
-
-/*
- * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
- */
-static void
-awe_equalizer(int bass, int treble)
-{
-       unsigned short w;
-
-       if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
-               return;
-       awe_poke(AWE_INIT4(0x01), bass_parm[bass][0]);
-       awe_poke(AWE_INIT4(0x11), bass_parm[bass][1]);
-       awe_poke(AWE_INIT3(0x11), treble_parm[treble][0]);
-       awe_poke(AWE_INIT3(0x13), treble_parm[treble][1]);
-       awe_poke(AWE_INIT3(0x1B), treble_parm[treble][2]);
-       awe_poke(AWE_INIT4(0x07), treble_parm[treble][3]);
-       awe_poke(AWE_INIT4(0x0B), treble_parm[treble][4]);
-       awe_poke(AWE_INIT4(0x0D), treble_parm[treble][5]);
-       awe_poke(AWE_INIT4(0x17), treble_parm[treble][6]);
-       awe_poke(AWE_INIT4(0x19), treble_parm[treble][7]);
-       w = bass_parm[bass][2] + treble_parm[treble][8];
-       awe_poke(AWE_INIT4(0x15), (unsigned short)(w + 0x0262));
-       awe_poke(AWE_INIT4(0x1D), (unsigned short)(w + 0x8362));
-}
-
-static void awe_update_equalizer(void)
-{
-       awe_equalizer(ctrls[AWE_MD_BASS_LEVEL], ctrls[AWE_MD_TREBLE_LEVEL]);
-}
-
-
-#ifdef CONFIG_AWE32_MIDIEMU
-
-/*================================================================
- * Emu8000 MIDI Emulation
- *================================================================*/
-
-/*================================================================
- * midi queue record
- *================================================================*/
-
-/* queue type */
-enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, };
-
-#define MAX_MIDIBUF    64
-
-/* midi status */
-typedef struct MidiStatus {
-       int queue;      /* queue type */
-       int qlen;       /* queue length */
-       int read;       /* chars read */
-       int status;     /* current status */
-       int chan;       /* current channel */
-       unsigned char buf[MAX_MIDIBUF];
-} MidiStatus;
-
-/* MIDI mode type */
-enum { MODE_GM, MODE_GS, MODE_XG, };
-
-/* NRPN / CC -> Emu8000 parameter converter */
-typedef struct {
-       int control;
-       int awe_effect;
-       unsigned short (*convert)(int val);
-} ConvTable;
-
-
-/*================================================================
- * prototypes
- *================================================================*/
-
-static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int));
-static void awe_midi_close(int dev);
-static int awe_midi_ioctl(int dev, unsigned cmd, caddr_t arg);
-static int awe_midi_outputc(int dev, unsigned char midi_byte);
-
-static void init_midi_status(MidiStatus *st);
-static void clear_rpn(void);
-static void get_midi_char(MidiStatus *st, int c);
-/*static void queue_varlen(MidiStatus *st, int c);*/
-static void special_event(MidiStatus *st, int c);
-static void queue_read(MidiStatus *st, int c);
-static void midi_note_on(MidiStatus *st);
-static void midi_note_off(MidiStatus *st);
-static void midi_key_pressure(MidiStatus *st);
-static void midi_channel_pressure(MidiStatus *st);
-static void midi_pitch_wheel(MidiStatus *st);
-static void midi_program_change(MidiStatus *st);
-static void midi_control_change(MidiStatus *st);
-static void midi_select_bank(MidiStatus *st, int val);
-static void midi_nrpn_event(MidiStatus *st);
-static void midi_rpn_event(MidiStatus *st);
-static void midi_detune(int chan, int coarse, int fine);
-static void midi_system_exclusive(MidiStatus *st);
-static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
-static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
-static int xg_control_change(MidiStatus *st, int cmd, int val);
-
-#define numberof(ary)  (sizeof(ary)/sizeof(ary[0]))
-
-
-/*================================================================
- * OSS Midi device record
- *================================================================*/
-
-static struct midi_operations awe_midi_operations =
-{
-       {"AWE Midi Emu", 0, 0, SNDCARD_SB},
-       NULL /*&std_midi_synth*/,
-       {0}, /* input_info */
-       awe_midi_open, /*open*/
-       awe_midi_close, /*close*/
-       awe_midi_ioctl, /*ioctl*/
-       awe_midi_outputc, /*outputc*/
-       NULL /*start_read*/,
-       NULL /*end_read*/,
-       NULL, /* kick */
-       NULL, /* command */
-};
-
-static int my_mididev = -1;
-
-static void attach_midiemu(void)
-{
-       if ((my_mididev = sound_alloc_mididev()) < 0)
-               printk ("Sound: Too many midi devices detected\n");
-       else
-               midi_devs[my_mididev] = &awe_midi_operations;
-}
-
-static void unload_midiemu(void)
-{
-       if (my_mididev >= 0)
-               sound_unload_mididev(my_mididev);
-}
-
-
-/*================================================================
- * open/close midi device
- *================================================================*/
-
-static int midi_opened = FALSE;
-
-static int midi_mode;
-static int coarsetune = 0, finetune = 0;
-
-static int xg_mapping = TRUE;
-static int xg_bankmode = 0;
-
-/* effect sensitivity */
-
-#define FX_CUTOFF      0
-#define FX_RESONANCE   1
-#define FX_ATTACK      2
-#define FX_RELEASE     3
-#define FX_VIBRATE     4
-#define FX_VIBDEPTH    5
-#define FX_VIBDELAY    6
-#define FX_NUMS                7
-
-#define DEF_FX_CUTOFF          170
-#define DEF_FX_RESONANCE       6
-#define DEF_FX_ATTACK          50
-#define DEF_FX_RELEASE         50
-#define DEF_FX_VIBRATE         30
-#define DEF_FX_VIBDEPTH                4
-#define DEF_FX_VIBDELAY                1500
-
-/* effect sense: */
-static int gs_sense[] = 
-{
-       DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
-       DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
-};
-static int xg_sense[] = 
-{
-       DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
-       DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
-};
-
-
-/* current status */
-static MidiStatus curst;
-
-
-static int
-awe_midi_open (int dev, int mode,
-              void (*input)(int,unsigned char),
-              void (*output)(int))
-{
-       if (midi_opened)
-               return -EBUSY;
-
-       midi_opened = TRUE;
-
-       midi_mode = MODE_GM;
-
-       curst.queue = Q_NONE;
-       curst.qlen = 0;
-       curst.read = 0;
-       curst.status = 0;
-       curst.chan = 0;
-       BZERO(curst.buf, sizeof(curst.buf));
-
-       init_midi_status(&curst);
-
-       return 0;
-}
-
-static void
-awe_midi_close (int dev)
-{
-       midi_opened = FALSE;
-}
-
-
-static int
-awe_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
-{
-       return -EPERM;
-}
-
-static int
-awe_midi_outputc (int dev, unsigned char midi_byte)
-{
-       if (! midi_opened)
-               return 1;
-
-       /* force to change playing mode */
-       playing_mode = AWE_PLAY_MULTI;
-
-       get_midi_char(&curst, midi_byte);
-       return 1;
-}
-
-
-/*================================================================
- * initialize
- *================================================================*/
-
-static void init_midi_status(MidiStatus *st)
-{
-       clear_rpn();
-       coarsetune = 0;
-       finetune = 0;
-}
-
-
-/*================================================================
- * RPN & NRPN
- *================================================================*/
-
-#define MAX_MIDI_CHANNELS      16
-
-/* RPN & NRPN */
-static unsigned char nrpn[MAX_MIDI_CHANNELS];  /* current event is NRPN? */
-static int msb_bit;  /* current event is msb for RPN/NRPN */
-/* RPN & NRPN indeces */
-static unsigned char rpn_msb[MAX_MIDI_CHANNELS], rpn_lsb[MAX_MIDI_CHANNELS];
-/* RPN & NRPN values */
-static int rpn_val[MAX_MIDI_CHANNELS];
-
-static void clear_rpn(void)
-{
-       int i;
-       for (i = 0; i < MAX_MIDI_CHANNELS; i++) {
-               nrpn[i] = 0;
-               rpn_msb[i] = 127;
-               rpn_lsb[i] = 127;
-               rpn_val[i] = 0;
-       }
-       msb_bit = 0;
-}
-
-
-/*================================================================
- * process midi queue
- *================================================================*/
-
-/* status event types */
-typedef void (*StatusEvent)(MidiStatus *st);
-static struct StatusEventList {
-       StatusEvent process;
-       int qlen;
-} status_event[8] = {
-       {midi_note_off, 2},
-       {midi_note_on, 2},
-       {midi_key_pressure, 2},
-       {midi_control_change, 2},
-       {midi_program_change, 1},
-       {midi_channel_pressure, 1},
-       {midi_pitch_wheel, 2},
-       {NULL, 0},
-};
-
-
-/* read a char from fifo and process it */
-static void get_midi_char(MidiStatus *st, int c)
-{
-       if (c == 0xfe) {
-               /* ignore active sense */
-               st->queue = Q_NONE;
-               return;
-       }
-
-       switch (st->queue) {
-       /* case Q_VARLEN: queue_varlen(st, c); break;*/
-       case Q_READ:
-       case Q_SYSEX:
-               queue_read(st, c);
-               break;
-       case Q_NONE:
-               st->read = 0;
-               if ((c & 0xf0) == 0xf0) {
-                       special_event(st, c);
-               } else if (c & 0x80) { /* status change */
-                       st->status = (c >> 4) & 0x07;
-                       st->chan = c & 0x0f;
-                       st->queue = Q_READ;
-                       st->qlen = status_event[st->status].qlen;
-                       if (st->qlen == 0)
-                               st->queue = Q_NONE;
-               }
-               break;
-       }
-}
-
-/* 0xfx events */
-static void special_event(MidiStatus *st, int c)
-{
-       switch (c) {
-       case 0xf0: /* system exclusive */
-               st->queue = Q_SYSEX;
-               st->qlen = 0;
-               break;
-       case 0xf1: /* MTC quarter frame */
-       case 0xf3: /* song select */
-               st->queue = Q_READ;
-               st->qlen = 1;
-               break;
-       case 0xf2: /* song position */
-               st->queue = Q_READ;
-               st->qlen = 2;
-               break;
-       }
-}
-
-#if 0
-/* read variable length value */
-static void queue_varlen(MidiStatus *st, int c)
-{
-       st->qlen += (c & 0x7f);
-       if (c & 0x80) {
-               st->qlen <<= 7;
-               return;
-       }
-       if (st->qlen <= 0) {
-               st->qlen = 0;
-               st->queue = Q_NONE;
-       }
-       st->queue = Q_READ;
-       st->read = 0;
-}
-#endif
-
-
-/* read a char */
-static void queue_read(MidiStatus *st, int c)
-{
-       if (st->read < MAX_MIDIBUF) {
-               if (st->queue != Q_SYSEX)
-                       c &= 0x7f;
-               st->buf[st->read] = (unsigned char)c;
-       }
-       st->read++;
-       if (st->queue == Q_SYSEX && c == 0xf7) {
-               midi_system_exclusive(st);
-               st->queue = Q_NONE;
-       } else if (st->queue == Q_READ && st->read >= st->qlen) {
-               if (status_event[st->status].process)
-                       status_event[st->status].process(st);
-               st->queue = Q_NONE;
-       }
-}
-
-
-/*================================================================
- * status events
- *================================================================*/
-
-/* note on */
-static void midi_note_on(MidiStatus *st)
-{
-       DEBUG(2,printk("midi: note_on (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
-       if (st->buf[1] == 0)
-               midi_note_off(st);
-       else
-               awe_start_note(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* note off */
-static void midi_note_off(MidiStatus *st)
-{
-       DEBUG(2,printk("midi: note_off (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
-       awe_kill_note(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* key pressure change */
-static void midi_key_pressure(MidiStatus *st)
-{
-       awe_key_pressure(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* channel pressure change */
-static void midi_channel_pressure(MidiStatus *st)
-{
-       channels[st->chan].chan_press = st->buf[0];
-       awe_modwheel_change(st->chan, st->buf[0]);
-}
-
-/* pitch wheel change */
-static void midi_pitch_wheel(MidiStatus *st)
-{
-       int val = (int)st->buf[1] * 128 + st->buf[0];
-       awe_bender(0, st->chan, val);
-}
-
-/* program change */
-static void midi_program_change(MidiStatus *st)
-{
-       int preset;
-       preset = st->buf[0];
-       if (midi_mode == MODE_GS && IS_DRUM_CHANNEL(st->chan) && preset == 127)
-               preset = 0;
-       else if (midi_mode == MODE_XG && xg_mapping && IS_DRUM_CHANNEL(st->chan))
-               preset += 64;
-
-       awe_set_instr(0, st->chan, preset);
-}
-
-#define send_effect(chan,type,val) awe_send_effect(chan,-1,type,val)
-#define add_effect(chan,type,val) awe_send_effect(chan,-1,(type)|0x80,val)
-#define unset_effect(chan,type) awe_send_effect(chan,-1,(type)|0x40,0)
-
-/* midi control change */
-static void midi_control_change(MidiStatus *st)
-{
-       int cmd = st->buf[0];
-       int val = st->buf[1];
-
-       DEBUG(2,printk("midi: control (%d) %d %d\n", st->chan, cmd, val));
-       if (midi_mode == MODE_XG) {
-               if (xg_control_change(st, cmd, val))
-                       return;
-       }
-
-       /* controls #31 - #64 are LSB of #0 - #31 */
-       msb_bit = 1;
-       if (cmd >= 0x20 && cmd < 0x40) {
-               msb_bit = 0;
-               cmd -= 0x20;
-       }
-
-       switch (cmd) {
-       case CTL_SOFT_PEDAL:
-               if (val == 127)
-                       add_effect(st->chan, AWE_FX_CUTOFF, -160);
-               else
-                       unset_effect(st->chan, AWE_FX_CUTOFF);
-               break;
-
-       case CTL_BANK_SELECT:
-               midi_select_bank(st, val);
-               break;
-               
-       /* set RPN/NRPN parameter */
-       case CTL_REGIST_PARM_NUM_MSB:
-               nrpn[st->chan]=0; rpn_msb[st->chan]=val;
-               break;
-       case CTL_REGIST_PARM_NUM_LSB:
-               nrpn[st->chan]=0; rpn_lsb[st->chan]=val;
-               break;
-       case CTL_NONREG_PARM_NUM_MSB:
-               nrpn[st->chan]=1; rpn_msb[st->chan]=val;
-               break;
-       case CTL_NONREG_PARM_NUM_LSB:
-               nrpn[st->chan]=1; rpn_lsb[st->chan]=val;
-               break;
-
-       /* send RPN/NRPN entry */
-       case CTL_DATA_ENTRY:
-               if (msb_bit)
-                       rpn_val[st->chan] = val * 128;
-               else
-                       rpn_val[st->chan] |= val;
-               if (nrpn[st->chan])
-                       midi_nrpn_event(st);
-               else
-                       midi_rpn_event(st);
-               break;
-
-       /* increase/decrease data entry */
-       case CTL_DATA_INCREMENT:
-               rpn_val[st->chan]++;
-               midi_rpn_event(st);
-               break;
-       case CTL_DATA_DECREMENT:
-               rpn_val[st->chan]--;
-               midi_rpn_event(st);
-               break;
-
-       /* default */
-       default:
-               awe_controller(0, st->chan, cmd, val);
-               break;
-       }
-}
-
-/* tone bank change */
-static void midi_select_bank(MidiStatus *st, int val)
-{
-       if (midi_mode == MODE_XG && msb_bit) {
-               xg_bankmode = val;
-               /* XG MSB value; not normal bank selection */
-               switch (val) {
-               case 127: /* remap to drum channel */
-                       awe_controller(0, st->chan, CTL_BANK_SELECT, 128);
-                       break;
-               default: /* remap to normal channel */
-                       awe_controller(0, st->chan, CTL_BANK_SELECT, val);
-                       break;
-               }
-               return;
-       } else if (midi_mode == MODE_GS && !msb_bit)
-               /* ignore LSB bank in GS mode (used for mapping) */
-               return;
-
-       /* normal bank controls; accept both MSB and LSB */
-       if (! IS_DRUM_CHANNEL(st->chan)) {
-               if (midi_mode == MODE_XG) {
-                       if (xg_bankmode) return;
-                       if (val == 64 || val == 126)
-                               val = 0;
-               } else if (midi_mode == MODE_GS && val == 127)
-                       val = 0;
-               awe_controller(0, st->chan, CTL_BANK_SELECT, val);
-       }
-}
-
-
-/*================================================================
- * RPN events
- *================================================================*/
-
-static void midi_rpn_event(MidiStatus *st)
-{
-       int type;
-       type = (rpn_msb[st->chan]<<8) | rpn_lsb[st->chan];
-       switch (type) {
-       case 0x0000: /* Pitch bend sensitivity */
-               /* MSB only / 1 semitone per 128 */
-               if (msb_bit) {
-                       channels[st->chan].bender_range = 
-                               rpn_val[st->chan] * 100 / 128;
-               }
-               break;
-                                       
-       case 0x0001: /* fine tuning: */
-               /* MSB/LSB, 8192=center, 100/8192 cent step */
-               finetune = rpn_val[st->chan] - 8192;
-               midi_detune(st->chan, coarsetune, finetune);
-               break;
-
-       case 0x0002: /* coarse tuning */
-               /* MSB only / 8192=center, 1 semitone per 128 */
-               if (msb_bit) {
-                       coarsetune = rpn_val[st->chan] - 8192;
-                       midi_detune(st->chan, coarsetune, finetune);
-               }
-               break;
-
-       case 0x7F7F: /* "lock-in" RPN */
-               break;
-       }
-}
-
-
-/* tuning:
- *   coarse = -8192 to 8192 (100 cent per 128)
- *   fine = -8192 to 8192 (max=100cent)
- */
-static void midi_detune(int chan, int coarse, int fine)
-{
-       /* 4096 = 1200 cents in AWE parameter */
-       int val;
-       val = coarse * 4096 / (12 * 128);
-       val += fine / 24;
-       if (val)
-               send_effect(chan, AWE_FX_INIT_PITCH, val);
-       else
-               unset_effect(chan, AWE_FX_INIT_PITCH);
-}
-
-
-/*================================================================
- * system exclusive message
- * GM/GS/XG macros are accepted
- *================================================================*/
-
-static void midi_system_exclusive(MidiStatus *st)
-{
-       /* GM on */
-       static unsigned char gm_on_macro[] = {
-               0x7e,0x7f,0x09,0x01,
-       };
-       /* XG on */
-       static unsigned char xg_on_macro[] = {
-               0x43,0x10,0x4c,0x00,0x00,0x7e,0x00,
-       };
-       /* GS prefix
-        * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off
-        * reverb mode: XX=0x01, YY=0x30, ZZ=0-7
-        * chorus mode: XX=0x01, YY=0x38, ZZ=0-7
-        */
-       static unsigned char gs_pfx_macro[] = {
-               0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/
-       };
-
-#if 0
-       /* SC88 system mode set
-        * single module mode: XX=1
-        * double module mode: XX=0
-        */
-       static unsigned char gs_mode_macro[] = {
-               0x41,0x10,0x42,0x12,0x00,0x00,0x7F,/*ZZ*/
-       };
-       /* SC88 display macro: XX=01:bitmap, 00:text
-        */
-       static unsigned char gs_disp_macro[] = {
-               0x41,0x10,0x45,0x12,0x10,/*XX,00*/
-       };
-#endif
-
-       /* GM on */
-       if (MEMCMP(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) {
-               if (midi_mode != MODE_GS && midi_mode != MODE_XG)
-                       midi_mode = MODE_GM;
-               init_midi_status(st);
-       }
-
-       /* GS macros */
-       else if (MEMCMP(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) {
-               if (midi_mode != MODE_GS && midi_mode != MODE_XG)
-                       midi_mode = MODE_GS;
-
-               if (st->buf[5] == 0x00 && st->buf[6] == 0x7f && st->buf[7] == 0x00) {
-                       /* GS reset */
-                       init_midi_status(st);
-               }
-
-               else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x15) {
-                       /* drum pattern */
-                       int p = st->buf[5] & 0x0f;
-                       if (p == 0) p = 9;
-                       else if (p < 10) p--;
-                       if (st->buf[7] == 0)
-                               DRUM_CHANNEL_OFF(p);
-                       else
-                               DRUM_CHANNEL_ON(p);
-
-               } else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x21) {
-                       /* program */
-                       int p = st->buf[5] & 0x0f;
-                       if (p == 0) p = 9;
-                       else if (p < 10) p--;
-                       if (! IS_DRUM_CHANNEL(p))
-                               awe_set_instr(0, p, st->buf[7]);
-
-               } else if (st->buf[5] == 0x01 && st->buf[6] == 0x30) {
-                       /* reverb mode */
-                       awe_set_reverb_mode(st->buf[7]);
-
-               } else if (st->buf[5] == 0x01 && st->buf[6] == 0x38) {
-                       /* chorus mode */
-                       awe_set_chorus_mode(st->buf[7]);
-
-               } else if (st->buf[5] == 0x00 && st->buf[6] == 0x04) {
-                       /* master volume */
-                       awe_change_master_volume(st->buf[7]);
-
-               }
-       }
-
-       /* XG on */
-       else if (MEMCMP(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) {
-               midi_mode = MODE_XG;
-               xg_mapping = TRUE;
-               xg_bankmode = 0;
-       }
-}
-
-
-/*================================================================
- * convert NRPN/control values
- *================================================================*/
-
-static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
-{
-       int i, cval;
-       for (i = 0; i < num_tables; i++) {
-               if (table[i].control == type) {
-                       cval = table[i].convert(val);
-                       send_effect(st->chan, table[i].awe_effect, cval);
-                       return TRUE;
-               }
-       }
-       return FALSE;
-}
-
-static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
-{
-       int i, cval;
-       for (i = 0; i < num_tables; i++) {
-               if (table[i].control == type) {
-                       cval = table[i].convert(val);
-                       add_effect(st->chan, table[i].awe_effect|0x80, cval);
-                       return TRUE;
-               }
-       }
-       return FALSE;
-}
-
-
-/*----------------------------------------------------------------
- * AWE32 NRPN effects
- *----------------------------------------------------------------*/
-
-static unsigned short fx_delay(int val);
-static unsigned short fx_attack(int val);
-static unsigned short fx_hold(int val);
-static unsigned short fx_decay(int val);
-static unsigned short fx_the_value(int val);
-static unsigned short fx_twice_value(int val);
-static unsigned short fx_conv_pitch(int val);
-static unsigned short fx_conv_Q(int val);
-
-/* function for each NRPN */           /* [range]  units */
-#define fx_env1_delay  fx_delay        /* [0,5900] 4msec */
-#define fx_env1_attack fx_attack       /* [0,5940] 1msec */
-#define fx_env1_hold   fx_hold         /* [0,8191] 1msec */
-#define fx_env1_decay  fx_decay        /* [0,5940] 4msec */
-#define fx_env1_release        fx_decay        /* [0,5940] 4msec */
-#define fx_env1_sustain        fx_the_value    /* [0,127] 0.75dB */
-#define fx_env1_pitch  fx_the_value    /* [-127,127] 9.375cents */
-#define fx_env1_cutoff fx_the_value    /* [-127,127] 56.25cents */
-
-#define fx_env2_delay  fx_delay        /* [0,5900] 4msec */
-#define fx_env2_attack fx_attack       /* [0,5940] 1msec */
-#define fx_env2_hold   fx_hold         /* [0,8191] 1msec */
-#define fx_env2_decay  fx_decay        /* [0,5940] 4msec */
-#define fx_env2_release        fx_decay        /* [0,5940] 4msec */
-#define fx_env2_sustain        fx_the_value    /* [0,127] 0.75dB */
-
-#define fx_lfo1_delay  fx_delay        /* [0,5900] 4msec */
-#define fx_lfo1_freq   fx_twice_value  /* [0,127] 84mHz */
-#define fx_lfo1_volume fx_twice_value  /* [0,127] 0.1875dB */
-#define fx_lfo1_pitch  fx_the_value    /* [-127,127] 9.375cents */
-#define fx_lfo1_cutoff fx_twice_value  /* [-64,63] 56.25cents */
-
-#define fx_lfo2_delay  fx_delay        /* [0,5900] 4msec */
-#define fx_lfo2_freq   fx_twice_value  /* [0,127] 84mHz */
-#define fx_lfo2_pitch  fx_the_value    /* [-127,127] 9.375cents */
-
-#define fx_init_pitch  fx_conv_pitch   /* [-8192,8192] cents */
-#define fx_chorus      fx_the_value    /* [0,255] -- */
-#define fx_reverb      fx_the_value    /* [0,255] -- */
-#define fx_cutoff      fx_twice_value  /* [0,127] 62Hz */
-#define fx_filterQ     fx_conv_Q       /* [0,127] -- */
-
-static unsigned short fx_delay(int val)
-{
-       return (unsigned short)calc_parm_delay(val);
-}
-
-static unsigned short fx_attack(int val)
-{
-       return (unsigned short)calc_parm_attack(val);
-}
-
-static unsigned short fx_hold(int val)
-{
-       return (unsigned short)calc_parm_hold(val);
-}
-
-static unsigned short fx_decay(int val)
-{
-       return (unsigned short)calc_parm_decay(val);
-}
-
-static unsigned short fx_the_value(int val)
-{
-       return (unsigned short)(val & 0xff);
-}
-
-static unsigned short fx_twice_value(int val)
-{
-       return (unsigned short)((val * 2) & 0xff);
-}
-
-static unsigned short fx_conv_pitch(int val)
-{
-       return (short)(val * 4096 / 1200);
-}
-
-static unsigned short fx_conv_Q(int val)
-{
-       return (unsigned short)((val / 8) & 0xff);
-}
-
-
-static ConvTable awe_effects[] =
-{
-       { 0, AWE_FX_LFO1_DELAY, fx_lfo1_delay},
-       { 1, AWE_FX_LFO1_FREQ,  fx_lfo1_freq},
-       { 2, AWE_FX_LFO2_DELAY, fx_lfo2_delay},
-       { 3, AWE_FX_LFO2_FREQ,  fx_lfo2_freq},
-
-       { 4, AWE_FX_ENV1_DELAY, fx_env1_delay},
-       { 5, AWE_FX_ENV1_ATTACK,fx_env1_attack},
-       { 6, AWE_FX_ENV1_HOLD,  fx_env1_hold},
-       { 7, AWE_FX_ENV1_DECAY, fx_env1_decay},
-       { 8, AWE_FX_ENV1_SUSTAIN,       fx_env1_sustain},
-       { 9, AWE_FX_ENV1_RELEASE,       fx_env1_release},
-
-       {10, AWE_FX_ENV2_DELAY, fx_env2_delay},
-       {11, AWE_FX_ENV2_ATTACK,        fx_env2_attack},
-       {12, AWE_FX_ENV2_HOLD,  fx_env2_hold},
-       {13, AWE_FX_ENV2_DECAY, fx_env2_decay},
-       {14, AWE_FX_ENV2_SUSTAIN,       fx_env2_sustain},
-       {15, AWE_FX_ENV2_RELEASE,       fx_env2_release},
-
-       {16, AWE_FX_INIT_PITCH, fx_init_pitch},
-       {17, AWE_FX_LFO1_PITCH, fx_lfo1_pitch},
-       {18, AWE_FX_LFO2_PITCH, fx_lfo2_pitch},
-       {19, AWE_FX_ENV1_PITCH, fx_env1_pitch},
-       {20, AWE_FX_LFO1_VOLUME,        fx_lfo1_volume},
-       {21, AWE_FX_CUTOFF,             fx_cutoff},
-       {22, AWE_FX_FILTERQ,    fx_filterQ},
-       {23, AWE_FX_LFO1_CUTOFF,        fx_lfo1_cutoff},
-       {24, AWE_FX_ENV1_CUTOFF,        fx_env1_cutoff},
-       {25, AWE_FX_CHORUS,             fx_chorus},
-       {26, AWE_FX_REVERB,             fx_reverb},
-};
-
-static int num_awe_effects = numberof(awe_effects);
-
-
-/*----------------------------------------------------------------
- * GS(SC88) NRPN effects; still experimental
- *----------------------------------------------------------------*/
-
-/* cutoff: quarter semitone step, max=255 */
-static unsigned short gs_cutoff(int val)
-{
-       return (val - 64) * gs_sense[FX_CUTOFF] / 50;
-}
-
-/* resonance: 0 to 15(max) */
-static unsigned short gs_filterQ(int val)
-{
-       return (val - 64) * gs_sense[FX_RESONANCE] / 50;
-}
-
-/* attack: */
-static unsigned short gs_attack(int val)
-{
-       return -(val - 64) * gs_sense[FX_ATTACK] / 50;
-}
-
-/* decay: */
-static unsigned short gs_decay(int val)
-{
-       return -(val - 64) * gs_sense[FX_RELEASE] / 50;
-}
-
-/* release: */
-static unsigned short gs_release(int val)
-{
-       return -(val - 64) * gs_sense[FX_RELEASE] / 50;
-}
-
-/* vibrato freq: 0.042Hz step, max=255 */
-static unsigned short gs_vib_rate(int val)
-{
-       return (val - 64) * gs_sense[FX_VIBRATE] / 50;
-}
-
-/* vibrato depth: max=127, 1 octave */
-static unsigned short gs_vib_depth(int val)
-{
-       return (val - 64) * gs_sense[FX_VIBDEPTH] / 50;
-}
-
-/* vibrato delay: -0.725msec step */
-static unsigned short gs_vib_delay(int val)
-{
-       return -(val - 64) * gs_sense[FX_VIBDELAY] / 50;
-}
-
-static ConvTable gs_effects[] =
-{
-       {32, AWE_FX_CUTOFF,     gs_cutoff},
-       {33, AWE_FX_FILTERQ,    gs_filterQ},
-       {99, AWE_FX_ENV2_ATTACK, gs_attack},
-       {100, AWE_FX_ENV2_DECAY, gs_decay},
-       {102, AWE_FX_ENV2_RELEASE, gs_release},
-       {8, AWE_FX_LFO1_FREQ, gs_vib_rate},
-       {9, AWE_FX_LFO1_VOLUME, gs_vib_depth},
-       {10, AWE_FX_LFO1_DELAY, gs_vib_delay},
-};
-
-static int num_gs_effects = numberof(gs_effects);
-
-
-/*================================================================
- * NRPN events: accept as AWE32/SC88 specific controls
- *================================================================*/
-
-static void midi_nrpn_event(MidiStatus *st)
-{
-       if (rpn_msb[st->chan] == 127 && rpn_lsb[st->chan] <= 26) {
-               if (! msb_bit) /* both MSB/LSB necessary */
-                       send_converted_effect(awe_effects, num_awe_effects,
-                                             st, rpn_lsb[st->chan],
-                                             rpn_val[st->chan] - 8192);
-       } else if (rpn_msb[st->chan] == 1) {
-               if (msb_bit) /* only MSB is valid */
-                       add_converted_effect(gs_effects, num_gs_effects,
-                                            st, rpn_lsb[st->chan],
-                                            rpn_val[st->chan] / 128);
-       }
-}
-
-
-/*----------------------------------------------------------------
- * XG control effects; still experimental
- *----------------------------------------------------------------*/
-
-/* cutoff: quarter semitone step, max=255 */
-static unsigned short xg_cutoff(int val)
-{
-       return (val - 64) * xg_sense[FX_CUTOFF] / 64;
-}
-
-/* resonance: 0(open) to 15(most nasal) */
-static unsigned short xg_filterQ(int val)
-{
-       return (val - 64) * xg_sense[FX_RESONANCE] / 64;
-}
-
-/* attack: */
-static unsigned short xg_attack(int val)
-{
-       return -(val - 64) * xg_sense[FX_ATTACK] / 64;
-}
-
-/* release: */
-static unsigned short xg_release(int val)
-{
-       return -(val - 64) * xg_sense[FX_RELEASE] / 64;
-}
-
-static ConvTable xg_effects[] =
-{
-       {71, AWE_FX_CUTOFF,     xg_cutoff},
-       {74, AWE_FX_FILTERQ,    xg_filterQ},
-       {72, AWE_FX_ENV2_RELEASE, xg_release},
-       {73, AWE_FX_ENV2_ATTACK, xg_attack},
-};
-
-static int num_xg_effects = numberof(xg_effects);
-
-static int xg_control_change(MidiStatus *st, int cmd, int val)
-{
-       return add_converted_effect(xg_effects, num_xg_effects, st, cmd, val);
-}
-
-#endif /* CONFIG_AWE32_MIDIEMU */
-
-#endif /* CONFIG_AWE32_SYNTH */
diff --git a/drivers/sound/lowlevel/lowlevel.h b/drivers/sound/lowlevel/lowlevel.h
deleted file mode 100644 (file)
index bb0f6c7..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef LOWLEVEL_MODULE
-#define MODVERSIONS
-#include <linux/modversions.h>
-#include "manual_config.h"
-#endif
diff --git a/drivers/sound/lowlevel/miroaci.h b/drivers/sound/lowlevel/miroaci.h
deleted file mode 100644 (file)
index a8b7ff4..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <linux/config.h>
-#if defined(CONFIG_ACI_MIXER) || defined(CONFIG_ACI_MIXER_MODULE)
-extern int aci_implied_cmd(unsigned char opcode);
-extern int aci_write_cmd(unsigned char opcode, unsigned char parameter);
-extern int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2);
-extern int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter);
-extern int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter);
-#else
-
-#error Compiling a driver that needs the ACI-mixer but ACI-mixer support is not configured
-
-#endif
diff --git a/drivers/sound/lowlevel/soundlow.c b/drivers/sound/lowlevel/soundlow.c
deleted file mode 100644 (file)
index 96fdb94..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * lowlevel/init.c - Calls initialization code for configured drivers.
- */
-
-#include "lowlevel.h"
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include "../soundvers.h"
-
-#ifdef LOWLEVEL_MODULE
-char *lowlevel_version = SOUND_VERSION_STRING;
-#endif
-
-extern int attach_aci(void);
-extern void unload_aci(void);
-extern int attach_awe(void);
-extern void unload_awe(void);
-extern int init_aedsp16(void) __init;
-extern void uninit_aedsp16(void) __init;
-
-/*
- * There are two places where you can insert initialization calls of
- * low level drivers. sound_init_lowlevel_drivers() is called after
- * the sound driver has been initialized (the normal case)
- * while sound_preinit_lowlevel_drivers() is called before that.
- */
-void
-sound_preinit_lowlevel_drivers(void)
-{
-#if defined(CONFIG_AEDSP16) && !defined(MODULE)
-   init_aedsp16();
-#endif
-}
-
-void
-sound_init_lowlevel_drivers(void)
-{
-#ifdef CONFIG_ACI_MIXER
-   attach_aci();
-#endif
-
-#ifdef CONFIG_AWE32_SYNTH
-   attach_awe();
-#endif
-}
-
-void
-sound_unload_lowlevel_drivers(void)
-{
-#ifdef CONFIG_ACI_MIXER
-   unload_aci();
-#endif
-
-#ifdef CONFIG_AWE32_SYNTH
-   unload_awe();
-#endif
-
-#ifdef CONFIG_AEDSP16
-   uninit_aedsp16();
-#endif
-
-}
-
-EXPORT_SYMBOL(sound_init_lowlevel_drivers);
-EXPORT_SYMBOL(sound_unload_lowlevel_drivers);
-EXPORT_SYMBOL(sound_preinit_lowlevel_drivers);
index 7e3ecb1a103817d95f2cdab27959ed7c328d44bf..40804417c3cb1ba5726467f84a8d2a064d6d179d 100644 (file)
@@ -285,29 +285,8 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
        if((sb_dev = isapnp_find_dev(bus,
                ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
        {
-#ifdef CMI8330_DMA0BAD
-               int dmahack = 0;
-#endif
                sb_dev->prepare(sb_dev);
                
-               /*  This device doesn't work with DMA 0, so we must allocate
-                *  it to prevent PnP routines to assign it to the card.
-                *
-                *  I know i could have inlined the following lines, but it's cleaner
-                *  this way.
-                */
-       
-#ifdef CMI8330_DMA0BAD
-               if(sb_dev->dma_resource[0].start == 0)
-               {
-                       if(!request_dma(0, "cmi8330 dma hack"))
-                       {
-                               /* DMA was free, we now have it */
-                               dmahack = 1;
-                       }
-               }
-#endif
-
                if((sb_dev = activate_dev("CMI8330", "sb", sb_dev)))
                {
                        hw_config->io_base      = sb_dev->resource[0].start;
@@ -318,9 +297,6 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
                        show_base("CMI8330", "sb", &sb_dev->resource[0]);
                }
 
-#ifdef CMI8330_DMA0BAD
-               if(dmahack) free_dma(0);
-#endif
                if(!sb_dev) return(NULL);
        }
        else
index ffb1204addf182337d32c678faab2fa3aa33def7..25318c1acade2eb7e04cb7e9f68ad5d438bdbba4 100644 (file)
@@ -21,9 +21,6 @@
  *
  */
 
-/* FIXME: *grr* why can't the f**in Makefile do this for me ? */
-#define EXPORT_SYMTAB
-
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
index 7053d56d746d2142ddb72af2569142ff25c28ab2..2c8c041d5cc2651805142d779aa8250d4a94244c 100644 (file)
@@ -449,19 +449,15 @@ static void usbdevfs_put_super(struct super_block *sb)
         MOD_DEC_USE_COUNT;
 }
 
-static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf)
 {
-        struct statfs tmp;
-
-        tmp.f_type = USBDEVICE_SUPER_MAGIC;
-        tmp.f_bsize = PAGE_SIZE/sizeof(long);   /* ??? */
-        tmp.f_blocks = 0;
-        tmp.f_bfree = 0;
-        tmp.f_bavail = 0;
-        tmp.f_files = 0;
-        tmp.f_ffree = 0;
-        tmp.f_namelen = NAME_MAX;
-        return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+        buf->f_type = USBDEVICE_SUPER_MAGIC;
+        buf->f_bsize = PAGE_SIZE/sizeof(long);   /* ??? */
+        buf->f_bfree = 0;
+        buf->f_bavail = 0;
+        buf->f_ffree = 0;
+        buf->f_namelen = NAME_MAX;
+        return 0;
 }
 
 static struct super_operations usbdevfs_sops = { 
index 4de32c098c504583835d93eb03812eeb5d38bb6b..2b46f14d9f2fec436e70462323b34286b9ee9c4e 100644 (file)
@@ -40,7 +40,7 @@ if [ "$CONFIG_FB" = "y" ]; then
       define_bool CONFIG_FB_Q40 y
    fi
    if [ "$CONFIG_AMIGA" = "y" ]; then
-      bool '  Amiga native chipset support' CONFIG_FB_AMIGA
+      tristate '  Amiga native chipset support' CONFIG_FB_AMIGA
       if [ "$CONFIG_FB_AMIGA" != "n" ]; then
         bool '    Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS
         bool '    Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS
index c3d442e228be2075c28f219673d03e0923c4b1c2..12918c1b587c3663e943646a4084a8f535593cd0 100644 (file)
@@ -16,7 +16,7 @@ M_OBJS   :=
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
-export-objs    := fbmem.o fbcmap.o fbcon.o fbcon-afb.o fbcon-ilbm.o \
+export-objs    := fbmem.o fbcmap.o fbcon.o fbmon.o fbcon-afb.o fbcon-ilbm.o \
                  fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
                  fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
                  fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
index af0a0d7c8f21aef489edd8a1de45226b9da4dde6..97df72fd20ba44f0173d3c826e38c84068eaf95b 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/console.h>
+#include <linux/ioport.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -1131,6 +1132,7 @@ static int amifb_set_cursorstate(struct fb_cursorstate *state, int con);
         */
 
 int amifb_init(void);
+static void amifb_deinit(void);
 static int amifbcon_switch(int con, struct fb_info *info);
 static int amifbcon_updatevar(int con, struct fb_info *info);
 static void amifbcon_blank(int blank, struct fb_info *info);
@@ -1143,6 +1145,7 @@ static void do_install_cmap(int con, struct fb_info *info);
 static int flash_cursor(void);
 static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
 static u_long chipalloc(u_long size);
+static void chipfree(void);
 static char *strtoke(char *s,const char *ct);
 
        /*
@@ -1181,13 +1184,6 @@ static void ami_build_copper(void);
 static void ami_rebuild_copper(void);
 
 
-       /*
-        * External references
-        */
-
-extern unsigned short ami_intena_vals[];
-
-
 static struct fb_ops amifb_ops = {
        amifb_open, amifb_release, amifb_get_fix, amifb_get_var,
        amifb_set_var, amifb_get_cmap, amifb_set_cmap,
@@ -1598,13 +1594,36 @@ static int amifb_set_cursorstate(struct fb_cursorstate *state, int con)
 }
 
 
+       /*
+        * Allocate, Clear and Align a Block of Chip Memory
+        */
+
+static u_long unaligned_chipptr = 0;
+
+static inline u_long __init chipalloc(u_long size)
+{
+       size += PAGE_SIZE-1;
+       if (!(unaligned_chipptr = (u_long)amiga_chip_alloc(size,
+                                                          "amifb [RAM]")))
+               panic("No Chip RAM for frame buffer");
+       memset((void *)unaligned_chipptr, 0, size);
+       return PAGE_ALIGN(unaligned_chipptr);
+}
+
+static inline void chipfree(void)
+{
+       if (unaligned_chipptr)
+               amiga_chip_free((void *)unaligned_chipptr);
+}
+
+
        /*
         * Initialisation
         */
 
 int __init amifb_init(void)
 {
-       int tag, i;
+       int tag, i, err = 0;
        u_long chipptr;
        u_int defmode;
        struct fb_var_screeninfo var;
@@ -1625,6 +1644,13 @@ int __init amifb_init(void)
        }
 #endif
 
+       /*
+        * We request all registers starting from bplpt[0]
+        */
+       if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120,
+                               "amifb [Denise/Lisa]"))
+               return -EBUSY;
+
        custom.dmacon = DMAF_ALL | DMAF_MASTER;
 
        switch (amiga_chipset) {
@@ -1688,7 +1714,8 @@ default_chipset:
                        strcat(amifb_name, "Unknown");
                        goto default_chipset;
 #else /* CONFIG_FB_AMIGA_OCS */
-                       return -ENXIO;
+                       err = -ENXIO;
+                       goto amifb_error;
 #endif /* CONFIG_FB_AMIGA_OCS */
                        break;
        }
@@ -1738,9 +1765,37 @@ default_chipset:
        fb_info.flags = FBINFO_FLAG_DEFAULT;
        memset(&var, 0, sizeof(var));
 
+#ifdef MODULE
+       var.xres = ami_modedb[defmode].xres;
+       var.yres = ami_modedb[defmode].yres;
+       var.xres_virtual = ami_modedb[defmode].xres;
+       var.yres_virtual = ami_modedb[defmode].yres;
+       var.xoffset = 0;
+       var.yoffset = 0;
+       var.bits_per_pixel = 4;
+       var.activate |= FB_ACTIVATE_TEST;
+       var.pixclock = ami_modedb[defmode].pixclock;
+       var.left_margin = ami_modedb[defmode].left_margin;
+       var.right_margin = ami_modedb[defmode].right_margin;
+       var.upper_margin = ami_modedb[defmode].upper_margin;
+       var.lower_margin = ami_modedb[defmode].lower_margin;
+       var.hsync_len = ami_modedb[defmode].hsync_len;
+       var.vsync_len = ami_modedb[defmode].vsync_len;
+       var.sync = ami_modedb[defmode].sync;
+       var.vmode = ami_modedb[defmode].vmode;
+       err = fb_info.fbops->fb_set_var(&var, -1, &fb_info);
+       var.activate &= ~FB_ACTIVATE_TEST;
+       if (err) {
+               err = -EINVAL;
+               goto amifb_error;
+       }
+#else
        if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb,
-                         NUM_TOTAL_MODES, &ami_modedb[defmode], 4))
-           panic("Can't find any usable video mode");
+                         NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
+               err = -EINVAL;
+               goto amifb_error;
+       }
+#endif
 
        round_down_bpp = 0;
        chipptr = chipalloc(videomemorysize+
@@ -1762,9 +1817,7 @@ default_chipset:
         * access the videomem with writethrough cache
         */
        videomemory_phys = (u_long)ZTWO_PADDR(videomemory);
-#if 1
        videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize);
-#endif
        if (!videomemory) {
                printk("amifb: WARNING! unable to map videomem cached writethrough\n");
                videomemory = ZTWO_VADDR(videomemory_phys);
@@ -1786,26 +1839,38 @@ default_chipset:
        ami_init_copper();
 
        if (request_irq(IRQ_AMIGA_AUTO_3, amifb_interrupt, 0,
-                       "fb vertb handler", NULL))
-               panic("Couldn't add vblank interrupt\n");
-       ami_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER;
-       ami_intena_vals[IRQ_AMIGA_COPPER] = 0;
+                       "fb vertb handler", NULL)) {
+               err = -EBUSY;
+               goto amifb_error;
+       }
+       amiga_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER;
+       amiga_intena_vals[IRQ_AMIGA_COPPER] = 0;
        custom.intena = IF_VERTB;
        custom.intena = IF_SETCLR | IF_COPER;
 
        amifb_set_var(&var, -1, &fb_info);
 
-       if (register_framebuffer(&fb_info) < 0)
-               return -EINVAL;
+       if (register_framebuffer(&fb_info) < 0) {
+               err = -EINVAL;
+               goto amifb_error;
+       }
 
        printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
               GET_FB_IDX(fb_info.node), fb_info.modename,
               videomemorysize>>10);
 
-       /* TODO: This driver cannot be unloaded yet */
-       MOD_INC_USE_COUNT;
-
        return 0;
+       
+amifb_error:
+       amifb_deinit();
+       return err;
+}
+
+static void amifb_deinit(void)
+{
+       chipfree();    
+       release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
+       custom.dmacon = DMAF_ALL | DMAF_MASTER;
 }
 
 static int amifbcon_switch(int con, struct fb_info *info)
@@ -1930,23 +1995,6 @@ static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
        }
 }
 
-       /*
-        * Allocate, Clear and Align a Block of Chip Memory
-        */
-
-static u_long __init chipalloc(u_long size)
-{
-       u_long ptr;
-
-       size += PAGE_SIZE-1;
-       if (!(ptr = (u_long)amiga_chip_alloc(size, "amifb")))
-               panic("No Chip RAM for frame buffer");
-       memset((void *)ptr, 0, size);
-       ptr = PAGE_ALIGN(ptr);
-
-       return ptr;
-}
-
        /*
         * A strtok which returns empty strings, too
         */
@@ -3373,9 +3421,7 @@ int init_module(void)
 
 void cleanup_module(void)
 {
-       /* Not reached because the usecount will never
-          be decremented to zero */
        unregister_framebuffer(&fb_info);
-       /* TODO: clean up ... */
+       amifb_deinit();
 }
 #endif /* MODULE */
index ceb289eb8740665f5d3db02b717987f4b1573736..d7d4116c0a6be5ac0082a24b02edfc454d562cd2 100644 (file)
@@ -1358,7 +1358,7 @@ aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb)
     } 
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
-    if (console_fb_info == &info->fb_info) {
+    if (!console_fb_info || console_fb_info == &info->fb_info) {
        int vmode, cmode;
 
        display_info.width = var->xres;
@@ -1429,13 +1429,8 @@ aty128_encode_fix(struct fb_fix_screeninfo *fix,
     
     strcpy(fix->id, aty128fb_name);
 
-#ifdef CONFIG_PPC /* why?  I don't know */
-    *fix->smem_start = (long)info->frame_buffer_phys;
-    *fix->mmio_start = (long)info->regbase_phys;
-#else
     fix->smem_start = (long)info->frame_buffer_phys;
     fix->mmio_start = (long)info->regbase_phys;
-#endif
 
     fix->smem_len = (u32)info->vram_size;
     fix->mmio_len = 0x1fff;
@@ -1676,7 +1671,7 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
     chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
 
     /* put a name with the face */
-    while (info->pdev->device != aci->device) { aci++; }
+    while (aci->name && info->pdev->device != aci->device) { aci++; }
     video_card = (char *)aci->name;
 
     printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] [card rev %x] ",
@@ -1723,7 +1718,10 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
     if (default_cmode == CMODE_NVRAM)
         default_cmode = nvram_read_byte(NV_CMODE);
 #endif
-    }
+    } else if (_machine == _MACH_Pmac)
+       if (mac_vmode_to_var(default_vmode, default_cmode, &var))
+           var = default_var;
+
 #endif
 #endif /* MODULE */
 
index aedbc8b17c8625bd0b01207ce5dfd631eae5b714..8da8117c904b53eb63ef2c42ba982eea2e256c6c 100644 (file)
 #define LOGO_W                 80
 #define LOGO_LINE      (LOGO_W/8)
 
+static int first_fb_vc = 0;
+static int last_fb_vc = MAX_NR_CONSOLES-1;
+static int fbcon_is_default = 1;
+
 struct display fb_display[MAX_NR_CONSOLES];
 char con2fb_map[MAX_NR_CONSOLES];
 static int logo_lines;
@@ -128,6 +132,8 @@ static int softback_lines;
 #define FNTSUM(fd)     (((int *)(fd))[-4])
 #define FONT_EXTRA_WORDS 4
 
+static char fontname[40] __initdata = { 0 };     /* default font name */
+
 #define CM_SOFTBACK    (8)
 
 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * conp->vc_size_row)
@@ -197,7 +203,8 @@ static int fbcon_scrolldelta(struct vc_data *conp, int lines);
  *  Internal routines
  */
 
-static void fbcon_setup(int con, int init, int logo);
+static int __init fbcon_setup(char *options);
+static void fbcon_set_disp(int con, int init, int logo);
 static __inline__ int real_y(struct display *p, int ypos);
 static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp);
 static __inline__ void updatescrollmode(struct display *p);
@@ -293,6 +300,8 @@ void set_con2fb_map(int unit, int newidx)
        newfb = registered_fb[newidx];
        if (newfb->fbops->fb_open(newfb,0))
            return;
+       newfb->count++;
+       oldfb->count--;         
        oldfb->fbops->fb_release(oldfb,0);
        conp = fb_display[unit].conp;
        fontdata = fb_display[unit].fontdata;
@@ -323,6 +332,57 @@ void set_con2fb_map(int unit, int newidx)
    }
 }
 
+static int __init fbcon_setup(char *options)
+{
+    int i, j;
+
+    if (!options || !*options)
+            return 0;
+
+    if (!strncmp(options, "font:", 5))
+        strcpy(fontname, options+5);
+
+    if (!strncmp(options, "scrollback:", 11)) {
+            options += 11;
+            if (*options) {
+                fbcon_softback_size = simple_strtoul(options, &options, 0);
+                if (*options == 'k' || *options == 'K') {
+                        fbcon_softback_size *= 1024;
+                        options++;
+                }
+                if (*options != ',')
+                        return 0;
+                options++;
+            } else
+                return 0;
+    }
+
+    if (!strncmp(options, "map:", 4)) {
+            options += 4;
+            if (*options)
+                    for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
+                            if (!options[j])
+                                    j = 0;
+                            con2fb_map[i] = (options[j++]-'0') % FB_MAX;
+                    }
+            return 0;
+    }
+
+    if (!strncmp(options, "vc:", 3)) {
+            options += 3;
+            if (*options)
+                first_fb_vc = simple_strtoul(options, &options, 10) - 1;
+            if (first_fb_vc < 0)
+                first_fb_vc = 0;
+            if (*options++ == '-')
+                last_fb_vc = simple_strtoul(options, &options, 10) - 1;
+            fbcon_is_default = 0;
+    }
+    return 0;
+}
+
+__setup("fbcon=", fbcon_setup);
+
 /*
  *  Low Level Operations
  */
@@ -419,15 +479,23 @@ static const char *fbcon_startup(void)
     return display_desc;
 }
 
-
 static void fbcon_init(struct vc_data *conp, int init)
 {
-    int unit = conp->vc_num;
+    int j, unit = conp->vc_num;
     struct fb_info *info;
-
+       
     /* on which frame buffer will we open this console? */
     info = registered_fb[(int)con2fb_map[unit]];
 
+    /*
+     *  We assume initial frame buffer devices can be opened this
+     *  many times
+     */
+    for (j = 0; j < (last_fb_vc - first_fb_vc + 1); j++) {
+        info->fbops->fb_open(info,0);
+       info->count++;  
+    }  
+
     info->changevar = &fbcon_changevar;
     fb_display[unit] = *(info->disp);  /* copy from default */
     DPRINTK("mode:   %s\n",info->modename);
@@ -443,8 +511,8 @@ static void fbcon_init(struct vc_data *conp, int init)
     fb_display[unit].cmap.green = 0;
     fb_display[unit].cmap.blue = 0;
     fb_display[unit].cmap.transp = 0;
-    fbcon_setup(unit, init, !init);
-    /* Must be done after fbcon_setup to prevent excess updates */
+    fbcon_set_disp(unit, init, !init);
+    /* Must be done after fbcon_set_disp to prevent excess updates */
     conp->vc_display_fg = &info->display_fg;
     if (!info->display_fg)
         info->display_fg = conp;
@@ -458,6 +526,7 @@ static void fbcon_deinit(struct vc_data *conp)
 
     fbcon_free_font(p);
     p->dispsw = &fbcon_dummy;
+    p->fb_info->count = 0;     
     p->conp = 0;
 }
 
@@ -465,7 +534,7 @@ static void fbcon_deinit(struct vc_data *conp)
 static int fbcon_changevar(int con)
 {
     if (fb_display[con].conp)
-           fbcon_setup(con, 0, 0);
+           fbcon_set_disp(con, 0, 0);
     return 0;
 }
 
@@ -504,7 +573,7 @@ static void fbcon_font_widths(struct display *p)
 
 #define fontwidthvalid(p,w) ((p)->dispsw->fontwidthmask & FONTWIDTH(w))
 
-static void fbcon_setup(int con, int init, int logo)
+static void fbcon_set_disp(int con, int init, int logo)
 {
     struct display *p = &fb_display[con];
     struct vc_data *conp = p->conp;
@@ -568,9 +637,8 @@ static void fbcon_setup(int con, int init, int logo)
     }
 
     if (!p->fontdata) {
-        if (!p->fb_info->fontname[0] ||
-           !(font = fbcon_find_font(p->fb_info->fontname)))
-               font = fbcon_get_default_font(p->var.xres, p->var.yres);
+        if (!fontname[0] || !(font = fbcon_find_font(fontname)))
+           font = fbcon_get_default_font(p->var.xres, p->var.yres);
         p->_fontwidth = font->width;
         p->_fontheight = font->height;
         p->fontdata = font->data;
@@ -586,7 +654,7 @@ static void fbcon_setup(int con, int init, int logo)
 #endif
        {
            /* ++Geert: changed from panic() to `correct and continue' */
-           printk(KERN_ERR "fbcon_setup: No support for fontwidth %d\n", fontwidth(p));
+           printk(KERN_ERR "fbcon_set_disp: No support for fontwidth %d\n", fontwidth(p));
            p->dispsw = &fbcon_dummy;
        }
     }
@@ -669,7 +737,7 @@ static void fbcon_setup(int con, int init, int logo)
     }
 
     if (p->dispsw == &fbcon_dummy)
-       printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not "
+       printk(KERN_WARNING "fbcon_set_disp: type %d (aux %d, depth %d) not "
               "supported\n", p->type, p->type_aux, p->var.bits_per_pixel);
     p->dispsw->setup(p);
 
@@ -2394,6 +2462,13 @@ struct consw fb_con = {
     con_getxy:         fbcon_getxy,
 };
 
+void __init fbconsole_init(void)
+{
+       if (!num_registered_fb || (first_fb_vc > last_fb_vc))
+                return;
+
+       take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
+}
 
 /*
  *  Dummy Low Level Operations
index 3bbf334b0e6170125616fca027950c8577953515..1f5492d4f05693c4fdd9ac89a3eba396dad78f94 100644 (file)
@@ -239,14 +239,8 @@ extern const char *global_mode_option;
 static initcall_t pref_init_funcs[FB_MAX];
 static int num_pref_init_funcs __initdata = 0;
 
-
 struct fb_info *registered_fb[FB_MAX];
 int num_registered_fb = 0;
-extern int fbcon_softback_size; 
-
-static int first_fb_vc = 0;
-static int last_fb_vc = MAX_NR_CONSOLES-1;
-static int fbcon_is_default = 1;
 
 static int fbmem_read_proc(char *buf, char **start, off_t offset,
                           int len, int *eof, void *private)
@@ -556,6 +550,8 @@ fb_open(struct inode *inode, struct file *file)
 #endif /* CONFIG_KMOD */
        if (!(info = registered_fb[fbidx]))
                return -ENODEV;
+       if (info->flags & FBINFO_FLAG_OPEN) return -EBUSY; 
+       info->flags |= FBINFO_FLAG_OPEN;                
        return info->fbops->fb_open(info,1);
 }
 
@@ -566,6 +562,7 @@ fb_release(struct inode *inode, struct file *file)
        struct fb_info *info = registered_fb[fbidx];
 
        info->fbops->fb_release(info,1);
+        info->flags &= ~FBINFO_FLAG_OPEN;
        return 0;
 }
 
@@ -583,10 +580,8 @@ static devfs_handle_t devfs_handle = NULL;
 int
 register_framebuffer(struct fb_info *fb_info)
 {
-       int i, j;
        char name_buf[8];
-       static int fb_ever_opened[FB_MAX];
-       static int first = 1;
+       int i;
 
        if (num_registered_fb == FB_MAX)
                return -ENXIO;
@@ -595,22 +590,9 @@ register_framebuffer(struct fb_info *fb_info)
                if (!registered_fb[i])
                        break;
        fb_info->node = MKDEV(FB_MAJOR, i);
+       fb_info->flags &= ~FBINFO_FLAG_OPEN;
+       fb_info->count = 0;
        registered_fb[i] = fb_info;
-       if (!fb_ever_opened[i]) {
-               /*
-                *  We assume initial frame buffer devices can be opened this
-                *  many times
-                */
-               for (j = 0; j < MAX_NR_CONSOLES; j++)
-                       if (con2fb_map[j] == i)
-                               fb_info->fbops->fb_open(fb_info,0);
-               fb_ever_opened[i] = 1;
-       }
-
-       if (first) {
-               first = 0;
-               take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
-       }
        sprintf (name_buf, "%d", i);
        fb_info->devfs_handle =
            devfs_register (devfs_handle, name_buf, 0, DEVFS_FL_NONE,
@@ -623,12 +605,12 @@ register_framebuffer(struct fb_info *fb_info)
 int
 unregister_framebuffer(struct fb_info *fb_info)
 {
-       int i, j;
+       int i;
 
        i = GET_FB_IDX(fb_info->node);
-       for (j = 0; j < MAX_NR_CONSOLES; j++)
-               if (con2fb_map[j] == i)
-                       return -EBUSY;
+       
+       if (fb_info->count || (fb_info->flags & FBINFO_FLAG_OPEN))
+               return -EBUSY;
        if (!registered_fb[i])
                return -EINVAL;
        devfs_unregister (fb_info->devfs_handle);
@@ -672,43 +654,6 @@ int __init video_setup(char *options)
 
     if (!options || !*options)
            return 0;
-           
-    if (!strncmp(options, "scrollback:", 11)) {
-           options += 11;
-           if (*options) {
-               fbcon_softback_size = simple_strtoul(options, &options, 0);
-               if (*options == 'k' || *options == 'K') {
-                       fbcon_softback_size *= 1024;
-                       options++;
-               }
-               if (*options != ',')
-                       return 0;
-               options++;
-           } else
-               return 0;
-    }
-
-    if (!strncmp(options, "map:", 4)) {
-           options += 4;
-           if (*options)
-                   for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
-                           if (!options[j])
-                                   j = 0;
-                           con2fb_map[i] = (options[j++]-'0') % FB_MAX;
-                   }
-           return 0;
-    }
-    
-    if (!strncmp(options, "vc:", 3)) {
-           options += 3;
-           if (*options)
-               first_fb_vc = simple_strtoul(options, &options, 10) - 1;
-           if (first_fb_vc < 0)
-               first_fb_vc = 0;
-           if (*options++ == '-')
-               last_fb_vc = simple_strtoul(options, &options, 10) - 1;
-           fbcon_is_default = 0;
-    }
 
     if (num_pref_init_funcs == FB_MAX)
            return 0;
index 38fb6adc9d69f384cc625644a2edaa35fab96a2d..77a796109a99461d982dfc886abedbe2c312a0c1 100644 (file)
@@ -41,6 +41,7 @@
  */
 #include <linux/tty.h>
 #include <linux/fb.h>
+#include <linux/module.h>
 
 int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal,
                         const struct fb_info *fb_info)
@@ -72,3 +73,5 @@ int fbmon_dpms(const struct fb_info *fb_info)
 {
   return fb_info->monspecs.dpms;
 }
+
+EXPORT_SYMBOL(fbmon_valid_timings);
index 68e6201cc840ca199e934c0eff532bdcd9c88b2e..f734c4f9fc195e1e50a056a6ae25b67d8466ab6b 100644 (file)
@@ -293,9 +293,6 @@ static int offb_ioctl(struct inode *inode, struct file *file, u_int cmd,
 }
 
 
-#ifdef CONFIG_FB_ATY128
-extern void aty128fb_of_init(struct device_node *dp);
-#endif /* CONFIG_FB_ATY */
 #ifdef CONFIG_FB_S3TRIO
 extern void s3triofb_init_of(struct device_node *dp);
 #endif /* CONFIG_FB_S3TRIO */
@@ -423,12 +420,6 @@ int __init offb_init(void)
 
 static int __init offb_init_driver(struct device_node *dp)
 {
-#ifdef CONFIG_FB_ATY128
-    if (!strncmp(dp->name, "ATY,Rage128", 11)) {
-       aty128fb_of_init(dp);
-       return 1;
-    }
-#endif
 #ifdef CONFIG_FB_S3TRIO
     if (!strncmp(dp->name, "S3Trio", 6)) {
        s3triofb_init_of(dp);
index 56a0526477a437be9c0faf951a93f99d26963005..1180d3ee0562ed2ec2e7e22e9867f6ff1eb1a337 100644 (file)
@@ -94,8 +94,6 @@ static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink,
 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count);
 static unsigned long vgacon_uni_pagedir[2];
 
-void clear_status_line( void );
-
 
 /* Description of the hardware situation */
 static unsigned long   vga_vram_base;          /* Base of video memory */
@@ -351,7 +349,6 @@ static void vgacon_init(struct vc_data *c, int init)
 static inline void vga_set_mem_top(struct vc_data *c)
 {
        write_vga(12, (c->vc_visible_origin-vga_vram_base)/2);
-       clear_status_line();
 }
 
 static void vgacon_deinit(struct vc_data *c)
@@ -1060,80 +1057,3 @@ struct consw vga_con = {
        vgacon_build_attr,
        vgacon_invert_region
 };
-
-
-int inited = 0;
-
-void
-clear_status_line( void )
-{
-#if CONFIG_COMMENT_INT==3
-        u16 *org;
-        int i;
-        int currcons = fg_console;
-       struct vc_data *c = vc_cons[fg_console].d;
-       if (!inited) return;
-        if (vga_is_gfx) return;
-       if (c->vc_origin != c->vc_visible_origin) return;
-        org = screen_pos( fg_console, video_num_lines*video_num_columns, 1 );
-        for (i=0; i<video_num_columns; i++)
-                scr_writew( (0x0f << 8) + ' ', org++ );
-#endif
-}
-
-#if CONFIG_COMMENT_INT==3
-void
-paint_status_line( int timer )
-{
-       u16 *org;
-       int i,j;
-       int currcons = fg_console;
-       struct vc_data *c = vc_cons[fg_console].d;
-
-       if (!inited) return;
-       if (vga_is_gfx)         /* We don't play origin tricks in graphic modes */
-               return;
-       if (c->vc_origin != c->vc_visible_origin) return;
-
-       org = screen_pos( fg_console, video_num_lines*video_num_columns, 1 );
-
-       /* Are we busy? */
-       {
-               i = current->pid;
-               j = 0;
-               if (i)
-                       j = (i>16) ? ((current->priority < DEF_PRIORITY) ? 0xA0:0xE0) : 0xC0;
-               scr_writew( (j<<8) + ' ', org++ );
-
-#if 0
-               org++;
-
-#define DISP( x ) scr_writew(  (((i&x) ? 0x90:0) << 8) + ' ', org++ );
-               DISP( 0x80 );
-               DISP( 0x40 );
-               DISP( 0x20 );
-               DISP( 0x10 );
-               DISP( 0x08 );
-               DISP( 0x04 );
-               DISP( 0x02 );
-               DISP( 0x01 );
-#endif
-       }
-
-       if (!timer) return;
-
-       org++;
-       /* Serial? */
-       {
-               j = (ledflags & 0x10) ? 0x90 : 0x00;
-               scr_writew( (j<<8) + 'S', org++ );
-       }
-
-       org++;
-       /* NE2000? */
-       {
-               j = (ledflags & 0x20) ? 0x90 : 0x00;
-               scr_writew( (j<<8) + 'N', org++ );
-       }
-}
-#endif
index 7c80a6958cd34b214e57c204852acc7636ab4a90..5320478b01e718a2b7eb6a64a21993a28a24affa 100644 (file)
@@ -213,21 +213,20 @@ static int adfs_remount(struct super_block *sb, int *flags, char *data)
        return parse_options(sb, data);
 }
 
-static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int adfs_statfs(struct super_block *sb, struct statfs *buf)
 {
        struct adfs_sb_info *asb = &sb->u.adfs_sb;
-       struct statfs tmp;
-
-       tmp.f_type    = ADFS_SUPER_MAGIC;
-       tmp.f_namelen = asb->s_namelen;
-       tmp.f_bsize   = sb->s_blocksize;
-       tmp.f_blocks  = asb->s_size;
-       tmp.f_files   = asb->s_ids_per_zone * asb->s_map_size;
-       tmp.f_bavail  =
-       tmp.f_bfree   = adfs_map_free(sb);
-       tmp.f_ffree   = tmp.f_bfree * tmp.f_files / tmp.f_blocks;
-
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+
+       buf->f_type    = ADFS_SUPER_MAGIC;
+       buf->f_namelen = asb->s_namelen;
+       buf->f_bsize   = sb->s_blocksize;
+       buf->f_blocks  = asb->s_size;
+       buf->f_files   = asb->s_ids_per_zone * asb->s_map_size;
+       buf->f_bavail  =
+       buf->f_bfree   = adfs_map_free(sb);
+       buf->f_ffree   = buf->f_bfree * buf->f_files / buf->f_blocks;
+
+       return 0;
 }
 
 static struct super_operations adfs_sops = {
index 38e5bccbe31e1c29b31280cb505b55812edbb662..c1a849a706da08c4258d2181adf7410d053c360f 100644 (file)
@@ -368,7 +368,7 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
        if (!empty_dir(bh,AFFS_I2HSIZE(inode)))
                goto rmdir_done;
        retval = -EBUSY;
-       if (!list_empty(&dentry->d_hash))
+       if (!d_unhashed(dentry))
                goto rmdir_done;
 
        if ((retval = affs_remove_header(bh,inode)) < 0)
@@ -557,6 +557,9 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
        }
        if (S_ISDIR(old_inode->i_mode)) {
                if (new_inode) {
+                       retval = -EBUSY;
+                       if (!d_unhashed(new_dentry))
+                               goto end_rename;
                        retval = -ENOTEMPTY;
                        if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
                                goto end_rename;
index 9eed5c09ef7f683586d9d3601c7437f64a13afee..b74504c063c954c59eb721adff1ee6ffb179ffcc 100644 (file)
@@ -35,7 +35,7 @@ extern struct timezone sys_tz;
 
 #define MIN(a,b) (((a)<(b))?(a):(b))
 
-static int affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int affs_statfs(struct super_block *sb, struct statfs *buf);
 static int affs_remount (struct super_block *sb, int *flags, char *data);
 
 static void
@@ -661,23 +661,20 @@ affs_remount(struct super_block *sb, int *flags, char *data)
 }
 
 static int
-affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+affs_statfs(struct super_block *sb, struct statfs *buf)
 {
        int              free;
-       struct statfs    tmp;
 
        pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size,
             sb->u.affs_sb.s_reserved);
 
        free          = affs_count_free_blocks(sb);
-       tmp.f_type    = AFFS_SUPER_MAGIC;
-       tmp.f_bsize   = sb->s_blocksize;
-       tmp.f_blocks  = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved;
-       tmp.f_bfree   = free;
-       tmp.f_bavail  = free;
-       tmp.f_files   = 0;
-       tmp.f_ffree   = 0;
-       return copy_to_user(buf,&tmp,bufsiz) ? -EFAULT : 0;
+       buf->f_type    = AFFS_SUPER_MAGIC;
+       buf->f_bsize   = sb->s_blocksize;
+       buf->f_blocks  = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved;
+       buf->f_bfree   = free;
+       buf->f_bavail  = free;
+       return 0;
 }
 
 static struct file_system_type affs_fs_type = {
index a67ca98226b638ea72815f0c09585e0690be3cac..9fcf7dd4e8099d7daea44478857b5d47a1522b69 100644 (file)
@@ -55,7 +55,7 @@ static void autofs_put_super(struct super_block *sb)
 #endif
 }
 
-static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int autofs_statfs(struct super_block *sb, struct statfs *buf);
 static void autofs_read_inode(struct inode *inode);
 static void autofs_write_inode(struct inode *inode);
 
@@ -274,19 +274,15 @@ fail_dec:
        return NULL;
 }
 
-static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int autofs_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       tmp.f_type = AUTOFS_SUPER_MAGIC;
-       tmp.f_bsize = 1024;
-       tmp.f_blocks = 0;
-       tmp.f_bfree = 0;
-       tmp.f_bavail = 0;
-       tmp.f_files = 0;
-       tmp.f_ffree = 0;
-       tmp.f_namelen = NAME_MAX;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = AUTOFS_SUPER_MAGIC;
+       buf->f_bsize = 1024;
+       buf->f_bfree = 0;
+       buf->f_bavail = 0;
+       buf->f_ffree = 0;
+       buf->f_namelen = NAME_MAX;
+       return 0;
 }
 
 static void autofs_read_inode(struct inode *inode)
index 35afe3cdc4f15818769ebe112be278dd680390ed..1540ceda844c3c2eff2cef9c6f25b6b36f0f51e8 100644 (file)
@@ -227,7 +227,7 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr
         * doesn't do the right thing for all system calls, but it should
         * be OK for the operations we permit from an autofs.
         */
-       if ( dentry->d_inode && list_empty(&dentry->d_hash) )
+       if ( dentry->d_inode && d_unhashed(dentry) )
                return ERR_PTR(-ENOENT);
 
        return NULL;
index 40d149272d8c96ba36224867b9f313349d5e241a..cfb2b1180654b830fb37a239146b93a6d181ca96 100644 (file)
@@ -117,7 +117,7 @@ static void autofs4_umount_begin(struct super_block *sb)
                autofs4_catatonic_mode(sbi);
 }
 
-static int autofs4_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int autofs4_statfs(struct super_block *sb, struct statfs *buf);
 static void autofs4_read_inode(struct inode *inode);
 static void autofs4_write_inode(struct inode *inode);
 
@@ -365,19 +365,15 @@ fail_dec:
        return NULL;
 }
 
-static int autofs4_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int autofs4_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       tmp.f_type = AUTOFS_SUPER_MAGIC;
-       tmp.f_bsize = 1024;
-       tmp.f_blocks = 0;
-       tmp.f_bfree = 0;
-       tmp.f_bavail = 0;
-       tmp.f_files = 0;
-       tmp.f_ffree = 0;
-       tmp.f_namelen = NAME_MAX;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = AUTOFS_SUPER_MAGIC;
+       buf->f_bsize = 1024;
+       buf->f_bfree = 0;
+       buf->f_bavail = 0;
+       buf->f_ffree = 0;
+       buf->f_namelen = NAME_MAX;
+       return 0;
 }
 
 static void autofs4_read_inode(struct inode *inode)
index 05045d40800bd571c46f967c3021c4e8f55e173c..8ff33b34499ac0e9833bad15fca1388f5e70b95b 100644 (file)
@@ -353,7 +353,7 @@ static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dent
         * doesn't do the right thing for all system calls, but it should
         * be OK for the operations we permit from an autofs.
         */
-       if ( dentry->d_inode && list_empty(&dentry->d_hash) )
+       if ( dentry->d_inode && d_unhashed(dentry) )
                return ERR_PTR(-ENOENT);
 
        return NULL;
index 79c7c6507541fde7d5f0e63a4eb42283cbbff7d3..affac9e13a4c810411d7470ff1dc2f01c0e51402 100644 (file)
@@ -185,19 +185,17 @@ static void bfs_put_super(struct super_block *s)
        MOD_DEC_USE_COUNT;
 }
 
-static int bfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
+static int bfs_statfs(struct super_block *s, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       tmp.f_type = BFS_MAGIC;
-       tmp.f_bsize = s->s_blocksize;
-       tmp.f_blocks = s->su_blocks;
-       tmp.f_bfree = tmp.f_bavail = s->su_freeb;
-       tmp.f_files = s->su_lasti + 1 - BFS_ROOT_INO;
-       tmp.f_ffree = s->su_freei;
-       tmp.f_fsid.val[0] = s->s_dev;
-       tmp.f_namelen = BFS_NAMELEN;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = BFS_MAGIC;
+       buf->f_bsize = s->s_blocksize;
+       buf->f_blocks = s->su_blocks;
+       buf->f_bfree = buf->f_bavail = s->su_freeb;
+       buf->f_files = s->su_lasti + 1 - BFS_ROOT_INO;
+       buf->f_ffree = s->su_freei;
+       buf->f_fsid.val[0] = s->s_dev;
+       buf->f_namelen = BFS_NAMELEN;
+       return 0;
 }
 
 static void bfs_write_super(struct super_block *s)
index 8e25fccd674a2a91321943c1e103bf2db1f61572..1e39811e6200b58c1a294d44e08c9a4dd3c10d5c 100644 (file)
@@ -451,7 +451,7 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
 
         dircnp = ITOC(dir);
 
-       if (!list_empty(&de->d_hash))
+       if (!d_unhashed(de))
                return -EBUSY;
        error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
 
index 1f82ef5bd46e7430c5fde9c294d331c672df9ec6..3757983be695a00729864d46667cab2760265bd9 100644 (file)
@@ -37,8 +37,7 @@ static void coda_read_inode(struct inode *);
 static void coda_put_inode(struct inode *);
 static void coda_delete_inode(struct inode *);
 static void coda_put_super(struct super_block *);
-static int coda_statfs(struct super_block *sb, struct statfs *buf, 
-                      int bufsiz);
+static int coda_statfs(struct super_block *sb, struct statfs *buf);
 
 /* exported operations */
 struct super_operations coda_super_operations =
@@ -235,31 +234,25 @@ int coda_notify_change(struct dentry *de, struct iattr *iattr)
         return error;
 }
 
-static int coda_statfs(struct super_block *sb, struct statfs *buf, 
-                      int bufsiz)
+static int coda_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
        int error;
 
-       memset(&tmp, 0, sizeof(struct statfs));
-
-       error = venus_statfs(sb, &tmp);
+       error = venus_statfs(sb, buf);
 
        if (error) {
                /* fake something like AFS does */
-               tmp.f_blocks = 9000000;
-               tmp.f_bfree  = 9000000;
-               tmp.f_bavail = 9000000;
-               tmp.f_files  = 9000000;
-               tmp.f_ffree  = 9000000;
+               buf->f_blocks = 9000000;
+               buf->f_bfree  = 9000000;
+               buf->f_bavail = 9000000;
+               buf->f_files  = 9000000;
+               buf->f_ffree  = 9000000;
        }
 
        /* and fill in the rest */
-       tmp.f_type = CODA_SUPER_MAGIC;
-       tmp.f_bsize = 1024;
-       tmp.f_namelen = CODA_MAXNAMLEN;
-
-       copy_to_user(buf, &tmp, bufsiz);
+       buf->f_type = CODA_SUPER_MAGIC;
+       buf->f_bsize = 1024;
+       buf->f_namelen = CODA_MAXNAMLEN;
 
        return 0; 
 }
index 89b9719f502bad7734f7e36d86aaf89a09adf049..5cb068e2b6924df5186cd2e716f2c12e33759cd7 100644 (file)
@@ -208,20 +208,15 @@ static void cramfs_put_super(struct super_block *sb)
        return;
 }
 
-static int cramfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
+static int cramfs_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       /* Unsupported fields set to -1 as per man page. */
-       memset(&tmp, 0xff, sizeof(tmp));
-
-       tmp.f_type = CRAMFS_MAGIC;
-       tmp.f_bsize = PAGE_CACHE_SIZE;
-       tmp.f_bfree = 0;
-       tmp.f_bavail = 0;
-       tmp.f_ffree = 0;
-       tmp.f_namelen = 255;
-       return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
+       buf->f_type = CRAMFS_MAGIC;
+       buf->f_bsize = PAGE_CACHE_SIZE;
+       buf->f_bfree = 0;
+       buf->f_bavail = 0;
+       buf->f_ffree = 0;
+       buf->f_namelen = 255;
+       return 0;
 }
 
 /*
index f2e09cd6ec870339232b8dc1e45951bc38ab2bc9..88d7248754a4d093bcb10ec7cb3c565cb2ce51d4 100644 (file)
@@ -2313,19 +2313,15 @@ static void devfs_put_super (struct super_block *sb)
     MOD_DEC_USE_COUNT;
 }   /*  End Function devfs_put_super  */
 
-static int devfs_statfs (struct super_block *sb, struct statfs *buf,int bufsiz)
-{
-    struct statfs tmp;
-
-    tmp.f_type = DEVFS_SUPER_MAGIC;
-    tmp.f_bsize = PAGE_SIZE / sizeof (long);
-    tmp.f_blocks = 0;
-    tmp.f_bfree = 0;
-    tmp.f_bavail = 0;
-    tmp.f_files = 0;
-    tmp.f_ffree = 0;
-    tmp.f_namelen = NAME_MAX;
-    return copy_to_user (buf, &tmp, bufsiz) ? -EFAULT : 0;
+static int devfs_statfs (struct super_block *sb, struct statfs *buf)
+{
+    buf->f_type = DEVFS_SUPER_MAGIC;
+    buf->f_bsize = PAGE_SIZE / sizeof (long);
+    buf->f_bfree = 0;
+    buf->f_bavail = 0;
+    buf->f_ffree = 0;
+    buf->f_namelen = NAME_MAX;
+    return 0;
 }   /*  End Function devfs_statfs  */
 
 static struct super_operations devfs_sops =
index dab1864cb1a3ddf515155235c50631a80422dde6..e43a56a606e5487cdfa19c71864cc702b1a59df1 100644 (file)
@@ -57,7 +57,7 @@ static void devpts_put_super(struct super_block *sb)
 #endif
 }
 
-static int devpts_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int devpts_statfs(struct super_block *sb, struct statfs *buf);
 static void devpts_read_inode(struct inode *inode);
 static void devpts_write_inode(struct inode *inode);
 
@@ -238,19 +238,15 @@ fail_dec:
        return NULL;
 }
 
-static int devpts_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int devpts_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       tmp.f_type = DEVPTS_SUPER_MAGIC;
-       tmp.f_bsize = 1024;
-       tmp.f_blocks = 0;
-       tmp.f_bfree = 0;
-       tmp.f_bavail = 0;
-       tmp.f_files = 0;
-       tmp.f_ffree = 0;
-       tmp.f_namelen = NAME_MAX;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = DEVPTS_SUPER_MAGIC;
+       buf->f_bsize = 1024;
+       buf->f_bfree = 0;
+       buf->f_bavail = 0;
+       buf->f_ffree = 0;
+       buf->f_namelen = NAME_MAX;
+       return 0;
 }
 
 static void devpts_read_inode(struct inode *inode)
index 4522b2cfe9588df744952678ecf3281ad535548a..febda295f30d99ddf7741ea515049d61d39fedc2 100644 (file)
@@ -225,24 +225,23 @@ void efs_put_super(struct super_block *s) {
        MOD_DEC_USE_COUNT;
 }
 
-int efs_statfs(struct super_block *s, struct statfs *buf, int bufsiz) {
-       struct statfs ret;
+int efs_statfs(struct super_block *s, struct statfs *buf) {
        struct efs_sb_info *sb = SUPER_INFO(s);
 
-       ret.f_type    = EFS_SUPER_MAGIC;        /* efs magic number */
-       ret.f_bsize   = EFS_BLOCKSIZE;          /* blocksize */
-       ret.f_blocks  = sb->total_groups *      /* total data blocks */
+       buf->f_type    = EFS_SUPER_MAGIC;       /* efs magic number */
+       buf->f_bsize   = EFS_BLOCKSIZE;         /* blocksize */
+       buf->f_blocks  = sb->total_groups *     /* total data blocks */
                        (sb->group_size - sb->inode_blocks);
-       ret.f_bfree   = sb->data_free;          /* free data blocks */
-       ret.f_bavail  = sb->data_free;          /* free blocks for non-root */
-       ret.f_files   = sb->total_groups *      /* total inodes */
+       buf->f_bfree   = sb->data_free;         /* free data blocks */
+       buf->f_bavail  = sb->data_free;         /* free blocks for non-root */
+       buf->f_files   = sb->total_groups *     /* total inodes */
                        sb->inode_blocks *
                        (EFS_BLOCKSIZE / sizeof(struct efs_dinode));
-       ret.f_ffree   = sb->inode_free; /* free inodes */
-       ret.f_fsid.val[0] = (sb->fs_magic >> 16) & 0xffff; /* fs ID */
-       ret.f_fsid.val[1] =  sb->fs_magic        & 0xffff; /* fs ID */
-       ret.f_namelen = EFS_MAXNAMELEN;         /* max filename length */
+       buf->f_ffree   = sb->inode_free;        /* free inodes */
+       buf->f_fsid.val[0] = (sb->fs_magic >> 16) & 0xffff; /* fs ID */
+       buf->f_fsid.val[1] =  sb->fs_magic        & 0xffff; /* fs ID */
+       buf->f_namelen = EFS_MAXNAMELEN;        /* max filename length */
 
-       return copy_to_user(buf, &ret, bufsiz) ? -EFAULT : 0;
+       return 0;
 }
 
index b4cdc58684e8ea607db987b12b016792657e8200..4369e5a5aaa29ca05feed4b9a0a66b312afceb50 100644 (file)
@@ -725,10 +725,9 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
        return 0;
 }
 
-int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
+int ext2_statfs (struct super_block * sb, struct statfs * buf)
 {
        unsigned long overhead;
-       struct statfs tmp;
        int     ngroups, i;
 
        if (test_opt (sb, MINIX_DF))
@@ -768,17 +767,17 @@ int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
                             (2 + sb->u.ext2_sb.s_itb_per_group));
        }
 
-       tmp.f_type = EXT2_SUPER_MAGIC;
-       tmp.f_bsize = sb->s_blocksize;
-       tmp.f_blocks = le32_to_cpu(sb->u.ext2_sb.s_es->s_blocks_count) - overhead;
-       tmp.f_bfree = ext2_count_free_blocks (sb);
-       tmp.f_bavail = tmp.f_bfree - le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count);
-       if (tmp.f_bfree < le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count))
-               tmp.f_bavail = 0;
-       tmp.f_files = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count);
-       tmp.f_ffree = ext2_count_free_inodes (sb);
-       tmp.f_namelen = EXT2_NAME_LEN;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = EXT2_SUPER_MAGIC;
+       buf->f_bsize = sb->s_blocksize;
+       buf->f_blocks = le32_to_cpu(sb->u.ext2_sb.s_es->s_blocks_count) - overhead;
+       buf->f_bfree = ext2_count_free_blocks (sb);
+       buf->f_bavail = buf->f_bfree - le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count);
+       if (buf->f_bfree < le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count))
+               buf->f_bavail = 0;
+       buf->f_files = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count);
+       buf->f_ffree = ext2_count_free_inodes (sb);
+       buf->f_namelen = EXT2_NAME_LEN;
+       return 0;
 }
 
 static struct file_system_type ext2_fs_type = {
index 63af738a3f06673190555c43da0a4d0d75c9f6a4..c486732b9cba777226b5f53a24c575e9428f6704 100644 (file)
@@ -702,14 +702,14 @@ out_fail:
        return NULL;
 }
 
-int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
+int fat_statfs(struct super_block *sb,struct statfs *buf)
 {
        int free,nr;
-       struct statfs tmp;
        
        if (MSDOS_SB(sb)->cvf_format &&
            MSDOS_SB(sb)->cvf_format->cvf_statfs)
-               return MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,bufsiz);
+               return MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,
+                                               sizeof(struct statfs));
          
        lock_fat(sb);
        if (MSDOS_SB(sb)->free_clusters != -1)
@@ -721,15 +721,13 @@ int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
                MSDOS_SB(sb)->free_clusters = free;
        }
        unlock_fat(sb);
-       tmp.f_type = sb->s_magic;
-       tmp.f_bsize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
-       tmp.f_blocks = MSDOS_SB(sb)->clusters;
-       tmp.f_bfree = free;
-       tmp.f_bavail = free;
-       tmp.f_files = 0;
-       tmp.f_ffree = 0;
-       tmp.f_namelen = MSDOS_SB(sb)->options.isvfat ? 260 : 12;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = sb->s_magic;
+       buf->f_bsize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
+       buf->f_blocks = MSDOS_SB(sb)->clusters;
+       buf->f_bfree = free;
+       buf->f_bavail = free;
+       buf->f_namelen = MSDOS_SB(sb)->options.isvfat ? 260 : 12;
+       return 0;
 }
 
 static int is_exec(char *extension)
index d0a446c6eff4b47a0e3070182add25cff34901d6..f039806a536b6b64593231a41fdfae6e0f75e2be 100644 (file)
@@ -89,10 +89,6 @@ void __init filesystem_setup(void)
 
        init_devfs_fs();  /*  Header file may make this empty  */
 
-#ifdef CONFIG_LOCKD
-       nlmxdr_init();
-#endif
-
 #ifdef CONFIG_NFS_FS
        init_nfs_fs();
 #endif
index 40f8d2e5f8b43f775030ddb8fde9dd2d13e8b414..debe0a9678dd4c1f008f96911dbd74115c9fdaa1 100644 (file)
@@ -311,7 +311,7 @@ int hfs_rmdir(struct inode * parent, struct dentry *dentry)
                goto hfs_rmdir_put;
 
        error = -EBUSY;
-       if (!list_empty(&dentry->d_hash))
+       if (!d_unhashed(dentry))
                goto hfs_rmdir_put;
 
        if (/* we only have to worry about 2 and 3 for mount points */
index 3ed8307a00ae9bc1b725d2a0e584b2cc1208804d..8bb61dac56efe5bc747163ed7bc8261f64e02c46 100644 (file)
@@ -36,7 +36,7 @@
 
 static void hfs_read_inode(struct inode *);
 static void hfs_put_super(struct super_block *);
-static int hfs_statfs(struct super_block *, struct statfs *, int);
+static int hfs_statfs(struct super_block *, struct statfs *);
 static void hfs_write_super(struct super_block *);
 
 /*================ Global variables ================*/
@@ -139,21 +139,20 @@ static void hfs_put_super(struct super_block *sb)
  *
  * changed f_files/f_ffree to reflect the fs_ablock/free_ablocks.
  */
-static int hfs_statfs(struct super_block *sb, struct statfs *buf, int len)
+static int hfs_statfs(struct super_block *sb, struct statfs *buf)
 {
        struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb;
-       struct statfs tmp;
-
-       tmp.f_type = HFS_SUPER_MAGIC;
-       tmp.f_bsize = HFS_SECTOR_SIZE;
-       tmp.f_blocks = mdb->alloc_blksz * mdb->fs_ablocks;
-       tmp.f_bfree = mdb->alloc_blksz * mdb->free_ablocks;
-       tmp.f_bavail = tmp.f_bfree;
-       tmp.f_files = mdb->fs_ablocks;  
-       tmp.f_ffree = mdb->free_ablocks;
-       tmp.f_namelen = HFS_NAMELEN;
-
-       return copy_to_user(buf, &tmp, len) ? -EFAULT : 0;
+
+       buf->f_type = HFS_SUPER_MAGIC;
+       buf->f_bsize = HFS_SECTOR_SIZE;
+       buf->f_blocks = mdb->alloc_blksz * mdb->fs_ablocks;
+       buf->f_bfree = mdb->alloc_blksz * mdb->free_ablocks;
+       buf->f_bavail = buf->f_bfree;
+       buf->f_files = mdb->fs_ablocks;  
+       buf->f_ffree = mdb->free_ablocks;
+       buf->f_namelen = HFS_NAMELEN;
+
+       return 0;
 }
 
 /*
index 44d1037cfa244c7c79bb45a058008966cdc06e68..677fda52c0a2d2dc03c8f5b3be9ccc9954f7baf8 100644 (file)
@@ -311,7 +311,7 @@ int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
 int hpfs_remount_fs(struct super_block *, int *, char *);
 void hpfs_put_super(struct super_block *);
 unsigned hpfs_count_one_bitmap(struct super_block *, secno);
-int hpfs_statfs(struct super_block *, struct statfs *, int);
+int hpfs_statfs(struct super_block *, struct statfs *);
 struct super_block *hpfs_read_super(struct super_block *, void *, int);
 
 extern struct address_space_operations hpfs_aops;
index 6638170858120981e86b1d440afbbb84d0b0e735..f02239eae6687af14ef2499d64115acf5ee60282 100644 (file)
@@ -375,7 +375,7 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
                hpfs_unlock_2inodes(dir, inode);
                return -ENOTDIR;
        }
-       if (!list_empty(&dentry->d_hash)) {
+       if (!d_unhashed(dentry)) {
                hpfs_brelse4(&qbh);
                hpfs_unlock_2inodes(dir, inode);
                return -EBUSY;
index 8937bb90e38ee38f1188c7b96c775aa56ff20629..37c816aa49169b3c082668ed50f4c25d4ea09795 100644 (file)
@@ -132,22 +132,21 @@ static unsigned count_bitmaps(struct super_block *s)
        return count;
 }
 
-int hpfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
+int hpfs_statfs(struct super_block *s, struct statfs *buf)
 {
-       struct statfs tmp;
        /*if (s->s_hpfs_n_free == -1) {*/
                s->s_hpfs_n_free = count_bitmaps(s);
                s->s_hpfs_n_free_dnodes = hpfs_count_one_bitmap(s, s->s_hpfs_dmap);
        /*}*/
-       tmp.f_type = s->s_magic;
-       tmp.f_bsize = 512;
-       tmp.f_blocks = s->s_hpfs_fs_size;
-       tmp.f_bfree = s->s_hpfs_n_free;
-       tmp.f_bavail = s->s_hpfs_n_free;
-       tmp.f_files = s->s_hpfs_dirband_size / 4;
-       tmp.f_ffree = s->s_hpfs_n_free_dnodes;
-       tmp.f_namelen = 254;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = s->s_magic;
+       buf->f_bsize = 512;
+       buf->f_blocks = s->s_hpfs_fs_size;
+       buf->f_bfree = s->s_hpfs_n_free;
+       buf->f_bavail = s->s_hpfs_n_free;
+       buf->f_files = s->s_hpfs_dirband_size / 4;
+       buf->f_ffree = s->s_hpfs_n_free_dnodes;
+       buf->f_namelen = 254;
+       return 0;
 }
 
 /* Super operations */
index 9b216857db77366b4b5ab7d5c7f6e536d0fa7445..c4915bba111fbc38b9853fdd49690a93fa0e3ee7 100644 (file)
@@ -94,6 +94,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
                INIT_LIST_HEAD(&inode->i_data.pages);
                INIT_LIST_HEAD(&inode->i_dentry);
                sema_init(&inode->i_sem, 1);
+               sema_init(&inode->i_zombie, 1);
                spin_lock_init(&inode->i_data.i_shared_lock);
        }
 }
index 996d5ba68d50a18ec243f1ee3bab0d8056da9d41..d2148320cba640330e3a07931ba2bc617749f9ab 100644 (file)
@@ -74,7 +74,7 @@ static void isofs_put_super(struct super_block *sb)
 }
 
 static void isofs_read_inode(struct inode *);
-static int isofs_statfs (struct super_block *, struct statfs *, int);
+static int isofs_statfs (struct super_block *, struct statfs *);
 
 static struct super_operations isofs_sops = {
        read_inode:     isofs_read_inode,
@@ -874,20 +874,18 @@ out_unlock:
        return NULL;
 }
 
-static int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
+static int isofs_statfs (struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       tmp.f_type = ISOFS_SUPER_MAGIC;
-       tmp.f_bsize = sb->s_blocksize;
-       tmp.f_blocks = (sb->u.isofs_sb.s_nzones
+       buf->f_type = ISOFS_SUPER_MAGIC;
+       buf->f_bsize = sb->s_blocksize;
+       buf->f_blocks = (sb->u.isofs_sb.s_nzones
                   << (sb->u.isofs_sb.s_log_zone_size - sb->s_blocksize_bits));
-       tmp.f_bfree = 0;
-       tmp.f_bavail = 0;
-       tmp.f_files = sb->u.isofs_sb.s_ninodes;
-       tmp.f_ffree = 0;
-       tmp.f_namelen = NAME_MAX;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_bfree = 0;
+       buf->f_bavail = 0;
+       buf->f_files = sb->u.isofs_sb.s_ninodes;
+       buf->f_ffree = 0;
+       buf->f_namelen = NAME_MAX;
+       return 0;
 }
 
 /* Life is simpler than for other filesystem since we never
index db36300bae9446dcde95bdbb4acf881f3853678a..b3990ed9893fff3f4af960dfd2ac28228fb60681 100644 (file)
@@ -39,15 +39,4 @@ EXPORT_SYMBOL(nlmsvc_ops);
 EXPORT_SYMBOL(nlmsvc_grace_period);
 EXPORT_SYMBOL(nlmsvc_timeout);
 
-#ifdef CONFIG_LOCKD_V4
-
-/* NLM4 exported symbols */ 
-EXPORT_SYMBOL(nlm4_rofs);
-EXPORT_SYMBOL(nlm4_stale_fh);
-EXPORT_SYMBOL(nlm4_deadlock);
-EXPORT_SYMBOL(nlm4_failed);
-EXPORT_SYMBOL(nlm4_fbig);
-
-#endif
-
 #endif /* CONFIG_MODULES */
index 62401adbd0e8b86ec1498300d850584dba07bae5..264c19c2e0304eb7d931e93afecfd6d922f4f3b0 100644 (file)
@@ -322,7 +322,6 @@ init_module(void)
        init_MUTEX(&nlmsvc_sema);
        nlmsvc_users = 0;
        nlmsvc_pid = 0;
-       nlmxdr_init();
        return 0;
 }
 
index c0797a16faa8f5e70b138e2a85c87c181bd67b89..eba3aaef61ad25e7ef95149f47ff2a28d1389190 100644 (file)
 #include <linux/lockd/sm_inter.h>
 
 #define NLMDBG_FACILITY                NLMDBG_XDR
-#define NLM_MAXSTRLEN          1024
 
-#define QUADLEN(len)           (((len) + 3) >> 2)
-
-
-u32    nlm_granted, nlm_lck_denied, nlm_lck_denied_nolocks,
-       nlm_lck_blocked, nlm_lck_denied_grace_period;
-
-
-typedef struct nlm_args        nlm_args;
-
-/*
- * Initialization of NFS status variables
- */
-void
-nlmxdr_init(void)
-{
-       static int      inited = 0;
-
-       if (inited)
-               return;
-
-       nlm_granted = htonl(NLM_LCK_GRANTED);
-       nlm_lck_denied = htonl(NLM_LCK_DENIED);
-       nlm_lck_denied_nolocks = htonl(NLM_LCK_DENIED_NOLOCKS);
-       nlm_lck_blocked = htonl(NLM_LCK_BLOCKED);
-       nlm_lck_denied_grace_period = htonl(NLM_LCK_DENIED_GRACE_PERIOD);
-
-#ifdef CONFIG_LOCKD_V4
-       nlm4_deadlock = htonl(NLM_DEADLCK);
-       nlm4_rofs = htonl(NLM_ROFS);
-       nlm4_stale_fh = htonl(NLM_STALE_FH);
-       nlm4_fbig = htonl(NLM_FBIG);
-       nlm4_failed = htonl(NLM_FAILED);
-#endif
-
-       inited = 1;
-}
 
 /*
  * XDR functions for basic NLM types
index 7cedcd849771978db6829aed2eefd591c5ee010b..025e3c5b07b335ac87a5653f133bb2343d4a274e 100644 (file)
 #include <linux/lockd/sm_inter.h>
 
 #define NLMDBG_FACILITY                NLMDBG_XDR
-#define NLM_MAXSTRLEN          1024
 #define OFFSET_MAX             ((off_t)LONG_MAX)
 
-#define QUADLEN(len)           (((len) + 3) >> 2)
-
-u32     nlm4_deadlock, nlm4_rofs, nlm4_stale_fh, nlm4_fbig,
-       nlm4_failed;
-
-
-typedef struct nlm_args        nlm_args;
 
 static inline off_t
 size_to_off_t(__s64 size)
index 1d9ebb062b855979b8e2ae9abc02f3ee87fdc169..935f5a4296da034e3062a4ed8c778bb3cc9b3c63 100644 (file)
 #include <linux/highuid.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
 #include <asm/bitops.h>
 
 #include <linux/minix_fs.h>
 
 static void minix_read_inode(struct inode * inode);
 static void minix_write_inode(struct inode * inode);
-static int minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int minix_statfs(struct super_block *sb, struct statfs *buf);
 static int minix_remount (struct super_block * sb, int * flags, char * data);
 
 static void minix_delete_inode(struct inode *inode)
@@ -345,19 +344,17 @@ out_bad_sb:
        return NULL;
 }
 
-static int minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int minix_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       tmp.f_type = sb->s_magic;
-       tmp.f_bsize = sb->s_blocksize;
-       tmp.f_blocks = (sb->u.minix_sb.s_nzones - sb->u.minix_sb.s_firstdatazone) << sb->u.minix_sb.s_log_zone_size;
-       tmp.f_bfree = minix_count_free_blocks(sb);
-       tmp.f_bavail = tmp.f_bfree;
-       tmp.f_files = sb->u.minix_sb.s_ninodes;
-       tmp.f_ffree = minix_count_free_inodes(sb);
-       tmp.f_namelen = sb->u.minix_sb.s_namelen;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = sb->s_magic;
+       buf->f_bsize = sb->s_blocksize;
+       buf->f_blocks = (sb->u.minix_sb.s_nzones - sb->u.minix_sb.s_firstdatazone) << sb->u.minix_sb.s_log_zone_size;
+       buf->f_bfree = minix_count_free_blocks(sb);
+       buf->f_bavail = buf->f_bfree;
+       buf->f_files = sb->u.minix_sb.s_ninodes;
+       buf->f_ffree = minix_count_free_inodes(sb);
+       buf->f_namelen = sb->u.minix_sb.s_namelen;
+       return 0;
 }
 
 /*
index c18b46a3750d8b55c442f220965d6421bdff23ff..211556d4a46b36fb8e81e27027de6154e5fc7cd1 100644 (file)
@@ -399,7 +399,7 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry)
                retval = -ENOENT;
                goto end_rmdir;
        }
-       if (!list_empty(&dentry->d_hash)) {
+       if (!d_unhashed(dentry)) {
                retval = -EBUSY;
                goto end_rmdir;
        }
@@ -569,6 +569,9 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
        }
        if (S_ISDIR(old_inode->i_mode)) {
                if (new_inode) {
+                       retval = -EBUSY;
+                       if (!d_unhashed(new_dentry))
+                               goto end_rename;
                        retval = -ENOTEMPTY;
                        if (!empty_dir(new_inode))
                                goto end_rename;
index 87a49fb477268bd57fe8830b425eac368ee5e735..679ac558181a1295bb0724abf498990dccc13192 100644 (file)
@@ -326,7 +326,7 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry)
         * whether it is empty.
         */
        res = -EBUSY;
-       if (!list_empty(&dentry->d_hash))
+       if (!d_unhashed(dentry))
                goto rmdir_done;
        res = fat_dir_empty(inode);
        if (res)
@@ -463,6 +463,9 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
                goto degenerate_case;
        if (is_dir) {
                if (new_inode) {
+                       error = -EBUSY;
+                       if (!d_unhashed(new_dentry))
+                               goto out;
                        error = fat_dir_empty(new_inode);
                        if (error)
                                goto out;
index 5f148b5a826a751dc3ff2e0fdb4ee19d2a8212fa..97c2399293b7052d2875dde4536bf919b739ffa3 100644 (file)
@@ -580,6 +580,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
        mode &= S_IALLUGO & ~current->fs->umask;
        mode |= S_IFREG;
 
+       down(&dir->i_zombie);
        error = may_create(dir, dentry);
        if (error)
                goto exit_lock;
@@ -591,6 +592,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
        DQUOT_INIT(dir);
        error = dir->i_op->create(dir, dentry, mode);
 exit_lock:
+       up(&dir->i_zombie);
        return error;
 }
 
@@ -745,7 +747,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
 
        mode &= ~current->fs->umask;
 
-       if (!S_ISFIFO(mode) && !capable(CAP_MKNOD))
+       down(&dir->i_zombie);
+       if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
                goto exit_lock;
 
        error = may_create(dir, dentry);
@@ -759,6 +762,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
        DQUOT_INIT(dir);
        error = dir->i_op->mknod(dir, dentry, mode, dev);
 exit_lock:
+       up(&dir->i_zombie);
        return error;
 }
 
@@ -836,6 +840,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
        int error;
 
+       down(&dir->i_zombie);
        error = may_create(dir, dentry);
        if (error)
                goto exit_lock;
@@ -849,6 +854,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        error = dir->i_op->mkdir(dir, dentry, mode);
 
 exit_lock:
+       up(&dir->i_zombie);
        return error;
 }
 
@@ -901,6 +907,34 @@ asmlinkage long sys_mkdir(const char * pathname, int mode)
        return error;
 }
 
+/*
+ * We try to drop the dentry early: we should have
+ * a usage count of 2 if we're the only user of this
+ * dentry, and if that is true (possibly after pruning
+ * the dcache), then we drop the dentry now.
+ *
+ * A low-level filesystem can, if it choses, legally
+ * do a
+ *
+ *     if (!d_unhashed(dentry))
+ *             return -EBUSY;
+ *
+ * if it cannot handle the case of removing a directory
+ * that is still in use by something else..
+ */
+static void d_unhash(struct dentry *dentry)
+{
+       dget(dentry);
+       switch (dentry->d_count) {
+       default:
+               shrink_dcache_parent(dentry);
+               if (dentry->d_count != 2)
+                       break;
+       case 2:
+               d_drop(dentry);
+       }
+}
+
 int vfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int error;
@@ -914,31 +948,11 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
 
        DQUOT_INIT(dir);
 
-       /*
-        * We try to drop the dentry early: we should have
-        * a usage count of 2 if we're the only user of this
-        * dentry, and if that is true (possibly after pruning
-        * the dcache), then we drop the dentry now.
-        *
-        * A low-level filesystem can, if it choses, legally
-        * do a
-        *
-        *      if (!list_empty(&dentry->d_hash))
-        *              return -EBUSY;
-        *
-        * if it cannot handle the case of removing a directory
-        * that is still in use by something else..
-        */
-       switch (dentry->d_count) {
-       default:
-               shrink_dcache_parent(dentry);
-               if (dentry->d_count != 2)
-                       break;
-       case 2:
-               d_drop(dentry);
-       }
-
+       double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
+       d_unhash(dentry);
        error = dir->i_op->rmdir(dir, dentry);
+       double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
+       dput(dentry);
 
        return error;
 }
@@ -954,27 +968,11 @@ static inline int do_rmdir(const char * name)
        if (IS_ERR(dentry))
                goto exit;
 
-       error = -ENOENT;
-       if (!dentry->d_inode)
-               goto exit_dput;
-
-       dir = dget(dentry->d_parent);
-
-       /*
-        * The dentry->d_count stuff confuses d_delete() enough to
-        * not kill the inode from under us while it is locked. This
-        * wouldn't be needed, except the dentry semaphore is really
-        * in the inode, not in the dentry..
-        */
-       dentry->d_count++;
-       double_lock(dir, dentry);
-
+       dir = lock_parent(dentry);
        error = -ENOENT;
        if (check_parent(dir, dentry))
                error = vfs_rmdir(dir->d_inode, dentry);
-
-       double_unlock(dentry, dir);
-exit_dput:
+       unlock_dir(dir);
        dput(dentry);
 exit:
        return error;
@@ -1001,6 +999,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
+       down(&dir->i_zombie);
        error = may_delete(dir, dentry, 0);
        if (!error) {
                error = -EPERM;
@@ -1009,10 +1008,11 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
                        error = dir->i_op->unlink(dir, dentry);
                }
        }
+       up(&dir->i_zombie);
        return error;
 }
 
-static inline int do_unlink(const char * name)
+int do_unlink(const char * name)
 {
        int error;
        struct dentry *dir;
@@ -1054,6 +1054,7 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
 {
        int error;
 
+       down(&dir->i_zombie);
        error = may_create(dir, dentry);
        if (error)
                goto exit_lock;
@@ -1066,6 +1067,7 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
        error = dir->i_op->symlink(dir, dentry, oldname);
 
 exit_lock:
+       up(&dir->i_zombie);
        return error;
 }
 
@@ -1121,6 +1123,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
        struct inode *inode;
        int error;
 
+       down(&dir->i_zombie);
        error = -ENOENT;
        inode = old_dentry->d_inode;
        if (!inode)
@@ -1147,6 +1150,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
        error = dir->i_op->link(old_dentry, dir, new_dentry);
 
 exit_lock:
+       up(&dir->i_zombie);
        return error;
 }
 
@@ -1212,11 +1216,37 @@ asmlinkage long sys_link(const char * oldname, const char * newname)
        return error;
 }
 
+/*
+ * The worst of all namespace operations - renaming directory. "Perverted"
+ * doesn't even start to describe it. Somebody in UCB had a heck of a trip...
+ * Problems:
+ *     a) we can get into loop creation. Check is done in is_subdir().
+ *     b) race potential - two innocent renames can create a loop together.
+ *        That's where 4.4 screws up. Current fix: serialization on
+ *        sb->s_vfs_rename_sem. We might be more accurate, but that's another
+ *        story.
+ *     c) we have to lock _three_ objects - parents and victim (if it exists).
+ *        And that - after we got ->i_sem on parents (until then we don't know
+ *        whether the target exists at all, let alone whether it is a directory
+ *        or not). Solution: ->i_zombie. Taken only after ->i_sem. Always taken
+ *        on link creation/removal of any kind. And taken (without ->i_sem) on
+ *        directory that will be removed (both in rmdir() and here).
+ *     d) some filesystems don't support opened-but-unlinked directories,
+ *        either because of layout or because they are not ready to deal with
+ *        all cases correctly. The latter will be fixed (taking this sort of
+ *        stuff into VFS), but the former is not going away. Solution: the same
+ *        trick as in rmdir().
+ *     e) conversion from fhandle to dentry may come in the wrong moment - when
+ *        we are removing the target. Solution: we will have to grab ->i_zombie
+ *        in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on
+ *        ->i_sem on parents, which works but leads to some truely excessive
+ *        locking].
+ */
 int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
               struct inode *new_dir, struct dentry *new_dentry)
 {
        int error;
-       int need_rehash = 0;
+       struct inode *target;
 
        if (old_dentry->d_inode == new_dentry->d_inode)
                return 0;
@@ -1254,15 +1284,26 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
        error = -EINVAL;
        if (is_subdir(new_dentry, old_dentry))
                goto out_unlock;
-       if (new_dentry->d_inode) {
-               error = -EBUSY;
-               if (d_invalidate(new_dentry)<0)
-                       goto out_unlock;
-               need_rehash = 1;
-       }
+       target = new_dentry->d_inode;
+       if (target) { /* Hastur! Hastur! Hastur! */
+               triple_down(&old_dir->i_zombie,
+                           &new_dir->i_zombie,
+                           &target->i_zombie);
+               d_unhash(new_dentry);
+       } else
+               double_down(&old_dir->i_zombie,
+                           &new_dir->i_zombie);
        error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
-       if (need_rehash)
+       if (target) {
+               triple_up(&old_dir->i_zombie,
+                         &new_dir->i_zombie,
+                         &target->i_zombie);
                d_rehash(new_dentry);
+               dput(new_dentry);
+       } else
+               double_up(&old_dir->i_zombie,
+                         &new_dir->i_zombie);
+               
        if (!error)
                d_move(old_dentry,new_dentry);
 out_unlock:
@@ -1297,7 +1338,9 @@ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
 
        DQUOT_INIT(old_dir);
        DQUOT_INIT(new_dir);
+       double_down(&old_dir->i_zombie, &new_dir->i_zombie);
        error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+       double_up(&old_dir->i_zombie, &new_dir->i_zombie);
        if (error)
                return error;
        /* The following d_move() should become unconditional */
index ae5c139629b22347d9f1b446ea69303b2e6b61e9..f5a5856f3e32ce30588ff54ff4c5e168dd01d48a 100644 (file)
@@ -929,7 +929,7 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
                goto out;
 
        error = -EBUSY;
-       if (!list_empty(&dentry->d_hash))
+       if (!d_unhashed(dentry))
                goto out;
 
        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
@@ -1072,7 +1072,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
                case 0x00:
                                DPRINTK("ncp renamed %s -> %s.\n",
                                 old_dentry->d_name.name,new_dentry->d_name.name);
-                       /* d_move(old_dentry, new_dentry); */
                        break;
                case 0x9E:
                        error = -ENAMETOOLONG;
index 85cc9bd39181dc5f4e50534404e9b452dd35bcb8..fceffc04cc17fd5ef928bc8fa1fbc4d058d11242 100644 (file)
@@ -34,7 +34,7 @@
 static void ncp_put_inode(struct inode *);
 static void ncp_delete_inode(struct inode *);
 static void ncp_put_super(struct super_block *);
-static int  ncp_statfs(struct super_block *, struct statfs *, int);
+static int  ncp_statfs(struct super_block *, struct statfs *);
 
 static struct super_operations ncp_sops =
 {
@@ -527,25 +527,21 @@ static void ncp_put_super(struct super_block *sb)
        MOD_DEC_USE_COUNT;
 }
 
-static int ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int ncp_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
        /* We cannot say how much disk space is left on a mounted
           NetWare Server, because free space is distributed over
           volumes, and the current user might have disk quotas. So
           free space is not that simple to determine. Our decision
           here is to err conservatively. */
 
-       tmp.f_type = NCP_SUPER_MAGIC;
-       tmp.f_bsize = NCP_BLOCK_SIZE;
-       tmp.f_blocks = 0;
-       tmp.f_bfree = 0;
-       tmp.f_bavail = 0;
-       tmp.f_files = -1;
-       tmp.f_ffree = -1;
-       tmp.f_namelen = 12;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = NCP_SUPER_MAGIC;
+       buf->f_bsize = NCP_BLOCK_SIZE;
+       buf->f_blocks = 0;
+       buf->f_bfree = 0;
+       buf->f_bavail = 0;
+       buf->f_namelen = 12;
+       return 0;
 }
 
 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
index d111076c05ab0f85258e0bc234f363b182cee632..37b2b682b1886e76eeb1899b2c5b4cacf76fa2e2 100644 (file)
@@ -672,7 +672,7 @@ static void show_dentry(struct list_head * dlist)
                struct dentry * dentry = list_entry(tmp, struct dentry, d_alias);
                const char * unhashed = "";
 
-               if (list_empty(&dentry->d_hash))
+               if (d_unhashed(dentry))
                        unhashed = "(unhashed)";
 
                printk("show_dentry: %s/%s, d_count=%d%s\n",
@@ -1027,7 +1027,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
        /*
         * Unhash the dentry while we remove the file ...
         */
-       if (!list_empty(&dentry->d_hash)) {
+       if (!d_unhashed(dentry)) {
                d_drop(dentry);
                rehash = 1;
        }
@@ -1194,11 +1194,13 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
         * For files, make a copy of the dentry and then do a 
         * silly-rename. If the silly-rename succeeds, the
         * copied dentry is hashed and becomes the new target.
-        *
-        * With directories check is done in VFS.
         */
+       if (!new_inode)
+               goto go_ahead;
        error = -EBUSY;
-       if (new_dentry->d_count > 1 && new_inode) {
+       if (S_ISDIR(new_inode->i_mode))
+               goto out;
+       else if (new_dentry->d_count > 1) {
                int err;
                /* copy the target dentry's name */
                dentry = d_alloc(new_dentry->d_parent,
@@ -1227,6 +1229,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
        }
 
+go_ahead:
        /*
         * ... prune child dentries and writebacks if needed.
         */
@@ -1235,21 +1238,11 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                shrink_dcache_parent(old_dentry);
        }
 
-       if (new_dentry->d_count > 1 && new_inode) {
-#ifdef NFS_PARANOIA
-               printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n",
-                      new_dentry->d_parent->d_name.name,
-                      new_dentry->d_name.name,
-                      new_dentry->d_count);
-#endif
-               goto out;
-       }
-
        /*
         * To prevent any new references to the target during the rename,
         * we unhash the dentry and free the inode in advance.
         */
-       if (!list_empty(&new_dentry->d_hash)) {
+       if (!d_unhashed(new_dentry)) {
                d_drop(new_dentry);
                rehash = 1;
        }
index 7d2a6c146e7bbd51a19a05a740ade6f47faa9379..3b391094241560ed5b5b76f849626ee1805d9abd 100644 (file)
@@ -46,7 +46,7 @@ static void nfs_put_inode(struct inode *);
 static void nfs_delete_inode(struct inode *);
 static void nfs_put_super(struct super_block *);
 static void nfs_umount_begin(struct super_block *);
-static int  nfs_statfs(struct super_block *, struct statfs *, int);
+static int  nfs_statfs(struct super_block *, struct statfs *);
 
 static struct super_operations nfs_sops = { 
        read_inode:     nfs_read_inode,
@@ -367,27 +367,24 @@ out_fail:
 }
 
 static int
-nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+nfs_statfs(struct super_block *sb, struct statfs *buf)
 {
        int error;
        struct nfs_fsinfo res;
-       struct statfs tmp;
 
        error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
                &res);
        if (error) {
                printk("nfs_statfs: statfs error = %d\n", -error);
-               res.bsize = res.blocks = res.bfree = res.bavail = 0;
+               res.bsize = res.blocks = res.bfree = res.bavail = -1;
        }
-       tmp.f_type = NFS_SUPER_MAGIC;
-       tmp.f_bsize = res.bsize;
-       tmp.f_blocks = res.blocks;
-       tmp.f_bfree = res.bfree;
-       tmp.f_bavail = res.bavail;
-       tmp.f_files = 0;
-       tmp.f_ffree = 0;
-       tmp.f_namelen = NAME_MAX;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = NFS_SUPER_MAGIC;
+       buf->f_bsize = res.bsize;
+       buf->f_blocks = res.blocks;
+       buf->f_bfree = res.bfree;
+       buf->f_bavail = res.bavail;
+       buf->f_namelen = NAME_MAX;
+       return 0;
 }
 
 /*
@@ -413,7 +410,7 @@ restart:
                struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
                dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
                        dentry->d_parent->d_name.name, dentry->d_name.name,
-                       dentry->d_count, !list_empty(&dentry->d_hash));
+                       dentry->d_count, !d_unhashed(dentry));
                if (!list_empty(&dentry->d_subdirs))
                        shrink_dcache_parent(dentry);
                if (!dentry->d_count) {
@@ -422,7 +419,7 @@ restart:
                        dput(dentry);
                        goto restart;
                }
-               if (list_empty(&dentry->d_hash))
+               if (d_unhashed(dentry))
                        unhashed++;
        }
        return unhashed;
index 24a8208bbfbc766a3dc290568dd2fdb04b48f358..22bded69d2740fe90f75af201bbb53948303afcd 100644 (file)
@@ -66,8 +66,6 @@ static int                    want_lock = 0;
 static int                     hash_count = 0;
 static DECLARE_WAIT_QUEUE_HEAD(        hash_wait );
 
-#define READLOCK               0
-#define WRITELOCK              1
 
 /*
  * Find a client's export for a device.
index 4062410c6e62a087d68eff6dc3a54d2c4fa7a3b3..62dc72ad5f66b3cfd8ebe0011346039a63975b81 100644 (file)
@@ -39,11 +39,14 @@ nlm_fopen(struct svc_rqst *rqstp, struct knfs_fh *f, struct file *filp)
         *            1 = stale file handle
         *            2 = other error
         */
-       if (nfserr == 0)
+       switch (nfserr) {
+       case nfs_ok:
                return 0;
-       else if (nfserr == nfserr_stale)
+       case nfserr_stale:
                return 1;
-       else return 2;
+       default:
+               return 2;
+       }
 }
 
 static void
index 3b0de5545286b20dc77359005adaad18cd53fd86..c9430ae0344cc2d57260e3d6ecfe6531b3ad74a5 100644 (file)
@@ -28,7 +28,7 @@
 
 #define NFSDDBG_FACILITY               NFSDDBG_PROC
 
-#define RETURN(st)     { resp->status = (st); return (st); }
+#define RETURN_STATUS(st)      { resp->status = (st); return (st); }
 
 static int     nfs3_ftypes[] = {
        0,                      /* NF3NON */
@@ -75,7 +75,7 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
 
        fh_copy(&resp->fh, &argp->fh);
        nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -93,7 +93,7 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
 
        fh_copy(&resp->fh, &argp->fh);
        nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -115,7 +115,7 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
                                    argp->name,
                                    argp->len,
                                    &resp->fh);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -135,7 +135,7 @@ nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
        fh_copy(&resp->fh, &argp->fh);
        resp->access = argp->access;
        nfserr = nfsd_access(rqstp, &resp->fh, &resp->access);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -160,7 +160,7 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle     *argp,
        fh_copy(&resp->fh, &argp->fh);
        resp->len = NFS3_MAXPATHLEN;
        nfserr = nfsd_readlink(rqstp, &resp->fh, (char *) path, &resp->len);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -201,7 +201,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
                resp->eof = (argp->offset + resp->count) >= inode->i_size;
        }
 
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -221,14 +221,14 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
                                argp->stable? " stable" : "");
 
        fh_copy(&resp->fh, &argp->fh);
+       resp->committed = argp->stable;
        nfserr = nfsd_write(rqstp, &resp->fh,
                                   argp->offset,
                                   argp->data,
                                   argp->len,
-                                  argp->stable);
-       resp->committed = argp->stable;
+                                  &resp->committed);
        resp->count = argp->count;
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -256,7 +256,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
        /* Get the directory inode */
        nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_CREATE);
        if (nfserr)
-               RETURN(nfserr);
+               RETURN_STATUS(nfserr);
 
        /* Unfudge the mode bits */
        attr->ia_mode &= ~S_IFMT;
@@ -272,7 +272,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
                                attr, newfhp,
                                argp->createmode, argp->verf);
 
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -295,7 +295,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
        nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
                                    &argp->attrs, S_IFDIR, 0, &resp->fh);
 
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 static int
@@ -314,7 +314,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
        nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
                                                   argp->tname, argp->tlen,
                                                   &resp->fh, &argp->attrs);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -336,22 +336,22 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
        fh_init(&resp->fh);
 
        if (argp->ftype == 0 || argp->ftype >= NF3BAD)
-               return nfserr_inval;
+               RETURN_STATUS(nfserr_inval);
        if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
                if ((argp->ftype == NF3CHR && argp->major >= MAX_CHRDEV)
                    || (argp->ftype == NF3BLK && argp->major >= MAX_BLKDEV)
                    || argp->minor > 0xFF)
-                       return nfserr_inval;
+                       RETURN_STATUS(nfserr_inval);
                rdev = ((argp->major) << 8) | (argp->minor);
        } else
                if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
-                       return nfserr_inval;
+                       RETURN_STATUS(nfserr_inval);
 
        type = nfs3_ftypes[argp->ftype];
        nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
                                    &argp->attrs, type, rdev, &resp->fh);
 
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -371,7 +371,7 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
        /* Unlink. -S_IFDIR means file must not be a directory */
        fh_copy(&resp->fh, &argp->fh);
        nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -390,7 +390,7 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
 
        fh_copy(&resp->fh, &argp->fh);
        nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 static int
@@ -411,7 +411,7 @@ nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
        fh_copy(&resp->tfh, &argp->tfh);
        nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
                                    &resp->tfh, argp->tname, argp->tlen);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 static int
@@ -431,7 +431,7 @@ nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
        fh_copy(&resp->tfh, &argp->tfh);
        nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
                                  &resp->fh);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -467,7 +467,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
        memcpy(resp->verf, argp->verf, 8);
        resp->count = count;
 
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -503,7 +503,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
        memcpy(resp->verf, argp->verf, 8);
        resp->count = count;
 
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -521,7 +521,7 @@ nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
 
        nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
        fh_put(&argp->fh);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -562,7 +562,7 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
        }
 
        fh_put(&argp->fh);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 /*
@@ -605,7 +605,7 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle      *argp,
        }
 
        fh_put(&argp->fh);
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 
@@ -625,12 +625,12 @@ nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
                                (unsigned long) argp->offset);
 
        if (argp->offset > NFS_OFFSET_MAX)
-               return nfserr_inval;
+               RETURN_STATUS(nfserr_inval);
 
        fh_copy(&resp->fh, &argp->fh);
        nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
 
-       RETURN(nfserr);
+       RETURN_STATUS(nfserr);
 }
 
 
index b0aac328009de9026349f522dde49e81dd654723..634ca7cbf610944d2ba1efc28c22cd859bc82065 100644 (file)
@@ -63,7 +63,6 @@ void proc_export_init(void)
 static void
 nfsd_init(void)
 {
-       nfsd_xdr_init();        /* XDR */
        nfsd_stat_init();       /* Statistics */
        nfsd_cache_init();      /* RPC reply cache */
        nfsd_export_init();     /* Exports table */
index 084a17d9b502b72558125d5d43f6ef7881538712..9a26419aa801cdf4412e5d545764ac976a8e3cff 100644 (file)
@@ -550,7 +550,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                                        !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
 
                if (IS_ERR(dentry)) {
-                       error = nfserrno(-PTR_ERR(dentry));
+                       error = nfserrno(PTR_ERR(dentry));
                        goto out;
                }
 #ifdef NFSD_PARANOIA
index ef69be746779708a8ca46bd2d64e206026390cfa..20a68228b9e5194f14c5490a4d614c9b0ce82f6c 100644 (file)
@@ -30,7 +30,6 @@ typedef struct svc_buf        svc_buf;
 
 #define NFSDDBG_FACILITY               NFSDDBG_PROC
 
-#define RETURN(st)     return st
 
 static void
 svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr)
@@ -42,7 +41,7 @@ svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr)
 static int
 nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
-       RETURN(nfs_ok);
+       return nfs_ok;
 }
 
 /*
@@ -57,7 +56,7 @@ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
                SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh));
 
        fh_copy(&resp->fh, &argp->fh);
-       RETURN(fh_verify(rqstp, &resp->fh, 0, MAY_NOP));
+       return fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
 }
 
 /*
@@ -73,7 +72,7 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
                argp->attrs.ia_valid, (long) argp->attrs.ia_size);
 
        fh_copy(&resp->fh, &argp->fh);
-       RETURN(nfsd_setattr(rqstp, &resp->fh, &argp->attrs));
+       return nfsd_setattr(rqstp, &resp->fh, &argp->attrs);
 }
 
 /*
@@ -95,7 +94,7 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
                                 &resp->fh);
 
        fh_put(&argp->fh);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 /*
@@ -118,7 +117,7 @@ nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle     *argp,
        nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len);
 
        fh_put(&argp->fh);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 /*
@@ -156,7 +155,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
                                  (char *) buffer,
                                  &resp->count);
 
-       RETURN(nfserr);
+       return nfserr;
 }
 
 /*
@@ -168,6 +167,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
                                        struct nfsd_attrstat  *resp)
 {
        int     nfserr;
+       int     stable = 1;
 
        dprintk("nfsd: WRITE    %d/%d %d bytes at %d\n",
                SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh),
@@ -177,8 +177,8 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
                                   argp->offset,
                                   argp->data,
                                   argp->len,
-                                  0);
-       RETURN(nfserr);
+                                  &stable);
+       return nfserr;
 }
 
 /*
@@ -321,7 +321,7 @@ out_unlock:
 
 done:
        fh_put(dirfhp);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 static int
@@ -335,7 +335,7 @@ nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
        /* Unlink. -SIFDIR means file must not be a directory */
        nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
        fh_put(&argp->fh);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 static int
@@ -352,7 +352,7 @@ nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
                                    &argp->tfh, argp->tname, argp->tlen);
        fh_put(&argp->ffh);
        fh_put(&argp->tfh);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 static int
@@ -370,7 +370,7 @@ nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
                                  &argp->ffh);
        fh_put(&argp->ffh);
        fh_put(&argp->tfh);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 static int
@@ -394,7 +394,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
 
        fh_put(&argp->ffh);
        fh_put(&newfh);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 /*
@@ -418,7 +418,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
        nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
                                    &argp->attrs, S_IFDIR, 0, &resp->fh);
        fh_put(&argp->fh);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 /*
@@ -434,7 +434,7 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
 
        nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
        fh_put(&argp->fh);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 /*
@@ -470,7 +470,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
        resp->count = count;
 
        fh_put(&argp->fh);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 /*
@@ -486,7 +486,7 @@ nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle   *argp,
 
        nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
        fh_put(&argp->fh);
-       RETURN(nfserr);
+       return nfserr;
 }
 
 /*
@@ -539,36 +539,36 @@ nfserrno (int errno)
                int     nfserr;
                int     syserr;
        } nfs_errtbl[] = {
-               { NFS_OK, 0 },
-               { NFSERR_PERM, EPERM },
-               { NFSERR_NOENT, ENOENT },
-               { NFSERR_IO, EIO },
-               { NFSERR_NXIO, ENXIO },
-               { NFSERR_ACCES, EACCES },
-               { NFSERR_EXIST, EEXIST },
-               { NFSERR_XDEV, EXDEV },
-               { NFSERR_MLINK, EMLINK },
-               { NFSERR_NODEV, ENODEV },
-               { NFSERR_NOTDIR, ENOTDIR },
-               { NFSERR_ISDIR, EISDIR },
-               { NFSERR_INVAL, EINVAL },
-               { NFSERR_FBIG, EFBIG },
-               { NFSERR_NOSPC, ENOSPC },
-               { NFSERR_ROFS, EROFS },
-               { NFSERR_MLINK, EMLINK },
-               { NFSERR_NAMETOOLONG, ENAMETOOLONG },
-               { NFSERR_NOTEMPTY, ENOTEMPTY },
+               { nfs_ok, 0 },
+               { nfserr_perm, -EPERM },
+               { nfserr_noent, -ENOENT },
+               { nfserr_io, -EIO },
+               { nfserr_nxio, -ENXIO },
+               { nfserr_acces, -EACCES },
+               { nfserr_exist, -EEXIST },
+               { nfserr_xdev, -EXDEV },
+               { nfserr_mlink, -EMLINK },
+               { nfserr_nodev, -ENODEV },
+               { nfserr_notdir, -ENOTDIR },
+               { nfserr_isdir, -EISDIR },
+               { nfserr_inval, -EINVAL },
+               { nfserr_fbig, -EFBIG },
+               { nfserr_nospc, -ENOSPC },
+               { nfserr_rofs, -EROFS },
+               { nfserr_mlink, -EMLINK },
+               { nfserr_nametoolong, -ENAMETOOLONG },
+               { nfserr_notempty, -ENOTEMPTY },
 #ifdef EDQUOT
-               { NFSERR_DQUOT, EDQUOT },
+               { nfserr_dquot, -EDQUOT },
 #endif
-               { NFSERR_STALE, ESTALE },
-               { -1, EIO }
+               { nfserr_stale, -ESTALE },
+               { -1, -EIO }
        };
        int     i;
 
        for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
                if (nfs_errtbl[i].syserr == errno)
-                       return htonl(nfs_errtbl[i].nfserr);
+                       return nfs_errtbl[i].nfserr;
        }
        printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno);
        return nfserr_io;
index 3afe9f83eedb3f573296e657ee6702621dde25ae..b5ad1c07704fe2a6c81d2c0462e60679b597715b 100644 (file)
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
-u32    nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio,
-       nfserr_acces, nfserr_exist, nfserr_xdev, nfserr_nodev,
-       nfserr_notdir, nfserr_isdir, nfserr_inval, nfserr_fbig,
-       nfserr_nospc, nfserr_rofs, nfserr_mlink,
-       nfserr_nametoolong, nfserr_notempty, nfserr_dquot, nfserr_stale,
-       nfserr_remote, nfserr_badhandle, nfserr_notsync,
-       nfserr_badcookie, nfserr_notsupp, nfserr_toosmall,
-       nfserr_serverfault, nfserr_badtype, nfserr_jukebox;
-
 
 #ifdef NFSD_OPTIMIZE_SPACE
 # define inline
@@ -41,51 +32,6 @@ static u32   nfs_ftypes[] = {
        NFSOCK, NFBAD,  NFLNK, NFBAD,
 };
 
-/*
- * Initialization of NFS status variables
- */
-void
-nfsd_xdr_init(void)
-{
-       static int      inited = 0;
-
-       if (inited)
-               return;
-
-       nfs_ok          = htonl(NFS_OK);
-       nfserr_perm     = htonl(NFSERR_PERM);
-       nfserr_noent    = htonl(NFSERR_NOENT);
-       nfserr_io       = htonl(NFSERR_IO);
-       nfserr_inval    = htonl(NFSERR_INVAL);
-       nfserr_nxio     = htonl(NFSERR_NXIO);
-       nfserr_acces    = htonl(NFSERR_ACCES);
-       nfserr_exist    = htonl(NFSERR_EXIST);
-       nfserr_xdev     = htonl(NFSERR_XDEV);
-       nfserr_nodev    = htonl(NFSERR_NODEV);
-       nfserr_notdir   = htonl(NFSERR_NOTDIR);
-       nfserr_isdir    = htonl(NFSERR_ISDIR);
-       nfserr_inval    = htonl(NFSERR_INVAL);
-       nfserr_fbig     = htonl(NFSERR_FBIG);
-       nfserr_nospc    = htonl(NFSERR_NOSPC);
-       nfserr_rofs     = htonl(NFSERR_ROFS);
-       nfserr_mlink    = htonl(NFSERR_MLINK);
-       nfserr_nametoolong = htonl(NFSERR_NAMETOOLONG);
-       nfserr_notempty = htonl(NFSERR_NOTEMPTY);
-       nfserr_dquot    = htonl(NFSERR_DQUOT);
-       nfserr_stale    = htonl(NFSERR_STALE);
-       nfserr_remote   = htonl(NFSERR_REMOTE);
-       nfserr_badhandle = htonl(NFSERR_BADHANDLE);
-       nfserr_notsync  = htonl(NFSERR_NOT_SYNC);
-       nfserr_badcookie = htonl(NFSERR_BAD_COOKIE);
-       nfserr_notsupp  = htonl(NFSERR_NOTSUPP);
-       nfserr_toosmall = htonl(NFSERR_TOOSMALL);
-       nfserr_serverfault = htonl(NFSERR_SERVERFAULT);
-       nfserr_badtype  = htonl(NFSERR_BADTYPE);
-       nfserr_jukebox  = htonl(NFSERR_JUKEBOX);
-
-
-       inited = 1;
-}
 
 /*
  * XDR functions for basic NFS types
index c8389381f0ee08f89204799a58c70f1d50692ec8..7cb4e4bc3de0145013ebea901dee50122ad84393 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/config.h>
 #include <linux/version.h>
+#include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
@@ -92,7 +93,7 @@ static struct raparms *               raparm_cache = NULL;
  * the check_parent in linux/fs/namei.c.
  */
 #define nfsd_check_parent(dir, dentry) \
-       ((dir) == (dentry)->d_parent && !list_empty(&dentry->d_hash))
+       ((dir) == (dentry)->d_parent && !d_unhashed(dentry))
 
 /*
  * Lock a parent directory following the VFS locking protocol.
@@ -195,7 +196,7 @@ out:
        return err;
 
 out_nfserr:
-       err = nfserrno(-PTR_ERR(dchild));
+       err = nfserrno(PTR_ERR(dchild));
        goto out;
 }
 
@@ -261,8 +262,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
 
        /* The size case is special. It changes the file as well as the attributes.  */
        if (iap->ia_valid & ATTR_SIZE) {
-if (!S_ISREG(inode->i_mode))
-printk("nfsd_setattr: size change??\n");
                if (iap->ia_size < inode->i_size) {
                        err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
                        if (err)
@@ -326,7 +325,7 @@ out:
        return err;
 
 out_nfserr:
-       err = nfserrno(-err);
+       err = nfserrno(err);
        goto out;
 }
 
@@ -393,18 +392,19 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access)
                if (map->access & query) {
                        unsigned int err2;
                        err2 = nfsd_permission(export, dentry, map->how);
-                       /* cannot use a "switch" as nfserr_* are variables, even though they are constant :-( */
-                       if (err2 == 0)
+                       switch (err2) {
+                       case nfs_ok:
                                result |= map->access;
+                               break;
+                               
                        /* the following error codes just mean the access was not allowed,
                         * rather than an error occurred */
-                       else if (err2 == nfserr_rofs ||
-                                err2 == nfserr_acces ||
-                                err2 == nfserr_perm
-                               )
+                       case nfserr_rofs:
+                       case nfserr_acces:
+                       case nfserr_perm:
                                /* simply don't "or" in the access bit. */
-                                       ;
-                       else {
+                               break;
+                       default:
                                error = err2;
                                goto out;
                        }
@@ -482,7 +482,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        }
 out_nfserr:
        if (err)
-               err = nfserrno(-err);
+               err = nfserrno(err);
 out:
        return err;
 }
@@ -618,7 +618,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
                *count = err;
                err = 0;
        } else 
-               err = nfserrno(-err);
+               err = nfserrno(err);
 out_close:
        nfsd_close(&file);
 out:
@@ -632,7 +632,7 @@ out:
  */
 int
 nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
-                               char *buf, unsigned long cnt, int stable)
+                               char *buf, unsigned long cnt, int *stablep)
 {
        struct svc_export       *exp;
        struct file             file;
@@ -640,6 +640,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
        struct inode            *inode;
        mm_segment_t            oldfs;
        int                     err = 0;
+       int                     stable = *stablep;
 #ifdef CONFIG_QUOTA
        uid_t                   saved_euid;
 #endif
@@ -666,10 +667,12 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
         * flushing the data to disk is handled separately below.
         */
 #ifdef CONFIG_NFSD_V3
-       if (rqstp->rq_vers == 2)
-               stable = EX_ISSYNC(exp);
-       else if (file.f_op->fsync == 0)
-              stable = 1;
+       if (file.f_op->fsync == 0) {/* COMMIT3 cannot work */
+              stable = 2;
+              *stablep = 2; /* FILE_SYNC */
+       }
+       if (!EX_ISSYNC(exp))
+               stable = 0;
        if (stable && !EX_WGATHER(exp))
                file.f_flags |= O_SYNC;
 #else
@@ -749,7 +752,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
        if (err >= 0)
                err = 0;
        else 
-               err = nfserrno(-err);
+               err = nfserrno(err);
 out_close:
        nfsd_close(&file);
 out:
@@ -774,11 +777,12 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
 
        if ((err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file)) != 0)
                return err;
-
-       if (file.f_op && file.f_op->fsync) {
-               nfsd_sync(&file);
-       } else {
-               err = nfserr_notsupp;
+       if (EX_ISSYNC(fhp->fh_export)) {
+               if (file.f_op && file.f_op->fsync) {
+                       nfsd_sync(&file);
+               } else {
+                       err = nfserr_notsupp;
+               }
        }
 
        nfsd_close(&file);
@@ -905,7 +909,7 @@ out:
        return err;
 
 out_nfserr:
-       err = nfserrno(-err);
+       err = nfserrno(err);
        goto out;
 }
 
@@ -1021,7 +1025,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
        return err;
  
  out_nfserr:
-       err = nfserrno(-err);
+       err = nfserrno(err);
        goto out;
 }
 #endif /* CONFIG_NFSD_V3 */
@@ -1067,7 +1071,7 @@ out:
        return err;
 
 out_nfserr:
-       err = nfserrno(-err);
+       err = nfserrno(err);
        goto out;
 }
 
@@ -1122,7 +1126,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
                       }
                }
        } else
-               err = nfserrno(-err);
+               err = nfserrno(err);
        fh_unlock(fhp);
 
        /* Compose the fh so the dentry will be freed ... */
@@ -1132,7 +1136,7 @@ out:
        return err;
 
 out_nfserr:
-       err = nfserrno(-err);
+       err = nfserrno(err);
        goto out;
 }
 
@@ -1186,7 +1190,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
                if (err == -EXDEV && rqstp->rq_vers == 2)
                        err = nfserr_acces;
                else
-                       err = nfserrno(-err);
+                       err = nfserrno(err);
        }
 
        fh_unlock(ffhp);
@@ -1196,7 +1200,7 @@ out:
        return err;
 
 out_nfserr:
-       err = nfserrno(-err);
+       err = nfserrno(err);
        goto out;
 }
 
@@ -1318,7 +1322,7 @@ out:
        return err;
 
 out_nfserr:
-       err = nfserrno(-err);
+       err = nfserrno(err);
        goto out;
 }
 
@@ -1356,47 +1360,19 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                goto out;
        }
 
+       err = fh_lock_parent(fhp, rdentry);
+       if (err)
+               goto out;
 
-       if (type != S_IFDIR) {
-               /* It's UNLINK */
-
-               err = fh_lock_parent(fhp, rdentry);
-               if (err)
-                       goto out;
-
+       if (type != S_IFDIR) { /* It's UNLINK */
                err = vfs_unlink(dirp, rdentry);
+       } else { /* It's RMDIR */
+               err = vfs_rmdir(dirp, rdentry);
+       }
 
-               fh_unlock(fhp);
-
-               dput(rdentry);
-
-       } else {
-               /* It's RMDIR */
-               /* See comments in fs/namei.c:do_rmdir */
-
-               rdentry->d_count++;
-               nfsd_double_down(&dirp->i_sem, &rdentry->d_inode->i_sem);
-
-#ifdef CONFIG_NFSD_V3
-               fill_pre_wcc(fhp);
-#else
-               fhp->fh_locked = 1;
-#endif /* CONFIG_NFSD_V3 */
-
-               err = -ENOENT;
-               if (nfsd_check_parent(dentry, rdentry))
-                       err = vfs_rmdir(dirp, rdentry);
-
-               rdentry->d_count--;
-#ifdef CONFIG_NFSD_V3
-               fill_post_wcc(fhp);
-#else
-               fhp->fh_locked = 0;
-#endif /* CONFIG_NFSD_V3 */
-               nfsd_double_up(&dirp->i_sem, &rdentry->d_inode->i_sem);
+       fh_unlock(fhp);
 
-               dput(rdentry);
-       }
+       dput(rdentry);
 
        if (err)
                goto out_nfserr;
@@ -1409,7 +1385,7 @@ out:
        return err;
 
 out_nfserr:
-       err = nfserrno(-err);
+       err = nfserrno(err);
        goto out;
 }
 
@@ -1499,7 +1475,7 @@ out:
        return err;
 
 out_nfserr:
-       err = nfserrno(-err);
+       err = nfserrno(err);
        goto out_close;
 }
 
@@ -1510,29 +1486,9 @@ out_nfserr:
 int
 nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct statfs *stat)
 {
-       struct dentry           *dentry;
-       struct inode            *inode;
-       struct super_block      *sb;
-       mm_segment_t            oldfs;
-       int                     err;
-
-       err = fh_verify(rqstp, fhp, 0, MAY_NOP);
-       if (err)
-               goto out;
-       dentry = fhp->fh_dentry;
-       inode = dentry->d_inode;
-
-       err = nfserr_io;
-       if (!(sb = inode->i_sb) || !sb->s_op->statfs)
-               goto out;
-
-       oldfs = get_fs();
-       set_fs (KERNEL_DS);
-       sb->s_op->statfs(sb, stat, sizeof(*stat));
-       set_fs (oldfs);
-       err = 0;
-
-out:
+       int err = fh_verify(rqstp, fhp, 0, MAY_NOP);
+       if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat))
+               err = nfserr_io;
        return err;
 }
 
@@ -1617,7 +1573,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
        if (current->fsuid != 0)
                current->cap_effective = saved_cap;
 
-       return err? nfserrno(-err) : 0;
+       return err? nfserrno(err) : 0;
 }
 
 void
index 89888bb6025bc4b17c214ef70d0319187433e256..7eef467363324414e69d3ee6d43042935f070e51 100644 (file)
@@ -750,9 +750,8 @@ static void ntfs_put_super(struct super_block *sb)
 }
 
 /* Called by the kernel when asking for stats */
-static int ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize)
+static int ntfs_statfs(struct super_block *sb, struct statfs *sf)
 {
-       struct statfs fs;
        struct inode *mft;
        ntfs_volume *vol;
        ntfs_u64 size;
@@ -760,30 +759,26 @@ static int ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize)
 
        ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n");
        vol=NTFS_SB2VOL(sb);
-       memset(&fs,0,sizeof(fs));
-       fs.f_type=NTFS_SUPER_MAGIC;
-       fs.f_bsize=vol->clustersize;
+       sf->f_type=NTFS_SUPER_MAGIC;
+       sf->f_bsize=vol->clustersize;
 
        error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &size );
        if( error )
                return -error;
-       fs.f_blocks = size;     /* volumesize is in clusters */
-       fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap);
-       fs.f_bavail=fs.f_bfree;
+       sf->f_blocks = size;    /* volumesize is in clusters */
+       sf->f_bfree=ntfs_get_free_cluster_count(vol->bitmap);
+       sf->f_bavail=sf->f_bfree;
 
-       /* Number of files is limited by free space only, so we lie here */
-       fs.f_ffree=0;
        mft=iget(sb,FILE_MFT);
        if (!mft)
                return -EIO;
        /* So ... we lie... thus this following cast of loff_t value
           is ok here.. */
-       fs.f_files = (unsigned long)mft->i_size / vol->mft_recordsize;
+       sf->f_files = (unsigned long)mft->i_size / vol->mft_recordsize;
        iput(mft);
 
        /* should be read from volume */
-       fs.f_namelen=255;
-       copy_to_user(sf,&fs,bufsize);
+       sf->f_namelen=255;
        return 0;
 }
 
index e7b119df70bb24f1e680ab8c5b0d7a0e6e873dae..6b11f4ab0ed89099d219cabc53e5f5bc5f0533fc 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/utime.h>
 #include <linux/file.h>
@@ -21,13 +22,10 @@ asmlinkage long sys_statfs(const char * path, struct statfs * buf)
        dentry = namei(path);
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
-               struct inode * inode = dentry->d_inode;
-               struct super_block * sb = inode->i_sb;
-
-               error = -ENODEV;
-               if (sb && sb->s_op && sb->s_op->statfs)
-                       error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
-
+               struct statfs tmp;
+               error = vfs_statfs(dentry->d_inode->i_sb, &tmp);
+               if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
+                       error = -EFAULT;
                dput(dentry);
        }
        unlock_kernel();
@@ -37,18 +35,17 @@ asmlinkage long sys_statfs(const char * path, struct statfs * buf)
 asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf)
 {
        struct file * file;
-       struct super_block * sb;
+       struct statfs tmp;
        int error;
 
        error = -EBADF;
        file = fget(fd);
        if (!file)
                goto out;
-       error = -ENODEV;
-       sb = file->f_dentry->d_inode->i_sb;
        lock_kernel();
-       if (sb && sb->s_op && sb->s_op->statfs)
-               error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
+       error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
+       if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
+               error = -EFAULT;
        unlock_kernel();
        fput(file);
 out:
index 1f9139a51419e3106aa7f75b0a37fca4a88192fc..87576a4dbd73ab5b0068df491dadee12d6b9786a 100644 (file)
@@ -985,19 +985,15 @@ static void openprom_put_super(struct super_block *sb)
        MOD_DEC_USE_COUNT;
 }
 
-static int openprom_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int openprom_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       tmp.f_type = OPENPROM_SUPER_MAGIC;
-       tmp.f_bsize = PAGE_SIZE/sizeof(long);   /* ??? */
-       tmp.f_blocks = 0;
-       tmp.f_bfree = 0;
-       tmp.f_bavail = 0;
-       tmp.f_files = 0;
-       tmp.f_ffree = 0;
-       tmp.f_namelen = NAME_MAX;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = OPENPROM_SUPER_MAGIC;
+       buf->f_bsize = PAGE_SIZE/sizeof(long);  /* ??? */
+       buf->f_bfree = 0;
+       buf->f_bavail = 0;
+       buf->f_ffree = 0;
+       buf->f_namelen = NAME_MAX;
+       return 0;
 }
 
 static struct super_operations openprom_sops = { 
index 3774308608d22876368784f37c58b0f5e950f732..5d58763c4d545fb9086671409f7f7ec992efe9b7 100644 (file)
@@ -151,12 +151,13 @@ static inline char * task_state(struct task_struct *p, char *buffer)
                "State:\t%s\n"
                "Pid:\t%d\n"
                "PPid:\t%d\n"
+               "TracerPid:\t%d\n"
                "Uid:\t%d\t%d\t%d\t%d\n"
                "Gid:\t%d\t%d\t%d\t%d\n"
                "FDSize:\t%d\n"
                "Groups:\t",
                get_task_state(p),
-               p->pid, p->p_pptr->pid,
+               p->pid, p->p_opptr->pid, p->p_pptr->pid != p->p_opptr->pid ? p->p_opptr->pid : 0,
                p->uid, p->euid, p->suid, p->fsuid,
                p->gid, p->egid, p->sgid, p->fsgid,
                p->files ? p->files->max_fds : 0);
@@ -327,7 +328,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
                task->pid,
                task->comm,
                state,
-               task->p_pptr->pid,
+               task->p_opptr->pid,
                task->pgrp,
                task->session,
                task->tty ? kdev_t_to_nr(task->tty->device) : 0,
index 84a23a7f52b113d6915ece462dc632ef33e4ade6..12bfd46112e8d18d705033c7ba7cfc2a9a287ecd 100644 (file)
@@ -100,19 +100,15 @@ static void proc_read_inode(struct inode * inode)
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 }
 
-static int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int proc_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       tmp.f_type = PROC_SUPER_MAGIC;
-       tmp.f_bsize = PAGE_SIZE/sizeof(long);
-       tmp.f_blocks = 0;
-       tmp.f_bfree = 0;
-       tmp.f_bavail = 0;
-       tmp.f_files = 0;
-       tmp.f_ffree = 0;
-       tmp.f_namelen = NAME_MAX;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = PROC_SUPER_MAGIC;
+       buf->f_bsize = PAGE_SIZE/sizeof(long);
+       buf->f_bfree = 0;
+       buf->f_bavail = 0;
+       buf->f_ffree = 0;
+       buf->f_namelen = NAME_MAX;
+       return 0;
 }
 
 static struct super_operations proc_sops = { 
index 49bad450ee74195917cbe4255e78241e47cf58d6..3fe876e96f39dd11272cd97f2df4544efc031077 100644 (file)
@@ -117,7 +117,7 @@ static struct super_block *qnx4_read_super(struct super_block *, void *, int);
 static void qnx4_put_super(struct super_block *sb);
 static void qnx4_read_inode(struct inode *);
 static int qnx4_remount(struct super_block *sb, int *flags, char *data);
-static int qnx4_statfs(struct super_block *, struct statfs *, int);
+static int qnx4_statfs(struct super_block *, struct statfs *);
 
 static struct super_operations qnx4_sops =
 {
@@ -269,22 +269,16 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
        return block;
 }
 
-static int qnx4_statfs(struct super_block *sb,
-                      struct statfs *buf, int bufsize)
+static int qnx4_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       memset(&tmp, 0, sizeof tmp);
-       tmp.f_type    = sb->s_magic;
-       tmp.f_bsize   = sb->s_blocksize;
-       tmp.f_blocks  = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size) * 8;
-       tmp.f_bfree   = qnx4_count_free_blocks(sb);
-       tmp.f_bavail  = tmp.f_bfree;
-       tmp.f_files   = -1;     /* we don't count files */
-       tmp.f_ffree   = -1;     /* inodes are allocated dynamically */
-       tmp.f_namelen = QNX4_NAME_MAX;
-
-       return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
+       buf->f_type    = sb->s_magic;
+       buf->f_bsize   = sb->s_blocksize;
+       buf->f_blocks  = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size) * 8;
+       buf->f_bfree   = qnx4_count_free_blocks(sb);
+       buf->f_bavail  = buf->f_bfree;
+       buf->f_namelen = QNX4_NAME_MAX;
+
+       return 0;
 }
 
 /*
index 0defa3dcb5c1256ea7db28d1e46d014aae61ceba..a25200b14d8cdeb77703901782fef3c0942e0067 100644 (file)
@@ -171,7 +171,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
                goto end_rmdir;
        }
 #endif
-       if (!list_empty(&dentry->d_hash)) {
+       if (!d_unhashed(dentry)) {
                retval = -EBUSY;
                goto end_rmdir;
        }
index b95dfa219d95bb938bd9d90384d37c4fcf527479..1180e0912e323d7f982ca752b38de8a8cfe1c663 100644 (file)
@@ -181,16 +181,14 @@ romfs_put_super(struct super_block *sb)
 /* That's simple too. */
 
 static int
-romfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
+romfs_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.f_type = ROMFS_MAGIC;
-       tmp.f_bsize = ROMBSIZE;
-       tmp.f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
-       tmp.f_namelen = ROMFS_MAXFN;
-       return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
+       buf->f_type = ROMFS_MAGIC;
+       buf->f_bsize = ROMBSIZE;
+       buf->f_bfree = buf->f_bavail = buf->f_ffree;
+       buf->f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
+       buf->f_namelen = ROMFS_MAXFN;
+       return 0;
 }
 
 /* some helper routines */
index 91061a28ffd74073950de8acd5e8e36e3725482d..a29e55c7a78e1e6c3afc318a845c5968184d9e43 100644 (file)
@@ -443,7 +443,7 @@ smb_rmdir(struct inode *dir, struct dentry *dentry)
         * Check that nobody else is using the directory..
         */
        error = -EBUSY;
-       if (!list_empty(&dentry->d_hash))
+       if (!d_unhashed(dentry))
                goto out;
 
        smb_invalid_dir_cache(dir);
index 3b13fdd8041375a79ab56d3ccb2a4625b19a27cb..c3a7b58480b888d356c24c1b3b0fcdd3aec921bc 100644 (file)
@@ -32,7 +32,7 @@
 static void smb_put_inode(struct inode *);
 static void smb_delete_inode(struct inode *);
 static void smb_put_super(struct super_block *);
-static int  smb_statfs(struct super_block *, struct statfs *, int);
+static int  smb_statfs(struct super_block *, struct statfs *);
 static void smb_set_inode_attr(struct inode *, struct smb_fattr *);
 
 static struct super_operations smb_sops =
@@ -415,19 +415,13 @@ out_fail:
 }
 
 static int
-smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+smb_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs attr;
+       smb_proc_dskattr(sb, buf);
 
-       memset(&attr, 0, sizeof(attr));
-
-       smb_proc_dskattr(sb, &attr);
-
-       attr.f_type = SMB_SUPER_MAGIC;
-       attr.f_files = -1;
-       attr.f_ffree = -1;
-       attr.f_namelen = SMB_MAXPATHLEN;
-       return copy_to_user(buf, &attr, bufsiz) ? -EFAULT : 0;
+       buf->f_type = SMB_SUPER_MAGIC;
+       buf->f_namelen = SMB_MAXPATHLEN;
+       return 0;
 }
 
 int
index e41e1d71d58f0f04549075c224a64366a689f891..10ac19f2dc3020a7aaeeea239886295a877e6034 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/string.h>
 #include <linux/malloc.h>
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
@@ -480,21 +481,15 @@ asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf)
         struct super_block *s;
         struct ustat tmp;
         struct statfs sbuf;
-        mm_segment_t old_fs;
        int err = -EINVAL;
 
        lock_kernel();
         s = get_super(to_kdev_t(dev));
         if (s == NULL)
                 goto out;
-       err = -ENOSYS;
-        if (!(s->s_op->statfs))
-                goto out;
-
-        old_fs = get_fs();
-        set_fs(get_ds());
-        s->s_op->statfs(s,&sbuf,sizeof(struct statfs));
-        set_fs(old_fs);
+       err = vfs_statfs(s, &sbuf);
+       if (err)
+               goto out;
 
         memset(&tmp,0,sizeof(struct ustat));
         tmp.f_tfree = sbuf.f_bfree;
index 2c79b3c71a21eccf4d190e15619fdabfd56ec5a6..2b52600cf8dcd7b52ba354011e241603370e5daf 100644 (file)
@@ -68,7 +68,7 @@ static void sysv_delete_inode(struct inode *inode)
 static void sysv_put_super(struct super_block *);
 static void sysv_write_super(struct super_block *);
 static void sysv_read_inode(struct inode *);
-static int sysv_statfs(struct super_block *, struct statfs *, int);
+static int sysv_statfs(struct super_block *, struct statfs *);
 
 static struct super_operations sysv_sops = {
        read_inode:     sysv_read_inode,
@@ -562,20 +562,18 @@ static void sysv_put_super(struct super_block *sb)
        MOD_DEC_USE_COUNT;
 }
 
-static int sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int sysv_statfs(struct super_block *sb, struct statfs *buf)
 {
-       struct statfs tmp;
-
-       tmp.f_type = sb->s_magic;                       /* type of filesystem */
-       tmp.f_bsize = sb->sv_block_size;                /* block size */
-       tmp.f_blocks = sb->sv_ndatazones;               /* total data blocks in file system */
-       tmp.f_bfree = sysv_count_free_blocks(sb);       /* free blocks in fs */
-       tmp.f_bavail = tmp.f_bfree;                     /* free blocks available to non-superuser */
-       tmp.f_files = sb->sv_ninodes;                   /* total file nodes in file system */
-       tmp.f_ffree = sysv_count_free_inodes(sb);       /* free file nodes in fs */
-       tmp.f_namelen = SYSV_NAMELEN;
-       /* Don't know what value to put in tmp.f_fsid */ /* file system id */
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_type = sb->s_magic;                      /* type of filesystem */
+       buf->f_bsize = sb->sv_block_size;               /* block size */
+       buf->f_blocks = sb->sv_ndatazones;              /* total data blocks in file system */
+       buf->f_bfree = sysv_count_free_blocks(sb);      /* free blocks in fs */
+       buf->f_bavail = buf->f_bfree;                   /* free blocks available to non-superuser */
+       buf->f_files = sb->sv_ninodes;                  /* total file nodes in file system */
+       buf->f_ffree = sysv_count_free_inodes(sb);      /* free file nodes in fs */
+       buf->f_namelen = SYSV_NAMELEN;
+       /* Don't know what value to put in buf->f_fsid */ /* file system id */
+       return 0;
 }
 
 
index a7b871073a59b88fb92e931875375e85176b86d3..6a7fbf34b6fcad71f879f7c566016e6f122933b8 100644 (file)
@@ -389,7 +389,7 @@ static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
                retval = -ENOTEMPTY;
                goto end_rmdir;
        }
-       if (!list_empty(&dentry->d_hash)) {
+       if (!d_unhashed(dentry)) {
                retval = -EBUSY;
                goto end_rmdir;
        }
@@ -552,6 +552,9 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
        }
        if (S_ISDIR(old_inode->i_mode)) {
                if (new_inode) {
+                       retval = -EBUSY;
+                       if (!d_unhashed(new_dentry))
+                               goto end_rename;
                        retval = -ENOTEMPTY;
                        if (!empty_dir(new_inode))
                                goto end_rename;
index db140e66e9f6ec3349479b9beade78068a123e84..c371b5d52cd3d1ebbb972d70f2914bc818694331 100644 (file)
@@ -1165,6 +1165,9 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
 
                if (new_inode)
                {
+                       retval = -EBUSY;
+                       if (!d_unhashed(new_dentry))
+                               goto end_rename;
                        retval = -ENOTEMPTY;
                        if (!empty_dir(new_inode))
                                goto end_rename;
index 6b3e32f038d15d2ad254b662e9d47ca8bd7ea5aa..488e99ef6f6376f94eeda42fa9aab247f9b72895 100644 (file)
@@ -93,7 +93,7 @@ static void udf_load_partdesc(struct super_block *, struct buffer_head *);
 static void udf_open_lvid(struct super_block *);
 static void udf_close_lvid(struct super_block *);
 static unsigned int udf_count_free(struct super_block *);
-static int udf_statfs(struct super_block *, struct statfs *, int);
+static int udf_statfs(struct super_block *, struct statfs *);
 
 /* UDF filesystem type */
 static struct file_system_type udf_fstype = {
@@ -1548,29 +1548,21 @@ udf_put_super(struct super_block *sb)
  *     Written, tested, and released.
  */
 static int
-udf_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
+udf_statfs(struct super_block *sb, struct statfs *buf)
 {
-       int size;
-       struct statfs tmp;
-       int rc;
-
-       size = (bufsize < sizeof(tmp)) ? bufsize: sizeof(tmp);
-
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.f_type = UDF_SUPER_MAGIC;
-       tmp.f_bsize = sb->s_blocksize;
-       tmp.f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
-       tmp.f_bfree = udf_count_free(sb);
-       tmp.f_bavail = tmp.f_bfree;
-       tmp.f_files = (UDF_SB_LVIDBH(sb) ?
+       buf->f_type = UDF_SUPER_MAGIC;
+       buf->f_bsize = sb->s_blocksize;
+       buf->f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
+       buf->f_bfree = udf_count_free(sb);
+       buf->f_bavail = buf->f_bfree;
+       buf->f_files = (UDF_SB_LVIDBH(sb) ?
                (le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) +
-               le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + tmp.f_bfree;
-       tmp.f_ffree = tmp.f_bfree;
+               le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree;
+       buf->f_ffree = buf->f_bfree;
        /* __kernel_fsid_t f_fsid */
-       tmp.f_namelen = UDF_NAME_LEN;
+       buf->f_namelen = UDF_NAME_LEN;
 
-       rc= copy_to_user(buf, &tmp, size) ? -EFAULT: 0;
-       return rc;
+       return 0;
 }
 
 static unsigned char udf_bitmap_lookup[16] = {
index 80e97bb060b23517afd3ec2d109fc733e7266fe5..1aa7eac730eeea52aea14454ad3a2cf63deb8d87 100644 (file)
@@ -924,28 +924,27 @@ int ufs_remount (struct super_block * sb, int * mount_flags, char * data)
        return 0;
 }
 
-int ufs_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
+int ufs_statfs (struct super_block * sb, struct statfs * buf)
 {
        struct ufs_sb_private_info * uspi;
        struct ufs_super_block_first * usb1;
-       struct statfs tmp;
        unsigned swab;
 
        swab = sb->u.ufs_sb.s_swab;
        uspi = sb->u.ufs_sb.s_uspi;
        usb1 = ubh_get_usb_first (USPI_UBH);
        
-       tmp.f_type = UFS_MAGIC;
-       tmp.f_bsize = sb->s_blocksize;
-       tmp.f_blocks = uspi->s_dsize;
-       tmp.f_bfree = ufs_blkstofrags(SWAB32(usb1->fs_cstotal.cs_nbfree)) +
+       buf->f_type = UFS_MAGIC;
+       buf->f_bsize = sb->s_blocksize;
+       buf->f_blocks = uspi->s_dsize;
+       buf->f_bfree = ufs_blkstofrags(SWAB32(usb1->fs_cstotal.cs_nbfree)) +
                SWAB32(usb1->fs_cstotal.cs_nffree);
-       tmp.f_bavail = (tmp.f_bfree > ((tmp.f_blocks / 100) * uspi->s_minfree))
-               ? (tmp.f_bfree - ((tmp.f_blocks / 100) * uspi->s_minfree)) : 0;
-       tmp.f_files = uspi->s_ncg * uspi->s_ipg;
-       tmp.f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree);
-       tmp.f_namelen = UFS_MAXNAMLEN;
-       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+       buf->f_bavail = (buf->f_bfree > ((buf->f_blocks / 100) * uspi->s_minfree))
+               ? (buf->f_bfree - ((buf->f_blocks / 100) * uspi->s_minfree)) : 0;
+       buf->f_files = uspi->s_ncg * uspi->s_ipg;
+       buf->f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree);
+       buf->f_namelen = UFS_MAXNAMLEN;
+       return 0;
 }
 
 static struct super_operations ufs_super_ops = {
index 08bb7b3407a48c72f1373ad7f19b82f562043e7b..75715116f2f3912db863fa51d9a997bdf20d1a1f 100644 (file)
@@ -876,7 +876,7 @@ int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
                goto out;
 
        ret = -EBUSY;
-       if (!list_empty(&dentry->d_hash))
+       if (!d_unhashed(dentry))
                goto out;
 
        /* check whether the EMD is empty */
index d05dfed73a71c335065894bbe0b6ea788f43712e..8c71dd7270e2acd03443bc2f15ac13dea0a6fb95 100644 (file)
@@ -157,7 +157,7 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
                goto out;
 
        ret = -EBUSY;
-       if (!list_empty(&dentry->d_hash))
+       if (!d_unhashed(dentry))
                goto out;
 
        ret = msdos_rmdir (dir, dentry);
index 476a09e9cc05548d289f351dbb50bd7dc8887fbd..87d9694cf707fd538017212aa30ecd3277203268 100644 (file)
@@ -978,7 +978,7 @@ static struct dentry *find_alias(struct inode *inode)
                tmp = next;
                next = tmp->next;
                alias = list_entry(tmp, struct dentry, d_alias);
-               if (!list_empty(&alias->d_hash))
+               if (!d_unhashed(alias))
                        return dget(alias);
        }
        return NULL;
@@ -1085,7 +1085,7 @@ int vfat_rmdir(struct inode *dir,struct dentry* dentry)
        struct buffer_head *bh = NULL;
        struct msdos_dir_entry *de;
 
-       if (!list_empty(&dentry->d_hash))
+       if (!d_unhashed(dentry))
                return -EBUSY;
 
        res = fat_dir_empty(dentry->d_inode);
@@ -1207,6 +1207,9 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
                }
 
                if (is_dir) {
+                       res =-EBUSY;
+                       if (!d_unhashed(new_dentry))
+                               goto rename_done;
                        res = fat_dir_empty(new_inode);
                        if (res)
                                goto rename_done;
index 1947b62c0b2b4b90144a0cabf8fc3337bcda5475..886eebb91d8382b79cbb62fed409ddcfc00ff69c 100644 (file)
 #include <linux/config.h>
 
 #ifndef MAX_HWIFS
+# ifdef CONFIG_BLK_DEV_IDEPCI
 #define MAX_HWIFS      10
+# else
+#define MAX_HWIFS      6
+# endif
 #endif
 
 #define ide__sti()     __sti()
index 6ec01ecd4dbf417e9a9d135ebcd2615cad7ec665..023203dc3858649063e0d776973c136015a62d0a 100644 (file)
 #include <linux/config.h>
 
 #ifndef MAX_HWIFS
+# ifdef CONFIG_BLK_DEV_IDEPCI
 #define MAX_HWIFS      10
+# else
+#define MAX_HWIFS      6
+# endif
 #endif
 
 #define ide__sti()     __sti()
index 3d084fd16f086fa323d8ffc179f28f818b3f6758..78c21958fa1bb9fffef58400840a35f14cb967ad 100644 (file)
@@ -64,7 +64,7 @@ ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
  */
 static inline void ide_init_default_hwifs(void)
 {
-#ifdef __DO_I_NEED_THIS
+#ifndef CONFIG_BLK_DEV_IDEPCI
        hw_regs_t hw;
        int index;
 
@@ -73,7 +73,7 @@ static inline void ide_init_default_hwifs(void)
                hw.irq = ide_default_irq(ide_default_io_base(index));
                ide_register_hw(&hw, NULL);
        }
-#endif /* __DO_I_NEED_THIS */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
 typedef union {
index 40deb121b0fe9b76aea21463553ad62bbc3d521d..66eaedda5343585cc01abd6b8377d6b9b626c3bf 100644 (file)
@@ -83,3 +83,6 @@ extern unsigned char *get_property(struct device_node *node, const char *name,
 extern void print_properties(struct device_node *node);
 extern int call_rtas(const char *service, int nargs, int nret,
                     unsigned long *outputs, ...);
+extern void prom_drawstring(const char *c);
+extern void prom_drawhex(unsigned long v);
+extern void prom_drawchar(char c);
index bec4233e62892f8eb19bb28da9a832bbe2d8172d..98e131739fa7255db6eba75fd67cf9a2139e44b9 100644 (file)
@@ -59,7 +59,7 @@ static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
  */
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifdef __DO_I_NEED_THIS
+#ifndef CONFIG_BLK_DEV_IDEPCI
        hw_regs_t hw;
        int index;
 
@@ -68,7 +68,7 @@ static __inline__ void ide_init_default_hwifs(void)
                hw.irq = ide_default_irq(ide_default_io_base(index));
                ide_register_hw(&hw, NULL);
        }
-#endif /* __DO_I_NEED_THIS */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
 typedef union {
index de78c266c95e070bdd4bd002356185f3ca32cf67..112145b0b07c888b45cc0784d126c4ed402cf94c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.80 1999/12/16 12:58:31 anton Exp $ */
+/* $Id: system.h,v 1.81 2000/02/28 04:00:44 anton Exp $ */
 #include <linux/config.h>
 
 #ifndef __SPARC_SYSTEM_H
@@ -251,16 +251,10 @@ extern __inline__ unsigned long read_psr_and_cli(void)
 
 #ifdef __SMP__
 
-/* This goes away after lockups have been found... */
-#ifndef DEBUG_IRQLOCK
-#define DEBUG_IRQLOCK
-#endif
-
 extern unsigned char global_irq_holder;
 
 #define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
 
-#ifdef DEBUG_IRQLOCK
 extern void __global_cli(void);
 extern void __global_sti(void);
 extern unsigned long __global_save_flags(void);
@@ -269,42 +263,6 @@ extern void __global_restore_flags(unsigned long flags);
 #define sti()                  __global_sti()
 #define save_flags(flags)      ((flags)=__global_save_flags())
 #define restore_flags(flags)   __global_restore_flags(flags)
-#else
-
-#error For combined sun4[md] smp, we need to get rid of the rdtbr.
-
-/* Visit arch/sparc/lib/irqlock.S for all the fun details... */
-#define cli()      __asm__ __volatile__("mov   %%o7, %%g4\n\t"                 \
-                                       "call   ___f_global_cli\n\t"            \
-                                       " rd    %%tbr, %%g7" : :                \
-                                       : "g1", "g2", "g3", "g4", "g5", "g7",   \
-                                         "memory", "cc")
-
-#define sti()                                                  \
-do {   register unsigned long bits asm("g7");                  \
-       bits = 0;                                               \
-       __asm__ __volatile__("mov       %%o7, %%g4\n\t"         \
-                            "call      ___f_global_sti\n\t"    \
-                            " rd       %%tbr, %%g2"            \
-                            : /* no outputs */                 \
-                            : "r" (bits)                       \
-                            : "g1", "g2", "g3", "g4", "g5",    \
-                              "memory", "cc");                 \
-} while(0)
-
-#define restore_flags(flags)                                           \
-do {   register unsigned long bits asm("g7");                          \
-       bits = flags;                                                   \
-       __asm__ __volatile__("mov       %%o7, %%g4\n\t"                 \
-                            "call      ___f_global_restore_flags\n\t"  \
-                            " andcc    %%g7, 0x1, %%g0"                \
-                            : "=&r" (bits)                             \
-                            : "0" (bits)                               \
-                            : "g1", "g2", "g3", "g4", "g5",            \
-                              "memory", "cc");                         \
-} while(0)
-
-#endif /* DEBUG_IRQLOCK */
 
 #else
 
index 3dcad335743a3c72364bc2fd40fedaf3cd345ae5..c5ef464b466e2001c8af3e1c94e43bb76c14917a 100644 (file)
@@ -191,6 +191,11 @@ static __inline__ struct dentry * dget(struct dentry *dentry)
        return dentry;
 }
 
+static __inline__ int d_unhashed(struct dentry *dentry)
+{
+       return list_empty(&dentry->d_hash);
+}
+
 extern void dput(struct dentry *);
 
 #endif /* __KERNEL__ */
index 2ba621bc2af3a455204ec5735e2ac7b7bb4dc06e..cc23e2e0c629e14352071716449e281164804a07 100644 (file)
@@ -53,7 +53,7 @@ extern int init_module(void);
 extern void cleanup_module(void);
 extern struct super_block *efs_read_super(struct super_block *, void *, int);
 extern void efs_put_super(struct super_block *);
-extern int efs_statfs(struct super_block *, struct statfs *, int);
+extern int efs_statfs(struct super_block *, struct statfs *);
 
 extern void efs_read_inode(struct inode *);
 extern efs_block_t efs_map_block(struct inode *, efs_block_t);
index 67c6fac1478c9915d021893f4a9cb52274cd2bd5..85e8d092fd011cd7c7edb3728c926748b4397814 100644 (file)
@@ -590,7 +590,7 @@ extern void ext2_put_super (struct super_block *);
 extern void ext2_write_super (struct super_block *);
 extern int ext2_remount (struct super_block *, int *, char *);
 extern struct super_block * ext2_read_super (struct super_block *,void *,int);
-extern int ext2_statfs (struct super_block *, struct statfs *, int);
+extern int ext2_statfs (struct super_block *, struct statfs *);
 
 /* truncate.c */
 extern void ext2_truncate (struct inode *);
index 0b55b363b37339179101a37fe7e6c577c18f7ec1..4a345df690b63a8f7dee912eeb612bb9a1b3af49 100644 (file)
@@ -283,12 +283,15 @@ struct fb_ops {
     int (*fb_rasterimg)(struct fb_info *info, int start);
 };
 
+/* fb_info flags */
+#define FBINFO_FLAG_MODULE      1       /* Low-level driver is a module */
+#define FBINFO_FLAG_OPEN        2       /* Has this been open already ? */ 
+
 struct fb_info {
    char modename[40];                  /* default video mode */
    kdev_t node;
    int flags;
-   int open;                            /* Has this been open already ? */
-#define FBINFO_FLAG_MODULE     1       /* Low-level driver is a module */
+   int count;                           /* How many using the hardware */
    struct fb_var_screeninfo var;        /* Current var */
    struct fb_fix_screeninfo fix;        /* Current fix */
    struct fb_monspecs monspecs;         /* Current Monitor specs */
index 45ec949e17ae7765326f19a542ef9c516f18160d..c481f5436c7b2fccb26a18857a92579bf35032e1 100644 (file)
@@ -384,6 +384,7 @@ struct inode {
        unsigned long           i_blocks;
        unsigned long           i_version;
        struct semaphore        i_sem;
+       struct semaphore        i_zombie;
        struct inode_operations *i_op;
        struct file_operations  *i_fop; /* former ->i_op->default_file_ops */
        struct super_block      *i_sb;
@@ -704,7 +705,7 @@ struct super_operations {
        void (*delete_inode) (struct inode *);
        void (*put_super) (struct super_block *);
        void (*write_super) (struct super_block *);
-       int (*statfs) (struct super_block *, struct statfs *, int);
+       int (*statfs) (struct super_block *, struct statfs *);
        int (*remount_fs) (struct super_block *, int *, char *);
        void (*clear_inode) (struct inode *);
        void (*umount_begin) (struct super_block *);
@@ -730,6 +731,16 @@ struct file_system_type {
 extern int register_filesystem(struct file_system_type *);
 extern int unregister_filesystem(struct file_system_type *);
 
+static inline int vfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+       if (!sb)
+               return -ENODEV;
+       if (!sb->s_op || !sb->s_op->statfs)
+               return -ENOSYS;
+       memset(buf, 0xff, sizeof(struct statfs));
+       return sb->s_op->statfs(sb, buf);
+}
+
 /* Return value for VFS lock functions - tells locks.c to lock conventionally
  * REALLY kosha for root NFS and nfs_lock
  */ 
@@ -907,6 +918,7 @@ extern void put_write_access(struct inode *);
 extern struct dentry * open_namei(const char *, int, int);
 extern struct dentry * do_mknod(const char *, int, dev_t);
 extern int do_pipe(int *);
+extern int do_unlink(const char * name);
 
 /* fs/dcache.c -- generic fs support functions */
 extern int is_subdir(struct dentry *, struct dentry *);
@@ -1085,7 +1097,7 @@ extern void inode_setattr(struct inode *, struct iattr *);
  * other process will be too late..
  */
 #define check_parent(dir, dentry) \
-       ((dir) == (dentry)->d_parent && !list_empty(&dentry->d_hash))
+       ((dir) == (dentry)->d_parent && !d_unhashed(dentry))
 
 /*
  * Locking the parent is needed to:
@@ -1122,11 +1134,8 @@ static inline void unlock_dir(struct dentry *dir)
  * Whee.. Deadlock country. Happily there are only two VFS
  * operations that does this..
  */
-static inline void double_lock(struct dentry *d1, struct dentry *d2)
+static inline void double_down(struct semaphore *s1, struct semaphore *s2)
 {
-       struct semaphore *s1 = &d1->d_inode->i_sem;
-       struct semaphore *s2 = &d2->d_inode->i_sem;
-
        if (s1 != s2) {
                if ((unsigned long) s1 < (unsigned long) s2) {
                        struct semaphore *tmp = s2;
@@ -1137,19 +1146,76 @@ static inline void double_lock(struct dentry *d1, struct dentry *d2)
        down(s2);
 }
 
-static inline void double_unlock(struct dentry *d1, struct dentry *d2)
+/*
+ * Ewwwwwwww... _triple_ lock. We are guaranteed that the 3rd argument is
+ * not equal to 1st and not equal to 2nd - the first case (target is parent of
+ * source) would be already caught, the second is plain impossible (target is
+ * its own parent and that case would be caught even earlier). Very messy.
+ * I _think_ that it works, but no warranties - please, look it through.
+ * Pox on bloody lusers who mandated overwriting rename() for directories...
+ */
+
+static inline void triple_down(struct semaphore *s1,
+                              struct semaphore *s2,
+                              struct semaphore *s3)
 {
-       struct semaphore *s1 = &d1->d_inode->i_sem;
-       struct semaphore *s2 = &d2->d_inode->i_sem;
+       if (s1 != s2) {
+               if ((unsigned long) s1 < (unsigned long) s2) {
+                       if ((unsigned long) s1 < (unsigned long) s3) {
+                               struct semaphore *tmp = s3;
+                               s3 = s1; s1 = tmp;
+                       }
+                       if ((unsigned long) s1 < (unsigned long) s2) {
+                               struct semaphore *tmp = s2;
+                               s2 = s1; s1 = tmp;
+                       }
+               } else {
+                       if ((unsigned long) s1 < (unsigned long) s3) {
+                               struct semaphore *tmp = s3;
+                               s3 = s1; s1 = tmp;
+                       }
+                       if ((unsigned long) s2 < (unsigned long) s3) {
+                               struct semaphore *tmp = s3;
+                               s3 = s2; s2 = tmp;
+                       }
+               }
+               down(s1);
+       } else if ((unsigned long) s2 < (unsigned long) s3) {
+               struct semaphore *tmp = s3;
+               s3 = s2; s2 = tmp;
+       }
+       down(s2);
+       down(s3);
+}
 
+static inline void double_up(struct semaphore *s1, struct semaphore *s2)
+{
        up(s1);
        if (s1 != s2)
                up(s2);
-       dput(d1);
-       dput(d2);
 }
 
+static inline void triple_up(struct semaphore *s1,
+                            struct semaphore *s2,
+                            struct semaphore *s3)
+{
+       up(s1);
+       if (s1 != s2)
+               up(s2);
+       up(s3);
+}
+
+static inline void double_lock(struct dentry *d1, struct dentry *d2)
+{
+       double_down(&d1->d_inode->i_sem, &d2->d_inode->i_sem);
+}
 
+static inline void double_unlock(struct dentry *d1, struct dentry *d2)
+{
+       double_up(&d1->d_inode->i_sem,&d2->d_inode->i_sem);
+       dput(d1);
+       dput(d2);
+}
 
 #endif /* __KERNEL__ */
 
index 64136c7327d7bcacbc9575b8c5ee96226ae46b89..248c37b39f43b186493b3002ab1d14bd53319b86 100644 (file)
@@ -414,6 +414,7 @@ typedef struct hwif_s {
 #if (DISK_RECOVERY_TIME > 0)
        unsigned long   last_time;      /* time when previous rq was done */
 #endif
+       byte            straight8;      /* Alan's straight 8 check */
 } ide_hwif_t;
 
 /*
index 4883f16a7a9864fa683327ce00f44b103ce337df..8de2f6b69cfb734ebc575891cd754efa7b19573c 100644 (file)
@@ -34,6 +34,19 @@ struct sockaddr_ec
 
 #ifdef __KERNEL__
 
+#define EC_HLEN                                6
+
+/* This is what an Econet frame looks like on the wire. */
+struct ec_framehdr 
+{
+  unsigned char dst_stn;
+  unsigned char dst_net;
+  unsigned char src_stn;
+  unsigned char src_net;
+  unsigned char cb;
+  unsigned char port;
+};
+
 struct econet_opt
 {
   unsigned char cb;
@@ -42,6 +55,14 @@ struct econet_opt
   unsigned char net;
 };
 
+struct ec_device
+{
+  unsigned char station, net;          /* Econet protocol address */
+};
+
+extern struct sock *ec_listening_socket(unsigned char port, unsigned char
+                                station, unsigned char net);
+
 #endif
 
 #endif
index f397306c4855f5b5bb37c5279ae4338b7a69874a..72752441ef8c3d7c033665c1fc58ef777edbeb79 100644 (file)
 #include <linux/nfs.h>
 #include <linux/sunrpc/xdr.h>
 
-extern u32     nlm_granted, nlm_lck_denied, nlm_lck_denied_nolocks,
-               nlm_lck_blocked, nlm_lck_denied_grace_period;
+#define NLM_MAXSTRLEN          1024
+
+#define QUADLEN(len)           (((len) + 3) >> 2)
+
+#define        nlm_granted             __constant_htonl(NLM_LCK_GRANTED)
+#define        nlm_lck_denied          __constant_htonl(NLM_LCK_DENIED)
+#define        nlm_lck_denied_nolocks  __constant_htonl(NLM_LCK_DENIED_NOLOCKS)
+#define        nlm_lck_blocked         __constant_htonl(NLM_LCK_BLOCKED)
+#define        nlm_lck_denied_grace_period     __constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD)
 
 /* Lock info passed via NLM */
 struct nlm_lock {
@@ -49,6 +56,8 @@ struct nlm_args {
        u32                     fsm_mode;
 };
 
+typedef struct nlm_args nlm_args;
+
 /*
  * Generic lockd result
  */
index d9d7e3f75e90f24fac439e0cae2e71729a0a96c3..cee36e7c0548f523752758eae748f482d28b4f42 100644 (file)
 #include <linux/lockd/xdr.h>
 
 /* error codes new to NLMv4 */
-extern u32     nlm4_deadlock, nlm4_rofs, nlm4_stale_fh, nlm4_fbig, nlm4_failed;
+#define        nlm4_deadlock           __constant_htonl(NLM_DEADLCK)
+#define        nlm4_rofs               __constant_htonl(NLM_ROFS)
+#define        nlm4_stale_fh           __constant_htonl(NLM_STALE_FH)
+#define        nlm4_fbig               __constant_htonl(NLM_FBIG)
+#define        nlm4_failed             __constant_htonl(NLM_FAILED)
+
 
 
 int    nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
index de2ccffbd0926372452e21716dd74f396cb19ec0..ce7837f1dd4518324f6dcf75d25f990f2c8a300c 100644 (file)
@@ -247,7 +247,7 @@ extern struct inode *fat_iget(struct super_block*,int);
 extern struct inode *fat_build_inode(struct super_block*,struct msdos_dir_entry*,int,int*);
 extern struct super_block *fat_read_super(struct super_block *s, void *data, int silent, struct inode_operations *dir_ops);
 extern void msdos_put_super(struct super_block *sb);
-extern int fat_statfs(struct super_block *sb,struct statfs *buf, int);
+extern int fat_statfs(struct super_block *sb,struct statfs *buf);
 extern void fat_write_inode(struct inode *inode);
 
 /* dir.c */
index d71a6923b845ceb4dc9814df1a205c4acd09a978..d73229c7e87d0da6afc388c2f7b2cfa2cdba7670 100644 (file)
@@ -100,7 +100,7 @@ void                nfsd_close(struct file *);
 int            nfsd_read(struct svc_rqst *, struct svc_fh *,
                                loff_t, char *, unsigned long *);
 int            nfsd_write(struct svc_rqst *, struct svc_fh *,
-                               loff_t, char *, unsigned long, int);
+                               loff_t, char *, unsigned long, int *);
 int            nfsd_readlink(struct svc_rqst *, struct svc_fh *,
                                char *, int *);
 int            nfsd_symlink(struct svc_rqst *, struct svc_fh *,
@@ -140,43 +140,38 @@ void              nfsd_lockd_shutdown(void);
 void           nfsd_lockd_unexport(struct svc_client *);
 
 
-#ifndef makedev
-#define makedev(maj, min)      (((maj) << 8) | (min))
-#endif
-
 /*
- * These variables contain pre-xdr'ed values for faster operation.
- * FIXME: should be replaced by macros for big-endian machines.
+ * These macros provide pre-xdr'ed values for faster operation.
  */
-extern u32     nfs_ok,
-               nfserr_perm,
-               nfserr_noent,
-               nfserr_io,
-               nfserr_nxio,
-               nfserr_acces,
-               nfserr_exist,
-               nfserr_xdev,
-               nfserr_nodev,
-               nfserr_notdir,
-               nfserr_isdir,
-               nfserr_inval,
-               nfserr_fbig,
-               nfserr_nospc,
-               nfserr_rofs,
-               nfserr_mlink,
-               nfserr_nametoolong,
-               nfserr_notempty,
-               nfserr_dquot,
-               nfserr_stale,
-               nfserr_remote,
-               nfserr_badhandle,
-               nfserr_notsync,
-               nfserr_badcookie,
-               nfserr_notsupp,
-               nfserr_toosmall,
-               nfserr_serverfault,
-               nfserr_badtype,
-               nfserr_jukebox;
+#define        nfs_ok                  __constant_htonl(NFS_OK)
+#define        nfserr_perm             __constant_htonl(NFSERR_PERM)
+#define        nfserr_noent            __constant_htonl(NFSERR_NOENT)
+#define        nfserr_io               __constant_htonl(NFSERR_IO)
+#define        nfserr_nxio             __constant_htonl(NFSERR_NXIO)
+#define        nfserr_acces            __constant_htonl(NFSERR_ACCES)
+#define        nfserr_exist            __constant_htonl(NFSERR_EXIST)
+#define        nfserr_xdev             __constant_htonl(NFSERR_XDEV)
+#define        nfserr_nodev            __constant_htonl(NFSERR_NODEV)
+#define        nfserr_notdir           __constant_htonl(NFSERR_NOTDIR)
+#define        nfserr_isdir            __constant_htonl(NFSERR_ISDIR)
+#define        nfserr_inval            __constant_htonl(NFSERR_INVAL)
+#define        nfserr_fbig             __constant_htonl(NFSERR_FBIG)
+#define        nfserr_nospc            __constant_htonl(NFSERR_NOSPC)
+#define        nfserr_rofs             __constant_htonl(NFSERR_ROFS)
+#define        nfserr_mlink            __constant_htonl(NFSERR_MLINK)
+#define        nfserr_nametoolong      __constant_htonl(NFSERR_NAMETOOLONG)
+#define        nfserr_notempty         __constant_htonl(NFSERR_NOTEMPTY)
+#define        nfserr_dquot            __constant_htonl(NFSERR_DQUOT)
+#define        nfserr_stale            __constant_htonl(NFSERR_STALE)
+#define        nfserr_remote           __constant_htonl(NFSERR_REMOTE)
+#define        nfserr_badhandle        __constant_htonl(NFSERR_BADHANDLE)
+#define        nfserr_notsync          __constant_htonl(NFSERR_NOTSYNC)
+#define        nfserr_badcookie        __constant_htonl(NFSERR_BADCOOKIE)
+#define        nfserr_notsupp          __constant_htonl(NFSERR_NOTSUPP)
+#define        nfserr_toosmall         __constant_htonl(NFSERR_TOOSMALL)
+#define        nfserr_serverfault      __constant_htonl(NFSERR_SERVERFAULT)
+#define        nfserr_badtype          __constant_htonl(NFSERR_BADTYPE)
+#define        nfserr_jukebox          __constant_htonl(NFSERR_JUKEBOX)
 
 /*
  * Time of server startup
index bc47b8bace0a50f6af28ed0c18f7bd7a96cf0d47..323c62b83d679ec189e5784e059a7574504dba52 100644 (file)
@@ -121,7 +121,6 @@ union nfsd_xdrstore {
 
 #define NFSSVC_XDRSIZE         sizeof(union nfsd_xdrstore)
 
-void nfsd_xdr_init(void);
 
 int nfssvc_decode_void(struct svc_rqst *, u32 *, void *);
 int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct svc_fh *);
index 7e09ba5c22fee6289a557346cd8bf824fda71c9a..ebe4d6865ce8411bb4b4c64cb23624122c1878e1 100644 (file)
 #define PCI_DEVICE_ID_TTI_HPT366       0x0004
 
 #define PCI_VENDOR_ID_VIA              0x1106
+#define PCI_DEVICE_ID_VIA_8371_0       0x0391
 #define PCI_DEVICE_ID_VIA_8501_0       0x0501
+#define PCI_DEVICE_ID_VIA_8601_0       0x0601
 #define PCI_DEVICE_ID_VIA_82C505       0x0505
 #define PCI_DEVICE_ID_VIA_82C561       0x0561
 #define PCI_DEVICE_ID_VIA_82C586_1     0x0571
 #define PCI_DEVICE_ID_VIA_82C686_5     0x3058
 #define PCI_DEVICE_ID_VIA_82C686_6     0x3068
 #define PCI_DEVICE_ID_VIA_86C100A      0x6100
+#define PCI_DEVICE_ID_VIA_8231         0x8231
+#define PCI_DEVICE_ID_VIA_8371_1       0x8391
 #define PCI_DEVICE_ID_VIA_8501_1       0x8501
 #define PCI_DEVICE_ID_VIA_82C597_1     0x8597
 #define PCI_DEVICE_ID_VIA_82C598_1     0x8598
+#define PCI_DEVICE_ID_VIA_8601_1       0x8601
 
 #define PCI_VENDOR_ID_SMC2             0x1113
 #define PCI_DEVICE_ID_SMC2_1211TX      0x1211
index e8b7d1f7c846b612b5ba8cce0d96dedc025c70cc..c1ab5240b9b96d4339e6344033eb59c8db61fcf9 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #define SHMMAX 0x2000000                /* max shared seg size (bytes) */
-#define SHMMIN 1 /* really PAGE_SIZE */         /* min shared seg size (bytes) */
+#define SHMMIN 0                        /* min shared seg size (bytes) */
 #define SHMMNI 128                      /* max num of segs system wide */
 #define SHMALL (SHMMAX/PAGE_SIZE*SHMMNI) /* max shm system wide (pages) */
 #define SHMSEG SHMMNI                   /* max shared segs per process */
index 1d91cf216feeae1d639dd8e821e9c793a5a2f86a..eb51e575fc23e7ecbdf809bdd17b635d339beef0 100644 (file)
@@ -110,7 +110,8 @@ enum
        KERN_SPARC_STOP_A=44,   /* int: Sparc Stop-A enable */
        KERN_SHMMNI=45,         /* int: shm array identifiers */
        KERN_OVERFLOWUID=46,    /* int: overflow UID */
-       KERN_OVERFLOWGID=47     /* int: overflow GID */
+       KERN_OVERFLOWGID=47,    /* int: overflow GID */
+       KERN_SHMPATH=48,        /* string: path to shm fs */
 };
 
 
diff --git a/include/net/dn_raw.h b/include/net/dn_raw.h
deleted file mode 100644 (file)
index 8232ddf..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _NET_DN_RAW_H
-#define _NET_DN_RAW_H
-
-#include <linux/config.h>
-
-#ifdef CONFIG_DECNET_RAW
-
-extern struct proto_ops dn_raw_proto_ops;
-
-extern void dn_raw_rx_nsp(struct sk_buff *skb);
-extern void dn_raw_rx_routing(struct sk_buff *skb);
-
-#ifdef CONFIG_DECNET_MOP
-extern void dn_raw_rx_mop(struct sk_buff *skb);
-#endif /* CONFIG_DECNET_MOP */
-
-#endif /* CONFIG_DECNET_RAW */
-
-#endif /* _NET_DN_RAW_H */
index d2c937f96432a8cca89f61bd8075c2e77fb6748a..569b8b6ea1e59ea57428eca1b5d44aa05fe1db60 100644 (file)
@@ -339,12 +339,14 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
 
 #if HZ == 20
 # define TCP_TW_RECYCLE_TICK (5+2-TCP_TW_RECYCLE_SLOTS_LOG)
+#elif HZ == 64
+# define TCP_TW_RECYCLE_TICK (6+2-TCP_TW_RECYCLE_SLOTS_LOG)
 #elif HZ == 100 || HZ == 128
 # define TCP_TW_RECYCLE_TICK (7+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ == 1024
+#elif HZ == 1024 || HZ == 1000
 # define TCP_TW_RECYCLE_TICK (10+2-TCP_TW_RECYCLE_SLOTS_LOG)
 #else
-# error HZ != 20 &&  HZ != 100 && HZ != 1024.
+# error HZ != 20 && HZ != 64 && HZ != 100 && HZ != 1000 && HZ != 1024
 #endif
 
 /*
index 6c6fc31d65c303fe0d695836c29fc7283779bae3..21d4257b5931b2b5329cca57c5a582990b5ffb84 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
  * avoid vmalloc and make shmmax, shmall, shmmni sysctl'able,
  *                         Christoph Rohland <hans-christoph.rohland@sap.com>
  * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
+ * make it a file system,  Christoph Rohland <hans-christoph.rohland@sap.com>
+ *
+ * The filesystem has the following restrictions/bugs:
+ * 1) It only can handle one directory.
+ * 2) Because the directory is represented by the SYSV shm array it
+ *    can only be mounted one time.
+ * 3) This again leads to SYSV shm not working properly in a chrooted
+ *    environment
+ * 4) Read and write are not implemented (should they?)
+ * 5) No special nodes are supported
  */
 
 #include <linux/config.h>
@@ -20,6 +30,9 @@
 #include <linux/swap.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/locks.h>
+#include <linux/file.h>
+#include <linux/mman.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
 
 #include "util.h"
 
+static struct super_block *shm_read_super(struct super_block *,void *, int);
+static void          shm_put_super  (struct super_block *);
+static int           shm_remount_fs (struct super_block *, int *, char *);
+static void          shm_read_inode (struct inode *);
+static void          shm_write_inode(struct inode *);
+static int           shm_statfs (struct super_block *, struct statfs *, int);
+static int           shm_create   (struct inode *,struct dentry *,int);
+static struct dentry *shm_lookup   (struct inode *,struct dentry *);
+static int           shm_unlink   (struct inode *,struct dentry *);
+static int           shm_setattr  (struct dentry *dent, struct iattr *attr);
+static void          shm_delete   (struct inode *);
+static int           shm_mmap     (struct file *, struct vm_area_struct *);
+static int           shm_readdir  (struct file *, void *, filldir_t);
+
+char shm_path[256] = "/var/shm";
+
+#define SHM_NAME_LEN NAME_MAX
+#define SHM_FMT ".IPC_%08x"
+#define SHM_FMT_LEN 13
+
 struct shmid_kernel /* private to the kernel */
 {      
        struct kern_ipc_perm    shm_perm;
        size_t                  shm_segsz;
-       time_t                  shm_atime;
-       time_t                  shm_dtime;
-       time_t                  shm_ctime;
-       pid_t                   shm_cpid;
-       pid_t                   shm_lpid;
        unsigned long           shm_nattch;
        unsigned long           shm_npages; /* size of segment (pages) */
-       pte_t                   **shm_dir;  /* ptr to array of ptrs to frames -> SHMMAX */ 
-       struct vm_area_struct   *attaches;  /* descriptors for attaches */
-       int                     id; /* backreference to id for shm_close */
-       struct semaphore sem;
+       pte_t                   **shm_dir;  /* ptr to arr of ptrs to frames */ 
+       int                     id;
+       union permap {
+               struct shmem {
+                       time_t                  atime;
+                       time_t                  dtime;
+                       time_t                  ctime;
+                       pid_t                   cpid;
+                       pid_t                   lpid;
+                       int                     nlen;
+                       char                    nm[0];
+               } shmem;
+               struct zero {
+                       struct semaphore        sema;
+                       struct list_head        list;
+               } zero;
+       } permap;
 };
 
+#define shm_atim       permap.shmem.atime
+#define shm_dtim       permap.shmem.dtime
+#define shm_ctim       permap.shmem.ctime
+#define shm_cprid      permap.shmem.cpid
+#define shm_lprid      permap.shmem.lpid
+#define shm_namelen    permap.shmem.nlen
+#define shm_name       permap.shmem.nm
+#define zsem           permap.zero.sema
+#define zero_list      permap.zero.list
+
 static struct ipc_ids shm_ids;
 
 #define shm_lock(id)   ((struct shmid_kernel*)ipc_lock(&shm_ids,id))
@@ -60,9 +111,8 @@ static struct ipc_ids shm_ids;
 #define shm_buildid(id, seq) \
        ipc_buildid(&shm_ids, id, seq)
 
-static int newseg (key_t key, int shmflg, size_t size);
-static int shm_map (struct vm_area_struct *shmd);
-static void killseg (int shmid);
+static int newseg (key_t key, const char *name, int namelen, int shmflg, size_t size);
+static void killseg_core(struct shmid_kernel *shp, int doacc);
 static void shm_open (struct vm_area_struct *shmd);
 static void shm_close (struct vm_area_struct *shmd);
 static struct page * shm_nopage(struct vm_area_struct *, unsigned long, int);
@@ -75,12 +125,62 @@ static void zshm_swap (int prio, int gfp_mask, zone_t *zone);
 static void zmap_unuse(swp_entry_t entry, struct page *page);
 static void shmzero_open(struct vm_area_struct *shmd);
 static void shmzero_close(struct vm_area_struct *shmd);
+static struct page *shmzero_nopage(struct vm_area_struct * shmd, unsigned long address, int no_share);
 static int zero_id;
 static struct shmid_kernel zshmid_kernel;
+static struct dentry *zdent;
+
+#define SHM_FS_MAGIC 0x02011994
+
+static struct super_block * shm_sb;
+
+static struct file_system_type shm_fs_type = {
+       "shm",
+       0,
+       shm_read_super,
+       NULL
+};
+
+static struct super_operations shm_sops = {
+       read_inode:     shm_read_inode,
+       write_inode:    shm_write_inode,
+       delete_inode:   shm_delete,
+       put_super:      shm_put_super,
+       statfs:         shm_statfs,
+       remount_fs:     shm_remount_fs,
+};
+
+static struct file_operations shm_root_operations = {
+       readdir:        shm_readdir,
+};
+
+static struct inode_operations shm_root_inode_operations = {
+       create:         shm_create,
+       lookup:         shm_lookup,
+       unlink:         shm_unlink,
+};
+
+static struct file_operations shm_file_operations = {
+       mmap:   shm_mmap,
+};
+
+static struct inode_operations shm_inode_operations = {
+       setattr:        shm_setattr,
+};
+
+static struct vm_operations_struct shm_vm_ops = {
+       open:   shm_open,       /* callback for a new vm-area open */
+       close:  shm_close,      /* callback for when the vm-area is released */
+       nopage: shm_nopage,
+       swapout:shm_swapout,
+};
 
 size_t shm_ctlmax = SHMMAX;
-int shm_ctlall = SHMALL;
-int shm_ctlmni = SHMMNI;
+
+/* These parameters should be part of the superblock */
+static int shm_ctlall;
+static int shm_ctlmni;
+static int shm_mode;
 
 static int shm_tot = 0; /* total number of shared memory pages */
 static int shm_rss = 0; /* number of shared memory pages that are in memory */
@@ -90,7 +190,7 @@ static int shm_swp = 0; /* number of shared memory pages that are in swap */
        pagecache_lock
        shm_lock()/shm_lockall()
        kernel lock
-       shp->sem
+       inode->i_sem
        sem_ids.sem
        mmap_sem
 
@@ -104,18 +204,323 @@ static int shm_swp = 0; /* number of shared memory pages that are in swap */
 /* some statistics */
 static ulong swap_attempts = 0;
 static ulong swap_successes = 0;
+static ulong used_segs = 0;
 
 void __init shm_init (void)
 {
-       ipc_init_ids(&shm_ids, shm_ctlmni);
+       ipc_init_ids(&shm_ids, 1);
+
+       register_filesystem (&shm_fs_type);
 #ifdef CONFIG_PROC_FS
        create_proc_read_entry("sysvipc/shm", 0, 0, sysvipc_shm_read_proc, NULL);
 #endif
-       zero_id = ipc_addid(&shm_ids, &zshmid_kernel.shm_perm, shm_ctlmni);
+       zero_id = ipc_addid(&shm_ids, &zshmid_kernel.shm_perm, 1);
        shm_unlock(zero_id);
+       zdent = d_alloc_root(get_empty_inode());
        return;
 }
 
+static int shm_parse_options(char *options)
+{
+       int blocks = shm_ctlall;
+       int inodes = shm_ctlmni;
+       umode_t mode = shm_mode;
+       char *this_char, *value;
+
+       this_char = NULL;
+       if ( options )
+               this_char = strtok(options,",");
+       for ( ; this_char; this_char = strtok(NULL,",")) {
+               if ((value = strchr(this_char,'=')) != NULL)
+                       *value++ = 0;
+               if (!strcmp(this_char,"nr_blocks")) {
+                       if (!value || !*value)
+                               return 1;
+                       blocks = simple_strtoul(value,&value,0);
+                       if (*value)
+                               return 1;
+               }
+               else if (!strcmp(this_char,"nr_inodes")) {
+                       if (!value || !*value)
+                               return 1;
+                       inodes = simple_strtoul(value,&value,0);
+                       if (*value)
+                               return 1;
+               }
+               else if (!strcmp(this_char,"mode")) {
+                       if (!value || !*value)
+                               return 1;
+                       mode = simple_strtoul(value,&value,8);
+                       if (*value)
+                               return 1;
+               }
+               else
+                       return 1;
+       }
+       shm_ctlmni = inodes;
+       shm_ctlall = blocks;
+       shm_mode   = mode;
+
+       return 0;
+}
+
+static struct super_block *shm_read_super(struct super_block *s,void *data, 
+                                         int silent)
+{
+       struct inode * root_inode;
+
+       if (shm_sb) {
+               printk ("shm fs already mounted\n");
+               return NULL;
+       }
+
+       lock_super(s);
+       shm_ctlall = SHMALL;
+       shm_ctlmni = SHMMNI;
+       shm_mode   = S_IRWXUGO | S_ISVTX;
+       if (shm_parse_options (data)) {
+               printk ("shm fs invalid option\n");
+               goto out_unlock;
+       }
+
+       s->s_blocksize = PAGE_SIZE;
+       s->s_blocksize_bits = PAGE_SHIFT;
+       s->s_magic = SHM_FS_MAGIC;
+       s->s_op = &shm_sops;
+       root_inode = iget (s, SEQ_MULTIPLIER);
+       if (!root_inode)
+               goto out_no_root;
+       root_inode->i_op = &shm_root_inode_operations;
+       root_inode->i_sb = s;
+       root_inode->i_nlink = 2;
+       root_inode->i_mode = S_IFDIR | shm_mode;
+       s->s_root = d_alloc_root(root_inode);
+       if (!s->s_root)
+               goto out_no_root;
+       s->u.generic_sbp = (void*) shm_sb;
+       shm_sb = s;
+       unlock_super(s);
+       return s;
+
+out_no_root:
+       printk("proc_read_super: get root inode failed\n");
+       iput(root_inode);
+out_unlock:
+       s->s_dev = 0;
+       unlock_super(s);
+       return NULL;
+}
+
+static int shm_remount_fs (struct super_block *sb, int *flags, char *data)
+{
+       if (shm_parse_options (data))
+               return -EINVAL;
+       return 0;
+}
+
+static void shm_put_super(struct super_block *sb)
+{
+       struct super_block **p = &shm_sb;
+       int i;
+       struct shmid_kernel *shp;
+
+       while (*p != sb) {
+               if (!*p)        /* should never happen */
+                       return;
+               p = (struct super_block **)&(*p)->u.generic_sbp;
+       }
+       *p = (struct super_block *)(*p)->u.generic_sbp;
+       down(&shm_ids.sem);
+       for(i = 0; i <= shm_ids.max_id; i++) {
+               if (i == zero_id)
+                       continue;
+               if (!(shp = shm_lock (i)))
+                       continue;
+               if (shp->shm_nattch)
+                       printk ("shm_nattch = %ld\n", shp->shm_nattch);
+               shp = shm_rmid(i);
+               shm_unlock(i);
+               killseg_core(shp, 1);
+       }
+       dput (sb->s_root);
+       up(&shm_ids.sem);
+}
+
+static int shm_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+       struct statfs tmp;
+
+       tmp.f_type = 0;
+       tmp.f_bsize = PAGE_SIZE;
+       tmp.f_blocks = shm_ctlall;
+       tmp.f_bavail = tmp.f_bfree = shm_ctlall - shm_tot;
+       tmp.f_files = shm_ctlmni;
+       tmp.f_ffree = shm_ctlmni - used_segs;
+       tmp.f_namelen = SHM_NAME_LEN;
+       return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+
+static void shm_write_inode(struct inode * inode)
+{
+}
+
+static void shm_read_inode(struct inode * inode)
+{
+       int id;
+       struct shmid_kernel *shp;
+
+       id = inode->i_ino;
+       inode->i_op = NULL;
+       inode->i_mode = 0;
+       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+       if (id < SEQ_MULTIPLIER) {
+               if (!(shp = shm_lock (id)))
+                       return;
+               inode->i_mode = shp->shm_perm.mode | S_IFREG;
+               inode->i_uid  = shp->shm_perm.uid;
+               inode->i_gid  = shp->shm_perm.gid;
+               inode->i_size = shp->shm_segsz;
+               shm_unlock (id);
+               inode->i_op  = &shm_inode_operations;
+               inode->i_fop = &shm_file_operations;
+               return;
+       }
+       inode->i_op    = &shm_root_inode_operations;
+       inode->i_fop   = &shm_root_operations;
+       inode->i_sb    = shm_sb;
+       inode->i_nlink = 2;
+       inode->i_mode  = S_IFDIR | shm_mode;
+       inode->i_uid   = inode->i_gid = 0;
+
+}
+
+static int shm_create (struct inode *dir, struct dentry *dent, int mode)
+{
+       int id, err;
+       struct inode * inode;
+
+       down(&shm_ids.sem);
+       err = id = newseg (IPC_PRIVATE, dent->d_name.name, dent->d_name.len, mode, 0);
+       if (err < 0)
+               goto out;
+
+       err = -ENOMEM;
+       inode = iget (shm_sb, id % SEQ_MULTIPLIER);
+       if (!inode)
+               goto out;
+
+       err = 0;
+       down (&inode->i_sem);
+       inode->i_mode = mode | S_IFREG;
+       inode->i_op   = &shm_inode_operations;
+       d_instantiate(dent, inode);
+       up (&inode->i_sem);
+
+out:
+       up(&shm_ids.sem);
+       return err;
+}
+
+static int shm_readdir (struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct inode * inode = filp->f_dentry->d_inode;
+       struct shmid_kernel *shp;
+       off_t nr;
+
+       nr = filp->f_pos;
+
+       switch(nr)
+       {
+       case 0:
+               if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+                       return 0;
+               filp->f_pos = ++nr;
+               /* fall through */
+       case 1:
+               if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+                       return 0;
+               filp->f_pos = ++nr;
+               /* fall through */
+       default:
+               down(&shm_ids.sem);
+               for (; nr-2 <= shm_ids.max_id; nr++ ) {
+                       if (!(shp = shm_get (nr-2))) 
+                               continue;
+                       if (shp->shm_perm.mode & SHM_DEST)
+                               continue;
+                       if (filldir(dirent, shp->shm_name, shp->shm_namelen, nr, nr) < 0 )
+                               break;;
+               }
+               filp->f_pos = nr;
+               up(&shm_ids.sem);
+               break;
+       }
+
+       UPDATE_ATIME(inode);
+       return 0;
+}
+
+static struct dentry *shm_lookup (struct inode *dir, struct dentry *dent)
+{
+       int i, err = 0;
+       struct shmid_kernel* shp;
+       struct inode *inode = NULL;
+
+       if (dent->d_name.len > SHM_NAME_LEN)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       down(&shm_ids.sem);
+       for(i = 0; i <= shm_ids.max_id; i++) {
+               if (!(shp = shm_lock(i)))
+                   continue;
+               if (!(shp->shm_perm.mode & SHM_DEST) &&
+                   dent->d_name.len == shp->shm_namelen &&
+                   strncmp(dent->d_name.name, shp->shm_name, shp->shm_namelen) == 0)
+                       goto found;
+               shm_unlock(i);
+       }
+
+       /*
+        * prevent the reserved names as negative dentries. 
+        * This also prevents object creation through the filesystem
+        */
+       if (dent->d_name.len == SHM_FMT_LEN &&
+           memcmp (SHM_FMT, dent->d_name.name, SHM_FMT_LEN - 8) == 0)
+               err = -EINVAL;  /* EINVAL to give IPC_RMID the right error */
+
+       goto out;
+
+found:
+       shm_unlock(i);
+       inode = iget(dir->i_sb, i);
+
+       if (!inode)
+               err = -EACCES;
+out:
+       if (err == 0)
+               d_add (dent, inode);
+       up (&shm_ids.sem);
+       return ERR_PTR(err);
+}
+
+static int shm_unlink (struct inode *dir, struct dentry *dent)
+{
+       struct inode * inode = dent->d_inode;
+       struct shmid_kernel *shp;
+
+       down (&shm_ids.sem);
+       if (!(shp = shm_lock (inode->i_ino)))
+               BUG();
+       shp->shm_perm.mode |= SHM_DEST;
+       shp->shm_perm.key = IPC_PRIVATE; /* Do not find it any more */
+       shm_unlock (inode->i_ino);
+       up (&shm_ids.sem);
+       inode->i_nlink -= 1;
+       d_delete (dent);
+       return 0;
+}
+
 #define SHM_ENTRY(shp, index) (shp)->shm_dir[(index)/PTRS_PER_PTE][(index)%PTRS_PER_PTE]
 
 static pte_t **shm_alloc(unsigned long pages)
@@ -124,9 +529,12 @@ static pte_t **shm_alloc(unsigned long pages)
        unsigned short last = pages % PTRS_PER_PTE;
        pte_t **ret, **ptr;
 
+       if (pages == 0)
+               return NULL;
+
        ret = kmalloc ((dir+1) * sizeof(pte_t *), GFP_KERNEL);
        if (!ret)
-               goto out;
+               goto nomem;
 
        for (ptr = ret; ptr < ret+dir ; ptr++)
        {
@@ -143,7 +551,6 @@ static pte_t **shm_alloc(unsigned long pages)
                        goto free;
                memset (*ptr, 0, last*sizeof(pte_t));
        }
-out:   
        return ret;
 
 free:
@@ -152,48 +559,90 @@ free:
                free_page ((unsigned long)*ptr);
 
        kfree (ret);
-       return NULL;
+nomem:
+       return ERR_PTR(-ENOMEM);
 }
 
-
 static void shm_free(pte_t** dir, unsigned long pages)
 {
        pte_t **ptr = dir+pages/PTRS_PER_PTE;
 
+       if (!dir)
+               return;
+
        /* first the last page */
        if (pages%PTRS_PER_PTE)
                kfree (*ptr);
        /* now the whole pages */
        while (--ptr >= dir)
-               free_page ((unsigned long)*ptr);
+               if (*ptr)
+                       free_page ((unsigned long)*ptr);
 
        /* Now the indirect block */
        kfree (dir);
 }
 
-static int shm_revalidate(struct shmid_kernel* shp, int shmid, int pagecount, int flg)
+static         int shm_setattr (struct dentry *dentry, struct iattr *attr)
 {
-       struct shmid_kernel* new;
-       new = shm_lock(shmid);
-       if(new==NULL) {
-               return -EIDRM;
-       }
-       if(new!=shp || shm_checkid(shp, shmid) || shp->shm_npages != pagecount) {
-               shm_unlock(shmid);
-               return -EIDRM;
-       }
-       if (ipcperms(&shp->shm_perm, flg)) {
-               shm_unlock(shmid);
-               return -EACCES;
+       int error;
+       struct inode *inode = dentry->d_inode;
+       struct shmid_kernel *shp;
+       unsigned long new_pages, old_pages;
+       pte_t **new_dir, **old_dir;
+
+       if ((error = inode_change_ok(inode, attr)))
+               return error;
+       if (!(attr->ia_valid & ATTR_SIZE))
+               goto set_attr;
+       if (attr->ia_size > shm_ctlmax)
+               return -EFBIG;
+
+       /* We set old_pages and old_dir for easier cleanup */
+       old_pages = new_pages = (attr->ia_size  + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       if (shm_tot + new_pages >= shm_ctlall)
+               return -ENOSPC;
+       if (IS_ERR(old_dir = new_dir = shm_alloc(new_pages)))
+               return PTR_ERR(new_dir);
+
+       if (!(shp = shm_lock(inode->i_ino)))
+               BUG();
+       if (shp->shm_segsz == attr->ia_size)
+               goto out;
+       old_dir = shp->shm_dir;
+       old_pages = shp->shm_npages;
+       if (old_dir){
+               pte_t *swap;
+               int i,j;
+               i = old_pages < new_pages ? old_pages : new_pages;
+               j = i % PTRS_PER_PTE;
+               i /= PTRS_PER_PTE;
+               if (j)
+                       memcpy (new_dir[i], old_dir[i], j * sizeof (pte_t));
+               while (i--) {
+                       swap = new_dir[i];
+                       new_dir[i] = old_dir[i];
+                       old_dir[i] = swap;
+               }
        }
+       shp->shm_dir = new_dir;
+       shp->shm_npages = new_pages;
+       shp->shm_segsz = attr->ia_size;
+out:
+       shm_unlock(inode->i_ino);
+       shm_lockall();
+       shm_tot += new_pages - old_pages;
+       shm_unlockall();
+       shm_free (old_dir, old_pages);
+set_attr:
+       inode_setattr(inode, attr);
        return 0;
 }
 
-static inline struct shmid_kernel *newseg_alloc(int numpages)
+static inline struct shmid_kernel *newseg_alloc(int numpages, size_t namelen)
 {
        struct shmid_kernel *shp;
 
-       shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_KERNEL);
+       shp = (struct shmid_kernel *) kmalloc (sizeof (*shp) + namelen, GFP_KERNEL);
        if (!shp)
                return 0;
 
@@ -203,29 +652,29 @@ static inline struct shmid_kernel *newseg_alloc(int numpages)
                return 0;
        }
        shp->shm_npages = numpages;
-       shp->attaches = NULL;
        shp->shm_nattch = 0;
-       init_MUTEX(&shp->sem);
+       shp->shm_namelen = namelen;
        return(shp);
 }
 
-static int newseg (key_t key, int shmflg, size_t size)
+static int newseg (key_t key, const char *name, int namelen,
+                  int shmflg, size_t size)
 {
        struct shmid_kernel *shp;
        int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
        int id;
 
-       if (size < SHMMIN)
-               return -EINVAL;
+       if (namelen > SHM_NAME_LEN)
+               return -ENAMETOOLONG;
 
        if (size > shm_ctlmax)
                return -EINVAL;
        if (shm_tot + numpages >= shm_ctlall)
                return -ENOSPC;
 
-       if (!(shp = newseg_alloc(numpages)))
+       if (!(shp = newseg_alloc(numpages, namelen ? namelen : SHM_FMT_LEN + 1)))
                return -ENOMEM;
-       id = ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni);
+       id = ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni+1);
        if(id == -1) {
                shm_free(shp->shm_dir,numpages);
                kfree(shp);
@@ -234,16 +683,23 @@ static int newseg (key_t key, int shmflg, size_t size)
        shp->shm_perm.key = key;
        shp->shm_perm.mode = (shmflg & S_IRWXUGO);
        shp->shm_segsz = size;
-       shp->shm_cpid = current->pid;
-       shp->shm_lpid = 0;
-       shp->shm_atime = shp->shm_dtime = 0;
-       shp->shm_ctime = CURRENT_TIME;
+       shp->shm_cprid = current->pid;
+       shp->shm_lprid = 0;
+       shp->shm_atim = shp->shm_dtim = 0;
+       shp->shm_ctim = CURRENT_TIME;
        shp->id = shm_buildid(id,shp->shm_perm.seq);
+       if (namelen != 0) {
+               shp->shm_namelen = namelen;
+               memcpy (shp->shm_name, name, namelen);            
+       } else {
+               shp->shm_namelen = sprintf (shp->shm_name, SHM_FMT, shp->id);
+       }
 
        shm_tot += numpages;
+       used_segs++;
        shm_unlock(id);
-
-       return shm_buildid(id,shp->shm_perm.seq);
+       
+       return shp->id;
 }
 
 asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
@@ -251,21 +707,31 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
        struct shmid_kernel *shp;
        int err, id = 0;
 
+       if (!shm_sb) {
+               printk ("shmget: shm filesystem not mounted\n");
+               return -EINVAL;
+       }
+
+       if (size < SHMMIN)
+               return -EINVAL;
+
        down(&shm_ids.sem);
        if (key == IPC_PRIVATE) {
-               err = newseg(key, shmflg, size);
+               err = newseg(key, NULL, 0, shmflg, size);
        } else if ((id = ipc_findkey(&shm_ids,key)) == -1) {
                if (!(shmflg & IPC_CREAT))
                        err = -ENOENT;
                else
-                       err = newseg(key, shmflg, size);
+                       err = newseg(key, NULL, 0, shmflg, size);
        } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
                err = -EEXIST;
        } else {
                shp = shm_lock(id);
                if(shp==NULL)
                        BUG();
-               if (ipcperms(&shp->shm_perm, shmflg))
+               if (shp->shm_segsz < size)
+                       err = -EINVAL;
+               else if (ipcperms(&shp->shm_perm, shmflg))
                        err = -EACCES;
                else
                        err = shm_buildid(id, shp->shm_perm.seq);
@@ -300,40 +766,26 @@ static void killseg_core(struct shmid_kernel *shp, int doacc)
                shm_rss -= rss;
                shm_swp -= swp;
                shm_tot -= numpages;
+               used_segs--;
                shm_unlockall();
        }
 }
 
-/*
- * Only called after testing nattch and SHM_DEST.
- * Here pages, pgtable and shmid_kernel are freed.
- */
-static void killseg (int shmid)
+static void shm_delete (struct inode *ino)
 {
+       int shmid = ino->i_ino;
        struct shmid_kernel *shp;
 
        down(&shm_ids.sem);
        shp = shm_lock(shmid);
        if(shp==NULL) {
-out_up:
-               up(&shm_ids.sem);
-               return;
-       }
-       if(shm_checkid(shp,shmid) || shp->shm_nattch > 0 ||
-           !(shp->shm_perm.mode & SHM_DEST)) {
-               shm_unlock(shmid);
-               goto out_up;
+               BUG();
        }
        shp = shm_rmid(shmid);
-       if(shp==NULL)
-               BUG();
-       if (!shp->shm_dir)
-               BUG();
        shm_unlock(shmid);
        up(&shm_ids.sem);
        killseg_core(shp, 1);
-
-       return;
+       clear_inode(ino);
 }
 
 static inline unsigned long copy_shmid_to_user(void *buf, struct shmid64_ds *in, int version)
@@ -427,12 +879,29 @@ static inline unsigned long copy_shminfo_to_user(void *buf, struct shminfo64 *in
        }
 }
 
+char * shm_getname(int id)
+{
+       char *result;
+
+       result = __getname ();
+       if (IS_ERR(result))
+               return result;
+
+       sprintf (result, "%s/" SHM_FMT, shm_path, id); 
+       return result;
+}
+
 asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
 {
        struct shm_setbuf setbuf;
        struct shmid_kernel *shp;
        int err, version;
 
+       if (!shm_sb) {
+               printk ("shmctl: shm filesystem not mounted\n");
+               return -EINVAL;
+       }
+
        if (cmd < 0 || shmid < 0)
                return -EINVAL;
 
@@ -481,14 +950,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
        {
                struct shmid64_ds tbuf;
                int result;
+               if ((shmid % SEQ_MULTIPLIER) == zero_id)
+                       return -EINVAL;
                memset(&tbuf, 0, sizeof(tbuf));
                shp = shm_lock(shmid);
                if(shp==NULL)
                        return -EINVAL;
-               if (shp == &zshmid_kernel) {
-                       shm_unlock(shmid);
-                       return -EINVAL;
-               }
                if(cmd==SHM_STAT) {
                        err = -EINVAL;
                        if (shmid > shm_ids.max_id)
@@ -505,11 +972,11 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
                        goto out_unlock;
                kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
                tbuf.shm_segsz  = shp->shm_segsz;
-               tbuf.shm_atime  = shp->shm_atime;
-               tbuf.shm_dtime  = shp->shm_dtime;
-               tbuf.shm_ctime  = shp->shm_ctime;
-               tbuf.shm_cpid   = shp->shm_cpid;
-               tbuf.shm_lpid   = shp->shm_lpid;
+               tbuf.shm_atime  = shp->shm_atim;
+               tbuf.shm_dtime  = shp->shm_dtim;
+               tbuf.shm_ctime  = shp->shm_ctim;
+               tbuf.shm_cpid   = shp->shm_cprid;
+               tbuf.shm_lpid   = shp->shm_lprid;
                tbuf.shm_nattch = shp->shm_nattch;
                shm_unlock(shmid);
                if(copy_shmid_to_user (buf, &tbuf, version))
@@ -523,16 +990,14 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
 /* Should the pages be faulted in here or leave it to user? */
 /* need to determine interaction with current->swappable */
                struct kern_ipc_perm *ipcp;
+               if ((shmid % SEQ_MULTIPLIER)== zero_id)
+                       return -EINVAL;
                if (!capable(CAP_IPC_LOCK))
                        return -EPERM;
 
                shp = shm_lock(shmid);
                if(shp==NULL)
                        return -EINVAL;
-               if (shp == &zshmid_kernel) {
-                       shm_unlock(shmid);
-                       return -EINVAL;
-               }
                err=-EIDRM;
                if(shm_checkid(shp,shmid))
                        goto out_unlock;
@@ -552,50 +1017,56 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
                return err;
        }
        case IPC_RMID:
-       case IPC_SET:
-               break;
-       default:
-               return -EINVAL;
+       {
+               char *name;
+               if ((shmid % SEQ_MULTIPLIER)== zero_id)
+                       return -EINVAL;
+               name = shm_getname(shmid);
+               if (IS_ERR(name))
+                       return PTR_ERR(name);
+               lock_kernel();
+               err = do_unlink (name);
+               unlock_kernel();
+               putname (name);
+               if (err == -ENOENT)
+                       err = -EINVAL;
+               return err;
        }
 
-       if (cmd == IPC_SET) {
+       case IPC_SET:
+       {
+               if ((shmid % SEQ_MULTIPLIER)== zero_id)
+                       return -EINVAL;
+
                if(copy_shmid_from_user (&setbuf, buf, version))
                        return -EFAULT;
-       }
-       down(&shm_ids.sem);
-       shp = shm_lock(shmid);
-       err=-EINVAL;
-       if(shp==NULL)
-               goto out_up;
-       if (shp == &zshmid_kernel)
-               goto out_unlock_up;
-       err=-EIDRM;
-       if(shm_checkid(shp,shmid))
-               goto out_unlock_up;
-       err=-EPERM;
-       if (current->euid != shp->shm_perm.uid &&
-           current->euid != shp->shm_perm.cuid && 
-           !capable(CAP_SYS_ADMIN)) {
-               goto out_unlock_up;
-       }
+               down(&shm_ids.sem);
+               shp = shm_lock(shmid);
+               err=-EINVAL;
+               if(shp==NULL)
+                       goto out_up;
+               err=-EIDRM;
+               if(shm_checkid(shp,shmid))
+                       goto out_unlock_up;
+               err=-EPERM;
+               if (current->euid != shp->shm_perm.uid &&
+                   current->euid != shp->shm_perm.cuid && 
+                   !capable(CAP_SYS_ADMIN)) {
+                       goto out_unlock_up;
+               }
 
-       switch (cmd) {
-       case IPC_SET:
                shp->shm_perm.uid = setbuf.uid;
                shp->shm_perm.gid = setbuf.gid;
                shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO)
                        | (setbuf.mode & S_IRWXUGO);
-               shp->shm_ctime = CURRENT_TIME;
+               shp->shm_ctim = CURRENT_TIME;
                break;
-       case IPC_RMID:
-               shp->shm_perm.mode |= SHM_DEST;
-               if (shp->shm_nattch <= 0) {
-                       shm_unlock(shmid);
-                       up(&shm_ids.sem);
-                       killseg (shmid);
-                       return 0;
-               }
        }
+
+       default:
+               return -EINVAL;
+       }
+
        err = 0;
 out_unlock_up:
        shm_unlock(shmid);
@@ -607,65 +1078,24 @@ out_unlock:
        return err;
 }
 
-/*
- * The per process internal structure for managing segments is
- * `struct vm_area_struct'.
- * A shmat will add to and shmdt will remove from the list.
- * shmd->vm_mm         the attacher
- * shmd->vm_start      virt addr of attach, multiple of SHMLBA
- * shmd->vm_end                multiple of SHMLBA
- * shmd->vm_next       next attach for task
- * shmd->vm_next_share next attach for segment
- * shmd->vm_pgoff      offset into segment (in pages)
- * shmd->vm_private_data               signature for this attach
- */
-
-static struct vm_operations_struct shm_vm_ops = {
-       open:           shm_open,       /* open - callback for a new vm-area open */
-       close:          shm_close,      /* close - callback for when the vm-area is released */
-       nopage:         shm_nopage,
-       swapout:        shm_swapout,
-};
+static inline void shm_inc (int id) {
+       struct shmid_kernel *shp;
 
-/* Insert shmd into the list shp->attaches */
-static inline void insert_attach (struct shmid_kernel * shp, struct vm_area_struct * shmd)
-{
-       if((shmd->vm_next_share = shp->attaches) != NULL)
-               shp->attaches->vm_pprev_share = &shmd->vm_next_share;
-       shp->attaches = shmd;
-       shmd->vm_pprev_share = &shp->attaches;
+       if(!(shp = shm_lock(id)))
+               BUG();
+       shp->shm_atim = CURRENT_TIME;
+       shp->shm_lprid = current->pid;
+       shp->shm_nattch++;
+       shm_unlock(id);
 }
 
-/* Remove shmd from list shp->attaches */
-static inline void remove_attach (struct shmid_kernel * shp, struct vm_area_struct * shmd)
+static int shm_mmap(struct file * file, struct vm_area_struct * vma)
 {
-       if(shmd->vm_next_share)
-               shmd->vm_next_share->vm_pprev_share = shmd->vm_pprev_share;
-       *shmd->vm_pprev_share = shmd->vm_next_share;
-}
-
-/*
- * ensure page tables exist
- * mark page table entries with shm_sgn.
- */
-static int shm_map (struct vm_area_struct *shmd)
-{
-       unsigned long tmp;
-
-       /* clear old mappings */
-       do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
-
-       /* add new mapping */
-       tmp = shmd->vm_end - shmd->vm_start;
-       if((current->mm->total_vm << PAGE_SHIFT) + tmp
-          > (unsigned long) current->rlim[RLIMIT_AS].rlim_cur)
-               return -ENOMEM;
-       current->mm->total_vm += tmp >> PAGE_SHIFT;
-       vmlist_modify_lock(current->mm);
-       insert_vm_struct(current->mm, shmd);
-       merge_segments(current->mm, shmd->vm_start, shmd->vm_end);
-       vmlist_modify_unlock(current->mm);
-
+       if (!(vma->vm_flags & VM_SHARED))
+               return -EINVAL; /* we cannot do private mappings */
+       UPDATE_ATIME(file->f_dentry->d_inode);
+       vma->vm_ops = &shm_vm_ops;
+       shm_inc(file->f_dentry->d_inode->i_ino);
        return 0;
 }
 
@@ -674,137 +1104,57 @@ static int shm_map (struct vm_area_struct *shmd)
  */
 asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
 {
-       struct shmid_kernel *shp;
-       struct vm_area_struct *shmd;
-       int err;
        unsigned long addr;
-       unsigned long len;
-       short flg = shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO;
+       struct file * file;
+       int    err;
+       int    flags;
+       char   *name;
 
-
-       if (shmid < 0)
+       if (!shm_sb || (shmid % SEQ_MULTIPLIER) == zero_id)
                return -EINVAL;
 
-       down(&current->mm->mmap_sem);
-       err = -EINVAL;
-       shp = shm_lock(shmid);
-       if (!shp)
-               goto out_up;
-       if (shp == &zshmid_kernel)
-               goto out_unlock_up;
-
-       err = -EACCES;
-       if (ipcperms(&shp->shm_perm, flg))
-               goto out_unlock_up;
-
-       err = -EIDRM;
-       if (shm_checkid(shp,shmid))
-               goto out_unlock_up;
-
-       if (!(addr = (ulong) shmaddr)) {
-               if (shmflg & SHM_REMAP)
-                       goto out_unlock_up;
-               err = -ENOMEM;
-               addr = 0;
-       again:
-               if (!(addr = get_unmapped_area(addr, (unsigned long)shp->shm_segsz)))
-                       goto out_unlock_up;
-               if(addr & (SHMLBA - 1)) {
-                       addr = (addr + (SHMLBA - 1)) & ~(SHMLBA - 1);
-                       goto again;
+       if ((addr = (ulong)shmaddr))
+       {
+               if(addr & (SHMLBA-1)) {
+                       if (shmflg & SHM_RND)
+                               addr &= ~(SHMLBA-1);       /* round down */
+                       else
+                               return -EINVAL;
                }
-       } else if (addr & (SHMLBA-1)) {
-               err=-EINVAL;
-               if (shmflg & SHM_RND)
-                       addr &= ~(SHMLBA-1);       /* round down */
-               else
-                       goto out_unlock_up;
-       }
-       /*
-        * Check if addr exceeds TASK_SIZE (from do_mmap)
-        */
-       len = PAGE_SIZE*shp->shm_npages;
-       err = -EINVAL;
-       if (addr >= TASK_SIZE || len > TASK_SIZE  || addr > TASK_SIZE - len)
-               goto out_unlock_up;
-       /*
-        * If shm segment goes below stack, make sure there is some
-        * space left for the stack to grow (presently 4 pages).
-        */
-       if (addr < current->mm->start_stack &&
-           addr > current->mm->start_stack - PAGE_SIZE*(shp->shm_npages + 4))
-               goto out_unlock_up;
-       if (!(shmflg & SHM_REMAP) && find_vma_intersection(current->mm, addr, addr + (unsigned long)shp->shm_segsz))
-               goto out_unlock_up;
+               flags = MAP_SHARED | MAP_FIXED;
+       } else
+               flags = MAP_SHARED;
 
-       shm_unlock(shmid);
-       err = -ENOMEM;
-       shmd = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-       err = shm_revalidate(shp, shmid, len/PAGE_SIZE,flg);
-       if(err) {
-               kmem_cache_free(vm_area_cachep, shmd);
-               goto out_up;
-       }
+       name = shm_getname(shmid);
+       if (IS_ERR (name))
+               return PTR_ERR (name);
 
-       shmd->vm_private_data = shp;
-       shmd->vm_start = addr;
-       shmd->vm_end = addr + shp->shm_npages * PAGE_SIZE;
-       shmd->vm_mm = current->mm;
-       shmd->vm_page_prot = (shmflg & SHM_RDONLY) ? PAGE_READONLY : PAGE_SHARED;
-       shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED
-                        | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC
-                        | ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE | VM_WRITE);
-       shmd->vm_file = NULL;
-       shmd->vm_pgoff = 0;
-       shmd->vm_ops = &shm_vm_ops;
-
-       shp->shm_nattch++;          /* prevent destruction */
-       shm_unlock(shp->id);
-       err = shm_map (shmd);
-       shm_lock(shmid); /* cannot fail */
-       if (err)
-               goto failed_shm_map;
-
-       insert_attach(shp,shmd);  /* insert shmd into shp->attaches */
-
-       shp->shm_lpid = current->pid;
-       shp->shm_atime = CURRENT_TIME;
-
-       *raddr = addr;
-       err = 0;
-out_unlock_up:
-       shm_unlock(shmid);
-out_up:
-       up(&current->mm->mmap_sem);
+       file = filp_open (name, O_RDWR, 0);
+       putname (name);
+       if (IS_ERR (file))
+               goto bad_file;
+       lock_kernel();
+       *raddr = do_mmap (file, addr, file->f_dentry->d_inode->i_size,
+                         (shmflg & SHM_RDONLY ? PROT_READ :
+                          PROT_READ | PROT_WRITE), flags, 0);
+       unlock_kernel();
+       if (IS_ERR(*raddr))
+               err = PTR_ERR(*raddr);
+       else
+               err = 0;
+       fput (file);
        return err;
 
-failed_shm_map:
-       {
-               int delete = 0;
-               if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
-                       delete = 1;
-               shm_unlock(shmid);
-               up(&current->mm->mmap_sem);
-               kmem_cache_free(vm_area_cachep, shmd);
-               if(delete)
-                       killseg(shmid);
-               return err;
-       }
+bad_file:
+       if ((err = PTR_ERR(file)) == -ENOENT)
+               return -EINVAL;
+       return err;
 }
 
 /* This is called by fork, once for every shm attach. */
 static void shm_open (struct vm_area_struct *shmd)
 {
-       struct shmid_kernel *shp;
-
-       shp = (struct shmid_kernel *) shmd->vm_private_data;
-       if(shp != shm_lock(shp->id))
-               BUG();
-       insert_attach(shp,shmd);  /* insert shmd into shp->attaches */
-       shp->shm_nattch++;
-       shp->shm_atime = CURRENT_TIME;
-       shp->shm_lpid = current->pid;
-       shm_unlock(shp->id);
+       shm_inc (shmd->vm_file->f_dentry->d_inode->i_ino);
 }
 
 /*
@@ -815,22 +1165,16 @@ static void shm_open (struct vm_area_struct *shmd)
  */
 static void shm_close (struct vm_area_struct *shmd)
 {
+       int id = shmd->vm_file->f_dentry->d_inode->i_ino;
        struct shmid_kernel *shp;
-       int id;
 
        /* remove from the list of attaches of the shm segment */
-       shp = (struct shmid_kernel *) shmd->vm_private_data;
-       if(shp != shm_lock(shp->id))
+       if(!(shp = shm_lock(id)))
                BUG();
-       remove_attach(shp,shmd);  /* remove from shp->attaches */
-       shp->shm_lpid = current->pid;
-       shp->shm_dtime = CURRENT_TIME;
-       id=-1;
-       if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
-               id=shp->id;
-       shm_unlock(shp->id);
-       if(id!=-1)
-               killseg(id);
+       shp->shm_lprid = current->pid;
+       shp->shm_dtim = CURRENT_TIME;
+       shp->shm_nattch--;
+       shm_unlock(id);
 }
 
 /*
@@ -868,31 +1212,13 @@ static int shm_swapout(struct page * page, struct file *file)
 /*
  * page not present ... go through shm_dir
  */
-static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long address, int no_share)
+static struct page * shm_nopage_core(struct shmid_kernel *shp, unsigned int idx, int *swp, int *rss)
 {
        pte_t pte;
-       struct shmid_kernel *shp;
-       unsigned int idx;
        struct page * page;
-       int is_shmzero;
-
-       shp = (struct shmid_kernel *) shmd->vm_private_data;
-       idx = (address - shmd->vm_start) >> PAGE_SHIFT;
-       idx += shmd->vm_pgoff;
-       is_shmzero = (shp->id == zero_id);
 
-       /*
-        * A shared mapping past the last page of the file is an error
-        * and results in a SIGBUS, so logically a shared mapping past 
-        * the end of a shared memory segment should result in SIGBUS
-        * as well.
-        */
-       if (idx >= shp->shm_npages) { 
-               return NULL;
-       }
-       down(&shp->sem);
-       if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
-               BUG();
+       if (idx >= shp->shm_npages)
+               goto sigbus;
 
        pte = SHM_ENTRY(shp,idx);
        if (!pte_present(pte)) {
@@ -905,7 +1231,7 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
                        if (!page)
                                goto oom;
                        clear_highpage(page);
-                       if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
+                       if ((shp != shm_lock(shp->id)) && (shp->id != zero_id))
                                BUG();
                } else {
                        swp_entry_t entry = pte_to_swp_entry(pte);
@@ -923,11 +1249,11 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
                        delete_from_swap_cache(page);
                        page = replace_with_highmem(page);
                        swap_free(entry);
-                       if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
+                       if ((shp != shm_lock(shp->id)) && (shp->id != zero_id))
                                BUG();
-                       if (is_shmzero == 0) shm_swp--;
+                       (*swp)--;
                }
-               if (is_shmzero == 0) shm_rss++;
+               (*rss)++;
                pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
                SHM_ENTRY(shp, idx) = pte;
        } else
@@ -935,14 +1261,32 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
 
        /* pte_val(pte) == SHM_ENTRY (shp, idx) */
        get_page(pte_page(pte));
-       shm_unlock(shp->id);
-       up(&shp->sem);
        current->min_flt++;
        return pte_page(pte);
 
 oom:
-       up(&shp->sem);
        return NOPAGE_OOM;
+sigbus:
+       return NOPAGE_SIGBUS;
+}
+
+static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long address, int no_share)
+{
+       struct page * page;
+       struct shmid_kernel *shp;
+       unsigned int idx;
+       struct inode * inode = shmd->vm_file->f_dentry->d_inode;
+
+       idx = (address - shmd->vm_start) >> PAGE_SHIFT;
+       idx += shmd->vm_pgoff;
+
+       down(&inode->i_sem);
+       if(!(shp = shm_lock(inode->i_ino)))
+               BUG();
+       page = shm_nopage_core(shp, idx, &shm_swp, &shm_rss);
+       shm_unlock(inode->i_ino);
+       up(&inode->i_sem);
+       return(page);
 }
 
 #define OKAY   0
@@ -1127,38 +1471,40 @@ static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int l
        int i, len = 0;
 
        down(&shm_ids.sem);
-       len += sprintf(buffer, "       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime\n");
+       len += sprintf(buffer, "       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime name\n");
 
-       for(i = 0; i <= shm_ids.max_id; i++) {
-               struct shmid_kernel* shp = shm_lock(i);
-               if (shp == &zshmid_kernel) {
-                       shm_unlock(i);
+       for(i = 0; i <= shm_ids.max_id; i++) {
+               struct shmid_kernel* shp;
+
+               if (i == zero_id)
                        continue;
-               }
+               shp = shm_lock(i);
                if(shp!=NULL) {
-#define SMALL_STRING "%10d %10d  %4o %10u %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
-#define BIG_STRING   "%10d %10d  %4o %21u %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
+#define SMALL_STRING "%10d %10d  %4o %10u %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu %.*s\n"
+#define BIG_STRING   "%10d %10d  %4o %21u %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu %.*s\n"
                        char *format;
 
                        if (sizeof(size_t) <= sizeof(int))
                                format = SMALL_STRING;
                        else
                                format = BIG_STRING;
-                       len += sprintf(buffer + len, format,
+                       len += sprintf(buffer + len, format,
                                shp->shm_perm.key,
                                shm_buildid(i, shp->shm_perm.seq),
                                shp->shm_perm.mode,
                                shp->shm_segsz,
-                               shp->shm_cpid,
-                               shp->shm_lpid,
+                               shp->shm_cprid,
+                               shp->shm_lprid,
                                shp->shm_nattch,
                                shp->shm_perm.uid,
                                shp->shm_perm.gid,
                                shp->shm_perm.cuid,
                                shp->shm_perm.cgid,
-                               shp->shm_atime,
-                               shp->shm_dtime,
-                               shp->shm_ctime);
+                               shp->shm_atim,
+                               shp->shm_dtim,
+                               shp->shm_ctim,
+                               shp->shm_namelen,
+                               shp->shm_name);
                        shm_unlock(i);
 
                        pos += len;
@@ -1183,31 +1529,85 @@ done:
 }
 #endif
 
-static struct shmid_kernel *zmap_list = 0;
+#define VMA_TO_SHP(vma)                ((vma)->vm_file->private_data)
+
+static LIST_HEAD(zmap_list);
 static spinlock_t zmap_list_lock = SPIN_LOCK_UNLOCKED;
 static unsigned long zswap_idx = 0; /* next to swap */
-static struct shmid_kernel *zswap_shp = 0;
+static struct shmid_kernel *zswap_shp = (struct shmid_kernel *)&zmap_list;
+static int zshm_rss;
 
 static struct vm_operations_struct shmzero_vm_ops = {
        open:           shmzero_open,
        close:          shmzero_close,
-       nopage:         shm_nopage,
+       nopage:         shmzero_nopage,
        swapout:        shm_swapout,
 };
 
+/*
+ * In this implementation, the "unuse" and "swapout" interfaces are
+ * interlocked out via the kernel_lock, as well as shm_lock(zero_id).
+ * "unuse" and "nopage/swapin", as well as "swapout" and "nopage/swapin"
+ * interlock via shm_lock(zero_id). All these interlocks can be based
+ * on a per mapping lock instead of being a global lock.
+ */
+/*
+ * Reference (existance) counting on the file/dentry/inode is done
+ * by generic vm_file code. The zero code does not hold any reference 
+ * on the pseudo-file. This is possible because the open/close calls
+ * are bracketed by the file count update calls.
+ */
+static struct file *file_setup(struct file *fzero, struct shmid_kernel *shp)
+{
+       struct file *filp;
+       struct inode *inp;
+
+       if ((filp = get_empty_filp()) == 0)
+               return(filp);
+       if ((inp = get_empty_inode()) == 0) {
+               put_filp(filp);
+               return(0);
+       }
+       if ((filp->f_dentry = d_alloc(zdent, &(const struct qstr) { "dev/zero", 
+                               8, 0 })) == 0) {
+               iput(inp);
+               put_filp(filp);
+               return(0);
+       }
+       d_instantiate(filp->f_dentry, inp);
+
+       /*
+        * Copy over /dev/zero dev/ino for benefit of procfs. Use
+        * ino to indicate seperate mappings.
+        */
+       filp->f_dentry->d_inode->i_dev = fzero->f_dentry->d_inode->i_dev;
+       filp->f_dentry->d_inode->i_ino = (unsigned long)shp;
+       fput(fzero);    /* release /dev/zero file */
+       return(filp);
+}
+
 int map_zero_setup(struct vm_area_struct *vma)
 {
+       extern int vm_enough_memory(long pages);
        struct shmid_kernel *shp;
+       struct file *filp;
 
-       if (!(shp = newseg_alloc((vma->vm_end - vma->vm_start) / PAGE_SIZE)))
+       if (!vm_enough_memory((vma->vm_end - vma->vm_start) >> PAGE_SHIFT))
+               return -ENOMEM;
+       if (!(shp = newseg_alloc((vma->vm_end - vma->vm_start) / PAGE_SIZE, 0)))
+               return -ENOMEM;
+       if ((filp = file_setup(vma->vm_file, shp)) == 0) {
+               killseg_core(shp, 0);
                return -ENOMEM;
-       shp->id = zero_id;      /* hack for shm_lock et al */
-       vma->vm_private_data = shp;
+       }
+       vma->vm_file = filp;
+       VMA_TO_SHP(vma) = (void *)shp;
+       shp->id = zero_id;
+       init_MUTEX(&shp->zsem);
        vma->vm_ops = &shmzero_vm_ops;
        shmzero_open(vma);
        spin_lock(&zmap_list_lock);
-       shp->attaches = (struct vm_area_struct *)zmap_list;
-       zmap_list = shp;
+       list_add(&shp->zero_list, &zmap_list);
        spin_unlock(&zmap_list_lock);
        return 0;
 }
@@ -1216,53 +1616,66 @@ static void shmzero_open(struct vm_area_struct *shmd)
 {
        struct shmid_kernel *shp;
 
-       shp = (struct shmid_kernel *) shmd->vm_private_data;
-       down(&shp->sem);
+       shp = VMA_TO_SHP(shmd);
+       down(&shp->zsem);
        shp->shm_nattch++;
-       up(&shp->sem);
+       up(&shp->zsem);
 }
 
 static void shmzero_close(struct vm_area_struct *shmd)
 {
        int done = 0;
-       struct shmid_kernel *shp, *prev, *cur;
+       struct shmid_kernel *shp;
 
-       shp = (struct shmid_kernel *) shmd->vm_private_data;
-       down(&shp->sem);
+       shp = VMA_TO_SHP(shmd);
+       down(&shp->zsem);
        if (--shp->shm_nattch == 0)
                done = 1;
-       up(&shp->sem);
+       up(&shp->zsem);
        if (done) {
                spin_lock(&zmap_list_lock);
                if (shp == zswap_shp)
-                       zswap_shp = (struct shmid_kernel *)(shp->attaches);
-               if (shp == zmap_list)
-                       zmap_list = (struct shmid_kernel *)(shp->attaches);
-               else {
-                       prev = zmap_list;
-                       cur = (struct shmid_kernel *)(prev->attaches);
-                       while (cur != shp) {
-                               prev = cur;
-                               cur = (struct shmid_kernel *)(prev->attaches);
-                       }
-                       prev->attaches = (struct vm_area_struct *)(shp->attaches);
-               }
+                       zswap_shp = list_entry(zswap_shp->zero_list.next, 
+                                               struct shmid_kernel, zero_list);
+               list_del(&shp->zero_list);
                spin_unlock(&zmap_list_lock);
                killseg_core(shp, 0);
        }
 }
 
+static struct page * shmzero_nopage(struct vm_area_struct * shmd, unsigned long address, int no_share)
+{
+       struct page *page;
+       struct shmid_kernel *shp;
+       unsigned int idx;
+       int dummy;
+
+       idx = (address - shmd->vm_start) >> PAGE_SHIFT;
+       idx += shmd->vm_pgoff;
+
+       shp = VMA_TO_SHP(shmd);
+       down(&shp->zsem);
+       shm_lock(zero_id);
+       page = shm_nopage_core(shp, idx, &dummy, &zshm_rss);
+       shm_unlock(zero_id);
+       up(&shp->zsem);
+       return(page);
+}
+
 static void zmap_unuse(swp_entry_t entry, struct page *page)
 {
        struct shmid_kernel *shp;
 
        spin_lock(&zmap_list_lock);
-       shp = zmap_list;
-       while (shp) {
+       shm_lock(zero_id);
+       for (shp = list_entry(zmap_list.next, struct shmid_kernel, zero_list);
+                       shp != (struct shmid_kernel *)&zmap_list;
+                       shp = list_entry(shp->zero_list.next, struct shmid_kernel,
+                                                               zero_list)) {
                if (shm_unuse_core(shp, entry, page))
                        break;
-               shp = (struct shmid_kernel *)shp->attaches;
        }
+       shm_unlock(zero_id);
        spin_unlock(&zmap_list_lock);
 }
 
@@ -1275,7 +1688,7 @@ static void zshm_swap (int prio, int gfp_mask, zone_t *zone)
        int counter;
        struct page * page_map;
 
-       counter = 10;   /* maybe we should use zshm_rss */
+       counter = zshm_rss >> prio;
        if (!counter)
                return;
 next:
@@ -1283,25 +1696,30 @@ next:
                return;
 
        spin_lock(&zmap_list_lock);
-       if (zmap_list == 0)
+       shm_lock(zero_id);
+       if (zmap_list.next == 0)
                goto failed;
 next_id:
-       if ((shp = zswap_shp) == 0) {
+       if (zswap_shp == (struct shmid_kernel *)&zmap_list) {
                if (loop) {
 failed:
+                       shm_unlock(zero_id);
                        spin_unlock(&zmap_list_lock);
                        __swap_free(swap_entry, 2);
                        return;
                }
-               zswap_shp = shp = zmap_list;
+               zswap_shp = list_entry(zmap_list.next, struct shmid_kernel, 
+                                                               zero_list);
                zswap_idx = 0;
                loop = 1;
        }
+       shp = zswap_shp;
 
 check_table:
        idx = zswap_idx++;
        if (idx >= shp->shm_npages) {
-               zswap_shp = (struct shmid_kernel *)(zswap_shp->attaches);
+               zswap_shp = list_entry(zswap_shp->zero_list.next, 
+                                       struct shmid_kernel, zero_list);
                zswap_idx = 0;
                goto next_id;
        }
@@ -1310,6 +1728,7 @@ check_table:
                case RETRY: goto check_table;
                case FAILED: goto failed;
        }
+       shm_unlock(zero_id);
        spin_unlock(&zmap_list_lock);
 
        shm_swap_postop(page_map);
@@ -1317,3 +1736,4 @@ check_table:
                goto next;
        return;
 }
+
index 1c929256a18b14e152b686640b686dd48ed4118d..580bef8afa6f0c7ee53aafc53383c666c9dcd731 100644 (file)
@@ -40,9 +40,6 @@ void __init ipc_init_ids(struct ipc_ids* ids, int size)
        if(size > IPCMNI)
                size = IPCMNI;
        ids->size = size;
-       if(size == 0)
-               return;
-
        ids->in_use = 0;
        ids->max_id = -1;
        ids->seq = 0;
index fdadf7a9f8ae930e5a8bb5c9d5d53ee2ab7806aa..63e66a558d50ea7c574aa94c21bc3fe87dbc2ca5 100644 (file)
@@ -88,24 +88,16 @@ void acct_timeout(unsigned long unused)
  */
 static int check_free_space(struct file *file)
 {
-       mm_segment_t fs;
        struct statfs sbuf;
-       struct super_block *sb;
        int res = acct_active;
        int act;
 
        if (!file || !acct_needcheck)
                return res;
 
-       sb = file->f_dentry->d_inode->i_sb;
-       if (!sb->s_op || !sb->s_op->statfs)
-               return res;
-
-       fs = get_fs();
-       set_fs(KERNEL_DS);
        /* May block */
-       sb->s_op->statfs(sb, &sbuf, sizeof(struct statfs));
-       set_fs(fs);
+       if (vfs_statfs(file->f_dentry->d_inode->i_sb, &sbuf))
+               return res;
 
        if (sbuf.f_bavail <= SUSPEND * sbuf.f_blocks / 100)
                act = -1;
index 08af7c6377c25c4a805627bd54d2d98b1b7af738..c578e0d2f9a9a046ecef07d059e9fbb6edd55054 100644 (file)
@@ -393,6 +393,7 @@ EXPORT_SYMBOL(schedule_timeout);
 EXPORT_SYMBOL(jiffies);
 EXPORT_SYMBOL(xtime);
 EXPORT_SYMBOL(do_gettimeofday);
+EXPORT_SYMBOL(do_settimeofday);
 #ifndef __ia64__
 EXPORT_SYMBOL(loops_per_sec);
 #endif
index efcda3de47e7f88c8f1b987de368e43d23a25539..c49f1eb05aa314ec4d0d2d96280cf859c9da8ef9 100644 (file)
@@ -57,8 +57,7 @@ extern int sg_big_buff;
 #endif
 #ifdef CONFIG_SYSVIPC
 extern size_t shm_ctlmax;
-extern int shm_ctlall;
-extern int shm_ctlmni;
+extern char shm_path[];
 extern int msg_ctlmax;
 extern int msg_ctlmnb;
 extern int msg_ctlmni;
@@ -200,12 +199,10 @@ static ctl_table kern_table[] = {
        {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
         0644, NULL, &proc_dointvec},
 #ifdef CONFIG_SYSVIPC
+       {KERN_SHMPATH, "shmpath", &shm_path, 256,
+        0644, NULL, &proc_dostring, &sysctl_string },
        {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
         0644, NULL, &proc_doulongvec_minmax},
-       {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (int),
-        0644, NULL, &proc_dointvec},
-       {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
-        0644, NULL, &proc_dointvec},
        {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
         0644, NULL, &proc_dointvec},
        {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
index 5a6820972026d37e4458b4ba32ce3213ae23786e..b650babc8ded090b2ca193042e799f81933066ec 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -305,14 +305,14 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
                        atomic_dec(&file->f_dentry->d_inode->i_writecount);
                        correct_wcount = 1;
                }
+               vma->vm_file = file;
+               get_file(file);
                error = file->f_op->mmap(file, vma);
                /* Fix up the count if necessary, then check for an error */
                if (correct_wcount)
                        atomic_inc(&file->f_dentry->d_inode->i_writecount);
                if (error)
                        goto unmap_and_free_vma;
-               vma->vm_file = file;
-               get_file(file);
        }
 
        /*
@@ -334,6 +334,8 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
        return addr;
 
 unmap_and_free_vma:
+       vma->vm_file = NULL;
+       fput(file);
        /* Undo any partial mapping done by a device driver. */
        flush_cache_range(mm, vma->vm_start, vma->vm_end);
        zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start);
index 833846406b200e109fc8148eb059df0ec8e98705..624885478fa26d62f7a338401357b8de8db01b7e 100644 (file)
@@ -54,11 +54,11 @@ if [ "$CONFIG_IPX" != "n" ]; then
    source net/ipx/Config.in
 fi
 tristate 'Appletalk protocol support' CONFIG_ATALK
+tristate 'DECnet Support' CONFIG_DECNET
+if [ "$CONFIG_DECNET" != "n" ]; then
+   source net/decnet/Config.in
+fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   tristate 'DECnet Support (EXPERIMENTAL)' CONFIG_DECNET
-   if [ "$CONFIG_DECNET" != "n" ]; then
-      source net/decnet/Config.in
-   fi
    tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
    tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE
index b11cdfa22467559c6c79c39c4ab12b039ab57f3d..c019d3f597f6e2602481167d9466f227f9a86e94 100644 (file)
@@ -5,7 +5,6 @@ bool '  DECnet: SIOCGIFCONF support' CONFIG_DECNET_SIOCGIFCONF
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    bool '  DECnet: router support (EXPERIMENTAL)' CONFIG_DECNET_ROUTER
    if [ "$CONFIG_DECNET_ROUTER"  = "y" ]; then
-      bool '    DECnet: use FWMARK value as routing key' CONFIG_DECNET_ROUTE_FWMARK
+      bool '    DECnet: use FWMARK value as routing key (EXPERIMENTAL)' CONFIG_DECNET_ROUTE_FWMARK
    fi
 fi
-bool '  DECnet: raw socket support' CONFIG_DECNET_RAW
index 1eeef6b40b6d85eea543cb2ea55f823ebedd16a3..03d35cc9c7fed782eea99861c4cf4e39ed00f330 100644 (file)
@@ -8,10 +8,6 @@ ifeq ($(CONFIG_DECNET_ROUTER),y)
 O_OBJS += dn_fib.o dn_rules.o dn_table.o
 endif
 
-ifeq ($(CONFIG_DECNET_RAW),y)
-O_OBJS += dn_raw.o
-endif
-
 ifeq ($(CONFIG_DECNET_FW),y)
 O_OBJS += dn_fw.o
 endif
index 0f5c3a649ef56b29d5ae0d5d2083f7b6f38089be..72ab936a2f4f1aa7be104f7264e3f09fd12f8a2b 100644 (file)
@@ -4,8 +4,6 @@ Steve's quick list of things that need finishing off:
  o Proper timeouts on each neighbour (in routing mode) rather than
    just the 60 second On-Ethernet cache value.
 
- o Misc. get/set_sockopt() functions [done for the time being, more later]
-
  o Support for X.25 linklayer
 
  o Support for DDCMP link layer
@@ -14,10 +12,6 @@ Steve's quick list of things that need finishing off:
 
  o PPP support (rfc1762)
 
- o sendmsg() in the raw socket layer (yes, its for sending routing messages)
-
- o Fix /proc for raw sockets
-
  o Lots of testing with real applications
 
  o Verify errors etc. against POSIX 1003.1g (draft)
index 7860597ab9bb7b9cf3d5ff84d5e353a3713dabe0..a2453c06a1a0e039f242e44af3ebb8ae9531d290 100644 (file)
@@ -123,7 +123,6 @@ Version 0.0.6    2.1.110   07-aug-98   Eduardo Marcelo Serrat
 #include <net/dn_dev.h>
 #include <net/dn_route.h>
 #include <net/dn_fib.h>
-#include <net/dn_raw.h>
 #include <net/dn_neigh.h>
 
 #define MAX(a,b) ((a)>(b)?(a):(b))
@@ -401,11 +400,6 @@ struct sock *dn_alloc_sock(struct socket *sock, int flags)
                goto no_sock;
 
        if (sock) {
-#ifdef CONFIG_DECNET_RAW
-               if (sock->type == SOCK_RAW)
-                       sock->ops = &dn_raw_proto_ops;
-               else
-#endif /* CONFIG_DECNET_RAW */
                        sock->ops = &dn_proto_ops;
        }
        sock_init_data(sock,sk);
@@ -647,13 +641,6 @@ static int dn_create(struct socket *sock, int protocol)
                        break;
                case SOCK_STREAM:
                        break;
-#ifdef CONFIG_DECNET_RAW
-               case SOCK_RAW:
-                       if ((protocol != DNPROTO_NSP) &&
-                                       (protocol != DNPROTO_ROU))
-                               return -EPROTONOSUPPORT;
-                       break;
-#endif /* CONFIG_DECNET_RAW */
                default:
                        return -ESOCKTNOSUPPORT;
        }
@@ -1095,6 +1082,7 @@ static unsigned int dn_poll(struct file *file, struct socket *sock, poll_table
 static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
+       struct dn_scp *scp = &sk->protinfo.dn;
        int err = -EOPNOTSUPP;
        unsigned long amount = 0;
        struct sk_buff *skb;
@@ -1221,8 +1209,17 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
        case TIOCINQ:
                lock_sock(sk);
-               if ((skb = skb_peek(&sk->receive_queue)) != NULL)
+               if ((skb = skb_peek(&scp->other_receive_queue)) != NULL) {
                        amount = skb->len;
+               } else {
+                       struct sk_buff *skb = sk->receive_queue.next;
+                       for(;;) {
+                               if (skb == (struct sk_buff *)&sk->receive_queue)
+                                       break;
+                               amount += skb->len;
+                               skb = skb->next;
+                       }
+               }
                release_sock(sk);
                err = put_user(amount, (int *)arg);
                break;
@@ -2028,11 +2025,7 @@ static int dn_get_info(char *buffer, char **start, off_t offset, int length)
        return len;
 }
 
-#ifdef CONFIG_DECNET_RAW
-
-extern int dn_raw_get_info(char *, char **, off_t, int);
 
-#endif /* CONFIG_DECNET_RAW */
 static struct net_proto_family dn_family_ops = {
        AF_DECnet,
        dn_create
@@ -2066,16 +2059,14 @@ void dn_unregister_sysctl(void);
 
 void __init decnet_proto_init(struct net_proto *pro)
 {
-        printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.38s (C) 1995-1999 Linux DECnet Project Team\n");
+        printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.49s (C) 1995-2000 Linux DECnet Project Team\n");
 
        sock_register(&dn_family_ops);
        dev_add_pack(&dn_dix_packet_type);
        register_netdevice_notifier(&dn_dev_notifier);
 
        proc_net_create("decnet", 0, dn_get_info);
-#ifdef CONFIG_DECNET_RAW
-       proc_net_create("decnet_raw", 0, dn_raw_get_info);
-#endif
+
        dn_neigh_init();
        dn_dev_init();
        dn_route_init();
@@ -2153,9 +2144,6 @@ void __exit cleanup_module(void)
 #endif /* CONFIG_DECNET_ROUTER */
 
        proc_net_remove("decnet");
-#ifdef CONFIG_DECNET_RAW
-       proc_net_remove("decnet_raw");
-#endif
 
        dev_remove_pack(&dn_dix_packet_type);
        sock_unregister(AF_DECnet);
index 66c72b4bd0ffff7db217c8d088473b82cc5e1513..854ed0e9203ca504ff826a3eb65db9ab68c0da7a 100644 (file)
@@ -70,7 +70,6 @@
 #include <net/dn_nsp.h>
 #include <net/dn_dev.h>
 #include <net/dn_route.h>
-#include <net/dn_raw.h>
 
 
 /*
@@ -320,7 +319,7 @@ static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb)
        struct dn_scp *scp = &sk->protinfo.dn;
        unsigned short reason;
 
-       if (skb->len < 2)
+       if (skb->len != 2)
                goto out;
 
        reason = dn_ntohs(*(__u16 *)skb->data);
@@ -552,10 +551,6 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
        if (decnet_debug_level & 2)
                printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags);
 
-#ifdef CONFIG_DECNET_RAW
-       dn_raw_rx_nsp(skb);
-#endif /* CONFIG_DECNET_RAW */
-
        if (skb->len < 2) 
                goto free_out;
 
index e4d0adad3b50c40936eca38053f629a95ff7f8bd..ebbf4163f2d516ab7b0bfd29bb07ab18e8e5f40c 100644 (file)
@@ -511,7 +511,7 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
                        int ddl, unsigned char *dd, __u16 rem, __u16 loc)
 {
        struct sk_buff *skb = NULL;
-       int size = 8 + ddl;
+       int size = 7 + ddl + ((msgflg == NSP_DISCINIT) ? 1 : 0);
        unsigned char *msg;
 
        if ((dst == NULL) || (rem == 0)) {
@@ -531,7 +531,8 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
        msg += 2;
        *(__u16 *)msg = dn_htons(reason);
        msg += 2;
-       *msg++ = ddl;
+       if (msgflg == NSP_DISCINIT)
+               *msg++ = ddl;
 
        if (ddl) {
                memcpy(msg, dd, ddl);
diff --git a/net/decnet/dn_raw.c b/net/decnet/dn_raw.c
deleted file mode 100644 (file)
index 90e9b2b..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * DECnet       An implementation of the DECnet protocol suite for the LINUX
- *              operating system.  DECnet is implemented using the  BSD Socket
- *              interface as the means of communication with the user level.
- *
- *              DECnet Raw Sockets Interface
- *
- * Author:      Steve Whitehouse <SteveW@ACM.org>
- *
- *
- * Changes:
- *           Steve Whitehouse - connect() function.
- *           Steve Whitehouse - SMP changes, removed MOP stubs. MOP will
- *                              be userland only.
- */
-
-#include <linux/config.h>
-#include <linux/net.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <net/sock.h>
-#include <net/dst.h>
-#include <net/dn.h>
-#include <net/dn_raw.h>
-#include <net/dn_route.h>
-
-static rwlock_t dn_raw_hash_lock = RW_LOCK_UNLOCKED;
-static struct sock *dn_raw_nsp_sklist = NULL;
-static struct sock *dn_raw_routing_sklist = NULL;
-
-static void dn_raw_hash(struct sock *sk)
-{
-       struct sock **skp;
-
-       switch(sk->protocol) {
-               case DNPROTO_NSP:
-                       skp = &dn_raw_nsp_sklist;
-                       break;
-               case DNPROTO_ROU:
-                       skp = &dn_raw_routing_sklist;
-                       break;
-               default:
-                       printk(KERN_DEBUG "dn_raw_hash: Unknown protocol\n");
-                       return;
-       }
-
-       write_lock_bh(&dn_raw_hash_lock);
-       sk->next = *skp;
-       sk->pprev = skp;
-       *skp = sk;
-       write_unlock_bh(&dn_raw_hash_lock);
-}
-
-static void dn_raw_unhash(struct sock *sk)
-{
-       struct sock **skp = sk->pprev;
-
-       if (skp == NULL)
-               return;
-
-       write_lock_bh(&dn_raw_hash_lock);
-       while(*skp != sk)
-               skp = &((*skp)->next);
-       *skp = sk->next;
-       write_unlock_bh(&dn_raw_hash_lock);
-
-       sk->next = NULL;
-       sk->pprev = NULL;
-}
-
-static void dn_raw_autobind(struct sock *sk)
-{
-       dn_raw_hash(sk);
-       sk->zapped = 0;
-}
-
-static int dn_raw_release(struct socket *sock)
-{
-       struct sock *sk = sock->sk;
-
-       if (sk == NULL)
-               return 0;
-
-       if (!sk->dead) sk->state_change(sk);
-
-       sk->dead = 1;
-       sk->socket = NULL;
-       sock->sk = NULL;
-
-       dn_raw_unhash(sk);
-       sock_put(sk);
-
-       return 0;
-}
-
-/*
- * Bind does odd things with raw sockets. Its basically used to filter
- * the incoming packets, but this differs with the different layers
- * at which you extract packets.
- *
- * For Routing layer sockets, the object name is a host ordered unsigned
- * short which is a mask for the 16 different types of possible routing
- * packet. I'd like to also select by destination address of the packets
- * but alas, this is rather too difficult to do at the moment.
- */
-static int dn_raw_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
-{
-       struct sock *sk = sock->sk;
-       struct sockaddr_dn *addr = (struct sockaddr_dn *)uaddr;
-
-       if (addr_len != sizeof(struct sockaddr_dn))
-               return -EINVAL;
-
-       if (sk->zapped == 0)
-               return -EINVAL;
-
-       switch(sk->protocol) {
-               case DNPROTO_ROU:
-                       if (dn_ntohs(addr->sdn_objnamel) && (dn_ntohs(addr->sdn_objnamel) != 2))
-                               return -EINVAL;
-                       /* Fall through here */
-               case DNPROTO_NSP:
-                       if (dn_ntohs(addr->sdn_add.a_len) && (dn_ntohs(addr->sdn_add.a_len) != 2))
-                               return -EINVAL;
-                       break;
-               default:
-                       return -EPROTONOSUPPORT;
-       }
-
-       if (dn_ntohs(addr->sdn_objnamel) > (DN_MAXOBJL-1))
-               return -EINVAL;
-
-       if (dn_ntohs(addr->sdn_add.a_len) > DN_MAXADDL)
-               return -EINVAL;
-
-       memcpy(&sk->protinfo.dn.addr, addr, sizeof(struct sockaddr_dn));
-
-       dn_raw_autobind(sk);
-
-       return 0;
-}
-
-/*
- * This is to allow send() and write() to work. You set the destination address
- * with this function.
- */
-static int dn_raw_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
-{
-       struct sock *sk = sock->sk;
-       struct dn_scp *scp = &sk->protinfo.dn;
-       struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
-       int err;
-
-       lock_sock(sk);
-
-       err = -EINVAL;
-       if (addr_len != sizeof(struct sockaddr_dn))
-               goto out;
-
-       if (saddr->sdn_family != AF_DECnet)
-               goto out;
-
-       if (dn_ntohs(saddr->sdn_objnamel) > (DN_MAXOBJL-1))
-               goto out;
-
-       if (dn_ntohs(saddr->sdn_add.a_len) > DN_MAXADDL)
-               goto out;
-
-       if (sk->zapped)
-               dn_raw_autobind(sk);
-
-       if ((err = dn_route_output(&sk->dst_cache, dn_saddr2dn(saddr), dn_saddr2dn(&scp->addr), 0)) < 0)
-               goto out;
-
-       memcpy(&scp->peer, saddr, sizeof(struct sockaddr_dn));
-out:
-       release_sock(sk);
-
-       return err;
-}
-
-/*
- * TBD.
- */
-static int dn_raw_sendmsg(struct socket *sock, struct msghdr *hdr, int size,
-                       struct scm_cookie *scm)
-{
-       struct sock *sk = sock->sk;
-
-       if (sk->zapped)
-               dn_raw_autobind(sk);
-
-       if (sk->protocol != DNPROTO_NSP)
-               return -EOPNOTSUPP;
-
-       return 0;
-}
-
-/*
- * This works fine, execpt that it doesn't report the originating address
- * or anything at the moment.
- */
-static int dn_raw_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-                       int flags, struct scm_cookie *scm)
-{
-       struct sock *sk = sock->sk;
-       struct sk_buff *skb;
-       int err = 0;
-       int copied = 0;
-
-       lock_sock(sk);
-
-       if (sk->zapped)
-               dn_raw_autobind(sk);
-
-       if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err)) == NULL)
-               goto out;
-
-       copied = skb->len;
-
-       if (copied > size) {
-               copied = size;
-               msg->msg_flags |= MSG_TRUNC;
-       }
-
-       if ((err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied)) != 0) {
-               if (flags & MSG_PEEK)
-                       atomic_dec(&skb->users);
-               else
-                       skb_queue_head(&sk->receive_queue, skb);
-
-               goto out;
-       }
-
-       skb_free_datagram(sk, skb);
-
-out:
-       release_sock(sk);
-
-       return copied ? copied : err;
-}
-
-struct proto_ops dn_raw_proto_ops = {
-       AF_DECnet,
-
-       dn_raw_release,
-       dn_raw_bind,
-       dn_raw_connect,
-       sock_no_socketpair,
-       sock_no_accept,
-       sock_no_getname,
-       datagram_poll,
-       sock_no_ioctl,
-       sock_no_listen,
-       sock_no_shutdown,
-       sock_no_setsockopt,
-       sock_no_getsockopt,
-       sock_no_fcntl,
-       dn_raw_sendmsg,
-       dn_raw_recvmsg,
-       sock_no_mmap
-};
-
-#ifdef CONFIG_PROC_FS
-int dn_raw_get_info(char *buffer, char **start, off_t offset, int length)
-{
-       int len = 0;
-       off_t pos = 0;
-       off_t begin = 0;
-       struct sock *sk;
-
-       read_lock_bh(&dn_raw_hash_lock);
-       for(sk = dn_raw_nsp_sklist; sk; sk = sk->next) {        
-               len += sprintf(buffer+len, "NSP\n");
-
-               pos = begin + len;
-
-               if (pos < offset) {
-                       len = 0;
-                       begin = pos;
-               }
-
-               if (pos > offset + length)
-                       goto all_done;
-
-       }
-
-       for(sk = dn_raw_routing_sklist; sk; sk = sk->next) {
-               len += sprintf(buffer+len, "ROU\n");
-
-               pos = begin + len;
-
-               if (pos < offset) {
-                       len = 0;
-                       begin = pos;
-               }
-
-               if (pos > offset + length)
-                       goto all_done;
-       }
-
-all_done:
-       read_unlock_bh(&dn_raw_hash_lock);
-
-       *start = buffer + (offset - begin);
-       len -= (offset - begin);
-
-       if (len > length) len = length;
-
-       return(len);
-}
-#endif /* CONFIG_PROC_FS */
-
-void dn_raw_rx_nsp(struct sk_buff *skb)
-{
-       struct sock *sk;
-       struct sk_buff *skb2;
-
-       read_lock(&dn_raw_hash_lock);
-       for(sk = dn_raw_nsp_sklist; sk != NULL; sk = sk->next) {
-               if (skb->len > sock_rspace(sk))
-                       continue;
-               if (sk->dead)
-                       continue;
-               if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
-                       skb_set_owner_r(skb2, sk);
-                       skb_queue_tail(&sk->receive_queue, skb2);
-                       sk->data_ready(sk, skb->len);   
-               }
-       }
-       read_unlock(&dn_raw_hash_lock);
-}
-
-void dn_raw_rx_routing(struct sk_buff *skb)
-{
-       struct sock *sk;
-       struct sk_buff *skb2;
-       struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
-       unsigned short rt_flagmask;
-       unsigned short objnamel;
-       struct dn_scp *scp;
-
-       read_lock(&dn_raw_hash_lock);
-       for(sk = dn_raw_routing_sklist; sk != NULL; sk = sk->next) {
-               if (skb->len > sock_rspace(sk))
-                       continue;
-               if (sk->dead)
-                       continue;
-               scp = &sk->protinfo.dn;
-
-               rt_flagmask = dn_ntohs(*(unsigned short *)scp->addr.sdn_objname);
-               objnamel = dn_ntohs(scp->addr.sdn_objnamel);
-
-               if ((objnamel == 2) && (!((1 << (cb->rt_flags & 0x0f)) & rt_flagmask)))
-                       continue;
-
-               if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
-                       skb_set_owner_r(skb2, sk);
-                       skb_queue_tail(&sk->receive_queue, skb2);
-                       sk->data_ready(sk, skb->len);
-               }
-       }
-       read_unlock(&dn_raw_hash_lock);
-}
-
index 27ff3a10ffc220451a1ab94e17c8c290c8992904..5e54a6fa852bc4ea5ffd4709469c064786800c71 100644 (file)
@@ -77,7 +77,6 @@
 #include <net/dn_route.h>
 #include <net/dn_neigh.h>
 #include <net/dn_fib.h>
-#include <net/dn_raw.h>
 
 struct dn_rt_hash_bucket
 {
@@ -427,10 +426,6 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
                        (int)flags, (dev) ? dev->name : "???", len, skb->len, 
                        padlen);
 
-#ifdef CONFIG_DECNET_RAW
-       dn_raw_rx_routing(skb);
-#endif /* CONFIG_DECNET_RAW */
-
         if (flags & DN_RT_PKT_CNTL) {
                 switch(flags & DN_RT_CNTL_MSK) {
                        case DN_RT_PKT_INIT:
index f80e5afc1fa04f0d983e332b3e07903685dada34..ff65e9ae6e69f7f9aed2d680d427c371fb7ccb14 100644 (file)
@@ -29,9 +29,9 @@
 
 int decnet_debug_level = 0;
 int decnet_time_wait = 30;
-int decnet_dn_count = 3;
-int decnet_di_count = 5;
-int decnet_dr_count = 5;
+int decnet_dn_count = 1;
+int decnet_di_count = 3;
+int decnet_dr_count = 3;
 
 #ifdef CONFIG_SYSCTL
 extern int decnet_dst_gc_interval;
index 3675848735aa8a79e7b3a7365717b3fbfd0fb191..8da31b692bd9efd1c719a8f9f1402b4d17a063d9 100644 (file)
@@ -7,17 +7,10 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
+O_TARGET := econet.o
 MOD_LIST_NAME := NET_MISC_MODULES
 
-O_OBJS :=
-M_OBJS :=
-
-ifeq ($(CONFIG_ECONET),y)
-  O_OBJS += econet.o
-else
-  ifeq ($(CONFIG_ECONET), m)
-    M_OBJS += econet.o
-  endif
-endif
+O_OBJS := af_econet.o sysctl_net_ec.o
+M_OBJS := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
new file mode 100644 (file)
index 0000000..a24bb50
--- /dev/null
@@ -0,0 +1,1154 @@
+/*
+ *     An implementation of the Acorn Econet and AUN protocols.
+ *     Philip Blundell <philb@gnu.org>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/route.h>
+#include <linux/inet.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/inet_common.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/if_ec.h>
+#include <net/udp.h>
+#include <net/ip.h>
+#include <linux/inetdevice.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+static struct proto_ops econet_ops;
+static struct sock *econet_sklist;
+
+/* Since there are only 256 possible network numbers (or fewer, depends
+   how you count) it makes sense to use a simple lookup table. */
+static struct net_device *net2dev_map[256];
+
+#ifdef CONFIG_ECONET_AUNUDP
+static spinlock_t aun_queue_lock;
+static struct socket *udpsock;
+#define AUN_PORT       0x8000
+
+#define EC_PORT_IP     0xd2
+
+struct aunhdr
+{
+       unsigned char code;             /* AUN magic protocol byte */
+       unsigned char port;
+       unsigned char cb;
+       unsigned char pad;
+       unsigned long handle;
+};
+
+static unsigned long aun_seq = 0;
+
+/* Queue of packets waiting to be transmitted. */
+static struct sk_buff_head aun_queue;
+static struct timer_list ab_cleanup_timer;
+
+#endif         /* CONFIG_ECONET_AUNUDP */
+
+/* Per-packet information */
+struct ec_cb
+{
+       struct sockaddr_ec sec;
+       unsigned long cookie;           /* Supplied by user. */
+#ifdef CONFIG_ECONET_AUNUDP
+       int done;
+       unsigned long seq;              /* Sequencing */
+       unsigned long timeout;          /* Timeout */
+       unsigned long start;            /* jiffies */
+#endif
+#ifdef CONFIG_ECONET_NATIVE
+       void (*sent)(struct sk_buff *, int result);
+#endif
+};
+
+/*
+ *     Pull a packet from our receive queue and hand it to the user.
+ *     If necessary we block.
+ */
+
+static int econet_recvmsg(struct socket *sock, struct msghdr *msg, int len,
+                         int flags, struct scm_cookie *scm)
+{
+       struct sock *sk = sock->sk;
+       struct sk_buff *skb;
+       int copied, err;
+
+       msg->msg_namelen = sizeof(struct sockaddr_ec);
+
+       /*
+        *      Call the generic datagram receiver. This handles all sorts
+        *      of horrible races and re-entrancy so we can forget about it
+        *      in the protocol layers.
+        *
+        *      Now it will return ENETDOWN, if device have just gone down,
+        *      but then it will block.
+        */
+
+       skb=skb_recv_datagram(sk,flags,flags&MSG_DONTWAIT,&err);
+
+       /*
+        *      An error occurred so return it. Because skb_recv_datagram() 
+        *      handles the blocking we don't see and worry about blocking
+        *      retries.
+        */
+
+       if(skb==NULL)
+               goto out;
+
+       /*
+        *      You lose any data beyond the buffer you gave. If it worries a
+        *      user program they can ask the device for its MTU anyway.
+        */
+
+       copied = skb->len;
+       if (copied > len)
+       {
+               copied=len;
+               msg->msg_flags|=MSG_TRUNC;
+       }
+
+       /* We can't use skb_copy_datagram here */
+       err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+       if (err)
+               goto out_free;
+       sk->stamp=skb->stamp;
+
+       if (msg->msg_name)
+               memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
+
+       /*
+        *      Free or return the buffer as appropriate. Again this
+        *      hides all the races and re-entrancy issues from us.
+        */
+       err = copied;
+
+out_free:
+       skb_free_datagram(sk, skb);
+out:
+       return err;
+}
+
+/*
+ *     Bind an Econet socket.
+ */
+
+static int econet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+       struct sockaddr_ec *sec = (struct sockaddr_ec *)uaddr;
+       struct sock *sk=sock->sk;
+       
+       /*
+        *      Check legality
+        */
+        
+       if (addr_len < sizeof(struct sockaddr_ec))
+               return -EINVAL;
+       if (sec->sec_family != AF_ECONET)
+               return -EINVAL;
+       
+       sk->protinfo.af_econet->cb = sec->cb;
+       sk->protinfo.af_econet->port = sec->port;
+       sk->protinfo.af_econet->station = sec->addr.station;
+       sk->protinfo.af_econet->net = sec->addr.net;
+
+       return 0;
+}
+
+/*
+ *     Queue a transmit result for the user to be told about.
+ */
+
+static void tx_result(struct sock *sk, unsigned long cookie, int result)
+{
+       struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
+       struct ec_cb *eb;
+       struct sockaddr_ec *sec;
+
+       if (skb == NULL)
+       {
+               printk(KERN_DEBUG "ec: memory squeeze, transmit result dropped.\n");
+               return;
+       }
+
+       eb = (struct ec_cb *)&skb->cb;
+       sec = (struct sockaddr_ec *)&eb->sec;
+       memset(sec, 0, sizeof(struct sockaddr_ec));
+       sec->cookie = cookie;
+       sec->type = ECTYPE_TRANSMIT_STATUS | result;
+       sec->sec_family = AF_ECONET;
+
+       if (sock_queue_rcv_skb(sk, skb) < 0)
+               kfree_skb(skb);
+}
+
+#ifdef CONFIG_ECONET_NATIVE
+/*
+ *     Called by the Econet hardware driver when a packet transmit
+ *     has completed.  Tell the user.
+ */
+
+static void ec_tx_done(struct sk_buff *skb, int result)
+{
+       struct ec_cb *eb = (struct ec_cb *)&skb->cb;
+       tx_result(skb->sk, eb->cookie, result);
+}
+#endif
+
+/*
+ *     Send a packet.  We have to work out which device it's going out on
+ *     and hence whether to use real Econet or the UDP emulation.
+ */
+
+static int econet_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+                         struct scm_cookie *scm)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_ec *saddr=(struct sockaddr_ec *)msg->msg_name;
+       struct net_device *dev;
+       struct ec_addr addr;
+       int err;
+       unsigned char port, cb;
+       struct sk_buff *skb;
+       struct ec_cb *eb;
+#ifdef CONFIG_ECONET_NATIVE
+       unsigned short proto = 0;
+#endif
+#ifdef CONFIG_ECONET_AUNUDP
+       struct msghdr udpmsg;
+       struct iovec iov[msg->msg_iovlen+1];
+       struct aunhdr ah;
+       struct sockaddr_in udpdest;
+       __kernel_size_t size;
+       int i;
+       mm_segment_t oldfs;
+#endif
+               
+       /*
+        *      Check the flags. 
+        */
+
+       if (msg->msg_flags&~MSG_DONTWAIT) 
+               return(-EINVAL);
+
+       /*
+        *      Get and verify the address. 
+        */
+        
+       if (saddr == NULL) {
+               addr.station = sk->protinfo.af_econet->station;
+               addr.net = sk->protinfo.af_econet->net;
+               port = sk->protinfo.af_econet->port;
+               cb = sk->protinfo.af_econet->cb;
+       } else {
+               if (msg->msg_namelen < sizeof(struct sockaddr_ec)) 
+                       return -EINVAL;
+               addr.station = saddr->addr.station;
+               addr.net = saddr->addr.net;
+               port = saddr->port;
+               cb = saddr->cb;
+       }
+
+       /* Look for a device with the right network number. */
+       dev = net2dev_map[addr.net];
+
+       /* If not directly reachable, use some default */
+       if (dev == NULL)
+       {
+               dev = net2dev_map[0];
+               /* No interfaces at all? */
+               if (dev == NULL)
+                       return -ENETDOWN;
+       }
+
+       if (dev->type == ARPHRD_ECONET)
+       {
+               /* Real hardware Econet.  We're not worthy etc. */
+#ifdef CONFIG_ECONET_NATIVE
+               atomic_inc(&dev->refcnt);
+               
+               skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, 
+                                         msg->msg_flags & MSG_DONTWAIT, &err);
+               if (skb==NULL)
+                       goto out_unlock;
+               
+               skb_reserve(skb, (dev->hard_header_len+15)&~15);
+               skb->nh.raw = skb->data;
+               
+               eb = (struct ec_cb *)&skb->cb;
+               
+               eb->cookie = saddr->cookie;
+               eb->sec = *saddr;
+               eb->sent = ec_tx_done;
+
+               if (dev->hard_header) {
+                       int res;
+                       struct ec_framehdr *fh;
+                       err = -EINVAL;
+                       res = dev->hard_header(skb, dev, ntohs(proto), 
+                                              &addr, NULL, len);
+                       /* Poke in our control byte and
+                          port number.  Hack, hack.  */
+                       fh = (struct ec_framehdr *)(skb->data);
+                       fh->cb = cb;
+                       fh->port = port;
+                       if (sock->type != SOCK_DGRAM) {
+                               skb->tail = skb->data;
+                               skb->len = 0;
+                       } else if (res < 0)
+                               goto out_free;
+               }
+               
+               /* Copy the data. Returns -EFAULT on error */
+               err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+               skb->protocol = proto;
+               skb->dev = dev;
+               skb->priority = sk->priority;
+               if (err)
+                       goto out_free;
+               
+               err = -ENETDOWN;
+               if (!(dev->flags & IFF_UP))
+                       goto out_free;
+               
+               /*
+                *      Now send it
+                */
+               
+               dev_queue_xmit(skb);
+               dev_put(dev);
+               return(len);
+
+       out_free:
+               kfree_skb(skb);
+       out_unlock:
+               if (dev)
+                       dev_put(dev);
+#else
+               err = -EPROTOTYPE;
+#endif
+               return err;
+       }
+
+#ifdef CONFIG_ECONET_AUNUDP
+       /* AUN virtual Econet. */
+
+       if (udpsock == NULL)
+               return -ENETDOWN;               /* No socket - can't send */
+       
+       /* Make up a UDP datagram and hand it off to some higher intellect. */
+
+       memset(&udpdest, 0, sizeof(udpdest));
+       udpdest.sin_family = AF_INET;
+       udpdest.sin_port = htons(AUN_PORT);
+
+       /* At the moment we use the stupid Acorn scheme of Econet address
+          y.x maps to IP a.b.c.x.  This should be replaced with something
+          more flexible and more aware of subnet masks.  */
+       {
+               struct in_device *idev = in_dev_get(dev);
+               unsigned long network = 0;
+               if (idev) {
+                       read_lock(&idev->lock);
+                       if (idev->ifa_list)
+                               network = ntohl(idev->ifa_list->ifa_address) & 
+                                       0xffffff00;             /* !!! */
+                       read_unlock(&idev->lock);
+                       in_dev_put(idev);
+               }
+               udpdest.sin_addr.s_addr = htonl(network | addr.station);
+       }
+
+       ah.port = port;
+       ah.cb = cb & 0x7f;
+       ah.code = 2;            /* magic */
+       ah.pad = 0;
+
+       /* tack our header on the front of the iovec */
+       size = sizeof(struct aunhdr);
+       iov[0].iov_base = (void *)&ah;
+       iov[0].iov_len = size;
+       for (i = 0; i < msg->msg_iovlen; i++) {
+               void *base = msg->msg_iov[i].iov_base;
+               size_t len = msg->msg_iov[i].iov_len;
+               /* Check it now since we switch to KERNEL_DS later. */
+               if ((err = verify_area(VERIFY_READ, base, len)) < 0)
+                       return err;
+               iov[i+1].iov_base = base;
+               iov[i+1].iov_len = len;
+               size += len;
+       }
+
+       /* Get a skbuff (no data, just holds our cb information) */
+       if ((skb = sock_alloc_send_skb(sk, 0, 0, 
+                            msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
+               return err;
+
+       eb = (struct ec_cb *)&skb->cb;
+
+       eb->cookie = saddr->cookie;
+       eb->timeout = (5*HZ);
+       eb->start = jiffies;
+       ah.handle = aun_seq;
+       eb->seq = (aun_seq++);
+       eb->sec = *saddr;
+
+       skb_queue_tail(&aun_queue, skb);
+
+       udpmsg.msg_name = (void *)&udpdest;
+       udpmsg.msg_namelen = sizeof(udpdest);
+       udpmsg.msg_iov = &iov[0];
+       udpmsg.msg_iovlen = msg->msg_iovlen + 1;
+       udpmsg.msg_control = NULL;
+       udpmsg.msg_controllen = 0;
+       udpmsg.msg_flags=0;
+
+       oldfs = get_fs(); set_fs(KERNEL_DS);    /* More privs :-) */
+       err = sock_sendmsg(udpsock, &udpmsg, size);
+       set_fs(oldfs);
+#else
+       err = -EPROTOTYPE;
+#endif
+       return err;
+}
+
+/*
+ *     Look up the address of a socket.
+ */
+
+static int econet_getname(struct socket *sock, struct sockaddr *uaddr,
+                         int *uaddr_len, int peer)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_ec *sec = (struct sockaddr_ec *)uaddr;
+
+       if (peer)
+               return -EOPNOTSUPP;
+
+       sec->sec_family = AF_ECONET;
+       sec->port = sk->protinfo.af_econet->port;
+       sec->addr.station = sk->protinfo.af_econet->station;
+       sec->addr.net = sk->protinfo.af_econet->net;
+
+       *uaddr_len = sizeof(*sec);
+       return 0;
+}
+
+static void econet_destroy_timer(unsigned long data)
+{
+       struct sock *sk=(struct sock *)data;
+
+       if (!atomic_read(&sk->wmem_alloc) && !atomic_read(&sk->rmem_alloc)) {
+               sk_free(sk);
+               MOD_DEC_USE_COUNT;
+               return;
+       }
+
+       sk->timer.expires=jiffies+10*HZ;
+       add_timer(&sk->timer);
+       printk(KERN_DEBUG "econet socket destroy delayed\n");
+}
+
+/*
+ *     Close an econet socket.
+ */
+
+static int econet_release(struct socket *sock)
+{
+       struct sk_buff  *skb;
+       struct sock *sk = sock->sk;
+
+       if (!sk)
+               return 0;
+
+       sklist_remove_socket(&econet_sklist, sk);
+
+       /*
+        *      Now the socket is dead. No more input will appear.
+        */
+
+       sk->state_change(sk);   /* It is useless. Just for sanity. */
+
+       sock->sk = NULL;
+       sk->socket = NULL;
+       sk->dead = 1;
+
+       /* Purge queues */
+
+       while ((skb=skb_dequeue(&sk->receive_queue))!=NULL)
+               kfree_skb(skb);
+
+       if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) {
+               sk->timer.data=(unsigned long)sk;
+               sk->timer.expires=jiffies+HZ;
+               sk->timer.function=econet_destroy_timer;
+               add_timer(&sk->timer);
+               return 0;
+       }
+
+       sk_free(sk);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+/*
+ *     Create an Econet socket
+ */
+
+static int econet_create(struct socket *sock, int protocol)
+{
+       struct sock *sk;
+       int err;
+
+       /* Econet only provides datagram services. */
+       if (sock->type != SOCK_DGRAM)
+               return -ESOCKTNOSUPPORT;
+
+       sock->state = SS_UNCONNECTED;
+       MOD_INC_USE_COUNT;
+
+       err = -ENOBUFS;
+       sk = sk_alloc(PF_ECONET, GFP_KERNEL, 1);
+       if (sk == NULL)
+               goto out;
+
+       sk->reuse = 1;
+       sock->ops = &econet_ops;
+       sock_init_data(sock,sk);
+
+       sk->protinfo.af_econet = kmalloc(sizeof(struct econet_opt), GFP_KERNEL);
+       if (sk->protinfo.af_econet == NULL)
+               goto out_free;
+       memset(sk->protinfo.af_econet, 0, sizeof(struct econet_opt));
+       sk->zapped=0;
+       sk->family = PF_ECONET;
+       sk->num = protocol;
+
+       sklist_insert_socket(&econet_sklist, sk);
+       return(0);
+
+out_free:
+       sk_free(sk);
+out:
+       MOD_DEC_USE_COUNT;
+       return err;
+}
+
+/*
+ *     Handle Econet specific ioctls
+ */
+
+static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void *arg)
+{
+       struct ifreq ifr;
+       struct ec_device *edev;
+       struct net_device *dev;
+       struct sockaddr_ec *sec;
+
+       /*
+        *      Fetch the caller's info block into kernel space
+        */
+
+       if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
+               return -EFAULT;
+
+       if ((dev = dev_get_by_name(ifr.ifr_name)) == NULL) 
+               return -ENODEV;
+
+       sec = (struct sockaddr_ec *)&ifr.ifr_addr;
+
+       switch (cmd)
+       {
+       case SIOCSIFADDR:
+               edev = dev->ec_ptr;
+               if (edev == NULL)
+               {
+                       /* Magic up a new one. */
+                       edev = kmalloc(GFP_KERNEL, sizeof(struct ec_device));
+                       if (edev == NULL) {
+                               printk("af_ec: memory squeeze.\n");
+                               dev_put(dev);
+                               return -ENOMEM;
+                       }
+                       memset(edev, 0, sizeof(struct ec_device));
+                       dev->ec_ptr = edev;
+               }
+               else
+                       net2dev_map[edev->net] = NULL;
+               edev->station = sec->addr.station;
+               edev->net = sec->addr.net;
+               net2dev_map[sec->addr.net] = dev;
+               if (!net2dev_map[0])
+                       net2dev_map[0] = dev;
+               dev_put(dev);
+               return 0;
+
+       case SIOCGIFADDR:
+               edev = dev->ec_ptr;
+               if (edev == NULL)
+               {
+                       dev_put(dev);
+                       return -ENODEV;
+               }
+               memset(sec, 0, sizeof(struct sockaddr_ec));
+               sec->addr.station = edev->station;
+               sec->addr.net = edev->net;
+               sec->sec_family = AF_ECONET;
+               dev_put(dev);
+               if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       dev_put(dev);
+       return -EINVAL;
+}
+
+/*
+ *     Handle generic ioctls
+ */
+
+static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       struct sock *sk = sock->sk;
+       int err;
+       int pid;
+
+       switch(cmd) 
+       {
+               case FIOSETOWN:
+               case SIOCSPGRP:
+                       err = get_user(pid, (int *) arg);
+                       if (err)
+                               return err; 
+                       if (current->pid != pid && current->pgrp != -pid && !suser())
+                               return -EPERM;
+                       sk->proc = pid;
+                       return(0);
+               case FIOGETOWN:
+               case SIOCGPGRP:
+                       return put_user(sk->proc, (int *)arg);
+               case SIOCGSTAMP:
+                       if(sk->stamp.tv_sec==0)
+                               return -ENOENT;
+                       err = -EFAULT;
+                       if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+                               err = 0;
+                       return err;
+               case SIOCGIFFLAGS:
+               case SIOCSIFFLAGS:
+               case SIOCGIFCONF:
+               case SIOCGIFMETRIC:
+               case SIOCSIFMETRIC:
+               case SIOCGIFMEM:
+               case SIOCSIFMEM:
+               case SIOCGIFMTU:
+               case SIOCSIFMTU:
+               case SIOCSIFLINK:
+               case SIOCGIFHWADDR:
+               case SIOCSIFHWADDR:
+               case SIOCSIFMAP:
+               case SIOCGIFMAP:
+               case SIOCSIFSLAVE:
+               case SIOCGIFSLAVE:
+               case SIOCGIFINDEX:
+               case SIOCGIFNAME:
+               case SIOCGIFCOUNT:
+               case SIOCSIFHWBROADCAST:
+                       return(dev_ioctl(cmd,(void *) arg));
+
+               case SIOCSIFADDR:
+               case SIOCGIFADDR:
+                       return ec_dev_ioctl(sock, cmd, (void *)arg);
+                       break;
+
+               default:
+                       return(dev_ioctl(cmd,(void *) arg));
+       }
+       /*NOTREACHED*/
+       return 0;
+}
+
+static struct net_proto_family econet_family_ops = {
+       PF_ECONET,
+       econet_create
+};
+
+static struct proto_ops SOCKOPS_WRAPPED(econet_ops) = {
+       PF_ECONET,
+
+       econet_release,
+       econet_bind,
+       sock_no_connect,
+       sock_no_socketpair,
+       sock_no_accept,
+       econet_getname, 
+       datagram_poll,
+       econet_ioctl,
+       sock_no_listen,
+       sock_no_shutdown,
+       sock_no_setsockopt,
+       sock_no_getsockopt,
+       sock_no_fcntl,
+       econet_sendmsg,
+       econet_recvmsg,
+       sock_no_mmap
+};
+
+#include <linux/smp_lock.h>
+SOCKOPS_WRAP(econet, PF_ECONET);
+
+/*
+ *     Find the listening socket, if any, for the given data.
+ */
+
+struct sock *ec_listening_socket(unsigned char port, unsigned char
+                                station, unsigned char net)
+{
+       struct sock *sk = econet_sklist;
+
+       while (sk)
+       {
+               struct econet_opt *opt = sk->protinfo.af_econet;
+               if ((opt->port == port || opt->port == 0) && 
+                   (opt->station == station || opt->station == 0) &&
+                   (opt->net == net || opt->net == 0))
+                       return sk;
+
+               sk = sk->next;
+       }
+
+       return NULL;
+}
+
+#ifdef CONFIG_ECONET_AUNUDP
+
+/*
+ *     Send an AUN protocol response. 
+ */
+
+static void aun_send_response(__u32 addr, unsigned long seq, int code, int cb)
+{
+       struct sockaddr_in sin;
+       struct iovec iov;
+       struct aunhdr ah;
+       struct msghdr udpmsg;
+       int err;
+       mm_segment_t oldfs;
+       
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_port = htons(AUN_PORT);
+       sin.sin_addr.s_addr = addr;
+
+       ah.code = code;
+       ah.pad = 0;
+       ah.port = 0;
+       ah.cb = cb;
+       ah.handle = seq;
+
+       iov.iov_base = (void *)&ah;
+       iov.iov_len = sizeof(ah);
+
+       udpmsg.msg_name = (void *)&sin;
+       udpmsg.msg_namelen = sizeof(sin);
+       udpmsg.msg_iov = &iov;
+       udpmsg.msg_iovlen = 1;
+       udpmsg.msg_control = NULL;
+       udpmsg.msg_controllen = 0;
+       udpmsg.msg_flags=0;
+
+       oldfs = get_fs(); set_fs(KERNEL_DS);
+       err = sock_sendmsg(udpsock, &udpmsg, sizeof(ah));
+       set_fs(oldfs);
+}
+
+/*
+ *     Queue a received packet for a socket.
+ */
+
+static int ec_queue_packet(struct sock *sk, struct sk_buff *skb,
+                          unsigned char stn, unsigned char net,
+                          unsigned char cb, unsigned char port)
+{
+       struct ec_cb *eb = (struct ec_cb *)&skb->cb;
+       struct sockaddr_ec *sec = (struct sockaddr_ec *)&eb->sec;
+
+       memset(sec, 0, sizeof(struct sockaddr_ec));
+       sec->sec_family = AF_ECONET;
+       sec->type = ECTYPE_PACKET_RECEIVED;
+       sec->port = port;
+       sec->cb = cb;
+       sec->addr.net = net;
+       sec->addr.station = stn;
+
+       return sock_queue_rcv_skb(sk, skb);
+}
+
+/*
+ *     Handle incoming AUN packets.  Work out if anybody wants them,
+ *     and send positive or negative acknowledgements as appropriate.
+ */
+
+static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len)
+{
+       struct iphdr *ip = skb->nh.iph;
+       unsigned char stn = ntohl(ip->saddr) & 0xff;
+       struct sock *sk;
+       struct sk_buff *newskb;
+       struct ec_device *edev = skb->dev->ec_ptr;
+
+       if (! edev)
+               goto bad;
+
+       if ((sk = ec_listening_socket(ah->port, stn, edev->net)) == NULL)
+               goto bad;               /* Nobody wants it */
+
+       newskb = alloc_skb((len - sizeof(struct aunhdr) + 15) & ~15, 
+                          GFP_ATOMIC);
+       if (newskb == NULL)
+       {
+               printk(KERN_DEBUG "AUN: memory squeeze, dropping packet.\n");
+               /* Send nack and hope sender tries again */
+               goto bad;
+       }
+
+       memcpy(skb_put(newskb, len - sizeof(struct aunhdr)), (void *)(ah+1), 
+              len - sizeof(struct aunhdr));
+
+       if (ec_queue_packet(sk, newskb, stn, edev->net, ah->cb, ah->port))
+       {
+               /* Socket is bankrupt. */
+               kfree_skb(newskb);
+               goto bad;
+       }
+
+       aun_send_response(ip->saddr, ah->handle, 3, 0);
+       return;
+
+bad:
+       aun_send_response(ip->saddr, ah->handle, 4, 0);
+}
+
+/*
+ *     Handle incoming AUN transmit acknowledgements.  If the sequence
+ *      number matches something in our backlog then kill it and tell
+ *     the user.  If the remote took too long to reply then we may have
+ *     dropped the packet already.
+ */
+
+static void aun_tx_ack(unsigned long seq, int result)
+{
+       struct sk_buff *skb;
+       unsigned long flags;
+       struct ec_cb *eb;
+
+       spin_lock_irqsave(&aun_queue_lock, flags);
+       skb = skb_peek(&aun_queue);
+       while (skb && skb != (struct sk_buff *)&aun_queue)
+       {
+               struct sk_buff *newskb = skb->next;
+               eb = (struct ec_cb *)&skb->cb;
+               if (eb->seq == seq)
+                       goto foundit;
+
+               skb = newskb;
+       }
+       spin_unlock_irqrestore(&aun_queue_lock, flags);
+       printk(KERN_DEBUG "AUN: unknown sequence %ld\n", seq);
+       return;
+
+foundit:
+       tx_result(skb->sk, eb->cookie, result);
+       skb_unlink(skb);
+       spin_unlock_irqrestore(&aun_queue_lock, flags);
+       kfree_skb(skb);
+}
+
+/*
+ *     Deal with received AUN frames - sort out what type of thing it is
+ *     and hand it to the right function.
+ */
+
+static void aun_data_available(struct sock *sk, int slen)
+{
+       int err;
+       struct sk_buff *skb;
+       unsigned char *data;
+       struct aunhdr *ah;
+       struct iphdr *ip;
+       size_t len;
+
+       while ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) {
+               if (err == -EAGAIN) {
+                       printk(KERN_ERR "AUN: no data available?!");
+                       return;
+               }
+               printk(KERN_DEBUG "AUN: recvfrom() error %d\n", -err);
+       }
+
+       data = skb->h.raw + sizeof(struct udphdr);
+       ah = (struct aunhdr *)data;
+       len = skb->len - sizeof(struct udphdr);
+       ip = skb->nh.iph;
+
+       switch (ah->code)
+       {
+       case 2:
+               aun_incoming(skb, ah, len);
+               break;
+       case 3:
+               aun_tx_ack(ah->handle, ECTYPE_TRANSMIT_OK);
+               break;
+       case 4:
+               aun_tx_ack(ah->handle, ECTYPE_TRANSMIT_NOT_LISTENING);
+               break;
+#if 0
+               /* This isn't quite right yet. */
+       case 5:
+               aun_send_response(ip->saddr, ah->handle, 6, ah->cb);
+               break;
+#endif
+       default:
+               printk(KERN_DEBUG "unknown AUN packet (type %d)\n", data[0]);
+       }
+
+       skb_free_datagram(sk, skb);
+}
+
+/*
+ *     Called by the timer to manage the AUN transmit queue.  If a packet
+ *     was sent to a dead or nonexistent host then we will never get an
+ *     acknowledgement back.  After a few seconds we need to spot this and
+ *     drop the packet.
+ */
+
+static void ab_cleanup(unsigned long h)
+{
+       struct sk_buff *skb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&aun_queue_lock, flags);
+       skb = skb_peek(&aun_queue);
+       while (skb && skb != (struct sk_buff *)&aun_queue)
+       {
+               struct sk_buff *newskb = skb->next;
+               struct ec_cb *eb = (struct ec_cb *)&skb->cb;
+               if ((jiffies - eb->start) > eb->timeout)
+               {
+                       tx_result(skb->sk, eb->cookie, 
+                                 ECTYPE_TRANSMIT_NOT_PRESENT);
+                       skb_unlink(skb);
+                       kfree_skb(skb);
+               }
+               skb = newskb;
+       }
+       spin_unlock_irqrestore(&aun_queue_lock, flags);
+
+       mod_timer(&ab_cleanup_timer, jiffies + (HZ*2));
+}
+
+static int __init aun_udp_initialise(void)
+{
+       int error;
+       struct sockaddr_in sin;
+
+       skb_queue_head_init(&aun_queue);
+       spin_lock_init(&aun_queue_lock);
+       init_timer(&ab_cleanup_timer);
+       ab_cleanup_timer.expires = jiffies + (HZ*2);
+       ab_cleanup_timer.function = ab_cleanup;
+       add_timer(&ab_cleanup_timer);
+
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_port = htons(AUN_PORT);
+
+       /* We can count ourselves lucky Acorn machines are too dim to
+          speak IPv6. :-) */
+       if ((error = sock_create(PF_INET, SOCK_DGRAM, 0, &udpsock)) < 0)
+       {
+               printk("AUN: socket error %d\n", -error);
+               return error;
+       }
+       
+       udpsock->sk->reuse = 1;
+       udpsock->sk->allocation = GFP_ATOMIC;   /* we're going to call it
+                                                  from interrupts */
+       
+       error = udpsock->ops->bind(udpsock, (struct sockaddr *)&sin,
+                               sizeof(sin));
+       if (error < 0)
+       {
+               printk("AUN: bind error %d\n", -error);
+               goto release;
+       }
+
+       udpsock->sk->data_ready = aun_data_available;
+
+       return 0;
+
+release:
+       sock_release(udpsock);
+       udpsock = NULL;
+       return error;
+}
+#endif
+
+#ifdef CONFIG_ECONET_NATIVE
+
+/*
+ *     Receive an Econet frame from a device.
+ */
+
+static int econet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+       struct ec_framehdr *hdr = (struct ec_framehdr *)skb->data;
+       struct sock *sk;
+       struct ec_device *edev = dev->ec_ptr;
+
+       if (! edev)
+       {
+               kfree_skb(skb);
+               return 0;
+       }
+
+       if (skb->len < sizeof(struct ec_framehdr))
+       {
+               /* Frame is too small to be any use */
+               kfree_skb(skb);
+               return 0;
+       }
+
+       /* First check for encapsulated IP */
+       if (hdr->port == EC_PORT_IP)
+       {
+               skb->protocol = htons(ETH_P_IP);
+               skb_pull(skb, sizeof(struct ec_framehdr));
+               netif_rx(skb);
+               return 0;
+       }
+
+       sk = ec_listening_socket(hdr->port, hdr->src_stn, hdr->src_net);
+       if (!sk) 
+       {
+               kfree_skb(skb);
+               return 0;
+       }
+
+       return ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb, 
+                              hdr->port);
+}
+
+struct packet_type econet_packet_type=
+{
+       0,
+       NULL,
+       econet_rcv,
+       NULL,
+       NULL
+};
+
+static void econet_hw_initialise(void)
+{
+       econet_packet_type.type = htons(ETH_P_ECONET);
+       dev_add_pack(&econet_packet_type);
+}
+
+#endif
+
+static int econet_notifier(struct notifier_block *this, unsigned long msg, void *data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct ec_device *edev;
+
+       switch (msg) {
+       case NETDEV_UNREGISTER:
+               /* A device has gone down - kill any data we hold for it. */
+               edev = dev->ec_ptr;
+               if (edev)
+               {
+                       if (net2dev_map[0] == dev)
+                               net2dev_map[0] = 0;
+                       net2dev_map[edev->net] = NULL;
+                       kfree(edev);
+                       dev->ec_ptr = NULL;
+               }
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+struct notifier_block econet_netdev_notifier={
+       econet_notifier,
+       NULL,
+       0
+};
+
+void __exit econet_proto_exit(void)
+{
+       extern void econet_sysctl_unregister(void);
+#ifdef CONFIG_ECONET_AUNUDP
+       del_timer(&ab_cleanup_timer);
+       if (udpsock)
+               sock_release(udpsock);
+#endif
+       unregister_netdevice_notifier(&econet_netdev_notifier);
+       sock_unregister(econet_family_ops.family);
+#ifdef CONFIG_SYSCTL
+       econet_sysctl_unregister();
+#endif
+}
+
+int __init econet_proto_init(struct net_proto *pro)
+{
+       extern void econet_sysctl_register(void);
+       spin_lock_init(&aun_queue_lock);
+       sock_register(&econet_family_ops);
+#ifdef CONFIG_ECONET_AUNUDP
+       aun_udp_initialise();
+#endif
+#ifdef CONFIG_ECONET_NATIVE
+       econet_hw_initialise();
+#endif
+       register_netdevice_notifier(&econet_netdev_notifier);
+#ifdef CONFIG_SYSCTL
+       econet_sysctl_register();
+#endif
+       return 0;
+}
+
+#ifdef MODULE
+module_init(econet_proto_init);
+module_exit(econet_proto_exit);
+#endif
diff --git a/net/econet/econet.c b/net/econet/econet.c
deleted file mode 100644 (file)
index 6e7523e..0000000
+++ /dev/null
@@ -1,1125 +0,0 @@
-/*
- *     An implementation of the Acorn Econet and AUN protocols.
- *     Philip Blundell <philb@gnu.org>
- *
- *     Fixes:
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/route.h>
-#include <linux/inet.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/inet_common.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/if_ec.h>
-#include <net/udp.h>
-#include <net/ip.h>
-#include <linux/spinlock.h>
-
-static struct proto_ops econet_ops;
-static struct sock *econet_sklist;
-
-static spinlock_t aun_queue_lock;
-
-#ifdef CONFIG_ECONET_AUNUDP
-static struct socket *udpsock;
-#define AUN_PORT       0x8000
-
-struct aunhdr
-{
-       unsigned char code;             /* AUN magic protocol byte */
-       unsigned char port;
-       unsigned char cb;
-       unsigned char pad;
-       unsigned long handle;
-};
-
-static unsigned long aun_seq = 0;
-
-/* Queue of packets waiting to be transmitted. */
-static struct sk_buff_head aun_queue;
-static struct timer_list ab_cleanup_timer;
-
-#endif         /* CONFIG_ECONET_AUNUDP */
-
-/* Per-packet information */
-struct ec_cb
-{
-       struct sockaddr_ec sec;
-       unsigned long cookie;           /* Supplied by user. */
-#ifdef CONFIG_ECONET_AUNUDP
-       int done;
-       unsigned long seq;              /* Sequencing */
-       unsigned long timeout;          /* Timeout */
-       unsigned long start;            /* jiffies */
-#endif
-#ifdef CONFIG_ECONET_NATIVE
-       void (*sent)(struct sk_buff *, int result);
-#endif
-};
-
-struct ec_device
-{
-       struct net_device *dev;         /* Real device structure */
-       unsigned char station, net;     /* Econet protocol address */
-       struct ec_device *prev, *next;  /* Linked list */
-};
-
-static struct ec_device *edevlist = NULL;
-
-static spinlock_t edevlist_lock;
-
-/*
- *     Faster version of edev_get - call with IRQs off
- */
-
-static __inline__ struct ec_device *__edev_get(struct net_device *dev)
-{
-       struct ec_device *edev;
-       for (edev = edevlist; edev; edev = edev->next)
-       {
-               if (edev->dev == dev)
-                       break;
-       }
-       return edev;
-}
-
-/*
- *     Find an Econet device given its `dev' pointer.  This is IRQ safe.
- *
- *     Against what is it safe? --ANK
- */
-
-static struct ec_device *edev_get(struct net_device *dev)
-{
-       struct ec_device *edev;
-       unsigned long flags;
-       spin_lock_irqsave(&edevlist_lock, flags);
-       edev = __edev_get(dev);
-       spin_unlock_irqrestore(&edevlist_lock, flags);
-       return edev;
-}
-
-/*
- *     Pull a packet from our receive queue and hand it to the user.
- *     If necessary we block.
- */
-
-static int econet_recvmsg(struct socket *sock, struct msghdr *msg, int len,
-                         int flags, struct scm_cookie *scm)
-{
-       struct sock *sk = sock->sk;
-       struct sk_buff *skb;
-       int copied, err;
-
-       msg->msg_namelen = sizeof(struct sockaddr_ec);
-
-       /*
-        *      Call the generic datagram receiver. This handles all sorts
-        *      of horrible races and re-entrancy so we can forget about it
-        *      in the protocol layers.
-        *
-        *      Now it will return ENETDOWN, if device have just gone down,
-        *      but then it will block.
-        */
-
-       skb=skb_recv_datagram(sk,flags,flags&MSG_DONTWAIT,&err);
-
-       /*
-        *      An error occurred so return it. Because skb_recv_datagram() 
-        *      handles the blocking we don't see and worry about blocking
-        *      retries.
-        */
-
-       if(skb==NULL)
-               goto out;
-
-       /*
-        *      You lose any data beyond the buffer you gave. If it worries a
-        *      user program they can ask the device for its MTU anyway.
-        */
-
-       copied = skb->len;
-       if (copied > len)
-       {
-               copied=len;
-               msg->msg_flags|=MSG_TRUNC;
-       }
-
-       /* We can't use skb_copy_datagram here */
-       err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
-       if (err)
-               goto out_free;
-       sk->stamp=skb->stamp;
-
-       if (msg->msg_name)
-               memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
-
-       /*
-        *      Free or return the buffer as appropriate. Again this
-        *      hides all the races and re-entrancy issues from us.
-        */
-       err = copied;
-
-out_free:
-       skb_free_datagram(sk, skb);
-out:
-       return err;
-}
-
-/*
- *     Bind an Econet socket.
- */
-
-static int econet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
-{
-       struct sockaddr_ec *sec = (struct sockaddr_ec *)uaddr;
-       struct sock *sk=sock->sk;
-       
-       /*
-        *      Check legality
-        */
-        
-       if (addr_len < sizeof(struct sockaddr_ec))
-               return -EINVAL;
-       if (sec->sec_family != AF_ECONET)
-               return -EINVAL;
-       
-       sk->protinfo.af_econet->cb = sec->cb;
-       sk->protinfo.af_econet->port = sec->port;
-       sk->protinfo.af_econet->station = sec->addr.station;
-       sk->protinfo.af_econet->net = sec->addr.net;
-
-       return 0;
-}
-
-/*
- *     Queue a transmit result for the user to be told about.
- */
-
-static void tx_result(struct sock *sk, unsigned long cookie, int result)
-{
-       struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
-       struct ec_cb *eb;
-       struct sockaddr_ec *sec;
-
-       if (skb == NULL)
-       {
-               printk(KERN_DEBUG "ec: memory squeeze, transmit result dropped.\n");
-               return;
-       }
-
-       eb = (struct ec_cb *)&skb->cb;
-       sec = (struct sockaddr_ec *)&eb->sec;
-       memset(sec, 0, sizeof(struct sockaddr_ec));
-       sec->cookie = cookie;
-       sec->type = ECTYPE_TRANSMIT_STATUS | result;
-       sec->sec_family = AF_ECONET;
-
-       if (sock_queue_rcv_skb(sk, skb) < 0)
-               kfree_skb(skb);
-}
-
-#ifdef CONFIG_ECONET_NATIVE
-/*
- *     Called by the Econet hardware driver when a packet transmit
- *     has completed.  Tell the user.
- */
-
-static void ec_tx_done(struct sk_buff *skb, int result)
-{
-       struct ec_cb *eb = (struct ec_cb *)&skb->cb;
-       tx_result(skb->sk, eb->cookie, result);
-}
-#endif
-
-/*
- *     Send a packet.  We have to work out which device it's going out on
- *     and hence whether to use real Econet or the UDP emulation.
- */
-
-static int econet_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-                         struct scm_cookie *scm)
-{
-       struct sock *sk = sock->sk;
-       struct sockaddr_ec *saddr=(struct sockaddr_ec *)msg->msg_name;
-       struct net_device *dev;
-       struct ec_addr addr;
-       struct ec_device *edev;
-       int err;
-       unsigned char port, cb;
-       struct sk_buff *skb;
-       struct ec_cb *eb;
-#ifdef CONFIG_ECONET_NATIVE
-       unsigned short proto = 0;
-#endif
-#ifdef CONFIG_ECONET_AUNUDP
-       struct msghdr udpmsg;
-       struct iovec iov[msg->msg_iovlen+1];
-       struct aunhdr ah;
-       struct sockaddr_in udpdest;
-       __kernel_size_t size;
-       int i;
-       mm_segment_t oldfs;
-#endif
-               
-       /*
-        *      Check the flags. 
-        */
-
-       if (msg->msg_flags&~MSG_DONTWAIT) 
-               return(-EINVAL);
-
-       /*
-        *      Get and verify the address. 
-        */
-        
-       if (saddr == NULL) {
-               addr.station = sk->protinfo.af_econet->station;
-               addr.net = sk->protinfo.af_econet->net;
-               port = sk->protinfo.af_econet->port;
-               cb = sk->protinfo.af_econet->cb;
-       } else {
-               if (msg->msg_namelen < sizeof(struct sockaddr_ec)) 
-                       return -EINVAL;
-               addr.station = saddr->addr.station;
-               addr.net = saddr->addr.net;
-               port = saddr->port;
-               cb = saddr->cb;
-       }
-
-       /* Look for a device with the right network number. */
-       for (edev = edevlist; edev && (edev->net != addr.net); 
-            edev = edev->next);
-
-       /* Bridge?  What's that? */
-       if (edev == NULL) 
-               return -ENETUNREACH;
-
-       dev = edev->dev;
-
-       if (dev->type == ARPHRD_ECONET)
-       {
-               /* Real hardware Econet.  We're not worthy etc. */
-#ifdef CONFIG_ECONET_NATIVE
-               atomic_inc(&dev->refcnt);
-               
-               skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, 
-                                         msg->msg_flags & MSG_DONTWAIT, &err);
-               if (skb==NULL)
-                       goto out_unlock;
-               
-               skb_reserve(skb, (dev->hard_header_len+15)&~15);
-               skb->nh.raw = skb->data;
-               
-               eb = (struct ec_cb *)&skb->cb;
-               
-               eb->cookie = saddr->cookie;
-               eb->sec = *saddr;
-               eb->sent = ec_tx_done;
-
-               if (dev->hard_header) {
-                       int res;
-                       err = -EINVAL;
-                       res = dev->hard_header(skb, dev, ntohs(proto), &addr, NULL, len);
-                       if (sock->type != SOCK_DGRAM) {
-                               skb->tail = skb->data;
-                               skb->len = 0;
-                       } else if (res < 0)
-                               goto out_free;
-               }
-               
-               /* Copy the data. Returns -EFAULT on error */
-               err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
-               skb->protocol = proto;
-               skb->dev = dev;
-               skb->priority = sk->priority;
-               if (err)
-                       goto out_free;
-               
-               err = -ENETDOWN;
-               if (!(dev->flags & IFF_UP))
-                       goto out_free;
-               
-               /*
-                *      Now send it
-                */
-               
-               dev_queue_xmit(skb);
-               dev_put(dev);
-               return(len);
-
-       out_free:
-               kfree_skb(skb);
-       out_unlock:
-               if (dev)
-                       dev_put(dev);
-#else
-               err = -EPROTOTYPE;
-#endif
-               return err;
-       }
-
-#ifdef CONFIG_ECONET_AUNUDP
-       /* AUN virtual Econet. */
-
-       if (udpsock == NULL)
-               return -ENETDOWN;               /* No socket - can't send */
-       
-       /* Make up a UDP datagram and hand it off to some higher intellect. */
-
-       memset(&udpdest, 0, sizeof(udpdest));
-       udpdest.sin_family = AF_INET;
-       udpdest.sin_port = htons(AUN_PORT);
-
-       /* At the moment we use the stupid Acorn scheme of Econet address
-          y.x maps to IP a.b.c.x.  This should be replaced with something
-          more flexible and more aware of subnet masks.  */
-       {
-               struct in_device *idev = in_dev_get(dev);
-               unsigned long network = 0;
-               if (idev) {
-                       read_lock(&idev->lock);
-                       if (idev->ifa_list)
-                               network = ntohl(idev->ifa_list->ifa_address) & 
-                                       0xffffff00;             /* !!! */
-                       read_unlock(&idev->lock);
-                       in_dev_put(idev);
-               }
-               udpdest.sin_addr.s_addr = htonl(network | addr.station);
-       }
-
-       ah.port = port;
-       ah.cb = cb & 0x7f;
-       ah.code = 2;            /* magic */
-       ah.pad = 0;
-
-       /* tack our header on the front of the iovec */
-       size = sizeof(struct aunhdr);
-       iov[0].iov_base = (void *)&ah;
-       iov[0].iov_len = size;
-       for (i = 0; i < msg->msg_iovlen; i++) {
-               void *base = msg->msg_iov[i].iov_base;
-               size_t len = msg->msg_iov[i].iov_len;
-               /* Check it now since we switch to KERNEL_DS later. */
-               if ((err = verify_area(VERIFY_READ, base, len)) < 0)
-                       return err;
-               iov[i+1].iov_base = base;
-               iov[i+1].iov_len = len;
-               size += len;
-       }
-
-       /* Get a skbuff (no data, just holds our cb information) */
-       if ((skb = sock_alloc_send_skb(sk, 0, 0, 
-                            msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
-               return err;
-
-       eb = (struct ec_cb *)&skb->cb;
-
-       eb->cookie = saddr->cookie;
-       eb->timeout = (5*HZ);
-       eb->start = jiffies;
-       ah.handle = aun_seq;
-       eb->seq = (aun_seq++);
-       eb->sec = *saddr;
-
-       skb_queue_tail(&aun_queue, skb);
-
-       udpmsg.msg_name = (void *)&udpdest;
-       udpmsg.msg_namelen = sizeof(udpdest);
-       udpmsg.msg_iov = &iov[0];
-       udpmsg.msg_iovlen = msg->msg_iovlen + 1;
-       udpmsg.msg_control = NULL;
-       udpmsg.msg_controllen = 0;
-       udpmsg.msg_flags=0;
-
-       oldfs = get_fs(); set_fs(KERNEL_DS);    /* More privs :-) */
-       err = sock_sendmsg(udpsock, &udpmsg, size);
-       set_fs(oldfs);
-#else
-       err = -EPROTOTYPE;
-#endif
-       return err;
-}
-
-/*
- *     Look up the address of a socket.
- */
-
-static int econet_getname(struct socket *sock, struct sockaddr *uaddr,
-                         int *uaddr_len, int peer)
-{
-       struct sock *sk = sock->sk;
-       struct sockaddr_ec *sec = (struct sockaddr_ec *)uaddr;
-
-       if (peer)
-               return -EOPNOTSUPP;
-
-       sec->sec_family = AF_ECONET;
-       sec->port = sk->protinfo.af_econet->port;
-       sec->addr.station = sk->protinfo.af_econet->station;
-       sec->addr.net = sk->protinfo.af_econet->net;
-
-       *uaddr_len = sizeof(*sec);
-       return 0;
-}
-
-static void econet_destroy_timer(unsigned long data)
-{
-       struct sock *sk=(struct sock *)data;
-
-       if (!atomic_read(&sk->wmem_alloc) && !atomic_read(&sk->rmem_alloc)) {
-               sk_free(sk);
-               MOD_DEC_USE_COUNT;
-               return;
-       }
-
-       sk->timer.expires=jiffies+10*HZ;
-       add_timer(&sk->timer);
-       printk(KERN_DEBUG "econet socket destroy delayed\n");
-}
-
-/*
- *     Close an econet socket.
- */
-
-static int econet_release(struct socket *sock)
-{
-       struct sk_buff  *skb;
-       struct sock *sk = sock->sk;
-
-       if (!sk)
-               return 0;
-
-       sklist_remove_socket(&econet_sklist, sk);
-
-       /*
-        *      Now the socket is dead. No more input will appear.
-        */
-
-       sk->state_change(sk);   /* It is useless. Just for sanity. */
-
-       sock->sk = NULL;
-       sk->socket = NULL;
-       sk->dead = 1;
-
-       /* Purge queues */
-
-       while ((skb=skb_dequeue(&sk->receive_queue))!=NULL)
-               kfree_skb(skb);
-
-       if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) {
-               sk->timer.data=(unsigned long)sk;
-               sk->timer.expires=jiffies+HZ;
-               sk->timer.function=econet_destroy_timer;
-               add_timer(&sk->timer);
-               return 0;
-       }
-
-       sk_free(sk);
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
-
-/*
- *     Create an Econet socket
- */
-
-static int econet_create(struct socket *sock, int protocol)
-{
-       struct sock *sk;
-       int err;
-
-       /* Econet only provides datagram services. */
-       if (sock->type != SOCK_DGRAM)
-               return -ESOCKTNOSUPPORT;
-
-       sock->state = SS_UNCONNECTED;
-       MOD_INC_USE_COUNT;
-
-       err = -ENOBUFS;
-       sk = sk_alloc(PF_ECONET, GFP_KERNEL, 1);
-       if (sk == NULL)
-               goto out;
-
-       sk->reuse = 1;
-       sock->ops = &econet_ops;
-       sock_init_data(sock,sk);
-
-       sk->protinfo.af_econet = kmalloc(sizeof(struct econet_opt), GFP_KERNEL);
-       if (sk->protinfo.af_econet == NULL)
-               goto out_free;
-       memset(sk->protinfo.af_econet, 0, sizeof(struct econet_opt));
-       sk->zapped=0;
-       sk->family = PF_ECONET;
-       sk->num = protocol;
-
-       sklist_insert_socket(&econet_sklist, sk);
-       return(0);
-
-out_free:
-       sk_free(sk);
-out:
-       MOD_DEC_USE_COUNT;
-       return err;
-}
-
-/*
- *     Handle Econet specific ioctls
- */
-
-static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void *arg)
-{
-       struct ifreq ifr;
-       struct ec_device *edev;
-       struct net_device *dev;
-       unsigned long flags;
-       struct sockaddr_ec *sec;
-
-       /*
-        *      Fetch the caller's info block into kernel space
-        */
-
-       if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
-               return -EFAULT;
-
-       if ((dev = dev_get_by_name(ifr.ifr_name)) == NULL) 
-               return -ENODEV;
-
-       sec = (struct sockaddr_ec *)&ifr.ifr_addr;
-
-       switch (cmd)
-       {
-       case SIOCSIFADDR:
-               spin_lock_irqsave(&edevlist_lock, flags);
-               edev = __edev_get(dev);
-               if (edev == NULL)
-               {
-                       /* Magic up a new one. */
-                       printk("Get fascist grenade!!!\n");
-                       *(int*)0 = 0;
-                       /* Note to author: please, remove this spinlock.
-                          You do not change edevlist from interrupts,
-                          so that such aggressive protection is redundant.
-
-                          BTW not all scans of edev_list are protected.
-                        */
-                       edev = kmalloc(GFP_KERNEL, sizeof(struct ec_device));
-                       if (edev == NULL) {
-                               printk("af_ec: memory squeeze.\n");
-                               spin_unlock_irqrestore(&edevlist_lock, flags);
-                               dev_put(dev);
-                               return -ENOMEM;
-                       }
-                       memset(edev, 0, sizeof(struct ec_device));
-                       edev->dev = dev;
-                       edev->next = edevlist;
-                       edevlist = edev;
-               }
-               edev->station = sec->addr.station;
-               edev->net = sec->addr.net;
-               spin_unlock_irqrestore(&edevlist_lock, flags);
-               dev_put(dev);
-               return 0;
-
-       case SIOCGIFADDR:
-               spin_lock_irqsave(&edevlist_lock, flags);
-               edev = __edev_get(dev);
-               if (edev == NULL)
-               {
-                       spin_unlock_irqrestore(&edevlist_lock, flags);
-                       dev_put(dev);
-                       return -ENODEV;
-               }
-               memset(sec, 0, sizeof(struct sockaddr_ec));
-               sec->addr.station = edev->station;
-               sec->addr.net = edev->net;
-               sec->sec_family = AF_ECONET;
-               spin_unlock_irqrestore(&edevlist_lock, flags);
-               dev_put(dev);
-               if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       dev_put(dev);
-       return -EINVAL;
-}
-
-/*
- *     Handle generic ioctls
- */
-
-static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-       struct sock *sk = sock->sk;
-       int err;
-       int pid;
-
-       switch(cmd) 
-       {
-               case FIOSETOWN:
-               case SIOCSPGRP:
-                       err = get_user(pid, (int *) arg);
-                       if (err)
-                               return err; 
-                       if (current->pid != pid && current->pgrp != -pid && !suser())
-                               return -EPERM;
-                       sk->proc = pid;
-                       return(0);
-               case FIOGETOWN:
-               case SIOCGPGRP:
-                       return put_user(sk->proc, (int *)arg);
-               case SIOCGSTAMP:
-                       if(sk->stamp.tv_sec==0)
-                               return -ENOENT;
-                       err = -EFAULT;
-                       if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
-                               err = 0;
-                       return err;
-               case SIOCGIFFLAGS:
-               case SIOCSIFFLAGS:
-               case SIOCGIFCONF:
-               case SIOCGIFMETRIC:
-               case SIOCSIFMETRIC:
-               case SIOCGIFMEM:
-               case SIOCSIFMEM:
-               case SIOCGIFMTU:
-               case SIOCSIFMTU:
-               case SIOCSIFLINK:
-               case SIOCGIFHWADDR:
-               case SIOCSIFHWADDR:
-               case SIOCSIFMAP:
-               case SIOCGIFMAP:
-               case SIOCSIFSLAVE:
-               case SIOCGIFSLAVE:
-               case SIOCGIFINDEX:
-               case SIOCGIFNAME:
-               case SIOCGIFCOUNT:
-               case SIOCSIFHWBROADCAST:
-                       return(dev_ioctl(cmd,(void *) arg));
-
-               case SIOCSIFADDR:
-               case SIOCGIFADDR:
-                       return ec_dev_ioctl(sock, cmd, (void *)arg);
-                       break;
-
-               default:
-                       return(dev_ioctl(cmd,(void *) arg));
-       }
-       /*NOTREACHED*/
-       return 0;
-}
-
-static struct net_proto_family econet_family_ops = {
-       PF_ECONET,
-       econet_create
-};
-
-static struct proto_ops SOCKOPS_WRAPPED(econet_ops) = {
-       PF_ECONET,
-
-       econet_release,
-       econet_bind,
-       sock_no_connect,
-       sock_no_socketpair,
-       sock_no_accept,
-       econet_getname, 
-       datagram_poll,
-       econet_ioctl,
-       sock_no_listen,
-       sock_no_shutdown,
-       sock_no_setsockopt,
-       sock_no_getsockopt,
-       sock_no_fcntl,
-       econet_sendmsg,
-       econet_recvmsg,
-       sock_no_mmap
-};
-
-#include <linux/smp_lock.h>
-SOCKOPS_WRAP(econet, PF_ECONET);
-
-/*
- *     Find the listening socket, if any, for the given data.
- */
-
-static struct sock *ec_listening_socket(unsigned char port, unsigned char
-                                       station, unsigned char net)
-{
-       struct sock *sk = econet_sklist;
-
-       while (sk)
-       {
-               struct econet_opt *opt = sk->protinfo.af_econet;
-               if ((opt->port == port || opt->port == 0) && 
-                   (opt->station == station || opt->station == 0) &&
-                   (opt->net == net || opt->net == 0))
-                       return sk;
-
-               sk = sk->next;
-       }
-
-       return NULL;
-}
-
-#ifdef CONFIG_ECONET_AUNUDP
-
-/*
- *     Send an AUN protocol response. 
- */
-
-static void aun_send_response(__u32 addr, unsigned long seq, int code, int cb)
-{
-       struct sockaddr_in sin;
-       struct iovec iov;
-       struct aunhdr ah;
-       struct msghdr udpmsg;
-       int err;
-       mm_segment_t oldfs;
-       
-       memset(&sin, 0, sizeof(sin));
-       sin.sin_family = AF_INET;
-       sin.sin_port = htons(AUN_PORT);
-       sin.sin_addr.s_addr = addr;
-
-       ah.code = code;
-       ah.pad = 0;
-       ah.port = 0;
-       ah.cb = cb;
-       ah.handle = seq;
-
-       iov.iov_base = (void *)&ah;
-       iov.iov_len = sizeof(ah);
-
-       udpmsg.msg_name = (void *)&sin;
-       udpmsg.msg_namelen = sizeof(sin);
-       udpmsg.msg_iov = &iov;
-       udpmsg.msg_iovlen = 1;
-       udpmsg.msg_control = NULL;
-       udpmsg.msg_controllen = 0;
-       udpmsg.msg_flags=0;
-
-       oldfs = get_fs(); set_fs(KERNEL_DS);
-       err = sock_sendmsg(udpsock, &udpmsg, sizeof(ah));
-       set_fs(oldfs);
-}
-
-/*
- *     Handle incoming AUN packets.  Work out if anybody wants them,
- *     and send positive or negative acknowledgements as appropriate.
- */
-
-static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len)
-{
-       struct ec_device *edev = edev_get(skb->dev);
-       struct iphdr *ip = skb->nh.iph;
-       unsigned char stn = ntohl(ip->saddr) & 0xff;
-       struct sock *sk;
-       struct sk_buff *newskb;
-       struct ec_cb *eb;
-       struct sockaddr_ec *sec;
-
-       if (edev == NULL)
-               return;         /* Device not configured for AUN */
-       
-       if ((sk = ec_listening_socket(ah->port, stn, edev->net)) == NULL)
-               goto bad;               /* Nobody wants it */
-
-       newskb = alloc_skb((len - sizeof(struct aunhdr) + 15) & ~15, 
-                          GFP_ATOMIC);
-       if (newskb == NULL)
-       {
-               printk(KERN_DEBUG "AUN: memory squeeze, dropping packet.\n");
-               /* Send nack and hope sender tries again */
-               goto bad;
-       }
-
-       eb = (struct ec_cb *)&newskb->cb;
-       sec = (struct sockaddr_ec *)&eb->sec;
-       memset(sec, 0, sizeof(struct sockaddr_ec));
-       sec->sec_family = AF_ECONET;
-       sec->type = ECTYPE_PACKET_RECEIVED;
-       sec->port = ah->port;
-       sec->cb = ah->cb;
-       sec->addr.net = edev->net;
-       sec->addr.station = stn;
-
-       memcpy(skb_put(newskb, len - sizeof(struct aunhdr)), (void *)(ah+1), 
-              len - sizeof(struct aunhdr));
-
-       if (sock_queue_rcv_skb(sk, newskb) < 0)
-       {
-               /* Socket is bankrupt. */
-               kfree_skb(newskb);
-               goto bad;
-       }
-
-       aun_send_response(ip->saddr, ah->handle, 3, 0);
-       return;
-
-bad:
-       aun_send_response(ip->saddr, ah->handle, 4, 0);
-}
-
-/*
- *     Handle incoming AUN transmit acknowledgements.  If the sequence
- *      number matches something in our backlog then kill it and tell
- *     the user.  If the remote took too long to reply then we may have
- *     dropped the packet already.
- */
-
-static void aun_tx_ack(unsigned long seq, int result)
-{
-       struct sk_buff *skb;
-       unsigned long flags;
-       struct ec_cb *eb;
-
-       spin_lock_irqsave(&aun_queue_lock, flags);
-       skb = skb_peek(&aun_queue);
-       while (skb && skb != (struct sk_buff *)&aun_queue)
-       {
-               struct sk_buff *newskb = skb->next;
-               eb = (struct ec_cb *)&skb->cb;
-               if (eb->seq == seq)
-                       goto foundit;
-
-               skb = newskb;
-       }
-       spin_unlock_irqrestore(&aun_queue_lock, flags);
-       printk(KERN_DEBUG "AUN: unknown sequence %ld\n", seq);
-       return;
-
-foundit:
-       tx_result(skb->sk, eb->cookie, result);
-       skb_unlink(skb);
-       spin_unlock_irqrestore(&aun_queue_lock, flags);
-}
-
-/*
- *     Deal with received AUN frames - sort out what type of thing it is
- *     and hand it to the right function.
- */
-
-static void aun_data_available(struct sock *sk, int slen)
-{
-       int err;
-       struct sk_buff *skb;
-       unsigned char *data;
-       struct aunhdr *ah;
-       struct iphdr *ip;
-       size_t len;
-
-       while ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) {
-               if (err == -EAGAIN) {
-                       printk(KERN_ERR "AUN: no data available?!");
-                       return;
-               }
-               printk(KERN_DEBUG "AUN: recvfrom() error %d\n", -err);
-       }
-
-       data = skb->h.raw + sizeof(struct udphdr);
-       ah = (struct aunhdr *)data;
-       len = skb->len - sizeof(struct udphdr);
-       ip = skb->nh.iph;
-
-       switch (ah->code)
-       {
-       case 2:
-               aun_incoming(skb, ah, len);
-               break;
-       case 3:
-               aun_tx_ack(ah->handle, ECTYPE_TRANSMIT_OK);
-               break;
-       case 4:
-               aun_tx_ack(ah->handle, ECTYPE_TRANSMIT_NOT_LISTENING);
-               break;
-#if 0
-               /* This isn't quite right yet. */
-       case 5:
-               aun_send_response(ip->saddr, ah->handle, 6, ah->cb);
-               break;
-#endif
-       default:
-               printk(KERN_DEBUG "unknown AUN packet (type %d)\n", data[0]);
-       }
-
-       skb_free_datagram(sk, skb);
-}
-
-/*
- *     Called by the timer to manage the AUN transmit queue.  If a packet
- *     was sent to a dead or nonexistent host then we will never get an
- *     acknowledgement back.  After a few seconds we need to spot this and
- *     drop the packet.
- */
-
-
-static void ab_cleanup(unsigned long h)
-{
-       struct sk_buff *skb;
-       unsigned long flags;
-
-       spin_lock_irqsave(&aun_queue_lock, flags);
-       skb = skb_peek(&aun_queue);
-       while (skb && skb != (struct sk_buff *)&aun_queue)
-       {
-               struct sk_buff *newskb = skb->next;
-               struct ec_cb *eb = (struct ec_cb *)&skb->cb;
-               if ((jiffies - eb->start) > eb->timeout)
-               {
-                       tx_result(skb->sk, eb->cookie, 
-                                 ECTYPE_TRANSMIT_NOT_PRESENT);
-                       skb_unlink(skb);
-               }
-               skb = newskb;
-       }
-       spin_unlock_irqrestore(&aun_queue_lock, flags);
-
-       mod_timer(&ab_cleanup_timer, jiffies + (HZ*2));
-}
-
-static int __init aun_udp_initialise(void)
-{
-       int error;
-       struct sockaddr_in sin;
-
-       skb_queue_head_init(&aun_queue);
-       spin_lock_init(&aun_queue_lock);
-       init_timer(&ab_cleanup_timer);
-       ab_cleanup_timer.expires = jiffies + (HZ*2);
-       ab_cleanup_timer.function = ab_cleanup;
-       add_timer(&ab_cleanup_timer);
-
-       memset(&sin, 0, sizeof(sin));
-       sin.sin_port = htons(AUN_PORT);
-
-       /* We can count ourselves lucky Acorn machines are too dim to
-          speak IPv6. :-) */
-       if ((error = sock_create(PF_INET, SOCK_DGRAM, 0, &udpsock)) < 0)
-       {
-               printk("AUN: socket error %d\n", -error);
-               return error;
-       }
-       
-       udpsock->sk->reuse = 1;
-       udpsock->sk->allocation = GFP_ATOMIC;   /* we're going to call it
-                                                  from interrupts */
-       
-       error = udpsock->ops->bind(udpsock, (struct sockaddr *)&sin,
-                               sizeof(sin));
-       if (error < 0)
-       {
-               printk("AUN: bind error %d\n", -error);
-               goto release;
-       }
-
-       udpsock->sk->data_ready = aun_data_available;
-
-       return 0;
-
-release:
-       sock_release(udpsock);
-       udpsock = NULL;
-       return error;
-}
-#endif
-
-static int econet_notifier(struct notifier_block *this, unsigned long msg, void *data)
-{
-       struct net_device *dev = (struct net_device *)data;
-       struct ec_device *edev;
-       unsigned long flags;
-
-       switch (msg) {
-       case NETDEV_UNREGISTER:
-               /* A device has gone down - kill any data we hold for it. */
-               spin_lock_irqsave(&edevlist_lock, flags);
-               for (edev = edevlist; edev; edev = edev->next)
-               {
-                       if (edev->dev == dev)
-                       {
-                               if (edev->prev)
-                                       edev->prev->next = edev->next;
-                               else
-                                       edevlist = edev->next;
-                               if (edev->next)
-                                       edev->next->prev = edev->prev;
-                               kfree(edev);
-                               break;
-                       }
-               }
-               spin_unlock_irqrestore(&edevlist_lock, flags);
-               break;
-       }
-
-       return NOTIFY_DONE;
-}
-
-struct notifier_block econet_netdev_notifier={
-       econet_notifier,
-       NULL,
-       0
-};
-
-#ifdef MODULE
-void cleanup_module(void)
-{
-#ifdef CONFIG_ECONET_AUNUDP
-       del_timer(&ab_cleanup_timer);
-       if (udpsock)
-               sock_release(udpsock);
-#endif
-       unregister_netdevice_notifier(&econet_netdev_notifier);
-       sock_unregister(econet_family_ops.family);
-       return;
-}
-
-int init_module(void)
-#else
-void __init econet_proto_init(struct net_proto *pro)
-#endif
-{
-       spin_lock_init(&edevlist_lock);
-       spin_lock_init(&aun_queue_lock);
-       /* Stop warnings from happening on UP systems. */
-       (void)edevlist_lock;
-       (void)aun_queue_lock;
-       sock_register(&econet_family_ops);
-#ifdef CONFIG_ECONET_AUNUDP
-       aun_udp_initialise();
-#endif
-       register_netdevice_notifier(&econet_netdev_notifier);
-#ifdef MODULE
-       return 0;
-#endif
-}
diff --git a/net/econet/sysctl_net_ec.c b/net/econet/sysctl_net_ec.c
new file mode 100644 (file)
index 0000000..9790a3a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *     An implementation of the Acorn Econet and AUN protocols.
+ *     Philip Blundell <philb@gnu.org>
+ *
+ *     Fixes:
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table econet_table[] = {
+       {0}
+};
+
+static struct ctl_table_header *econet_sysctl_header;
+
+static ctl_table econet_net_table[] = {
+       {NET_ECONET, "econet", NULL, 0, 0555, econet_table},
+        {0}
+};
+
+static ctl_table econet_root_table[] = {
+       {CTL_NET, "net", NULL, 0, 0555, econet_net_table},
+        {0}
+};
+
+void econet_sysctl_register(void)
+{
+       econet_sysctl_header = register_sysctl_table(econet_root_table, 0);
+}
+
+#ifdef MODULE
+void econet_sysctl_unregister(void)
+{
+       unregister_sysctl_table(econet_sysctl_header);
+}
+#endif /* MODULE */
index 9f7ad441ee5e57f63ea93a3941f412ecaf1e63bf..7d3e49bed3ca3c2f8d519189fa29ad11e2971416 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.163 2000/02/08 21:27:13 davem Exp $
+ * Version:    $Id: tcp.c,v 1.164 2000/03/08 19:36:40 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -624,28 +624,29 @@ int tcp_listen_start(struct sock *sk)
        tp->listen_opt = lopt;
        write_unlock_bh(&tp->syn_wait_lock);
 
+       /* There is race window here: we announce ourselves listening,
+        * but this transition is still not validated by get_port().
+        * It is OK, because this socket enters to hash table only
+        * after validation is complete.
+        */
        sk->state = TCP_LISTEN;
-       if (sk->num == 0) {
-               if (sk->prot->get_port(sk, 0) != 0) {
-                       sk->state = TCP_CLOSE;
-                       write_lock_bh(&tp->syn_wait_lock);
-                       tp->listen_opt = NULL;
-                       write_unlock_bh(&tp->syn_wait_lock);
-                       kfree(lopt);
-                       return -EAGAIN;
-               }
+       if (sk->prot->get_port(sk, sk->num) == 0) {
                sk->sport = htons(sk->num);
-       } else {
-               if (sk->prev)
-                       ((struct tcp_bind_bucket*)sk->prev)->fastreuse = 0;
-       }
 
-       sk_dst_reset(sk);
-       sk->prot->hash(sk);
-       sk->socket->flags |= SO_ACCEPTCON;
-       sk->write_space = tcp_listen_write_space;
+               sk->write_space = tcp_listen_write_space;
+               sk_dst_reset(sk);
+               sk->prot->hash(sk);
+               sk->socket->flags |= SO_ACCEPTCON;
 
-       return 0;
+               return 0;
+       }
+
+       sk->state = TCP_CLOSE;
+       write_lock_bh(&tp->syn_wait_lock);
+       tp->listen_opt = NULL;
+       write_unlock_bh(&tp->syn_wait_lock);
+       kfree(lopt);
+       return -EADDRINUSE;
 }
 
 /*
index 25a71d5f04d081355b7af18b2e21823d2fde73f9..204f2557457f2c1dea442bb593e3065d31c5b7bb 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.200 2000/02/11 22:27:26 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.201 2000/03/08 19:36:42 davem Exp $
  *
  *             IPv4 specific functions
  *
@@ -231,14 +231,15 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
                                break;
        }
        if (tb != NULL && tb->owners != NULL) {
-               if (tb->fastreuse != 0 && sk->reuse != 0) {
+               if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
                        goto success;
                } else {
                        struct sock *sk2 = tb->owners;
                        int sk_reuse = sk->reuse;
 
                        for( ; sk2 != NULL; sk2 = sk2->bind_next) {
-                               if (sk->bound_dev_if == sk2->bound_dev_if) {
+                               if (sk != sk2 &&
+                                   sk->bound_dev_if == sk2->bound_dev_if) {
                                        if (!sk_reuse   ||
                                            !sk2->reuse ||
                                            sk2->state == TCP_LISTEN) {
@@ -269,11 +270,15 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
                tb->fastreuse = 0;
 success:
        sk->num = snum;
-       if ((sk->bind_next = tb->owners) != NULL)
-               tb->owners->bind_pprev = &sk->bind_next;
-       tb->owners = sk;
-       sk->bind_pprev = &tb->owners;
-       sk->prev = (struct sock *) tb;
+       if (sk->prev == NULL) {
+               if ((sk->bind_next = tb->owners) != NULL)
+                       tb->owners->bind_pprev = &sk->bind_next;
+               tb->owners = sk;
+               sk->bind_pprev = &tb->owners;
+               sk->prev = (struct sock *) tb;
+       } else {
+               BUG_TRAP(sk->prev == (struct sock *) tb);
+       }
        ret = 0;
 
 fail_unlock:
index f47b4a1037bcc0f5f7acd9fca02b0015d037f1a7..b0e8ee714451d83bea02291e26180d6570e5d264 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.120 2000/02/27 19:51:49 davem Exp $
+ *     $Id: tcp_ipv6.c,v 1.121 2000/03/08 19:36:47 davem Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
@@ -132,7 +132,7 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
                                break;
        }
        if (tb != NULL && tb->owners != NULL) {
-               if (tb->fastreuse != 0 && sk->reuse != 0) {
+               if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
                        goto success;
                } else {
                        struct sock *sk2 = tb->owners;
@@ -141,7 +141,8 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
 
                        /* We must walk the whole port owner list in this case. -DaveM */
                        for( ; sk2 != NULL; sk2 = sk2->bind_next) {
-                               if (sk->bound_dev_if == sk2->bound_dev_if) {
+                               if (sk != sk2 &&
+                                   sk->bound_dev_if == sk2->bound_dev_if) {
                                        if (!sk_reuse   ||
                                            !sk2->reuse ||
                                            sk2->state == TCP_LISTEN) {
@@ -177,11 +178,15 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
 
 success:
        sk->num = snum;
-       if ((sk->bind_next = tb->owners) != NULL)
-               tb->owners->bind_pprev = &sk->bind_next;
-       tb->owners = sk;
-       sk->bind_pprev = &tb->owners;
-       sk->prev = (struct sock *) tb;
+       if (sk->prev == NULL) {
+               if ((sk->bind_next = tb->owners) != NULL)
+                       tb->owners->bind_pprev = &sk->bind_next;
+               tb->owners = sk;
+               sk->bind_pprev = &tb->owners;
+               sk->prev = (struct sock *) tb;
+       } else {
+               BUG_TRAP(sk->prev == (struct sock *) tb);
+       }
        ret = 0;
 
 fail_unlock:
index e539693fef14a8315a3a4d2fd84bab00b2317bef..bda8d54d8bc19a1f24c134cb66deffa92fece3bd 100644 (file)
@@ -42,6 +42,10 @@ extern ctl_table ipv6_table[];
 extern ctl_table tr_table[];
 #endif
 
+#ifdef CONFIG_ECONET
+extern ctl_table econet_table[];
+#endif
+
 ctl_table net_table[] = {
        {NET_CORE,   "core",      NULL, 0, 0555, core_table},      
 #ifdef CONFIG_UNIX
@@ -62,6 +66,9 @@ ctl_table net_table[] = {
 #endif
 #ifdef CONFIG_TR
        {NET_TR, "token-ring", NULL, 0, 0555, tr_table},
+#endif
+#ifdef CONFIG_ECONET
+       {NET_ECONET, "econet",    NULL, 0, 0555, econet_table},
 #endif
        {0}
 };