diff -u --recursive --new-file v2.1.93/linux/CREDITS linux/CREDITS
--- v2.1.93/linux/CREDITS	Wed Apr  1 20:11:46 1998
+++ linux/CREDITS	Wed Apr  8 17:31:27 1998
@@ -895,6 +895,10 @@
 E: rfkoenig@immd4.informatik.uni-erlangen.de
 D: The Linux Support Team Erlangen
 
+N: Andreas Koensgen
+E: ajk@iehk.rwth-aachen.de
+D: 6pack driver for AX.25
+
 N: Andi Kleen
 E: ak@muc.de
 D: network hacker, syncookies
@@ -1254,6 +1258,14 @@
 S: FIN-00330 Helsingfors
 S: Finland
 
+N: Matija Nalis
+E: mnalis@jagor.srce.hr
+E: mnalis@voyager.hr
+D: Maintainer of the Umsdos file system
+S: Listopadska 7
+S: 10000 Zagreb
+S: Croatia
+
 N: Jonathan Naylor
 E: g4klx@g4klx.demon.co.uk
 E: g4klx@amsat.org
@@ -1407,7 +1419,7 @@
 
 N: Joerg Reuter
 E: jreuter@poboxes.com
-W: http://www.rat.de/jr/
+W: http://poboxes.com/jreuter/
 W: http://qsl.net/dl1bke/
 D: Generic Z8530 driver, AX.25 DAMA slave implementation
 D: Several AX.25 hacks
@@ -1865,6 +1877,14 @@
 S: Hernesaarenkatu 15 A 2
 S: Fin-00150 Helsinki
 S: Finland
+
+N: Jonathan Woithe
+E: jwoithe@physics.adelaide.edu.au
+W: http://www.physics.adelaide.edu.au/~jwoithe
+D: ALS-007 soundcard extensions to Sound Blaster driver
+S: 4/36 Trevelyan St
+S: Wayville SA 5034
+S: Australia
 
 N: Roger E. Wolff
 E: R.E.Wolff@BitWizard.nl
diff -u --recursive --new-file v2.1.93/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.93/linux/Documentation/Configure.help	Mon Apr  6 17:40:59 1998
+++ linux/Documentation/Configure.help	Wed Apr  8 17:31:27 1998
@@ -1089,7 +1089,7 @@
   want to say Y here. Information about ELF is on the WWW at
   http://www.sjc.ox.ac.uk/users/barlow/elf-howto.html (To browse the
   WWW, you need to have access to a machine on the Internet that has a
-  programs like lynx or netscape).  If you find that after upgrading
+  program like lynx or netscape).  If you find that after upgrading
   from Linux kernel 1.2 and saying Y here, you still can't run any ELF
   binaries (they just crash), then you'll have to install the newest
   ELF runtime libraries, including ld.so (check the file
@@ -1208,7 +1208,7 @@
   the line "SMP=1" is not commented out and read Documentation/smp and
   Documentation/IO-APIC.txt and the SMP-FAQ on the WWW at
   http://www.irisa.fr/prive/mentre/smp-faq/ (to browse the WWW, you
-  need to have access to a machine on the Internet that has a programs
+  need to have access to a machine on the Internet that has a program
   like lynx or netscape). People using multiprocessor machines should
   also say Y to "Enhanced Real Time Clock Support", below.
   If you want to compile a kernel that should work on both single
@@ -1243,7 +1243,7 @@
   extensive information about drivers for many devices attaching to
   the parallel port see http://www.torque.net/linux-pp.html on the WWW
   (To browse the WWW, you need to have access to a machine on the
-  Internet that has a programs like lynx or netscape). It is possible
+  Internet that has a program like lynx or netscape). It is possible
   to share a single parallel port among several devices and it is safe
   to compile all the corresponding drivers into the kernel. If you
   want to compile parallel port support as a module ( = code which can
@@ -1295,72 +1295,6 @@
   themselves when requested.  Say Y to enable this feature, or M to
   compile it as a module (parport_ieee1284.o).  If in doubt, say N.
 
-Plug and Play subsystem (EXPERIMENTAL)
-CONFIG_PNP_DRV
-  This enables support for the new Plug-and-Play (or PnP) Linux
-  subsystems. This support is required for PnP ISA support, and for PnP
-  Legacy support. User-mode utilities for this support may be found at
-  http://www.lpsg.demon.co.uk/pnp-linux.html.
-
-PnP resource management
-CONFIG_KERNEL_PNP_RESOURCE
-  This option will cause the new PnP generic resource management
-  routines to be used instead of the old routines request_xxx and
-  free_xxx. Emulation routines are put in place to support the old
-  calling style. This code support masks for IO decoding (required for
-  Plug and Play devices). There is no need to enable this option unless
-  you want to - these features will still be used where they are needed.
-  However, enabling it will reduce your kernel size slightly, and also
-  allow you to test this code more extensively.
-
-Support for boot-loaded PnP configuration (RECOMMENDED)
-CONFIG_PNP_BLDCONFIG
-  This will enable support for preloading data about the configuration
-  of any Plug-and-Play devices in the system into the kernel at boot
-  time, which means that any devices required at boot can be configured
-  at this time manually. Say Y unless you have a reason not to.
-
-PnP ISA support
-CONFIG_PNP_ISA
-  This option is required to allow the Linux PnP subsystem to handle
-  Plug and Play ISA devices. This includes full support for PnP ISA,
-  including the I/O range check feature.
-
-PnP ISA backwards-compatibility support
-CONFIG_PNP_ISA_COMPAT
-  This option will enable partial backwards compatibility with drivers
-  written using older versions (up to the last 0.2.x) of the PnP driver
-  written by Tom Lees <tom@lpsg.demon.co.uk>.
-
-PnP Legacy device support
-CONFIG_PNP_LEGACY
-  Before PnP ISA was standardized, several "jumperless", or
-  "soft-configurable" boards were finding their way onto the market.
-  These cards used somewhat proprietary mechanisms for configuring
-  IRQs, DMAs, IO addresses, and memory ranges. These devices (mainly
-  network cards, but also some sound cards) can be configured as any
-  other PnP device can by saying Y here, if appropriate drivers
-  for these devices are available.
-
-PnP sysctl support (RECOMMENDED)
-CONFIG_PNP_SYSCTL
-  This option enables support for the user-mode interface to the
-  kernel-mode PnP systems. It requires that you said Y to "Sysctl
-  support" above.  The only reason you might want to switch this off
-  is if you aren't going to use user-mode utilities to configure PnP,
-  and you want to save a couple of kilobytes of kernel space. Answer Y
-  unless you know what you are doing. User-mode utilities and a
-  library for accessing this interface may be found at
-  http://www.lpsg.demon.co.uk/pnp-linux.html.
-
-PnP auto-configures all devices on startup
-CONFIG_PNP_BOOTINIT
-  This option will allow the PnP subsystem to automatically configure
-  all the PnP devices it finds upon system startup (or at least
-  attempt to). This is useful if you have older drivers which do not use
-  the Linux-PnP system to configure PnP devices, and which you need
-  to be configured by PnP before you can use them.
-
 Enable loadable module support
 CONFIG_MODULES
   Kernel modules are small pieces of compiled code which can be
@@ -3560,6 +3494,14 @@
   whenever you want), say M here and read
   Documentation/modules.txt. The module will be called mkiss.o.
 
+Serial port 6PACK driver for AX.25
+CONFIG_6PACK
+6pack is a protocol that attaches a TNC connected to a serial interface
+to be used as a network device. 6pack can be used as an alternative to KISS,
+but has some extended functionality. Note that this driver is still
+experimental and might cause problems. For details about the features
+and the usage of the driver, read Documentation/networking/6pack.txt.
+
 PLIP (parallel port) support
 CONFIG_PLIP
   PLIP (Parallel Line Internet Protocol) is used to create a
@@ -6700,7 +6642,7 @@
   fashion. (They should also Documentation/smp and
   Documentation/IO-APIC.txt and the SMP-FAQ on the WWW at
   http://www.irisa.fr/prive/mentre/smp-faq/ (to browse the WWW, you
-  need to have access to a machine on the Internet that has a programs
+  need to have access to a machine on the Internet that has a program
   like lynx or netscape)).
   If you think you have a use for such a device (such as periodic data
   sampling), then say Y here, and go read the file
@@ -6801,6 +6743,16 @@
   why they still haven't released any documentation.
   [http://204.200.238.31/cgi-bin/link.pl?co=i&cl=/ts/ibm/contact.html]
 
+Are you using the IBM Mwave "emulation" of SB ?
+CONFIG_SB_MWAVE
+  The IBM Mwave can do whats loosely describable as emulation of an 8bit
+  soundblaster if you load the right firmware from DOS warm boot and pray
+  and your machine happens to like you. Say Y if you are doing this as the
+  IRQ test normally fails on the mwave emulation. If you'd like real MWAVE
+  support phone IBM (425-556-8822) and ask them why they still haven't 
+  released any documentation.
+  [http://204.200.238.31/cgi-bin/link.pl?co=i&cl=/ts/ibm/contact.html]
+
 Generic OPL2/OPL3 FM synthesizer support
 CONFIG_ADLIB
   Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
@@ -6898,6 +6850,15 @@
   manufacturers such as Turtle Beach (Tropez), Reveal (some models)
   and Diamond (latest ones).
 
+Support MIDI in older MAD16 based cards (requires SB)
+CONFIG_MAD16_OLDCARD
+  Answer Y (or M) if you have an older card based on the C928
+  or Mozart chipset and you want to have  MIDI support. If you
+  enable this option you also need to enable support for SoundBlaster.
+
+ If you answer Y here you will
+  also need to enable the SoundBlaster driver.
+
 Support for Crystal CS4232 based (PnP) cards
 CONFIG_CS4232
   Say Y here if you have a card based on the Crystal CS4232 chip set,
@@ -7854,6 +7815,11 @@
   inserted in and removed from the running kernel whenever you
   want). If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
+
+SAA5249 Teletext processor
+CONFIG_VIDEO_SAA5249
+  Support for I2C bus based teletext using the SAA5249 chip. At the moment
+  this is only useful on some european WinTV cards.
 
 Quickcam BW Video For Linux
 CONFIG_VIDEO_BWQCAM
diff -u --recursive --new-file v2.1.93/linux/Documentation/filesystems/umsdos.txt linux/Documentation/filesystems/umsdos.txt
--- v2.1.93/linux/Documentation/filesystems/umsdos.txt	Mon Jan 30 23:39:02 1995
+++ linux/Documentation/filesystems/umsdos.txt	Wed Apr  8 11:39:45 1998
@@ -1,7 +1,13 @@
+Firstly, let me say that UMSDOS is going through some major code changes,
+and has some KNOWN BUGS (and quite a few unknown :-). Please read
+fs/umsdos/README-WIP.txt for more information on current status. Thanks.
+
+----------------------------------------------------------------------------
 Very short explanation for the impatient!!!
 
 Umsdos is a file system driver that run on top the MSDOS fs driver.
 It is written by Jacques Gelinas (jacques@solucorp.qc.ca)
+and is currently maintained by Matija Nalis (mnalis@jagor.srce.hr)
 
 Umsdos is not a file system per se, but a twist to make a boring
 one into a useful one.
diff -u --recursive --new-file v2.1.93/linux/Documentation/joystick.txt linux/Documentation/joystick.txt
--- v2.1.93/linux/Documentation/joystick.txt	Sat Nov 29 10:33:18 1997
+++ linux/Documentation/joystick.txt	Wed Apr  8 15:31:03 1998
@@ -41,7 +41,13 @@
 select `M' for this driver in the kernel configuration and insert the
 module:
 
-insmod js.o js=0xXX,0xYY
+insmod joystick.o js=0xXX,0xYY
+
+  To enable autoloading/-unloading of the joystick module, you have to add
+these lines to /etc/conf.modules:
+
+alias char-major-15 joystick
+options joystick js=0xXX,0xYY
 
   To enable the user space programs to read the joystick device, you have to
 create the device files using mknod (man mknod for more info):
diff -u --recursive --new-file v2.1.93/linux/Documentation/networking/6pack.txt linux/Documentation/networking/6pack.txt
--- v2.1.93/linux/Documentation/networking/6pack.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/6pack.txt	Wed Apr  8 17:31:27 1998
@@ -0,0 +1,175 @@
+This is the 6pack-mini-HOWTO, written by
+
+Andreas Könsgen DG3KQ
+Internet: ajk@iehk.rwth-aachen.de
+AMPR-net: dg3kq@db0pra.ampr.org
+AX.25:    dg3kq@db0ach.#nrw.deu.eu
+
+Last update: April 7, 1998
+
+1. What is 6pack, and what are the advantages to KISS?
+
+6pack is a transmission protocol for the data exchange between the PC and
+the TNC over a serial line. It can be used as an alternative to KISS.
+
+6pack has two major advantages:
+- The PC is given the full control over the radio
+  channel. Special control data is exchanged between the PC and the TNC so
+  that the PC knows at any time if the TNC is receiving data, if an TNC
+  buffer underrun or overrun has occured, if the PTT is
+  set and so on. This control data is processed at a higher priority than
+  normal data, so a data stream can be interrupted at any time to issue an
+  important event. This helps to improve the channel access and timing algorithms
+  as everything is computed in the PC. It would even be possible to experiment with
+  something completely different than the known CSMA and DAMA channel access
+  methods.
+  This kind of real-time control is especially important to supply several
+  TNCs that are connected between each other and the PC by a daisy chain
+  (however, this feature is not supported yet by the Linux 6pack driver).
+
+- Each packet transferred over the serial line is supplied with a checksum,
+  so it is easy to detect errors due to problems on the serial line.
+  Received packets that are corrupt are not passed on to the AX.25 layer.
+  Damaged packets that the TNC has received from the PC are not transmitted.
+
+More details about 6pack are described in the file 6pack.ps that is located
+in the doc directory of the AX.25 utilities package.
+
+2. Who has developed the 6pack protocol?
+
+The 6pack protocol has been developed by Ekki Plicht DF4OR, Henning Rech
+DF9IC and Gunter Jost DK7WJ. A driver for 6pack, written by Gunter Jost and
+Matthias Welwarsky DG2FEF, comes along with the PC version of FlexNet.
+They have also written a firmware for TNCs to perform the 6pack
+protocol (see section 4 below).
+
+3. Where can I get the latest version of 6pack for LinuX?
+
+At the moment, the 6pack stuff can obtained via anonymous ftp from
+db0bm.automation.fh-aachen.de. In the directory /incoming/dg3kq,
+there is a file named 6pack.tgz.
+
+4. Preparing the TNC for 6pack operation
+
+To be able to use 6pack, a special firmware for the TNC is needed. The EPROM
+of a newly bought TNC does not contain 6pack, so you will have to
+program an EPROM yourself. The image file for 6pack EPROMs should be
+available on any packet radio box where PC/FlexNet can be found. The name of
+the file is 6pack.bin. This file is copyrighted and maintainend by the FlexNet
+team. It can be used under the terms of the license that comes along
+with PC/FlexNet. Please do not ask me about the internals of this file as I
+don't know anything about it. I used a textual description of the 6pack
+protocol to program the Linux driver.
+
+TNCs contain a 64kByte EPROM, the lower half of which is used for
+TheFirmware/KISS. The upper half is either empty or is sometimes
+programmed with a software called TAPR. In the latter case, the TNC
+is supplied with a DIP switch so you can easily change between the
+two systems. When programming a new EPROM, one of the systems is replaced
+by 6pack. It is useful to replace TAPR, as this software is rarely used
+nowadays. If your TNC is not equipped with the switch mentioned above, you
+can build in one yourself that switches over the highest address pin
+of the EPROM between HIGH and LOW level. After having inserted the new EPROM
+and switched to 6pack, apply power to the TNC for a first test. The connect
+and the status LED are lit for about a second if the firmware initialises
+the TNC correctly.
+
+5. Building and installing the 6pack driver
+
+The driver has been tested with kernel version 2.1.90. Using with older
+kernels may lead to a compilation error because the interface to a kernel
+function has been changed in the 2.1.8x kernels.
+
+How to turn on 6pack support:
+
+- In the linux kernel configuration program, select the code maturity level
+  options menu and turn on the prompting for development drivers.
+
+- Select the amateur radio support menu and turn on the serial port 6pack
+  driver.
+
+- Compile and install the kernel and the modules.
+
+To use the driver, the kissattach program delivered with the AX.25 utilities
+has to be modified.
+
+- Do a cd to the directory that keeps the kissattach sources. Edit the
+  kissattach.c file. At the top, insert the following lines:
+
+  #ifndef N_6PACK
+  #define N_6PACK (N_AX25+1)
+  #endif
+
+  Then find the line
+   
+  int disc = N_AX25;
+
+  and replace N_AX25 by N_6PACK.
+
+- Recompile kissattach. Rename it to spattach to avoid confusions.
+
+Installing the driver:
+
+- Do an insmod 6pack. Look at your
+  /var/log/messages file to check if the module has printed its initialization message.
+
+- Do a spattach as you would launch kissattach when starting a KISS port.
+  Check if the kernel prints the message '6pack: TNC found'. 
+
+- From here, everything should work as if you were setting up a KISS port.
+  The only difference is that the network device that represents
+  the 6pack port is called sp instead of sl or ax. So, sp0 would be the
+  first 6pack port.
+
+Although the driver has been tested on various platforms, I still declare it
+ALPHA. BE CAREFUL! Sync your disks before insmoding the 6pack module
+and spattaching. Watch out if your computer behaves strangely. Read section
+6 of this file about known problems.
+
+Note that the connect and status LEDs of the TNC are controlled in a
+different way than they are when the TNC is used with PC/FlexNet. When using
+FlexNet, the connect LED is on if there is a connection; the status LED is
+on if there is data in the buffer of the PC's AX.25 engine that has to be
+transmitted. Under LinuX, the 6pack layer is beyond the AX.25 layer,
+so the 6pack driver doesn't know anything about connects or data that
+has not yet been transmitted. Therefore the LEDs are controlled
+as they are in KISS mode: The connect LED is turned on if data is transferred
+from the PC to the TNC over the serial line, the status LED if data is
+sent to the PC.
+
+6. Known problems
+
+When testing the driver with 2.0.3x kernels and
+operating with data rates on the radio channel of 9600 Baud or higher,
+the driver may, on certain systems, sometimes print the message '6pack:
+bad checksum', which is due to data loss if the other station sends two
+or more subsequent packets. I have been told that this is due tu a problem
+with the serial driver of 2.0.3x kernels. I don't know yet if the problem
+still exists with 2.1.x kernels, as I have heard that the serial driver
+code has been changed with 2.1.x.
+
+When shutting down the sp interface with ifconfig, the kernel crashes if
+there is still an AX.25 connection left over which an IP connection was
+running, even if that IP connection is already closed. The problem does not
+occur when there is a bare AX.25 connection still running. I don't know if
+this is a problem of the 6pack driver or something else in the kernel.
+
+The driver has been tested as a module, not yet as a kernel-builtin driver.
+
+The 6pack protocol supports daisy-chaining of TNCs in a token ring, which is
+connected to one serial port of the PC. This feature is not implemented
+and at least at the moment I won't be able to do it because I do not have
+the opportunity to build a TNC daisy-chain and test it.
+
+Some of the comments in the source code are inaccurate. They are left from
+the SLIP/KISS driver, from which the 6pack driver has been derived.
+I haven't modified or removed them yet -- sorry! The code itself needs
+some cleaning and optimizing. This will be done in a later release.
+
+If you encounter a bug or if you have a question or suggestion concerning the
+driver, feel free to mail me, using the adresses given at the beginning of
+this file.
+
+Have fun!
+
+Andreas
diff -u --recursive --new-file v2.1.93/linux/Documentation/sound/AWE32 linux/Documentation/sound/AWE32
--- v2.1.93/linux/Documentation/sound/AWE32	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/AWE32	Wed Apr  8 15:34:23 1998
@@ -0,0 +1,63 @@
+From: Nicola Bernardelli <nbern@mail.protos.it>
+
+     In order to load SB-AWE related drivers on recent kernels (tested
+with 2.1.86 and 2.1.88) with modularized sound support these lines can
+be issued (of course with the suitable values for the parameters)
+after PNP setup:
+
+insmod  sound.o
+insmod  uart401.o
+insmod  sb.o io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
+insmod  awe_wave.o
+
+     Alternatively, in order to also have automatic load on demand
+(not of the awe support, which would anyway most likely also require a
+call to sfxload), these lines can be added to /etc/conf.modules, of
+course with the suitable values for the parameters):
+
+alias char-major-14 sb
+post-install sb modprobe "-k" "adlib_card"
+options sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
+options adlib_card io=0x388     # FM synthetiser
+
+and then these two commands can be issued:
+
+modprobe sb
+insmod awe_wave
+
+------------------------------------------------------------------------------
+
+After picking up the second approach, you may want to put these lines
+on an ossfreeOn script:
+
+ -----
+#!/bin/sh
+
+modprobe sb
+insmod awe_wave
+
+# A call to 'aumix -L' (attention to what the home dir is at boot
+# time, you may put a link /.aumixrc -> /home/<sounduser>/.aumixrc) to
+# restore mixer device levels and a call to 'sfxload <path to
+# soundfont bank>' may be added in a customized ossfreeSetup script:
+
+if [ -x /usr/local/sbin/ossfreeSetup ] ; then
+  /usr/local/sbin/ossfreeSetup
+fi
+ -----
+
+And these lines in an ossfreeOff script:
+
+ -----
+#!/bin/sh
+
+# NOT set -e, maybe not all of them are currently loaded.
+
+rmmod awe_wave 
+rmmod adlib_card
+rmmod opl3
+rmmod sb
+rmmod uart401
+rmmod sound
+ -----
+
diff -u --recursive --new-file v2.1.93/linux/Documentation/sound/MAD16 linux/Documentation/sound/MAD16
--- v2.1.93/linux/Documentation/sound/MAD16	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/MAD16	Wed Apr  8 15:34:23 1998
@@ -0,0 +1,25 @@
+From: Shaw Carruthers <shaw@shawc.demon.co.uk>
+
+I have been using mad16 sound for some time now with no problems, current
+kernel 2.1.89
+
+lsmod shows:
+
+mad16                   5176   0 
+sb                     22044   0  [mad16]
+uart401                 5576   0  [mad16 sb]
+ad1848                 14176   1  [mad16]
+sound                  61928   0  [mad16 sb uart401 ad1848]
+
+.config has:
+
+CONFIG_SOUND=m
+CONFIG_ADLIB=m
+CONFIG_MAD16=m
+CONFIG_YM3812=m
+
+modules.conf has:
+
+alias char-major-14 mad16
+options sb mad16=1
+options mad16 io=0x530 irq=7 dma=0 dma16=1  && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
diff -u --recursive --new-file v2.1.93/linux/Documentation/sound/Opti linux/Documentation/sound/Opti
--- v2.1.93/linux/Documentation/sound/Opti	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/Opti	Wed Apr  8 15:34:23 1998
@@ -0,0 +1,216 @@
+Support for the OPTi 82C931 chip
+--------------------------------
+Note: parts of this README file apply also to other
+cards that use the mad16 driver.
+
+Some items in this README file are based on features
+added to the sound driver after Linux-2.1.91 was out.
+By the time of writing this I do not know which official
+kernel release will include these features.
+Please do not report inconsistencies on older Linux
+kernels.
+
+The OPTi 82C931 is supported in its non PnP mode.
+Usually you do not need to set jumpers etc... The sound driver
+will check the card status and if it is required it will
+force the card into a mode in which it can be programmed.
+
+If you have another OS installed on your computer it is recommended
+that Linux and the other OS use the same resources.
+
+Also, it is recommended that resources specified in /etc/conf.modules
+and resources specified in /etc/isapnp.conf agree.
+
+Compiling the sound driver
+--------------------------
+I highly recommend that you build a modularized sound driver.
+This document does not cover sound-driver which is built in
+the kernel.
+
+Sound card support should be enabled as a module (chose m).
+Answer 'm' for  these items:
+  Generic OPL2/OPL3 FM synthesizer support			(CONFIG_ADLIB)
+  Microsoft Sound System support				(CONFIG_MSS)
+  Support for OPTi MAD16 and/or Mozart based cards	 	(CONFIG_MAD16)
+  FM synthesizer (YM3812/OPL-3) support				(CONFIG_YM3812)
+
+The configuration menu may ask for addresses, irq lines or dma
+channels. If the card is used as a module the module loading
+options will override these values.
+
+For the OPTi 931 you can answer 'n' to:
+  Support MIDI in older MAD16 based cards (requires SB)		(CONFIG_MAD16_OLDCARD)
+If you do need MIDI support in a Mozart or C928 based card you
+need to answer 'm' to the above question. In that case you will
+also need to answer 'm' to:
+  '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SB)
+
+Go on and compile your kernel and modules. Install the modules. Run depmod -a.
+
+Using isapnptools
+-----------------
+In most systems with a PnP bios you do not need to use isapnp. The
+initialization provided by the bios is sufficient for the driver
+to pick up the card and continue initialization.
+
+If that fails, or if you have other PnP cards, you need to use isapnp
+to initialize the card.
+This was tested with isapnptools-1.11 but I recommend that you use
+isapnptools-1.13 (or newer). Run pnpdump to dump the information
+about your PnP cards. Then edit the resulting file and select
+the options of your choice. This file is normally installed as
+/etc/isapnp.conf.
+
+The driver had one limitation WRT io port resources.
+IO3 base should be 0x0E0C. Isapnp allows other io ports but this
+address is hard-coded into the driver.
+
+Using kmod and autoloading the sound driver
+-------------------------------------------
+Comment: as of linux-2.1.90 kmod is replacing kerneld.
+The config file '/etc/conf.modules' is used as before.
+
+This is the sound part of my /etc/conf.modules file.
+Following that I will explain each line.
+
+alias mixer0 mad16
+alias audio0 mad16
+alias midi0  mad16
+alias synth0 opl3
+options sb mad16=1
+options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0
+options opl3 io=0x388
+post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6
+
+Explain:
+
+alias mixer0 mad16
+alias audio0 mad16
+alias midi0  mad16
+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.
+
+The sound module in it's turn will request loading of a sub-driver
+for mixer, audio, midi or synthesizer device. The first 3 are
+supported by the mad16 driver. The synth device is supported
+by the opl3 driver.
+
+There is currently no way to autoload the sound device driver
+if more than one card is installed.
+
+options sb mad16=1
+
+This is left for historical reason. If you enable the
+config option 'Support MIDI in older MAD16 based cards (requires SB)'
+or if you use an older mad16 driver it will force loading of the
+SoundBlaster driver. This option tells the SB driver not to look
+for a SB card but to wait for the mad16 driver.
+
+options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0
+options opl3 io=0x388
+
+post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6
+
+This sets resources and options for the mad16 and opl3 drivers.
+I use 2 dma channels (only one is required) to enable full duplex.
+joystick=1 enables the joystick port. cdtype=0 disables the cd port.
+You can also set mpu_io and mpu_irq in the mad16 options for the
+uart401 driver.
+
+This tells modprobe to run /sbin/ad1848_mixer_reroute after
+mad16 is successfully loaded and initialized. The source
+for ad1848_mixer_reroute is appended to the end of this readme
+file. It is impossible for the sound driver to know the actual
+connections to the mixer. The 3 inputs intended for cd, synth
+and line-in are mapped to the generic inputs line1, line2 and
+line3. This program reroutes these mixer channels to their
+right names (note the right mapping depends on the actual sound
+card that you use).
+The numeric parameters mean:
+ 14=line1 8=cd    - reroute line1 to the CD input.
+ 15=line2 3=synth - reroute line2 to the synthesizer input.
+ 16=line3 6=line  - reroute line3 to the line input.
+For reference on other input names look at the file
+/usr/include/linux/soundcard.h.
+
+Using a joystick
+-----------------
+You must enable a joystick in the mad16 options. (also
+in /etc/isapnp.conf if you use it).
+Tested with regular analog joysticks.
+
+A CDROM drive connected to the sound card
+-----------------------------------------
+The 82C931 chip has support only for secondary ATAPI cdrom.
+(cdtype=8). Loading the mad16 driver resets the C931 chip
+and if a cdrom was already mounted it may cause a complete
+system hang. Do not use the sound card if you have an alternative.
+If you do use the sound card it is important that you load
+the mad16 driver (use "modprobe mad16" to prevent auto-unloading)
+before the cdrom is accessed the first time.
+
+Using the sound driver built-in the kernel may help here. but...
+Most new systems have a PnP bios and also two IDE controllers.
+The IDE controller on the sound card may be needed only on older
+systems (which have only one IDE controller) but these systems
+also do not have a PnP bios - requiring isapnptoosl and a modularized
+driver.
+
+Known problems
+--------------
+1. See the section on "A CDROM drive connected to the sound card".
+
+2. On my system the codec cannot capture companded sound samples.
+   (eg., recording from /dev/audio). When any companded capture is
+   requested I get a stereo-16 bit samples instead. Playback of
+   companded samples work well. Apparently this problem is not common
+   to all C931 based cards. I do not know how to identify cards that
+   have this problem.
+
+Source for ad1848_mixer_reroute.c
+---------------------------------
+#include <stdio.h>
+#include <fcntl.h>
+#include <linux/soundcard.h>
+
+static char *mixer_names[SOUND_MIXER_NRDEVICES] =
+	SOUND_DEVICE_LABELS;
+
+int
+main(int argc, char **argv) {
+	int val, from, to;
+	int i, fd;
+
+	fd = open("/dev/mixer", O_RDWR);
+	if(fd < 0) {
+		perror("/dev/mixer");
+		return 1;
+	}
+
+	for(i = 2; i < argc; i += 2) {
+		from = atoi(argv[i-1]);
+		to = atoi(argv[i]);
+
+		if(to == SOUND_MIXER_NONE)
+			fprintf(stderr, "%s: turning off mixer %s\n",
+				argv[0], mixer_names[to]);
+		else
+			fprintf(stderr, "%s: rerouting mixer %s to %s\n",
+				argv[0], mixer_names[from], mixer_names[to]);
+
+		val = from << 8 | to;
+
+		if(ioctl(fd, SOUND_MIXER_PRIVATE2, &val)) {
+			perror("AD1848 mixer reroute");
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
diff -u --recursive --new-file v2.1.93/linux/Documentation/sound/mwave linux/Documentation/sound/mwave
--- v2.1.93/linux/Documentation/sound/mwave	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/mwave	Wed Apr  8 15:34:23 1998
@@ -0,0 +1,192 @@
+	How to try and survive an IBM Mwave under Linux SB drivers
+
+
+* IBM refuse to provide documentation. If anyone can ever find out what
+  MWD50430.EXE actually does to load firmware then this comedy could go
+  away.
+
+* If you'd like to ask IBM why they don't release Mwave information.
+  phone IBM (425-556-8822) and ask them why they still haven't 
+  released any documentation.
+  [http://204.200.238.31/cgi-bin/link.pl?co=i&cl=/ts/ibm/contact.html]
+
+----------------------------------------------------------------------------
+
+OK, First thing - the IRQ problem IS a problem, whether the test is bypassed or
+not. And it is NOT a linux problem - it is an MWAVE problem that is fixed with
+the latest MWAVE patches. So, in other words, DON'T bypass the test for MWAVES!!
+
+My config is Win 95 on HDA1, swap on HDA2, RH 5 on HDA3.
+
+The steps, then:
+
+    Boot to Linux. 
+    Mount Win95 file system (assume mount mount = /dos95)
+    mkdir /dos95/linux
+    mkdir /dos95/linux/boot
+    mkdir /dos95/linux/boot/parms
+
+    Copy the kernel, any initrd image, and loadlin to /dos95/linux/boot
+
+    Reboot to win 95
+
+    Edit C:/msdos.sys and add/change the following:
+
+        Logo=0
+        BootGUI=0
+
+        [Note msdos.sys IS a text file but it needs to be 'unhidden' and make
+         read-writable before it can be eddited]
+
+    Edit Config .sys to have multiple config menus. I have one for win95, and
+    five for linux. Like this:
+------------
+[menu]
+menuitem=W95, Windows 95
+menuitem=LINTP, Linux - ThinkPad
+menuitem=LINTP3, Linux - ThinkPad Console
+menuitem=LINDOC, Linux - Docked
+menuitem=LINDOC3, Linux - Docked Console
+menuitem=LIN1, Linux - Single User Mode
+REM menudefault=W95,10
+
+[W95]
+
+[LINTP]
+
+[LINDOC]
+
+[LINTP3]
+
+[LINDOC3]
+
+[LIN1]
+
+[COMMON]
+FILES=30
+REM Please read README.TXT in C:\MWW subdirectory before changing the DOS= statement.
+DOS=HIGH,UMB
+DEVICE=C:\MWW\MANAGER\MWD50430.EXE
+SHELL=c:\command.com /e:2048
+-------------------
+
+The important things are the SHELL and DEVICE statements
+
+    Then change Autoexec.bat. Basically everything in there originally should be
+    done ONLY when Win95 is booted. Then you add new things specifically for
+    Linux.  Mine is as follows
+
+---------------
+@ECHO OFF
+if "%CONFIG%" == "W95" goto W95
+
+REM
+REM Linux stuff
+REM
+SET MWPATH=C:\MWW\DLL;C:\MWW\MWGAMES;C:\MWW\DSP
+SET BLASTER=A220 I5 D1
+SET MWROOT=C:\MWW
+SET LIBPATH=C:\MWW\DLL
+SET PATH=C:\WINDOWS;C:\MWW\DLL;
+CALL MWAVE START NOSHOW
+c:\linux\boot\loadlin.exe @c:\linux\boot\parms\%CONFIG%.par
+
+:W95
+REM
+REM Windows 95 stuff
+REM
+c:\toolkit\guard
+SET MSINPUT=C:\MSINPUT
+SET MWPATH=C:\MWW\DLL;C:\MWW\MWGAMES;C:\MWW\DSP
+REM The following is used by DOS games to recognize Sound Blaster hardware.
+REM If hardware settings are changed, please change this line as well.
+REM See the Mwave README file for instructions.
+SET BLASTER=A220 I5 D1
+SET MWROOT=C:\MWW
+SET LIBPATH=C:\MWW\DLL
+SET PATH=C:\WINDOWS;C:\WINDOWS\COMMAND;E:\ORAWIN95\BIN;f:\msdev\bin;e:\v30\bin.dbg;v:\devt\v30\bin;c:\JavaSDK\Bin;C:\MWW\DLL;
+SET INCLUDE=f:\MSDEV\INCLUDE;F:\MSDEV\MFC\INCLUDE
+SET LIB=F:\MSDEV\LIB;F:\MSDEV\MFC\LIB
+win
+
+------------------------
+
+Now build a file in c:\linux\boot\parms for each linux config that you have.
+
+For example, my LINDOC3 config is for a docked Thinkpad at runlevel 3 with no
+initrd image, and has a parm file named LINDOC3.PAR in c:\linux\boot\parms:
+
+-----------------------
+#   LOADLIN @param_file image=other_image root=/dev/other
+#
+#	Linux Console in docking station
+#
+c:\linux\boot\zImage.krn         # first value must be the filename of the Linux-kernel
+root=/dev/hda3                    # the device which gets mounted as root FS
+ro                                      # Other kernel agruments go here
+apm=off
+doc=yes
+3
+-----------------------
+
+the doc=yes parm is an environment variable that my init scripts use, it is not
+a kernel argument.
+
+However, the apm=off parm IS a kernel argument!!!!!!! APM, at least in my setup,
+causes the kernel to crash when loaded via loadlin (but NOT when loaded via
+LILO). The APM stuff COULD be forced out of the kernel via the kernel compile
+options. BUT I, instead, got hold of an unofficial patch to the APM drivers that
+allows them to be dynamically deactivated via kernel arguments. Whatever you
+chose to document, APM, it seems, MUST be off for setups like mine.
+
+Now check the C:\MWW\MWCONFIG.REF looks like this:
+
+----------------------
+[NativeDOS]
+Default=SB1.5
+SBInputSource=CD
+SYNTH=FM
+QSound=OFF
+Reverb=OFF
+Chorus=OFF
+ReverbDepth=5
+ChorusDepth=5
+SBInputVolume=5
+SBMainVolume=10
+SBWaveVolume=10
+SBSynthVolume=10
+WaveTableVolume=10
+AudioPowerDriver=ON
+
+[FastCFG]
+Show=No
+HideOption=Off
+-----------------------------
+
+OR the Default= line COULD be
+
+Default=SBPRO
+
+Reboot to Win95 and choose Linux. When booted, use sndconfig to configure the  
+sound modules and VOILA - ThinkPad sound with Linux.
+
+Now the gottchas - You can either have CD sound OR Mixers but not both. Thats a
+problem with the SB1.5(CD sound) or SBPRO(Mixers) settings. No-one knows why
+this is!
+
+And, for some reason MPEG3 files, when played through mpg123, sound like they
+are playing at 1/8th speed - not very useful!!!!!!!!!!!! If you have ANY insight
+on why this second thing might be happening I would be grateful.
+
+===========================================================
+    _/      _/_/_/_/
+   _/_/  _/_/     _/
+  _/ _/_/ _/_/_/_/      Martin John Bartlett
+ _/  _/  _/     _/      (martin@nitram.demon.co.uk)
+_/      _/_/_/_/
+       _/
+_/    _/
+ _/_/
+===========================================================
+
+
diff -u --recursive --new-file v2.1.93/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.93/linux/MAINTAINERS	Tue Mar 17 22:18:13 1998
+++ linux/MAINTAINERS	Wed Apr  8 17:31:27 1998
@@ -76,6 +76,12 @@
 L:	linux-net@vger.rutgers.edu
 S:	Maintained
 
+6PACK NETWORK DRIVER FOR AX.25
+P:	Andreas Koensgen
+M:	ajk@iehk.rwth-aachen.de
+L:	linux-hams@vger.rutgers.edu
+S:	Maintained
+
 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
 P:	Paul Gortmaker
 M	gpg109@rsphy1.anu.edu.au
@@ -157,7 +163,7 @@
 DAMA SLAVE for AX.25
 P:	Joerg Reuter
 M:	jreuter@poboxes.com
-W:	http://www.rat.de/jr/
+W:	http://poboxes.com/jreuter/
 W:	http://qsl.net/dl1bke/
 L:	linux-hams@vger.rutgers.edu
 S:	Maintained
@@ -313,6 +319,7 @@
 JOYSTICK DRIVER
 P:	Vojtech Pavlik
 M:	vojtech@atrey.karlin.mff.cuni.cz
+L:	linux-joystick@atrey.karlin.mff.cuni.cz
 S:	Maintained
 
 KERNEL AUTOMOUNTER (AUTOFS)
@@ -461,9 +468,9 @@
 PNP SUPPORT
 P:	Tom Lees
 M:	tom@lpsg.demon.co.uk
-L:	pnp-list@lpsg.demon.co.uk
-L:	pnp-list@redhat.com (maybe)
-W:	http://www.lpsg.demon.co.uk/pnp-linux.html
+L:	pnp-users@ferret.lmh.ox.ac.uk
+L:	pnp-devel@ferret.lmh.ox.ac.uk
+W:	http://www-jcr.lmh.ox.ac.uk/~pnp/
 S:	Maintained
 
 PPP PROTOCOL DRIVERS AND COMPRESSORS
@@ -516,7 +523,7 @@
 
 SOUND
 P:	Alan Cox 
-M:	Alan Cox@linux.org
+M:	Alan.Cox@linux.org
 S:	Maintained
 
 SPARC:
@@ -613,7 +620,7 @@
 Z8530 DRIVER FOR AX.25
 P:	Joerg Reuter
 M:	jreuter@poboxes.com
-W:	http://www.rat.de/jr/
+W:	http://poboxes.com/jreuter/
 W:	http://qsl.net/dl1bke/
 L:	linux-hams@vger.rutgers.edu
 S:	Maintained
diff -u --recursive --new-file v2.1.93/linux/Makefile linux/Makefile
--- v2.1.93/linux/Makefile	Mon Apr  6 17:40:59 1998
+++ linux/Makefile	Mon Apr  6 17:41:27 1998
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 93
+SUBLEVEL = 94
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
diff -u --recursive --new-file v2.1.93/linux/Rules.make linux/Rules.make
--- v2.1.93/linux/Rules.make	Tue Jan 13 11:47:55 1998
+++ linux/Rules.make	Wed Apr  8 15:36:26 1998
@@ -176,9 +176,21 @@
 MODINCL = $(TOPDIR)/include/linux/modules
 
 # The -w option (enable warnings) for genksyms will return here in 2.1
+# So where has it gone ???
+#
+# Added the SMP seperator to stop module accidents between uniproc/smp
+# intel boxes - AC - from bits by Michael Chastain
+#
+
+ifdef SMP
+	genksyms_smp_prefix := -p smp_
+else
+	genksyms_smp_prefix := 
+endif
+
 $(MODINCL)/%.ver: %.c
 	$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<\
-	| $(GENKSYMS) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp
+	| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp
 	mv $@.tmp $@
 	
 $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)): $(TOPDIR)/include/linux/autoconf.h
diff -u --recursive --new-file v2.1.93/linux/arch/alpha/boot/bootp.c linux/arch/alpha/boot/bootp.c
--- v2.1.93/linux/arch/alpha/boot/bootp.c	Wed Apr  1 20:11:47 1998
+++ linux/arch/alpha/boot/bootp.c	Tue Apr  7 07:52:04 1998
@@ -11,7 +11,6 @@
 #include <linux/string.h>
 #include <linux/version.h>
 #include <linux/mm.h>
-#include <linux/config.h>
 
 #include <asm/system.h>
 #include <asm/console.h>
diff -u --recursive --new-file v2.1.93/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.1.93/linux/arch/alpha/config.in	Wed Apr  1 20:11:47 1998
+++ linux/arch/alpha/config.in	Tue Apr  7 08:05:05 1998
@@ -12,7 +12,6 @@
 unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS
 unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
 unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION
-unset CONFIG_ALPHA_SRM CONFIG_ALPHA_SRM_SETUP
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.1.93/linux/arch/alpha/kernel/alpha_ksyms.c	Tue Mar 17 22:18:13 1998
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Tue Apr  7 08:05:05 1998
@@ -27,7 +27,6 @@
 #define __KERNEL_SYSCALLS__
 #include <asm/unistd.h>
 
-extern void bcopy (const char *src, char *dst, int len);
 extern struct hwrpb_struct *hwrpb;
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
@@ -134,7 +133,6 @@
  * interface isn't gonna change any time soon now, so it's OK
  * to leave it out of version control.
  */
-# undef bcopy
 # undef memcpy
 # undef memset
 EXPORT_SYMBOL_NOVERS(__divl);
@@ -147,7 +145,3 @@
 EXPORT_SYMBOL_NOVERS(__remqu);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
-
-#if CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v2.1.93/linux/arch/alpha/kernel/bios32.c	Mon Apr  6 17:40:59 1998
+++ linux/arch/alpha/kernel/bios32.c	Tue Apr  7 08:05:05 1998
@@ -560,15 +560,13 @@
 }
 
 
-unsigned long pcibios_init(unsigned long mem_start,
-			   unsigned long mem_end)
+void __init
+pcibios_init(void)
 {
 	printk("Alpha PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
-
 #if !PCI_MODIFY
 	printk("...NOT modifying existing (SRM) PCI configuration\n");
 #endif
-	return mem_start;
 }
 
 /*
@@ -1951,20 +1949,20 @@
 extern void tga_console_init(void);
 #endif /* CONFIG_TGA_CONSOLE */
 
-unsigned long __init
-pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
+void __init
+pcibios_fixup(void)
 {
 	  struct pci_bus *cur;
 
 #ifdef CONFIG_ALPHA_MCPCIA
 	/* must do massive setup for multiple PCI busses here... */
 	DBG_DEVS(("pcibios_fixup: calling mcpcia_fixup()...\n"));
-	mem_start = mcpcia_fixup(mem_start, mem_end);
+	mcpcia_fixup();
 #endif /* MCPCIA */
 
 #ifdef CONFIG_ALPHA_TSUNAMI
 	/* must do massive setup for multiple PCI busses here... */
-	/*	mem_start = tsunami_fixup(mem_start, mem_end); */
+	/* tsunami_fixup(); */
 #endif /* TSUNAMI */
 
 #if PCI_MODIFY && !defined(CONFIG_ALPHA_RUFFIAN)
@@ -2030,8 +2028,6 @@
 	tga_console_init();
 #endif
 #endif
-
-	return mem_start;
 }
 
 
diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v2.1.93/linux/arch/alpha/kernel/head.S	Wed Apr  1 20:11:47 1998
+++ linux/arch/alpha/kernel/head.S	Tue Apr  7 07:52:04 1998
@@ -8,7 +8,6 @@
  */
 
 #define __ASSEMBLY__
-#include <linux/config.h>
 #include <asm/system.h>
 
 #define halt call_pal PAL_halt
diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/mcpcia.c linux/arch/alpha/kernel/mcpcia.c
--- v2.1.93/linux/arch/alpha/kernel/mcpcia.c	Mon Apr  6 17:40:59 1998
+++ linux/arch/alpha/kernel/mcpcia.c	Tue Apr  7 08:05:05 1998
@@ -962,8 +962,7 @@
 	}
 }
 
-unsigned long mcpcia_fixup(unsigned long memory_start,
-			   unsigned long memory_end)
+void mcpcia_fixup(void)
 {
 	struct linux_hose_info *hose;
 
@@ -974,7 +973,5 @@
 	for (hose = mcpcia_root; hose; hose = hose->next) {
 		mcpcia_probe(hose, &memory_start);
 	}
-
-	return memory_start;
 }
 #endif /* CONFIG_ALPHA_MCPCIA */
diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.1.93/linux/arch/alpha/kernel/setup.c	Wed Apr  1 20:11:47 1998
+++ linux/arch/alpha/kernel/setup.c	Tue Apr  7 08:05:05 1998
@@ -395,7 +395,7 @@
 		       "BogoMIPS\t\t: %lu.%02lu\n"
 		       "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
 		       "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
-		       "platform string\t: %s\n"
+		       "platform string\t\t: %s\n"
 #ifdef __SMP__
 		       "%s"
 #endif
diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/smc37c669.c linux/arch/alpha/kernel/smc37c669.c
--- v2.1.93/linux/arch/alpha/kernel/smc37c669.c	Mon Apr  6 17:40:59 1998
+++ linux/arch/alpha/kernel/smc37c669.c	Tue Apr  7 08:05:05 1998
@@ -994,7 +994,7 @@
 ** and standard ISA IRQs.
 **
 */
-static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata; 
+static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata = 0; 
 
 /*
 ** The following definition is for the default IRQ 
@@ -1020,7 +1020,7 @@
 ** ISA DMA channels.
 **
 */
-static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata; 
+static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata = 0;
 
 /*
 ** The following definition is the default DRQ
diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.1.93/linux/arch/alpha/kernel/smp.c	Wed Apr  1 20:11:47 1998
+++ linux/arch/alpha/kernel/smp.c	Tue Apr  7 07:52:04 1998
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
diff -u --recursive --new-file v2.1.93/linux/arch/alpha/lib/memcpy.c linux/arch/alpha/lib/memcpy.c
--- v2.1.93/linux/arch/alpha/lib/memcpy.c	Sun Oct  6 22:55:45 1996
+++ linux/arch/alpha/lib/memcpy.c	Tue Apr  7 08:05:05 1998
@@ -104,7 +104,7 @@
 	DO_REST_ALIGNED(d,s,n);
 }
 
-void * __memcpy(void * dest, const void *src, size_t n)
+void * memcpy(void * dest, const void *src, size_t n)
 {
 	if (!(((unsigned long) dest ^ (unsigned long) src) & 7)) {
 		__memcpy_aligned((unsigned long) dest, (unsigned long) src, n);
@@ -114,22 +114,5 @@
 	return dest;
 }
 
-/*
- * Broken compiler uses "bcopy" to do internal
- * assignments. Silly OSF/1 BSDism.
- */
-char * bcopy(const char * src, char * dest, size_t n)
-{
-	__memcpy(dest, src, n);
-	return dest;
-}
-
-/*
- * gcc-2.7.1 and newer generate calls to memset and memcpy.  So we
- * need to define that here:
- */
-#ifdef __ELF__
- asm (".weak memcpy; memcpy = __memcpy");
-#else
- asm (".weakext memcpy, __memcpy");
-#endif
+/* For backward modules compatibility, define __memcpy.  */
+asm("__memcpy = memcpy; .globl __memcpy");
diff -u --recursive --new-file v2.1.93/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.1.93/linux/arch/arm/config.in	Wed Apr  1 20:11:47 1998
+++ linux/arch/arm/config.in	Wed Apr  8 15:42:59 1998
@@ -105,6 +105,17 @@
 # fi
 # endmenu
 
+# Conditionally compile in the Uniform CD-ROM driver
+if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" ]; then
+  define_bool CONFIG_CDROM y
+else
+  if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" ]; then
+    define_bool CONFIG_CDROM m
+  else
+    define_bool CONFIG_CDROM n
+  fi
+fi
+
 source fs/Config.in
 
 source fs/nls/Config.in
diff -u --recursive --new-file v2.1.93/linux/arch/arm/defconfig linux/arch/arm/defconfig
--- v2.1.93/linux/arch/arm/defconfig	Wed Apr  1 20:11:47 1998
+++ linux/arch/arm/defconfig	Wed Apr  8 15:42:59 1998
@@ -169,6 +169,7 @@
 CONFIG_ETHER1=m
 CONFIG_ETHER3=m
 CONFIG_ETHERH=m
+CONFIG_CDROM=y
 
 #
 # Filesystems
diff -u --recursive --new-file v2.1.93/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c
--- v2.1.93/linux/arch/arm/kernel/armksyms.c	Tue Mar 17 22:18:13 1998
+++ linux/arch/arm/kernel/armksyms.c	Wed Apr  8 15:42:59 1998
@@ -12,6 +12,7 @@
 #include <asm/dma.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
+#include <asm/irq.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(struct pt_regs *, struct user_fp_struct *);
@@ -76,6 +77,10 @@
 
 /* processor dependencies */
 EXPORT_SYMBOL(processor);
+
+/* irq */
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
 
 /* io */
 EXPORT_SYMBOL(outswb);
diff -u --recursive --new-file v2.1.93/linux/arch/arm/kernel/calls.S linux/arch/arm/kernel/calls.S
--- v2.1.93/linux/arch/arm/kernel/calls.S	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/calls.S	Wed Apr  8 15:42:59 1998
@@ -5,7 +5,7 @@
  */
 #ifndef NR_SYSCALLS
 #define NR_syscalls 256
-#define NR_SYSCALLS 182
+#define NR_SYSCALLS 184
 #else
 
 /* 0 */		.long	SYMBOL_NAME(sys_setup)
@@ -190,5 +190,7 @@
 		.long	SYMBOL_NAME(sys_rt_sigsuspend_wrapper)
 /* 180 */	.long	SYMBOL_NAME(sys_pread)
 		.long	SYMBOL_NAME(sys_pwrite)
-		.space	(NR_syscalls - 182) * 4
+		.long	SYMBOL_NAME(sys_xstat)
+		.long	SYMBOL_NAME(sys_xmknod)
+		.space	(NR_syscalls - 184) * 4
 #endif
diff -u --recursive --new-file v2.1.93/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c
--- v2.1.93/linux/arch/arm/kernel/irq.c	Mon Feb 23 18:12:01 1998
+++ linux/arch/arm/kernel/irq.c	Wed Apr  8 15:42:59 1998
@@ -98,7 +98,7 @@
 		if (!action)
 			continue;
 		p += sprintf(p, "%3d: %10u   %s",
-			     i, kstat.interrupts[i], action->name);
+			     i, kstat.irqs[0][i], action->name);
 		for (action = action->next; action; action = action->next) {
 			p += sprintf(p, ", %s", action->name);
 		}
@@ -126,7 +126,7 @@
 
 	cpu = smp_processor_id();
 	irq_enter(cpu, irq);
-	kstat.interrupts[irq]++;
+	kstat.irqs[0][irq]++;
 
 	/* Return with this interrupt masked if no action */
 	status = 0;
diff -u --recursive --new-file v2.1.93/linux/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c
--- v2.1.93/linux/arch/arm/mm/fault-armo.c	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/fault-armo.c	Wed Apr  8 15:42:59 1998
@@ -27,6 +27,50 @@
 #define FAULT_CODE_WRITE	0x02
 #define FAULT_CODE_USER		0x01
 
+struct pgtable_cache_struct quicklists;
+
+void __bad_pte(pmd_t *pmd)
+{
+	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+	set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
+}
+
+pgd_t *get_pgd_slow(void)
+{
+	pgd_t *pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
+	pgd_t *init;
+	
+	if (pgd) {
+		init = pgd_offset(&init_mm, 0);
+		memzero (pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+		memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
+	}
+	return pgd;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
+	if (pmd_none(*pmd)) {
+		if (pte) {
+			memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			set_pmd(pmd, mk_pmd(pte));
+			return pte + offset;
+		}
+		set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
+		return NULL;
+	}
+	kfree (pte);
+	if (pmd_bad(*pmd)) {
+		__bad_pte(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + offset;
+}
+
 extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
 
 static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
diff -u --recursive --new-file v2.1.93/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- v2.1.93/linux/arch/arm/mm/fault-armv.c	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/fault-armv.c	Wed Apr  8 15:42:59 1998
@@ -25,6 +25,81 @@
 #define FAULT_CODE_READ		0x02
 #define FAULT_CODE_USER		0x01
 
+struct pgtable_cache_struct quicklists;
+
+void __bad_pte(pmd_t *pmd)
+{
+	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+	set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
+}
+
+void __bad_pte_kernel(pmd_t *pmd)
+{
+	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+	set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
+}
+
+pgd_t *get_pgd_slow(void)
+{
+	/*
+	 * need to get a 16k page for level 1
+	 */
+	pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,2);
+	pgd_t *init;
+	
+	if (pgd) {
+		init = pgd_offset(&init_mm, 0);
+		memzero ((void *)pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+		memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
+	}
+	return pgd;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) get_small_page(GFP_KERNEL);
+	if (pmd_none(*pmd)) {
+		if (pte) {
+			memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			set_pmd(pmd, mk_user_pmd(pte));
+			return pte + offset;
+		}
+		set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
+		return NULL;
+	}
+	free_small_page ((unsigned long) pte);
+	if (pmd_bad(*pmd)) {
+		__bad_pte(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) get_small_page(GFP_KERNEL);
+	if (pmd_none(*pmd)) {
+		if (pte) {
+			memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			set_pmd(pmd, mk_kernel_pmd(pte));
+			return pte + offset;
+		}
+		set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
+		return NULL;
+	}
+	free_small_page ((unsigned long) pte);
+	if (pmd_bad(*pmd)) {
+		__bad_pte_kernel(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + offset;
+}
+
 extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
 
 static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
diff -u --recursive --new-file v2.1.93/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.1.93/linux/arch/arm/mm/init.c	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/init.c	Wed Apr  8 15:42:59 1998
@@ -30,7 +30,6 @@
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
-const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
 extern char _etext, _stext, _edata, __bss_start, _end;
 extern char __init_begin, __init_end;
 
diff -u --recursive --new-file v2.1.93/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- v2.1.93/linux/arch/i386/Makefile	Wed Apr  1 20:11:47 1998
+++ linux/arch/i386/Makefile	Wed Apr  8 18:05:55 1998
@@ -58,9 +58,6 @@
 DRIVERS := $(DRIVERS) arch/i386/math-emu/math.a
 endif
 
-memsize: dummy
-	@echo "__kernel_offset__ = (0x1000-$(CONFIG_MAX_MEMSIZE))*1024*1024;" > arch/i386/.kernel_offset.lds
-
 arch/i386/kernel: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=arch/i386/kernel
 
@@ -69,31 +66,30 @@
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
-zImage: memsize vmlinux
+zImage: vmlinux
 	@$(MAKEBOOT) zImage
 
-bzImage: memsize vmlinux
+bzImage: vmlinux
 	@$(MAKEBOOT) bzImage
 
 compressed: zImage
 
-zlilo: memsize vmlinux
+zlilo: vmlinux
 	@$(MAKEBOOT) BOOTIMAGE=zImage zlilo
 
-bzlilo: memsize vmlinux
+bzlilo: vmlinux
 	@$(MAKEBOOT) BOOTIMAGE=bzImage zlilo
 
-zdisk: memsize vmlinux
+zdisk: vmlinux
 	@$(MAKEBOOT) BOOTIMAGE=zImage zdisk
 
-bzdisk: memsize vmlinux
+bzdisk: vmlinux
 	@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk
 
-install: memsize vmlinux
+install: vmlinux
 	@$(MAKEBOOT) BOOTIMAGE=bzImage install
 
 archclean:
-	rm -f .kernel_offset.lds
 	@$(MAKEBOOT) clean
 
 archdep:
diff -u --recursive --new-file v2.1.93/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.1.93/linux/arch/i386/config.in	Wed Apr  1 20:11:47 1998
+++ linux/arch/i386/config.in	Wed Apr  8 16:05:45 1998
@@ -17,7 +17,6 @@
 	 Pentium/K5/5x86/6x86	CONFIG_M586	\
 	 PPro/K6/6x86MX		CONFIG_M686" Pentium
 bool 'Math emulation' CONFIG_MATH_EMULATION
-int ' Max physical memory in MB' CONFIG_MAX_MEMSIZE 1024
 endmenu
 
 mainmenu_option next_comment
diff -u --recursive --new-file v2.1.93/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- v2.1.93/linux/arch/i386/kernel/bios32.c	Mon Apr  6 17:40:59 1998
+++ linux/arch/i386/kernel/bios32.c	Tue Apr  7 07:37:46 1998
@@ -125,42 +125,7 @@
 int pcibios_read_config_byte (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned char *value)
 {
-	int res;
-
-	res = access_pci->read_config_byte(bus, device_fn, where, value);
-
-#ifdef __SMP__
-/*
- * IOAPICs can take PCI IRQs directly, lets first check the mptable:
- *
- * This can go away once nobody probes the irq this way,
- * but uses the PCI tables instead.
- */
-	if (where == PCI_INTERRUPT_LINE) {
-		int irq;
-		char pin;
-
-		/*
-		 * get the PCI IRQ INT _physical pin_ for this device
-		 */
-		access_pci->read_config_byte(bus, device_fn,
-						PCI_INTERRUPT_PIN, &pin);
-		/*
-		 * subtle, PCI pins are numbered starting from 1 ...
-		 */
-		pin--;
-
-		irq = IO_APIC_get_PCI_irq_vector (bus,PCI_SLOT(device_fn),pin);
-		if (irq != -1)
-			*value = (unsigned char) irq;
-
-		printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
-			bus,PCI_SLOT(device_fn), pin, irq);
-
-	}
-#endif
-
-	return res;
+	return access_pci->read_config_byte(bus, device_fn, where, value);
 }
 
 int pcibios_read_config_word (unsigned char bus,
diff -u --recursive --new-file v2.1.93/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.1.93/linux/arch/i386/kernel/head.S	Wed Apr  1 20:11:47 1998
+++ linux/arch/i386/kernel/head.S	Wed Apr  8 16:07:16 1998
@@ -619,9 +619,6 @@
 	.fill 256,8,0		# idt is uninitialized
 
 /*
- * This gdt setup gives the kernel a CONFIG_MAX_MEMSIZE sized address space at
- * virtual address PAGE_OFFSET.
- *
  * This contains up to 8192 quadwords depending on NR_TASKS - 64kB of
  * gdt entries.  Ugh. 
  *
diff -u --recursive --new-file v2.1.93/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.1.93/linux/arch/i386/kernel/irq.c	Thu Mar 26 15:57:02 1998
+++ linux/arch/i386/kernel/irq.c	Tue Apr  7 07:48:54 1998
@@ -70,7 +70,9 @@
 
 static unsigned int irq_events [NR_IRQS] = { -1, };
 static int disabled_irq [NR_IRQS] = { 0, };
+#ifdef __SMP__
 static int ipi_pending [NR_IRQS] = { 0, };
+#endif
 
 /*
  * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
diff -u --recursive --new-file v2.1.93/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c
--- v2.1.93/linux/arch/i386/kernel/mca.c	Fri Jan 30 11:28:06 1998
+++ linux/arch/i386/kernel/mca.c	Wed Apr  8 18:12:32 1998
@@ -62,7 +62,7 @@
 /*--------------------------------------------------------------------*/
 
 #ifdef CONFIG_PROC_FS
-static long mca_do_proc_init( long memory_start, long memory_end );
+static void mca_do_proc_init( void );
 static int mca_default_procfn( char* buf, int slot );
 
 static ssize_t proc_mca_read( struct file*, char*, size_t, loff_t *);
@@ -79,7 +79,7 @@
 
 /*--------------------------------------------------------------------*/
 
-__initfunc(long mca_init(long memory_start, long memory_end))
+__initfunc(void mca_init(void))
 {
 	unsigned int  i, j;
 	int foundscsi = 0;
@@ -96,21 +96,14 @@
 	 */
 	
 	if (!MCA_bus)
-		return memory_start;
+		return;
 	cli();
 
 	/*
 	 *	Allocate MCA_info structure (at address divisible by 8)
 	 */ 
 
-	if( ((memory_start+7)&(~7)) > memory_end ) 
-	{
-	  	/* uh oh */
-	  	return memory_start;
-	}
-
-	mca_info = (struct MCA_info*) ((memory_start+7)&(~7));
-	memory_start = ((long)mca_info) + sizeof(struct MCA_info);
+	mca_info = kmalloc(sizeof(struct MCA_info), GFP_ATOMIC);
 
 	/*
 	 *	Make sure adapter setup is off
@@ -194,10 +187,8 @@
 	request_region(0x100,0x08,"POS (MCA)");
 
 #ifdef CONFIG_PROC_FS
-	memory_start = mca_do_proc_init( memory_start, memory_end );
+	mca_do_proc_init();
 #endif
-
-	return memory_start;
 }
 
 /*--------------------------------------------------------------------*/
@@ -418,12 +409,12 @@
 
 
 /*--------------------------------------------------------------------*/
-__initfunc(long mca_do_proc_init( long memory_start, long memory_end ))
+__initfunc(void mca_do_proc_init( void ))
 {
 	int i = 0;
 	struct proc_dir_entry* node = 0;
 
-	if( mca_info == 0 ) return memory_start;	/* never happens */
+	if( mca_info == 0 ) return;	/* never happens */
 
 	proc_register( &proc_mca, &(struct proc_dir_entry) {
 		PROC_MCA_REGISTERS, 3, "pos", S_IFREG|S_IRUGO,
@@ -439,11 +430,7 @@
 		mca_info->slot[i].dev = 0;
 
 		if( ! mca_isadapter( i ) ) continue;
-		if( memory_start + sizeof(struct proc_dir_entry) > memory_end ) {
-			continue;
-		}
-		node = (struct proc_dir_entry*) memory_start;
-		memory_start += sizeof(struct proc_dir_entry);
+		node = kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC);
 
 		if( i < MCA_MAX_SLOT_NR ) {
 			node->low_ino = PROC_MCA_SLOT + i;
@@ -464,7 +451,6 @@
 		proc_register( &proc_mca, node );
 	}
 
-	return memory_start;
 } /* mca_do_proc_init() */
 
 /*--------------------------------------------------------------------*/
diff -u --recursive --new-file v2.1.93/linux/arch/i386/math-emu/poly.h linux/arch/i386/math-emu/poly.h
--- v2.1.93/linux/arch/i386/math-emu/poly.h	Sun Jul 31 22:19:14 1994
+++ linux/arch/i386/math-emu/poly.h	Tue Apr  7 07:48:54 1998
@@ -83,7 +83,7 @@
 /* Note: the constraints in the asm statement didn't always work properly
    with gcc 2.5.8.  Changing from using edi to using ecx got around the
    problem, but keep fingers crossed! */
-extern inline int add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
+extern inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
 {
   asm volatile ("movl %2,%%ecx; movl %3,%%esi;
                  movl (%%esi),%%eax; addl %%eax,(%%ecx);
diff -u --recursive --new-file v2.1.93/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.1.93/linux/arch/i386/mm/init.c	Mon Apr  6 17:40:59 1998
+++ linux/arch/i386/mm/init.c	Wed Apr  8 11:35:15 1998
@@ -293,8 +293,6 @@
 	}
 
 	local_flush_tlb();
-	printk("IO APIC ID: %d\n", *(int *)0xFEC00000);
-	printk("APIC ID: %d\n", *(int *)0xFEE00000);
 }
 #endif
 	local_flush_tlb();
diff -u --recursive --new-file v2.1.93/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- v2.1.93/linux/arch/i386/vmlinux.lds	Tue Mar 17 22:18:14 1998
+++ linux/arch/i386/vmlinux.lds	Wed Apr  8 18:01:53 1998
@@ -1,13 +1,12 @@
 /* ld script to make i386 Linux kernel
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
-INCLUDE arch/i386/.kernel_offset.lds
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
 ENTRY(_start)
 SECTIONS
 {
-  . = __kernel_offset__ + 0x100000;
+  . = 0xC0000000 + 0x100000;
   _text = .;			/* Text and read-only data */
   .text : {
 	*(.text)
diff -u --recursive --new-file v2.1.93/linux/arch/m68k/amiga/amiga_ksyms.c linux/arch/m68k/amiga/amiga_ksyms.c
--- v2.1.93/linux/arch/m68k/amiga/amiga_ksyms.c	Thu Mar 26 15:57:02 1998
+++ linux/arch/m68k/amiga/amiga_ksyms.c	Tue Apr  7 07:52:04 1998
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/zorro.h>
diff -u --recursive --new-file v2.1.93/linux/arch/m68k/atari/atari_ksyms.c linux/arch/m68k/atari/atari_ksyms.c
--- v2.1.93/linux/arch/m68k/atari/atari_ksyms.c	Thu Mar 26 15:57:02 1998
+++ linux/arch/m68k/atari/atari_ksyms.c	Tue Apr  7 07:52:04 1998
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <asm/ptrace.h>
diff -u --recursive --new-file v2.1.93/linux/arch/m68k/mac/ksyms.c linux/arch/m68k/mac/ksyms.c
--- v2.1.93/linux/arch/m68k/mac/ksyms.c	Thu Mar 26 15:57:02 1998
+++ linux/arch/m68k/mac/ksyms.c	Tue Apr  7 07:52:04 1998
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/module.h>
 #include <asm/ptrace.h>
 #include <asm/traps.h>
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/block/Config.in linux/drivers/acorn/block/Config.in
--- v2.1.93/linux/drivers/acorn/block/Config.in	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/block/Config.in	Wed Apr  8 15:51:32 1998
@@ -16,6 +16,4 @@
   bool '   Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT
 fi
 
-bool 'ADFS partition support' CONFIG_BLK_DEV_PART
-
 endmenu
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c
--- v2.1.93/linux/drivers/acorn/block/mfmhd.c	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/block/mfmhd.c	Wed Apr  8 15:51:32 1998
@@ -85,6 +85,8 @@
  *		card slots if someone tries this)!
  *
  * 17/1/97:RMK:	Upgraded to 2.1 kernels.
+ *
+ *  4/3/98:RMK:	Changed major number to 21.
  */
 
 /*
@@ -108,6 +110,9 @@
 #include <linux/major.h>
 #include <linux/ioport.h>
 
+#define MAJOR_NR	MFM_ACORN_MAJOR
+#include <linux/blk.h>
+
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq-no.h>
@@ -117,12 +122,6 @@
 #include <asm/hardware.h>
 #include <asm/ecard.h>
 
-#define MFM_DISK_MAJOR	13
-#undef  XT_DISK_MAJOR
-#define XT_DISK_MAJOR	-1
-#define MAJOR_NR	MFM_DISK_MAJOR
-#include "blk.h"
-
 /*
  * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc
  */
@@ -231,9 +230,6 @@
 static void mfm_specify (void);
 static void issue_request(int dev, unsigned int block, unsigned int nsect,
 			  struct request *req);
-
-#define mfm_init xd_init
-#define mfm_setup xd_setup
 
 static unsigned int mfm_addr;		/* Controller address */
 static unsigned int mfm_IRQPollLoc;	/* Address to read for IRQ information */
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c
--- v2.1.93/linux/drivers/acorn/net/ether1.c	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/net/ether1.c	Wed Apr  8 15:51:32 1998
@@ -41,16 +41,16 @@
 #include <linux/in.h>
 #include <linux/malloc.h>
 #include <linux/string.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
 #include <linux/errno.h>
-
+#include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
 #include <asm/ecard.h>
 
 #define __ETHER1_C
@@ -58,9 +58,6 @@
 
 static unsigned int net_debug = NET_DEBUG;
 
-#define 	struct ether1_priv *priv = (struct ether1_priv *)dev->priv \
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv
-
 #define BUFFER_SIZE	0x10000
 #define TX_AREA_START	0x00100
 #define TX_AREA_END	0x05000
@@ -87,7 +84,8 @@
 #define ether1_inw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
 #define ether1_outw(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
 
-static inline unsigned short ether1_inw_p (struct device *dev, int addr, int svflgs)
+static inline unsigned short
+ether1_inw_p (struct device *dev, int addr, int svflgs)
 {
 	unsigned long flags;
 	unsigned short ret;
@@ -102,7 +100,8 @@
 	return ret;
 }
 
-static inline void ether1_outw_p (struct device *dev, unsigned short val, int addr, int svflgs)
+static inline void
+ether1_outw_p (struct device *dev, unsigned short val, int addr, int svflgs)
 {
 	unsigned long flags;
 
@@ -124,8 +123,8 @@
  * This routine is essentially an optimised memcpy from the card's
  * onboard RAM to kernel memory.
  */
- 
-static inline void *ether1_inswb (unsigned int addr, void *data, unsigned int len)
+static inline void *
+ether1_inswb (unsigned int addr, void *data, unsigned int len)
 {
 	int used;
 
@@ -161,13 +160,14 @@
 2:		adds	%3, %3, #1
 		ldreqb	%0, [%1]
 		streqb	%0, [%2]"
-		: "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len)
-		:                "1"  (addr), "2"   (data), "3"   (len));
+	: "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len)
+	:                "1"  (addr), "2"   (data), "3"   (len));
 
 	return data;
 }
 
-static inline void *ether1_outswb (unsigned int addr, void *data, unsigned int len)
+static inline void *
+ether1_outswb (unsigned int addr, void *data, unsigned int len)
 {
 	int used;
 
@@ -203,28 +203,26 @@
 2:		adds	%3, %3, #1
 		ldreqb	%0, [%2]
 		streqb	%0, [%1]"
-		: "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len)
-		:                "1"  (addr), "2"   (data), "3"   (len));
+	: "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len)
+	:                "1"  (addr), "2"   (data), "3"   (len));
 
 	return data;
 }
 
 
-static void ether1_writebuffer (struct device *dev, void *data, unsigned int start, unsigned int length)
+static void
+ether1_writebuffer (struct device *dev, void *data, unsigned int start, unsigned int length)
 {
 	unsigned int page, thislen, offset;
+
 	offset = start & 4095;
 
-	for (page = start >> 12; length; page++) 
-	{
+	for (page = start >> 12; length; page++) {
 		outb (page, REG_PAGE);
-		if (offset + length > 4096) 
-		{
-		    length -= 4096 - offset;
-		    thislen = 4096 - offset;
-		}
-		else
-		{
+		if (offset + length > 4096) {
+			length -= 4096 - offset;
+			thislen = 4096 - offset;
+		} else {
 			thislen = length;
 			length = 0;
 		}
@@ -234,23 +232,20 @@
 	}
 }
 
-static void ether1_readbuffer (struct device *dev, void *data, unsigned int start, unsigned int length)
+static void
+ether1_readbuffer (struct device *dev, void *data, unsigned int start, unsigned int length)
 {
 	unsigned int page, thislen, offset;
 
 	offset = start & 4095;
 
-	for (page = start >> 12; length; page++) 
-	{
+	for (page = start >> 12; length; page++) {
 		outb (page, REG_PAGE);
-		if (offset + length > 4096) 
-		{
+		if (offset + length > 4096) {
 			length -= 4096 - offset;
 			thislen = 4096 - offset;
-		}
-		else
-		{
-	 		thislen = length;
+		} else {
+			thislen = length;
 			length = 0;
 		}
 
@@ -259,7 +254,8 @@
 	}
 }
 
-static int ether1_ramtest (struct device *dev, unsigned char byte)
+__initfunc(static int
+ether1_ramtest (struct device *dev, unsigned char byte))
 {
 	unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
 	int i, ret = BUFFER_SIZE;
@@ -275,12 +271,9 @@
 	memset (buffer, byte ^ 0xff, BUFFER_SIZE);
 	ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE);
 
-	for (i = 0; i < BUFFER_SIZE; i++) 
-	{
-		if (buffer[i] != byte) 
-		{
-			if (max_errors >= 0 && bad != buffer[i]) 
-			{
+	for (i = 0; i < BUFFER_SIZE; i++) {
+		if (buffer[i] != byte) {
+			if (max_errors >= 0 && bad != buffer[i]) {
 				if (bad != -1)
 					printk ("\n");
 				printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X",
@@ -290,12 +283,9 @@
 				bad = buffer[i];
 				bad_start = i;
 			}
-		}
-		else
-		{
-			if (bad != -1) 
-			{
-				if (bad_start == i - 1)
+		} else {
+			if (bad != -1) {
+			    	if (bad_start == i - 1)
 					printk ("\n");
 				else
 					printk (" - 0x%04X\n", i - 1);
@@ -311,13 +301,15 @@
 	return ret;
 }
 
-static int ether1_reset (struct device *dev)
+static int
+ether1_reset (struct device *dev)
 {
 	outb (CTRL_RST|CTRL_ACK, REG_CONTROL);
 	return BUS_16;
 }
 
-static int ether1_init_2 (struct device *dev)
+__initfunc(static int
+ether1_init_2 (struct device *dev))
 {
 	int i;
 	dev->mem_start = 0;
@@ -328,7 +320,7 @@
 		i = ether1_ramtest (dev, 0x1e);
 
 	if (i <= 0)
-    		return -ENODEV;
+	    	return -ENODEV;
 
 	dev->mem_end = i;
 	return 0;
@@ -340,12 +332,9 @@
  */
 
 /* at 0x0100 */
-
 #define NOP_ADDR	(TX_AREA_START)
 #define NOP_SIZE	(0x06)
-
-static nop_t  init_nop  = 
-{
+static nop_t  init_nop  = {
 	0,
 	CMD_NOP,
 	NOP_ADDR
@@ -364,8 +353,7 @@
 /* at 0x002e */
 #define MC_ADDR		(0x002e)
 #define MC_SIZE		(0x0c)
-static mc_t   init_mc   = 
-{
+static mc_t   init_mc   = {
 	0,
 	CMD_SETMULTICAST,
 	TDR_ADDR,
@@ -447,7 +435,7 @@
 };
 
 #define RBD_SIZE	(0x0a)
-static rbd_t  init_rbd	= {	
+static rbd_t  init_rbd	= {
 	0,
 	0,
 	0,
@@ -458,7 +446,8 @@
 #define TX_SIZE		(0x08)
 #define TBD_SIZE	(0x08)
 
-static int ether1_init_for_open (struct device *dev)
+static int
+ether1_init_for_open (struct device *dev)
 {
 	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 	int i, status, addr, next, next2;
@@ -479,8 +468,7 @@
 	ether1_writebuffer (dev, &init_tdr,  TDR_ADDR,  TDR_SIZE);
 	ether1_writebuffer (dev, &init_nop,  NOP_ADDR,  NOP_SIZE);
 
-	if (ether1_inw (dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) 
-	{
+	if (ether1_inw (dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) {
 		printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n",
 			dev->name);
 		return 1;
@@ -492,21 +480,16 @@
 	 * First rfd is linked to scp, first rbd is linked to first
 	 * rfd.  Last rbd has a suspend command.
 	 */
-	
 	addr = RX_AREA_START;
-
-	do 
-	{
+	do {
 		next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
 		next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
 
-		if (next2 >= RX_AREA_END) 
-		{
+		if (next2 >= RX_AREA_END) {
 			next = RX_AREA_START;
 			init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
 			priv->rx_tail = addr;
-		}
-		else
+		} else
 			init_rfd.rfd_command = 0;
 		if (addr == RX_AREA_START)
 			init_rfd.rfd_rbdoffset = addr + RFD_SIZE;
@@ -519,8 +502,7 @@
 		ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE);
 		ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE);
 		addr = next;
-	}
-	while (next2 < RX_AREA_END);
+	} while (next2 < RX_AREA_END);
 
 	priv->tx_link = NOP_ADDR;
 	priv->tx_head = NOP_ADDR + NOP_SIZE;
@@ -536,10 +518,8 @@
 
 	/* 586 should now unset iscp.busy */
 	i = jiffies + HZ/2;
-	while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) 
-	{
-		if (jiffies > i) 
-		{
+	while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
+		if (jiffies > i) {
 			printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
 			return 1;
 		}
@@ -547,32 +527,30 @@
 
 	/* check status of commands that we issued */
 	i += HZ/10;
-	while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) 
-	{
-		if (jiffies-i<0)
+	while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
+			& STAT_COMPLETE) == 0) {
+		if (jiffies > i)
 			break;
 	}
 
-	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) 
-	{
+	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
 		printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status);
 		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-		ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-		ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-		ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-		ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
 		failures += 1;
 	}
 
 	i += HZ/10;
-	while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) 
-	{
-		if (jiffies-i<0)
+	while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
+			& STAT_COMPLETE) == 0) {
+		if (jiffies > i)
 			break;
 	}
 
-	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) 
-	{
+	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
 		printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status);
 		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
 			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
@@ -583,14 +561,13 @@
 	}
 
 	i += HZ/10;
-	while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) 
-	{
-		if (jiffies-i < 0)
+	while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
+			& STAT_COMPLETE) == 0) {
+		if (jiffies > i)
 			break;
 	}
 
-	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) 
-	{
+	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
 		printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
 		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
 			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
@@ -601,33 +578,29 @@
 	}
 
 	i += HZ;
-	while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) 
-	{
-		if (jiffies-i <0)
+	while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
+			& STAT_COMPLETE) == 0) {
+		if (jiffies > i)
 			break;
 	}
 
-	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) 
-	{
+	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
 		printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);
 		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
 			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
 			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
 			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
 			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
-	}
-	else 
-	{
+	} else {
 		status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
 		if (status & TDR_XCVRPROB)
 			printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);
-		else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) 
-		{
+		else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) {
 #ifdef FANCY
 			printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,
 				status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,
 				(status & TDR_TIME) % 10);
-#else	
+#else
 			printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,
 				status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));
 #endif
@@ -639,7 +612,8 @@
 	return failures ? 1 : 0;
 }
 
-static int ether1_probe1 (struct device *dev)
+__initfunc(static int
+ether1_probe1 (struct device *dev))
 {
 	static unsigned int version_printed = 0;
 	struct ether1_priv *priv;
@@ -649,13 +623,12 @@
 		dev->priv = kmalloc (sizeof (struct ether1_priv), GFP_KERNEL);
 
 	if (!dev->priv)
-    		return 1;
+	    	return 1;
 
 	priv = (struct ether1_priv *)dev->priv;
 	memset (priv, 0, sizeof (struct ether1_priv));
 
-	if ((priv->bus_type = ether1_reset (dev)) == 0) 
-	{
+	if ((priv->bus_type = ether1_reset (dev)) == 0) {
 		kfree (dev->priv);
 		return 1;
 	}
@@ -672,15 +645,14 @@
 	for (i = 0; i < 6; i++)
 		printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]);
 
-	if (ether1_init_2 (dev)) 
-	{
+	if (ether1_init_2 (dev)) {
 		kfree (dev->priv);
 		return 1;
 	}
 
-	dev->open	    = ether1_open;
-	dev->stop	    = ether1_close;
-	dev->hard_start_xmit= ether1_sendpacket;
+	dev->open		    = ether1_open;
+	dev->stop		    = ether1_close;
+	dev->hard_start_xmit    = ether1_sendpacket;
 	dev->get_stats	    = ether1_getstats;
 	dev->set_multicast_list = ether1_setmulticastlist;
 
@@ -688,8 +660,7 @@
 	ether_setup (dev);
 
 #ifndef CLAIM_IRQ_AT_OPEN
-	if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) 
-	{
+	if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) {
 		kfree (dev->priv);
 		return -EAGAIN;
 	}
@@ -699,7 +670,8 @@
     
 /* ------------------------------------------------------------------------- */
 
-static void ether1_addr (struct device *dev)
+__initfunc(static void
+ether1_addr (struct device *dev))
 {
 	int i;
     
@@ -707,7 +679,8 @@
 		dev->dev_addr[i] = inb (IDPROM_ADDRESS + i);
 }
 
-int ether1_probe (struct device *dev)
+__initfunc(int
+ether1_probe (struct device *dev))
 {
 #ifndef MODULE
 	struct expansion_card *ec;
@@ -723,6 +696,7 @@
 	dev->irq       = ec->irq;
 
 	ecard_claim (ec);
+
 #endif
 	ether1_addr (dev);
 
@@ -733,36 +707,36 @@
 
 /* ------------------------------------------------------------------------- */
 
-static int ether1_txalloc (struct device *dev, int size)
+static int
+ether1_txalloc (struct device *dev, int size)
 {
-    	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 	int start, tail;
 
 	size = (size + 1) & ~1;
 	tail = priv->tx_tail;
 
-	if (priv->tx_head + size > TX_AREA_END) 
-	{
+	if (priv->tx_head + size > TX_AREA_END) {
 		if (tail > priv->tx_head)
 			return -1;
 		start = TX_AREA_START;
 		if (start + size > tail)
 			return -1;
 		priv->tx_head = start + size;
-	}
-	else
-	{
+	} else {
 		if (priv->tx_head < tail && (priv->tx_head + size) > tail)
 			return -1;
 		start = priv->tx_head;
 		priv->tx_head += size;
 	}
+
 	return start;
 }
 
-static void ether1_restart (struct device *dev, char *reason)
+static void
+ether1_restart (struct device *dev, char *reason)
 {
-    	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 	priv->stats.tx_errors ++;
 
 	if (reason)
@@ -781,9 +755,10 @@
 	dev->start = 1;
 }
 
-static int ether1_open (struct device *dev)
+static int
+ether1_open (struct device *dev)
 {
-    	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 #ifdef CLAIM_IRQ_AT_OPEN
 	if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev))
 		return -EAGAIN;
@@ -792,8 +767,7 @@
 
 	memset (&priv->stats, 0, sizeof (struct enet_statistics));
 
-	if (ether1_init_for_open (dev)) 
-	{
+	if (ether1_init_for_open (dev)) {
 #ifdef CLAIM_IRQ_AT_OPEN
 		free_irq (dev->irq, dev);
 #endif
@@ -808,15 +782,15 @@
 	return 0;
 }
 
-static int ether1_sendpacket (struct sk_buff *skb, struct device *dev)
+static int
+ether1_sendpacket (struct sk_buff *skb, struct device *dev)
 {
-    	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 
 	if (priv->restart)
 		ether1_restart (dev, NULL);
 
-	if (dev->tbusy) 
-	{
+	if (dev->tbusy) {
 		/*
 		 * If we get here, some higher level has decided that we are broken.
 		 * There should really be a "kick me" function call instead.
@@ -835,11 +809,9 @@
 	 * Block a timer-based transmit from overlapping.  This could better be
 	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
 	 */
-	 
 	if (test_and_set_bit (0, (void *)&dev->tbusy) != 0)
 		printk (KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
-	else 
-	{
+	else {
 		int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
 		int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
 		unsigned long flags;
@@ -890,14 +862,15 @@
 		if (tst != -1)
 			dev->tbusy = 0;
 	}
-	dev_kfree_skb (skb, FREE_WRITE);
+	dev_kfree_skb (skb);
 
 	return 0;
 }
 
-static void ether1_xmit_done (struct device *dev)
+static void
+ether1_xmit_done (struct device *dev)
 {
-    	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 	nop_t nop;
 	int caddr, tst;
 
@@ -906,57 +879,52 @@
 again:
 	ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
 
-	switch (nop.nop_command & CMD_MASK) 
-	{
-		case CMD_TDR:
-			/* special case */
-			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) != (unsigned short)I82586_NULL) 
-			{
-				ether1_outw (dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
-				scb_command, NORMALIRQS);
-				outb (CTRL_CA, REG_CONTROL);
-			}
-			priv->tx_tail = NOP_ADDR;
-			return;
+	switch (nop.nop_command & CMD_MASK) {
+	case CMD_TDR:
+		/* special case */
+		if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
+				!= (unsigned short)I82586_NULL) {
+			ether1_outw(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
+				    scb_command, NORMALIRQS);
+			outb (CTRL_CA, REG_CONTROL);
+		}
+		priv->tx_tail = NOP_ADDR;
+		return;
 
-		case CMD_NOP:
-			if (nop.nop_link == caddr)
-			{
-				if (priv->initialising == 0)
-					printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
-				else
-	        			priv->initialising = 0;
-				return;
-			}
-			if (caddr == nop.nop_link)
-				return;
-			caddr = nop.nop_link;
-			goto again;
-
-		case CMD_TX:
-			if (nop.nop_status & STAT_COMPLETE)
-				break;
-			printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);
-			priv->restart = 1;
+	case CMD_NOP:
+		if (nop.nop_link == caddr) {
+			if (priv->initialising == 0)
+				printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
+			else
+			        priv->initialising = 0;
 			return;
-
-		default:
-			printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
-				nop.nop_command & CMD_MASK, caddr);
-			priv->restart = 1;
+		}
+		if (caddr == nop.nop_link)
 			return;
+		caddr = nop.nop_link;
+		goto again;
+
+	case CMD_TX:
+		if (nop.nop_status & STAT_COMPLETE)
+			break;
+		printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);
+		priv->restart = 1;
+		return;
+
+	default:
+		printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
+			nop.nop_command & CMD_MASK, caddr);
+		priv->restart = 1;
+		return;
 	}
 
-	while (nop.nop_status & STAT_COMPLETE) 
-	{
-		if (nop.nop_status & STAT_OK) 
-		{
+	while (nop.nop_status & STAT_COMPLETE) {
+		if (nop.nop_status & STAT_OK) {
 			priv->stats.tx_packets ++;
 			priv->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
-		}
-		else
-		{
+		} else {
 			priv->stats.tx_errors ++;
+
 			if (nop.nop_status & STAT_COLLAFTERTX)
 				priv->stats.collisions ++;
 			if (nop.nop_status & STAT_NOCARRIER)
@@ -968,16 +936,15 @@
 			if (nop.nop_status & STAT_COLLEXCESSIVE)
 				priv->stats.collisions += 16;
 		}
-		if (nop.nop_link == caddr) 
-		{
+
+		if (nop.nop_link == caddr) {
 			printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);
 			break;
 		}
 
 		caddr = nop.nop_link;
 		ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
-		if ((nop.nop_command & CMD_MASK) != CMD_NOP) 
-		{
+		if ((nop.nop_command & CMD_MASK) != CMD_NOP) {
 			printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);
 			break;
 		}
@@ -987,8 +954,7 @@
 
 		caddr = nop.nop_link;
 		ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
-		if ((nop.nop_command & CMD_MASK) != CMD_TX) 
-		{
+		if ((nop.nop_command & CMD_MASK) != CMD_TX) {
 			printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);
 			break;
 		}
@@ -1004,15 +970,15 @@
 	mark_bh (NET_BH);
 }
 
-static void ether1_recv_done (struct device *dev)
+static void
+ether1_recv_done (struct device *dev)
 {
-    	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 	int status;
 	int nexttail, rbdaddr;
 	rbd_t rbd;
 
-	do
-	{
+	do {
 		status = ether1_inw (dev, priv->rx_head, rfd_t, rfd_status, NORMALIRQS);
 		if ((status & RFD_COMPLETE) == 0)
 			break;
@@ -1020,16 +986,14 @@
 		rbdaddr = ether1_inw (dev, priv->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
 		ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
 
-		if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) 
-		{
+		if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
 			int length = rbd.rbd_status & RBD_ACNT;
 			struct sk_buff *skb;
 
 			length = (length + 1) & ~1;
 			skb = dev_alloc_skb (length + 2);
 
-			if (skb) 
-			{
+			if (skb) {
 				skb->dev = dev;
 				skb_reserve (skb, 2);
 
@@ -1038,13 +1002,10 @@
 				skb->protocol = eth_type_trans (skb, dev);
 				netif_rx (skb);
 				priv->stats.rx_packets ++;
-			}
-			else
+			} else
 				priv->stats.rx_dropped ++;
-		}
-		else 
-		{
-			printk (KERN_WARNING "%s: %s\n", dev->name,
+		} else {
+			printk(KERN_WARNING "%s: %s\n", dev->name,
 				(rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
 			priv->stats.rx_dropped ++;
 		}
@@ -1052,7 +1013,7 @@
 		nexttail = ether1_inw (dev, priv->rx_tail, rfd_t, rfd_link, NORMALIRQS);
 		/* nexttail should be rx_head */
 		if (nexttail != priv->rx_head)
-			printk (KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
+			printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
 				dev->name, nexttail, priv->rx_head);
 		ether1_outw (dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
 		ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_command, NORMALIRQS);
@@ -1061,86 +1022,85 @@
 	
 		priv->rx_tail = nexttail;
 		priv->rx_head = ether1_inw (dev, priv->rx_head, rfd_t, rfd_link, NORMALIRQS);
-	}
-	while (1);
+	} while (1);
 }
 
-static void ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+static void
+ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct device *dev = (struct device *)dev_id;
-    	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 	int status;
 
 	dev->interrupt = 1;
 
 	status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
 
-	if (status) 
-	{
-		ether1_outw (dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
-			SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+	if (status) {
+		ether1_outw(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
+			    SCB_ADDR, scb_t, scb_command, NORMALIRQS);
 		outb (CTRL_CA | CTRL_ACK, REG_CONTROL);
-		if (status & SCB_STCX)
+		if (status & SCB_STCX) {
 			ether1_xmit_done (dev);
-		if (status & SCB_STCNA) 
-		{
+		}
+		if (status & SCB_STCNA) {
 			if (priv->resetting == 0)
 				printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);
 			else
 				priv->resetting += 1;
-			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) != (unsigned short)I82586_NULL) 
-			{
+			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
+					!= (unsigned short)I82586_NULL) {
 				ether1_outw (dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
 				outb (CTRL_CA, REG_CONTROL);
 			}
 			if (priv->resetting == 2)
 				priv->resetting = 0;
 		}
-		if (status & SCB_STFR)
+		if (status & SCB_STFR) {
 			ether1_recv_done (dev);
-
-		if (status & SCB_STRNR) 
-		{
-			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) 
-			{
+		}
+		if (status & SCB_STRNR) {
+			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {
 				printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
 				ether1_outw (dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
 				outb (CTRL_CA, REG_CONTROL);
 				priv->stats.rx_dropped ++;	/* we suspended due to lack of buffer space */
-			}
-			else
-				printk (KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
-			printk (KERN_WARNING "RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset,NORMALIRQS));
+			} else
+				printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
+					ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
+			printk (KERN_WARNING "RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset,
+						NORMALIRQS));
 		}
-	}
-	else
-        	outb (CTRL_ACK, REG_CONTROL);
+	} else
+	        outb (CTRL_ACK, REG_CONTROL);
 
 	dev->interrupt = 0;
 }
 
-static int ether1_close (struct device *dev)
+static int
+ether1_close (struct device *dev)
 {
 #ifdef CLAIM_IRQ_AT_OPEN
 	free_irq (dev->irq, dev);
 #endif
 
-	ether1_reset (dev);	
+	ether1_reset (dev);
+
 	dev->start = 0;
 	dev->tbusy = 0;
+
 	MOD_DEC_USE_COUNT;
 
 	return 0;
 }
 
-static struct enet_statistics *ether1_getstats (struct device *dev)
+static struct enet_statistics *
+ether1_getstats (struct device *dev)
 {
-    	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 	return &priv->stats;
 }
 
-
 /*
  * Set or clear the multicast filter for this adaptor.
  * num_addrs == -1	Promiscuous mode, receive all packets.
@@ -1148,8 +1108,8 @@
  * num_addrs > 0	Multicast mode, receive normal and MC packets, and do
  *			best-effort filtering.
  */
-
-static void ether1_setmulticastlist (struct device *dev)
+static void
+ether1_setmulticastlist (struct device *dev)
 {
 }
 
@@ -1161,12 +1121,12 @@
 static struct device *my_ethers[MAX_ECARDS];
 static struct expansion_card *ec[MAX_ECARDS];
 
-int init_module (void)
+int
+init_module (void)
 {
 	int i;
 
-	for (i = 0; i < MAX_ECARDS; i++) 
-	{
+	for (i = 0; i < MAX_ECARDS; i++) {
 		my_ethers[i] = NULL;
 		ec[i] = NULL;
 		strcpy (ethernames[i], "        ");
@@ -1174,10 +1134,9 @@
 
 	i = 0;
 
-	ecard_startfind();
+	ecard_startfind ();
 
-	do 
-	{
+	do {
 		if ((ec[i] = ecard_find(0, ether1_cids)) == NULL)
 			break;
 
@@ -1191,17 +1150,13 @@
 
 		ecard_claim (ec[i]);
 
-		if (register_netdev (my_ethers[i]) != 0) 
-		{
-			for (i = 0; i < 4; i++) 
-	    		{
-				if (my_ethers[i]) 
-				{
+		if (register_netdev (my_ethers[i]) != 0) {
+			for (i = 0; i < 4; i++) {
+				if (my_ethers[i]) {
 					kfree (my_ethers[i]);
 					my_ethers[i] = NULL;
 				}
-				if (ec[i])
-				{
+				if (ec[i]) {
 					ecard_release (ec[i]);
 					ec[i] = NULL;
 				}
@@ -1209,20 +1164,18 @@
 			return -EIO;
 		}
 		i++;
-	}
-	while (i < MAX_ECARDS);
+	} while (i < MAX_ECARDS);
 
 	return i != 0 ? 0 : -ENODEV;
 }
 
-void cleanup_module (void)
+void
+cleanup_module (void)
 {
 	int i;
 
-	for (i = 0; i < MAX_ECARDS; i++) 
-	{
-		if (my_ethers[i]) 
-		{
+	for (i = 0; i < MAX_ECARDS; i++) {
+		if (my_ethers[i]) {
 			unregister_netdev (my_ethers[i]);
 			release_region (my_ethers[i]->base_addr, 16);
 			release_region (my_ethers[i]->base_addr + 0x800, 4096);
@@ -1231,8 +1184,7 @@
 #endif
 			my_ethers[i] = NULL;
 		}
-		if (ec[i]) 
-		{
+		if (ec[i]) {
 			ecard_release (ec[i]);
 			ec[i] = NULL;
 		}
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c
--- v2.1.93/linux/drivers/acorn/net/ether3.c	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/net/ether3.c	Wed Apr  8 15:51:32 1998
@@ -7,29 +7,30 @@
  * By Russell King, with some suggestions from borris@ant.co.uk
  *
  * Changelog:
- * 1.04 RMK     29/02/1996      Won't pass packets that are from our ethernet
- *                              address up to the higher levels - they're
- *                              silently ignored.  I/F can now be put into
- *                              multicast mode.  Receiver routine optimised.
- * 1.05 RMK     30/02/1996      Now claims interrupt at open when part of
- *                              the kernel rather than when a module.
- * 1.06 RMK     02/03/1996      Various code cleanups
- * 1.07 RMK     13/10/1996      Optimised interrupt routine and transmit
- *                              routines.
- * 1.08 RMK     14/10/1996      Fixed problem with too many packets,
- *                              prevented the kernel message about dropped
- *                              packets appearing too many times a second.
- *                              Now does not disable all IRQs, only the IRQ
- *                              used by this card.
- * 1.09 RMK     10/11/1996      Only enables TX irq when buffer space is low,
- *                              but we still service the TX queue if we get a
- *                              RX interrupt.
- * 1.10 RMK     15/07/1997      Fixed autoprobing of NQ8004.
- * 1.11 RMK     16/11/1997      Fixed autoprobing of NQ8005A.
- * 1.12 RMK     31/12/1997      Removed reference to dev_tint for Linux 2.1.
+ * 1.04	RMK	29/02/1996	Won't pass packets that are from our ethernet
+ *				address up to the higher levels - they're
+ *				silently ignored.  I/F can now be put into
+ *				multicast mode.  Receiver routine optimised.
+ * 1.05	RMK	30/02/1996	Now claims interrupt at open when part of
+ *				the kernel rather than when a module.
+ * 1.06	RMK	02/03/1996	Various code cleanups
+ * 1.07	RMK	13/10/1996	Optimised interrupt routine and transmit
+ *				routines.
+ * 1.08	RMK	14/10/1996	Fixed problem with too many packets,
+ *				prevented the kernel message about dropped
+ *				packets appearing too many times a second.
+ *				Now does not disable all IRQs, only the IRQ
+ *				used by this card.
+ * 1.09	RMK	10/11/1996	Only enables TX irq when buffer space is low,
+ *				but we still service the TX queue if we get a
+ *				RX interrupt.
+ * 1.10	RMK	15/07/1997	Fixed autoprobing of NQ8004.
+ * 1.11	RMK	16/11/1997	Fixed autoprobing of NQ8005A.
+ * 1.12	RMK	31/12/1997	Removed reference to dev_tint for Linux 2.1.
  *
  * TODO:
  *  When we detect a fatal error on the interface, we should restart it.
+ *  Reap transmit packets after some time even if the buffer never filled.
  */
 
 static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.12\n";
@@ -49,6 +50,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -64,25 +66,20 @@
 #endif
 
 static unsigned int net_debug = NET_DEBUG;
-
-static const card_ids ether3_cids[] =
-{
-	{MANU_ANT2, PROD_ANT_ETHER3},
-	{MANU_ANT, PROD_ANT_ETHER3},
-	{MANU_ANT, PROD_ANT_ETHERB},	/* trial - will etherb work? */
-	{0xffff, 0xffff}
+static const card_ids ether3_cids[] = {
+	{ MANU_ANT2, PROD_ANT_ETHER3 },
+	{ MANU_ANT,  PROD_ANT_ETHER3 },
+	{ MANU_ANT,  PROD_ANT_ETHERB }, /* trial - will etherb work? */
+	{ 0xffff, 0xffff }
 };
 
 static void ether3_setmulticastlist(struct device *dev);
-static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt);
+static int  ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt);
 static void ether3_tx(struct device *dev, struct dev_priv *priv);
 
 extern int inswb(int reg, void *buffer, int len);
 extern int outswb(int reg, void *buffer, int len);
 
-#define 	struct dev_priv *priv = (struct dev_priv *)dev->priv \
-	struct dev_priv *priv = (struct dev_priv *)dev->priv
-
 #define BUS_16		2
 #define BUS_8		1
 #define BUS_UNKNOWN	0
@@ -91,9 +88,7 @@
  * I'm not sure what address we should default to if the internal one
  * is corrupted...
  */
-
-unsigned char def_eth_addr[6] =
-{0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+unsigned char def_eth_addr[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
 
 /* --------------------------------------------------------------------------- */
 
@@ -102,16 +97,17 @@
 	buffer_read
 } buffer_rw_t;
 
-static int ether3_setbuffer(struct device *dev, buffer_rw_t read, int start)
+static int
+ether3_setbuffer(struct device *dev, buffer_rw_t read, int start)
 {
-	struct dev_priv *priv = (struct dev_priv *) dev->priv;
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
 	int timeout = 1000;
 
 	outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
 	outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
 	while ((inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) {
 		if (!timeout--) {
-			printk(KERN_ERR "%s: setbuffer broken\n", dev->name);
+			printk("%s: setbuffer broken\n", dev->name);
 			priv->broken = 1;
 			return 1;
 		}
@@ -131,47 +127,49 @@
  * write data to the buffer memory
  */
 #define ether3_writebuffer(dev,data,length)			\
-	outswb (REG_BUFWIN, (data), (length))
+	outswb(REG_BUFWIN, (data), (length))
 
 #define ether3_writeword(dev,data)				\
-	outw ((data), REG_BUFWIN)
+	outw((data), REG_BUFWIN)
 
 #define ether3_writelong(dev,data)	{			\
 	unsigned long reg_bufwin = REG_BUFWIN;			\
-	outw ((data), reg_bufwin);				\
-	outw ((data) >> 16, reg_bufwin);			\
+	outw((data), reg_bufwin);				\
+	outw((data) >> 16, reg_bufwin);			\
 }
 
 /*
  * read data from the buffer memory
  */
 #define ether3_readbuffer(dev,data,length)			\
-	inswb (REG_BUFWIN, (data), (length))
+	inswb(REG_BUFWIN, (data), (length))
 
 #define ether3_readword(dev)					\
-	inw (REG_BUFWIN)
+	inw(REG_BUFWIN)
 
 #define ether3_readlong(dev)	 				\
-	inw (REG_BUFWIN) | (inw (REG_BUFWIN) << 16)
+	inw(REG_BUFWIN) | (inw(REG_BUFWIN) << 16)
 
 /*
  * Switch LED off...
  */
-static void ether3_ledoff(unsigned long data)
+static void
+ether3_ledoff(unsigned long data)
 {
-	struct device *dev = (struct device *) data;
-	struct dev_priv *priv = (struct dev_priv *) dev->priv;
+	struct device *dev = (struct device *)data;
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
 	outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2);
 }
 
 /*
  * switch LED on...
  */
-static inline void ether3_ledon(struct device *dev, struct dev_priv *priv)
+static inline void
+ether3_ledon(struct device *dev, struct dev_priv *priv)
 {
 	del_timer(&priv->timer);
-	priv->timer.expires = jiffies + HZ / 50;	/* leave on for 1/50th second */
-	priv->timer.data = (unsigned long) dev;
+	priv->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */
+	priv->timer.data = (unsigned long)dev;
 	priv->timer.function = ether3_ledoff;
 	add_timer(&priv->timer);
 	if (priv->regs.config2 & CFG2_CTRLO)
@@ -182,30 +180,36 @@
  * Read the ethernet address string from the on board rom.
  * This is an ascii string!!!
  */
-static void ether3_addr(char *addr, struct expansion_card *ec)
+__initfunc(static void
+ether3_addr(char *addr, struct expansion_card *ec))
 {
 	struct in_chunk_dir cd;
 	char *s;
-
+	
 	if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) {
 		int i;
-		for (i = 0; i < 6; i++) {
+		for (i = 0; i<6; i++) {
 			addr[i] = simple_strtoul(s + 1, &s, 0x10);
-			if (*s != (i == 5 ? ')' : ':'))
+			if (*s != (i==5?')' : ':' ))
 				break;
 		}
 		if (i == 6)
 			return;
 	}
+	/* I wonder if we should even let the user continue in this case
+	 *   - no, it would be better to disable the device
+	 */
+	printk(KERN_ERR "ether3: Couldn't read a valid MAC address from card.\n");
 	memcpy(addr, def_eth_addr, 6);
 }
 
 /* --------------------------------------------------------------------------- */
 
-static int ether3_ramtest(struct device *dev, unsigned char byte)
+__initfunc(static int
+ether3_ramtest(struct device *dev, unsigned char byte))
 {
 	unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL);
-	int i, ret = 0;
+	int i,ret = 0;
 	int max_errors = 4;
 	int bad = -1;
 
@@ -234,7 +238,7 @@
 			}
 		} else {
 			if (bad != -1) {
-				if (bad != i - 1)
+			    	if (bad != i - 1)
 					printk(" - 0x%04X", i - 1);
 				printk("\n");
 				bad = -1;
@@ -250,13 +254,14 @@
 
 /* ------------------------------------------------------------------------------- */
 
-static int ether3_init_2(struct device *dev)
+__initfunc(static int
+ether3_init_2(struct device *dev))
 {
-	struct dev_priv *priv = (struct dev_priv *) dev->priv;
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
 	int i;
 
-	priv->regs.config1 = CFG1_RECVCOMPSTAT0 | CFG1_DMABURST8;
-	priv->regs.config2 = CFG2_CTRLO | CFG2_RECVCRC | CFG2_ERRENCRC;
+	priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8;
+	priv->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC;
 	priv->regs.command = 0;
 	/*
 	 * Set up our hardware address
@@ -273,12 +278,12 @@
 		priv->regs.config1 |= CFG1_RECVSPECBROAD;
 
 	/*
-	 * There is a problem with the NQ8005 in that it occasionally losses the
-	 * last two bytes.  To get round this problem, we receive the CRC as well.
-	 * That way, if we do loose the last two, then it doesn't matter
+	 * There is a problem with the NQ8005 in that it occasionally loses the
+	 * last two bytes.  To get round this problem, we receive the CRC as
+	 * well.  That way, if we do loose the last two, then it doesn't matter.
 	 */
 	outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
-	outw((TX_END >> 8) - 1, REG_BUFWIN);
+	outw((TX_END>>8) - 1, REG_BUFWIN);
 	outw(priv->rx_head, REG_RECVPTR);
 	outw(0, REG_TRANSMITPTR);
 	outw(priv->rx_head >> 8, REG_RECVEND);
@@ -287,10 +292,10 @@
 	outw(priv->regs.command, REG_COMMAND);
 
 	i = ether3_ramtest(dev, 0x5A);
-	if (i)
+	if(i)
 		return i;
 	i = ether3_ramtest(dev, 0x1E);
-	if (i)
+	if(i)
 		return i;
 
 	ether3_setbuffer(dev, buffer_write, 0);
@@ -298,29 +303,30 @@
 	return 0;
 }
 
-static void ether3_init_for_open(struct device *dev)
+static void
+ether3_init_for_open(struct device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *) dev->priv;
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
 	int i;
 
 	memset(&priv->stats, 0, sizeof(struct enet_statistics));
 
 	priv->regs.command = 0;
-	outw(CMD_RXOFF | CMD_TXOFF, REG_COMMAND);
-	while (inw(REG_STATUS) & (STAT_RXON | STAT_TXON));
+	outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
+	while (inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
 
 	outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
 	for (i = 0; i < 6; i++)
 		outb(dev->dev_addr[i], REG_BUFWIN);
 
-	priv->tx_used = 0;
-	priv->tx_head = 0;
-	priv->tx_tail = 0;
+	priv->tx_used	= 0;
+	priv->tx_head	= 0;
+	priv->tx_tail	= 0;
 	priv->regs.config2 |= CFG2_CTRLO;
-	priv->rx_head = RX_START;
+	priv->rx_head	= RX_START;
 
 	outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
-	outw((TX_END >> 8) - 1, REG_BUFWIN);
+	outw((TX_END>>8) - 1, REG_BUFWIN);
 	outw(priv->rx_head, REG_RECVPTR);
 	outw(priv->rx_head >> 8, REG_RECVEND);
 	outw(0, REG_TRANSMITPTR);
@@ -337,20 +343,22 @@
 /*
  * This is the real probe routine.
  */
-static int ether3_probe1(struct device *dev)
+__initfunc(static int
+ether3_probe1(struct device *dev))
 {
 	static unsigned version_printed = 0;
 	struct dev_priv *priv;
 	unsigned int i, bus_type, error = ENODEV;
 
-	if (net_debug && version_printed++ == 0)
+	if (net_debug  &&  version_printed++ == 0)
 		printk(version);
 
 	if (!dev->priv) {
-		dev->priv = kmalloc(sizeof(struct dev_priv), GFP_KERNEL);
+		dev->priv = kmalloc(sizeof (struct dev_priv), GFP_KERNEL);
 		if (!dev->priv)
 			return -ENOMEM;
 	}
+
 	priv = (struct dev_priv *) dev->priv;
 	memset(priv, 0, sizeof(struct dev_priv));
 
@@ -374,6 +382,7 @@
 		else if (inw(REG_RECVPTR) == 0x101)
 			bus_type = BUS_16;
 	}
+
 	switch (bus_type) {
 	case BUS_UNKNOWN:
 		printk(KERN_ERR "%s: unable to identify podule bus width\n", dev->name);
@@ -407,7 +416,8 @@
 #endif
 			return 0;
 	}
-      failed:
+
+failed:
 	kfree(dev->priv);
 	dev->priv = NULL;
 	release_region(dev->base_addr, 128);
@@ -415,7 +425,8 @@
 }
 
 #ifndef MODULE
-int ether3_probe(struct device *dev)
+__initfunc(int
+ether3_probe(struct device *dev))
 {
 	struct expansion_card *ec;
 
@@ -445,7 +456,8 @@
  * registers that "should" only need to be set once at boot, so that
  * there is non-reboot way to recover if something goes wrong.
  */
-static int ether3_open(struct device *dev)
+static int
+ether3_open(struct device *dev)
 {
 	ether3_init_for_open(dev);
 
@@ -453,7 +465,7 @@
 
 #ifdef CLAIM_IRQ_AT_OPEN
 	if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) {
-		MOD_DEC_USE_COUNT;
+	    	MOD_DEC_USE_COUNT;
 		return -EAGAIN;
 	}
 #endif
@@ -467,18 +479,19 @@
 /*
  * The inverse routine to ether3_open().
  */
-static int ether3_close(struct device *dev)
+static int
+ether3_close(struct device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *) dev->priv;
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
 
 	dev->tbusy = 1;
 	dev->start = 0;
 
 	disable_irq(dev->irq);
 
-	outw(CMD_RXOFF | CMD_TXOFF, REG_COMMAND);
+	outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
 	priv->regs.command = 0;
-	while (inw(REG_STATUS) & (STAT_RXON | STAT_TXON));
+	while (inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
 	outb(0x80, REG_CONFIG2 + 1);
 	outw(0, REG_COMMAND);
 
@@ -492,12 +505,12 @@
 }
 
 /*
- * Get the current statistics.        This may be called with the card open or
+ * Get the current statistics.	This may be called with the card open or
  * closed.
  */
 static struct enet_statistics *ether3_getstats(struct device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *) dev->priv;
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
 	return &priv->stats;
 }
 
@@ -509,14 +522,15 @@
  */
 static void ether3_setmulticastlist(struct device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *) dev->priv;
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
 
 	priv->regs.config1 &= ~CFG1_RECVPROMISC;
 
 	if (dev->flags & IFF_PROMISC) {
 		/* promiscuous mode */
 		priv->regs.config1 |= CFG1_RECVPROMISC;
-	} else if (dev->flags & IFF_ALLMULTI) {
+	} else
+	if (dev->flags & IFF_ALLMULTI) {
 		priv->regs.config1 |= CFG1_RECVSPECBRMULTI;
 	} else
 		priv->regs.config1 |= CFG1_RECVSPECBROAD;
@@ -527,15 +541,16 @@
 /*
  * Transmit a packet
  */
-static int ether3_sendpacket(struct sk_buff *skb, struct device *dev)
+static int
+ether3_sendpacket(struct sk_buff *skb, struct device *dev)
 {
-	struct dev_priv *priv = (struct dev_priv *) dev->priv;
-      retry:
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+retry:
 	if (!dev->tbusy) {
 		/* Block a timer-based transmit from overlapping.  This could better be
 		 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
 		 */
-		if (!test_and_set_bit(0, (void *) &dev->tbusy)) {
+		if (!test_and_set_bit(0, (void *)&dev->tbusy)) {
 			unsigned long flags;
 			unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 			unsigned int ptr, nextptr;
@@ -543,17 +558,18 @@
 			length = (length + 1) & ~1;
 
 			if (priv->broken) {
-				dev_kfree_skb(skb, FREE_WRITE);
-				priv->stats.tx_dropped++;
+				dev_kfree_skb(skb);
+				priv->stats.tx_dropped ++;
 				dev->tbusy = 0;
 				return 0;
 			}
+
 			ptr = priv->tx_head;
 			nextptr = ptr + 0x600;
 			if (nextptr >= TX_END)
 				nextptr = 0;
 			if (nextptr == priv->tx_tail)
-				return 1;	/* unable to queue */
+				return 1;		/* unable to queue */
 			priv->tx_head = nextptr;
 
 			save_flags_cli(flags);
@@ -562,13 +578,13 @@
 			ether3_setbuffer(dev, buffer_write, ptr + 4);
 			ether3_writebuffer(dev, skb->data, length);
 			ether3_writeword(dev, htons(nextptr));
-			ether3_writeword(dev, (TXHDR_TRANSMIT | TXHDR_CHAINCONTINUE) >> 16);
+			ether3_writeword(dev, (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE) >> 16);
 			ether3_setbuffer(dev, buffer_write, ptr);
 #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
 			ether3_writeword(dev, htons(ptr + length + 4));
 			ether3_writeword(dev, (TXHDR_FLAGS >> 16));
 			ether3_ledon(dev, priv);
-			priv->tx_used++;
+			priv->tx_used ++;
 			if (priv->tx_used < MAX_TX_BUFFERED)
 				dev->tbusy = 0;
 			if (priv->tx_used >= (MAX_TX_BUFFERED * 3 / 4)) {
@@ -578,7 +594,7 @@
 			restore_flags(flags);
 
 			dev->trans_start = jiffies;
-			dev_kfree_skb(skb, FREE_WRITE);
+			dev_kfree_skb(skb);
 			if (!(inw(REG_STATUS) & STAT_TXON)) {
 				outw(ptr, REG_TRANSMITPTR);
 				outw(priv->regs.command | CMD_TXON, REG_COMMAND);
@@ -599,24 +615,25 @@
 		printk("%s: transmit timed out, network cable problem?\n", dev->name);
 		dev->tbusy = 0;
 		priv->regs.config2 |= CFG2_CTRLO;
-		outw(priv->regs.config2, REG_CONFIG2);
+		outw(priv->regs.config2 , REG_CONFIG2);
 		dev->trans_start = jiffies;
 		goto retry;
 	}
 }
 
-static void ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void
+ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	struct device *dev = (struct device *) dev_id;
+	struct device *dev = (struct device *)dev_id;
 	struct dev_priv *priv;
 	unsigned int status;
 
 #if NET_DEBUG > 1
-	if (net_debug & DEBUG_INT)
+	if(net_debug & DEBUG_INT)
 		printk("eth3irq: %d ", irq);
 #endif
 
-	priv = (struct dev_priv *) dev->priv;
+	priv = (struct dev_priv *)dev->priv;
 
 	dev->interrupt = 1;
 	status = inw(REG_STATUS);
@@ -625,12 +642,13 @@
 	 * mostly empty, if we happen to get a RX interrupt, we might as
 	 * well handle the TX packets as well.
 	 */
-	if (status & STAT_INTTX) {	/* Packets transmitted */
+	if (status & STAT_INTTX) { /* Packets transmitted */
 		outw(CMD_ACKINTTX | priv->regs.command, REG_COMMAND);
 		ether3_tx(dev, priv);
 	}
+
 	status = inw(REG_STATUS);
-	if (status & STAT_INTRX && ether3_rx(dev, priv, 12)) {	/* Got packet(s). */
+	if (status & STAT_INTRX && ether3_rx(dev, priv, 12)) { /* Got packet(s). */
 		/*
 		 * We only acknowledge the interrupt if we have received all packets
 		 * in the buffer or else we run out of memory. This is to allow the
@@ -646,7 +664,7 @@
 	dev->interrupt = 0;
 
 #if NET_DEBUG > 1
-	if (net_debug & DEBUG_INT)
+	if(net_debug & DEBUG_INT)
 		printk("done\n");
 #endif
 }
@@ -654,7 +672,8 @@
 /*
  * If we have a good packet(s), get it/them out of the buffers.
  */
-static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt)
+static int
+ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt)
 {
 	unsigned int next_ptr = priv->rx_head, received = 0;
 	ether3_ledon(dev, priv);
@@ -681,16 +700,17 @@
 			next_ptr = ntohs(temp_ptr);
 		}
 		ether3_setbuffer(dev, buffer_read, this_ptr);
-		ether3_readbuffer(dev, addrs + 2, 12);
+		ether3_readbuffer(dev, addrs+2, 12);
 
 		/*
-		 * ignore our own packets...
-		 */
-		if (!(*(unsigned long *) &dev->dev_addr[0] ^ *(unsigned long *) &addrs[2 + 6]) &&
-		    !(*(unsigned short *) &dev->dev_addr[4] ^ *(unsigned short *) &addrs[2 + 10])) {
-			maxcnt++;	/* compensate for loopedback packet */
+ 		 * ignore our own packets...
+	 	 */
+		if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) &&
+		    !(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) {
+			maxcnt ++; /* compensate for loopedback packet */
 			outw(next_ptr >> 8, REG_RECVEND);
-		} else if (!(status & (RXSTAT_OVERSIZE | RXSTAT_CRCERROR | RXSTAT_DRIBBLEERROR | RXSTAT_SHORTPACKET))) {
+		} else
+		if (!(status & (RXSTAT_OVERSIZE|RXSTAT_CRCERROR|RXSTAT_DRIBBLEERROR|RXSTAT_SHORTPACKET))) {
 			unsigned int length = next_ptr - this_ptr;
 			struct sk_buff *skb;
 
@@ -706,32 +726,28 @@
 				buf = skb_put(skb, length);
 				ether3_readbuffer(dev, buf + 12, length - 12);
 				outw(next_ptr >> 8, REG_RECVEND);
-				*(unsigned short *) (buf + 0) = *(unsigned short *) (addrs + 2);
-				*(unsigned long *) (buf + 2) = *(unsigned long *) (addrs + 4);
-				*(unsigned long *) (buf + 6) = *(unsigned long *) (addrs + 8);
-				*(unsigned short *) (buf + 10) = *(unsigned short *) (addrs + 12);
+				*(unsigned short *)(buf + 0)	= *(unsigned short *)(addrs + 2);
+				*(unsigned long *)(buf + 2)	= *(unsigned long *)(addrs + 4);
+				*(unsigned long *)(buf + 6)	= *(unsigned long *)(addrs + 8);
+				*(unsigned short *)(buf + 10)	= *(unsigned short *)(addrs + 12);
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
-				received++;
+				received ++;
 			} else
 				goto dropping;
 		} else {
 			struct enet_statistics *stats = &priv->stats;
 			outw(next_ptr >> 8, REG_RECVEND);
-			if (status & RXSTAT_OVERSIZE)
-				stats->rx_length_errors++;
-			if (status & RXSTAT_CRCERROR)
-				stats->rx_crc_errors++;
-			if (status & RXSTAT_DRIBBLEERROR)
-				stats->rx_fifo_errors++;
-			if (status & RXSTAT_SHORTPACKET)
-				stats->rx_length_errors++;
+			if (status & RXSTAT_OVERSIZE)	  stats->rx_length_errors ++;
+			if (status & RXSTAT_CRCERROR)	  stats->rx_crc_errors ++;
+			if (status & RXSTAT_DRIBBLEERROR) stats->rx_fifo_errors ++;
+			if (status & RXSTAT_SHORTPACKET)  stats->rx_length_errors ++;
 			stats->rx_errors++;
 		}
 	}
-	while (--maxcnt);
+	while (-- maxcnt);
 
-      done:
+done:
 	priv->stats.rx_packets += received;
 	priv->rx_head = next_ptr;
 	/*
@@ -739,42 +755,44 @@
 	 * have dropped at least one packet.
 	 */
 	if (!(inw(REG_STATUS) & STAT_RXON)) {
-		priv->stats.rx_dropped++;
-		outw(next_ptr, REG_RECVPTR);
+		priv->stats.rx_dropped ++;
+    		outw(next_ptr, REG_RECVPTR);
 		outw(priv->regs.command | CMD_RXON, REG_COMMAND);
 	}
+
 	return maxcnt;
 
-      dropping:{
-		static unsigned long last_warned;
+dropping:{
+	static unsigned long last_warned;
 
-		outw(next_ptr >> 8, REG_RECVEND);
-		/*
-		 * Don't print this message too many times...
-		 */
-		if (jiffies - last_warned > 30 * HZ) {
-			last_warned = jiffies;
-			printk("%s: memory squeeze, dropping packet.\n", dev->name);
-		}
-		priv->stats.rx_dropped++;
-		goto done;
+	outw(next_ptr >> 8, REG_RECVEND);
+	/*
+	 * Don't print this message too many times...
+	 */
+	if (jiffies - last_warned > 30 * HZ) {
+		last_warned = jiffies;
+		printk("%s: memory squeeze, dropping packet.\n", dev->name);
+	}
+	priv->stats.rx_dropped ++;
+	goto done;
 	}
 }
 
 /*
  * Update stats for the transmitted packet(s)
  */
-static void ether3_tx(struct device *dev, struct dev_priv *priv)
+static void
+ether3_tx(struct device *dev, struct dev_priv *priv)
 {
 	unsigned int tx_tail = priv->tx_tail;
 
 	do {
-		unsigned long status;
-		/*
-		 * Read the packet header
-		 */
-		ether3_setbuffer(dev, buffer_read, tx_tail);
-		status = ether3_readlong(dev);
+	    	unsigned long status;
+    		/*
+	    	 * Read the packet header
+    		 */
+	    	ether3_setbuffer(dev, buffer_read, tx_tail);
+    		status = ether3_readlong(dev);
 
 		/*
 		 * Check to see if this packet has been transmitted
@@ -788,11 +806,9 @@
 		if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS)))
 			priv->stats.tx_packets++;
 		else {
-			priv->stats.tx_errors++;
-			if (status & TXSTAT_16COLLISIONS)
-				priv->stats.collisions += 16;
-			if (status & TXSTAT_BABBLED)
-				priv->stats.tx_fifo_errors++;
+			priv->stats.tx_errors ++;
+			if (status & TXSTAT_16COLLISIONS) priv->stats.collisions += 16;
+			if (status & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++;
 		}
 
 		/*
@@ -824,11 +840,12 @@
 static struct device *my_ethers[MAX_ECARDS];
 static struct expansion_card *ec[MAX_ECARDS];
 
-int init_module(void)
+int
+init_module(void)
 {
 	int i;
 
-	for (i = 0; i < MAX_ECARDS; i++) {
+	for(i = 0; i < MAX_ECARDS; i++) {
 		my_ethers[i] = NULL;
 		ec[i] = NULL;
 		strcpy(ethernames[i], "        ");
@@ -842,11 +859,11 @@
 		if ((ec[i] = ecard_find(0, ether3_cids)) == NULL)
 			break;
 
-		my_ethers[i] = (struct device *) kmalloc(sizeof(struct device), GFP_KERNEL);
+		my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL);
 		memset(my_ethers[i], 0, sizeof(struct device));
 
 		my_ethers[i]->irq = ec[i]->irq;
-		my_ethers[i]->base_addr = ecard_address(ec[i], ECARD_MEMC, 0);
+		my_ethers[i]->base_addr= ecard_address(ec[i], ECARD_MEMC, 0);
 		my_ethers[i]->init = ether3_probe1;
 		my_ethers[i]->name = ethernames[i];
 
@@ -854,13 +871,13 @@
 
 		ecard_claim(ec[i]);
 
-		if (register_netdev(my_ethers[i]) != 0) {
+		if(register_netdev(my_ethers[i]) != 0) {
 			for (i = 0; i < 4; i++) {
-				if (my_ethers[i]) {
+				if(my_ethers[i]) {
 					kfree(my_ethers[i]);
 					my_ethers[i] = NULL;
 				}
-				if (ec[i]) {
+				if(ec[i]) {
 					ecard_release(ec[i]);
 					ec[i] = NULL;
 				}
@@ -869,28 +886,25 @@
 		}
 		i++;
 	}
-	while (i < MAX_ECARDS);
+	while(i < MAX_ECARDS);
 
 	return i != 0 ? 0 : -ENODEV;
 }
 
-void cleanup_module(void)
+void
+cleanup_module(void)
 {
-	if (MOD_IN_USE) {
-		printk("ether3: device busy, remove delayed\n");
-	} else {
-		int i;
-		for (i = 0; i < MAX_ECARDS; i++) {
-			if (my_ethers[i]) {
-				release_region(my_ethers[i]->base_addr, 128);
-				unregister_netdev(my_ethers[i]);
-				my_ethers[i] = NULL;
-			}
-			if (ec[i]) {
-				ecard_release(ec[i]);
-				ec[i] = NULL;
-			}
+	int i;
+	for (i = 0; i < MAX_ECARDS; i++) {
+		if (my_ethers[i]) {
+		  	release_region(my_ethers[i]->base_addr, 128);
+			unregister_netdev(my_ethers[i]);
+			my_ethers[i] = NULL;
+		}
+		if (ec[i]) {
+			ecard_release(ec[i]);
+			ec[i] = NULL;
 		}
 	}
 }
-#endif				/* MODULE */
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c
--- v2.1.93/linux/drivers/acorn/net/etherh.c	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/net/etherh.c	Wed Apr  8 15:51:32 1998
@@ -41,7 +41,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include "8390.h"
+#include "../../net/8390.h"
 
 #define NET_DEBUG  0
 #define DEBUG_INIT 2
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/cumana_1.c linux/drivers/acorn/scsi/cumana_1.c
--- v2.1.93/linux/drivers/acorn/scsi/cumana_1.c	Tue Mar 10 10:03:31 1998
+++ linux/drivers/acorn/scsi/cumana_1.c	Wed Apr  8 15:51:32 1998
@@ -33,7 +33,13 @@
  */
 
 /*
- * $Log: cumana_NCR5380.c,v $
+ * $Log: cumana_1.c,v $
+ * Revision 1.2  1998/03/08 05:49:46  davem
+ * Merge to 2.1.89
+ *
+ * Revision 1.1  1998/02/23 02:45:22  davem
+ * Merge to 2.1.88
+ *
  */
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/cumana_1.h linux/drivers/acorn/scsi/cumana_1.h
--- v2.1.93/linux/drivers/acorn/scsi/cumana_1.h	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/scsi/cumana_1.h	Wed Apr  8 15:51:32 1998
@@ -23,7 +23,10 @@
  */
 
 /*
- * $Log: cumana_NCR5380.h,v $
+ * $Log: cumana_1.h,v $
+ * Revision 1.1  1998/02/23 02:45:22  davem
+ * Merge to 2.1.88
+ *
  */
 
 #ifndef CUMANA_NCR5380_H
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c
--- v2.1.93/linux/drivers/acorn/scsi/cumana_2.c	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/scsi/cumana_2.c	Wed Apr  8 15:51:32 1998
@@ -114,7 +114,7 @@
 	    unsigned long word;
 
 
-	    if (inb (REG0_STATUS(&info->info)) & STATUS_INT)
+	    if (inb (REG_STAT(&info->info)) & STAT_INT)
 		goto end;
 
 	    if (!(inb (info->cstatus) & CSTATUS_DRQ))
@@ -131,7 +131,7 @@
     else {
 	if (transfer && (transfer & 255)) {
 	    while (length >= 256) {
-		if (inb (REG0_STATUS(&info->info)) & STATUS_INT)
+		if (inb (REG_STAT(&info->info)) & STAT_INT)
 		    goto end;
 	    
 		if (!(inb (info->cstatus) & CSTATUS_DRQ))
@@ -146,7 +146,7 @@
 	while (length > 0) {
 	    unsigned long word;
 
-	    if (inb (REG0_STATUS(&info->info)) & STATUS_INT)
+	    if (inb (REG_STAT(&info->info)) & STAT_INT)
 		goto end;
 	    
 	    if (!(inb (info->cstatus) & CSTATUS_DRQ))
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/ecoscsi.c linux/drivers/acorn/scsi/ecoscsi.c
--- v2.1.93/linux/drivers/acorn/scsi/ecoscsi.c	Tue Mar 10 10:03:31 1998
+++ linux/drivers/acorn/scsi/ecoscsi.c	Wed Apr  8 15:51:32 1998
@@ -32,7 +32,13 @@
  */
 
 /*
- * $Log: ecoscsi_NCR5380.c,v $
+ * $Log: ecoscsi.c,v $
+ * Revision 1.2  1998/03/08 05:49:47  davem
+ * Merge to 2.1.89
+ *
+ * Revision 1.1  1998/02/23 02:45:24  davem
+ * Merge to 2.1.88
+ *
  */
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/ecoscsi.h linux/drivers/acorn/scsi/ecoscsi.h
--- v2.1.93/linux/drivers/acorn/scsi/ecoscsi.h	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/scsi/ecoscsi.h	Wed Apr  8 15:51:32 1998
@@ -19,7 +19,10 @@
  */
 
 /*
- * $Log: ecoscsi_NCR5380.h,v $
+ * $Log: ecoscsi.h,v $
+ * Revision 1.1  1998/02/23 02:45:24  davem
+ * Merge to 2.1.88
+ *
  */
 
 #ifndef ECOSCSI_NCR5380_H
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c
--- v2.1.93/linux/drivers/acorn/scsi/fas216.c	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/scsi/fas216.c	Wed Apr  8 15:51:32 1998
@@ -37,8 +37,8 @@
 
 #define FAS216_C
 
-#include "scsi.h"
-#include "hosts.h"
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
 #include "fas216.h"
 
 #define VER_MAJOR	0
@@ -104,7 +104,7 @@
 
 	if (value < 4)
 		value = 4;
-	else if value > 35)
+	else if (value > 35)
 		value = 35;
 
 	return value & 31;
@@ -1269,6 +1269,46 @@
 		*SCpntp2 = NULL;
 }
 
+/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+ * Purpose : abort this command
+ * Params  : SCpnt - command to abort
+ * Returns : FAILED if unable to abort
+ */
+int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
+}
+
+/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the device associated with this command
+ * Params  : SCpnt - command specifing device to reset
+ * Returns : FAILED if unable to reset
+ */
+int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
+}
+
+/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the complete bus associated with this command
+ * Params  : SCpnt - command specifing bus to reset
+ * Returns : FAILED if unable to reset
+ */
+int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
+}
+
+/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the host associated with this command
+ * Params  : SCpnt - command specifing host to reset
+ * Returns : FAILED if unable to reset
+ */
+int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
+}
+
 /* Function: int fas216_abort (Scsi_Cmnd *SCpnt)
  * Purpose : abort a command if something horrible happens.
  * Params  : SCpnt - Command that is believed to be causing a problem.
@@ -1352,7 +1392,7 @@
 #else
 		info->device[i].disconnect_ok = 0;
 #endif
-		info->device[i].stp = fas216_syncperiod(info->ifcfg.asyncperiod);
+		info->device[i].stp = fas216_syncperiod(info, info->ifcfg.asyncperiod);
 		info->device[i].sof = 0;
 #ifdef SCSI2SYNC
 		info->device[i].negstate = syncneg_start;
@@ -1374,7 +1414,7 @@
 	outb(info->scsi.cfg[2], REG_CNTL3(info));
 	outb(info->ifcfg.select_timeout, REG_STIM(info));
 	outb(0, REG_SOF(info));
-	outb(fas216_syncperiod(info->ifcfg.asyncperiod), REG_STP(info));
+	outb(fas216_syncperiod(info, info->ifcfg.asyncperiod), REG_STP(info));
 	outb(info->scsi.cfg[0], REG_CNTL1(info));
 }
 
@@ -1465,7 +1505,7 @@
 	info->host = instance;
 	info->scsi.cfg[0] = instance->this_id;
 	info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE;
-	info->scsi.cfg[2] = CNTL3_ADDIDCHK | CNTL3_G2CB | CNTL3_FASTSCSI | CNTL3_FASTCLK;
+	info->scsi.cfg[2] = CNTL3_ADIDCHK | CNTL3_G2CB | CNTL3_FASTSCSI | CNTL3_FASTCLK;
 	info->scsi.type = "unknown";
 	info->SCpnt = NULL;
 	fas216_reset_state(info);
@@ -1500,7 +1540,7 @@
 	}
 
 
-	outb(CNTL3_IDENABLE, REG_CNTL3(info));
+	outb(CNTL3_ADIDCHK, REG_CNTL3(info));
 	outb(0, REG_CNTL3(info));
 
 	outb(CMD_RESETCHIP, REG_CMD(info));
@@ -1562,6 +1602,11 @@
 EXPORT_SYMBOL(fas216_command);
 EXPORT_SYMBOL(fas216_intr);
 EXPORT_SYMBOL(fas216_release);
+EXPORT_SYMBOL(fas216_eh_abort);
+EXPORT_SYMBOL(fas216_eh_device_reset);
+EXPORT_SYMBOL(fas216_eh_bus_reset);
+EXPORT_SYMBOL(fas216_eh_host_reset);
+
 
 #ifdef MODULE
 int init_module (void)
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/fas216.h linux/drivers/acorn/scsi/fas216.h
--- v2.1.93/linux/drivers/acorn/scsi/fas216.h	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/scsi/fas216.h	Wed Apr  8 15:51:32 1998
@@ -196,7 +196,7 @@
 typedef enum {
 	syncneg_start,					/* Negociate with device for Sync xfers	*/
 	syncneg_sent,					/* Sync Xfer negociation sent		*/
-	syncnsg_complete				/* Sync Xfer complete			*/
+	syncneg_complete				/* Sync Xfer complete			*/
 } syncneg_t;
 
 typedef struct {
@@ -277,81 +277,82 @@
 	int			internal_done;		/* flag to indicate request done */
 } FAS216_Info;
 
-/*
- * Function: int fas216_init (struct Scsi_Host *instance)
- *
+/* Function: int fas216_init (struct Scsi_Host *instance)
  * Purpose : initialise FAS/NCR/AMD SCSI ic.
- *
  * Params  : instance - a driver-specific filled-out structure
- *
  * Returns : 0 on success
  */
 extern int fas216_init (struct Scsi_Host *instance);
 
-/*
- * Function: int fas216_abort (Scsi_Cmnd *SCpnt)
- *
+/* Function: int fas216_abort (Scsi_Cmnd *SCpnt)
  * Purpose : abort a command if something horrible happens.
- *
  * Params  : SCpnt - Command that is believed to be causing a problem.
- *
  * Returns : one of SCSI_ABORT_ macros.
  */
 extern int fas216_abort (Scsi_Cmnd *);
 
-/*
- * Function: int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
- *
+/* Function: int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
  * Purpose : resets the adapter if something horrible happens.
- *
  * Params  : SCpnt - Command that is believed to be causing a problem.
  *	     reset_flags - flags indicating reset type that is believed to be required.
- *
  * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET macros.
  */
 extern int fas216_reset (Scsi_Cmnd *, unsigned int);
 
-/*
- * Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
- *
+/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
  * Purpose : queue a command for adapter to process.
- *
  * Params  : SCpnt - Command to queue
  *	     done  - done function to call once command is complete
- *
  * Returns : 0 - success, else error
  */
 extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 
-/*
- * Function: int fas216_command (Scsi_Cmnd *SCpnt)
- *
+/* Function: int fas216_command (Scsi_Cmnd *SCpnt)
  * Purpose : queue a command for adapter to process.
- *
  * Params  : SCpnt - Command to queue
- *
  * Returns : scsi result code
  */
 extern int fas216_command (Scsi_Cmnd *);
 
-/*
- * Function: void fas216_intr (struct Scsi_Host *instance)
- *
+/* Function: void fas216_intr (struct Scsi_Host *instance)
  * Purpose : handle interrupts from the interface to progress a command
- *
  * Params  : instance - interface to service
  */
 extern void fas216_intr (struct Scsi_Host *instance);
 
-/*
- * Function: int fas216_release (struct Scsi_Host *instance)
- *
+/* Function: int fas216_release (struct Scsi_Host *instance)
  * Purpose : release all resources and put everything to bed for FAS/NCR/AMD SCSI ic.
- *
  * Params  : instance - a driver-specific filled-out structure
- *
  * Returns : 0 on success
  */
 extern int fas216_release (struct Scsi_Host *instance);
+
+/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+ * Purpose : abort this command
+ * Params  : SCpnt - command to abort
+ * Returns : FAILED if unable to abort
+ */
+extern int fas216_eh_abort(Scsi_Cmnd *SCpnt);
+
+/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the device associated with this command
+ * Params  : SCpnt - command specifing device to reset
+ * Returns : FAILED if unable to reset
+ */
+extern int fas216_eh_device_reset(Scsi_Cmnd *SCpnt);
+
+/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the complete bus associated with this command
+ * Params  : SCpnt - command specifing bus to reset
+ * Returns : FAILED if unable to reset
+ */
+extern int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt);
+
+/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the host associated with this command
+ * Params  : SCpnt - command specifing host to reset
+ * Returns : FAILED if unable to reset
+ */
+extern int fas216_eh_host_reset(Scsi_Cmnd *SCpnt);
 
 #endif /* FAS216_H */
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/oak.c linux/drivers/acorn/scsi/oak.c
--- v2.1.93/linux/drivers/acorn/scsi/oak.c	Tue Mar 10 10:03:31 1998
+++ linux/drivers/acorn/scsi/oak.c	Wed Apr  8 15:51:32 1998
@@ -33,6 +33,12 @@
 
 /*
  * $Log: oak.c,v $
+ * Revision 1.2  1998/03/08 05:49:48  davem
+ * Merge to 2.1.89
+ *
+ * Revision 1.1  1998/02/23 02:45:27  davem
+ * Merge to 2.1.88
+ *
  */
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/oak.h linux/drivers/acorn/scsi/oak.h
--- v2.1.93/linux/drivers/acorn/scsi/oak.h	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/scsi/oak.h	Wed Apr  8 15:51:32 1998
@@ -23,7 +23,10 @@
  */
 
 /*
- * $Log: oak_NCR5380.h,v $
+ * $Log: oak.h,v $
+ * Revision 1.1  1998/02/23 02:45:27  davem
+ * Merge to 2.1.88
+ *
  */
 
 #ifndef OAK_NCR5380_H
diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/powertec.h linux/drivers/acorn/scsi/powertec.h
--- v2.1.93/linux/drivers/acorn/scsi/powertec.h	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/scsi/powertec.h	Wed Apr  8 15:51:32 1998
@@ -53,7 +53,13 @@
 this_id:	SCSI_ID,		/* scsi host id		*/	\
 sg_tablesize:	SG_ALL,			/* sg_tablesize		*/	\
 cmd_per_lun:	CMD_PER_LUN,		/* cmd per lun		*/	\
-use_clustering:	ENABLE_CLUSTERING					\
+use_clustering:	ENABLE_CLUSTERING,					\
+eh_strategy_handler:		NULL,					\
+eh_host_reset_handler:		fas216_eh_host_reset,			\
+eh_bus_reset_handler:		fas216_eh_bus_reset,			\
+eh_device_reset_handler:	fas216_eh_device_reset,			\
+eh_abort_handler:		fas216_eh_abort,			\
+use_new_eh_code:		0					\
 	}
 
 #ifndef HOSTS_C
diff -u --recursive --new-file v2.1.93/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c
--- v2.1.93/linux/drivers/block/ide-proc.c	Mon Apr  6 17:40:59 1998
+++ linux/drivers/block/ide-proc.c	Tue Apr  7 07:48:54 1998
@@ -254,11 +254,13 @@
 static int proc_ide_read_config
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	ide_hwif_t	*hwif = (ide_hwif_t *)data;
 	char		*out = page;
-	int		len, reg = 0;
+	int		len;
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
+	ide_hwif_t	*hwif = (ide_hwif_t *)data;
+	int		reg = 0;
+
 	struct pci_dev *dev = hwif->pci_dev;
 
 	out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n",
diff -u --recursive --new-file v2.1.93/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.1.93/linux/drivers/char/Config.in	Tue Mar 17 22:18:14 1998
+++ linux/drivers/char/Config.in	Wed Apr  8 17:24:48 1998
@@ -117,6 +117,13 @@
     dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV
   fi
   dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
+  #dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
+  if [ "$CONFIG_VIDEO_SAA5249" != "n" ]; then
+	define_bool CONFIG_BUS_I2C $CONFIG_VIDEO_SAA5249
+  fi
+  if [ "$CONFIG_VIDEO_BT848" != "n" ]; then
+	define_bool CONFIG_BUS_I2C $CONFIG_VIDEO_BT848
+  fi
 fi
 tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'PC joystick support' CONFIG_JOYSTICK
diff -u --recursive --new-file v2.1.93/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.93/linux/drivers/char/Makefile	Mon Apr  6 17:40:59 1998
+++ linux/drivers/char/Makefile	Wed Apr  8 17:24:48 1998
@@ -302,11 +302,27 @@
   endif
 endif
 
+ifeq ($(CONFIG_BUS_I2C),y)
+	LX_OBJS += i2c.o
+else
+  ifeq ($(CONFIG_BUS_I2C),m)
+	MX_OBJS += i2c.o
+  endif
+endif
+
 ifeq ($(CONFIG_VIDEO_BT848),y)
-L_OBJS += bttv.o
+L_OBJS += bttv.o msp3400.o tuner.o
 else
   ifeq ($(CONFIG_VIDEO_BT848),m)
-    M_OBJS += bttv.o
+    M_OBJS += bttv.o msp3400.o tuner.o
+  endif
+endif
+
+ifeq ($(CONFIG_VIDEO_SAA5249),y)
+L_OBJS += saa5249.o
+else
+  ifeq ($(CONFIG_VIDEO_SAA5249),m)
+    M_OBJS += saa5249.o
   endif
 endif
 
@@ -330,7 +346,7 @@
 L_OBJS += pms.o
 else
   ifeq ($(CONFIG_VIDEO_PMS),m)
-    M_OBJS += pms.o
+  M_OBJS += pms.o
   endif
 endif
 
diff -u --recursive --new-file v2.1.93/linux/drivers/char/bt848.h linux/drivers/char/bt848.h
--- v2.1.93/linux/drivers/char/bt848.h	Sat Nov 29 10:33:19 1997
+++ linux/drivers/char/bt848.h	Wed Apr  8 17:24:48 1998
@@ -1,7 +1,7 @@
 /* 
     bt848.h - Bt848 register offsets
 
-    Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+    Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -22,13 +22,15 @@
 #define _BT848_H_
 
 #ifndef PCI_VENDOR_ID_BROOKTREE
-#define PCI_VENDOR_ID_BROOKTREE 0x109e
+#define PCI_VENDOR_ID_BROOKTREE 0x109e 
 #endif
 #ifndef PCI_DEVICE_ID_BT848
-#define PCI_DEVICE_ID_BT848     0x350
+#define PCI_DEVICE_ID_BT848     0x350	
+#endif
+#ifndef PCI_DEVICE_ID_BT849
+#define PCI_DEVICE_ID_BT849     0x351
 #endif
 
-#define RISCMEM_LEN 131040
 
 /* Brooktree 848 registers */
 
diff -u --recursive --new-file v2.1.93/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.1.93/linux/drivers/char/bttv.c	Mon Feb 23 18:12:04 1998
+++ linux/drivers/char/bttv.c	Wed Apr  8 17:24:48 1998
@@ -1,7 +1,8 @@
 /* 
     bttv - Bt848 frame grabber driver
 
-    Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+                           & Marcus Metzler (mocm@thp.uni-koeln.de)
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -20,10 +21,20 @@
     Modified to put the RISC code writer in the kernel and to fit a
     common (and I hope safe) kernel interface. When we have an X extension
     all will now be really sweet.
+ 
+    TODO:  
+   
+    * think of some good ioctls for Video4Linux to handle 
+      YUV, planar YUV, ...  grabs and sell them to AC :-)
+    * move norm from tuner to channel struct!?
+      composite source from a satellite tuner can deliver different norms
+      depending on tuned channel
+    * mmap VBI data?
 */
 
 #include <linux/module.h>
 #include <linux/bios32.h>
+#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -39,21 +50,31 @@
 #include <linux/sched.h>
 #include <asm/segment.h>
 #include <linux/types.h>
-#include <linux/videodev.h>
+#include <linux/wrapper.h>
 
+#include <linux/videodev.h>
 #include <linux/version.h>
 #include <asm/uaccess.h>
 
+#include "i2c.h"
 #include "bttv.h"
 #include "tuner.h"
 
 #define DEBUG(x)		/* Debug driver */	
-#define IDEBUG(x)		/* Debug interrupt handler */
+#define IDEBUG(x) 		/* Debug interrupt handler */
 
-static unsigned int remap=0;
-static unsigned int vidmem=0;
-static unsigned int tuner=0;	/* Default tuner */
-MODULE_PARM(tuner,"i");
+static unsigned int remap=0;    /* remap Bt848 */
+static unsigned int vidmem=0;   /* manually set video mem address */
+static int triton1=0;
+static int radio=0;
+
+static unsigned int card=0;
+
+MODULE_PARM(remap,"i");
+MODULE_PARM(vidmem,"i");
+MODULE_PARM(triton1,"i");
+MODULE_PARM(radio,"i");
+MODULE_PARM(card,"i");
 
 static int find_vga(void);
 static void bt848_set_risc_jmps(struct bttv *btv);
@@ -61,17 +82,21 @@
 /* Anybody who uses more than four? */
 #define BTTV_MAX 4
 
-static int bttv_num;
+static int bttv_num;			/* number of Bt848s in use */
 static struct bttv bttvs[BTTV_MAX];
 
 #define I2C_TIMING (0x7<<4)
 #define I2C_COMMAND (I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA)
 
+#define I2C_DELAY   10
+#define I2C_SET(CTRL,DATA) \
+    { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); }
+#define I2C_GET()   (btread(BT848_I2C)&1)
+
 #define AUDIO_MUTE_DELAY 10000
 #define FREQ_CHANGE_DELAY 20000
 #define EEPROM_WRITE_DELAY 20000
 
-
 /*******************************/
 /* Memory management functions */
 /*******************************/
@@ -79,56 +104,137 @@
 /* convert virtual user memory address to physical address */
 /* (virt_to_phys only works for kmalloced kernel memory) */
 
-static inline ulong uvirt_to_phys(ulong adr)
+static inline unsigned long uvirt_to_phys(unsigned long adr)
 {
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *ptep, pte;
   
-/*  printk("adr: 0x%08x\n",adr);*/
 	pgd = pgd_offset(current->mm, adr);
-/*  printk("pgd: 0x%08x\n",pgd);*/
 	if (pgd_none(*pgd))
 		return 0;
 	pmd = pmd_offset(pgd, adr);
-/*  printk("pmd: 0x%08x\n",pmd); */
 	if (pmd_none(*pmd))
 		return 0;
-	ptep = pte_offset(pmd, adr&(~PGDIR_MASK));
+	ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
 	pte = *ptep;
 	if(pte_present(pte))
-		return (pte_page(pte)|(adr&(PAGE_SIZE-1)));
+		return 
+		  virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
 	return 0;
 }
 
+static inline unsigned long uvirt_to_bus(unsigned long adr) 
+{
+	/*  printk("adr: 0x%8x, ",adr);
+	printk("phys: 0x%8x, ",(uvirt_to_phys(adr)));
+	printk("bus: 0x%8x\n",virt_to_bus(phys_to_virt(uvirt_to_phys(adr))));
+	*/
+	return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
+}
+
 /* convert virtual kernel memory address to physical address */
 /* (virt_to_phys only works for kmalloced kernel memory) */
 
-static inline ulong kvirt_to_phys(ulong adr) 
+static inline unsigned long kvirt_to_phys(unsigned long adr) 
 {
 	return uvirt_to_phys(VMALLOC_VMADDR(adr));
 }
 
-static inline ulong kvirt_to_bus(ulong adr) 
+static inline unsigned long kvirt_to_bus(unsigned long adr) 
 {
-	return virt_to_bus(phys_to_virt(kvirt_to_phys(adr)));
+	return uvirt_to_bus(VMALLOC_VMADDR(adr));
 }
 
+static void * rvmalloc(unsigned long size)
+{
+	void * mem;
+	unsigned long adr, page;
+        
+	mem=vmalloc(size);
+	if (mem) 
+	{
+	        adr=(unsigned long) mem;
+		while (size > 0) 
+                {
+	                page = kvirt_to_phys(adr);
+			mem_map_reserve(MAP_NR(phys_to_virt(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+	}
+	return mem;
+}
 
-/*****************/
-/* I2C functions */
-/*****************/
+static void rvfree(void * mem, unsigned long size)
+{
+        unsigned long adr, page;
+        
+	if (mem) 
+	{
+	        adr=(unsigned long) mem;
+		while (size > 0) 
+                {
+	                page = kvirt_to_phys(adr);
+			mem_map_unreserve(MAP_NR(phys_to_virt(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
 
-static int I2CRead(struct bttv *btv, int addr)
+/*
+ *	Create the giant waste of buffer space we need for now
+ *	until we get DMA to user space sorted out (probably 2.3.x)
+ *
+ *	We only create this as and when someone uses mmap
+ */
+ 
+static int fbuffer_alloc(struct bttv *btv)
+{
+	if(!btv->fbuffer)
+		btv->fbuffer=(unsigned char *) rvmalloc(2*0x144000);
+	else
+		printk(KERN_ERR "bttv: Double alloc of fbuffer!\n");
+	if(!btv->fbuffer)
+		return -ENOBUFS;
+	return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions                                                           */
+
+/* software I2C functions */
+
+static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data)
+{
+        struct bttv *btv = (struct bttv*)bus->data;
+	btwrite((ctrl<<1)|data, BT848_I2C);
+	udelay(I2C_DELAY);
+}
+
+static int i2c_getdataline(struct i2c_bus *bus)
+{
+        struct bttv *btv = (struct bttv*)bus->data;
+	return btread(BT848_I2C)&1;
+}
+
+/* hardware I2C functions */
+
+/* read I2C */
+static int I2CRead(struct i2c_bus *bus, unsigned char addr) 
 {
 	u32 i;
 	u32 stat;
+	struct bttv *btv = (struct bttv*)bus->data;
   
 	/* clear status bit ; BT848_INT_RACK is ro */
 	btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
   
 	btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C);
-
+  
 	/*
 	 * Timeout for I2CRead is 1 second (this should be enough, really!)
 	 */
@@ -136,11 +242,12 @@
 	{
 		stat=btread(BT848_INT_STAT);
 		if (stat & BT848_INT_I2CDONE)
-			break;
-		udelay(1000); /* 1ms, as I2C is 1kHz (?) */
+                        break;
+                udelay(1000);
 	}
   
-	if (!i) {
+	if (!i) 
+	{
 		printk(KERN_DEBUG "bttv: I2CRead timeout\n");
 		return -1;
 	}
@@ -153,12 +260,13 @@
 
 /* set both to write both bytes, reset it to write only b1 */
 
-static int I2CWrite(struct bttv *btv, unchar addr, unchar b1,
-		    unchar b2, int both)
+static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1,
+		    unsigned char b2, int both)
 {
 	u32 i;
 	u32 data;
 	u32 stat;
+	struct bttv *btv = (struct bttv*)bus->data;
   
 	/* clear status bit; BT848_INT_RACK is ro */
 	btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
@@ -172,15 +280,16 @@
   
 	btwrite(data, BT848_I2C);
 
-	for (i=1000; i; i--)
+	for (i=0x1000; i; i--)
 	{
 		stat=btread(BT848_INT_STAT);
 		if (stat & BT848_INT_I2CDONE)
 			break;
-		udelay(1000);
+                udelay(1000);
 	}
   
-	if (!i) {
+	if (!i) 
+	{
 		printk(KERN_DEBUG "bttv: I2CWrite timeout\n");
 		return -1;
 	}
@@ -190,19 +299,20 @@
 	return 0;
 }
 
-static void readee(struct bttv *btv, unchar *eedata)
+/* read EEPROM */
+static void readee(struct i2c_bus *bus, unsigned char *eedata)
 {
 	int i, k;
-  
-	if (I2CWrite(btv, 0xa0, 0, -1, 0)<0)
+        
+	if (I2CWrite(bus, 0xa0, 0, -1, 0)<0)
 	{
 		printk(KERN_WARNING "bttv: readee error\n");
 		return;
 	}
-
+        
 	for (i=0; i<256; i++)
 	{
-		k=I2CRead(btv, 0xa1);
+		k=I2CRead(bus, 0xa1);
 		if (k<0)
 		{
 			printk(KERN_WARNING "bttv: readee error\n");
@@ -212,13 +322,14 @@
 	}
 }
 
-static void writeee(struct bttv *btv, unchar *eedata)
+/* write EEPROM */
+static void writeee(struct i2c_bus *bus, unsigned char *eedata)
 {
 	int i;
   
 	for (i=0; i<256; i++)
 	{
-		if (I2CWrite(btv, 0xa0, i, eedata[i], 1)<0)
+		if (I2CWrite(bus, 0xa0, i, eedata[i], 1)<0)
 		{
 			printk(KERN_WARNING "bttv: writeee error (%d)\n", i);
 			break;
@@ -227,28 +338,91 @@
 	}
 }
 
+void attach_inform(struct i2c_bus *bus, int id)
+{
+        struct bttv *btv = (struct bttv*)bus->data;
+	int tunertype;
+        
+	switch (id) 
+        {
+        	case I2C_DRIVERID_MSP3400:
+                	btv->have_msp3400 = 1;
+			break;
+        	case I2C_DRIVERID_TUNER:
+			btv->have_tuner = 1;
+			if (btv->type == BTTV_MIRO) 
+			{
+				tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+				i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
+					TUNER_SET_TYPE,&tunertype);
+			}
+			break;
+	}
+}
+
+void detach_inform(struct i2c_bus *bus, int id)
+{
+        struct bttv *btv = (struct bttv*)bus->data;
+
+	switch (id) 
+	{
+		case I2C_DRIVERID_MSP3400:
+		        btv->have_msp3400 = 0;
+			break;
+		case I2C_DRIVERID_TUNER:
+			btv->have_tuner = 0;
+			break;
+	}
+}
+
+static struct i2c_bus bttv_i2c_bus_template = 
+{
+        "bt848",
+        I2C_BUSID_BT848,
+	NULL,
+
+	SPIN_LOCK_UNLOCKED,
+
+	attach_inform,
+	detach_inform,
+	
+	i2c_setlines,
+	i2c_getdataline,
+	I2CRead,
+	I2CWrite,
+};
+ 
+/* ----------------------------------------------------------------------- */
+
 /*
- *	Tuner, internal, external and mute 
+ *	Tuner, Radio, internal, external and mute 
  */
  
-static unchar audiomuxs[][4] = 
+static unsigned char audiomuxs[][5] = 
 {
-	{ 0x00, 0x00, 0x00, 0x00}, /* unknown */
-	{ 0x02, 0x00, 0x00, 0x0a}, /* MIRO */
-	{ 0x00, 0x02, 0x03, 0x04}, /* Hauppauge */
-	{ 0x04, 0x02, 0x03, 0x01}, /* STB */
-	{ 0x01, 0x02, 0x03, 0x04}, /* Intel??? */
-	{ 0x01, 0x02, 0x03, 0x04}, /* Diamond DTV2000??? */
+	{ 0x00, 0x00, 0x00, 0x00, 0x00}, /* unknown */
+	{ 0x02, 0x00, 0x00, 0x00, 0x0a}, /* MIRO */
+	{ 0x00, 0x01, 0x02, 0x03, 0x04}, /* Hauppauge */
+	{ 0x04, 0x00, 0x02, 0x03, 0x01}, /* STB */
+	{ 0x00, 0x01, 0x02, 0x03, 0x04}, /* Intel??? */
+	{ 0x00, 0x01, 0x02, 0x03, 0x04}, /* Diamond DTV2000 */
+	{ 0x0c, 0x00, 0x0b, 0x0b, 0x00}, /* AVerMedia TVPhone */
 };
 
 static void audio(struct bttv *btv, int mode)
 {
+        /* enable least significant GPIO output nibble */
 	btwrite(0x0f, BT848_GPIO_OUT_EN);
+
+        /* select direct input */
 	btwrite(0x00, BT848_GPIO_REG_INP);
 
 	switch (mode)
 	{
-		case AUDIO_UNMUTE:
+	        case AUDIO_MUTE:
+                        btv->audio|=AUDIO_MUTE;
+			break;
+ 		case AUDIO_UNMUTE:
 			btv->audio&=~AUDIO_MUTE;
 			mode=btv->audio;
 			break;
@@ -263,8 +437,12 @@
 			btv->audio|=mode;
 			break;
 	}
-	if ((btv->audio&AUDIO_MUTE) || !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
-		mode=AUDIO_OFF;
+        /* if audio mute or not in H-lock, turn audio off */
+	if ((btv->audio&AUDIO_MUTE) || 
+	    (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)))
+	        mode=AUDIO_OFF;
+        if ((mode == 0) && (btv->radio))
+		mode = 1;
 	btaor(audiomuxs[btv->type][mode] , ~0x0f, BT848_GPIO_DATA);
 }
 
@@ -319,11 +497,19 @@
 
 #define VBIBUF_SIZE 65536
 
+/* Maximum sample number per VBI line is 2044, can NTSC deliver this? 
+   Note that we write 2048-aligned to keep alignment to memory pages 
+*/
+#define VBI_SPL 2044
+
+/* RISC command to write one VBI data line */
+#define VBI_RISC BT848_RISC_WRITE|VBI_SPL|BT848_RISC_EOL|BT848_RISC_SOL
+
 static void make_vbitab(struct bttv *btv)
 {
 	int i;
-	dword *po=(dword *) btv->vbi_odd;
-	dword *pe=(dword *) btv->vbi_even;
+	unsigned int *po=(unsigned int *) btv->vbi_odd;
+	unsigned int *pe=(unsigned int *) btv->vbi_even;
   
 	DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd));
 	DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even));
@@ -333,8 +519,8 @@
 	*(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0;
 	for (i=0; i<16; i++) 
 	{
-		*(po++)=BT848_RISC_WRITE|2044|BT848_RISC_EOL|BT848_RISC_SOL|(13<<20);
-		*(po++)=kvirt_to_bus((ulong)btv->vbibuf+i*2048);
+		*(po++)=VBI_RISC;
+		*(po++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048);
 	}
 	*(po++)=BT848_RISC_JUMP;
 	*(po++)=virt_to_bus(btv->risc_jmp+4);
@@ -342,11 +528,129 @@
 	*(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0;
 	for (i=16; i<32; i++) 
 	{
-		*(pe++)=BT848_RISC_WRITE|2044|BT848_RISC_EOL|BT848_RISC_SOL;
-		*(pe++)=kvirt_to_bus((ulong)btv->vbibuf+i*2048);
+		*(pe++)=VBI_RISC;
+		*(pe++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048);
 	}
 	*(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16);
 	*(pe++)=virt_to_bus(btv->risc_jmp+10);
+	DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po));
+	DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe));
+}
+
+int fmtbppx2[16] = {
+        8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 
+};
+
+static int  make_vrisctab(struct bttv *btv, unsigned int *ro, unsigned int *re, 
+	unsigned int *vbuf, unsigned short width, unsigned short height, unsigned short fmt)
+{
+        unsigned long line;
+	unsigned long bpl;  /* bytes per line */
+	unsigned long bl;
+	unsigned long todo;
+	unsigned int **rp;
+	int inter;
+	unsigned long vadr=(unsigned long) vbuf;
+
+	inter = (height>btv->win.cropheight/2) ? 1 : 0;
+	bpl=width*fmtbppx2[fmt&0xf]/2;
+	
+	*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
+	*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+  
+	for (line=0; line < (height<<(1^inter)); line++)
+	{
+	        if (inter) 
+		        rp= (line&1) ? &re : &ro;
+		else 
+	                rp= (line>height) ? &re : &ro; 
+
+		bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr);
+		if (bpl<=bl)
+                {
+		        *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|
+			        BT848_RISC_EOL|bpl; 
+			*((*rp)++)=kvirt_to_bus(vadr);
+			vadr+=bpl;
+		}
+		else
+		{
+		        todo=bpl;
+		        *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|bl;
+			*((*rp)++)=kvirt_to_bus(vadr);
+			vadr+=bl;
+			todo-=bl;
+			while (todo>PAGE_SIZE)
+			{
+			        *((*rp)++)=BT848_RISC_WRITE|PAGE_SIZE;
+				*((*rp)++)=kvirt_to_bus(vadr);
+				vadr+=PAGE_SIZE;
+				todo-=PAGE_SIZE;
+			}
+			*((*rp)++)=BT848_RISC_WRITE|BT848_RISC_EOL|todo;
+			*((*rp)++)=kvirt_to_bus(vadr);
+			vadr+=todo;
+		}
+	}
+	
+	*(ro++)=BT848_RISC_JUMP;
+	*(ro++)=btv->bus_vbi_even;
+	*(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16);
+	*(re++)=btv->bus_vbi_odd;
+	
+	return 0;
+}
+
+/* does this really make a difference ???? */
+#define BURST_MAX 4096
+
+static inline void write_risc_segment(unsigned int **rp, unsigned long line_adr, unsigned int command,
+			int *x, uint dx, uint bpp, uint width)
+{
+        unsigned int flags, len;
+  
+	if (!dx)
+                return;
+	len=dx*bpp;
+
+#ifdef LIMIT_DMA
+	if (command==BT848_RISC_WRITEC)
+	{
+                unsigned int dx2=BURST_MAX/bpp;
+		while (len>BURST_MAX)
+		{
+	                write_risc_segment(rp, line_adr, command,
+					   &x,dx2, bpp, width);
+			dx-=dx2;
+			len=dx*bpp;
+		}
+	}
+#endif
+
+	/* mask upper 8 bits for 24+8 bit overlay modes */
+	flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0);
+	
+	if (*x==0) 
+	{
+                if (command==BT848_RISC_SKIP) 
+		{
+	                if (dx<width)
+			{
+		                flags|=BT848_RISC_BYTE_ALL;
+				command=BT848_RISC_WRITE;
+			}
+		}
+		else
+	                if (command==BT848_RISC_WRITEC)
+                                command=BT848_RISC_WRITE;
+		flags|=BT848_RISC_SOL;
+        }
+	if (*x+dx==width)
+                flags|=BT848_RISC_EOL;
+	*((*rp)++)=command|flags|len;
+	if (command==BT848_RISC_WRITE)
+                *((*rp)++)=line_adr+*x*bpp;
+	*x+=dx;
 }
 
 /*
@@ -358,237 +662,264 @@
  *	www.brooktree.com - nicely done those folks.
  */
  
-static void bt848_set_size(struct bttv *btv)
+struct tvnorm 
+{
+        u16 cropwidth, cropheight;
+	u16 totalwidth;
+	u8 adelay, bdelay, iform;
+	u32 scaledtwidth;
+	u16 hdelayx1, hactivex1;
+	u16 vdelay;
+};
+
+static struct tvnorm tvnorms[] = {
+	/* PAL-BDGHI */
+        { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+	    944, 186, 922, 0x20},
+	/* NTSC */
+	{ 640, 480,  910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+	    780, 135, 754, 0x16},
+	/* SECAM */
+	{ 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
+	    944, 186, 922, 0x20},
+	/* PAL-M */
+	{ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+	    780, 186, 922, 0x16},
+	/* PAL-N */
+	{ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
+	    944, 186, 922, 0x20},
+};
+#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
+
+
+/* set geometry for even/odd frames 
+   just if you are wondering:
+   handling of even and odd frames will be separated, e.g. for grabbing
+   the even ones as RGB into videomem and the others as YUV in main memory for 
+   compressing and sending to the video conferencing partner.
+
+*/
+static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc, 
+				   u16 hscale, u16 vscale,
+				   u16 hactive, u16 vactive,
+				   u16 hdelay, u16 vdelay,
+				   u8 crop)
+{
+        int off = odd ? 0x80 : 0x00;
+  
+	btwrite(vtc, BT848_E_VTC+off);
+	btwrite(hscale>>8, BT848_E_HSCALE_HI+off);
+	btwrite(hscale&0xff, BT848_E_HSCALE_LO+off);
+	btaor((vscale>>8), 0xc0, BT848_E_VSCALE_HI+off);
+	btwrite(vscale&0xff, BT848_E_VSCALE_LO+off);
+	btwrite(hactive&0xff, BT848_E_HACTIVE_LO+off);
+	btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off);
+	btwrite(vactive&0xff, BT848_E_VACTIVE_LO+off);
+	btwrite(vdelay&0xff, BT848_E_VDELAY_LO+off);
+	btwrite(crop, BT848_E_CROP+off);
+}
+
+
+static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
 {
-	u16 vscale, hscale;
+        u16 vscale, hscale;
 	u32 xsf, sr;
 	u16 hdelay, vdelay;
 	u16 hactive, vactive;
 	u16 inter;
-	u8 crop;
-
-	/*
-	 *	No window , no try...
-	 */
-	 
-	if (!btv->win.width)
-		return;
-	if (!btv->win.height)
-		return;
-    
-	inter=(btv->win.interlace&1)^1;
+	u8 crop, vtc;  
+	struct tvnorm *tvn;
+ 	
+	if (!width || !height)
+	        return;
 
-	switch (btv->win.bpp) 
-	{
-		/*
-		 * RGB8 seems to be a 9x5x5 GRB color cube starting at color 16
-		 * Why the h... can't they even mention this in the datasheet???
-		 */
-		case 1: 
-			btwrite(BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT);
-			btand(~0x10, BT848_CAP_CTL);  /* Dithering looks much better in this mode */
-			break;
-		case 2: 
-			btwrite(BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT);
-			btor(0x10, BT848_CAP_CTL);
-			break;
-		case 3: 
-			btwrite(BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT);
-			btor(0x10, BT848_CAP_CTL);
-			break;
-		case 4: 
-			btwrite(BT848_COLOR_FMT_RGB32, BT848_COLOR_FMT);
-			btor(0x10, BT848_CAP_CTL);
-			break;
-	}
+	tvn=&tvnorms[btv->win.norm];
 	
-	/*
-	 *	Set things up according to the final picture width.
-	 */
-	 
-	hactive=btv->win.width;
-	if (hactive < 193) 
-	{
-		btwrite (2, BT848_E_VTC);
-		btwrite (2, BT848_O_VTC);
-	}
-	else if (hactive < 385) 
-	{
-		btwrite (1, BT848_E_VTC);
-		btwrite (1, BT848_O_VTC);
-	}
-	else 
-	{
-		btwrite (0, BT848_E_VTC);
-		btwrite (0, BT848_O_VTC);
-	}
+	if (btv->win.cropwidth>tvn->cropwidth)
+                btv->win.cropwidth=tvn->cropwidth;
+	if (btv->win.cropheight>tvn->cropheight)
+	        btv->win.cropheight=tvn->cropheight;
+
+	if (width>btv->win.cropwidth)
+                width=btv->win.cropwidth;
+	if (height>btv->win.cropheight)
+	        height=btv->win.cropheight;
+
+	btwrite(tvn->adelay, BT848_ADELAY);
+	btwrite(tvn->bdelay, BT848_BDELAY);
+	btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM);
+
+	btwrite(fmt, BT848_COLOR_FMT);
+	hactive=width;
+
+        vtc=0;
+	/* Some people say interpolation looks bad ... */
+	/* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */
+     
+	btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0;
+	inter=(btv->win.interlace&1)^1;
+	xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth;
+	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
+	vdelay=btv->win.cropy+tvn->vdelay;
+
+	hdelay=(tvn->hdelayx1*tvn->scaledtwidth)/tvn->totalwidth;
+	hdelay=((hdelay+btv->win.cropx)*hactive)/btv->win.cropwidth;
+	hdelay&=0x3fe;
 
-	/*
-	 *	Ok are we doing Never The Same Color or PAL ?
-	 */
-	 
-	if (btv->win.norm==1) 
-	{ 
-		btv->win.cropwidth=640;
-		btv->win.cropheight=480;
-		btwrite(0x68, BT848_ADELAY);
-		btwrite(0x5d, BT848_BDELAY);
-		btaor(BT848_IFORM_NTSC, ~7, BT848_IFORM);
-		btaor(BT848_IFORM_XT0, ~0x18, BT848_IFORM);
-		xsf = (btv->win.width*365625UL)/300000UL;
-		hscale = ((910UL*4096UL)/xsf-4096);
-		vdelay=btv->win.cropy+0x16;
-		hdelay=((hactive*135)/754+btv->win.cropx)&0x3fe;
-	}
-	else
-	{
-		btv->win.cropwidth=768;
-		btv->win.cropheight=576;
-		if (btv->win.norm==0)
-		{ 
-			btwrite(0x7f, BT848_ADELAY);
-			btwrite(0x72, BT848_BDELAY);
-			btaor(BT848_IFORM_PAL_BDGHI, ~BT848_IFORM_NORM, BT848_IFORM);
-		}
-		else
-		{
-			btwrite(0x7f, BT848_ADELAY);
-			btwrite(0x00, BT848_BDELAY);
-			btaor(BT848_IFORM_SECAM, ~BT848_IFORM_NORM, BT848_IFORM);
-		}
-		btaor(BT848_IFORM_XT1, ~0x18, BT848_IFORM);
-		xsf = (btv->win.width*36875UL)/30000UL;
-		hscale = ((1135UL*4096UL)/xsf-4096);
-		vdelay=btv->win.cropy+0x20;
-		hdelay=((hactive*186)/922+btv->win.cropx)&0x3fe;
-	}
-	sr=((btv->win.cropheight>>inter)*512)/btv->win.height-512;
+	sr=((btv->win.cropheight>>inter)*512)/height-512;
 	vscale=(0x10000UL-sr)&0x1fff;
 	vactive=btv->win.cropheight;
+	crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
+	        ((vactive>>4)&0x30)|((vdelay>>2)&0xc0);
+	vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
+	
+	bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive,
+			hdelay, vdelay, crop);
+	bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive,
+			hdelay, vdelay, crop);
+	
+}
 
-#if 0
-	printk("bttv: hscale=0x%04x, ",hscale);
-	printk("bttv: vscale=0x%04x\n",vscale);
-
-	printk("bttv: hdelay =0x%04x\n",hdelay);
-	printk("bttv: hactive=0x%04x\n",hactive);
-	printk("bttv: vdelay =0x%04x\n",vdelay);
-	printk("bttv: vactive=0x%04x\n",vactive);
-#endif
 
-	/*
-	 *	Interlace is set elsewhere according to the final image 
-	 *	size we desire
-	 */
-	 
-	if (btv->win.interlace) 
-	{ 
-		btor(BT848_VSCALE_INT, BT848_E_VSCALE_HI);
-		btor(BT848_VSCALE_INT, BT848_O_VSCALE_HI);
-	}
-	else
+int bpp2fmt[4] = {
+        BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, 
+        BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 
+};
+
+static void bt848_set_winsize(struct bttv *btv)
+{
+        unsigned short format;
+	int bpp;
+
+	bpp=fmtbppx2[btv->win.color_fmt&0x0f]/2;
+	if (btv->win.bpp == 0) 
 	{
-		btand(~BT848_VSCALE_INT, BT848_E_VSCALE_HI);
-		btand(~BT848_VSCALE_INT, BT848_O_VSCALE_HI);
+	        btv->win.bpp=bpp;
+		format=btv->win.color_fmt;
 	}
-
-	/*
-	 *	Load her up
+	else if (btv->win.bpp!=bpp)
+		btv->win.color_fmt=format=bpp2fmt[(btv->win.bpp-1)&3];
+	else
+                format=btv->win.color_fmt;
+                	
+	/*	RGB8 seems to be a 9x5x5 GRB color cube starting at
+	 *	color 16. Why the h... can't they even mention this in the
+	 *	datasheet???  [AC - because its a standard format so I guess
+	 *	it never occured them]
+	 *	Enable dithering in this mode
 	 */
-	 
-	btwrite(hscale>>8, BT848_E_HSCALE_HI);
-	btwrite(hscale>>8, BT848_O_HSCALE_HI);
-	btwrite(hscale&0xff, BT848_E_HSCALE_LO);
-	btwrite(hscale&0xff, BT848_O_HSCALE_LO);
-
-	btwrite((vscale>>8)|(btread(BT848_E_VSCALE_HI)&0xe0), BT848_E_VSCALE_HI);
-	btwrite((vscale>>8)|(btread(BT848_O_VSCALE_HI)&0xe0), BT848_O_VSCALE_HI);
-	btwrite(vscale&0xff, BT848_E_VSCALE_LO);
-	btwrite(vscale&0xff, BT848_O_VSCALE_LO);
-
-	btwrite(hactive&0xff, BT848_E_HACTIVE_LO);
-	btwrite(hactive&0xff, BT848_O_HACTIVE_LO);
-	btwrite(hdelay&0xff, BT848_E_HDELAY_LO);
-	btwrite(hdelay&0xff, BT848_O_HDELAY_LO);
-
-	btwrite(vactive&0xff, BT848_E_VACTIVE_LO);
-	btwrite(vactive&0xff, BT848_O_VACTIVE_LO);
-	btwrite(vdelay&0xff, BT848_E_VDELAY_LO);
-	btwrite(vdelay&0xff, BT848_O_VDELAY_LO);
+	if (format==BT848_COLOR_FMT_RGB8)
+                btand(~0x10, BT848_CAP_CTL); 
+	else
+	        btor(0x10, BT848_CAP_CTL);
 
-	crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
-		((vactive>>4)&0x30)|((vdelay>>2)&0xc0);
-	btwrite(crop, BT848_E_CROP);
-	btwrite(crop, BT848_O_CROP);
+        bt848_set_geo(btv,btv->win.width, btv->win.height, format);
 }
 
-
-/*
- *	The floats in the tuner struct are computed at compile time
- *	by gcc and cast back to integers. Thus we don't violate the
- *	"no float in kernel" rule.
- */
- 
-static struct tunertype tuners[] = {
-	{"Temic PAL", TEMIC, PAL,
-		16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2, 623},
-	{"Philips PAL_I", Philips, PAL_I,
-		16*140.25,16*463.25,0x00,0x00,0x00,0x00,0x00, 623},
-	{"Philips NTSC", Philips, NTSC,
-		16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0, 732},
-	{"Philips SECAM", Philips, SECAM,
-		16*168.25,16*447.25,0xA3,0x93,0x33,0x8e,0xc0, 623},
-	{"NoTuner", NoTuner, NOTUNER,
-		0        ,0        ,0x00,0x00,0x00,0x00,0x00, 0},
-	{"Philips PAL", Philips, PAL,
-		16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0, 623},
-	{"Temic NTSC", TEMIC, NTSC,
-		16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2, 732},
-	{"TEMIC PAL_I", TEMIC, PAL_I,
-		0        ,0        ,0x00,0x00,0x00,0x00,0xc2, 623},
-}; 
-
 /*
  *	Set TSA5522 synthesizer frequency in 1/16 Mhz steps
  */
 
-static void set_freq(struct bttv *btv, ushort freq)
+static void set_freq(struct bttv *btv, unsigned short freq)
 {
-	u8 config;
-	u16 div;
-	struct tunertype *tun=&tuners[btv->tuner];
+	int fixme = freq; /* XXX */
 	int oldAudio = btv->audio;
-
+	
 	audio(btv, AUDIO_MUTE);
 	udelay(AUDIO_MUTE_DELAY);
-	
-	if (freq < tun->thresh1) 
-		config = tun->VHF_L;
-	else if (freq < tun->thresh2) 
-		config = tun->VHF_H;
-	else
-		config = tun->UHF;
 
-	if(freq < tun->thresh1)
-		config = tun->VHF_L;
-	else if(freq < tun->thresh2)
-		config = tun->VHF_H;
-	else
-		config=tun->UHF;
-		
-	div=freq+tun->IFPCoff;
-	  
-	div&=0x7fff;
+	if (btv->radio) 
+	{
+		if (btv->have_tuner)
+			i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
+					   TUNER_SET_RADIOFREQ,&fixme);
 	
-	if (I2CWrite(btv, btv->tuneradr, (div>>8)&0x7f, div&0xff, 1)<0)
-		return;
-	I2CWrite(btv, btv->tuneradr, tun->config, config, 1);
-	if (!(oldAudio & AUDIO_MUTE))
+		if (btv->have_msp3400) {
+			i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
+					   MSP_SET_RADIO,0);
+			i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
+					   MSP_NEWCHANNEL,0);
+		}
+	}
+	else
 	{
+		if (btv->have_tuner)
+			i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
+					   TUNER_SET_TVFREQ,&fixme);
+
+		if (btv->have_msp3400) {
+			i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
+					   MSP_SET_TVNORM,&(btv->win.norm));
+			i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
+					   MSP_NEWCHANNEL,0);
+		}
+	}
+
+ 	if (!(oldAudio & AUDIO_MUTE)) {
 		udelay(FREQ_CHANGE_DELAY);
 		audio(btv, AUDIO_UNMUTE);
 	}
 }
+      
+
+/*
+ *	Grab into virtual memory.
+ *	Currently only does double buffering. Do we need more?
+ */
+
+static int vgrab(struct bttv *btv, struct video_mmap *mp)
+{
+	unsigned int *ro, *re;
+	unsigned int *vbuf;
+	
+	if(btv->fbuffer==NULL)
+	{
+		if(fbuffer_alloc(btv))
+			return -ENOBUFS;
+	}
+	
+	/*
+	 *	No grabbing past the end of the buffer!
+	 */
+	 
+	if(mp->frame>1 || mp->frame <0)
+		return -EINVAL;
+		
+	if(mp->height <0 || mp->width <0)
+		return -EINVAL;
+	
+	if(mp->height>480 || mp->width>640)
+		return -EINVAL;
+
+	/*
+	 *	FIXME: Check the format of the grab here. This is probably
+	 *	also less restrictive than the normal overlay grabs. Stuff
+	 *	like QCIF has meaning as a capture.
+	 */
+	 
+	/*
+	 *	Ok load up the BT848
+	 */
+	 
+	vbuf=(unsigned int *)(btv->fbuffer+0x144000*mp->frame);
+	if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
+                return -EAGAIN;
+	ro=btv->grisc+(((btv->grabcount++)&1) ? 2048 :0);
+	re=ro+1024;
+	btv->gwidth=mp->width;
+	btv->gheight=mp->height;
+	btv->gfmt=mp->format;
+	make_vrisctab(btv, ro, re, vbuf, btv->gwidth, btv->gheight, btv->gfmt);
+	/* bt848_set_risc_jmps(btv); */
+	btor(3, BT848_CAP_CTL);
+	btor(3, BT848_GPIO_DMA_CTL);
+	btv->gro=virt_to_bus(ro);
+	btv->gre=virt_to_bus(re);
+	if (!(btv->grabbing++)) 
+		btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ;
+	/* interruptible_sleep_on(&btv->capq); */
+	return 0;
+}
 
 static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock)
 {
@@ -608,7 +939,6 @@
 		todo-=q;
 		buf+=q;
 
-/*		btv->vbip=0; */
 		cli();
 		if (todo && q==VBIBUF_SIZE-btv->vbip) 
 		{
@@ -659,14 +989,17 @@
 				users+=bttvs[i].user;
 			if (users==1)
 				find_vga();
+			btv->fbuffer=NULL;
+			if (!btv->fbuffer)
+				btv->fbuffer=(unsigned char *) rvmalloc(2*0x144000);
+			if (!btv->fbuffer)
+                        { 
+				btv->user--;
+				return -EINVAL;
+			}
 			break;
 		case 1:
 			break;
-		case 2:
-			btv->vbip=VBIBUF_SIZE;
-			btv->cap|=0x0c;
-			bt848_set_risc_jmps(btv);
-			break;
 	}
 	MOD_INC_USE_COUNT;
 	return 0;   
@@ -679,17 +1012,15 @@
 	btv->user--;
 	audio(btv, AUDIO_MUTE);
 	btv->cap&=~3;
-#if 0 /* FIXME */	
-	if(minor&0x20) 
-	{
-		btv->cap&=~0x0c;
-	}
-#endif	
 	bt848_set_risc_jmps(btv);
 
+	if(btv->fbuffer)
+		rvfree((void *) btv->fbuffer, 2*0x144000);
+	btv->fbuffer=0;
 	MOD_DEC_USE_COUNT;  
 }
 
+
 /***********************************/
 /* ioctls and supporting functions */
 /***********************************/
@@ -714,7 +1045,7 @@
 	btaor(conthi, ~4, BT848_O_CONTROL);
 }
 
-extern inline void bt848_sat_u(struct bttv *btv, ulong data)
+extern inline void bt848_sat_u(struct bttv *btv, unsigned long data)
 {
 	u32 datahi;
 
@@ -724,7 +1055,7 @@
 	btaor(datahi, ~2, BT848_O_CONTROL);
 }
 
-static inline void bt848_sat_v(struct bttv *btv, ulong data)
+static inline void bt848_sat_v(struct bttv *btv, unsigned long data)
 {
 	u32 datahi;
 
@@ -734,6 +1065,7 @@
 	btaor(datahi, ~1, BT848_O_CONTROL);
 }
 
+
 /*
  *	Cliprect -> risc table.
  *
@@ -772,15 +1104,17 @@
 	}
 	first2.next=NULL;
 	
-	rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; rmem[rpo++]=0;
+	rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1|(0xf<<20);
+	rmem[rpo++]=0;
 
-	rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; rmem2[rpe++]=0;
+	rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1;
+	rmem2[rpe++]=0;
 
 
 	/*
 	 *	32bit depth frame buffers need extra flags setting
 	 */
-
+	 
 	if (depth==4)
 		mask=BT848_RISC_BYTE3;
 	else
@@ -842,7 +1176,7 @@
 		 *	here, but the overlap might be partial
 		 */
 		 
-		/* add rect to second (x-sorted) list if rect.y == y  */
+ 		/* add rect to second (x-sorted) list if rect.y == y  */
 		if ((cur=first.next)) 
 		{
 			while ((cur) && (cur->y == y))
@@ -953,8 +1287,9 @@
 			{
 				/* Skip the line : write a SKIP + start/end of line marks */
 				(*rp)--;
-				rpp[(*rp)-1]=BT848_RISC_SKIP|(btv->win.width*depth)|
-					BT848_RISC_EOL|BT848_RISC_SOL;
+				rpp[(*rp)-1]=BT848_RISC_SKIP|
+				        (btv->win.width*depth)|
+					  BT848_RISC_EOL|BT848_RISC_SOL;
 			}
 		}
 		/*
@@ -988,15 +1323,15 @@
 	vw->clipcount++;
 }
 
+
 /*
  *	ioctl routine
  */
  
+
 static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
 	unsigned char eedata[256];
-/*	unsigned long data;*/
-/*	static ushort creg;*/
 	struct bttv *btv=(struct bttv *)dev;
   	static int lastchan=0;
   	
@@ -1092,10 +1427,14 @@
 			/* Only channel 0 has a tuner */
 			if(v.tuner!=0 || lastchan)
 				return -EINVAL;
-			if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC)
+			if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC
+			   &&v.mode!=VIDEO_MODE_SECAM)
 				return -EOPNOTSUPP;
+			/* FIXME: norm should be in video_channel struct 
+			   composite source can have different norms too
+			 */
 			btv->win.norm = v.mode;
-			bt848_set_size(btv);
+			bt848_set_winsize(btv);
 			return 0;
 		}
 		case VIDIOCGPICT:
@@ -1109,6 +1448,7 @@
 				p.palette=VIDEO_PALETTE_RGB24;
 			if(btv->win.bpp==4)
 				p.palette=VIDEO_PALETTE_RGB32;
+			
 			if(copy_to_user(arg, &p, sizeof(p)))
 				return -EFAULT;
 			return 0;
@@ -1155,7 +1495,7 @@
 			on=(btv->cap&3)?1:0;
 			
 			bt848_cap(btv,0);
-			bt848_set_size(btv);
+			bt848_set_winsize(btv);
 
 			if(vw.clipcount>256)
 				return -EDOM;	/* Too many! */
@@ -1188,7 +1528,7 @@
 			 */
 			write_risc_data(btv,vcp, vw.clipcount);
 			vfree(vcp);
-			if(on)
+			if(on && btv->win.vidadr!=0)
 				bt848_cap(btv,1);
 			return 0;
 		}
@@ -1213,14 +1553,15 @@
 			int v;
 			if(copy_from_user(&v, arg,sizeof(v)))
 				return -EFAULT;
-			if(btv->win.vidadr==0 || btv->win.width==0 || btv->win.height==0)
-				return -EINVAL;
 			if(v==0)
 			{
 				bt848_cap(btv,0);
 			}
 			else
 			{
+			        if(btv->win.vidadr==0 || btv->win.width==0
+				   || btv->win.height==0)
+				  return -EINVAL;
 				bt848_cap(btv,1);
 			}
 			return 0;
@@ -1247,7 +1588,13 @@
 				return -EFAULT;
 			if(v.depth!=8 && v.depth!=16 && v.depth!=24 && v.depth!=32)
 				return -EINVAL;
-			btv->win.vidadr=(int)v.base;
+			if (v.base)
+			        /* also handle virtual base addresses */
+			        if ((unsigned int)v.base>=0xe0000000UL)
+			                btv->win.vidadr=(uint)v.base;
+				else 
+				  btv->win.vidadr=PAGE_OFFSET|
+				    uvirt_to_bus((uint)v.base);
 			btv->win.sheight=v.height;
 			btv->win.swidth=v.width;
 			btv->win.bpp=v.depth/8;
@@ -1255,7 +1602,7 @@
 			
 			DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
 				v.base, v.width,v.height, btv->win.bpp, btv->win.bpl));
-			bt848_set_size(btv);
+			bt848_set_winsize(btv);
 			return 0;		
 		}
 		case VIDIOCKEY:
@@ -1287,6 +1634,17 @@
 			v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE);
 			v.flags|=VIDEO_AUDIO_MUTABLE;
 			strcpy(v.name,"TV");
+			if (btv->have_msp3400) 
+			{
+				v.flags|=VIDEO_AUDIO_VOLUME;
+				i2c_control_device(&(btv->i2c),
+					I2C_DRIVERID_MSP3400,
+					MSP_GET_VOLUME,&(v.volume));
+				i2c_control_device(&(btv->i2c),
+					I2C_DRIVERID_MSP3400,
+					MSP_GET_STEREO,&(v.mode));
+			}
+			else v.mode = VIDEO_SOUND_MONO;
 			if(copy_to_user(arg,&v,sizeof(v)))
 				return -EFAULT;
 			return 0;
@@ -1296,28 +1654,55 @@
 			struct video_audio v;
 			if(copy_from_user(&v,arg, sizeof(v)))
 				return -EFAULT;
-			if(v.audio!=0)
-				return -EINVAL;
 			if(v.flags&VIDEO_AUDIO_MUTE)
 				audio(btv, AUDIO_MUTE);
+			if(v.audio<0||v.audio>2)
+				return -EINVAL;
+			bt848_muxsel(btv,v.audio);
 			if(!(v.flags&VIDEO_AUDIO_MUTE))
 				audio(btv, AUDIO_UNMUTE);
+			if (btv->have_msp3400) 
+			{
+				i2c_control_device(&(btv->i2c),
+					I2C_DRIVERID_MSP3400,
+					MSP_SET_VOLUME,&(v.volume));
+				i2c_control_device(&(btv->i2c),
+					I2C_DRIVERID_MSP3400,
+					MSP_SET_STEREO,&(v.mode));
+			}
 			btv->audio_dev=v;
 			return 0;
 		}
 
-		case BTTV_WRITEEE:
+	        case VIDIOCSYNC:
+		        if (btv->grabbing && btv->grab==btv->lastgrab)
+			        interruptible_sleep_on(&btv->capq);
+		        btv->lastgrab=btv->grab;
+		        return 0;
+
+		case BTTV_WRITEE:
+			if(!suser())
+				return -EPERM;
 			if(copy_from_user((void *) eedata, (void *) arg, 256))
 				return -EFAULT;
-			writeee(btv, eedata);
-			break;
+			writeee(&(btv->i2c), eedata);
+			return 0;
 
 		case BTTV_READEE:
-			readee(btv, eedata);
+			if(!suser())
+				return -EPERM;
+			readee(&(btv->i2c), eedata);
 			if(copy_to_user((void *) arg, (void *) eedata, 256))
 				return -EFAULT;
 			break;
 
+	        case VIDIOCMCAPTURE:
+		{
+                        struct video_mmap vm;
+			if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
+				return -EFAULT;
+		        return vgrab(btv, &vm);
+		}
 		default:
 			return -ENOIOCTLCMD;
 	}
@@ -1329,6 +1714,41 @@
 	return 0;
 }
 
+/*
+ *	This maps the vmalloced and reserved fbuffer to user space.
+ *
+ *  FIXME: 
+ *  - PAGE_READONLY should suffice!?
+ *  - remap_page_range is kind of inefficient for page by page remapping.
+ *    But e.g. pte_alloc() does not work in modules ... :-(
+ */
+ 
+static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+	struct bttv *btv=(struct bttv *)dev;
+        unsigned long start=(unsigned long) adr;
+	unsigned long page,pos;
+
+	if (size>2*0x144000)
+	        return -EINVAL;
+	if (!btv->fbuffer)
+	{
+		if(fbuffer_alloc(btv))
+			return -EINVAL;
+	}
+	pos=(unsigned long) btv->fbuffer;
+	while (size > 0) 
+	{
+	        page = kvirt_to_phys(pos);
+		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+		        return -EAGAIN;
+		start+=PAGE_SIZE;
+		pos+=PAGE_SIZE;
+		size-=PAGE_SIZE;    
+	}
+	return 0;
+}
+
 static struct video_device bttv_template=
 {
 	"UNSET",
@@ -1339,6 +1759,96 @@
 	bttv_read,
 	bttv_write,
 	bttv_ioctl,
+	bttv_mmap,
+	bttv_init_done,
+	NULL,
+	0,
+	0
+};
+
+
+static long vbi_read(struct video_device *v, char *buf, unsigned long count,
+		     int nonblock)
+{
+	struct bttv *btv=(struct bttv *)(v-2);
+	int q,todo;
+
+	todo=count;
+	while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) 
+	{
+		if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q))
+			return -EFAULT;
+		todo-=q;
+		buf+=q;
+
+		cli();
+		if (todo && q==VBIBUF_SIZE-btv->vbip) 
+		{
+			if(nonblock)
+			{
+				sti();
+				if(count==todo)
+					return -EWOULDBLOCK;
+				return count-todo;
+			}
+			interruptible_sleep_on(&btv->vbiq);
+			sti();
+			if(signal_pending(current))
+			{
+				if(todo==count)
+					return -EINTR;
+				else
+					return count-todo;
+			}
+		}
+	}
+	if (todo) 
+	{
+		if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo))
+			return -EFAULT;
+		btv->vbip+=todo;
+	}
+	return count;
+}
+
+static int vbi_open(struct video_device *dev, int flags)
+{
+	struct bttv *btv=(struct bttv *)(dev-2);
+
+	btv->vbip=VBIBUF_SIZE;
+	btv->cap|=0x0c;
+	bt848_set_risc_jmps(btv);
+
+	MOD_INC_USE_COUNT;
+	return 0;   
+}
+
+static void vbi_close(struct video_device *dev)
+{
+	struct bttv *btv=(struct bttv *)(dev-2);
+  
+	btv->cap&=~0x0c;
+	bt848_set_risc_jmps(btv);
+
+	MOD_DEC_USE_COUNT;  
+}
+
+
+static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	return -EINVAL;
+}
+
+static struct video_device vbi_template=
+{
+	"bttv vbi",
+	VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
+	VID_HARDWARE_BT848,
+	vbi_open,
+	vbi_close,
+	vbi_read,
+	bttv_write,
+	vbi_ioctl,
 	NULL,	/* no mmap yet */
 	bttv_init_done,
 	NULL,
@@ -1346,9 +1856,106 @@
 	0
 };
 
+
+static int radio_open(struct video_device *dev, int flags)
+{
+	struct bttv *btv = (struct bttv *)(dev-1);
+
+	if (btv->user)
+		return -EBUSY;
+	btv->user++;
+	set_freq(btv,400*16);
+	btv->radio = 1;
+	bt848_muxsel(btv,0);
+	audio(btv, AUDIO_UNMUTE);
+	
+	MOD_INC_USE_COUNT;
+	return 0;   
+}
+
+static void radio_close(struct video_device *dev)
+{
+	struct bttv *btv=(struct bttv *)(dev-1);
+  
+	btv->user--;
+	btv->radio = 0;
+	audio(btv, AUDIO_MUTE);
+	MOD_DEC_USE_COUNT;  
+}
+
+static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock)
+{
+	return -EINVAL;
+}
+
+static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+        struct bttv *btv=(struct bttv *)(dev-1);
+  	static int lastchan=0;
+	switch (cmd) {	
+	case VIDIOCGCAP:
+		/* XXX */
+		break;
+	case VIDIOCGTUNER:
+	{
+		struct video_tuner v;
+		if(copy_from_user(&v,arg,sizeof(v))!=0)
+			return -EFAULT;
+		if(v.tuner||lastchan)	/* Only tuner 0 */
+			return -EINVAL;
+		strcpy(v.name, "Radio");
+		v.rangelow=(int)(87.5*16);
+		v.rangehigh=(int)(108.0*16);
+		v.flags= 0; /* XXX */
+		v.mode = 0; /* XXX */
+		if(copy_to_user(arg,&v,sizeof(v)))
+			return -EFAULT;
+		return 0;
+	}
+	case VIDIOCSTUNER:
+	{
+		struct video_tuner v;
+		if(copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
+		/* Only channel 0 has a tuner */
+		if(v.tuner!=0 || lastchan)
+			return -EINVAL;
+		/* XXX anything to do ??? */
+		return 0;
+	}
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		bttv_ioctl((struct video_device *)btv,cmd,arg);
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static struct video_device radio_template=
+{
+	"bttv radio",
+	VID_TYPE_TUNER,
+	VID_HARDWARE_BT848,
+	radio_open,
+	radio_close,
+	radio_read,          /* just returns -EINVAL */
+	bttv_write,          /* just returns -EINVAL */
+	radio_ioctl,
+	NULL,	             /* no mmap */
+	bttv_init_done,      /* just returns 0 */
+	NULL,
+	0,
+	0
+};
+
+
 struct vidbases 
 {
-	ushort vendor, device;
+	unsigned short vendor, device;
 	char *name;
 	uint badr;
 };
@@ -1386,7 +1993,7 @@
 static int find_vga(void)
 {
 	unsigned int devfn, class, vendev;
-	ushort vendor, device, badr;
+	unsigned short vendor, device, badr;
 	int found=0, bus=0, i, tga_type;
 	unsigned int vidadr=0;
 
@@ -1470,6 +2077,8 @@
 	return found;
 }
 
+
+
 #define  TRITON_PCON	           0x50 
 #define  TRITON_BUS_CONCURRENCY   (1<<0)
 #define  TRITON_STREAMING	  (1<<1)
@@ -1480,28 +2089,27 @@
 {
 	int index;
   
+	/*	Just in case some nut set this to something dangerous */
+	if (triton1)
+		triton1=BT848_INT_ETBF;
+	
 	for (index = 0; index < 8; index++)
 	{
 		unsigned char bus, devfn;
-		unsigned char b, bo;
+		unsigned char b;
     
 		/* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */
 		
-		if (!pcibios_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, index, &bus, &devfn))
+		if (!pcibios_find_device(PCI_VENDOR_ID_SI, 
+					 PCI_DEVICE_ID_SI_496, 
+					 index, &bus, &devfn))
 		{
 			printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n");
 		}			
 
-		if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
-			    index, &bus, &devfn)) 
-		{
-			pcibios_read_config_byte(bus, devfn, 0x53, &b);
-			DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "));
-			DEBUG(printk("bufcon=0x%02x\n",b));
-		}
-
-		if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
-			    index, &bus, &devfn)) 
+		if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, 
+					 PCI_DEVICE_ID_INTEL_82441,
+					 index, &bus, &devfn)) 
 		{
 			pcibios_read_config_byte(bus, devfn, 0x53, &b);
 			DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "));
@@ -1512,139 +2120,176 @@
 			    index, &bus, &devfn)) 
 		{
 			printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n");
-			pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b);
-			bo=b;
-			DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b));
-
+			triton1=BT848_INT_ETBF;
+			
+#if 0			
+			/* The ETBF bit SHOULD make all this unnecessary */
 			/* 430FX (Triton I) freezes with bus concurrency on -> switch it off */
-			if(!(b & TRITON_BUS_CONCURRENCY)) 
-			{
-				printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n");
-				b |= TRITON_BUS_CONCURRENCY;
-			}
+			{   
+			        unsigned char bo;
 
-			/* still freezes on other boards -> switch off even more */
-			if(b & TRITON_PEER_CONCURRENCY) 
-			{
-				printk(KERN_WARNING "bttv: 82437FX: disabling peer concurrency\n");
-				b &= ~TRITON_PEER_CONCURRENCY;
-			}
-			if(!(b & TRITON_STREAMING)) 
-			{
-				printk(KERN_WARNING "bttv: 82437FX: disabling streaming\n");
-				b |=  TRITON_STREAMING;
-			}
+				pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b);
+				bo=b;
+				DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b));
 
-			if (b!=bo) 
-			{
-				pcibios_write_config_byte(bus, devfn, TRITON_PCON, b); 
-				printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b);
+				if(!(b & TRITON_BUS_CONCURRENCY)) 
+				{
+					printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n");
+					b |= TRITON_BUS_CONCURRENCY;
+				}
+
+				if(b & TRITON_PEER_CONCURRENCY) 
+				{
+					printk(KERN_WARNING "bttv: 82437FX: disabling peer concurrency\n");
+					b &= ~TRITON_PEER_CONCURRENCY;
+				}
+				if(!(b & TRITON_STREAMING)) 
+				{
+					printk(KERN_WARNING "bttv: 82437FX: disabling streaming\n");
+					b |=  TRITON_STREAMING;
+				}
+
+				if (b!=bo) 
+				{
+					pcibios_write_config_byte(bus, devfn, TRITON_PCON, b); 
+					printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b);
+				}
 			}
+#endif
 		}
 	}
 }
 
-static void init_tda9850(struct bttv *btv)
+
+static void init_tda9850(struct i2c_bus *bus)
 {
-	I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0, 1);
+        I2CWrite(bus, I2C_TDA9850, TDA9850_CON1, 0x08, 1);  /* noise threshold st */
+	I2CWrite(bus, I2C_TDA9850, TDA9850_CON2, 0x08, 1);  /* noise threshold sap */
+	I2CWrite(bus, I2C_TDA9850, TDA9850_CON3, 0x40, 1);  /* stereo mode */
+	I2CWrite(bus, I2C_TDA9850, TDA9850_CON4, 0x07, 1);  /* 0 dB input gain?*/
+	I2CWrite(bus, I2C_TDA9850, TDA9850_ALI1, 0x10, 1);  /* wideband alignment? */
+	I2CWrite(bus, I2C_TDA9850, TDA9850_ALI2, 0x10, 1);  /* spectral alignment? */
+	I2CWrite(bus, I2C_TDA9850, TDA9850_ALI3, 0x03, 1);
 }
 
+
+
 /* Figure out card and tuner type */
 
 static void idcard(struct bttv *btv)
 {
-	int i;
-
+	int tunertype;
 	btwrite(0, BT848_GPIO_OUT_EN);
 	DEBUG(printk(KERN_DEBUG "bttv: GPIO: 0x%08x\n", btread(BT848_GPIO_DATA)));
 
-	btv->type=BTTV_MIRO;
-	btv->tuner=tuner;
-  
-	if (I2CRead(btv, I2C_HAUPEE)>=0)
-		btv->type=BTTV_HAUPPAUGE;
-	else if (I2CRead(btv, I2C_STBEE)>=0)
-		btv->type=BTTV_STB;
-
-	for (i=0xc0; i<0xd0; i+=2)
+	/* Default the card to the user-selected one. */
+	btv->type=card;
+ 
+	/* If we were asked to auto-detect, then do so! 
+	   Right now this will only recognize Miro, Hauppauge or STB
+	   */
+	if (btv->type == BTTV_UNKNOWN) 
 	{
-		if (I2CRead(btv, i)>=0) 
-		{
-			btv->tuneradr=i;
-			break;
-		}
+	        btv->type=BTTV_MIRO;
+    
+		if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0)
+		        btv->type=BTTV_HAUPPAUGE;
+		else
+		        if (I2CRead(&(btv->i2c), I2C_STBEE)>=0)
+			        btv->type=BTTV_STB;
 	}
 
-	btv->dbx = I2CRead(btv, I2C_TDA9850) ? 0 : 1;
+	btv->dbx = I2CRead(&(btv->i2c), I2C_TDA9850) ? 0 : 1;
 
 	if (btv->dbx)
-		init_tda9850(btv);
+		init_tda9850(&(btv->i2c));
 
 	/* How do I detect the tuner type for other cards but Miro ??? */
 	printk(KERN_INFO "bttv: model: ");
 	switch (btv->type) 
 	{
 		case BTTV_MIRO:
-			btv->tuner=((btread(BT848_GPIO_DATA)>>10)-1)&7;
-			printk("MIRO");
+			printk("MIRO\n");
+			if (btv->have_tuner) 
+			{
+				tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+				i2c_control_device(&(btv->i2c),
+						   I2C_DRIVERID_TUNER,
+						   TUNER_SET_TYPE,&tunertype);
+			}
 			strcpy(btv->video_dev.name,"BT848(Miro)");
 			break;
 		case BTTV_HAUPPAUGE:
-			printk("HAUPPAUGE");
+			printk("HAUPPAUGE\n");
 			strcpy(btv->video_dev.name,"BT848(Hauppauge)");
 			break;
 		case BTTV_STB: 
-			printk("STB");
+			printk("STB\n");
 			strcpy(btv->video_dev.name,"BT848(STB)");
 			break;
 		case BTTV_INTEL: 
-			printk("Intel");
+			printk("Intel\n");
 			strcpy(btv->video_dev.name,"BT848(Intel)");
 			break;
 		case BTTV_DIAMOND: 
-			printk("Diamond");
+			printk("Diamond\n");
 			strcpy(btv->video_dev.name,"BT848(Diamond)");
 			break;
+		case BTTV_AVERMEDIA: 
+			printk("AVerMedia\n");
+			strcpy(btv->video_dev.name,"BT848(AVerMedia)");
+			break;
 	}
-	printk(" (%s @ 0x%02x)\n", tuners[btv->tuner].name, btv->tuneradr);
 	audio(btv, AUDIO_MUTE);
 }
 
 
+
 static void bt848_set_risc_jmps(struct bttv *btv)
 {
 	int flags=btv->cap;
-  
+
+	/* Sync to start of odd field */
 	btv->risc_jmp[0]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE;
 	btv->risc_jmp[1]=0;
 
-	btv->risc_jmp[2]=BT848_RISC_JUMP;
+	/* Jump to odd vbi sub */
+	btv->risc_jmp[2]=BT848_RISC_JUMP|(0x5<<20);
 	if (flags&8)
 		btv->risc_jmp[3]=virt_to_bus(btv->vbi_odd);
 	else
 		btv->risc_jmp[3]=virt_to_bus(btv->risc_jmp+4);
 
-	btv->risc_jmp[4]=BT848_RISC_JUMP;
+        /* Jump to odd sub */
+	btv->risc_jmp[4]=BT848_RISC_JUMP|(0x6<<20);
 	if (flags&2)
 		btv->risc_jmp[5]=virt_to_bus(btv->risc_odd);
 	else
 		btv->risc_jmp[5]=virt_to_bus(btv->risc_jmp+6);
 
+
+	/* Sync to start of even field */
 	btv->risc_jmp[6]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO;
 	btv->risc_jmp[7]=0;
 
+	/* Jump to even vbi sub */
 	btv->risc_jmp[8]=BT848_RISC_JUMP;
 	if (flags&4)
 		btv->risc_jmp[9]=virt_to_bus(btv->vbi_even);
 	else
 		btv->risc_jmp[9]=virt_to_bus(btv->risc_jmp+10);
 
-	btv->risc_jmp[10]=BT848_RISC_JUMP;
+	/* Jump to even sub */
+	btv->risc_jmp[10]=BT848_RISC_JUMP|(8<<20);
 	if (flags&1)
 		btv->risc_jmp[11]=virt_to_bus(btv->risc_even);
 	else
-		btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp);
+		btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp+12);
+
+	btv->risc_jmp[12]=BT848_RISC_JUMP;
+	btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp);
 
+	/* enable cpaturing and DMA */
 	btaor(flags, ~0x0f, BT848_CAP_CTL);
 	if (flags&0x0f)
 		bt848_dma(btv, 3);
@@ -1653,12 +2298,15 @@
 }
 
 
-static int init_bt848(struct bttv *btv)
+static int init_bt848(int i)
 {
-	/* reset the bt848 */
-	btwrite(0,BT848_SRESET);
+        struct bttv *btv = &bttvs[i];
+
 	btv->user=0; 
 
+	/* reset the bt848 */
+	btwrite(0, BT848_SRESET);
+
 	DEBUG(printk(KERN_DEBUG "bttv: bt848_mem: 0x%08x\n",(unsigned int) btv->bt848_mem));
 
 	/* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
@@ -1674,43 +2322,66 @@
 	btv->win.cropx=0;
 	btv->win.cropy=0;
 	btv->win.bpp=2;
+	btv->win.color_fmt=BT848_COLOR_FMT_RGB16;
 	btv->win.bpl=1024*btv->win.bpp;
 	btv->win.swidth=1024;
 	btv->win.sheight=768;
 	btv->cap=0;
 
-	if (!(btv->risc_odd=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
+	btv->gmode=0;
+	btv->risc_odd=0;
+	btv->risc_even=0;
+	btv->risc_jmp=0;
+	btv->vbibuf=0;
+	btv->grisc=0;
+	btv->grabbing=0;
+	btv->grabcount=0;
+	btv->grab=0;
+	btv->lastgrab=0;
+
+	/* i2c */
+	memcpy(&(btv->i2c),&bttv_i2c_bus_template,sizeof(struct i2c_bus));
+	sprintf(btv->i2c.name,"bt848-%d",i);
+	btv->i2c.data = btv;
+
+	if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
 		return -1;
-	if (!(btv->risc_even=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
+	if (!(btv->risc_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
 		return -1;
-	if (!(btv->risc_jmp =(dword *) kmalloc(2048, GFP_KERNEL)))
+	if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL)))
 		return -1;
-	btv->vbi_odd=btv->risc_jmp+12;
+ 	DEBUG(printk(KERN_DEBUG "risc_jmp: %p\n",btv->risc_jmp));
+	btv->vbi_odd=btv->risc_jmp+16;
 	btv->vbi_even=btv->vbi_odd+256;
-	btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp);
+	btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12);
 	btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6);
 
 	btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD);
-	btv->vbibuf=(unchar *) vmalloc(VBIBUF_SIZE);
+	btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE);
 	if (!btv->vbibuf) 
 		return -1;
+	if (!(btv->grisc=(unsigned int *) kmalloc(16384, GFP_KERNEL)))
+		return -1;
+
+	btv->fbuffer=NULL;
 
 	bt848_muxsel(btv, 1);
-	bt848_set_size(btv);
+	bt848_set_winsize(btv);
 
 /*	btwrite(0, BT848_TDEC); */
 	btwrite(0x10, BT848_COLOR_CTL);
 	btwrite(0x00, BT848_CAP_CTL);
+	btwrite(0xfc, BT848_GPIO_DMA_CTL);
 
 	btwrite(0x0ff, BT848_VBI_PACK_SIZE);
 	btwrite(1, BT848_VBI_PACK_DEL);
 
-	btwrite(0xfc, BT848_GPIO_DMA_CTL);
+		
 	btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI,
 		BT848_IFORM);
 
-	bt848_bright(btv, 0x10);
 	btwrite(0xd8, BT848_CONTRAST_LO);
+	bt848_bright(btv, 0x10);
 
 	btwrite(0x60, BT848_E_VSCALE_HI);
 	btwrite(0x60, BT848_O_VSCALE_HI);
@@ -1719,19 +2390,27 @@
 
 	btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
 	btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+
+	btv->picture.colour=254<<7;
+	btv->picture.brightness=128<<8;
+	btv->picture.hue=128<<8;
+	btv->picture.contrast=0xd8<<7;
+
 	btwrite(0x00, BT848_E_SCLOOP);
 	btwrite(0x00, BT848_O_SCLOOP);
 
-	btwrite(0xffffffUL,BT848_INT_STAT);
-/*	  BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|BT848_INT_FDSR|
-	  BT848_INT_FTRGT|BT848_INT_FBUS|*/
-	btwrite(BT848_INT_ETBF|
+	/* clear interrupt status */
+	btwrite(0xfffffUL, BT848_INT_STAT);
+        
+	/* set interrupt mask */
+	btwrite(triton1|
+/*	        BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
+		BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
 		BT848_INT_SCERR|
 		BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
 		BT848_INT_FMTCHG|BT848_INT_HLOCK,
 		BT848_INT_MASK);
 
-/*	make_risctab(btv); */
 	make_vbitab(btv);
 	bt848_set_risc_jmps(btv);
   
@@ -1739,20 +2418,32 @@
 	 *	Now add the template and register the device unit.
 	 */
 
-	memcpy(&btv->video_dev,&bttv_template,sizeof(bttv_template));
+	memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template));
+	memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template));
+	memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template));
 	idcard(btv);
-	
-	btv->picture.brightness=0x90<<8;
-	btv->picture.contrast = 0x70 << 8;
-	btv->picture.colour = 0x70<<8;
-	btv->picture.hue = 0x8000;
-	
-	if(video_register_device(&btv->video_dev)<0)
+
+	if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
 		return -1;
+	if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) 
+        {
+	        video_unregister_device(&btv->video_dev);
+		return -1;
+	}
+	if (radio)
+	{
+		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) 
+                {
+		        video_unregister_device(&btv->vbi_dev);
+		        video_unregister_device(&btv->video_dev);
+			return -1;
+		}
+	}
+	i2c_register_bus(&btv->i2c);
+
 	return 0;
 }
 
-
 static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
 {
 	u32 stat,astat;
@@ -1779,7 +2470,8 @@
 		if (astat&BT848_INT_FMTCHG) 
 		{
 			IDEBUG(printk ("bttv: IRQ_FMTCHG\n"));
-/*			btv->win.norm&=(dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
+			/*btv->win.norm&=
+			  (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
 		}
 		if (astat&BT848_INT_VPRES) 
 		{
@@ -1795,22 +2487,47 @@
 			bt848_dma(btv, 1);
 			wake_up_interruptible(&btv->vbiq);
 			wake_up_interruptible(&btv->capq);
+
 		}
 		if (astat&BT848_INT_RISCI) 
 		{
 			IDEBUG(printk ("bttv: IRQ_RISCI\n"));
-			/* printk ("bttv: IRQ_RISCI%d\n",stat>>28); */
+
+			/* captured VBI frame */
 			if (stat&(1<<28)) 
 			{
 				btv->vbip=0;
 				wake_up_interruptible(&btv->vbiq);
 			}
+
+			/* captured full frame */
 			if (stat&(2<<28)) 
 			{
-				bt848_set_risc_jmps(btv);
+			        btv->grab++;
 				wake_up_interruptible(&btv->capq);
+			        if ((--btv->grabbing))
+				{
+                                        btv->risc_jmp[5]=btv->gro;
+					btv->risc_jmp[11]=btv->gre;
+					bt848_set_geo(btv, btv->gwidth,
+						      btv->gheight,
+						      btv->gfmt);
+				} else {
+					bt848_set_risc_jmps(btv);
+					bt848_set_geo(btv, btv->win.width, 
+						      btv->win.height,
+						      btv->win.color_fmt);
+				}
 				break;
 			}
+			if (stat&(8<<28)) 
+			{
+			        btv->risc_jmp[5]=btv->gro;
+				btv->risc_jmp[11]=btv->gre;
+				btv->risc_jmp[12]=BT848_RISC_JUMP;
+				bt848_set_geo(btv, btv->gwidth, btv->gheight,
+					      btv->gfmt);
+			}
 		}
 		if (astat&BT848_INT_OCERR) 
 		{
@@ -1842,7 +2559,7 @@
 		}
 		if (astat&BT848_INT_HLOCK) 
 		{
-			if (dstat&BT848_DSTATUS_HLOC)
+			if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio))
 				audio(btv, AUDIO_ON);
 			else
 				audio(btv, AUDIO_OFF);
@@ -1858,12 +2575,14 @@
 		if (count > 20) 
 		{
 			btwrite(0, BT848_INT_MASK);
-			printk(KERN_ERR "bttv: IRQ lockup, cleared int mask\n");
+			printk(KERN_ERR 
+			       "bttv: IRQ lockup, cleared int mask\n");
 		}
 	}
 }
 
 
+
 /*
  *	Scan for a Bt848 card, request the irq and map the io memory 
  */
@@ -1885,8 +2604,10 @@
 	}
 
 	for (pci_index = 0;
-		!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
-			    pci_index, &bus, &devfn);
+                !pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
+				     pci_index, &bus, &devfn)
+	      ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+ 				    pci_index, &bus, &devfn);
 		++pci_index) 
 	{
 		btv=&bttvs[bttv_num];
@@ -1899,8 +2620,13 @@
 		btv->vbi_even=NULL;
 		btv->vbiq=NULL;
 		btv->capq=NULL;
+		btv->capqo=NULL;
+		btv->capqe=NULL;
+
 		btv->vbip=VBIBUF_SIZE;
 
+		pcibios_read_config_word(btv->bus, btv->devfn, PCI_DEVICE_ID,
+					 &btv->id);
 		pcibios_read_config_byte(btv->bus, btv->devfn,
 			PCI_INTERRUPT_LINE, &btv->irq);
 		pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
@@ -1921,7 +2647,8 @@
 		btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
 		pcibios_read_config_byte(btv->bus, btv->devfn, PCI_CLASS_REVISION,
 			     &btv->revision);
-		printk(KERN_INFO "bttv: Brooktree Bt848 (rev %d) ",btv->revision);
+		printk(KERN_INFO "bttv: Brooktree Bt%d (rev %d) ",
+		       btv->id, btv->revision);
 		printk("bus: %d, devfn: %d, ",
 			btv->bus, btv->devfn);
 		printk("irq: %d, ",btv->irq);
@@ -1959,8 +2686,8 @@
 		if (!latency) 
 		{
 			latency=32;
-			pcibios_write_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER,
-				latency);
+			pcibios_write_config_byte(btv->bus, btv->devfn,
+						  PCI_LATENCY_TIMER, latency);
 		}
 		DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency));
 		bttv_num++;
@@ -1970,6 +2697,7 @@
 	return bttv_num;
 }
 
+
 static void release_bttv(void)
 {
 	u8 command;
@@ -1979,21 +2707,28 @@
 	for (i=0;i<bttv_num; i++) 
 	{
 		btv=&bttvs[i];
+
 		/* turn off all capturing, DMA and IRQs */
 
+		btand(~15, BT848_GPIO_DMA_CTL);
+
 		/* first disable interrupts before unmapping the memory! */
 		btwrite(0, BT848_INT_MASK);
 		btwrite(0xffffffffUL,BT848_INT_STAT);
 		btwrite(0x0, BT848_GPIO_OUT_EN);
 
-		bt848_cap(btv, 0);
-    
+    		/* unregister i2c_bus */
+		i2c_unregister_bus((&btv->i2c));
+
 		/* disable PCI bus-mastering */
 		pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
 		command|=PCI_COMMAND_MASTER;
 		pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command);
     
 		/* unmap and free memory */
+		if (btv->grisc)
+		        kfree((void *) btv->grisc);
+
 		if (btv->risc_odd)
 			kfree((void *) btv->risc_odd);
 			
@@ -2007,15 +2742,20 @@
 		DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%08x.\n", btv->vbibuf));
 		if (btv->vbibuf)
 			vfree((void *) btv->vbibuf);
+
+
 		free_irq(btv->irq,btv);
 		DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem));
 		if (btv->bt848_mem)
 			iounmap(btv->bt848_mem);
+
 		video_unregister_device(&btv->video_dev);
+		video_unregister_device(&btv->vbi_dev);
+		if (radio)
+			video_unregister_device(&btv->radio_dev);
 	}
 }
 
-
 #ifdef MODULE
 
 int init_module(void)
@@ -2030,22 +2770,39 @@
 	if (find_bt848()<0)
 		return -EIO;
 
+	/* initialize Bt848s */
 	for (i=0; i<bttv_num; i++) 
 	{
-		if (init_bt848(&bttvs[i])<0) 
+		if (init_bt848(i)<0) 
 		{
 			release_bttv();
 			return -EIO;
 		} 
-	}  
+	}
 	return 0;
 }
 
+
+
 #ifdef MODULE
 
 void cleanup_module(void)
 {
-	release_bttv();
+        release_bttv();
 }
 
 #endif
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.1.93/linux/drivers/char/bttv.h linux/drivers/char/bttv.h
--- v2.1.93/linux/drivers/char/bttv.h	Sat Nov 29 10:33:19 1997
+++ linux/drivers/char/bttv.h	Wed Apr  8 17:24:48 1998
@@ -26,72 +26,138 @@
 #include <linux/types.h>
 #include <linux/wait.h>
 
+#include "i2c.h"
+#include "msp3400.h"
 #include "bt848.h"
+#include <linux/videodev.h>
+
+#define MAX_CLIPRECS	100
+#define RISCMEM_LEN	(32744*2)
+#define MAX_FBUF	0x144000
+
+struct riscprog 
+{
+	unsigned int length;  
+	u32 *busadr;
+	u32 *prog;
+};
 
-typedef unsigned int dword;
 
-struct riscprog {
-  uint length;  
-  dword *busadr;
-  dword *prog;
+/* clipping rectangle */
+struct cliprec 
+{
+	int x, y, x2, y2;
+	struct cliprec *next;
 };
 
-/* values that can be set by user programs */
 
-struct bttv_window {
-  int x, y;
-  ushort width, height;
-  ushort bpp, bpl;
-  ushort swidth, sheight;
-  short cropx, cropy;
-  ushort cropwidth, cropheight;
-  int vidadr;
-  ushort freq;
-  int norm;
-  int interlace;
-  int color_fmt;
+/* grab buffer */
+struct gbuffer 
+{
+	struct gbuffer *next;
+	struct gbuffer *next_active;
+	void *adr;
+	int x, y;
+	int width, height;
+	unsigned int bpl;
+	unsigned int fmt;
+	int flags;
+#define GBUF_ODD  1
+#define GBUF_EVEN 2
+#define GBUF_LFB  4
+#define GBUF_INT  8
+	unsigned int length;
+	void *ro;
+	void *re;
+	u32 bro;
+	u32 bre;
 };
 
-/* private data that can only be read (or set indirectly) by user program */
 
-struct bttv {
-  struct video_device video_dev;
-  struct video_picture picture;		/* Current picture params */
-  struct video_audio audio_dev;		/* Current audio params */
-  u_char bus;          /* PCI bus the Bt848 is on */
-  u_char devfn;
-  u_char revision;
-  u_char irq;          /* IRQ used by Bt848 card */
-  uint bt848_adr;      /* bus address of IO mem returned by PCI BIOS */
-  u_char *bt848_mem;   /* pointer to mapped IO memory */
-  ulong busriscmem; 
-  dword *riscmem;
+#ifdef __KERNEL__
+
+struct bttv_window 
+{
+	int x, y;
+	ushort width, height;
+	ushort bpp, bpl;
+	ushort swidth, sheight;
+	short cropx, cropy;
+	ushort cropwidth, cropheight;
+	unsigned int vidadr;
+	ushort freq;
+	int norm;
+	int interlace;
+	int color_fmt;
+};
+
+
+struct bttv 
+{
+	struct video_device video_dev;
+	struct video_device radio_dev;
+	struct video_device vbi_dev;
+	struct video_picture picture;		/* Current picture params */
+	struct video_audio audio_dev;		/* Current audio params */
+
+	struct i2c_bus i2c;
+	int have_msp3400;
+	int have_tuner;
+
+	unsigned short id;
+	unsigned char bus;          /* PCI bus the Bt848 is on */
+	unsigned char devfn;
+	unsigned char revision;
+	unsigned char irq;          /* IRQ used by Bt848 card */
+	unsigned int bt848_adr;      /* bus address of IO mem returned by PCI BIOS */
+	unsigned char *bt848_mem;   /* pointer to mapped IO memory */
+	unsigned long busriscmem; 
+	u32 *riscmem;
   
-  u_char *vbibuf;
-  struct bttv_window win;
-  int type;            /* card type  */
-  int audio;           /* audio mode */
-  int user;
-  int tuner;
-  int tuneradr;
-  int dbx;
-
-  dword *risc_jmp;
-  dword *vbi_odd;
-  dword *vbi_even;
-  dword bus_vbi_even;
-  dword bus_vbi_odd;
-  struct wait_queue *vbiq;
-  struct wait_queue *capq;
-  int vbip;
-
-  dword *risc_odd;
-  dword *risc_even;
-  int cap;
+	unsigned char *vbibuf;
+	struct bttv_window win;
+	int type;            /* card type  */
+	int audio;           /* audio mode */
+	int user;
+	int dbx;
+	int radio;
+
+	u32 *risc_jmp;
+	u32 *vbi_odd;
+	u32 *vbi_even;
+	u32 bus_vbi_even;
+	u32 bus_vbi_odd;
+	struct wait_queue *vbiq;
+	struct wait_queue *capq;
+	struct wait_queue *capqo;
+	struct wait_queue *capqe;
+	int vbip;
+
+	u32 *risc_odd;
+	u32 *risc_even;
+	int cap;
+	struct cliprec *cliprecs;
+	int ncr;		/* number of clipping rectangles */
+
+	struct gbuffer *ogbuffers;
+	struct gbuffer *egbuffers;
+	u16 gwidth, gheight, gfmt;
+	u32 *grisc;
+	unsigned long gro;
+	unsigned long gre;
+	char *fbuffer;
+	int gmode;
+	int grabbing;
+	int lastgrab;
+	int grab;
+	int grabcount;
 };
 
+#endif
+
 /*The following should be done in more portable way. It depends on define
   of _ALPHA_BTTV in the Makefile.*/
+
 #ifdef _ALPHA_BTTV
 #define btwrite(dat,adr)    writel((dat),(char *) (btv->bt848_adr+(adr)))
 #define btread(adr)         readl(btv->bt848_adr+(adr))
@@ -105,30 +171,10 @@
 #define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
 
 /* bttv ioctls */
-#define BTTV_WRITE_BTREG   0x00
-#define BTTV_READ_BTREG    0x01
-#define BTTV_SET_BTREG     0x02
-#define BTTV_SETRISC       0x03
-#define BTTV_SETWTW        0x04
-#define BTTV_GETWTW        0x05
-#define BTTV_DMA           0x06
-#define BTTV_CAP_OFF       0x07
-#define BTTV_CAP_ON        0x08
-#define BTTV_GETBTTV       0x09
-#define BTTV_SETFREQ       0x0a
-#define BTTV_SETCHAN       0x0b
-#define BTTV_INPUT         0x0c
-#define BTTV_READEE        0x0d
-#define BTTV_WRITEEE       0x0e
-#define BTTV_BRIGHT        0x0f
-#define BTTV_HUE           0x10
-#define BTTV_COLOR         0x11
-#define BTTV_CONTRAST      0x12
-#define BTTV_SET_FFREQ     0x13
-#define BTTV_MUTE          0x14
 
-#define BTTV_GRAB          0x20
-#define BTTV_TESTM         0x20
+#define BTTV_READEE		_IOW('v',  BASE_VIDIOCPRIVATE+0, char [256])
+#define BTTV_WRITEE		_IOR('v',  BASE_VIDIOCPRIVATE+1, char [256])
+#define BTTV_GRAB		_IOR('v' , BASE_VIDIOCPRIVATE+2, struct gbuf)
 
 
 #define BTTV_UNKNOWN       0x00
@@ -137,12 +183,14 @@
 #define BTTV_STB           0x03
 #define BTTV_INTEL         0x04
 #define BTTV_DIAMOND       0x05 
+#define BTTV_AVERMEDIA     0x06 
 
 #define AUDIO_TUNER        0x00
-#define AUDIO_EXTERN       0x01
-#define AUDIO_INTERN       0x02
-#define AUDIO_OFF          0x03 
-#define AUDIO_ON           0x04
+#define AUDIO_RADIO        0x01
+#define AUDIO_EXTERN       0x02
+#define AUDIO_INTERN       0x03
+#define AUDIO_OFF          0x04 
+#define AUDIO_ON           0x05
 #define AUDIO_MUTE         0x80
 #define AUDIO_UNMUTE       0x81
 
diff -u --recursive --new-file v2.1.93/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c
--- v2.1.93/linux/drivers/char/bw-qcam.c	Mon Feb 23 18:12:04 1998
+++ linux/drivers/char/bw-qcam.c	Wed Apr  8 17:24:48 1998
@@ -885,7 +885,7 @@
 	
 	printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
 	
-	if(video_register_device(&qcam->vdev)==-1)
+	if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1)
 	{
 		parport_unregister_device(qcam->pdev);
 		kfree(qcam);
diff -u --recursive --new-file v2.1.93/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c
--- v2.1.93/linux/drivers/char/c-qcam.c	Mon Feb 23 18:12:04 1998
+++ linux/drivers/char/c-qcam.c	Wed Apr  8 17:24:48 1998
@@ -727,7 +727,7 @@
 	printk(KERN_INFO "Connectix Colour Quickcam on %s\n", 
 	       qcam->pport->name);
 	
-	if (video_register_device(&qcam->vdev)==-1)
+	if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1)
 	{
 		parport_unregister_device(qcam->pdev);
 		kfree(qcam);
diff -u --recursive --new-file v2.1.93/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.1.93/linux/drivers/char/console.c	Wed Apr  1 20:11:48 1998
+++ linux/drivers/char/console.c	Wed Apr  8 11:30:27 1998
@@ -204,7 +204,6 @@
 int want_console = -1;
 int kmsg_redirect = 0;
 
-#define CONFIG_SERIAL_ECHO
 #ifdef CONFIG_SERIAL_ECHO
 
 #include <linux/serial_reg.h>
diff -u --recursive --new-file v2.1.93/linux/drivers/char/hfmodem/gentbl.c linux/drivers/char/hfmodem/gentbl.c
--- v2.1.93/linux/drivers/char/hfmodem/gentbl.c	Thu Mar 26 15:57:02 1998
+++ linux/drivers/char/hfmodem/gentbl.c	Tue Apr  7 07:48:54 1998
@@ -62,7 +62,7 @@
 	printf("/*\n * This file is automatically generated by %s, DO NOT EDIT!\n*/\n\n",
 	       argv[0]);
 	gensintbl();
-	return(0);
+	exit(0);
 }
 
 /* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.1.93/linux/drivers/char/i2c.c linux/drivers/char/i2c.c
--- v2.1.93/linux/drivers/char/i2c.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/i2c.c	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,430 @@
+/*
+ *	Generic i2c interface for linux
+ *
+ *	(c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/locks.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+
+#include "i2c.h"
+
+#define REGPRINT(x)   if (verbose)   (x)
+#define I2C_DEBUG(x)  if (i2c_debug) (x)
+
+static int scan      = 0;
+static int verbose   = 1;
+static int i2c_debug = 0;
+
+MODULE_PARM(scan,"i");
+MODULE_PARM(verbose,"i");
+MODULE_PARM(i2c_debug,"i");
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_bus    *busses[I2C_BUS_MAX];
+static struct i2c_driver *drivers[I2C_DRIVER_MAX];
+static int bus_count = 0, driver_count = 0;
+
+int i2c_init(void)
+{
+	printk(KERN_INFO "i2c: initialized%s\n",
+		scan ? " (i2c bus scan enabled)" : "");
+	/* anything to do here ? */
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void i2c_attach_device(struct i2c_bus *bus, struct i2c_driver *driver)
+{
+	unsigned long flags;
+	struct i2c_device *device;
+	int i,j,ack=1;
+	unsigned char addr;
+    
+	/* probe for device */
+	LOCK_I2C_BUS(bus);
+	for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) 
+	{
+		i2c_start(bus);
+		ack = i2c_sendbyte(bus,addr,0);
+		i2c_stop(bus);
+		if (!ack)
+			break;
+	}
+	UNLOCK_I2C_BUS(bus);
+	if (ack)
+		return;
+
+	/* got answer */
+	for (i = 0; i < I2C_DEVICE_MAX; i++)
+		if (NULL == driver->devices[i])
+			break;
+	if (I2C_DEVICE_MAX == i)
+		return;
+
+	for (j = 0; j < I2C_DEVICE_MAX; j++)
+		if (NULL == bus->devices[j])
+			break;
+	if (I2C_DEVICE_MAX == j)
+		return;
+
+	if (NULL == (device = kmalloc(sizeof(struct i2c_device),GFP_KERNEL)))
+		return;
+	device->bus = bus;
+	device->driver = driver;
+	device->addr = addr;
+
+	/* Attach */
+	
+	if (driver->attach(device)!=0) 
+	{
+		kfree(device);
+		return;
+	}
+	driver->devices[i] = device;
+	driver->devcount++;
+	bus->devices[j] = device;
+	bus->devcount++;
+
+	if (bus->attach_inform)
+		bus->attach_inform(bus,driver->id);
+	REGPRINT(printk("i2c: device attached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,addr,bus->name,driver->name));
+}
+
+static void i2c_detach_device(struct i2c_device *device)
+{
+	int i;
+
+	if (device->bus->detach_inform)
+		device->bus->detach_inform(device->bus,device->driver->id);
+	device->driver->detach(device);
+
+	for (i = 0; i < I2C_DEVICE_MAX; i++)
+		if (device == device->driver->devices[i])
+			break;
+	if (I2C_DEVICE_MAX == i) 
+	{
+		printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n",
+			device->name);
+		return;
+	}
+	device->driver->devices[i] = NULL;
+	device->driver->devcount--;
+
+	for (i = 0; i < I2C_DEVICE_MAX; i++)
+		if (device == device->bus->devices[i])
+			break;
+	if (I2C_DEVICE_MAX == i) 
+	{
+		printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n",
+		       device->name);
+		return;
+	}
+	device->bus->devices[i] = NULL;
+	device->bus->devcount--;
+
+	REGPRINT(printk("i2c: device detached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,device->addr,device->bus->name,device->driver->name));
+	kfree(device);
+}
+
+/* ----------------------------------------------------------------------- */
+
+int i2c_register_bus(struct i2c_bus *bus)
+{
+	unsigned long flags;
+	int i,ack;
+
+	memset(bus->devices,0,sizeof(bus->devices));
+	bus->devcount = 0;
+
+	for (i = 0; i < I2C_BUS_MAX; i++)
+		if (NULL == busses[i])
+			break;
+	if (I2C_BUS_MAX == i)
+		return -ENOMEM;
+
+	busses[i] = bus;
+	bus_count++;
+	REGPRINT(printk("i2c: bus registered: %s\n",bus->name));
+	
+	MOD_INC_USE_COUNT;
+
+	if (scan) 
+	{
+		/* scan whole i2c bus */
+		LOCK_I2C_BUS(bus);
+		for (i = 0; i < 256; i+=2) 
+		{
+			i2c_start(bus);
+			ack = i2c_sendbyte(bus,i,0);
+			i2c_stop(bus);
+			if (!ack) 
+			{
+				printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n",
+					bus->name,i);
+			}
+		}
+		UNLOCK_I2C_BUS(bus);
+	}
+
+	/* probe available drivers */
+	for (i = 0; i < I2C_DRIVER_MAX; i++)
+		if (drivers[i])
+			i2c_attach_device(bus,drivers[i]);
+	return 0;
+}
+
+int i2c_unregister_bus(struct i2c_bus *bus)
+{
+	int i;
+
+	/* detach devices */
+	for (i = 0; i < I2C_DEVICE_MAX; i++)
+		if (bus->devices[i])
+			i2c_detach_device(bus->devices[i]);
+
+	for (i = 0; i < I2C_BUS_MAX; i++)
+		if (bus == busses[i])
+			break;
+	if (I2C_BUS_MAX == i) 
+	{
+		printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n",
+			bus->name);
+		return -ENODEV;
+	}
+	
+	MOD_DEC_USE_COUNT;
+	
+	busses[i] = NULL;
+	bus_count--;
+	REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name));
+
+	return 0;    
+}
+
+/* ----------------------------------------------------------------------- */
+
+int i2c_register_driver(struct i2c_driver *driver)
+{
+	int i;
+
+	memset(driver->devices,0,sizeof(driver->devices));
+	driver->devcount = 0;
+
+	for (i = 0; i < I2C_DRIVER_MAX; i++)
+		if (NULL == drivers[i])
+			break;
+	if (I2C_DRIVER_MAX == i)
+		return -ENOMEM;
+
+	drivers[i] = driver;
+	driver_count++;
+	
+	MOD_INC_USE_COUNT;
+	
+	REGPRINT(printk("i2c: driver registered: %s\n",driver->name));
+
+	/* Probe available busses */
+	for (i = 0; i < I2C_BUS_MAX; i++)
+		if (busses[i])
+			i2c_attach_device(busses[i],driver);
+
+	return 0;
+}
+
+int i2c_unregister_driver(struct i2c_driver *driver)
+{
+	int i;
+
+	/* detach devices */
+	for (i = 0; i < I2C_DEVICE_MAX; i++)
+		if (driver->devices[i])
+			i2c_detach_device(driver->devices[i]);
+
+	for (i = 0; i < I2C_DRIVER_MAX; i++)
+		if (driver == drivers[i])
+			break;
+	if (I2C_DRIVER_MAX == i) 
+	{
+		printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n",
+			driver->name);
+		return -ENODEV;
+	}
+
+	MOD_DEC_USE_COUNT;
+	
+	drivers[i] = NULL;
+	driver_count--;
+	REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name));
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int i2c_control_device(struct i2c_bus *bus, int id,
+		       unsigned int cmd, void *arg)
+{
+	int i;
+
+	for (i = 0; i < I2C_DEVICE_MAX; i++)
+		if (bus->devices[i] && bus->devices[i]->driver->id == id)
+			break;
+	if (i == I2C_DEVICE_MAX)
+		return -ENODEV;
+	if (NULL == bus->devices[i]->driver->command)
+		return -ENODEV;
+	return bus->devices[i]->driver->command(bus->devices[i],cmd,arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+#define I2C_SET(bus,ctrl,data)  (bus->i2c_setlines(bus,ctrl,data))
+#define I2C_GET(bus)            (bus->i2c_getdataline(bus))
+
+void i2c_start(struct i2c_bus *bus)
+{
+	I2C_SET(bus,0,1);
+	I2C_SET(bus,1,1);
+	I2C_SET(bus,1,0);
+	I2C_SET(bus,0,0);
+	I2C_DEBUG(printk("%s: < ",bus->name));
+}
+
+void i2c_stop(struct i2c_bus *bus)
+{
+	I2C_SET(bus,0,0);
+	I2C_SET(bus,1,0);
+	I2C_SET(bus,1,1);
+	I2C_DEBUG(printk(">\n"));
+}
+
+void i2c_one(struct i2c_bus *bus)
+{
+	I2C_SET(bus,0,1);
+	I2C_SET(bus,1,1);
+	I2C_SET(bus,0,1);
+}
+
+void i2c_zero(struct i2c_bus *bus)
+{
+	I2C_SET(bus,0,0);
+	I2C_SET(bus,1,0);
+	I2C_SET(bus,0,0);
+}
+
+int i2c_ack(struct i2c_bus *bus)
+{
+	int ack;
+    
+	I2C_SET(bus,0,1);
+	I2C_SET(bus,1,1);
+	ack = I2C_GET(bus);
+	I2C_SET(bus,0,1);
+	return ack;
+}
+
+int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack)
+{
+	int i, ack;
+    
+	I2C_SET(bus,0,0);
+	for (i=7; i>=0; i--)
+		(data&(1<<i)) ? i2c_one(bus) : i2c_zero(bus);
+	if (wait_for_ack)
+		udelay(wait_for_ack);
+	ack=i2c_ack(bus);
+	I2C_DEBUG(printk("%02x%c ",(int)data,ack?'-':'+'));
+	return ack;
+}
+
+unsigned char i2c_readbyte(struct i2c_bus *bus,int last)
+{
+	int i;
+	unsigned char data=0;
+    
+	I2C_SET(bus,0,1);
+	for (i=7; i>=0; i--) 
+	{
+		I2C_SET(bus,1,1);
+		if (I2C_GET(bus))
+			data |= (1<<i);
+		I2C_SET(bus,0,1);
+	}
+	last ? i2c_one(bus) : i2c_zero(bus);
+	I2C_DEBUG(printk("=%02x%c ",(int)data,last?'-':'+'));
+	return data;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int i2c_read(struct i2c_bus *bus, unsigned char addr)
+{
+	int ret;
+    
+	if (bus->i2c_read)
+		return bus->i2c_read(bus, addr);
+
+	i2c_start(bus);
+	i2c_sendbyte(bus,addr,0);
+	ret = i2c_readbyte(bus,1);
+	i2c_stop(bus);
+	return ret;
+}
+
+int i2c_write(struct i2c_bus *bus, unsigned char addr,
+	      unsigned char data1, unsigned char data2, int both)
+{
+	int ack;
+
+	if (bus->i2c_write)
+		return bus->i2c_write(bus, addr, data1, data2, both);
+
+	i2c_start(bus);
+	i2c_sendbyte(bus,addr,0);
+	ack = i2c_sendbyte(bus,data1,0);
+	if (both)
+		ack = i2c_sendbyte(bus,data2,0);
+	i2c_stop(bus);
+	return ack ? -1 : 0 ;
+}
+
+/* ----------------------------------------------------------------------- */
+
+#ifdef MODULE
+
+EXPORT_SYMBOL(i2c_register_bus);
+EXPORT_SYMBOL(i2c_unregister_bus);
+EXPORT_SYMBOL(i2c_register_driver);
+EXPORT_SYMBOL(i2c_unregister_driver);
+EXPORT_SYMBOL(i2c_control_device);
+EXPORT_SYMBOL(i2c_start);
+EXPORT_SYMBOL(i2c_stop);
+EXPORT_SYMBOL(i2c_one);
+EXPORT_SYMBOL(i2c_zero);
+EXPORT_SYMBOL(i2c_ack);
+EXPORT_SYMBOL(i2c_sendbyte);
+EXPORT_SYMBOL(i2c_readbyte);
+EXPORT_SYMBOL(i2c_read);
+EXPORT_SYMBOL(i2c_write);
+
+
+int init_module(void)
+{
+	return i2c_init();
+}
+
+void cleanup_module(void)
+{
+}
+#endif
diff -u --recursive --new-file v2.1.93/linux/drivers/char/i2c.h linux/drivers/char/i2c.h
--- v2.1.93/linux/drivers/char/i2c.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/i2c.h	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,166 @@
+#ifndef I2C_H
+#define I2C_H
+
+/*
+ * linux i2c interface.  Works a little bit like the scsi subsystem.
+ * There are:
+ *
+ *     i2c          the basic control module        (like scsi_mod)
+ *     bus driver   a driver with a i2c bus         (hostadapter driver)
+ *     chip driver  a driver for a chip connected
+ *                  to a i2c bus                    (cdrom/hd driver)
+ *
+ * A device will be attached to one bus and one chip driver.  Every chip
+ * driver gets a unique ID.
+ *
+ * A chip driver can provide a ioctl-like callback for the
+ * communication with other parts of the kernel (not every i2c chip is
+ * useful without other devices, a TV card tuner for example). 
+ *
+ * "i2c internal" parts of the structs: only the i2c module is allowed to
+ * write to them, for others they are read-only.
+ *
+ */
+
+#define I2C_BUS_MAX       4    /* max # of bus drivers  */
+#define I2C_DRIVER_MAX    8    /* max # of chip drivers */
+#define I2C_DEVICE_MAX    8    /* max # if devices per bus/driver */
+
+struct i2c_bus;
+struct i2c_driver;
+struct i2c_device;
+
+#define I2C_DRIVERID_MSP3400     1
+#define I2C_DRIVERID_TUNER       2
+#define I2C_DRIVERID_VIDEOTEXT	 3
+
+#define I2C_BUSID_BT848		1	/* I2C bus on a BT848 */
+
+/*
+ * struct for a driver for a i2c chip (tuner, soundprocessor,
+ * videotext, ... ).
+ *
+ * a driver will register within the i2c module.  The i2c module will
+ * callback the driver (i2c_attach) for every device it finds on a i2c
+ * bus at the specified address.  If the driver decides to "accept"
+ * the, device, it must return a struct i2c_device, and NULL
+ * otherwise.
+ *
+ * i2c_detach = i2c_attach ** -1
+ * 
+ * i2c_command will be used to pass commands to the driver in a
+ * ioctl-line manner.
+ *
+ */
+
+struct i2c_driver 
+{
+    char           name[32];         /* some useful label         */
+    int            id;               /* device type ID            */
+    unsigned char  addr_l, addr_h;   /* address range of the chip */
+
+    int (*attach)(struct i2c_device *device);
+    int (*detach)(struct i2c_device *device);
+    int (*command)(struct i2c_device *device,unsigned int cmd, void *arg);
+
+    /* i2c internal */
+    struct i2c_device   *devices[I2C_DEVICE_MAX];
+    int                 devcount;
+};
+
+
+/*
+ * this holds the informations about a i2c bus available in the system.
+ * 
+ * a chip with a i2c bus interface (like bt848) registers the bus within
+ * the i2c module. This struct provides functions to access the i2c bus.
+ * 
+ * One must hold the spinlock to access the i2c bus (XXX: is the irqsave
+ * required? Maybe better use a semaphore?). 
+ * [-AC-] having a spinlock_irqsave is only needed if we have drivers wishing
+ *	  to bang their i2c bus from an interrupt.
+ * 
+ * attach/detach_inform is a callback to inform the bus driver about
+ * attached chip drivers.
+ *
+ */
+
+/* needed: unsigned long flags */
+
+#define LOCK_I2C_BUS(bus)    spin_lock_irqsave(&(bus->bus_lock),flags);
+#define UNLOCK_I2C_BUS(bus)  spin_unlock_irqrestore(&(bus->bus_lock),flags);
+
+struct i2c_bus 
+{
+	char  name[32];         /* some useful label */
+	int   id;
+	void  *data;            /* free for use by the bus driver */
+
+	spinlock_t bus_lock;
+
+	/* attach/detach inform callbacks */
+	void    (*attach_inform)(struct i2c_bus *bus, int id);
+	void    (*detach_inform)(struct i2c_bus *bus, int id);
+
+	/* Software I2C */
+	void    (*i2c_setlines)(struct i2c_bus *bus, int ctrl, int data);
+	int     (*i2c_getdataline)(struct i2c_bus *bus);
+
+	/* Hardware I2C */
+	int     (*i2c_read)(struct i2c_bus *bus, unsigned char addr);
+	int     (*i2c_write)(struct i2c_bus *bus, unsigned char addr,
+			 unsigned char b1, unsigned char b2, int both);
+
+	/* internal data for i2c module */
+	struct i2c_device   *devices[I2C_DEVICE_MAX];
+	int                 devcount;
+};
+
+
+/*
+ *	This holds per-device data for a i2c device
+ */
+
+struct i2c_device 
+{
+	char           name[32];         /* some useful label */
+	void           *data;            /* free for use by the chip driver */
+	unsigned char  addr;             /* chip addr */
+
+	/* i2c internal */
+	struct i2c_bus     *bus;
+	struct i2c_driver  *driver;
+};
+
+
+/* ------------------------------------------------------------------- */
+/* i2c module functions                                                */
+
+/* register/unregister a i2c bus */
+int i2c_register_bus(struct i2c_bus *bus);
+int i2c_unregister_bus(struct i2c_bus *bus);
+
+/* register/unregister a chip driver */
+int i2c_register_driver(struct i2c_driver *driver);
+int i2c_unregister_driver(struct i2c_driver *driver);
+
+/* send a command to a chip using the ioctl-like callback interface */
+int i2c_control_device(struct i2c_bus *bus, int id,
+		       unsigned int cmd, void *arg);
+
+/* i2c bus access functions */
+void    i2c_start(struct i2c_bus *bus);
+void    i2c_stop(struct i2c_bus *bus);
+void    i2c_one(struct i2c_bus *bus);
+void    i2c_zero(struct i2c_bus *bus);
+int     i2c_ack(struct i2c_bus *bus);
+
+int     i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack);
+unsigned char i2c_readbyte(struct i2c_bus *bus,int last);
+
+/* i2c (maybe) hardware functions */
+int     i2c_read(struct i2c_bus *bus, unsigned char addr);
+int     i2c_write(struct i2c_bus *bus, unsigned char addr,
+		  unsigned char b1, unsigned char b2, int both);
+
+#endif /* I2C_H */
diff -u --recursive --new-file v2.1.93/linux/drivers/char/joystick.c linux/drivers/char/joystick.c
--- v2.1.93/linux/drivers/char/joystick.c	Tue Mar 10 10:03:31 1998
+++ linux/drivers/char/joystick.c	Wed Apr  8 17:24:48 1998
@@ -1,7 +1,7 @@
 /*
- *  $Id: joystick.c,v 1.2 1997/10/31 19:11:48 mj Exp $
+ *  $Id: joystick.c,v 1.6 1998/03/30 11:10:43 mj Exp $
  *
- *  Copyright (C) 1997 Vojtech Pavlik
+ *  Copyright (C) 1997, 1998 Vojtech Pavlik
  */
 
 /*
@@ -15,25 +15,20 @@
 #include <linux/ioport.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
-#include <linux/ptrace.h>
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
 #include <linux/poll.h>
 #include <linux/major.h>
 #include <linux/joystick.h>
-
 #include <asm/io.h>
-#include <asm/ptrace.h>
-#include <asm/uaccess.h>
-#include <asm/param.h>
 
 #define PIT_HZ			1193180L	/* PIT clock is 1.19318 MHz */
 
 #define JS_MAXTIME		PIT_HZ/250	/* timeout for read (4 ms) */
 
-#define JS_BUTTON_PERIOD	HZ/50		/* button valid time (20 ms) */
-#define JS_AXIS_MIN_PERIOD	HZ/25		/* axis min valid time (40 ms) */
-#define JS_AXIS_MAX_PERIOD	HZ/25*2		/* axis max valid time (80 ms) */
+#define JS_TIMER_PERIOD		HZ/50		/* button valid time (20 ms) */
+#define JS_BH_MIN_PERIOD	HZ/25		/* axis min valid time (40 ms) */
+#define JS_BH_MAX_PERIOD	HZ/25*2		/* axis max valid time (80 ms) */
 
 #define JS_FIFO_SIZE    	16		/* number of FIFO entries */
 #define JS_BUFF_SIZE		32 		/* output buffer size */
@@ -95,7 +90,7 @@
 static struct js_fifo js_fifo[JS_FIFO_SIZE];		/* the fifo */
 
 static unsigned char js_last_buttons = 0;		/* last read button state */
-static unsigned long js_axis_time = 0;			/* last read axis time */
+static unsigned long js_bh_time = 0;			/* last read axis time */
 static unsigned long js_mark_time = 0;
 
 static unsigned char js_axes_exist;			/* all axes that exist */
@@ -132,12 +127,14 @@
  * count_bits() counts set bits in a byte.
  */
 
-static int count_bits(unsigned char c)
+static int count_bits(unsigned int c)
 {
-	int i, t = 0;
-	for (i = 0; i < 8; i++)
-		if (c & (1 << i)) t++;
-	return t;
+	int i = 0;
+	while (c) {
+		i += c & 1;
+		c >>= 1;
+	}
+	return i;
 }
 
 /*
@@ -228,14 +225,59 @@
 		}
 	} 
 	else
- 	if ((jiffies > js_axis_time + JS_AXIS_MAX_PERIOD) && !js_mark_time) {
+ 	if ((jiffies > js_bh_time + JS_BH_MAX_PERIOD) && !js_mark_time) {
 		js_mark_time = jiffies;
 		mark_bh(JS_BH);
 	}
-	js_timer.expires = jiffies + JS_BUTTON_PERIOD;
+	js_timer.expires = jiffies + JS_TIMER_PERIOD;
 	add_timer(&js_timer);
 }
 
+
+/*
+ * Put an event in the buffer. This requires additional queue processing
+ * done by js_sync_buff, otherwise the buffer will be corrupted.
+ */
+
+static void js_add_event(int i, __u32 time, __u8 type, __u8 number, __u16 value)
+{
+	int ahead = jsd[i].ahead++;
+	jsd[i].buff[ahead].time = time;
+	jsd[i].buff[ahead].type = type;
+	jsd[i].buff[ahead].number = number;
+	jsd[i].buff[ahead].value = value;
+	if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead=0;
+}
+
+/*
+ * This checks for all owerflows caused by recent additions to the buffer.
+ * It does anything only if some processes are reading the data too slowly.
+ */
+
+static void js_sync_buff(void)
+{
+	int i;
+	
+	for (i = 0; i < JS_NUM; i++)
+	if (jsd[i].list)
+	if (jsd[i].bhead != jsd[i].ahead)	{
+		if (ROT(jsd[i].bhead, jsd[i].tail, jsd[i].ahead) || (jsd[i].tail == jsd[i].bhead)) {
+			struct js_list *curl;
+			curl = jsd[i].list;
+			while (curl) {
+				if (ROT(jsd[i].bhead, curl->tail, jsd[i].ahead) || (curl->tail == jsd[i].bhead)) {
+					curl->tail = jsd[i].ahead; 				
+					curl->startup = jsd[i].exist;
+				}
+				curl = curl->next;
+			}
+			jsd[i].tail = jsd[i].ahead;		
+		}
+		jsd[i].bhead = jsd[i].ahead;
+		wake_up_interruptible(&jsd[i].wait);
+	}
+}
+
 /*
  * js_do_bh() does the main processing and adds events to output buffers.
  */
@@ -246,7 +288,7 @@
 	int i, j, k;
 	unsigned int t;
 
-	if (jiffies > js_axis_time + JS_AXIS_MIN_PERIOD) {
+	if (jiffies > js_bh_time + JS_BH_MIN_PERIOD) {
 
 		unsigned int old_axis[4];
 		unsigned int t_low, t_high;
@@ -348,18 +390,12 @@
 			k = 0;
 			for (j = 0; j < 4; j++)
 			if ((1 << j) & jsd[i].exist) {
-				if (!js_compare(js_axis[j].value, old_axis[j], js_axis[j].corr.prec)) {
-					jsd[i].buff[jsd[i].ahead].time = js_mark_time;
-					jsd[i].buff[jsd[i].ahead].type = JS_EVENT_AXIS;
-					jsd[i].buff[jsd[i].ahead].number = k;
-					jsd[i].buff[jsd[i].ahead].value = js_axis[j].value;
-					jsd[i].ahead++;
-					if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead = 0;
-				}
+				if (!js_compare(js_axis[j].value, old_axis[j], js_axis[j].corr.prec))
+					js_add_event(i, js_mark_time, JS_EVENT_AXIS, k, js_axis[j].value);
 				k++;
 			}
 		}
-		js_axis_time = jiffies;
+		js_bh_time = jiffies;
 	}
 	js_mark_time = 0;
 
@@ -373,14 +409,8 @@
 			k = 0;
 			for (j = 4; j < 8; j++)
 			if ((1 << j) & jsd[i].exist) {
-				if ((1 << j) & (js_buttons ^ js_fifo[t].event)) {
-					jsd[i].buff[jsd[i].ahead].time = js_fifo[t].time;
-					jsd[i].buff[jsd[i].ahead].type = JS_EVENT_BUTTON;
-					jsd[i].buff[jsd[i].ahead].number = k;
-					jsd[i].buff[jsd[i].ahead].value = (js_fifo[t].event >> j) & 1;
-					jsd[i].ahead++;
-					if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead = 0;
-					}
+				if ((1 << j) & (js_buttons ^ js_fifo[t].event))
+					js_add_event(i, js_fifo[t].time, JS_EVENT_BUTTON, k, (js_fifo[t].event >> j) & 1);
 				k++;
 			}
 		}
@@ -388,27 +418,10 @@
 	}
 
 /*
- * Sync ahead with bhead and cut too long tails.
+ * Synchronize the buffer.
  */
-	
-	for (i = 0; i < JS_NUM; i++)
-	if (jsd[i].list)
-	if (jsd[i].bhead != jsd[i].ahead)	{
-		if (ROT(jsd[i].bhead, jsd[i].tail, jsd[i].ahead) || (jsd[i].tail == jsd[i].bhead)) {
-			struct js_list *curl;
-			curl = jsd[i].list;
-			while (curl) {
-				if (ROT(jsd[i].bhead, curl->tail, jsd[i].ahead) || (curl->tail == jsd[i].bhead)) {
-					curl->tail = jsd[i].ahead; 				
-					curl->startup = jsd[i].exist;
-				}
-				curl = curl->next;
-			}
-			jsd[i].tail = jsd[i].ahead;		
-		}
-		jsd[i].bhead = jsd[i].ahead;
-		wake_up_interruptible(&jsd[i].wait);
-	}
+
+	js_sync_buff();
 
 }
 
@@ -459,38 +472,46 @@
  * Handle (non)blocking i/o.
  */
 
-	if (count != sizeof(struct JS_DATA_TYPE)) {
 
-		if ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup) || (curl->startup && !js_axis_time)) {
-			add_wait_queue(&jsd[minor].wait, &wait);
-			current->state = TASK_INTERRUPTIBLE;
-			while ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup) || (curl->startup && !js_axis_time)) {
-				if (file->f_flags & O_NONBLOCK) {
-					retval = -EAGAIN;
-					break;
-				}
-				if (signal_pending(current)) {
-					retval = -ERESTARTSYS;
-					break;
-				}
-				schedule();
-				if (!jsd[minor].exist) {
-					retval = -ENODEV;
-					break;
-				}
+	if ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup && count != sizeof(struct JS_DATA_TYPE))
+            || (curl->startup && !js_bh_time)) {
+
+		add_wait_queue(&jsd[minor].wait, &wait);
+		current->state = TASK_INTERRUPTIBLE;
+
+		while ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup && count != sizeof(struct JS_DATA_TYPE))
+		       || (curl->startup && !js_bh_time)) {
+
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+			if (!jsd[minor].exist) {
+				retval = -ENODEV;
+				break;
 			}
-			current->state = TASK_RUNNING;
-			remove_wait_queue(&jsd[minor].wait, &wait);
 		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&jsd[minor].wait, &wait);
+	}
 
-		if (retval) return retval;
+	if (retval) return retval;
 	
 /*
  * Do the i/o.
  */
+	if (count != sizeof(struct JS_DATA_TYPE)) {
 
 		if (curl->startup) {
 			struct js_event tmpevent;
+/*
+ * Initial button state.
+ */
 
 			t = 0;
 			for (j = 0; j < 4 && (i < blocks) && !retval; j++)
@@ -509,6 +530,10 @@
 				t++;	
 			}
 
+/*
+ * Initial axis state.
+ */
+
 			t = 0;
 			for (j = 4; j < 8 && (i < blocks) && !retval; j++)
 			if (jsd[minor].exist & (1 << j)) {
@@ -527,6 +552,9 @@
 			}
 		}
 
+/*
+ * Buffer data.
+ */
 
 		while ((jsd[minor].ahead != (t = GOF(curl->tail))) && (i < blocks) && !retval) {
 			if (copy_to_user(&buff[i], &jsd[minor].buff[t], sizeof(struct js_event)))
@@ -562,6 +590,7 @@
 			buttons |= (!!(js_last_buttons & (1 << j))) << (i++);
 		copy_to_user(&bufo->buttons, &buttons, sizeof(int));
 
+		curl->startup = 0;
 		curl->tail = GOB(jsd[minor].ahead);
 		retval = sizeof(struct JS_DATA_TYPE);
 	}
@@ -637,7 +666,7 @@
 				sizeof(struct js_corr))) return -EFAULT;
 			j++;
 		}
-		js_axis_time = 0;
+		js_bh_time = 0;
 		break;
 	case JSIOCGCORR:
 		j = 0;
@@ -680,7 +709,7 @@
 	MOD_INC_USE_COUNT;
 
 	if (!jsd[0].list && !jsd[1].list) { 
-		js_timer.expires = jiffies + JS_BUTTON_PERIOD;
+		js_timer.expires = jiffies + JS_TIMER_PERIOD;
 		add_timer(&js_timer);
 	}
 
@@ -793,8 +822,8 @@
 	}
 
 	for (i = 0; i < JS_NUM; i++) {
-		if (jsd[i].exist) printk(KERN_INFO "js%d: %d-axis joystick at %#x\n",
-			 i,  count_bits(jsd[i].exist & JS_AXES), JS_PORT);
+		if (jsd[i].exist) printk(KERN_INFO "js%d: %d-axis %d-button joystick at %#x\n",
+			 i,  count_bits(jsd[i].exist & JS_AXES), count_bits(jsd[i].exist & JS_AXES), JS_PORT);
 		jsd[i].ahead = jsd[i].bhead = 0;
 		jsd[i].tail = JS_BUFF_SIZE - 1;
 		jsd[i].list = NULL;
diff -u --recursive --new-file v2.1.93/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.93/linux/drivers/char/lp.c	Wed Apr  1 20:11:48 1998
+++ linux/drivers/char/lp.c	Wed Apr  8 17:27:12 1998
@@ -14,6 +14,8 @@
  *                                             carsten@sol.wohnheim.uni-ulm.de
  * Support for parport by Philip Blundell <Philip.Blundell@pobox.com>
  * parport_sharing hacking by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * Fixed kernel_(to/from)_user memory copy to check for errors
+ * 				by Riccardo Facchetti <fizban@tin.it>
  */
 
 /* This driver should, in theory, work with any parallel port that has an
@@ -273,7 +275,9 @@
 	do {
 		bytes_written = 0;
 		copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
-		copy_from_user(lp->lp_buffer, buf, copy_size);
+
+		if (copy_from_user(lp->lp_buffer, buf, copy_size))
+			return -EFAULT;
 
 		while (copy_size) {
 			if (lp_char(lp->lp_buffer[bytes_written], minor)) {
@@ -459,15 +463,19 @@
 			current->timeout=jiffies + LP_TIME(minor);
 			schedule ();
 		}
+
 		counter=0;
+
 		if (( i & 1) != 0) {
 			Byte= (Byte | z<<4);
-			put_user(Byte, temp);
+			if (put_user(Byte, (char *)temp))
+				return -EFAULT;
 			temp++;
 		} else Byte=z;
 	}
+
 	lp_select_in_high(minor);
-	parport_release(lp_table[minor].dev);
+	lp_parport_release(minor);
 	return temp-buf;	
 }
 
@@ -538,6 +546,7 @@
 		    unsigned int cmd, unsigned long arg)
 {
 	unsigned int minor = MINOR(inode->i_rdev);
+	int status;
 	int retval = 0;
 
 #ifdef LP_DEBUG
@@ -579,48 +588,33 @@
 			return -EINVAL;
 			break;
 		case LPGETIRQ:
-			retval = verify_area(VERIFY_WRITE, (void *) arg,
-			    sizeof(int));
-		    	if (retval)
-		    		return retval;
-			copy_to_user((int *) arg, &LP_IRQ(minor), sizeof(int));
+			if (copy_to_user((int *) arg, &LP_IRQ(minor),
+					sizeof(int)))
+				return -EFAULT;
 			break;
 		case LPGETSTATUS:
-			retval = verify_area(VERIFY_WRITE, (void *) arg,
-			    sizeof(int));
-		    	if (retval)
-		    		return retval;
-			else {
-				int status;
-				lp_parport_claim (minor);
-				status = r_str(minor);
-				lp_parport_release (minor);
-				copy_to_user((int *) arg, &status, sizeof(int));
-			}
+			lp_parport_claim(minor);
+			status = r_str(minor);
+			lp_parport_release(minor);
+
+			if (copy_to_user((int *) arg, &status, sizeof(int)))
+				return -EFAULT;
 			break;
 		case LPRESET:
 			lp_reset(minor);
 			break;
 		case LPGETSTATS:
-			retval = verify_area(VERIFY_WRITE, (void *) arg,
-			    sizeof(struct lp_stats));
-		    	if (retval)
-		    		return retval;
-			else {
-				copy_to_user((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats));
-				if (suser())
-					memset(&LP_STAT(minor), 0, sizeof(struct lp_stats));
-			}
+			if (copy_to_user((int *) arg, &LP_STAT(minor),
+					sizeof(struct lp_stats)))
+				return -EFAULT;
+			if (suser())
+				memset(&LP_STAT(minor), 0,
+						sizeof(struct lp_stats));
 			break;
  		case LPGETFLAGS:
- 			retval = verify_area(VERIFY_WRITE, (void *) arg,
- 			    sizeof(int));
- 		    	if (retval)
- 		    		return retval;
- 			else {
- 				int status = LP_F(minor);
-				copy_to_user((int *) arg, &status, sizeof(int));
-			}
+ 			status = LP_F(minor);
+			if (copy_to_user((int *) arg, &status, sizeof(int)))
+				return -EFAULT;
 			break;
 		default:
 			retval = -EINVAL;
diff -u --recursive --new-file v2.1.93/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c
--- v2.1.93/linux/drivers/char/msp3400.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/msp3400.c	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,923 @@
+/*
+ * programming the msp34* sound processor family
+ *
+ * (c) 1997,1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * what works and what doesn't:
+ *
+ *  AM-Mono
+ *      probably doesn't (untested)
+ *
+ *  FM-Mono
+ *      should work. The stereo modes are backward compatible to FM-mono,
+ *      therefore FM-Mono should be allways available.
+ *
+ *  FM-Stereo (B/G, used in germany)
+ *      should work, with autodetect
+ *
+ *  FM-Stereo (satellite)
+ *      should work, no autodetect (i.e. default is mono, but you can
+ *      switch to stereo -- untested)
+ *
+ *  NICAM (B/G, used in UK, Scandinavia and Spain)
+ *      should work, with autodetect. Support for NICAM was added by
+ *      Pekka Pietikainen <pp@netppl.fi>
+ *
+ *
+ * TODO:
+ *   - better SAT support
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+/* #include <asm/smp_lock.h> */
+
+/* kernel_thread */
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
+#include "i2c.h"
+#include <linux/videodev.h>
+
+#include "msp3400.h"
+
+int debug = 0; /* insmod parameter */
+
+struct msp3400c 
+{
+	struct i2c_bus     *bus;
+
+	int nicam;
+	int mode;
+	int norm;
+	int volume;
+	int stereo;
+
+	/* thread */
+	struct task_struct	*thread;
+	struct semaphore	*wait;
+	struct semaphore	*notify;
+	int active,restart,rmmod;
+};
+
+#define VIDEO_MODE_RADIO 16      /* norm magic for radio mode */
+
+/* ---------------------------------------------------------------------- */
+
+#define dprintk     if (debug) printk
+
+MODULE_PARM(debug,"i");
+
+/* ---------------------------------------------------------------------- */
+
+#define I2C_MSP3400C       0x80
+#define I2C_MSP3400C_DEM   0x10
+#define I2C_MSP3400C_DFP   0x12
+
+/* ----------------------------------------------------------------------- */
+/* functions for talking to the MSP3400C Sound processor                   */
+
+static int msp3400c_reset(struct i2c_bus *bus)
+{
+	int ret = 0;
+    
+	udelay(2000);
+	i2c_start(bus);
+	i2c_sendbyte(bus, I2C_MSP3400C,2000);
+	i2c_sendbyte(bus, 0x00,0);
+	i2c_sendbyte(bus, 0x80,0);
+	i2c_sendbyte(bus, 0x00,0);
+	i2c_stop(bus);
+	udelay(2000);
+	i2c_start(bus);
+	if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) ||
+		0 != i2c_sendbyte(bus, 0x00,0) ||
+		0 != i2c_sendbyte(bus, 0x00,0) ||
+		0 != i2c_sendbyte(bus, 0x00,0)) 
+	{
+		ret = -1;
+		printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n");
+	}
+	i2c_stop(bus);
+	udelay(2000);
+	return ret;
+}
+
+static int msp3400c_read(struct i2c_bus *bus, int dev, int addr)
+{
+	int ret=0;
+	short val = 0;
+	i2c_start(bus);
+	if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) ||
+		0 != i2c_sendbyte(bus, dev+1,       0)    ||
+		0 != i2c_sendbyte(bus, addr >> 8,   0)    ||
+		0 != i2c_sendbyte(bus, addr & 0xff, 0)) 
+	{
+		ret = -1;
+	}
+	else
+	{
+		i2c_start(bus);
+		if (0 != i2c_sendbyte(bus, I2C_MSP3400C+1,2000)) 
+		{
+			ret = -1;
+		}
+		else
+		{
+			val |= (int)i2c_readbyte(bus,0) << 8;
+			val |= (int)i2c_readbyte(bus,1);
+		}
+	}
+	i2c_stop(bus);
+	if (-1 == ret) 
+	{
+		printk(KERN_WARNING "msp3400: I/O error, trying reset (read %s 0x%x)\n",
+			(dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr);
+		msp3400c_reset(bus);
+	}
+	return val;
+}
+
+static int msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val)
+{
+	int ret = 0;
+    
+	i2c_start(bus);
+	if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) ||
+		0 != i2c_sendbyte(bus, dev,         0)    ||
+		0 != i2c_sendbyte(bus, addr >> 8,   0)    ||
+		0 != i2c_sendbyte(bus, addr & 0xff, 0)    ||
+		0 != i2c_sendbyte(bus, val >> 8,    0)    ||
+		0 != i2c_sendbyte(bus, val & 0xff,  0))
+	{
+		ret = -1;
+	}
+	i2c_stop(bus);
+	if (-1 == ret) 
+	{
+		printk(KERN_ERR "msp3400: I/O error, trying reset (write %s 0x%x)\n",
+			(dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr);
+		msp3400c_reset(bus);
+	}
+	return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* This macro is allowed for *constants* only, gcc must calculate it
+   at compile time.  Remember -- no floats in kernel mode */
+#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24)))
+
+#define MSP_MODE_AM_DETECT   0
+#define MSP_MODE_FM_RADIO    2
+#define MSP_MODE_FM_TERRA    3
+#define MSP_MODE_FM_SAT      4
+#define MSP_MODE_FM_NICAM1   5
+#define MSP_MODE_FM_NICAM2   6
+
+static struct MSP_INIT_DATA_DEM 
+{
+	int fir1[6];
+	int fir2[6];
+	int cdo1;
+	int cdo2;
+	int ad_cv;
+	int mode_reg;
+	int dfp_src;
+	int dfp_matrix;
+} msp_init_data[] = {
+		/* AM (for carrier detect / msp3400) */
+		{ { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 },
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),  0x00d0, 0x0500,   0x0020, 0x3000},
+
+		/* AM (for carrier detect / msp3410) */
+		{ { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 },
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),  0x00d0, 0x0100,   0x0020, 0x3000},
+
+		/* FM Radio */
+		{ { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 },
+		MSP_CARRIER(10.7), MSP_CARRIER(10.7),  0x00d0, 0x0480, 0x0020, 0x3002 },
+
+		/* Terrestial FM-mono */
+		{ {  3, 18, 27, 48, 66, 72 }, {  3, 18, 27, 48, 66, 72 },
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),  0x00d0, 0x0480,   0x0030, 0x3000},
+
+		/* Sat FM-mono */
+		{ {  1,  9, 14, 24, 33, 37 }, {  3, 18, 27, 48, 66, 72 },
+		MSP_CARRIER(6.5), MSP_CARRIER(6.5),  0x00c6, 0x0480,   0x0000, 0x3000},
+
+		/* NICAM B/G, D/K */
+		{ { -2, -8, -10, 10, 50, 86 }, {  3, 18, 27, 48, 66, 72 },
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),  0x00d0, 0x0040,   0x0120, 0x3000},
+
+		/* NICAM I */
+		{ {  2, 4, -6, -4, 40, 94 }, {  3, 18, 27, 48, 66, 72 },
+		MSP_CARRIER(5.5), MSP_CARRIER(5.5),  0x00d0, 0x0040,   0x0120, 0x3000},
+};
+
+struct CARRIER_DETECT 
+{
+	int   cdo;
+	char *name;
+};
+
+static struct CARRIER_DETECT carrier_detect_main[] = 
+{
+	/* main carrier */
+	{ MSP_CARRIER(4.5),        "4.5   NTSC"                   }, 
+	{ MSP_CARRIER(5.5),        "5.5   PAL B/G"                }, 
+	{ MSP_CARRIER(6.0),        "6.0   PAL I"                  },
+	{ MSP_CARRIER(6.5),        "6.5   PAL SAT / SECAM"        }
+};
+
+static struct CARRIER_DETECT carrier_detect_55[] = {
+	/* PAL B/G */
+	{ MSP_CARRIER(5.7421875),  "5.742 PAL B/G FM-stereo"     }, 
+	{ MSP_CARRIER(5.85),       "5.85  PAL B/G NICAM"         }
+};
+
+static struct CARRIER_DETECT carrier_detect_65[] = {
+	/* PAL SAT / SECAM */
+	{ MSP_CARRIER(7.02),       "7.02  PAL SAT FM-stereo s/b" },
+	{ MSP_CARRIER(7.20),       "7.20  PAL SAT FM-stereo s"   },
+	{ MSP_CARRIER(7.38),       "7.38  PAL SAT FM-stereo b"   },
+};
+
+#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
+
+/* ------------------------------------------------------------------------ */
+
+static void msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2)
+{
+	msp3400c_write(bus,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff);
+	msp3400c_write(bus,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12);
+	msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff);
+	msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12);
+}
+
+static void msp3400c_setvolume(struct i2c_bus *bus, int vol)
+{
+	int val = (vol * 0x73 / 65535) << 8;
+
+	dprintk("msp3400: setvolume: 0x%02x\n",val>>8);
+	msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
+	msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0006, val); /* headphones  */
+	/* scart - on/off only */
+	msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0);
+}
+
+static void msp3400c_setmode(struct msp3400c *msp, int type)
+{
+	int i;
+	
+	dprintk("msp3400: setmode: %d\n",type);
+	msp->mode   = type;
+	msp->stereo = VIDEO_SOUND_MONO;
+
+	msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x00bb,          /* ad_cv */
+		msp_init_data[type].ad_cv);
+    
+	for (i = 5; i >= 0; i--)                                   /* fir 1 */
+		msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0001,
+			msp_init_data[type].fir1[i]);
+    
+	msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */
+	msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0040);
+	msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0000);
+	for (i = 5; i >= 0; i--)
+		msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005,
+			msp_init_data[type].fir2[i]);
+    
+	msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0083,          /* MODE_REG */
+		msp_init_data[type].mode_reg);
+    
+	msp3400c_setcarrier(msp->bus, msp_init_data[type].cdo1,
+		msp_init_data[type].cdo2);
+    
+	msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,
+		msp_init_data[type].dfp_src);
+	msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,
+		msp_init_data[type].dfp_src);
+	msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,
+		msp_init_data[type].dfp_src);
+	msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e,
+		msp_init_data[type].dfp_matrix);
+
+	if (msp->nicam) 
+	{
+		/* msp3410 needs some more initialization */
+        	msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0010, 0x3000);
+	}
+}
+
+static void msp3400c_setstereo(struct msp3400c *msp, int mode)
+{
+	int nicam=0; /* channel source: FM/AM or nicam */
+
+	/* switch demodulator */
+	switch (msp->mode) 
+	{
+		case MSP_MODE_FM_TERRA:
+			dprintk("msp3400: B/G setstereo: %d\n",mode);
+			msp->stereo = mode;
+			msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.7421875),MSP_CARRIER(5.5));
+			switch (mode) 
+			{
+				case VIDEO_SOUND_STEREO:
+					msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3001);
+					break;
+				case VIDEO_SOUND_MONO:
+				case VIDEO_SOUND_LANG1:
+				case VIDEO_SOUND_LANG2:
+					msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3000);
+					break;
+			}
+			break;
+		case MSP_MODE_FM_SAT:
+			dprintk("msp3400: sat setstereo: %d\n",mode);
+			msp->stereo = mode;
+			switch (mode) 
+			{
+				case VIDEO_SOUND_MONO:
+					msp3400c_setcarrier(msp->bus, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
+					break;
+				case VIDEO_SOUND_STEREO:
+					msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
+					break;
+				case VIDEO_SOUND_LANG1:
+					msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+					break;
+				case VIDEO_SOUND_LANG2:
+					msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+					break;
+			}
+			break;
+		case MSP_MODE_FM_NICAM1:
+			dprintk("msp3400: NICAM1 setstereo: %d\n",mode);
+			msp->stereo = mode;
+			msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.85),MSP_CARRIER(5.5));
+			nicam=0x0100;
+			break;
+		default:
+			/* can't do stereo - abort here */
+			return;
+	}
+
+	/* switch audio */
+	switch (mode) 
+	{
+		case VIDEO_SOUND_STEREO:
+			msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0020|nicam);
+			msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0020|nicam);
+			msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0020|nicam);
+			msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0005, 0x4000);
+			break;
+		case VIDEO_SOUND_MONO:
+		case VIDEO_SOUND_LANG1:
+			msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0000|nicam);
+			msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0000|nicam);
+			msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0000|nicam);
+			break;
+		case VIDEO_SOUND_LANG2:
+			msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0010|nicam);
+			msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0010|nicam);
+			msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0010|nicam);
+			break;
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct REGISTER_DUMP {
+	int addr;
+	char *name;
+};
+
+struct REGISTER_DUMP d1[] = 
+{
+	{ 0x007e, "autodetect" },
+	{ 0x0023, "C_AD_BITS " },
+	{ 0x0038, "ADD_BITS  " },
+	{ 0x003e, "CIB_BITS  " },
+	{ 0x0057, "ERROR_RATE" },
+};
+
+/*
+ * A kernel thread for msp3400 control -- we don't want to block the
+ * in the ioctl while doing the sound carrier & stereo detect
+ */
+
+int msp3400c_thread(void *data)
+{
+	unsigned long flags;
+	struct msp3400c *msp = data;
+	struct semaphore sem = MUTEX_LOCKED;
+    
+	struct CARRIER_DETECT *cd;
+	int count, max1,max2,val1,val2, val,this, check_stereo;
+	int i;
+    
+	/* lock_kernel(); */
+    
+	exit_mm(current);
+	current->session = 1;
+	current->pgrp = 1;
+	sigfillset(&current->blocked);
+	current->fs->umask = 0;
+	strcpy(current->comm,"msp3400");
+
+	msp->wait   = &sem;
+	msp->thread = current;
+
+	/* unlock_kernel(); */
+
+	dprintk("msp3400: thread: start\n");
+	if(msp->notify != NULL)
+		up(msp->notify);
+		
+	for (;;) 
+	{
+		if (msp->rmmod)
+			goto done;
+		dprintk("msp3400: thread: sleep\n");
+		down_interruptible(&sem);
+		dprintk("msp3400: thread: wakeup\n");
+		if (msp->rmmod)
+			goto done;
+#if 0
+		if (VIDEO_MODE_RADIO == msp->norm) 
+		{
+			msp->active = 1;
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + HZ/10;
+			schedule();
+			if (signal_pending(current))
+				goto done;
+			LOCK_I2C_BUS(msp->bus);
+			val1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b);
+			val2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c);
+			UNLOCK_I2C_BUS(msp->bus);
+			printk("msp3400: DC %d/%d\n",val1,val2);
+			msp->active = 0;
+			continue;
+		}
+#endif
+	
+		if (VIDEO_MODE_RADIO == msp->norm)
+			continue;  /* nothing to do */
+	
+		msp->active = 1;
+restart:
+		LOCK_I2C_BUS(msp->bus);
+		msp3400c_setvolume(msp->bus, 0);
+		msp3400c_setmode(msp, MSP_MODE_AM_DETECT);
+		val1 = val2 = max1 = max2 = check_stereo = 0;
+
+		/* carrier detect pass #1 -- main carrier */
+		cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main);
+		for (this = 0; this < count; this++) 
+		{
+			msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo);
+			UNLOCK_I2C_BUS(msp->bus);
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + HZ/25;
+			schedule();
+			if (signal_pending(current))
+				goto done;
+			if (msp->restart) 
+			{
+				msp->restart = 0;
+				goto restart;
+			}
+
+			LOCK_I2C_BUS(msp->bus);
+			val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b);
+			if (val1 < val)
+				val1 = val, max1 = this;
+			dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name);
+		}
+
+		/* carrier detect pass #2 -- second (stereo) carrier */
+		switch (max1) 
+		{
+			case 1: /* 5.5 */
+				cd = carrier_detect_55; count = CARRIER_COUNT(carrier_detect_55);
+				break;
+			case 3: /* 6.5 */
+				cd = carrier_detect_65; count = CARRIER_COUNT(carrier_detect_65);
+				break;
+			case 0: /* 4.5 */
+			case 2: /* 6.0 */
+			default:
+				cd = NULL; count = 0;
+				break;
+		}
+		for (this = 0; this < count; this++) 
+		{
+			msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo);
+			UNLOCK_I2C_BUS(msp->bus);
+
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + HZ/25;
+			schedule();
+			if (signal_pending(current))
+				goto done;
+			if (msp->restart) 
+			{
+				msp->restart = 0;
+				goto restart;
+			}
+
+			LOCK_I2C_BUS(msp->bus);
+			val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b);
+			if (val2 < val)
+				val2 = val, max2 = this;
+			dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name);
+		}
+
+		/* programm the msp3400 according to the results */
+		switch (max1) 
+		{
+			case 0: /* 4.5 */
+			case 1: /* 5.5 */
+				msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
+				msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo,
+				carrier_detect_main[max1].cdo);
+				if (max2 == 0) 
+				{
+					/* B/G FM-stereo */
+					msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
+					check_stereo = 1;
+				}
+				if (max2 == 1 && msp->nicam) 
+				{
+					/* B/G NICAM */
+					msp3400c_setmode(msp, MSP_MODE_FM_NICAM1);
+					/* msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01); */
+					msp3400c_setcarrier(msp->bus, MSP_CARRIER(5.85),
+						MSP_CARRIER(5.5));
+					check_stereo = 1;
+				}
+				break;
+			case 2: /* 6.0 */
+			case 3: /* 6.5 */
+			default:
+				msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
+				msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo,
+					carrier_detect_main[max1].cdo);
+				msp3400c_setstereo(msp, VIDEO_SOUND_STEREO);
+				break;
+		}
+	
+		/* unmute */
+		msp3400c_setvolume(msp->bus, msp->volume);
+
+		if (check_stereo) 
+		{
+			/* stereo available -- check current mode */
+			UNLOCK_I2C_BUS(msp->bus);
+		   
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + HZ;
+			schedule();
+			if (signal_pending(current))
+				goto done;
+			if (msp->restart) 
+			{
+				msp->restart = 0;
+				goto restart;
+			}
+		    
+			LOCK_I2C_BUS(msp->bus);
+			switch (msp->mode) 
+			{
+				case MSP_MODE_FM_TERRA:
+					val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x18);
+					dprintk("msp3400: stereo detect register: %d\n",val);
+			
+					if (val > 4096) 
+					{
+						msp3400c_setstereo(msp, VIDEO_SOUND_STEREO);
+					}
+					else if (val < -4096) 
+					{
+						msp3400c_setstereo(msp, VIDEO_SOUND_LANG1);
+					}
+					else
+					{
+						msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
+					}
+					break;
+				case MSP_MODE_FM_NICAM1:
+  					val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23);
+ 					switch ((val & 0x1e) >> 1)  
+ 					{
+						case 0:
+						case 8:
+							msp3400c_setstereo(msp, VIDEO_SOUND_STEREO);
+							break;
+						default:
+							msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
+							break;
+ 					}			
+
+					/* dump registers (for debugging) */
+					if (debug)
+					{
+						for (i=0; i<sizeof(d1)/sizeof(struct REGISTER_DUMP); i++) 
+						{
+							val = msp3400c_read(msp->bus,I2C_MSP3400C_DEM, d1[i].addr);
+							printk(KERN_DEBUG "msp3400: %s = 0x%x\n",
+		       						d1[i].name,val);
+						}
+					}
+					break;
+			}
+		}
+		UNLOCK_I2C_BUS(msp->bus);
+		msp->active = 0;
+	}
+
+done:
+	dprintk("msp3400: thread: exit\n");
+	msp->wait   = NULL;
+	msp->active = 0;
+	msp->thread = NULL;
+
+	if(msp->notify != NULL)
+		up(msp->notify);
+	return 0;
+}
+
+int msp3410d_thread(void *data)
+{
+	unsigned long flags;
+	struct msp3400c *msp = data;
+	struct semaphore sem = MUTEX_LOCKED;
+	int i, val;
+
+	/* lock_kernel(); */
+    
+	exit_mm(current);
+	current->session = 1;
+	current->pgrp = 1;
+	sigfillset(&current->blocked);
+	current->fs->umask = 0;
+	strcpy(current->comm,"msp3410 (nicam)");
+
+	msp->wait   = &sem;
+	msp->thread = current;
+
+	/* unlock_kernel(); */
+
+	dprintk("msp3410: thread: start\n");
+	if(msp->notify != NULL)
+		up(msp->notify);
+		
+	for (;;) 
+	{
+		if (msp->rmmod)
+			goto done;
+		dprintk("msp3410: thread: sleep\n");
+		down_interruptible(&sem);
+		dprintk("msp3410: thread: wakeup\n");
+		if (msp->rmmod)
+			goto done;
+	
+		if (VIDEO_MODE_RADIO == msp->norm)
+			continue;  /* nothing to do */
+	
+		msp->active = 1;
+
+restart:
+		LOCK_I2C_BUS(msp->bus);
+		/* mute */
+		msp3400c_setvolume(msp->bus, 0);
+		/* quick & dirty hack:
+		   get the audio proccessor into some useful state */
+		msp3400c_setmode(msp, MSP_MODE_FM_NICAM1);
+		/* kick autodetect */
+		msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x20, 0x01);
+		msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01);
+		UNLOCK_I2C_BUS(msp->bus);
+
+		/* wait 1 sec */
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + HZ;
+		schedule();
+		if (signal_pending(current))
+			goto done;
+		if (msp->restart) 
+		{
+			msp->restart = 0;
+			goto restart;
+		}
+	
+		LOCK_I2C_BUS(msp->bus);
+		/* debug register dump */
+		for (i = 0; i < sizeof(d1)/sizeof(struct REGISTER_DUMP); i++) 
+		{
+			val = msp3400c_read(msp->bus,I2C_MSP3400C_DEM,d1[i].addr);
+			printk(KERN_DEBUG "msp3400: %s = 0x%x\n",d1[i].name,val);
+		}	
+		/* unmute */
+		msp3400c_setvolume(msp->bus, msp->volume);
+		UNLOCK_I2C_BUS(msp->bus);
+
+		msp->active = 0;
+	}
+
+done:
+	dprintk("msp3410: thread: exit\n");
+	msp->wait   = NULL;
+	msp->active = 0;
+	msp->thread = NULL;
+
+	if(msp->notify != NULL)
+		up(msp->notify);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int msp3400c_attach(struct i2c_device *device)
+{
+	unsigned long flags;
+	struct semaphore sem = MUTEX_LOCKED;
+	struct msp3400c *msp;
+	int rev1,rev2;
+	
+	/*
+	 *	MSP3400's are for now only assumed to live on busses
+	 *	connected to a BT848. Adjust as and when you get new
+	 *	funky cards using these components.
+	 */
+	
+	if(device->bus->id != I2C_BUSID_BT848)
+		return -EINVAL;
+
+	device->data = msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL);
+	if (NULL == msp)
+		return -ENOMEM;
+	memset(msp,0,sizeof(struct msp3400c));
+	msp->bus = device->bus;
+	msp->volume = 65535;
+
+	LOCK_I2C_BUS(msp->bus);
+	if (-1 == msp3400c_reset(msp->bus)) 
+	{
+		UNLOCK_I2C_BUS(msp->bus);
+		kfree(msp);
+		return -1;
+	}
+    
+	msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
+	msp3400c_setvolume(msp->bus, msp->volume);
+
+	rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e);
+	rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f);
+
+#if 0
+	/* this will turn on a 1kHz beep - might be useful for debugging... */
+	msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0014, 0x1040);
+#endif
+	UNLOCK_I2C_BUS(msp->bus);
+
+	sprintf(device->name,"MSP34%02d%c-%c%d",
+		(rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f);
+	msp->nicam = (((rev2>>8)&0xff) == 10) ? 1 : 0;
+	printk(KERN_INFO "msp3400: init: chip=%s%s\n",
+		device->name, msp->nicam ? ", can decode nicam" : "");
+
+	MOD_INC_USE_COUNT;
+	/* startup control thread */
+	msp->notify = &sem;
+	kernel_thread(msp3400c_thread, (void *)msp, 0);
+	down(&sem);
+	msp->notify = NULL;
+	if (!msp->active)
+		up(msp->wait);
+	return 0;
+}
+
+static int msp3400c_detach(struct i2c_device *device)
+{
+	unsigned long flags;
+	struct semaphore sem = MUTEX_LOCKED;
+	struct msp3400c *msp  = (struct msp3400c*)device->data;
+    
+	/* shutdown control thread */
+	msp->notify = &sem;
+	msp->rmmod = 1;
+	if (!msp->active)
+		up(msp->wait);
+	down(&sem);
+	msp->notify = NULL;
+   
+	LOCK_I2C_BUS(msp->bus);
+	msp3400c_reset(msp->bus);
+	UNLOCK_I2C_BUS(msp->bus);
+
+	kfree(msp);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int msp3400c_command(struct i2c_device *device,
+		 unsigned int cmd, void *arg)
+{
+	unsigned long flags;
+	struct msp3400c *msp = (struct msp3400c*)device->data;
+	int *iarg = (int*)arg;
+
+	switch (cmd) 
+	{
+		case MSP_SET_RADIO:
+			msp->norm = VIDEO_MODE_RADIO;
+			LOCK_I2C_BUS(msp->bus);
+			msp3400c_setmode(msp,MSP_MODE_FM_RADIO);
+			msp3400c_setcarrier(msp->bus, MSP_CARRIER(10.7),MSP_CARRIER(10.7));
+			UNLOCK_I2C_BUS(msp->bus);
+			break;
+		case MSP_SET_TVNORM:
+			msp->norm = *iarg;
+			break;
+		case MSP_NEWCHANNEL:
+			if (!msp->active)
+				up(msp->wait);
+			else
+				msp->restart = 1;
+			break;
+
+		case MSP_GET_VOLUME:
+			*iarg = msp->volume;
+			break;
+		case MSP_SET_VOLUME:
+			msp->volume = *iarg;
+			LOCK_I2C_BUS(msp->bus);
+			msp3400c_setvolume(msp->bus,msp->volume);
+			UNLOCK_I2C_BUS(msp->bus);
+			break;
+
+		case MSP_GET_STEREO:
+			*iarg = msp->stereo;
+			break;
+		case MSP_SET_STEREO:
+			if (*iarg) 
+			{
+				LOCK_I2C_BUS(msp->bus);
+				msp3400c_setstereo(msp,*iarg);
+				UNLOCK_I2C_BUS(msp->bus);
+			}
+			break;
+
+		case MSP_GET_DC:
+			LOCK_I2C_BUS(msp->bus);
+			*iarg = (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) +
+				(int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c);
+			UNLOCK_I2C_BUS(msp->bus);
+			break;
+	
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_msp = 
+{
+	"msp3400",                    /* name       */
+	I2C_DRIVERID_MSP3400,         /* ID         */
+	I2C_MSP3400C, I2C_MSP3400C,   /* addr range */
+
+	msp3400c_attach,
+	msp3400c_detach,
+	msp3400c_command
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int msp3400c_init(void)
+#endif
+{
+	i2c_register_driver(&i2c_driver_msp);
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	i2c_unregister_driver(&i2c_driver_msp);
+}
+#endif
+
diff -u --recursive --new-file v2.1.93/linux/drivers/char/msp3400.h linux/drivers/char/msp3400.h
--- v2.1.93/linux/drivers/char/msp3400.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/msp3400.h	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,18 @@
+#ifndef MSP3400_H
+#define MSP3400_H
+
+/* ---------------------------------------------------------------------- */
+
+#define MSP_SET_TVNORM     _IOW('m',1,int)  /* TV mode + PAL/SECAM/NTSC  */
+#define MSP_SET_RADIO      _IO('m',2)       /* Radio mode                */
+#define MSP_NEWCHANNEL     _IO('m',3)       /* indicate new channel      */
+
+#define MSP_GET_VOLUME     _IOR('m',4,int)
+#define MSP_SET_VOLUME     _IOW('m',5,int)
+
+#define MSP_GET_STEREO     _IOR('m',6,int)
+#define MSP_SET_STEREO     _IOW('m',7,int)
+
+#define MSP_GET_DC         _IOW('m',8,int)
+
+#endif /* MSP3400_H */
diff -u --recursive --new-file v2.1.93/linux/drivers/char/pms.c linux/drivers/char/pms.c
--- v2.1.93/linux/drivers/char/pms.c	Mon Feb 23 18:12:04 1998
+++ linux/drivers/char/pms.c	Wed Apr  8 17:24:48 1998
@@ -1020,11 +1020,10 @@
  */
  
 #ifdef MODULE
-
-MODULE_PARM(io_port,"i");
-MODULE_PARM(mem_base,"i");
-
 int init_module(void)
+#else
+void init_pms_cards(void)
+#endif
 {
 	printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
 	
@@ -1040,8 +1039,13 @@
 	pms_device.width=320;
 	pms_swsense(75);
 	pms_resolution(320,240);
-	return video_register_device((struct video_device *)&pms_device);
+	return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER);
 }
+
+#ifdef MODULE
+
+MODULE_PARM(io_port,"i");
+MODULE_PARM(mem_base,"i");
 
 void cleanup_module(void)
 {
diff -u --recursive --new-file v2.1.93/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v2.1.93/linux/drivers/char/pty.c	Mon Apr  6 17:40:59 1998
+++ linux/drivers/char/pty.c	Tue Apr  7 07:52:04 1998
@@ -7,7 +7,6 @@
  *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
  */
 
-#include <linux/config.h>
 #include <linux/module.h>	/* For EXPORT_SYMBOL */
 
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.93/linux/drivers/char/tuner.c linux/drivers/char/tuner.c
--- v2.1.93/linux/drivers/char/tuner.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/tuner.c	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,269 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+#include "i2c.h"
+#include <linux/videodev.h>
+
+#include "tuner.h"
+
+int debug = 0; /* insmod parameter */
+int type  = 0; /* tuner type */
+
+#define dprintk     if (debug) printk
+
+MODULE_PARM(debug,"i");
+MODULE_PARM(type,"i");
+
+struct tuner 
+{
+	struct i2c_bus   *bus;     /* where is our chip */
+	int               addr;
+
+	int type;            /* chip type */
+	int freq;            /* keep track of the current settings */
+	int radio;
+};
+
+/* ---------------------------------------------------------------------- */
+
+struct tunertype 
+{
+	char *name;
+	unsigned char Vendor;
+	unsigned char Type;
+  
+	unsigned short thresh1; /* frequency Range for UHF,VHF-L, VHF_H */   
+	unsigned short thresh2;  
+	unsigned char VHF_L;
+	unsigned char VHF_H;
+	unsigned char UHF;
+	unsigned char config; 
+	unsigned char I2C;
+	unsigned short IFPCoff;
+};
+
+/*
+ *	The floats in the tuner struct are computed at compile time
+ *	by gcc and cast back to integers. Thus we don't violate the
+ *	"no float in kernel" rule.
+ */
+static struct tunertype tuners[] = {
+        {"Temic PAL", TEMIC, PAL,
+                16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,623},
+	{"Philips PAL_I", Philips, PAL_I,
+	        16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc0,623},
+	{"Philips NTSC", Philips, NTSC,
+	        16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0,732},
+	{"Philips SECAM", Philips, SECAM,
+	        16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,0xc0,623},
+	{"NoTuner", NoTuner, NOTUNER,
+	         0        ,0        ,0x00,0x00,0x00,0x00,0x00,000},
+	{"Philips PAL", Philips, PAL,
+	        16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0,623},
+	{"Temic NTSC", TEMIC, NTSC,
+	        16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,732},
+	{"TEMIC PAL_I", TEMIC, PAL_I,
+	        16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_getstatus (struct tuner *t)
+{
+	return i2c_read(t->bus,t->addr+1);
+}
+
+#define TUNER_POR       0x80
+#define TUNER_FL        0x40
+#define TUNER_AFC       0x07
+
+static int tuner_islocked (struct tuner *t)
+{
+        return (tuner_getstatus (t) & TUNER_FL);
+}
+
+static int tuner_afcstatus (struct tuner *t)
+{
+        return (tuner_getstatus (t) & TUNER_AFC) - 2;
+}
+
+
+static void set_tv_freq(struct tuner *t, int freq)
+{
+        unsigned long flags;
+	u8 config;
+	u16 div;
+	struct tunertype *tun=&tuners[t->type];
+
+	if (freq < tun->thresh1) 
+		config = tun->VHF_L;
+	else if (freq < tun->thresh2) 
+		config = tun->VHF_H;
+	else
+		config = tun->UHF;
+
+	div=freq + (int)(16*38.9);
+  	div&=0x7fff;
+
+	LOCK_I2C_BUS(t->bus);
+	if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) {
+	    printk("tuner: i2c i/o error #1\n");
+	} else {
+	    if (i2c_write(t->bus, t->addr, tun->config, config, 1))
+		printk("tuner: i2c i/o error #2\n");
+	}
+	UNLOCK_I2C_BUS(t->bus);
+}
+
+static void set_radio_freq(struct tuner *t, int freq)
+{
+        unsigned long flags;
+	u8 config;
+	u16 div;
+	struct tunertype *tun=&tuners[type];
+
+	config = 0xa5;
+	div=freq + (int)(16*10.7);
+  	div&=0x7fff;
+
+	LOCK_I2C_BUS(t->bus);
+	if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) {
+	    printk("tuner: i2c i/o error #1\n");
+	} else {
+	    if (i2c_write(t->bus, t->addr, tun->config, config, 1))
+		printk("tuner: i2c i/o error #2\n");
+	}
+	if (debug) {
+		UNLOCK_I2C_BUS(t->bus);
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + HZ/10;
+		schedule();
+		LOCK_I2C_BUS(t->bus);
+		
+		if (tuner_islocked (t))
+			printk ("tuner: PLL locked\n");
+		else
+			printk ("tuner: PLL not locked\n");
+		
+		printk ("tuner: AFC: %d\n", tuner_afcstatus (t));
+	}
+	UNLOCK_I2C_BUS(t->bus);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_attach(struct i2c_device *device)
+{
+	struct tuner *t;
+
+	/*
+	 *	For now we only try and attach these tuners to the BT848
+	 *	bus. This same module will however work different species
+	 *	of card using these chips. Just change the constraints
+	 *	(i2c doesn't have a totally clash free 'address' space)
+	 */
+	 
+	if(device->bus->id!=I2C_BUSID_BT848)
+		return -EINVAL;
+		
+	device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
+	if (NULL == t)
+		return -ENOMEM;
+	memset(t,0,sizeof(struct tuner));
+	strcpy(device->name,"tuner");
+	t->bus  = device->bus;
+	t->addr = device->addr;
+	t->type = type;
+	dprintk("tuner: type is %d (%s)\n",t->type,tuners[t->type].name);
+	
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int tuner_detach(struct i2c_device *device)
+{
+	struct tuner *t = (struct tuner*)device->data;
+	kfree(t);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int tuner_command(struct i2c_device *device,
+	      unsigned int cmd, void *arg)
+{
+	struct tuner *t = (struct tuner*)device->data;
+	int *iarg = (int*)arg;
+
+	switch (cmd) 
+	{
+		case TUNER_SET_TYPE:
+			t->type = *iarg;
+			dprintk("tuner: type set to %d (%s)\n",
+			t->type,tuners[t->type].name);
+			break;
+
+		case TUNER_SET_TVFREQ:
+			dprintk("tuner: tv freq set to %d.%02d\n",
+				(*iarg)/16,(*iarg)%16*100/16);
+			set_tv_freq(t,*iarg);
+			t->radio = 0;
+			t->freq = *iarg;
+			break;
+	    
+		case TUNER_SET_RADIOFREQ:
+			dprintk("tuner: radio freq set to %d.%02d\n",
+				(*iarg)/16,(*iarg)%16*100/16);
+			set_radio_freq(t,*iarg);
+			t->radio = 1;
+			t->freq = *iarg;
+			break;
+	    
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_tuner = 
+{
+	"tuner",                      /* name       */
+	I2C_DRIVERID_TUNER,           /* ID         */
+	0xc0, 0xce,                   /* addr range */
+
+	tuner_attach,
+	tuner_detach,
+	tuner_command
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int msp3400c_init(void)
+#endif
+{
+	i2c_register_driver(&i2c_driver_tuner);
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	i2c_unregister_driver(&i2c_driver_tuner);
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -u --recursive --new-file v2.1.93/linux/drivers/char/tuner.h linux/drivers/char/tuner.h
--- v2.1.93/linux/drivers/char/tuner.h	Tue Jan 13 20:14:36 1998
+++ linux/drivers/char/tuner.h	Wed Apr  8 17:24:48 1998
@@ -42,19 +42,8 @@
 #define TEMIC   2
 #define Sony    3
 
-struct tunertype {
-  char *name;
-  unchar Vendor;
-  unchar Type;
-  
-  ushort thresh1; /* frequency Range for UHF,VHF-L, VHF_H */   
-  ushort thresh2;  
-  unchar VHF_L;
-  unchar VHF_H;
-  unchar UHF;
-  unchar config; 
-  unchar I2C;
-  ushort IFPCoff;
-};
-#endif
+#define TUNER_SET_TYPE               _IOW('t',1,int)    /* set tuner type */
+#define TUNER_SET_TVFREQ             _IOW('t',2,int)    /* set tv freq */
+#define TUNER_SET_RADIOFREQ          _IOW('t',3,int)    /* set radio freq */
 
+#endif
diff -u --recursive --new-file v2.1.93/linux/drivers/char/videodev.c linux/drivers/char/videodev.c
--- v2.1.93/linux/drivers/char/videodev.c	Fri Jan 23 18:10:31 1998
+++ linux/drivers/char/videodev.c	Wed Apr  8 17:24:48 1998
@@ -39,6 +39,9 @@
 #ifdef CONFIG_VIDEO_BT848
 extern int init_bttv_cards(struct video_init *);
 #endif
+#ifdef CONFIG_VIDEO_SAA5249
+extern int init_saa_5249(struct video_init *);
+#endif	
 #ifdef CONFIG_VIDEO_CQCAM
 extern int init_colour_qcams(struct video_init *);
 #endif
@@ -50,6 +53,9 @@
 #ifdef CONFIG_VIDEO_BT848
 	{"bttv", init_bttv_cards},
 #endif	
+#ifdef CONFIG_VIDEO_SAA5249
+	{"saa5249", init_saa_5249},
+#endif	
 #ifdef CONFIG_VIDEO_CQCAM
 	{"c-qcam", init_colour_qcams},
 #endif	
@@ -57,7 +63,7 @@
 	{"bw-qcam", init_bw_qcams},
 #endif	
 #ifdef CONFIG_VIDEO_PMS
-	{"PMS", init_pms_cards}, 	/* not defined anywhere */
+	{"PMS", init_pms_cards}, 
 #endif	
 	{"end", NULL}
 };
@@ -74,6 +80,8 @@
 	return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
 }
 
+
+
 /*
  *	Write for now does nothing. No reason it shouldnt do overlay setting
  *	for some boards I guess..
@@ -162,18 +170,51 @@
 /*
  *	We need to do MMAP support
  */
+ 
+ 
+int video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+	if(vfl->mmap)
+		return vfl->mmap(vfl, (char *)vma->vm_start, 
+				(unsigned long)(vma->vm_end-vma->vm_start));
+	return -EINVAL;
+}
 
 /*
  *	Video For Linux device drivers request registration here.
  */
  
-int video_register_device(struct video_device *vfd)
+int video_register_device(struct video_device *vfd, int type)
 {
 	int i=0;
-	int base=0;
+	int base;
 	int err;
+	int end;
+	
+	switch(type)
+	{
+		case VFL_TYPE_GRABBER:
+			base=0;
+			end=64;
+			break;
+		case VFL_TYPE_VTX:
+			base=192;
+			end=224;
+			break;
+		case VFL_TYPE_VBI:
+			base=224;
+			end=240;
+			break;
+		case VFL_TYPE_RADIO:
+			base=64;
+			end=128;
+			break;
+		default:
+			return -1;
+	}
 	
-	for(i=base;i<base+VIDEO_NUM_DEVICES;i++)
+	for(i=base;i<end;i++)
 	{
 		if(video_device[i]==NULL)
 		{
@@ -216,7 +257,7 @@
 	NULL,	/* readdir */
 	NULL,	/* poll */
 	video_ioctl,
-	NULL,	/* mmap */
+	video_mmap,
 	video_open,
 	video_release
 };
diff -u --recursive --new-file v2.1.93/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c
--- v2.1.93/linux/drivers/isdn/hisax/niccy.c	Wed Apr  1 20:11:51 1998
+++ linux/drivers/isdn/hisax/niccy.c	Tue Apr  7 07:52:04 1998
@@ -15,7 +15,7 @@
  *
  */
 
-
+#include <linux/config.h>
 #define __NO_VERSION__
 #include "hisax.h"
 #include "isac.h"
diff -u --recursive --new-file v2.1.93/linux/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c
--- v2.1.93/linux/drivers/isdn/isdnloop/isdnloop.c	Wed Apr  1 20:11:51 1998
+++ linux/drivers/isdn/isdnloop/isdnloop.c	Tue Apr  7 07:52:04 1998
@@ -38,6 +38,7 @@
  *
  */
 
+#include <linux/config.h>
 #include "isdnloop.h"
 
 static char
diff -u --recursive --new-file v2.1.93/linux/drivers/isdn/isdnloop/isdnloop.h linux/drivers/isdn/isdnloop/isdnloop.h
--- v2.1.93/linux/drivers/isdn/isdnloop/isdnloop.h	Wed Apr  1 20:11:51 1998
+++ linux/drivers/isdn/isdnloop/isdnloop.h	Tue Apr  7 07:52:04 1998
@@ -53,7 +53,6 @@
 #ifdef __KERNEL__
 /* Kernel includes */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.93/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c
--- v2.1.93/linux/drivers/misc/parport_procfs.c	Tue Feb 17 13:12:46 1998
+++ linux/drivers/misc/parport_procfs.c	Wed Apr  8 17:27:12 1998
@@ -4,6 +4,7 @@
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *          Philip Blundell <philb@gnu.org>
  *          Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *          Riccardo Facchetti <fizban@tin.it>
  *
  * based on work by Grant Guenther <grant@torque.net>
  *              and Philip Blundell
@@ -11,6 +12,7 @@
 
 #include <linux/stddef.h>
 #include <linux/tasks.h>
+#include <linux/ctype.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -32,55 +34,78 @@
 static int irq_write_proc(struct file *file, const char *buffer,
 					  unsigned long count, void *data)
 {
-	int newirq, oldirq;
+	int retval = -EINVAL;
+	int newirq = PARPORT_IRQ_NONE;
 	struct parport *pp = (struct parport *)data;
-	
-	if (count > 5 )  /* more than 4 digits + \n for a irq 0x?? 0?? ??  */
-		return -EOVERFLOW;
+	struct pardevice *cad = pp->cad;
+	int oldirq = pp->irq;
 
-	if (buffer[0] < 32 || !strncmp(buffer, "none", 4)) {
-		newirq = PARPORT_IRQ_NONE;
-	} else {
-		if (buffer[0] == '0') {
-			if (buffer[1] == 'x')
-				newirq = simple_strtoul(&buffer[2], 0, 16);
-			else
-				newirq = simple_strtoul(&buffer[1], 0, 8);
-		} else {
-			newirq = simple_strtoul(buffer, 0, 10);
-		}
-	}
+/*
+ * We can have these valid cases:
+ * 	"none" (count == 4 || count == 5)
+ * 	decimal number (count == 2 || count == 3)
+ * 	octal number (count == 3 || count == 4)
+ * 	hex number (count == 4 || count == 5)
+ * all other cases are -EINVAL
+ *
+ * Note: newirq is alredy set up to NONE.
+ *
+ * -RF
+ */
+	if (count > 5  || count < 1)
+		goto out;
 
-	if (newirq >= NR_IRQS)
-		return -EOVERFLOW;
+	if (isdigit(buffer[0]))
+		newirq = simple_strtoul(buffer, NULL, 0);
+	else if (strncmp(buffer, "none", 4) != 0) {
+		if (buffer[0] < 32)
+			/* Things like '\n' are harmless */
+			retval = count;
 
-	if (pp->irq != PARPORT_IRQ_NONE && !(pp->flags & PARPORT_FLAG_COMA)) {
-		if (pp->cad != NULL && pp->cad->irq_func != NULL)
-			free_irq(pp->irq, pp->cad->private);
-		else
-			free_irq(pp->irq, NULL);
+		goto out;
 	}
 
-	oldirq = pp->irq;
-	pp->irq = newirq;
+	retval = count;
+
+	if (oldirq == newirq)
+		goto out;
 
-	if (pp->irq != PARPORT_IRQ_NONE && !(pp->flags & PARPORT_FLAG_COMA)) { 
-		struct pardevice *cad = pp->cad;
+	if (pp->flags & PARPORT_FLAG_COMA)
+		goto out_ok;
 
-		if (cad == NULL)
-			request_irq(pp->irq, parport_null_intr_func,
-				    SA_INTERRUPT, pp->name, NULL);
+	if (newirq != PARPORT_IRQ_NONE) { 
+		void (*handler)(int, void *, struct pt_regs *);
+
+		if (cad && cad->irq_func)
+			handler = cad->irq_func;
+		else
+			handler = parport_null_intr_func;
+
+		retval = request_irq(newirq, handler,
+				     SA_INTERRUPT,
+				     cad ? cad->name : pp->name,
+				     cad ? cad->private : NULL);
+		if (retval)
+			goto out;
+		else retval = count;
+	}
+
+	if (oldirq != PARPORT_IRQ_NONE) {
+		if (cad && cad->irq_func)
+			free_irq(oldirq, cad->private);
 		else
-			request_irq(pp->irq, cad->irq_func ? cad->irq_func :
-				    parport_null_intr_func, SA_INTERRUPT,
-				    cad->name, cad->private);
+			free_irq(oldirq, NULL);
 	}
 
+out_ok:
+	pp->irq = newirq;
+
 	if (oldirq != PARPORT_IRQ_NONE && newirq == PARPORT_IRQ_NONE &&
-	    pp->cad != NULL && pp->cad->irq_func != NULL)
-		pp->cad->irq_func(pp->irq, pp->cad->private, NULL);
+	    cad && cad->irq_func)
+		cad->irq_func(pp->irq, cad->private, NULL);
 
-	return count;
+out:
+	return retval;
 }
 
 static int irq_read_proc(char *page, char **start, off_t off,
@@ -167,6 +192,20 @@
 	*d = NULL;
 }
 
+static void destroy_proc_tree(struct parport *pp) {
+	if (pp->pdir.entry) {
+		if (pp->pdir.irq) 
+			destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq);
+		if (pp->pdir.devices) 
+			destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices);
+		if (pp->pdir.hardware)
+			destroy_proc_entry(pp->pdir.entry, &pp->pdir.hardware);
+		if (pp->pdir.probe)
+			destroy_proc_entry(pp->pdir.entry, &pp->pdir.probe);
+		destroy_proc_entry(base, &pp->pdir.entry);
+	}
+}
+
 static struct proc_dir_entry *new_proc_entry(const char *name, mode_t mode,
 					     struct proc_dir_entry *parent,
 					     unsigned short ino)
@@ -220,8 +259,6 @@
 
 int parport_proc_register(struct parport *pp)
 {
-	static const char *proc_msg = KERN_ERR "%s: Trouble with /proc.\n";
-
 	memset(&pp->pdir, 0, sizeof(struct parport_dir));
 
 	if (base == NULL) {
@@ -233,63 +270,43 @@
 		sizeof(pp->pdir.name));
 
 	pp->pdir.entry = new_proc_entry(pp->pdir.name, S_IFDIR, base, 0);
-	if (pp->pdir.entry == NULL) {
-		printk(proc_msg, pp->name);
-		return 1;
-	}
+	if (pp->pdir.entry == NULL)
+		goto out_fail;
 
 	pp->pdir.irq = new_proc_entry("irq", S_IFREG | S_IRUGO | S_IWUSR, 
 				      pp->pdir.entry, 0);
-	if (pp->pdir.irq == NULL) {
-		printk(proc_msg, pp->name);
-		destroy_proc_entry(base, &pp->pdir.entry);
-		return 1;
-	}
+	if (pp->pdir.irq == NULL)
+		goto out_fail;
+
 	pp->pdir.irq->read_proc = irq_read_proc;
 	pp->pdir.irq->write_proc = irq_write_proc;
 	pp->pdir.irq->data = pp;
 	
 	pp->pdir.devices = new_proc_entry("devices", 0, pp->pdir.entry, 0);
-	if (pp->pdir.devices == NULL) {
-		printk(proc_msg, pp->name);
-		destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq);
-		destroy_proc_entry(base, &pp->pdir.entry);
-		return 1;
-	}
+	if (pp->pdir.devices == NULL)
+		goto out_fail;
+
 	pp->pdir.devices->read_proc = devices_read_proc;
 	pp->pdir.devices->data = pp;
 	
 	pp->pdir.hardware = new_proc_entry("hardware", 0, pp->pdir.entry, 0);
-	if (pp->pdir.hardware == NULL) {
-		printk(proc_msg, pp->name);
-		destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices);
-		destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq);
-		destroy_proc_entry(base, &pp->pdir.entry);
-		return 1;
-	}
+	if (pp->pdir.hardware == NULL)
+		goto out_fail;
+
 	pp->pdir.hardware->read_proc = hardware_read_proc;
 	pp->pdir.hardware->data = pp;
 
 	return 0;
+
+out_fail:
+
+	printk(KERN_ERR "%s: failure registering /proc/ entry.\n", pp->name);
+	destroy_proc_tree(pp);
+	return 1;
 }
 
 int parport_proc_unregister(struct parport *pp)
 {
-	if (pp->pdir.entry) {
-		if (pp->pdir.irq) 
-			destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq);
-		
-		if (pp->pdir.devices) 
-			destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices);
-		
-		if (pp->pdir.hardware)
-			destroy_proc_entry(pp->pdir.entry, &pp->pdir.hardware);
-
-		if (pp->pdir.probe)
-			destroy_proc_entry(pp->pdir.entry, &pp->pdir.probe);
-		
-		destroy_proc_entry(base, &pp->pdir.entry);
-	}
-	
+	destroy_proc_tree(pp);
 	return 0;
 }
diff -u --recursive --new-file v2.1.93/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.93/linux/drivers/net/Config.in	Tue Mar 17 22:18:14 1998
+++ linux/drivers/net/Config.in	Tue Apr  7 08:05:05 1998
@@ -102,8 +102,9 @@
     tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
     tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN
       tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
+      tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
+      tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN
       bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
     fi
   fi
diff -u --recursive --new-file v2.1.93/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.1.93/linux/drivers/net/Makefile	Thu Mar 26 15:57:03 1998
+++ linux/drivers/net/Makefile	Tue Apr  7 08:05:05 1998
@@ -581,6 +581,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_EPIC100),y)
+L_OBJS += epic100.o
+else
+  ifeq ($(CONFIG_EPIC100),m)
+  M_OBJS += epic100.o
+  endif
+endif
+
 # If anything built-in uses slhc, then build it into the kernel also.
 # If not, but a module uses it, build as a module.
 ifdef CONFIG_SLHC_BUILTIN
diff -u --recursive --new-file v2.1.93/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.1.93/linux/drivers/net/Space.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/net/Space.c	Tue Apr  7 08:05:05 1998
@@ -94,6 +94,7 @@
 extern int mace_probe(struct device *);
 extern int cs89x0_probe(struct device *dev);
 extern int ethertap_probe(struct device *dev);
+extern int epic100_probe(struct device *dev);
 
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct device *);
@@ -286,6 +287,9 @@
 #endif
 #ifdef CONFIG_ARM_AM79C961A
 	&& am79c961_probe(dev)
+#endif
+#ifdef CONFIG_EPIC100
+	&& epic100_probe(dev)
 #endif
 	&& 1 ) {
 	return 1;	/* -ENODEV or -EAGAIN would be more accurate. */
diff -u --recursive --new-file v2.1.93/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.1.93/linux/drivers/net/de4x5.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/net/de4x5.c	Tue Apr  7 07:52:04 1998
@@ -380,6 +380,7 @@
 
 static const char *version = "de4x5.c:V0.536 1998/3/5 davies@maniac.ultranet.com\n";
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.1.93/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.1.93/linux/drivers/net/epic100.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/epic100.c	Tue Apr  7 08:05:05 1998
@@ -0,0 +1,1215 @@
+/* epic100.c: A SMC 83c170 EPIC/100 fast ethernet driver for Linux. */
+/*
+   NOTICE: THIS IS THE ALPHA TEST VERSION!
+	Written 1997 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+    All other rights reserved.
+
+	This driver is for the SMC EtherPower II 9432 PCI ethernet adapter based on
+	the SMC83c170.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	Support and updates available at
+	http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html
+*/
+
+static const char *version =
+"epic100.c:v0.10 10/14/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
+
+/* A few user-configurable values. */
+
+/* Keep the ring sizes a power of two for efficiency.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority.
+   There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	32
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature. */
+static const int rx_copybreak = 200;
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 10;
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  ((2000*HZ)/1000)
+
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+
+/* Bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 128		/* Rounded down to 4 byte units. */
+#define RX_FIFO_THRESH 1		/* 0-3, 0==32, 64,96, or 3==128 bytes  */
+
+#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+   This is only in the support-all-kernels source code. */
+#include <linux/version.h>		/* Evil, but neccessary */
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300
+#define RUN_AT(x) (x)			/* What to put in timer->expires.  */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+#define virt_to_bus(addr)  ((unsigned long)addr)
+#define bus_to_virt(addr) ((void*)addr)
+
+#else  /* 1.3.0 and later */
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338
+#ifdef MODULE
+#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__)
+char kernel_version[] = UTS_RELEASE;
+#endif
+#else
+#undef MOD_INC_USE_COUNT
+#define MOD_INC_USE_COUNT
+#undef MOD_DEC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+#endif /* 1.3.38 */
+
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
+#include <linux/delay.h>
+#endif
+
+#ifdef SA_SHIRQ
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
+#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
+#else
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#else
+#ifdef MODULE
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("SMC 82c170 EPIC series Ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+#endif
+#endif
+
+/* The I/O extent. */
+#define EPIC_TOTAL_SIZE 0x100
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry epic100_drv =
+{"Epic100", epic100_pci_probe, EPIC_TOTAL_SIZE, NULL};
+#endif
+
+static int epic_debug = 1;
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the SMC "EPCI/100", the SMC
+single-chip ethernet controllers for PCI.  This chip is used on
+the SMC EtherPower II boards.
+
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS will assign the
+PCI INTA signal to a (preferably otherwise unused) system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+IVb. References
+
+http://www.smc.com/components/catalog/smc83c170.html
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.national.com/pf/DP/DP83840.html
+
+IVc. Errata
+
+*/
+
+#ifndef PCI_VENDOR_ID_SMC
+#define PCI_VENDOR_ID_SMC			0x10B8
+#endif
+#ifndef PCI_DEVICE_ID_SMC_EPIC100
+#define PCI_DEVICE_ID_SMC_EPIC100	0x0005
+#endif
+
+/* The rest of these values should never change. */
+/* Offsets to registers, using the (ugh) SMC names. */
+enum epic_registers {
+  COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14,
+  TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28,	/* Rx error counters. */
+  MIICtrl=0x30, MIIData=0x34, MIICfg=0x38,
+  LAN0=64,						/* MAC address. */
+  MC0=80,						/* Multicast filter table. */
+  RxCtrl=96, TxCtrl=112, TxSTAT=0x74,
+  PRxCDAR=0x84, RxSTAT=0xA4, EarlyRx=0xB0, PTxCDAR=0xC4, TxThresh=0xDC,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatus {
+  TxIdle=0x40000, RxIdle=0x20000,
+  CntFull=0x0200, TxUnderrun=0x0100,
+  TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010,
+  RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001,
+};
+
+/* The EPIC100 Rx and Tx buffer descriptors. */
+
+struct epic_tx_desc {
+	s16 status;
+	u16 txlength;
+	u32 bufaddr;
+	u16 buflength;
+	u16 control;
+    u32 next;
+};
+
+struct epic_rx_desc {
+	s16 status;
+	u16 rxlength;
+	u32 bufaddr;
+	u32 buflength;
+    u32 next;
+};
+
+struct epic_private {
+	char devname[8];			/* Used only for kernel debugging. */
+	const char *product_name;
+	struct device *next_module;
+	struct epic_rx_desc rx_ring[RX_RING_SIZE];
+	struct epic_tx_desc tx_ring[TX_RING_SIZE];
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	/* The addresses of receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	int chip_id;
+	int revision;
+	struct enet_statistics stats;
+	struct timer_list timer;	/* Media selection timer. */
+	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	unsigned char mc_filter[8];
+	signed char phys[4];				/* MII device addresses. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int media2:4;				/* Secondary monitored media port. */
+	unsigned int medialock:1;			/* Don't sense media type. */
+	unsigned int mediasense:1;			/* Media sensing in progress. */
+	int pad0, pad1;						/* Used for 8-byte alignment */
+};
+
+static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#ifdef MODULE
+/* Used to pass the full-duplex flag, etc. */
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#endif
+
+static struct device *epic100_probe1(struct device *dev, int ioaddr, int irq,
+									 int chip_id, int options, int card_idx);
+static int epic_open(struct device *dev);
+static int read_eeprom(int ioaddr, int location);
+static int mii_read(int ioaddr, int phy_id, int location);
+static void epic_timer(unsigned long data);
+static void epic_tx_timeout(struct device *dev);
+static void epic_init_ring(struct device *dev);
+static int epic_start_xmit(struct sk_buff *skb, struct device *dev);
+static int epic_rx(struct device *dev);
+static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int epic_close(struct device *dev);
+static struct enet_statistics *epic_get_stats(struct device *dev);
+#ifdef NEW_MULTICAST
+static void set_rx_mode(struct device *dev);
+#else
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+
+
+#ifdef MODULE
+/* A list of all installed EPIC devices, for removing the driver module. */
+static struct device *root_epic_dev = NULL;
+#endif
+
+int epic100_probe(struct device *dev)
+{
+	int cards_found = 0;
+	static int pci_index = 0;	/* Static, for multiple probe calls. */
+
+	/* Ideally we would detect all network cards in slot order.  That would
+	   be best done a central PCI probe dispatch, which wouldn't work
+	   well with the current structure.  So instead we detect just the
+	   Epic cards in slot order. */
+
+	if (pcibios_present()) {
+		unsigned char pci_bus, pci_device_fn;
+
+		for (;pci_index < 0xff; pci_index++) {
+			unsigned char pci_irq_line, pci_latency;
+			unsigned short pci_command, vendor, device;
+			unsigned int pci_ioaddr, chip_idx = 0;
+
+			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+#ifdef REVERSE_PROBE_ORDER
+									0xff - pci_index,
+#else
+									pci_index,
+#endif
+									&pci_bus, &pci_device_fn)
+				!= PCIBIOS_SUCCESSFUL)
+				break;
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_VENDOR_ID, &vendor);
+			if (vendor != PCI_VENDOR_ID_SMC)
+				continue;
+
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_DEVICE_ID, &device);
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_INTERRUPT_LINE, &pci_irq_line);
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+			/* Remove I/O space marker in bit 0. */
+			pci_ioaddr &= ~3;
+
+			if (device != PCI_DEVICE_ID_SMC_EPIC100) {
+				printk("Unknown SMC PCI ethernet chip type %4.4x detected:"
+					   " not configured.\n", device);
+				continue;
+			}
+			if (epic_debug > 2)
+				printk("Found SMC PCI EPIC/100 at I/O %#x, IRQ %d.\n",
+					   pci_ioaddr, pci_irq_line);
+
+			if (check_region(pci_ioaddr, EPIC_TOTAL_SIZE))
+				continue;
+
+#ifdef MODULE
+			dev = epic100_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
+						 options[cards_found], cards_found);
+#else
+			dev = epic100_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
+						 dev ? dev->mem_start : 0, -1);
+#endif
+
+			if (dev) {
+			  /* Get and check the bus-master and latency values. */
+			  pcibios_read_config_word(pci_bus, pci_device_fn,
+									   PCI_COMMAND, &pci_command);
+			  if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+				printk("  PCI Master Bit has not been set! Setting...\n");
+				pci_command |= PCI_COMMAND_MASTER;
+				pcibios_write_config_word(pci_bus, pci_device_fn,
+										  PCI_COMMAND, pci_command);
+			  }
+			  pcibios_read_config_byte(pci_bus, pci_device_fn,
+									   PCI_LATENCY_TIMER, &pci_latency);
+			  if (pci_latency < 10) {
+				printk("  PCI latency timer (CFLT) is unreasonably low at %d."
+					   "  Setting to 255 clocks.\n", pci_latency);
+				pcibios_write_config_byte(pci_bus, pci_device_fn,
+										  PCI_LATENCY_TIMER, 255);
+			  } else if (epic_debug > 1)
+				printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
+			  dev = 0;
+			  cards_found++;
+			}
+		}
+	}
+
+#if defined (MODULE)
+	return cards_found;
+#else
+	return cards_found ? 0 : -ENODEV;
+#endif
+}
+
+static struct device *epic100_probe1(struct device *dev, int ioaddr, int irq,
+								   int chip_id, int options, int card_idx)
+{
+	static int did_version = 0;			/* Already printed version info. */
+	struct epic_private *tp;
+	int i;
+
+	if (epic_debug > 0  &&  did_version++ == 0)
+		printk(version);
+
+	dev = init_etherdev(dev, 0);
+
+	printk("%s: SMC EPIC/100 at %#3x, IRQ %d, ", dev->name, ioaddr, irq);
+
+	/* Bring the chip out of low-power mode. */
+	outl(0x0200, ioaddr + GENCTL);
+	/* Magic?!  If we don't set this bit the MII interface won't work. */
+	outl(0x0008, ioaddr + TEST1);
+
+	/* This could also be read from the EEPROM. */
+	for (i = 0; i < 3; i++)
+		((u16 *)dev->dev_addr)[i] = inw(ioaddr + LAN0 + i*4);
+
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x.\n", dev->dev_addr[i]);
+
+	if (epic_debug > 1) {
+	  printk("%s: EEPROM contents\n", dev->name);
+	  for (i = 0; i < 64; i++)
+		printk(" %4.4x%s", read_eeprom(ioaddr, i), i % 16 == 15 ? "\n" : "");
+	}
+
+	/* We do a request_region() to register /proc/ioports info. */
+	request_region(ioaddr, EPIC_TOTAL_SIZE, "SMC EPIC/100");
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	/* The data structures must be quadword aligned. */
+	tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
+	memset(tp, 0, sizeof(*tp));
+	dev->priv = tp;
+
+#ifdef MODULE
+	tp->next_module = root_epic_dev;
+	root_epic_dev = dev;
+#endif
+
+	tp->chip_id = chip_id;
+
+	/* Find the connected MII xcvrs.
+	   Doing this in open() would allow detecting external xcvrs later, but
+	   takes too much time. */
+	{
+		int phy, phy_idx;
+		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+			 phy++) {
+			int mii_status = mii_read(ioaddr, phy, 0);
+			if (mii_status != 0xffff  && mii_status != 0x0000) {
+				tp->phys[phy_idx++] = phy;
+				printk("%s: MII transceiver found at address %d.\n",
+					   dev->name, phy);
+			}
+		}
+		if (phy_idx == 0) {
+			printk("%s: ***WARNING***: No MII transceiver found!\n",
+				   dev->name);
+			/* Use the known PHY address of the EPII. */
+			tp->phys[0] = 3;
+		}
+	}
+
+	/* Leave the chip in low-power mode. */
+	outl(0x0008, ioaddr + GENCTL);
+
+	/* The lower four bits are the media type. */
+	if (options > 0) {
+		tp->full_duplex = (options & 16) ? 1 : 0;
+		tp->default_port = options & 15;
+		if (tp->default_port)
+		  tp->medialock = 1;
+	}
+	if (card_idx >= 0) {
+		if (full_duplex[card_idx] >= 0)
+			tp->full_duplex = full_duplex[card_idx];
+	}
+
+	/* The Epic-specific entries in the device structure. */
+	dev->open = &epic_open;
+	dev->hard_start_xmit = &epic_start_xmit;
+	dev->stop = &epic_close;
+	dev->get_stats = &epic_get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+
+	return dev;
+}
+
+/* Serial EEPROM section. */
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
+#define EE_CS			0x02	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x08	/* EEPROM chip data in. */
+#define EE_WRITE_0		0x01
+#define EE_WRITE_1		0x09
+#define EE_DATA_READ	0x10	/* EEPROM chip data out. */
+#define EE_ENB			(0x0001 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   The 1.2 code is a "nasty" timing loop, but PC compatible machines are
+   *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro.  */
+#ifdef _LINUX_DELAY_H
+#define eeprom_delay(nanosec)	udelay((nanosec + 999)/1000)
+#else
+#define eeprom_delay(nanosec)	do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+#endif
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5 << 6)
+#define EE_READ_CMD		(6 << 6)
+#define EE_ERASE_CMD	(7 << 6)
+
+static int read_eeprom(int ioaddr, int location)
+{
+	int i;
+	int retval = 0;
+	int ee_addr = ioaddr + EECTL;
+	int read_cmd = location | EE_READ_CMD;
+	
+	outl(EE_ENB & ~EE_CS, ee_addr);
+	outl(EE_ENB, ee_addr);
+	
+	/* Shift the read command bits out. */
+	for (i = 10; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		outl(EE_ENB | dataval, ee_addr);
+		eeprom_delay(100);
+		outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay(150);
+		outl(EE_ENB | dataval, ee_addr);	/* Finish EEPROM a clock tick. */
+		eeprom_delay(250);
+	}
+	outl(EE_ENB, ee_addr);
+	
+	for (i = 16; i > 0; i--) {
+		outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay(100);
+		retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+		outl(EE_ENB, ee_addr);
+		eeprom_delay(100);
+	}
+
+	/* Terminate the EEPROM access. */
+	outl(EE_ENB & ~EE_CS, ee_addr);
+	return retval;
+}
+
+#define MII_READOP		1
+#define MII_WRITEOP		2
+static int mii_read(int ioaddr, int phy_id, int location)
+{
+	int i;
+
+	outl((phy_id << 9) | (location << 4) | MII_READOP, ioaddr + MIICtrl);
+	/* Typical operation takes < 50 ticks. */
+	for (i = 4000; i > 0; i--)
+		if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0)
+			break;
+	return inw(ioaddr + MIIData);
+}
+
+
+static int
+epic_open(struct device *dev)
+{
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int i;
+	int mii_reg5;
+	int full_duplex = 0;
+
+	/* Soft reset the chip. */
+	outl(0x0001, ioaddr + GENCTL);
+
+#ifdef SA_SHIRQ
+	if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ,
+					"SMC EPIC/100", dev)) {
+		return -EAGAIN;
+	}
+#else
+	if (irq2dev_map[dev->irq] != NULL
+		|| (irq2dev_map[dev->irq] = dev) == NULL
+		|| dev->irq == 0
+		|| request_irq(dev->irq, &epic_interrupt, 0, "SMC EPIC/100")) {
+		return -EAGAIN;
+	}
+#endif
+
+	MOD_INC_USE_COUNT;
+
+	epic_init_ring(dev);
+
+	/* This next line by Ken Yamaguchi.. ?? */
+	outl(0x8, ioaddr + 0x1c);
+
+	/* Pull the chip out of low-power mode, enable interrupts, and set for PCI read multiple. */
+	outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
+
+	for (i = 0; i < 3; i++)
+		outl(((u16*)dev->dev_addr)[i], ioaddr + LAN0 + i*4);
+
+	outl(TX_FIFO_THRESH, ioaddr + TxThresh);
+	full_duplex = tp->full_duplex;
+
+	mii_reg5 = mii_read(ioaddr, tp->phys[0], 5);
+	if (mii_reg5 != 0xffff && (mii_reg5 & 0x0100)) {
+		full_duplex = 1;
+		if (epic_debug > 1)
+			printk("%s: Setting %s-duplex based on MII xcvr %d"
+				   " register read of %4.4x.\n", dev->name,
+				   full_duplex ? "full" : "half", tp->phys[0],
+				   mii_read(ioaddr, tp->phys[0], 5));
+	}
+
+	outl(full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
+	outl(virt_to_bus(tp->rx_ring), ioaddr + PRxCDAR);
+	outl(virt_to_bus(tp->tx_ring), ioaddr + PTxCDAR);
+
+	/* Start the chip's Rx process. */
+	set_rx_mode(dev);
+	outl(0x000A, ioaddr + COMMAND);
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* Enable interrupts by setting the interrupt mask. */
+	outl(CntFull | TxUnderrun | TxDone
+		 | RxError | RxOverflow | RxFull | RxHeader | RxDone,
+		 ioaddr + INTMASK);
+
+	if (epic_debug > 1)
+		printk("%s: epic_open() ioaddr %4.4x IRQ %d status %4.4x %s-duplex.\n",
+			   dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL),
+			   full_duplex ? "full" : "half");
+
+	/* Set the timer to switch to check for link beat and perhaps switch
+	   to an alternate media type. */
+	init_timer(&tp->timer);
+	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
+	tp->timer.data = (unsigned long)dev;
+	tp->timer.function = &epic_timer;				/* timer handler */
+	add_timer(&tp->timer);
+
+	return 0;
+}
+
+static void epic_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int next_tick = 0;
+
+	if (epic_debug > 3) {
+		printk("%s: Media selection tick, Tx status %8.8x.\n",
+			   dev->name, inl(ioaddr + TxSTAT));
+		printk("%s: Other registers are IntMask %4.4x IntStatus %4.4x RxStatus"
+			   " %4.4x.\n",
+			   dev->name, inl(ioaddr + INTMASK), inl(ioaddr + INTSTAT),
+			   inl(ioaddr + RxSTAT));
+	}
+
+	if (next_tick) {
+		tp->timer.expires = RUN_AT(next_tick);
+		add_timer(&tp->timer);
+	}
+}
+
+static void epic_tx_timeout(struct device *dev)
+{
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (epic_debug > 0) {
+		printk("%s: Transmit timeout using MII device, Tx status %4.4x.\n",
+			   dev->name, inw(ioaddr + TxSTAT));
+		if (epic_debug > 1) {
+			printk("%s: Tx indices: dirty_tx %d, cur_tx %d.\n",
+			 dev->name, tp->dirty_tx, tp->cur_tx);
+		}
+	}
+	/* Perhaps stop and restart the chip's Tx processes . */
+	/* Trigger a transmit demand. */
+	outl(0x0004, dev->base_addr + COMMAND);
+
+	dev->trans_start = jiffies;
+	tp->stats.tx_errors++;
+	return;
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+epic_init_ring(struct device *dev)
+{
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int i;
+
+	tp->tx_full = 0;
+	tp->cur_rx = tp->cur_tx = 0;
+	tp->dirty_rx = tp->dirty_tx = 0;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		tp->rx_ring[i].status = 0x8000;		/* Owned by Epic chip */
+		tp->rx_ring[i].buflength = PKT_BUF_SZ;
+		{
+			/* Note the receive buffer must be longword aligned.
+			   dev_alloc_skb() provides 16 byte alignment.  But do *not*
+			   use skb_reserve() to align the IP header! */
+			struct sk_buff *skb;
+			skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
+			tp->rx_skbuff[i] = skb;
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+			skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
+			tp->rx_ring[i].bufaddr = virt_to_bus(skb->tail);
+#else
+			tp->rx_ring[i].bufaddr = virt_to_bus(skb->data);
+#endif
+		}
+		tp->rx_ring[i].next = virt_to_bus(&tp->rx_ring[i+1]);
+	}
+	/* Mark the last entry as wrapping the ring. */
+	tp->rx_ring[i-1].next = virt_to_bus(&tp->rx_ring[0]);
+
+	/* The Tx buffer descriptor is filled in as needed, but we
+	   do need to clear the ownership bit. */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		tp->tx_skbuff[i] = 0;
+		tp->tx_ring[i].status = 0x0000;
+		tp->tx_ring[i].next = virt_to_bus(&tp->tx_ring[i+1]);
+	}
+	tp->tx_ring[i-1].next = virt_to_bus(&tp->tx_ring[0]);
+}
+
+static int
+epic_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int entry;
+	u32 flag;
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		if (jiffies - dev->trans_start < TX_TIMEOUT)
+			return 1;
+		epic_tx_timeout(dev);
+		return 1;
+	}
+
+	/* Caution: the write order is important here, set the base address
+	   with the "ownership" bits last. */
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = tp->cur_tx % TX_RING_SIZE;
+
+	tp->tx_skbuff[entry] = skb;
+	tp->tx_ring[entry].txlength = (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN);
+	tp->tx_ring[entry].bufaddr = virt_to_bus(skb->data);
+	tp->tx_ring[entry].buflength = skb->len;
+
+	if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
+	  flag = 0x10; /* No interrupt */
+	  dev->tbusy = 0;
+	} else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
+	  flag = 0x14; /* Tx-done intr. */
+	  dev->tbusy = 0;
+	} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
+	  flag = 0x10; /* No Tx-done intr. */
+	  dev->tbusy = 0;
+	} else {
+	  /* Leave room for two additional entries. */
+	  flag = 0x14; /* Tx-done intr. */
+	  tp->tx_full = 1;
+	}
+
+	tp->tx_ring[entry].control = flag;
+	tp->tx_ring[entry].status = 0x8000;	/* Pass ownership to the chip. */
+	tp->cur_tx++;
+	/* Trigger an immediate transmit demand. */
+	outl(0x0004, dev->base_addr + COMMAND);
+
+	dev->trans_start = jiffies;
+	if (epic_debug > 4)
+		printk("%s: Queued Tx packet size %d to slot %d, "
+			   "flag %2.2x Tx status %8.8x.\n",
+			   dev->name, (int)skb->len, entry, flag,
+			   inl(dev->base_addr + TxSTAT));
+
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void epic_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
+{
+#ifdef SA_SHIRQ
+	struct device *dev = (struct device *)dev_instance;
+#else
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+#endif
+	struct epic_private *lp;
+	int status, ioaddr, boguscnt = max_interrupt_work;
+
+	if (dev == NULL) {
+		printk ("epic_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	ioaddr = dev->base_addr;
+	lp = (struct epic_private *)dev->priv;
+	if (dev->interrupt)
+		printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+	dev->interrupt = 1;
+
+	do {
+		status = inl(ioaddr + INTSTAT);
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		outl(status & 0x00007fff, ioaddr + INTSTAT);
+
+		if (epic_debug > 4)
+			printk("%s: interrupt  interrupt=%#8.8x new intstat=%#8.8x.\n",
+				   dev->name, status, inl(ioaddr + INTSTAT));
+
+		if ((status & (RxDone | TxEmpty | TxDone)) == 0)
+			break;
+
+		if (status & RxDone)			/* Rx interrupt */
+			epic_rx(dev);
+
+		if (status & (TxEmpty | TxDone)) {
+			int dirty_tx;
+
+			for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) {
+				int entry = dirty_tx % TX_RING_SIZE;
+				int txstatus = lp->tx_ring[entry].status;
+
+				if (txstatus < 0)
+					break;			/* It still hasn't been Txed */
+
+				if ( ! (txstatus & 0x0001)) {
+					/* There was an major error, log it. */
+#ifndef final_version
+					if (epic_debug > 1)
+						printk("%s: Transmit error, Tx status %8.8x.\n",
+							   dev->name, txstatus);
+#endif
+					lp->stats.tx_errors++;
+					if (txstatus & 0x1050) lp->stats.tx_aborted_errors++;
+					if (txstatus & 0x0008) lp->stats.tx_carrier_errors++;
+					if (txstatus & 0x0040) lp->stats.tx_window_errors++;
+					if (txstatus & 0x0010) lp->stats.tx_fifo_errors++;
+#ifdef ETHER_STATS
+					if (txstatus & 0x1000) lp->stats.collisions16++;
+#endif
+				} else {
+#ifdef ETHER_STATS
+					if ((txstatus & 0x0002) != 0) lp->stats.tx_deferred++;
+#endif
+					lp->stats.collisions += (txstatus >> 8) & 15;
+					lp->stats.tx_packets++;
+				}
+
+				/* Free the original skb. */
+				dev_kfree_skb(lp->tx_skbuff[entry]);
+				lp->tx_skbuff[entry] = 0;
+			}
+
+#ifndef final_version
+			if (lp->cur_tx - dirty_tx > TX_RING_SIZE) {
+				printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+					   dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (lp->tx_full && dev->tbusy
+				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+				/* The ring is no longer full, clear tbusy. */
+				lp->tx_full = 0;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+
+			lp->dirty_tx = dirty_tx;
+		}
+
+		/* Check uncommon events all at once. */
+		if (status & (CntFull | TxUnderrun | RxOverflow)) {
+			/* Always update the error counts to avoid overhead later. */
+			lp->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+			lp->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+			lp->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+
+			if (status & TxUnderrun) { /* Tx FIFO underflow. */
+			  lp->stats.tx_fifo_errors++;
+			  /* Restart the transmit process. */
+			  outl(0x0080, ioaddr + COMMAND);
+			}
+			if (status & RxOverflow) {		/* Missed a Rx frame. */
+				lp->stats.rx_errors++;
+			}
+			/* Clear all error sources. */
+			outl(status & 0x7f18, ioaddr + INTSTAT);
+		}
+		if (--boguscnt < 0) {
+			printk("%s: Too much work at interrupt, IntrStatus=0x%8.8x.\n",
+				   dev->name, status);
+			/* Clear all interrupt sources. */
+			outl(0x0001ffff, ioaddr + INTSTAT);
+			break;
+		}
+	} while (1);
+
+	if (epic_debug > 3)
+		printk("%s: exiting interrupt, intr_status=%#4.4x.\n",
+			   dev->name, inl(ioaddr + INTSTAT));
+
+	/* Code that should never be run!  Perhaps remove after testing.. */
+	{
+		static int stopit = 10;
+		if (dev->start == 0  &&  --stopit < 0) {
+			printk("%s: Emergency stop, looping startup interrupt.\n",
+				   dev->name);
+			FREE_IRQ(irq, dev);
+		}
+	}
+
+	dev->interrupt = 0;
+	return;
+}
+
+static int
+epic_rx(struct device *dev)
+{
+	struct epic_private *lp = (struct epic_private *)dev->priv;
+	int entry = lp->cur_rx % RX_RING_SIZE;
+
+	if (epic_debug > 4)
+		printk(" In epic_rx(), entry %d %8.8x.\n", entry,
+			   lp->rx_ring[entry].status);
+	/* If we own the next entry, it's a new packet. Send it up. */
+	while (lp->rx_ring[entry].status >= 0) {
+		int status = lp->rx_ring[entry].status;
+
+		if (epic_debug > 4)
+			printk("  epic_rx() status was %8.8x.\n", status);
+		if (status & 0x2000) {
+			printk("%s: Oversized Ethernet frame spanned multiple buffers,"
+				   " status %4.4x!\n", dev->name, status);
+			  lp->stats.rx_length_errors++;
+		} else if (status & 0x0006) {
+			/* Rx Frame errors are counted in hardware. */
+			lp->stats.rx_errors++;
+		} else {
+			/* Malloc up new buffer, compatible with net-2e. */
+			/* Omit the four octet CRC from the length. */
+			short pkt_len = lp->rx_ring[entry].rxlength - 4;
+			struct sk_buff *skb;
+			int rx_in_place = 0;
+
+			/* Check if the packet is long enough to just accept without
+			   copying to a properly sized skbuff. */
+			if (pkt_len > rx_copybreak) {
+				struct sk_buff *newskb;
+				char *temp;
+
+				/* Pass up the skb already on the Rx ring. */
+				skb = lp->rx_skbuff[entry];
+				temp = skb_put(skb, pkt_len);
+				if (bus_to_virt(lp->rx_ring[entry].bufaddr) != temp)
+					printk("%s: Warning -- the skbuff addresses do not match"
+						   " in epic_rx: %p vs. %p / %p.\n", dev->name,
+						   bus_to_virt(lp->rx_ring[entry].bufaddr),
+						   skb->head, temp);
+				/* Get a fresh skbuff to replace the filled one. */
+				newskb = DEV_ALLOC_SKB(PKT_BUF_SZ);
+				if (newskb) {
+					rx_in_place = 1;
+					lp->rx_skbuff[entry] = newskb;
+					newskb->dev = dev;
+#if LINUX_VERSION_CODE > 0x10300
+					/* Align IP on 16 byte boundaries */
+					skb_reserve(newskb, 2);
+					lp->rx_ring[entry].bufaddr = virt_to_bus(newskb->tail);
+#else
+					lp->rx_ring[entry].bufaddr = virt_to_bus(newskb->data);
+#endif
+				} else			/* No memory, drop the packet. */
+				  skb = 0;
+			} else
+				skb = DEV_ALLOC_SKB(pkt_len + 2);
+			if (skb == NULL) {
+				int i;
+				printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+				/* Check that at least two ring entries are free.
+				   If not, free one and mark stats->rx_dropped++. */
+				for (i = 0; i < RX_RING_SIZE; i++)
+					if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0)
+						break;
+
+				if (i > RX_RING_SIZE -2) {
+					lp->stats.rx_dropped++;
+					lp->rx_ring[entry].status = 0x8000;
+					lp->cur_rx++;
+				}
+				break;
+			}
+			skb->dev = dev;
+			if (! rx_in_place) {
+				skb_reserve(skb, 2);	/* 16 byte align the data fields */
+				memcpy(skb_put(skb, pkt_len),
+					   bus_to_virt(lp->rx_ring[entry].bufaddr), pkt_len);
+			}
+#if LINUX_VERSION_CODE > 0x10300
+			skb->protocol = eth_type_trans(skb, dev);
+#else
+			skb->len = pkt_len;
+#endif
+			netif_rx(skb);
+			lp->stats.rx_packets++;
+		}
+
+		lp->rx_ring[entry].status = 0x8000;
+		entry = (++lp->cur_rx) % RX_RING_SIZE;
+	}
+
+	return 0;
+}
+
+static int
+epic_close(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int i;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	if (epic_debug > 1)
+		printk("%s: Shutting down ethercard, status was %2.2x.\n",
+			   dev->name, inl(ioaddr + INTSTAT));
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outl(0x00000000, ioaddr + INTMASK);
+	/* Stop the chip's Tx and Rx DMA processes. */
+	outw(0x0061, ioaddr + COMMAND);
+
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+	tp->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+	tp->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+
+	del_timer(&tp->timer);
+
+#ifdef SA_SHIRQ
+	free_irq(dev->irq, dev);
+#else
+	free_irq(dev->irq);
+	irq2dev_map[dev->irq] = 0;
+#endif
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = tp->rx_skbuff[i];
+		tp->rx_skbuff[i] = 0;
+		tp->rx_ring[i].status = 0;		/* Not owned by Epic chip. */
+		tp->rx_ring[i].buflength = 0;
+		tp->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
+		if (skb) {
+#if LINUX_VERSION_CODE < 0x20100
+			skb->free = 1;
+#endif
+			dev_kfree_skb(skb);
+		}
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (tp->tx_skbuff[i])
+			dev_kfree_skb(tp->tx_skbuff[i]);
+		tp->tx_skbuff[i] = 0;
+	}
+
+
+	/* Green! Leave the chip in low-power mode. */
+	outl(0x0008, ioaddr + GENCTL);
+	
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static struct enet_statistics *
+epic_get_stats(struct device *dev)
+{
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (dev->start) {
+		/* Update the error counts. */
+		tp->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+		tp->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+		tp->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+	}
+
+	return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   Note that we only use exclusion around actually queueing the
+   new frame, not around filling tp->setup_frame.  This is non-deterministic
+   when re-entered but still correct. */
+
+/* The little-endian AUTODIN II ethernet CRC calculation.
+   N.B. Do not use for bulk data, use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+	unsigned int crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+
+
+#ifdef NEW_MULTICAST
+static void set_rx_mode(struct device *dev)
+#else
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
+#endif
+{
+	int ioaddr = dev->base_addr;
+	struct epic_private *tp = (struct epic_private *)dev->priv;
+	unsigned char mc_filter[8];		 /* Multicast hash filter */
+	int i;
+
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		outl(0x002C, ioaddr + RxCtrl);
+		/* Unconditionally log net taps. */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+	} else if ((dev->mc_count > 0)  ||  (dev->flags & IFF_ALLMULTI)) {
+		/* There is apparently a chip bug, so the multicast filter
+		   is never enabled. */
+		/* Too many to filter perfectly -- accept all multicasts. */
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+		outl(0x000C, ioaddr + RxCtrl);
+	} else if (dev->mc_count == 0) {
+		outl(0x0004, ioaddr + RxCtrl);
+		return;
+	} else {					/* Never executed, for now. */
+		struct dev_mc_list *mclist;
+
+		memset(mc_filter, 0, sizeof(mc_filter));
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			 i++, mclist = mclist->next)
+			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
+					mc_filter);
+	}
+	/* ToDo: perhaps we need to stop the Tx and Rx process here? */
+	if (memcmp(mc_filter, tp->mc_filter, sizeof(mc_filter))) {
+		for (i = 0; i < 4; i++)
+			outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4);
+		memcpy(tp->mc_filter, mc_filter, sizeof(mc_filter));
+	}
+	return;
+}
+
+#ifdef MODULE
+
+/* An additional parameter that may be passed in... */
+static int debug = -1;
+
+int
+init_module(void)
+{
+	int cards_found;
+
+	if (debug >= 0)
+		epic_debug = debug;
+
+	root_epic_dev = NULL;
+	cards_found = epic100_probe(0);
+
+	return cards_found ? 0 : -ENODEV;
+}
+
+void
+cleanup_module(void)
+{
+	struct device *next_dev;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_epic_dev) {
+		next_dev = ((struct epic_private *)root_epic_dev->priv)->next_module;
+		unregister_netdev(root_epic_dev);
+		release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE);
+		kfree(root_epic_dev);
+		root_epic_dev = next_dev;
+	}
+}
+
+#endif  /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.1.93/linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c
--- v2.1.93/linux/drivers/net/hamradio/6pack.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/hamradio/6pack.c	Wed Apr  8 17:31:27 1998
@@ -0,0 +1,1129 @@
+/*
+ * 6pack.c	This module implements the 6pack protocol for kernel-based
+ *		devices like TTY. It interfaces between a raw TTY and the
+ *		kernel's AX.25 protocol layers.
+ *
+ * Version:	@(#)6pack.c	0.3.0	04/07/98
+ *
+ * Authors:	Andreas Könsgen <ajk@iehk.rwth-aachen.de>
+ *
+ * Quite a lot of stuff "stolen" by Jörg Reuter from slip.c, written by
+ *
+ *		Laurence Culhane, <loz@holmes.demon.co.uk>
+ *		Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ */
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/timer.h>
+#include <net/ax25.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/if_slip.h>
+#include <linux/init.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+/* 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h> 
+*/
+
+#include "6pack.h"
+
+typedef unsigned char byte;
+
+
+typedef struct sixpack_ctrl {
+	char		if_name[8];	/* "sp0\0" .. "sp99999\0"	*/
+	struct sixpack	ctrl;		/* 6pack things			*/
+	struct device	dev;		/* the device			*/
+} sixpack_ctrl_t;
+static sixpack_ctrl_t	**sixpack_ctrls = NULL;
+int sixpack_maxdev = SIXP_NRUNIT;	/* Can be overridden with insmod! */
+
+static struct tty_ldisc	sp_ldisc;
+
+static void sp_start_tx_timer(struct sixpack *);
+static void sp_xmit_on_air(unsigned long);
+static void resync_tnc(unsigned long);
+void sixpack_decode(struct sixpack *, unsigned char[], int);
+int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char);
+
+void decode_prio_command(byte, struct sixpack *);
+void decode_std_command(byte, struct sixpack *);
+void decode_data(byte, struct sixpack *);
+
+static int tnc_init(struct sixpack *);
+
+/* Find a free 6pack channel, and link in this `tty' line. */
+static inline struct sixpack *
+sp_alloc(void)
+{
+	sixpack_ctrl_t *spp = NULL;
+	int i;
+
+	if (sixpack_ctrls == NULL) return NULL;	/* Master array missing ! */
+
+	for (i = 0; i < sixpack_maxdev; i++) 
+	{
+		spp = sixpack_ctrls[i];
+
+		if (spp == NULL)
+			break;
+
+		if (!test_and_set_bit(SIXPF_INUSE, &spp->ctrl.flags))
+			break;
+	}
+
+	/* Too many devices... */
+	if (i >= sixpack_maxdev) 
+		return NULL;
+
+	/* If no channels are available, allocate one */
+	if (!spp &&
+	    (sixpack_ctrls[i] = (sixpack_ctrl_t *)kmalloc(sizeof(sixpack_ctrl_t),
+						    GFP_KERNEL)) != NULL) 
+	{
+		spp = sixpack_ctrls[i];
+		memset(spp, 0, sizeof(sixpack_ctrl_t));
+
+		/* Initialize channel control data */
+		set_bit(SIXPF_INUSE, &spp->ctrl.flags);
+		spp->ctrl.tty         = NULL;
+		sprintf(spp->if_name, "sp%d", i);
+		spp->dev.name         = spp->if_name;
+		spp->dev.base_addr    = i;
+		spp->dev.priv         = (void*)&(spp->ctrl);
+		spp->dev.next         = NULL;
+		spp->dev.init         = sixpack_init;
+	}
+
+	if (spp != NULL) 
+	{
+		/* register device so that it can be ifconfig'ed       */
+		/* sixpack_init() will be called as a side-effect         */
+		/* SIDE-EFFECT WARNING: sixpack_init() CLEARS spp->ctrl ! */
+
+		if (register_netdev(&(spp->dev)) == 0) 
+		{
+			set_bit(SIXPF_INUSE, &spp->ctrl.flags);
+			spp->ctrl.dev = &(spp->dev);
+			spp->dev.priv = (void*)&(spp->ctrl);
+
+			return (&(spp->ctrl));
+		} else {
+		  	clear_bit(SIXPF_INUSE,&(spp->ctrl.flags));
+			printk(KERN_WARNING "sp_alloc() - register_netdev() failure.\n");
+		}
+	}
+
+	return NULL;
+}
+
+
+/* Free a 6pack channel. */
+static inline void
+sp_free(struct sixpack *sp)
+{
+	/* Free all 6pack frame buffers. */
+	if (sp->rbuff)
+		kfree(sp->rbuff);
+	sp->rbuff = NULL;
+	if (sp->xbuff) {
+		kfree(sp->xbuff);
+	}
+	sp->xbuff = NULL;
+
+	if (!test_and_clear_bit(SIXPF_INUSE, &sp->flags)) 
+	{
+		printk(KERN_WARNING "%s: sp_free for already free unit.\n", sp->dev->name);
+	}
+}
+
+
+/* Set the "sending" flag. */
+static inline void
+sp_lock(struct sixpack *sp)
+{
+	if (test_and_set_bit(0, (void *) &sp->dev->tbusy))  
+		printk(KERN_WARNING "%s: trying to lock already locked device!\n", sp->dev->name);
+}
+
+
+/* Clear the "sending" flag. */
+static inline void
+sp_unlock(struct sixpack *sp)
+{
+	if (!test_and_clear_bit(0, (void *)&sp->dev->tbusy))  
+		printk(KERN_WARNING "%s: trying to unlock already unlocked device!\n", sp->dev->name);
+}
+
+
+/* Send one completely decapsulated IP datagram to the IP layer. */
+
+/* This is the routine that sends the received data to the kernel AX.25.
+   'cmd' is the KISS command. For AX.25 data, it is zero. */
+
+static void
+sp_bump(struct sixpack *sp, char cmd)
+{
+	struct sk_buff *skb;
+	int count;
+	unsigned char *ptr;
+
+	count = sp->rcount+1;
+
+	sp->rx_bytes+=count;
+
+	skb = dev_alloc_skb(count);
+	if (skb == NULL)
+	{
+		printk(KERN_DEBUG "%s: memory squeeze, dropping packet.\n", sp->dev->name);
+		sp->rx_dropped++;
+		return;
+	}
+
+	skb->dev = sp->dev;
+	ptr = skb_put(skb, count);
+	*ptr++ = cmd;	/* KISS command */
+
+	memcpy(ptr, (sp->cooked_buf)+1, count);
+	skb->mac.raw=skb->data;
+	skb->protocol=htons(ETH_P_AX25);
+	netif_rx(skb);
+	sp->rx_packets++;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+/* Encapsulate one AX.25 frame and stuff into a TTY queue. */
+static void
+sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
+{
+	unsigned char *p;
+	int actual, count;
+
+	if (len > sp->mtu) 	/* sp->mtu = AX25_MTU = max. PACLEN = 256 */ 
+	{
+		len = sp->mtu;
+		printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n", sp->dev->name);
+		sp->tx_dropped++;
+		sp_unlock(sp);
+		return;
+	}
+
+	p = icp;
+
+	if (p[0] > 5)
+	{
+		printk(KERN_DEBUG "%s: invalid KISS command -- dropped\n", sp->dev->name);
+		sp_unlock(sp);
+		return;
+	}
+
+	if ((p[0] != 0) && (len > 2))
+	{
+		printk(KERN_DEBUG "%s: KISS control packet too long -- dropped\n", sp->dev->name);
+		sp_unlock(sp);
+		return;
+	}
+
+	if ((p[0] == 0) && (len < 15))
+	{
+		printk(KERN_DEBUG "%s: bad AX.25 packet to transmit -- dropped\n", sp->dev->name);
+		sp_unlock(sp);
+		sp->tx_dropped++;
+		return;
+	}
+
+	count = encode_sixpack(p, (unsigned char *) sp->xbuff, len, sp->tx_delay);
+	sp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+
+	switch(p[0])
+	{
+		case 1:	sp->tx_delay = p[1]; 		return;
+		case 2:	sp->persistance = p[1];		return;
+		case 3: sp->slottime = p[1];		return;
+		case 4: /* ignored */			return;
+		case 5: sp->duplex = p[1];		return;
+	}
+
+	if (p[0] == 0) {
+		/* in case of fullduplex or DAMA operation, we don't take care
+		   about the state of the DCD or of any timers, as the determination
+		   of the correct time to send is the job of the AX.25 layer. We send
+		   immediately after data has arrived. */
+		if (sp->duplex == 1){
+			sp->led_state = 0x70;
+			sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1);
+			sp->tx_enable = 1;
+			actual = sp->tty->driver.write(sp->tty, 0, sp->xbuff, count);
+			sp->xleft = count - actual;
+			sp->xhead = sp->xbuff + actual;
+			sp->led_state = 0x60;
+			sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1);
+		}
+		else {
+			sp->xleft = count;
+			sp->xhead = sp->xbuff;
+			sp->status2 = count;
+			if (sp->duplex == 0)
+				sp_start_tx_timer(sp);
+		}
+	}
+}
+
+/*
+ * Called by the TTY driver when there's room for more data.  If we have
+ * more packets to send, we send them here.
+ */
+static void sixpack_write_wakeup(struct tty_struct *tty)
+{
+	int actual;
+	struct sixpack *sp = (struct sixpack *) tty->disc_data;
+
+	/* First make sure we're connected. */
+	if (!sp || sp->magic != SIXPACK_MAGIC || !sp->dev->start) {
+		return;
+	}
+	if (sp->xleft <= 0)  {
+		/* Now serial buffer is almost free & we can start
+		 * transmission of another packet */
+		sp->tx_packets++;
+		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+		sp_unlock(sp);
+		sp->tx_enable = 0;
+		mark_bh(NET_BH);
+		return;
+	}
+
+	if (sp->tx_enable == 1) {
+		actual = tty->driver.write(tty, 0, sp->xhead, sp->xleft);
+		sp->xleft -= actual;
+		sp->xhead += actual;
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* Encapsulate an IP datagram and kick it into a TTY queue. */
+
+static int
+sp_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct sixpack *sp = (struct sixpack*)(dev->priv);
+
+	if (!dev->start)  
+	{
+		printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name);
+		return 1;
+	}
+
+	if (dev->tbusy)
+		return 1;
+
+	/* We were not busy, so we are now... :-) */
+	if (skb != NULL) {
+		sp_lock(sp);
+		sp->tx_bytes+=skb->len; /*---2.1.x---*/
+		sp_encaps(sp, skb->data, skb->len);
+		dev_kfree_skb(skb);
+	}
+	return 0;
+}
+/* #endif */
+
+
+/* perform the persistence/slottime algorithm for CSMA access. If the persistence
+   check was successful, write the data to the serial driver. Note that in case
+   of DAMA operation, the data is not sent here. */
+
+static 
+void sp_xmit_on_air(unsigned long channel)
+{
+	struct sixpack *sp = (struct sixpack *) channel;
+	int actual;
+	static unsigned char random;
+	
+	random = random * 17 + 41;
+
+	if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistance)) {
+		sp->led_state = 0x70;
+		sp->tty->driver.write(sp->tty, 0, &(sp->led_state),1);
+		sp->tx_enable = 1;
+		actual = sp->tty->driver.write(sp->tty, 0, sp->xbuff, sp->status2);
+		sp->xleft -= actual;
+		sp->xhead += actual;
+		sp->led_state = 0x60;
+		sp->tty->driver.write(sp->tty, 0, &(sp->led_state),1);
+		sp->status2 = 0;
+	} else
+		sp_start_tx_timer(sp);
+} /* sp_xmit */
+
+/* #if defined(CONFIG_6PACK) || defined(CONFIG_6PACK_MODULE) */
+
+/* Return the frame type ID */
+static int sp_header(struct sk_buff *skb, struct device *dev, unsigned short type,
+	  void *daddr, void *saddr, unsigned len)
+{
+#ifdef CONFIG_INET
+	if (type != htons(ETH_P_AX25))
+		return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
+#endif
+	return 0;
+}
+
+
+static int sp_rebuild_header(struct sk_buff *skb)
+{
+#ifdef CONFIG_INET
+	return ax25_rebuild_header(skb);
+#else
+	return 0;
+#endif
+}
+
+/* #endif */ /* CONFIG_{AX25,AX25_MODULE} */
+
+/* Open the low-level part of the 6pack channel. */
+static int
+sp_open(struct device *dev)
+{
+	struct sixpack *sp = (struct sixpack*)(dev->priv);
+	unsigned long len;
+
+	if (sp->tty == NULL) 
+		return -ENODEV;
+
+	/*
+	 * Allocate the 6pack frame buffers:
+	 *
+	 * rbuff	Receive buffer.
+	 * xbuff	Transmit buffer.
+	 * cbuff        Temporary compression buffer.
+	 */
+	 
+	/* !!! length of the buffers. MTU is IP MTU, not PACLEN!
+	 */
+
+	len = dev->mtu * 2;
+
+	sp->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+	if (sp->rbuff == NULL)   
+		return -ENOMEM;
+
+	sp->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
+	if (sp->xbuff == NULL)   
+	{
+		kfree(sp->rbuff);
+		return -ENOMEM;
+	}
+
+	sp->mtu	     = AX25_MTU + 73;
+	sp->buffsize = len;
+	sp->rcount   = 0;
+	sp->rx_count = 0;
+	sp->rx_count_cooked = 0;
+	sp->xleft    = 0;
+
+	sp->flags   &= (1 << SIXPF_INUSE);      /* Clear ESCAPE & ERROR flags */
+
+	sp->duplex = 0;
+	sp->tx_delay    = SIXP_TXDELAY;
+	sp->persistance = SIXP_PERSIST;
+	sp->slottime    = SIXP_SLOTTIME;
+	sp->led_state   = 0x60;
+	sp->status      = 1;
+	sp->status1     = 1;
+	sp->status2     = 0;
+	sp->tnc_ok      = 0;
+	sp->tx_enable   = 0;
+	
+	dev->tbusy  = 0;
+	dev->start  = 1;
+
+	init_timer(&sp->tx_t);
+	init_timer(&sp->resync_t);
+	return 0;
+}
+
+
+/* Close the low-level part of the 6pack channel. */
+static int
+sp_close(struct device *dev)
+{
+	struct sixpack *sp = (struct sixpack*)(dev->priv);
+
+	if (sp->tty == NULL) {
+		return -EBUSY;
+	}
+	sp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+	dev->tbusy = 1;
+	dev->start = 0;
+	
+	return 0;
+}
+
+static int
+sixpack_receive_room(struct tty_struct *tty)
+{
+	return 65536;  /* We can handle an infinite amount of data. :-) */
+}
+
+/* !!! receive state machine */
+
+/*
+ * Handle the 'receiver data ready' interrupt.
+ * This function is called by the 'tty_io' module in the kernel when
+ * a block of 6pack data has been received, which can now be decapsulated
+ * and sent on to some IP layer for further processing.
+ */
+static void
+sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+	unsigned char buf[512];
+	unsigned long flags;
+	int count1;
+
+	struct sixpack *sp = (struct sixpack *) tty->disc_data;
+
+	if (!sp || sp->magic != SIXPACK_MAGIC || !sp->dev->start || !count)
+		return;
+
+	save_flags(flags);
+	cli();
+	memcpy(buf, cp, count<sizeof(buf)? count:sizeof(buf));
+	restore_flags(flags);
+	
+	/* Read the characters out of the buffer */
+
+	count1 = count;
+	while(count)
+	{
+		count--;
+		if (fp && *fp++)
+		{
+			if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))  {
+				sp->rx_errors++;
+			}			
+			continue;
+		}
+	}
+	sixpack_decode(sp, buf, count1);
+}
+
+/*
+ * Open the high-level part of the 6pack channel.
+ * This function is called by the TTY module when the
+ * 6pack line discipline is called for.  Because we are
+ * sure the tty line exists, we only have to link it to
+ * a free 6pcack channel...
+ */
+static int
+sixpack_open(struct tty_struct *tty)
+{
+	struct sixpack *sp = (struct sixpack *) tty->disc_data;
+	int err;
+
+	/* First make sure we're not already connected. */
+
+	if (sp && sp->magic == SIXPACK_MAGIC) 
+		return -EEXIST;
+
+	/* OK.  Find a free 6pack channel to use. */
+	if ((sp = sp_alloc()) == NULL)
+		return -ENFILE;
+	sp->tty = tty;
+	tty->disc_data = sp;
+	if (tty->driver.flush_buffer) 
+		tty->driver.flush_buffer(tty);
+
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+
+
+	/* Restore default settings */
+	sp->dev->type = ARPHRD_AX25;
+
+	/* Perform the low-level 6pack initialization. */
+	if ((err = sp_open(sp->dev)))  
+		return err;
+	
+	MOD_INC_USE_COUNT;
+
+	/* Done.  We have linked the TTY line to a channel. */
+
+	tnc_init(sp);
+
+	return sp->dev->base_addr;
+}
+
+
+/*
+ * Close down a 6pack channel.
+ * This means flushing out any pending queues, and then restoring the
+ * TTY line discipline to what it was before it got hooked to 6pack
+ * (which usually is TTY again).
+ */
+static void
+sixpack_close(struct tty_struct *tty)
+{
+	struct sixpack *sp = (struct sixpack *) tty->disc_data;
+
+	/* First make sure we're connected. */
+	if (!sp || sp->magic != SIXPACK_MAGIC)
+		return;
+
+	rtnl_lock();
+	if (sp->dev->flags & IFF_UP)
+		(void) dev_close(sp->dev);
+
+	del_timer(&(sp->tx_t));
+	del_timer(&(sp->resync_t));
+	
+	tty->disc_data = 0;
+	sp->tty = NULL;
+	/* VSV = very important to remove timers */
+
+	sp_free(sp);
+	unregister_netdev(sp->dev);
+	rtnl_unlock();
+	MOD_DEC_USE_COUNT;
+}
+
+
+static struct net_device_stats *
+sp_get_stats(struct device *dev)
+{
+	static struct net_device_stats stats;
+	struct sixpack *sp = (struct sixpack*)(dev->priv);
+
+	memset(&stats, 0, sizeof(struct net_device_stats));
+
+	stats.rx_packets     = sp->rx_packets;
+	stats.tx_packets     = sp->tx_packets;
+	stats.rx_bytes       = sp->rx_bytes;
+	stats.tx_bytes       = sp->tx_bytes;
+	stats.rx_dropped     = sp->rx_dropped;
+	stats.tx_dropped     = sp->tx_dropped;
+	stats.tx_errors      = sp->tx_errors;
+	stats.rx_errors      = sp->rx_errors;
+	stats.rx_over_errors = sp->rx_over_errors;
+	return (&stats);
+}
+
+
+int
+sp_set_mac_address(struct device *dev, void *addr)
+{
+	int err;
+
+	err = verify_area(VERIFY_READ, addr, AX25_ADDR_LEN);
+	if (err)  {
+		return err;
+	}
+
+	copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN);	/* addr is an AX.25 shifted ASCII mac address */
+
+	return 0;
+}
+
+static int
+sp_set_dev_mac_address(struct device *dev, void *addr)
+{
+	struct sockaddr *sa=addr;
+	memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN);
+	return 0;
+}
+
+
+/* Perform I/O control on an active 6pack channel. */
+static int
+sixpack_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
+{
+	struct sixpack *sp = (struct sixpack *) tty->disc_data;
+	int err;
+	unsigned int tmp;
+
+	/* First make sure we're connected. */
+	if (!sp || sp->magic != SIXPACK_MAGIC) {
+		return -EINVAL;
+	}
+
+	switch(cmd) {
+	 case SIOCGIFNAME:
+		err = verify_area(VERIFY_WRITE, arg, strlen(sp->dev->name) + 1);
+		if (err)  {
+			return err;
+		}
+		copy_to_user(arg, sp->dev->name, strlen(sp->dev->name) + 1);
+		return 0;
+
+	case SIOCGIFENCAP:
+		err = verify_area(VERIFY_WRITE, arg, sizeof(int));
+		if (err)  {
+			return err;
+		}
+		put_user(0, (int *)arg);
+		return 0;
+
+	case SIOCSIFENCAP:
+		err = verify_area(VERIFY_READ, arg, sizeof(int));
+		if (err)  {
+			return err;
+		}
+		get_user(tmp,(int *)arg);
+
+ 		sp->mode = tmp;
+		sp->dev->addr_len        = AX25_ADDR_LEN;	  /* sizeof an AX.25 addr */
+		sp->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3;
+		sp->dev->type            = ARPHRD_AX25;
+
+		return 0;
+
+	 case SIOCSIFHWADDR:
+		return sp_set_mac_address(sp->dev, arg);
+
+	/* Allow stty to read, but not set, the serial port */
+	case TCGETS:
+	case TCGETA:
+		return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg);
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static int sp_open_dev(struct device *dev)
+{
+	struct sixpack *sp = (struct sixpack*)(dev->priv);
+	if(sp->tty==NULL)
+		return -ENODEV;
+	return 0;
+}
+
+/* Initialize 6pack control device -- register 6pack line discipline */
+
+#ifdef MODULE
+static int sixpack_init_ctrl_dev(void)
+#else	/* !MODULE */
+__initfunc sixpack_init_ctrl_dev(struct device *dummy)
+#endif	/* !MODULE */
+{
+	int status;
+
+	if (sixpack_maxdev < 4) sixpack_maxdev = 4; /* Sanity */
+
+	printk(KERN_INFO "6pack: %s (dynamic channels, max=%d)\n",
+	       SIXPACK_VERSION, sixpack_maxdev);
+
+	sixpack_ctrls = (sixpack_ctrl_t **) kmalloc(sizeof(void*)*sixpack_maxdev, GFP_KERNEL);
+	if (sixpack_ctrls == NULL) 
+	{
+		printk(KERN_WARNING "6pack: Can't allocate sixpack_ctrls[] array!  Uaargh! (-> No 6pack available)\n");
+		return -ENOMEM;
+	}
+
+	/* Clear the pointer array, we allocate devices when we need them */
+	memset(sixpack_ctrls, 0, sizeof(void*)*sixpack_maxdev); /* Pointers */
+
+
+	/* Fill in our line protocol discipline, and register it */
+	memset(&sp_ldisc, 0, sizeof(sp_ldisc));
+	sp_ldisc.magic  = TTY_LDISC_MAGIC;
+	sp_ldisc.name   = "6pack";
+	sp_ldisc.flags  = 0;
+	sp_ldisc.open   = sixpack_open;
+	sp_ldisc.close  = sixpack_close;
+	sp_ldisc.read   = NULL;
+	sp_ldisc.write  = NULL;
+	sp_ldisc.ioctl  = (int (*)(struct tty_struct *, struct file *,
+				   unsigned int, unsigned long)) sixpack_ioctl;
+	sp_ldisc.poll = NULL;
+	sp_ldisc.receive_buf = sixpack_receive_buf;
+	sp_ldisc.receive_room = sixpack_receive_room;
+	sp_ldisc.write_wakeup = sixpack_write_wakeup;
+	if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0)  {
+		printk(KERN_WARNING "6pack: can't register line discipline (err = %d)\n", status);
+	}
+
+#ifdef MODULE
+	return status;
+#else
+	/* Return "not found", so that dev_init() will unlink
+	 * the placeholder device entry for us.
+	 */
+	return ENODEV;
+#endif
+}
+
+/* Initialize the 6pack driver.  Called by DDI. */
+int
+sixpack_init(struct device *dev)
+{
+	struct sixpack *sp = (struct sixpack*)(dev->priv);
+
+	static char ax25_bcast[AX25_ADDR_LEN] =
+		{'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
+	static char ax25_test[AX25_ADDR_LEN] =
+		{'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
+
+	if (sp == NULL)		/* Allocation failed ?? */
+	  return -ENODEV;
+
+	/* Set up the "6pack Control Block". (And clear statistics) */
+	
+	memset(sp, 0, sizeof (struct sixpack));
+	sp->magic  = SIXPACK_MAGIC;
+	sp->dev	   = dev;
+	
+	/* Finish setting up the DEVICE info. */
+	dev->mtu		= SIXP_MTU;
+	dev->hard_start_xmit	= sp_xmit;
+	dev->open		= sp_open_dev;
+	dev->stop		= sp_close;
+	dev->hard_header	= sp_header;
+	dev->get_stats	        = sp_get_stats;
+	dev->set_mac_address    = sp_set_dev_mac_address;
+	dev->hard_header_len	= AX25_MAX_HEADER_LEN;
+	dev->addr_len		= AX25_ADDR_LEN;
+	dev->type		= ARPHRD_AX25;
+	dev->tx_queue_len	= 10;
+	dev->rebuild_header	= sp_rebuild_header;
+
+	memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);	/* Only activated in AX.25 mode */
+	memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);	/*    ""      ""       ""    "" */
+
+	dev_init_buffers(dev);
+
+	/* New-style flags. */
+	dev->flags		= 0;
+
+	return 0;
+}
+
+#ifdef MODULE
+
+int
+init_module(void)
+{
+	return sixpack_init_ctrl_dev();
+}
+
+void
+cleanup_module(void)
+{
+	int i;
+
+	if (sixpack_ctrls != NULL) 
+	{
+		for (i = 0; i < sixpack_maxdev; i++)  
+		{
+			if (sixpack_ctrls[i])
+			{
+				/*
+				 * VSV = if dev->start==0, then device
+				 * unregistered while close proc.
+				 */ 
+				if (sixpack_ctrls[i]->dev.start)
+					unregister_netdev(&(sixpack_ctrls[i]->dev));
+
+				kfree(sixpack_ctrls[i]);
+				sixpack_ctrls[i] = NULL;
+			}
+		}
+		kfree(sixpack_ctrls);
+		sixpack_ctrls = NULL;
+	}
+	if ((i = tty_register_ldisc(N_6PACK, NULL)))  
+	{
+		printk(KERN_WARNING "6pack: can't unregister line discipline (err = %d)\n", i);
+	}
+}
+#endif /* MODULE */
+
+/* ----> 6pack timer interrupt handler and friends. <---- */
+static void 
+sp_start_tx_timer(struct sixpack *sp)
+{
+	int when = sp->slottime;
+	
+	del_timer(&(sp->tx_t));
+	sp->tx_t.data = (unsigned long) sp;
+	sp->tx_t.function = sp_xmit_on_air;
+	sp->tx_t.expires = jiffies + ((when+1)*HZ)/100;
+	add_timer(&(sp->tx_t));
+}
+
+
+/* encode an AX.25 packet into 6pack */
+
+int encode_sixpack(byte *tx_buf, byte *tx_buf_raw, int length, byte tx_delay)
+{
+	int count = 0;
+	byte checksum = 0, buf[400];
+	int raw_count = 0;
+
+	tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK;
+	tx_buf_raw[raw_count++] = SIXP_SEOF;
+
+	buf[0] = tx_delay;
+	for(count = 1; count < length; count++)
+		buf[count] = tx_buf[count];
+
+	for(count = 0; count < length; count++)
+		checksum += buf[count];
+	buf[length] = (byte)0xff - checksum;
+	
+	for(count = 0; count <= length; count++) {
+		if((count % 3) == 0) {
+			tx_buf_raw[raw_count++] = (buf[count] & 0x3f);
+			tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30);
+		}
+		else if((count % 3) == 1) {
+			tx_buf_raw[raw_count++] |= (buf[count] & 0x0f);
+			tx_buf_raw[raw_count] =
+				((buf[count] >> 2) & 0x3c);
+		} else {
+			tx_buf_raw[raw_count++] |= (buf[count] & 0x03);
+			tx_buf_raw[raw_count++] =
+				(buf[count] >> 2);
+		} /* else */
+	} /* for */
+	if ((length % 3) != 2)
+		raw_count++;
+	tx_buf_raw[raw_count++] = SIXP_SEOF;
+	return(raw_count);
+}
+
+
+/* decode a 6pack packet */
+
+void
+sixpack_decode(struct sixpack *sp, unsigned char pre_rbuff[], int count)
+{
+	byte inbyte;
+	int count1;
+
+	for (count1 = 0; count1 < count; count1++) {
+		inbyte = pre_rbuff[count1];
+		if (inbyte == SIXP_FOUND_TNC) {
+			printk(KERN_INFO "6pack: TNC found.\n");
+			sp->tnc_ok = 1;
+			del_timer(&(sp->resync_t));
+		}
+		if((inbyte & SIXP_PRIO_CMD_MASK) != 0)
+			decode_prio_command(inbyte, sp);
+		else if((inbyte & SIXP_STD_CMD_MASK) != 0)
+			decode_std_command(inbyte, sp);
+		else {
+			if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)
+				decode_data(inbyte, sp);
+		} /* else */
+	} /* for */
+}
+
+static int
+tnc_init(struct sixpack *sp)
+{
+	static byte inbyte;
+	
+	inbyte = 0xe8;
+	sp->tty->driver.write(sp->tty, 0, &inbyte, 1);
+
+	del_timer(&(sp->resync_t));
+	sp->resync_t.data = (unsigned long) sp;
+	sp->resync_t.function = resync_tnc;
+	sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
+	add_timer(&(sp->resync_t));
+
+	return 0;
+}
+
+
+/* identify and execute a 6pack priority command byte */
+
+void decode_prio_command(byte cmd, struct sixpack *sp)
+{
+	byte channel;
+	int actual;
+
+	channel = cmd & SIXP_CHN_MASK;
+	if ((cmd & SIXP_PRIO_DATA_MASK) != 0) {     /* idle ? */
+
+	/* RX and DCD flags can only be set in the same prio command,
+	   if the DCD flag has been set without the RX flag in the previous
+	   prio command. If DCD has not been set before, something in the
+	   transmission has gone wrong. In this case, RX and DCD are
+	   cleared in order to prevent the decode_data routine from
+	   reading further data that might be corrupt. */
+
+		if (((sp->status & SIXP_DCD_MASK) == 0) &&
+			((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) {
+				if (sp->status != 1)
+					printk(KERN_DEBUG "6pack: protocol violation\n");
+				else
+					sp->status = 0;
+				cmd &= !SIXP_RX_DCD_MASK;
+		}
+		sp->status = cmd & SIXP_PRIO_DATA_MASK;
+	} /* if */
+	else { /* output watchdog char if idle */
+		if ((sp->status2 != 0) && (sp->duplex == 1)) {
+			sp->led_state = 0x70;
+			sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1);
+			sp->tx_enable = 1;
+			actual = sp->tty->driver.write(sp->tty, 0, sp->xbuff, sp->status2);
+			sp->xleft -= actual;
+			sp->xhead += actual;
+			sp->led_state = 0x60;
+			sp->status2 = 0;
+
+		} /* if */
+	} /* else */
+
+	/* needed to trigger the TNC watchdog */
+	sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1);
+
+        /* if the state byte has been received, the TNC is present,
+           so the resync timer can be reset. */
+
+	if (sp->tnc_ok == 1) {
+		del_timer(&(sp->resync_t));
+		sp->resync_t.data = (unsigned long) sp;
+		sp->resync_t.function = resync_tnc;
+		sp->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT;
+		add_timer(&(sp->resync_t));
+	}
+
+	sp->status1 = cmd & SIXP_PRIO_DATA_MASK;
+}
+
+/* try to resync the TNC. Called by the resync timer defined in
+  decode_prio_command */
+
+static void
+resync_tnc(unsigned long channel)
+{
+	static char resync_cmd = 0xe8;
+	struct sixpack *sp = (struct sixpack *) channel;
+
+	printk(KERN_INFO "6pack: resyncing TNC\n");
+
+	/* clear any data that might have been received */
+	
+	sp->rx_count = 0;
+	sp->rx_count_cooked = 0;
+
+	/* reset state machine */
+
+	sp->status = 1;
+	sp->status1 = 1;
+	sp->status2 = 0;
+	sp->tnc_ok = 0;
+	
+	/* resync the TNC */
+
+	sp->led_state = 0x60;
+	sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1);
+	sp->tty->driver.write(sp->tty, 0, &resync_cmd, 1);
+
+
+	/* Start resync timer again -- the TNC might be still absent */
+
+	del_timer(&(sp->resync_t));
+	sp->resync_t.data = (unsigned long) sp;
+	sp->resync_t.function = resync_tnc;
+	sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
+	add_timer(&(sp->resync_t));
+}
+
+
+
+/* identify and execute a standard 6pack command byte */
+
+void decode_std_command(byte cmd, struct sixpack *sp)
+{
+	byte checksum = 0, rest = 0, channel;
+	short i;
+
+	channel = cmd & SIXP_CHN_MASK;
+	switch(cmd & SIXP_CMD_MASK) {     /* normal command */
+		case SIXP_SEOF:
+			if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) {
+				if ((sp->status & SIXP_RX_DCD_MASK) ==
+					SIXP_RX_DCD_MASK) {
+					sp->led_state = 0x68;
+					sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1);
+				} /* if */
+			} else {
+				sp->led_state = 0x60;
+				/* fill trailing bytes with zeroes */
+				sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1);
+				rest = sp->rx_count;
+				if (rest != 0)
+					 for(i=rest; i<=3; i++)
+						decode_data(0, sp);
+				if (rest == 2)
+					sp->rx_count_cooked -= 2;
+				else if (rest == 3)
+					sp->rx_count_cooked -= 1;
+				for (i=0; i<sp->rx_count_cooked; i++)
+					checksum+=sp->cooked_buf[i];
+				if (checksum != SIXP_CHKSUM) {
+					printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum);
+				} else {
+					sp->rcount = sp->rx_count_cooked-2;
+					sp_bump(sp, 0);
+				} /* else */
+				sp->rx_count_cooked = 0;
+			} /* else */
+			break;
+		case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n");
+			break;
+		case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n");
+			break;
+		case SIXP_RX_BUF_OVL:
+			printk(KERN_DEBUG "6pack: RX buffer overflow\n");
+	} /* switch */
+} /* function */
+
+/* decode 4 sixpack-encoded bytes into 3 data bytes */
+
+void decode_data(byte inbyte, struct sixpack *sp)
+{
+
+	unsigned char *buf;
+
+	if (sp->rx_count != 3)
+		sp->raw_buf[sp->rx_count++] = inbyte;
+	else {
+		buf = sp->raw_buf;
+		sp->cooked_buf[sp->rx_count_cooked++] =
+			buf[0] | ((buf[1] << 2) & 0xc0);
+		sp->cooked_buf[sp->rx_count_cooked++] =
+			(buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0);
+		sp->cooked_buf[sp->rx_count_cooked++] =
+			(buf[2] & 0x03) | (inbyte << 2);
+		sp->rx_count = 0;
+	}
+}
diff -u --recursive --new-file v2.1.93/linux/drivers/net/hamradio/6pack.h linux/drivers/net/hamradio/6pack.h
--- v2.1.93/linux/drivers/net/hamradio/6pack.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/hamradio/6pack.h	Wed Apr  8 17:31:27 1998
@@ -0,0 +1,135 @@
+/*
+ * 6pack.h	Define the 6pack device driver interface and constants.
+ *
+ * NOTE:	THIS FILE WILL BE MOVED TO THE LINUX INCLUDE DIRECTORY
+ *		AS SOON AS POSSIBLE!
+ *
+ * Version:	@(#)6pack.h	0.3.0	04/07/98
+ *
+ * Fixes:
+ *
+ * Author:	Andreas Könsgen <ajk@iehk.rwth-aachen.de>
+ *
+ *		This file is derived from slip.h, written by
+ *		Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ */
+
+#ifndef _LINUX_6PACK_H
+#define _LINUX_6PACK_H
+
+#define SIXPACK_VERSION    "Revision: 0.3.0"
+
+#ifdef __KERNEL__
+
+/* sixpack priority commands */
+#define SIXP_SEOF	0x40	/* start and end of a 6pack frame */
+#define SIXP_TX_URUN	0x48	/* transmit overrun */
+#define SIXP_RX_ORUN	0x50	/* receive overrun */
+#define SIXP_RX_BUF_OVL	0x58	/* receive buffer overflow */
+
+#define SIXP_CHKSUM	0xFF	/* valid checksum of a 6pack frame */
+
+/* masks to get certain bits out of the status bytes sent by the TNC */
+
+#define SIXP_CMD_MASK		0xC0
+#define SIXP_CHN_MASK		0x07
+#define SIXP_PRIO_CMD_MASK	0x80
+#define SIXP_STD_CMD_MASK	0x40
+#define SIXP_PRIO_DATA_MASK	0x38
+#define SIXP_TX_MASK		0x20
+#define SIXP_RX_MASK		0x10
+#define SIXP_RX_DCD_MASK	0x18
+#define SIXP_LEDS_ON		0x78
+#define SIXP_LEDS_OFF		0x60
+#define SIXP_CON		0x08
+#define SIXP_STA		0x10
+
+#define SIXP_FOUND_TNC		0xe9
+#define SIXP_CON_ON		0x68
+#define SIXP_DCD_MASK		0x08
+#define SIXP_DAMA_OFF		0
+
+/* default level 2 parameters */
+#define SIXP_TXDELAY			25	/* in 10 ms */
+#define SIXP_PERSIST			50	/* in 256ths */
+#define SIXP_SLOTTIME			10	/* in 10 ms */
+#define SIXP_INIT_RESYNC_TIMEOUT	150	/* in 10 ms */
+#define SIXP_RESYNC_TIMEOUT		500	/* in 10 ms */
+
+/* 6pack configuration. */
+#define SIXP_NRUNIT			256	/* MAX number of 6pack channels */
+#define SIXP_MTU			256	/* Default MTU */
+
+enum sixpack_flags {
+	SIXPF_INUSE,	/* Channel in use	*/
+	SIXPF_ERROR,	/* Parity, etc. error	*/
+};
+
+struct sixpack {
+  int			magic;
+
+  /* Various fields. */
+  struct tty_struct	*tty;		/* ptr to TTY structure		*/
+  struct device		*dev;		/* easy for intr handling	*/
+
+  /* These are pointers to the malloc()ed frame buffers. */
+  unsigned char		*rbuff;		/* receiver buffer		*/
+  int                   rcount;         /* received chars counter       */
+  unsigned char		*xbuff;		/* transmitter buffer		*/
+  unsigned char         *xhead;         /* pointer to next byte to XMIT */
+  int                   xleft;          /* bytes left in XMIT queue     */
+
+  unsigned char		raw_buf[4];
+  unsigned char		cooked_buf[400];
+
+  unsigned int		rx_count;
+  unsigned int		rx_count_cooked;
+
+  /* 6pack interface statistics. */
+  unsigned long		rx_packets;	/* inbound frames counter	*/
+  unsigned long         tx_packets;     /* outbound frames counter      */
+  unsigned long         rx_bytes;       /* inbound bytes counter        */
+  unsigned long         tx_bytes;       /* outboud bytes counter        */
+  unsigned long         rx_errors;      /* Parity, etc. errors          */
+  unsigned long         tx_errors;      /* Planned stuff                */
+  unsigned long         rx_dropped;     /* No memory for skb            */
+  unsigned long         tx_dropped;     /* When MTU change              */
+  unsigned long         rx_over_errors; /* Frame bigger then 6pack buf. */
+
+  /* Detailed 6pack statistics. */
+
+  int			mtu;		/* Our mtu (to spot changes!)   */
+  int                   buffsize;       /* Max buffers sizes            */
+
+  unsigned char		flags;		/* Flag values/ mode etc	*/
+  unsigned char		mode;		/* 6pack mode			*/
+
+/* 6pack stuff */
+  
+  unsigned char tx_delay;
+  unsigned char persistance;
+  unsigned char slottime;
+  unsigned char duplex;
+  unsigned char led_state;
+  unsigned char status;
+  unsigned char status1;
+  unsigned char status2;
+  unsigned char tx_enable;
+  unsigned char tnc_ok;
+  
+/*  unsigned char retval; */
+
+  struct timer_list tx_t;
+  struct timer_list resync_t;
+}; /* struct sixpack */
+
+
+/* should later be moved to include/net/ax25.h */
+#define AX25_6PACK_HEADER_LEN 0
+#define SIXPACK_MAGIC 0x5304
+
+extern int sixpack_init(struct device *dev);
+
+#endif
+
+#endif	/* _LINUX_6PACK.H */
diff -u --recursive --new-file v2.1.93/linux/drivers/net/hamradio/Config.in linux/drivers/net/hamradio/Config.in
--- v2.1.93/linux/drivers/net/hamradio/Config.in	Wed Feb  4 11:36:00 1998
+++ linux/drivers/net/hamradio/Config.in	Wed Apr  8 17:31:27 1998
@@ -1,7 +1,7 @@
 comment 'AX.25 network device drivers'
 
 dep_tristate 'Serial port KISS driver' CONFIG_MKISS $CONFIG_AX25
-# dep_tristate 'Serial port 6PACK driver' CONFIG_6PACK $CONFIG_AX25
+dep_tristate 'Serial port 6PACK driver' CONFIG_6PACK $CONFIG_AX25
 dep_tristate 'BPQ Ethernet driver' CONFIG_BPQETHER $CONFIG_AX25
     
 dep_tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25
diff -u --recursive --new-file v2.1.93/linux/drivers/net/hamradio/Makefile linux/drivers/net/hamradio/Makefile
--- v2.1.93/linux/drivers/net/hamradio/Makefile	Sun Jan  4 10:40:16 1998
+++ linux/drivers/net/hamradio/Makefile	Wed Apr  8 17:31:27 1998
@@ -45,6 +45,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_6PACK),y)
+L_OBJS += 6pack.o
+else
+  ifeq ($(CONFIG_6PACK),m)
+  M_OBJS += 6pack.o
+  endif
+endif
+
 ifeq ($(CONFIG_PI),y)
 L_OBJS += pi2.o
 else
diff -u --recursive --new-file v2.1.93/linux/drivers/net/hamradio/soundmodem/gentbl.c linux/drivers/net/hamradio/soundmodem/gentbl.c
--- v2.1.93/linux/drivers/net/hamradio/soundmodem/gentbl.c	Thu Mar 26 15:57:03 1998
+++ linux/drivers/net/hamradio/soundmodem/gentbl.c	Tue Apr  7 07:48:54 1998
@@ -681,7 +681,7 @@
 	gentbl_costab(f, 6);
 	gentbl_afsk2400(f, 7372800);
 	fclose(f);
-	return(0);
+	exit(0);
 }
 
 
diff -u --recursive --new-file v2.1.93/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c
--- v2.1.93/linux/drivers/net/sdla_fr.c	Thu Mar 26 15:57:03 1998
+++ linux/drivers/net/sdla_fr.c	Tue Apr  7 07:52:04 1998
@@ -83,7 +83,6 @@
 * Jan 02, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
-#include <linux/config.h>	/* OS configuration options */
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
diff -u --recursive --new-file v2.1.93/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c
--- v2.1.93/linux/drivers/net/sdla_ppp.c	Thu Mar 26 15:57:03 1998
+++ linux/drivers/net/sdla_ppp.c	Tue Apr  7 07:52:04 1998
@@ -56,7 +56,6 @@
 * Jan 06, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
-#include <linux/config.h>	/* OS configuration options */
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
diff -u --recursive --new-file v2.1.93/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c
--- v2.1.93/linux/drivers/net/sdla_x25.c	Thu Mar 26 15:57:03 1998
+++ linux/drivers/net/sdla_x25.c	Tue Apr  7 07:52:04 1998
@@ -42,7 +42,6 @@
 #error	This code MUST be compiled as a kernel module!
 #endif
 
-#include <linux/config.h>	/* OS configuration options */
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
diff -u --recursive --new-file v2.1.93/linux/drivers/scsi/mvme16x.c linux/drivers/scsi/mvme16x.c
--- v2.1.93/linux/drivers/scsi/mvme16x.c	Thu Mar 26 15:57:03 1998
+++ linux/drivers/scsi/mvme16x.c	Tue Apr  7 07:52:04 1998
@@ -8,7 +8,6 @@
 #include <linux/blk.h>
 #include <linux/sched.h>
 #include <linux/version.h>
-#include <linux/config.h>
 #include <linux/zorro.h>
 
 #include <asm/page.h>
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.1.93/linux/drivers/sound/Config.in	Tue Mar 17 22:18:14 1998
+++ linux/drivers/sound/Config.in	Wed Apr  8 17:24:48 1998
@@ -6,8 +6,6 @@
 
 dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND
 if [ "$CONFIG_SB" = "y" ]; then
-    bool 'Is the card a Soundman Games ?' CONFIG_SM_GAMES
-    bool 'Are you using the IBM Mwave "emulation" of SB ?' CONFIG_SB_MWAVE
     hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220
     int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7
     int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1
@@ -43,7 +41,7 @@
     int 'MPU401 IRQ Check from manual of the card' CONFIG_MPU_IRQ 9
 fi
 
-dep_tristate 'PSS (ECHO-ADI2111) support' CONFIG_PSS $CONFIG_SOUND
+dep_tristate 'PSS (AD1848, ADSP-2115, ESC614) support' CONFIG_PSS $CONFIG_SOUND 
 if [ "$CONFIG_PSS" = "y" ]; then
     hex 'PSS I/O base 220 or 240' CONFIG_PSS_BASE 220
     hex 'PSS audio I/O base 530, 604, E80 or F40' CONFIG_PSS_MSS_BASE 530
@@ -56,6 +54,9 @@
        string '  Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE
     fi
 fi
+if [ "$CONFIG_PSS" = "m" ] || [ "$CONFIG_PSS" = "y" ]; then
+    bool '  Enable PSS mixer (Beethoven ADSP-16 and other compatibile)' CONFIG_PSS_MIXER
+fi
 
 dep_tristate 'Microsoft Sound System support' CONFIG_MSS $CONFIG_SOUND
 if [ "$CONFIG_MSS" = "y" ]; then
@@ -92,6 +93,7 @@
 fi
 
 dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_MAD16 $CONFIG_SOUND
+dep_tristate 'Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD $CONFIG_MAD16
 if [ "$CONFIG_MAD16" = "y" ]; then
     hex 'MAD16 audio I/O base 530, 604, E80 or F40' CONFIG_MAD16_BASE 530
     int 'MAD16 audio IRQ 7, 9, 10 or 11' CONFIG_MAD16_IRQ 11
@@ -213,3 +215,6 @@
    fi
 fi
 
+if [ "$CONFIG_ARM" = "y" ]; then
+	bool 'VIDC 16-bit sound' CONFIG_VIDC_SOUND
+fi
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/Defines linux/drivers/sound/Defines
--- v2.1.93/linux/drivers/sound/Defines	Mon Feb 23 18:12:08 1998
+++ linux/drivers/sound/Defines	Wed Apr  8 17:24:48 1998
@@ -231,6 +231,12 @@
 endif
 endif
 
+ifdef CONFIG_VIDC_SOUND
+ifneq ($(CONFIG_SEQUENCER),Y)
+CONFIG_SEQUENCER=y
+endif
+endif
+
 ifdef CONFIG_PAS
 ifneq ($(CONFIG_AUDIO),Y)
 CONFIG_AUDIO=y
@@ -304,6 +310,12 @@
 endif
 
 ifdef CONFIG_SOFTOSS
+ifneq ($(CONFIG_AUDIO),Y)
+CONFIG_AUDIO=y
+endif
+endif
+
+ifdef CONFIG_VIDC_SOUND
 ifneq ($(CONFIG_AUDIO),Y)
 CONFIG_AUDIO=y
 endif
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.1.93/linux/drivers/sound/Makefile	Tue Mar 17 22:18:14 1998
+++ linux/drivers/sound/Makefile	Wed Apr  8 17:24:48 1998
@@ -117,6 +117,22 @@
   endif
 endif
 
+ifeq ($(CONFIG_MPU401),y)
+LX_OBJS += mpu401.o
+else
+  ifeq ($(CONFIG_MPU401),m)
+  MX_OBJS += mpu401.o
+  else
+    ifeq ($(CONFIG_MPU_EMU),y)
+    LX_OBJS += mpu401.o
+    else
+      ifeq ($(CONFIG_MPU_EMU),m)
+      MX_OBJS += mpu401.o
+      endif
+    endif
+  endif
+endif
+
 ifeq ($(CONFIG_UART401),y)
 LX_OBJS += uart401.o
 else
@@ -143,31 +159,9 @@
 
 ifeq ($(CONFIG_SSCAPE),y)
 L_OBJS += sscape.o
-LX_OBJS += ad1848.o
-CONFIG_MPU401 = y
 else
   ifeq ($(CONFIG_SSCAPE),m)
   M_OBJS += sscape.o
-  MX_OBJS += ad1848.o
-  ifneq ($(CONFIG_MPU401),y)
-    CONFIG_MPU401 = m
-  endif
-  endif
-endif
-
-ifeq ($(CONFIG_MPU401),y)
-LX_OBJS += mpu401.o
-else
-  ifeq ($(CONFIG_MPU401),m)
-  MX_OBJS += mpu401.o
-  else
-    ifeq ($(CONFIG_MPU_EMU),y)
-    LX_OBJS += mpu401.o
-    else
-      ifeq ($(CONFIG_MPU_EMU),m)
-      MX_OBJS += mpu401.o
-      endif
-    endif
   endif
 endif
 
@@ -230,27 +224,31 @@
    endif
 endif
 
+ifeq ($(CONFIG_VIDC_SOUND),y)
+  L_OBJS += vidc.o vidc_audio.o vidc_mixer.o vidc_synth.o vidc_fill.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 softoss2.o:	softoss.o softoss_rs.o
-	ld -r -o softoss2.o softoss.o softoss_rs.o
+	$(LD) -r -o softoss2.o softoss.o softoss_rs.o
 
 pas2.o:       pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
-	ld -r -o pas2.o pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
+	$(LD) -r -o pas2.o pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
 
 sb.o: sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o
-	ld -r -o sb.o sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o
+	$(LD) -r -o sb.o sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o
 
 lowlevel/lowlevel.o:
 	cd lowlevel; make
 
-sound.o: soundcard.o dev_table.o audio.o dmabuf.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o
-	ld -r -o sound.o soundcard.o dev_table.o audio.o dmabuf.o \
+sound.o: soundcard.o dev_table.o audio.o dmabuf.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o sound_syms.o
+	$(LD) -r -o sound.o soundcard.o dev_table.o audio.o dmabuf.o \
 	       sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o \
-	       midi_synth.o midibuf.o sound_firmware.o
+	       midi_synth.o midibuf.o sound_firmware.o sound_syms.o
 
 gus.o: gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
-	ld -r -o gus.o gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
+	$(LD) -r -o gus.o gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
 
 # Firmware files that need translation
 #
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/README.C931 linux/drivers/sound/README.C931
--- v2.1.93/linux/drivers/sound/README.C931	Sun Dec 21 17:41:24 1997
+++ linux/drivers/sound/README.C931	Wed Dec 31 16:00:00 1969
@@ -1,62 +0,0 @@
-Support for the OPTI 82C931 chip
---------------------------------
-
-The opti 82C931 is supported in it's non PnP mode.
-You do not need to set jumpers etc... The sound driver
-will check the card status and if it is required it will
-force the card into a mode that it can be programmed.
-
-To compile support for the OPTI 82C931 card you can use
-the regular Linux config menus (ie, "make xconfig").
-
-Sound card support should be enabled as a module (chose m).
-Enable (m) for  these items:
-  100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support (CONFIG_SB)
-  Generic OPL2/OPL3 FM synthesizer support                         (CONFIG_ADLIB)
-  Microsoft Sound System support		                   (CONFIG_MSS)
-  Support for OPTi MAD16 and/or Mozart based cards		   (CONFIG_MAD16)
-  FM synthesizer (YM3812/OPL-3) support				   (CONFIG_YM3812)
-
-The configuration menu may ask for addresses, irq lines or dma
-channels. If the card is used as a module the module loading
-options will override these values.
-
-Go on and compile your kernel and modules, install the modules.
-
-I use this configuration as part of /etc/conf.modules:
-
-options sb mad16=1
-options mad16 irq=10 dma=1 io=0x530 joystick=1 cdtype=0
-options opl3 io=0x388
-
-After installing everything and booting to a kernel that
-matches the modules you can load the sound driver:
-
-modprobe mad16
-modprobe opl3
-
-As a result these modules are loaded:
-Module                  Size  Used by
-opl3                   10416   0  (unused)
-mad16                   6472   0 
-sb                     23544   0  [mad16]
-uart401                 5796   0  [mad16 sb]
-ad1848                 16532   1  [mad16]
-sound                  82052   0  [opl3 mad16 sb uart401 ad1848]
-
-Known problems:
-1. The uart401 cannot be used. This is probably a problem which
-   was introduced when the sound driver was modularized.
-   Do not try to load uart401 with options (io=xxx, irq=yyy) because
-   it will try to initialize itself and fail.
-
-2. Cannot use the sound driver in Duplex mode. Until it is fixed
-   use only one DMA channel (0, 1 or 3) for mad16.
-
-3. Configuration of the cdrom adaptor on the sound card is not
-   tested and probably does not work.
-
-4. General problem with the modularized sound driver: If you 
-   load part of the sound driver while a sound program is
-   running, stopping the program may result with a situation
-   where the "Used by" count becomes negative.
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v2.1.93/linux/drivers/sound/ad1848.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/sound/ad1848.c	Wed Apr  8 17:24:48 1998
@@ -12,16 +12,16 @@
  *
  * CS4232 is a PnP audio chip which contains a CS4231A (and SB, MPU).
  * CS4232A is an improved version of CS4232.
- */
-
-/*
+ *
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
- */
-/*
+ *
+ *
  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
  *		     general sleep/wakeup clean up.
  * Alan Cox	   : reformatted. Fixed SMP bugs. Moved to kernel alloc/free
@@ -84,7 +84,6 @@
 	int             irq_ok;
 	mixer_ents     *mix_devices;
 	int             mixer_output_port;
-	int             c930_password_port;
 } ad1848_info;
 
 typedef struct ad1848_port_info
@@ -561,6 +560,12 @@
 		val = devc->mixer_output_port;
 		return put_user(val, (int *)arg);
 	}
+	if (cmd == SOUND_MIXER_PRIVATE2)
+	{
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		return(ad1848_control(AD1848_MIXER_REROUTE, val));
+	}
 	if (((cmd >> 8) & 0xff) == 'M') 
 	{
 		if (_SIOC_DIR(cmd) & _SIOC_WRITE)
@@ -1409,7 +1414,6 @@
 	devc->chip_name = devc->name = "AD1848";
 	devc->model = MD_1848;	/* AD1848 or CS4248 */
 	devc->levels = NULL;
-	devc->c930_password_port = 0;
 	devc->debug_flag = 0;
 
 	/*
@@ -1789,11 +1793,15 @@
 		if (request_irq(devc->irq, adintr, 0, devc->name, (void *)my_dev) < 0)
 		{
 			printk(KERN_WARNING "ad1848: Unable to allocate IRQ\n");
+			/* Don't free it either then.. */
+			devc->irq = 0;
 		}
 		if (devc->model != MD_1848 && devc->model != MD_C930)
 		{
+#ifndef __SMP__
 			int x;
 			unsigned char tmp = ad_read(devc, 16);
+#endif			
 
 			devc->timer_ticks = 0;
 
@@ -1843,16 +1851,15 @@
 	{
 		audio_devs[my_dev]->mixer_dev = e;
 	}
-	MOD_INC_USE_COUNT;
 	return my_dev;
 }
 
-void ad1848_control(int cmd, int arg)
+int ad1848_control(int cmd, int arg)
 {
 	ad1848_info *devc;
 
 	if (nr_ad1848_devs < 1)
-		return;
+		return -ENODEV;
 
 	devc = &adev_info[nr_ad1848_devs - 1];
 
@@ -1860,7 +1867,7 @@
 	{
 		case AD1848_SET_XTAL:	/* Change clock frequency of AD1845 (only ) */
 			if (devc->model != MD_1845)
-				return;
+				return -EINVAL;
 			ad_enter_MCE(devc);
 			ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5));
 			ad_leave_MCE(devc);
@@ -1871,32 +1878,37 @@
 			int o = (arg >> 8) & 0xff;
 			int n = arg & 0xff;
 
+			if (o < 0 || o >= SOUND_MIXER_NRDEVICES)
+				return -EINVAL;
+
+			if (!(devc->supported_devices & (1 << o)) &&
+			    !(devc->supported_rec_devices & (1 << o)))
+				return -EINVAL;
+
 			if (n == SOUND_MIXER_NONE)
 			{	/* Just hide this control */
 				ad1848_mixer_set(devc, o, 0);	/* Shut up it */
 				devc->supported_devices &= ~(1 << o);
 				devc->supported_rec_devices &= ~(1 << o);
-				return;
+				break;
 			}
-			/* Make the mixer control identified by o to appear as n */
 
-			if (o < 0 || o > SOUND_MIXER_NRDEVICES)
-				return;
-			if (n < 0 || n > SOUND_MIXER_NRDEVICES)
-				return;
-			if (!(devc->supported_devices & (1 << o)))
-				return;	/* Not supported */
+			/* Make the mixer control identified by o to appear as n */
+			if (n < 0 || n >= SOUND_MIXER_NRDEVICES)
+				return -EINVAL;
 
 			devc->mixer_reroute[n] = o;	/* Rename the control */
-			devc->supported_devices &= ~(1 << o);
-			devc->supported_devices |= (1 << n);
+			if (devc->supported_devices & (1 << o))
+				devc->supported_devices |= (1 << n);
 			if (devc->supported_rec_devices & (1 << o))
 				devc->supported_rec_devices |= (1 << n);
+
+			devc->supported_devices &= ~(1 << o);
 			devc->supported_rec_devices &= ~(1 << o);
 		}
 		break;
 	}
-	return;
+	return 0;
 }
 
 void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int share_dma)
@@ -1932,7 +1944,6 @@
 	}
 	else
 		printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base);
-	MOD_DEC_USE_COUNT;
 }
 
 void adintr(int irq, void *dev_id, struct pt_regs *dummy)
@@ -1965,37 +1976,22 @@
 			save_flags(flags);
 			cli();
 
-			alt_stat = 0;
-
-			if (devc->c930_password_port)
-				outb((0xe4), devc->c930_password_port);	/* Password */
+			/* 0xe0e is C930 address port
+			 * 0xe0f is C930 data port
+			 */
 			outb(11, 0xe0e);
 			c930_stat = inb(0xe0f);
+			outb((~c930_stat), 0xe0f);
 
-			if (c930_stat & 0x04)
-				alt_stat |= 0x10;	/* Playback intr */
-			if (c930_stat & 0x08)
-				alt_stat |= 0x20;	/* Playback intr */
 			restore_flags(flags);
-		} else if (devc->model != MD_1848)
-			alt_stat = ad_read(devc, 24);
-
-		/* Acknowledge the intr before proceeding */
-		if (devc->model == MD_C930)
-		{		/* 82C930 has interrupt status register in MAD16 register MC11 */
-			unsigned long   flags;
-
-			save_flags(flags);
-			cli();
 
-			if (devc->c930_password_port)
-				outb((0xe4), devc->c930_password_port);	/* Password */
-			outb((11), 0xe0e);
-			outb((~c930_stat), 0xe0f);
-			restore_flags(flags);
+			alt_stat = (c930_stat << 2) & 0x30;
 		}
 		else if (devc->model != MD_1848)
+		{
+			alt_stat = ad_read(devc, 24);
 			ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat);	/* Selective ack */
+		}
 
 		if (devc->open_mode & OPEN_READ && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
 		{
@@ -2550,11 +2546,10 @@
 
 struct address_info hw_config;
 
-
 int init_module(void)
 {
 	printk(KERN_INFO "ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-	if(io!=-1)
+	if(io != -1)
 	{
 		if(irq == -1 || dma == -1)
 		{
@@ -2581,12 +2576,5 @@
 	if(loaded)
 		unload_ms_sound(&hw_config);
 }
-
-#else
-
-void export_ad1848_syms(void)
-{
-}
-
 #endif
 #endif
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h
--- v2.1.93/linux/drivers/sound/ad1848_mixer.h	Tue Sep 30 08:46:44 1997
+++ linux/drivers/sound/ad1848_mixer.h	Wed Apr  8 17:24:48 1998
@@ -1,6 +1,6 @@
 /*
  * sound/ad1848_mixer.h
- * 
+ *
  * Definitions for the mixer of AD1848 and compatible codecs.
  */
 
@@ -77,7 +77,7 @@
  */
 
 #define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r, mute_bit)	\
-	{{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r, mute_bit}}
+	{{reg_l, pola_l, pos_l, len_l, mute_bit}, {reg_r, pola_r, pos_r, len_r, mute_bit}}
 
 static mixer_ents ad1848_mix_devices[32] = {
 MIX_ENT(SOUND_MIXER_VOLUME,	27, 1, 0, 4,	29, 1, 0, 4,  8),
@@ -88,13 +88,13 @@
 MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
 MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1,  8),
-MIX_ENT(SOUND_MIXER_CD,	 	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
 MIX_ENT(SOUND_MIXER_IMIX,	13, 1, 2, 6,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
 MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE1, 	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
 MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
 MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5,  7)
 };
@@ -108,13 +108,13 @@
 MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5,  7),
 MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1,  8),
-MIX_ENT(SOUND_MIXER_CD,	 	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+MIX_ENT(SOUND_MIXER_CD,		 2, 1, 0, 5,	 3, 1, 0, 5,  7),
 MIX_ENT(SOUND_MIXER_IMIX,	16, 1, 0, 5,	17, 1, 0, 5,  8),
 MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
 MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE1, 	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
+MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 0, 5,	 3, 1, 0, 5,  7),
 MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
 MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5,  7)
 };
@@ -125,21 +125,21 @@
  * MIC is level of mic monitoring direct to output. Same for CD, LINE, etc.
  */
 static mixer_ents c930_mix_devices[32] = {
-MIX_ENT(SOUND_MIXER_VOLUME,	22, 1, 0, 5,	23, 1, 0, 5,  7),
+MIX_ENT(SOUND_MIXER_VOLUME,	22, 1, 1, 5,	23, 1, 1, 5,  7),
 MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5,  7),
-MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6,  7),
-MIX_ENT(SOUND_MIXER_SPEAKER,	22, 1, 0, 5,	 23, 1, 0, 5,  8),
+MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 1, 4,	 5, 1, 1, 4,  7),
+MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 5,	 7, 1, 0, 5,  7),
+MIX_ENT(SOUND_MIXER_SPEAKER,	22, 1, 1, 5,	23, 1, 1, 5,  7),
 MIX_ENT(SOUND_MIXER_LINE,	18, 1, 1, 4,	19, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_MIC,	 20, 1, 0, 4,	 21, 1, 0, 4,  8),
-MIX_ENT(SOUND_MIXER_CD,	 	 2, 1, 1, 4,	 3, 1, 1, 4,  7),
-MIX_ENT(SOUND_MIXER_IMIX,	0, 0, 0, 0,	 0, 0, 0, 0,  8),
+MIX_ENT(SOUND_MIXER_MIC,	20, 1, 1, 4,	21, 1, 1, 4,  7),
+MIX_ENT(SOUND_MIXER_CD,		 2, 1, 1, 4,	 3, 1, 1, 4,  7),
+MIX_ENT(SOUND_MIXER_IMIX,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
 MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4,  8),
 MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0,  8),
-MIX_ENT(SOUND_MIXER_LINE1, 	 2, 1, 1, 4,	 3, 1, 1, 4,  7),
+MIX_ENT(SOUND_MIXER_LINE1,	 2, 1, 1, 4,	 3, 1, 1, 4,  7),
 MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 1, 4,	 5, 1, 1, 4,  7),
 MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 1, 4,	19, 1, 1, 4,  7)
 };
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c
--- v2.1.93/linux/drivers/sound/adlib_card.c	Tue Jan 20 16:44:57 1998
+++ linux/drivers/sound/adlib_card.c	Wed Apr  8 17:24:48 1998
@@ -2,19 +2,17 @@
  * sound/adlib_card.c
  *
  * Detection routine for the AdLib card.
- */
-
-/*
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
-#include <linux/config.h>
-#include <linux/module.h>
 
 
+#include <linux/config.h>
+#include <linux/module.h>
 #include "sound_config.h"
 #include "soundmodule.h"
 
@@ -28,7 +26,8 @@
 
 int probe_adlib(struct address_info *hw_config)
 {
-	if (check_region(hw_config->io_base, 4)) {
+	if (check_region(hw_config->io_base, 4)) 
+	{
 		DDB(printk("opl3.c: I/O port %x already in use\n", hw_config->io_base));
 		return 0;
 	}
@@ -46,12 +45,14 @@
 int io = -1;
 MODULE_PARM(io, "i");
 
+EXPORT_NO_SYMBOLS;
+
 struct address_info cfg;
 
 int init_module(void)
 {
 	if (io == -1) {
-		printk("adlib: must specify I/O address.\n");
+		printk(KERN_ERR "adlib: must specify I/O address.\n");
 		return -EINVAL;
 	}
 	cfg.io_base = io;
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
--- v2.1.93/linux/drivers/sound/audio.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/sound/audio.c	Wed Apr  8 17:24:48 1998
@@ -21,6 +21,7 @@
 
 #include <linux/config.h>
 #include <linux/stddef.h>
+#include <linux/kmod.h>
 
 #include "sound_config.h"
 
@@ -164,8 +165,6 @@
 	DMAbuf_release(dev, mode);
 }
 
-#if defined(NO_INLINE_ASM) || !defined(i386)
-
 static void translate_bytes(const unsigned char *table, unsigned char *buff, int n)
 {
 	unsigned long   i;
@@ -177,24 +176,6 @@
 		buff[i] = table[buff[i]];
 }
 
-#else
-extern inline void
-translate_bytes(const void *table, void *buff, int n)
-{
-	if (n > 0)
-	{
-		__asm__("cld\n"
-			"1:\tlodsb\n\t"
-			"xlatb\n\t"
-			"stosb\n\t"
-		"loop 1b\n\t":
-		:	  "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff)
-		:	  "bx", "cx", "di", "si", "ax");
-	}
-}
-
-#endif
-
 int audio_write(int dev, struct file *file, const char *buf, int count)
 {
 	int c, p, l, buf_size;
@@ -827,8 +808,10 @@
 				DMAbuf_launch_output(dev, dmap_out);
 			}
 			audio_devs[dev]->enable_bits = bits;
+#if 0
 			if (changed && audio_devs[dev]->d->trigger)
 				audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go);
+#endif				
 			restore_flags(flags);
 			/* Falls through... */
 
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c
--- v2.1.93/linux/drivers/sound/cs4232.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/sound/cs4232.c	Wed Apr  8 17:24:48 1998
@@ -301,6 +301,8 @@
 MODULE_PARM(dma,"i");
 MODULE_PARM(dma2,"i");
 
+EXPORT_NO_SYMBOLS;
+
 struct address_info cfg;
 
 /*
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c
--- v2.1.93/linux/drivers/sound/dev_table.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/sound/dev_table.c	Wed Apr  8 17:24:48 1998
@@ -18,7 +18,6 @@
 #define _DEV_TABLE_C_
 #include "sound_config.h"
 
-int sb_be_quiet = 0;
 int softoss_dev = 0;
 int sound_started = 0;
 int sndtable_get_cardcount(void);
@@ -148,6 +147,9 @@
 		}
 	}
 
+        for (i=0;i<num_audiodevs;i++)
+		DMAbuf_deinit(i);
+
 	if (trace_init)
 		printk(KERN_DEBUG "Sound unload complete\n");
 }
@@ -418,13 +420,11 @@
 		return -(EBUSY);
 	}
 	d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_driver)));
-	sound_mem_sizes[sound_nblocks] = sizeof(struct audio_driver);
 
 	if (sound_nblocks < 1024)
 		sound_nblocks++;
 
 	op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations)));
-	sound_mem_sizes[sound_nblocks] = sizeof(struct audio_operations);
 
 	if (sound_nblocks < 1024)
 		sound_nblocks++;
@@ -490,7 +490,6 @@
 	   until you unload sound! */
 	   
 	op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations)));
-	sound_mem_sizes[sound_nblocks] = sizeof(struct mixer_operations);
 
 	if (sound_nblocks < 1024)
 		sound_nblocks++;
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.1.93/linux/drivers/sound/dev_table.h	Mon Feb 23 18:12:08 1998
+++ linux/drivers/sound/dev_table.h	Wed Apr  8 17:24:48 1998
@@ -23,6 +23,7 @@
  */
 
 #define SNDCARD_DESKPROXL		27	/* Compaq Deskpro XL */
+#define SNDCARD_VIDC			28	/* ARMs VIDC */
 #define SNDCARD_SBPNP			29
 #define SNDCARD_OPL3SA1			38
 #define SNDCARD_OPL3SA1_SB		39
@@ -464,6 +465,9 @@
 #if defined(CONFIG_VMIDI) && defined(CONFIG_MIDI) && !defined(CONFIG_VMIDI_MODULE)
 	{"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device",      attach_v_midi, probe_v_midi, unload_v_midi},
 #endif
+#ifdef CONFIG_VIDC_SOUND
+	{"VIDC", 0, SNDCARD_VIDC, "ARM VIDC 16-bit D/A", attach_vidc, probe_vidc, unload_vidc },
+#endif
 	{NULL, 0, 0,		"*?*",			NULL, NULL, NULL}
 };
 
@@ -612,6 +616,9 @@
 	{SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 
+#ifdef CONFIG_VIDC_SOUND
+	{ SNDCARD_VIDC, {0, 0, 0, 0}, SND_DEFAULT_ENABLE },
+#endif
 	{0, {0}, 0}
 };
 
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v2.1.93/linux/drivers/sound/dmabuf.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/sound/dmabuf.c	Wed Apr  8 17:24:48 1998
@@ -104,7 +104,7 @@
 	dmap->raw_buf_phys = virt_to_bus(start_addr);
 
 	for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++)
-		set_bit(PG_reserved, &mem_map[i].flags);
+		set_bit(PG_reserved, &mem_map[i].flags);;
 	return 0;
 }
 
@@ -115,6 +115,8 @@
 
 	if (dmap->raw_buf == NULL)
 		return;
+	if (dmap->mapping_flags & DMA_MAP_MAPPED)
+		return;		/* Don't free mmapped buffer. Will use it next time */
 	for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1);
 
 	start_addr = (unsigned long) dmap->raw_buf;
@@ -125,8 +127,6 @@
 
 	free_pages((unsigned long) dmap->raw_buf, sz);
 	dmap->raw_buf = NULL;
-	/* Remember the buffer is deleted so we dont Oops later */
-	dmap->fragment_size = 0;
 }
 
 
@@ -206,7 +206,6 @@
 		dmap->dma_mode = DMODE_NONE;
 	dmap->flags &= ~DMA_BUSY;
 	disable_dma(dmap->dma);
-	sound_free_dmap(dmap);
 }
 
 
@@ -1210,6 +1209,20 @@
 unsigned int DMAbuf_poll(struct file * file, int dev, poll_table *wait)
 {
 	return poll_input(file, dev, wait) | poll_output(file, dev, wait);
+}
+
+void DMAbuf_deinit(int dev)
+{
+	struct audio_operations *adev = audio_devs[dev];
+	/* This routine is called when driver is being unloaded */
+	if (!adev)
+		return;
+#ifdef RUNTIME_DMA_ALLOC
+	sound_free_dmap(adev->dmap_out);
+
+	if (adev->flags & DMA_DUPLEX)
+		sound_free_dmap(adev->dmap_in);
+#endif
 }
 
 #endif
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.1.93/linux/drivers/sound/dmasound.c	Mon Dec  1 09:45:01 1997
+++ linux/drivers/sound/dmasound.c	Wed Apr  8 17:24:48 1998
@@ -3,76 +3,76 @@
 
 /*
 
-   OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k
+OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k
 
-   (c) 1995 by Michael Schlueter & Michael Marte
+(c) 1995 by Michael Schlueter & Michael Marte
 
-   Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS
-   interface and the u-law to signed byte conversion.
+Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS
+interface and the u-law to signed byte conversion.
 
-   Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue,
-   /dev/mixer, /dev/sndstat and complemented the VFS interface. He would like
-   to thank:
-   Michael Schlueter for initial ideas and documentation on the MFP and
-   the DMA sound hardware.
-   Therapy? for their CD 'Troublegum' which really made me rock.
-
-   /dev/sndstat is based on code by Hannu Savolainen, the author of the
-   VoxWare family of drivers.
-
-   This file is subject to the terms and conditions of the GNU General Public
-   License.  See the file COPYING in the main directory of this archive
-   for more details.
-
-   History:
-   1995/8/25    first release
-
-   1995/9/02    ++roman: fixed atari_stram_alloc() call, the timer programming
-   and several race conditions
-
-   1995/9/14    ++roman: After some discussion with Michael Schlueter, revised
-   the interrupt disabling
-   Slightly speeded up U8->S8 translation by using long
-   operations where possible
-   Added 4:3 interpolation for /dev/audio
-
-   1995/9/20    ++TeSche: Fixed a bug in sq_write and changed /dev/audio
-   converting to play at 12517Hz instead of 6258Hz.
-
-   1995/9/23    ++TeSche: Changed sq_interrupt() and sq_play() to pre-program
-   the DMA for another frame while there's still one
-   running. This allows the IRQ response to be
-   arbitrarily delayed and playing will still continue.
-
-   1995/10/14   ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for
-   Falcon audio (the Falcon doesn't raise an IRQ at the
-   end of a frame, but at the beginning instead!). uses
-   'if (codec_dma)' in lots of places to simply switch
-   between Falcon and TT code.
-
-   1995/11/06   ++TeSche: started introducing a hardware abstraction scheme
-   (may perhaps also serve for Amigas?), can now play
-   samples at almost all frequencies by means of a more
-   generalized expand routine, takes a good deal of care
-   to cut data only at sample sizes, buffer size is now
-   a kernel runtime option, implemented fsync() & several
-   minor improvements
-   ++Guenther: useful hints and bug fixes, cross-checked it for
-   Falcons
-
-   1996/3/9     ++geert: support added for Amiga, A-law, 16-bit little endian.
-   Unification to drivers/sound/dmasound.c.
-
-   1996/4/6     ++Martin Mitchell: updated to 1.3 kernel.
-
-   1996/6/13       ++topi: fixed things that were broken (mainly the amiga
-   14-bit routines), /dev/sndstat shows now the real
-   hardware frequency, the lowpass filter is disabled
-   by default now.
+Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue,
+/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like
+to thank:
+Michael Schlueter for initial ideas and documentation on the MFP and
+the DMA sound hardware.
+Therapy? for their CD 'Troublegum' which really made me rock.
+
+/dev/sndstat is based on code by Hannu Savolainen, the author of the
+VoxWare family of drivers.
+
+This file is subject to the terms and conditions of the GNU General Public
+License.  See the file COPYING in the main directory of this archive
+for more details.
+
+History:
+1995/8/25	first release
+
+1995/9/02	++roman: fixed atari_stram_alloc() call, the timer programming
+			and several race conditions
+
+1995/9/14	++roman: After some discussion with Michael Schlueter, revised
+			the interrupt disabling
+			Slightly speeded up U8->S8 translation by using long
+			operations where possible
+			Added 4:3 interpolation for /dev/audio
+
+1995/9/20	++TeSche: Fixed a bug in sq_write and changed /dev/audio
+			converting to play at 12517Hz instead of 6258Hz.
+
+1995/9/23	++TeSche: Changed sq_interrupt() and sq_play() to pre-program
+			the DMA for another frame while there's still one
+			running. This allows the IRQ response to be
+			arbitrarily delayed and playing will still continue.
+
+1995/10/14	++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for
+			Falcon audio (the Falcon doesn't raise an IRQ at the
+			end of a frame, but at the beginning instead!). uses
+			'if (codec_dma)' in lots of places to simply switch
+			between Falcon and TT code.
+
+1995/11/06	++TeSche: started introducing a hardware abstraction scheme
+			(may perhaps also serve for Amigas?), can now play
+			samples at almost all frequencies by means of a more
+			generalized expand routine, takes a good deal of care
+			to cut data only at sample sizes, buffer size is now
+			a kernel runtime option, implemented fsync() & several
+			minor improvements
+		++Guenther: useful hints and bug fixes, cross-checked it for
+			Falcons
+
+1996/3/9	++geert: support added for Amiga, A-law, 16-bit little endian.
+			Unification to drivers/sound/dmasound.c.
+
+1996/4/6	++Martin Mitchell: updated to 1.3 kernel.
+
+1996/6/13       ++topi: fixed things that were broken (mainly the amiga
+                        14-bit routines), /dev/sndstat shows now the real
+                        hardware frequency, the lowpass filter is disabled
+			by default now.
 
-   1996/9/25    ++geert: modularization
+1996/9/25	++geert: modularization
 
- */
+*/
 
 
 #include <linux/module.h>
@@ -94,55 +94,54 @@
 #ifdef CONFIG_ATARI
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
-#endif				/* CONFIG_ATARI */
+#include <asm/atari_stram.h>
+#endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
-#endif				/* CONFIG_AMIGA */
+#endif /* CONFIG_AMIGA */
 
 #include "dmasound.h"
 #include <linux/soundcard.h>
 
 
 #ifdef MODULE
-static int      chrdev_registered = 0;
-static int      irq_installed = 0;
-
-#endif				/* MODULE */
-static char   **sound_buffers = NULL;
+static int chrdev_registered = 0;
+static int irq_installed = 0;
+#endif /* MODULE */
+static char **sound_buffers = NULL;
 
 
 #ifdef CONFIG_ATARI
-extern void     atari_microwire_cmd(int cmd);
-
-#endif				/* CONFIG_ATARI */
+extern void atari_microwire_cmd(int cmd);
+#endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
    /*
-    * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
-    *   (Imported from arch/m68k/amiga/amisound.c)
+    *	The minimum period for audio depends on htotal (for OCS/ECS/AGA)
+    *	(Imported from arch/m68k/amiga/amisound.c)
     */
 
 extern volatile u_short amiga_audio_min_period;
 
 
    /*
-    * amiga_mksound() should be able to restore the period after beeping
-    *   (Imported from arch/m68k/amiga/amisound.c)
+    *	amiga_mksound() should be able to restore the period after beeping
+    *	(Imported from arch/m68k/amiga/amisound.c)
     */
 
-extern u_short  amiga_audio_period;
+extern u_short amiga_audio_period;
 
 
    /*
-    * Audio DMA masks
+    *	Audio DMA masks
     */
 
 #define AMI_AUDIO_OFF	(DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
 #define AMI_AUDIO_8	(DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
 #define AMI_AUDIO_14	(AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
 
-#endif				/* CONFIG_AMIGA */
+#endif /* CONFIG_AMIGA */
 
 
 /*** Some declarations *******************************************************/
@@ -157,7 +156,7 @@
 #define MIN_BUFSIZE 		4
 #define MAX_BUFSIZE		128	/* Limit for Amiga */
 
-static int      catchRadius = 0, numBufs = 4, bufSize = 32;
+static int catchRadius = 0, numBufs = 4, bufSize = 32;
 
 
 #define arraysize(x)	(sizeof(x)/sizeof(*(x)))
@@ -177,78 +176,76 @@
 
 /* 8 bit mu-law */
 
-static char     ulaw2dma8[] =
-{
-	-126, -122, -118, -114, -110, -106, -102, -98,
-	-94, -90, -86, -82, -78, -74, -70, -66,
-	-63, -61, -59, -57, -55, -53, -51, -49,
-	-47, -45, -43, -41, -39, -37, -35, -33,
-	-31, -30, -29, -28, -27, -26, -25, -24,
-	-23, -22, -21, -20, -19, -18, -17, -16,
-	-16, -15, -15, -14, -14, -13, -13, -12,
-	-12, -11, -11, -10, -10, -9, -9, -8,
-	-8, -8, -7, -7, -7, -7, -6, -6,
-	-6, -6, -5, -5, -5, -5, -4, -4,
-	-4, -4, -4, -4, -3, -3, -3, -3,
-	-3, -3, -3, -3, -2, -2, -2, -2,
-	-2, -2, -2, -2, -2, -2, -2, -2,
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, 0,
-	125, 121, 117, 113, 109, 105, 101, 97,
-	93, 89, 85, 81, 77, 73, 69, 65,
-	62, 60, 58, 56, 54, 52, 50, 48,
-	46, 44, 42, 40, 38, 36, 34, 32,
-	30, 29, 28, 27, 26, 25, 24, 23,
-	22, 21, 20, 19, 18, 17, 16, 15,
-	15, 14, 14, 13, 13, 12, 12, 11,
-	11, 10, 10, 9, 9, 8, 8, 7,
-	7, 7, 6, 6, 6, 6, 5, 5,
-	5, 5, 4, 4, 4, 4, 3, 3,
-	3, 3, 3, 3, 2, 2, 2, 2,
-	2, 2, 2, 2, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0
+static char ulaw2dma8[] = {
+    -126,   -122,   -118,   -114,   -110,   -106,   -102,    -98,
+     -94,    -90,    -86,    -82,    -78,    -74,    -70,    -66,
+     -63,    -61,    -59,    -57,    -55,    -53,    -51,    -49,
+     -47,    -45,    -43,    -41,    -39,    -37,    -35,    -33,
+     -31,    -30,    -29,    -28,    -27,    -26,    -25,    -24,
+     -23,    -22,    -21,    -20,    -19,    -18,    -17,    -16,
+     -16,    -15,    -15,    -14,    -14,    -13,    -13,    -12,
+     -12,    -11,    -11,    -10,    -10,     -9,     -9,     -8,
+      -8,     -8,     -7,     -7,     -7,     -7,     -6,     -6,
+      -6,     -6,     -5,     -5,     -5,     -5,     -4,     -4,
+      -4,     -4,     -4,     -4,     -3,     -3,     -3,     -3,
+      -3,     -3,     -3,     -3,     -2,     -2,     -2,     -2,
+      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
+      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+      -1,     -1,     -1,     -1,     -1,     -1,     -1,      0,
+     125,    121,    117,    113,    109,    105,    101,     97,
+      93,     89,     85,     81,     77,     73,     69,     65,
+      62,     60,     58,     56,     54,     52,     50,     48,
+      46,     44,     42,     40,     38,     36,     34,     32,
+      30,     29,     28,     27,     26,     25,     24,     23,
+      22,     21,     20,     19,     18,     17,     16,     15,
+      15,     14,     14,     13,     13,     12,     12,     11,
+      11,     10,     10,      9,      9,      8,      8,      7,
+       7,      7,      6,      6,      6,      6,      5,      5,
+       5,      5,      4,      4,      4,      4,      3,      3,
+       3,      3,      3,      3,      2,      2,      2,      2,
+       2,      2,      2,      2,      1,      1,      1,      1,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0
 };
 
 /* 8 bit A-law */
 
-static char     alaw2dma8[] =
-{
-	-22, -21, -24, -23, -18, -17, -20, -19,
-	-30, -29, -32, -31, -26, -25, -28, -27,
-	-11, -11, -12, -12, -9, -9, -10, -10,
-	-15, -15, -16, -16, -13, -13, -14, -14,
-	-86, -82, -94, -90, -70, -66, -78, -74,
-	-118, -114, -126, -122, -102, -98, -110, -106,
-	-43, -41, -47, -45, -35, -33, -39, -37,
-	-59, -57, -63, -61, -51, -49, -55, -53,
-	-2, -2, -2, -2, -2, -2, -2, -2,
-	-2, -2, -2, -2, -2, -2, -2, -2,
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1,
-	-6, -6, -6, -6, -5, -5, -5, -5,
-	-8, -8, -8, -8, -7, -7, -7, -7,
-	-3, -3, -3, -3, -3, -3, -3, -3,
-	-4, -4, -4, -4, -4, -4, -4, -4,
-	21, 20, 23, 22, 17, 16, 19, 18,
-	29, 28, 31, 30, 25, 24, 27, 26,
-	10, 10, 11, 11, 8, 8, 9, 9,
-	14, 14, 15, 15, 12, 12, 13, 13,
-	86, 82, 94, 90, 70, 66, 78, 74,
-	118, 114, 126, 122, 102, 98, 110, 106,
-	43, 41, 47, 45, 35, 33, 39, 37,
-	59, 57, 63, 61, 51, 49, 55, 53,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	5, 5, 5, 5, 4, 4, 4, 4,
-	7, 7, 7, 7, 6, 6, 6, 6,
-	2, 2, 2, 2, 2, 2, 2, 2,
-	3, 3, 3, 3, 3, 3, 3, 3
+static char alaw2dma8[] = {
+     -22,    -21,    -24,    -23,    -18,    -17,    -20,    -19,
+     -30,    -29,    -32,    -31,    -26,    -25,    -28,    -27,
+     -11,    -11,    -12,    -12,     -9,     -9,    -10,    -10,
+     -15,    -15,    -16,    -16,    -13,    -13,    -14,    -14,
+     -86,    -82,    -94,    -90,    -70,    -66,    -78,    -74,
+    -118,   -114,   -126,   -122,   -102,    -98,   -110,   -106,
+     -43,    -41,    -47,    -45,    -35,    -33,    -39,    -37,
+     -59,    -57,    -63,    -61,    -51,    -49,    -55,    -53,
+      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
+      -2,     -2,     -2,     -2,     -2,     -2,     -2,     -2,
+      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+      -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,
+      -6,     -6,     -6,     -6,     -5,     -5,     -5,     -5,
+      -8,     -8,     -8,     -8,     -7,     -7,     -7,     -7,
+      -3,     -3,     -3,     -3,     -3,     -3,     -3,     -3,
+      -4,     -4,     -4,     -4,     -4,     -4,     -4,     -4,
+      21,     20,     23,     22,     17,     16,     19,     18,
+      29,     28,     31,     30,     25,     24,     27,     26,
+      10,     10,     11,     11,      8,      8,      9,      9,
+      14,     14,     15,     15,     12,     12,     13,     13,
+      86,     82,     94,     90,     70,     66,     78,     74,
+     118,    114,    126,    122,    102,     98,    110,    106,
+      43,     41,     47,     45,     35,     33,     39,     37,
+      59,     57,     63,     61,     51,     49,     55,     53,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       1,      1,      1,      1,      1,      1,      1,      1,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       5,      5,      5,      5,      4,      4,      4,      4,
+       7,      7,      7,      7,      6,      6,      6,      6,
+       2,      2,      2,      2,      2,      2,      2,      2,
+       3,      3,      3,      3,      3,      3,      3,      3
 };
 
 
@@ -256,403 +253,381 @@
 
 /* 16 bit mu-law */
 
-static char     ulaw2dma16[] =
-{
-	-32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
-	-23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
-	-15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
-	-11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
-	-7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
-	-5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
-	-3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
-	-2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
-	-1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
-	-1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
-	-876, -844, -812, -780, -748, -716, -684, -652,
-	-620, -588, -556, -524, -492, -460, -428, -396,
-	-372, -356, -340, -324, -308, -292, -276, -260,
-	-244, -228, -212, -196, -180, -164, -148, -132,
-	-120, -112, -104, -96, -88, -80, -72, -64,
-	-56, -48, -40, -32, -24, -16, -8, 0,
-	32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
-	23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
-	15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
-	11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
-	7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
-	5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
-	3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
-	2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
-	1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
-	1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
-	876, 844, 812, 780, 748, 716, 684, 652,
-	620, 588, 556, 524, 492, 460, 428, 396,
-	372, 356, 340, 324, 308, 292, 276, 260,
-	244, 228, 212, 196, 180, 164, 148, 132,
-	120, 112, 104, 96, 88, 80, 72, 64,
-	56, 48, 40, 32, 24, 16, 8, 0,
+static char ulaw2dma16[] = {
+    -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
+    -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
+    -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
+    -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
+     -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
+     -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
+     -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
+     -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
+     -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
+     -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
+      -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
+      -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
+      -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
+      -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
+      -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
+       -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
+     32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
+     23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
+     15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
+     11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
+      7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
+      5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
+      3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
+      2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
+      1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
+      1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
+       876,    844,    812,    780,    748,    716,    684,    652,
+       620,    588,    556,    524,    492,    460,    428,    396,
+       372,    356,    340,    324,    308,    292,    276,    260,
+       244,    228,    212,    196,    180,    164,    148,    132,
+       120,    112,    104,     96,     88,     80,     72,     64,
+        56,     48,     40,     32,     24,     16,      8,      0,
 };
 
 /* 16 bit A-law */
 
-static char     alaw2dma16[] =
-{
-	-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-	-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
-	-2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
-	-3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
-	-22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
-	-30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
-	-11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
-	-15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
-	-344, -328, -376, -360, -280, -264, -312, -296,
-	-472, -456, -504, -488, -408, -392, -440, -424,
-	-88, -72, -120, -104, -24, -8, -56, -40,
-	-216, -200, -248, -232, -152, -136, -184, -168,
-	-1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
-	-1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
-	-688, -656, -752, -720, -560, -528, -624, -592,
-	-944, -912, -1008, -976, -816, -784, -880, -848,
-	5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
-	7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
-	2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
-	3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
-	22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
-	30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
-	11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
-	15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
-	344, 328, 376, 360, 280, 264, 312, 296,
-	472, 456, 504, 488, 408, 392, 440, 424,
-	88, 72, 120, 104, 24, 8, 56, 40,
-	216, 200, 248, 232, 152, 136, 184, 168,
-	1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
-	1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
-	688, 656, 752, 720, 560, 528, 624, 592,
-	944, 912, 1008, 976, 816, 784, 880, 848,
+static char alaw2dma16[] = {
+     -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
+     -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
+     -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
+     -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
+    -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
+    -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
+    -11008, -10496, -12032, -11520,  -8960,  -8448,  -9984,  -9472,
+    -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
+      -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
+      -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
+       -88,    -72,   -120,   -104,    -24,     -8,    -56,    -40,
+      -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
+     -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
+     -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
+      -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
+      -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848,
+      5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
+      7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
+      2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
+      3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
+     22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
+     30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
+     11008,  10496,  12032,  11520,   8960,   8448,   9984,   9472,
+     15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
+       344,    328,    376,    360,    280,    264,    312,    296,
+       472,    456,    504,    488,    408,    392,    440,    424,
+        88,     72,    120,    104,     24,      8,     56,     40,
+       216,    200,    248,    232,    152,    136,    184,    168,
+      1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
+      1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
+       688,    656,    752,    720,    560,    528,    624,    592,
+       944,    912,   1008,    976,    816,    784,    880,    848,
 };
-
-#endif				/* HAS_16BIT_TABLES */
+#endif /* HAS_16BIT_TABLES */
 
 
 #ifdef HAS_14BIT_TABLES
 
 /* 14 bit mu-law (LSB) */
 
-static char     alaw2dma14l[] =
-{
-	33, 33, 33, 33, 33, 33, 33, 33,
-	33, 33, 33, 33, 33, 33, 33, 33,
-	33, 33, 33, 33, 33, 33, 33, 33,
-	33, 33, 33, 33, 33, 33, 33, 33,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	49, 17, 49, 17, 49, 17, 49, 17,
-	49, 17, 49, 17, 49, 17, 49, 17,
-	41, 57, 9, 25, 41, 57, 9, 25,
-	41, 57, 9, 25, 41, 57, 9, 25,
-	37, 45, 53, 61, 5, 13, 21, 29,
-	37, 45, 53, 61, 5, 13, 21, 29,
-	35, 39, 43, 47, 51, 55, 59, 63,
-	3, 7, 11, 15, 19, 23, 27, 31,
-	34, 36, 38, 40, 42, 44, 46, 48,
-	50, 52, 54, 56, 58, 60, 62, 0,
-	31, 31, 31, 31, 31, 31, 31, 31,
-	31, 31, 31, 31, 31, 31, 31, 31,
-	31, 31, 31, 31, 31, 31, 31, 31,
-	31, 31, 31, 31, 31, 31, 31, 31,
-	63, 63, 63, 63, 63, 63, 63, 63,
-	63, 63, 63, 63, 63, 63, 63, 63,
-	15, 47, 15, 47, 15, 47, 15, 47,
-	15, 47, 15, 47, 15, 47, 15, 47,
-	23, 7, 55, 39, 23, 7, 55, 39,
-	23, 7, 55, 39, 23, 7, 55, 39,
-	27, 19, 11, 3, 59, 51, 43, 35,
-	27, 19, 11, 3, 59, 51, 43, 35,
-	29, 25, 21, 17, 13, 9, 5, 1,
-	61, 57, 53, 49, 45, 41, 37, 33,
-	30, 28, 26, 24, 22, 20, 18, 16,
-	14, 12, 10, 8, 6, 4, 2, 0
+static char alaw2dma14l[] = {
+        33,     33,     33,     33,     33,     33,     33,     33,
+        33,     33,     33,     33,     33,     33,     33,     33,
+        33,     33,     33,     33,     33,     33,     33,     33,
+        33,     33,     33,     33,     33,     33,     33,     33,
+         1,      1,      1,      1,      1,      1,      1,      1,
+         1,      1,      1,      1,      1,      1,      1,      1,
+        49,     17,     49,     17,     49,     17,     49,     17,
+        49,     17,     49,     17,     49,     17,     49,     17,
+        41,     57,      9,     25,     41,     57,      9,     25,
+        41,     57,      9,     25,     41,     57,      9,     25,
+        37,     45,     53,     61,      5,     13,     21,     29,
+        37,     45,     53,     61,      5,     13,     21,     29,
+        35,     39,     43,     47,     51,     55,     59,     63,
+         3,      7,     11,     15,     19,     23,     27,     31,
+        34,     36,     38,     40,     42,     44,     46,     48,
+        50,     52,     54,     56,     58,     60,     62,      0,
+        31,     31,     31,     31,     31,     31,     31,     31,
+        31,     31,     31,     31,     31,     31,     31,     31,
+        31,     31,     31,     31,     31,     31,     31,     31,
+        31,     31,     31,     31,     31,     31,     31,     31,
+        63,     63,     63,     63,     63,     63,     63,     63,
+        63,     63,     63,     63,     63,     63,     63,     63,
+        15,     47,     15,     47,     15,     47,     15,     47,
+        15,     47,     15,     47,     15,     47,     15,     47,
+        23,      7,     55,     39,     23,      7,     55,     39,
+        23,      7,     55,     39,     23,      7,     55,     39,
+        27,     19,     11,      3,     59,     51,     43,     35,
+        27,     19,     11,      3,     59,     51,     43,     35,
+        29,     25,     21,     17,     13,      9,      5,      1,
+        61,     57,     53,     49,     45,     41,     37,     33,
+        30,     28,     26,     24,     22,     20,     18,     16,
+        14,     12,     10,      8,      6,      4,      2,      0
 };
 
 /* 14 bit A-law (LSB) */
 
-static char     alaw2dma14l[] =
-{
-	32, 32, 32, 32, 32, 32, 32, 32,
-	32, 32, 32, 32, 32, 32, 32, 32,
-	16, 48, 16, 48, 16, 48, 16, 48,
-	16, 48, 16, 48, 16, 48, 16, 48,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	42, 46, 34, 38, 58, 62, 50, 54,
-	10, 14, 2, 6, 26, 30, 18, 22,
-	42, 46, 34, 38, 58, 62, 50, 54,
-	10, 14, 2, 6, 26, 30, 18, 22,
-	40, 56, 8, 24, 40, 56, 8, 24,
-	40, 56, 8, 24, 40, 56, 8, 24,
-	20, 28, 4, 12, 52, 60, 36, 44,
-	20, 28, 4, 12, 52, 60, 36, 44,
-	32, 32, 32, 32, 32, 32, 32, 32,
-	32, 32, 32, 32, 32, 32, 32, 32,
-	48, 16, 48, 16, 48, 16, 48, 16,
-	48, 16, 48, 16, 48, 16, 48, 16,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	22, 18, 30, 26, 6, 2, 14, 10,
-	54, 50, 62, 58, 38, 34, 46, 42,
-	22, 18, 30, 26, 6, 2, 14, 10,
-	54, 50, 62, 58, 38, 34, 46, 42,
-	24, 8, 56, 40, 24, 8, 56, 40,
-	24, 8, 56, 40, 24, 8, 56, 40,
-	44, 36, 60, 52, 12, 4, 28, 20,
-	44, 36, 60, 52, 12, 4, 28, 20
+static char alaw2dma14l[] = {
+        32,     32,     32,     32,     32,     32,     32,     32,
+        32,     32,     32,     32,     32,     32,     32,     32,
+        16,     48,     16,     48,     16,     48,     16,     48,
+        16,     48,     16,     48,     16,     48,     16,     48,
+         0,      0,      0,      0,      0,      0,      0,      0,
+         0,      0,      0,      0,      0,      0,      0,      0,
+         0,      0,      0,      0,      0,      0,      0,      0,
+         0,      0,      0,      0,      0,      0,      0,      0,
+        42,     46,     34,     38,     58,     62,     50,     54,
+        10,     14,      2,      6,     26,     30,     18,     22,
+        42,     46,     34,     38,     58,     62,     50,     54,
+        10,     14,      2,      6,     26,     30,     18,     22,
+        40,     56,      8,     24,     40,     56,      8,     24,
+        40,     56,      8,     24,     40,     56,      8,     24,
+        20,     28,      4,     12,     52,     60,     36,     44,
+        20,     28,      4,     12,     52,     60,     36,     44,
+        32,     32,     32,     32,     32,     32,     32,     32,
+        32,     32,     32,     32,     32,     32,     32,     32,
+        48,     16,     48,     16,     48,     16,     48,     16,
+        48,     16,     48,     16,     48,     16,     48,     16,
+         0,      0,      0,      0,      0,      0,      0,      0,
+         0,      0,      0,      0,      0,      0,      0,      0,
+         0,      0,      0,      0,      0,      0,      0,      0,
+         0,      0,      0,      0,      0,      0,      0,      0,
+        22,     18,     30,     26,      6,      2,     14,     10,
+        54,     50,     62,     58,     38,     34,     46,     42,
+        22,     18,     30,     26,      6,      2,     14,     10,
+        54,     50,     62,     58,     38,     34,     46,     42,
+        24,      8,     56,     40,     24,      8,     56,     40,
+        24,      8,     56,     40,     24,      8,     56,     40,
+        44,     36,     60,     52,     12,      4,     28,     20,
+        44,     36,     60,     52,     12,      4,     28,     20
 };
-
-#endif				/* HAS_14BIT_TABLES */
+#endif /* HAS_14BIT_TABLES */
 
 
 /*** Translations ************************************************************/
 
 
 #ifdef CONFIG_ATARI
-static long     ata_ct_law(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ct_s8(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ct_u8(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ct_s16be(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ct_u16be(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ct_s16le(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ct_u16le(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ctx_law(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ctx_s8(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ctx_u8(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ctx_s16be(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ctx_u16be(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ctx_s16le(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ata_ctx_u16le(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-
-#endif				/* CONFIG_ATARI */
+static long ata_ct_law(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ct_s8(const u_char *userPtr, unsigned long userCount,
+		      u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ct_u8(const u_char *userPtr, unsigned long userCount,
+		      u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ctx_law(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount,
+			  u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount,
+			  u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount,
+			  u_char frame[], long *frameUsed, long frameLeft);
+static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount,
+			  u_char frame[], long *frameUsed, long frameLeft);
+#endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
-static long     ami_ct_law(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ami_ct_s8(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ami_ct_u8(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ami_ct_s16be(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ami_ct_u16be(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ami_ct_s16le(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long     ami_ct_u16le(const u_char * userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-
-#endif				/* CONFIG_AMIGA */
+static long ami_ct_law(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft);
+static long ami_ct_s8(const u_char *userPtr, unsigned long userCount,
+		      u_char frame[], long *frameUsed, long frameLeft);
+static long ami_ct_u8(const u_char *userPtr, unsigned long userCount,
+		      u_char frame[], long *frameUsed, long frameLeft);
+static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft);
+#endif /* CONFIG_AMIGA */
 
 
 /*** Machine definitions *****************************************************/
 
 
-typedef struct
-  {
-	  int             type;
-	  void           *(*dma_alloc) (unsigned int, int);
-	  void            (*dma_free) (void *, unsigned int);
-	  int             (*irqinit) (void);
+typedef struct {
+    int type;
+    void *(*dma_alloc)(unsigned int, int);
+    void (*dma_free)(void *, unsigned int);
+    int (*irqinit)(void);
 #ifdef MODULE
-	  void            (*irqcleanup) (void);
-#endif				/* MODULE */
-	  void            (*init) (void);
-	  void            (*silence) (void);
-	  int             (*setFormat) (int);
-	  int             (*setVolume) (int);
-	  int             (*setBass) (int);
-	  int             (*setTreble) (int);
-	  void            (*play) (void);
-  }
-MACHINE;
+    void (*irqcleanup)(void);
+#endif /* MODULE */
+    void (*init)(void);
+    void (*silence)(void);
+    int (*setFormat)(int);
+    int (*setVolume)(int);
+    int (*setBass)(int);
+    int (*setTreble)(int);
+    int (*setGain)(int);
+    void (*play)(void);
+} MACHINE;
 
 
 /*** Low level stuff *********************************************************/
 
 
-typedef struct
-  {
-	  int             format;	/* AFMT_* */
-	  int             stereo;	/* 0 = mono, 1 = stereo */
-	  int             size;	/* 8/16 bit */
-	  int             speed;	/* speed */
-  }
-SETTINGS;
-
-typedef struct
-  {
-	  long            (*ct_ulaw) (const u_char *, unsigned long, u_char *, long *, long);
-	  long            (*ct_alaw) (const u_char *, unsigned long, u_char *, long *, long);
-	  long            (*ct_s8) (const u_char *, unsigned long, u_char *, long *, long);
-	  long            (*ct_u8) (const u_char *, unsigned long, u_char *, long *, long);
-	  long            (*ct_s16be) (const u_char *, unsigned long, u_char *, long *, long);
-	  long            (*ct_u16be) (const u_char *, unsigned long, u_char *, long *, long);
-	  long            (*ct_s16le) (const u_char *, unsigned long, u_char *, long *, long);
-	  long            (*ct_u16le) (const u_char *, unsigned long, u_char *, long *, long);
-  }
-TRANS;
-
-struct sound_settings
-  {
-	  MACHINE         mach;	/* machine dependent things */
-	  SETTINGS        hard;	/* hardware settings */
-	  SETTINGS        soft;	/* software settings */
-	  SETTINGS        dsp;	/* /dev/dsp default settings */
-	  TRANS          *trans;	/* supported translations */
-	  int             volume_left;	/* volume (range is machine dependent) */
-	  int             volume_right;
-	  int             bass;	/* tone (range is machine dependent) */
-	  int             treble;
-	  int             minDev;	/* minor device number currently open */
+typedef struct {
+    int format;		/* AFMT_* */
+    int stereo;		/* 0 = mono, 1 = stereo */
+    int size;		/* 8/16 bit*/
+    int speed;		/* speed */
+} SETTINGS;
+
+typedef struct {
+    long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long);
+    long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long);
+    long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long);
+    long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long);
+    long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long);
+    long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long);
+    long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long);
+    long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long);
+} TRANS;
+
+struct sound_settings {
+    MACHINE mach;	/* machine dependent things */
+    SETTINGS hard;	/* hardware settings */
+    SETTINGS soft;	/* software settings */
+    SETTINGS dsp;	/* /dev/dsp default settings */
+    TRANS *trans;	/* supported translations */
+    int volume_left;	/* volume (range is machine dependent) */
+    int volume_right;
+    int bass;		/* tone (range is machine dependent) */
+    int treble;
+    int gain;
+    int minDev;		/* minor device number currently open */
 #ifdef CONFIG_ATARI
-	  int             bal;	/* balance factor for expanding (not volume!) */
-	  u_long          data;	/* data for expanding */
-#endif				/* CONFIG_ATARI */
-  };
+    int bal;		/* balance factor for expanding (not volume!) */
+    u_long data;	/* data for expanding */
+#endif /* CONFIG_ATARI */
+};
 
 static struct sound_settings sound;
 
 
 #ifdef CONFIG_ATARI
-static void    *AtaAlloc(unsigned int size, int flags);
-static void     AtaFree(void *, unsigned int size);
-static int      AtaIrqInit(void);
-
+static void *AtaAlloc(unsigned int size, int flags);
+static void AtaFree(void *, unsigned int size);
+static int AtaIrqInit(void);
 #ifdef MODULE
-static void     AtaIrqCleanUp(void);
-
-#endif				/* MODULE */
-static int      AtaSetBass(int bass);
-static int      AtaSetTreble(int treble);
-static void     TTSilence(void);
-static void     TTInit(void);
-static int      TTSetFormat(int format);
-static int      TTSetVolume(int volume);
-static void     FalconSilence(void);
-static void     FalconInit(void);
-static int      FalconSetFormat(int format);
-static int      FalconSetVolume(int volume);
-static void     ata_sq_play_next_frame(int index);
-static void     AtaPlay(void);
-static void     ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
-
-#endif				/* CONFIG_ATARI */
+static void AtaIrqCleanUp(void);
+#endif /* MODULE */
+static int AtaSetBass(int bass);
+static int AtaSetTreble(int treble);
+static void TTSilence(void);
+static void TTInit(void);
+static int TTSetFormat(int format);
+static int TTSetVolume(int volume);
+static int TTSetGain(int gain);
+static void FalconSilence(void);
+static void FalconInit(void);
+static int FalconSetFormat(int format);
+static int FalconSetVolume(int volume);
+static void ata_sq_play_next_frame(int index);
+static void AtaPlay(void);
+static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
+#endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
-static void    *AmiAlloc(unsigned int size, int flags);
-static void     AmiFree(void *, unsigned int);
-static int      AmiIrqInit(void);
-
+static void *AmiAlloc(unsigned int size, int flags);
+static void AmiFree(void *, unsigned int);
+static int AmiIrqInit(void);
 #ifdef MODULE
-static void     AmiIrqCleanUp(void);
-
-#endif				/* MODULE */
-static void     AmiSilence(void);
-static void     AmiInit(void);
-static int      AmiSetFormat(int format);
-static int      AmiSetVolume(int volume);
-static int      AmiSetTreble(int treble);
-static void     ami_sq_play_next_frame(int index);
-static void     AmiPlay(void);
-static void     ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
-
-#endif				/* CONFIG_AMIGA */
+static void AmiIrqCleanUp(void);
+#endif /* MODULE */
+static void AmiSilence(void);
+static void AmiInit(void);
+static int AmiSetFormat(int format);
+static int AmiSetVolume(int volume);
+static int AmiSetTreble(int treble);
+static void ami_sq_play_next_frame(int index);
+static void AmiPlay(void);
+static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
+#endif /* CONFIG_AMIGA */
 
 
 /*** Mid level stuff *********************************************************/
 
 
-static void     sound_silence(void);
-static void     sound_init(void);
-static int      sound_set_format(int format);
-static int      sound_set_speed(int speed);
-static int      sound_set_stereo(int stereo);
-static int      sound_set_volume(int volume);
-
+static void sound_silence(void);
+static void sound_init(void);
+static int sound_set_format(int format);
+static int sound_set_speed(int speed);
+static int sound_set_stereo(int stereo);
+static int sound_set_volume(int volume);
 #ifdef CONFIG_ATARI
-static int      sound_set_bass(int bass);
-
-#endif				/* CONFIG_ATARI */
-static int      sound_set_treble(int treble);
-static long     sound_copy_translate(const u_char * userPtr,
-				     unsigned long userCount,
-				     u_char frame[], long *frameUsed,
-				     long frameLeft);
+static int sound_set_bass(int bass);
+#endif /* CONFIG_ATARI */
+static int sound_set_treble(int treble);
+static long sound_copy_translate(const u_char *userPtr,
+				 unsigned long userCount,
+				 u_char frame[], long *frameUsed,
+				 long frameLeft);
 
 
 /*
  * /dev/mixer abstraction
  */
 
-struct sound_mixer
-  {
-	  int             busy;
-  };
+struct sound_mixer {
+    int busy;
+};
 
 static struct sound_mixer mixer;
 
-static void     mixer_init(void);
-static int      mixer_open(int open_mode);
-static int      mixer_release(void);
-static int      mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
-			    u_long arg);
+static void mixer_init(void);
+static int mixer_open(int open_mode);
+static int mixer_release(void);
+static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg);
 
 
 /*
  * Sound queue stuff, the heart of the driver
  */
 
-struct sound_queue
-  {
-	  int             max_count, block_size;
-	  char          **buffers;
-
-	  /* it shouldn't be necessary to declare any of these volatile */
-	  int             front, rear, count;
-	  int             rear_size;
-	  /*
-	   *        The use of the playing field depends on the hardware
-	   *
-	   *  Atari: The number of frames that are loaded/playing
-	   *
-	   *  Amiga: Bit 0 is set: a frame is loaded
-	   *         Bit 1 is set: a frame is playing
-	   */
-	  int             playing;
-	  struct wait_queue *write_queue, *open_queue, *sync_queue;
-	  int             open_mode;
-	  int             busy, syncing;
+struct sound_queue {
+    int max_count, block_size;
+    char **buffers;
+
+    /* it shouldn't be necessary to declare any of these volatile */
+    int front, rear, count;
+    int rear_size;
+    /*
+     *	The use of the playing field depends on the hardware
+     *
+     *	Atari: The number of frames that are loaded/playing
+     *
+     *	Amiga: Bit 0 is set: a frame is loaded
+     *	       Bit 1 is set: a frame is playing
+     */
+    int playing;
+    struct wait_queue *write_queue, *open_queue, *sync_queue;
+    int open_mode;
+    int busy, syncing;
 #ifdef CONFIG_ATARI
-	  int             ignore_int;	/* ++TeSche: used for Falcon */
-#endif				/* CONFIG_ATARI */
+    int ignore_int;		/* ++TeSche: used for Falcon */
+#endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-	  int             block_size_half, block_size_quarter;
-#endif				/* CONFIG_AMIGA */
-  };
+    int block_size_half, block_size_quarter;
+#endif /* CONFIG_AMIGA */
+};
 
 static struct sound_queue sq;
 
@@ -666,72 +641,69 @@
 	interruptible_sleep_on(&queue);
 #define WAKE_UP(queue)	(wake_up_interruptible(&queue))
 
-static void     sq_init(int numBufs, int bufSize, char **buffers);
-static void     sq_play(void);
-static long     sq_write(const char *src, unsigned long uLeft);
-static int      sq_open(int open_mode);
-static void     sq_reset(void);
-static int      sq_sync(void);
-static int      sq_release(void);
+static void sq_init(int numBufs, int bufSize, char **buffers);
+static void sq_play(void);
+static long sq_write(const char *src, unsigned long uLeft);
+static int sq_open(int open_mode);
+static void sq_reset(void);
+static int sq_sync(void);
+static int sq_release(void);
 
 
 /*
  * /dev/sndstat
  */
 
-struct sound_state
-  {
-	  int             busy;
-	  char            buf[512];
-	  int             len, ptr;
-  };
+struct sound_state {
+    int busy;
+    char buf[512];
+    int len, ptr;
+};
 
 static struct sound_state state;
 
-static void     state_init(void);
-static int      state_open(int open_mode);
-static int      state_release(void);
-static long     state_read(char *dest, unsigned long count);
+static void state_init(void);
+static int state_open(int open_mode);
+static int state_release(void);
+static long state_read(char *dest, unsigned long count);
 
 
 /*** High level stuff ********************************************************/
 
 
-static int      sound_open(struct inode *inode, struct file *file);
-static int      sound_fsync(struct inode *inode, struct file *filp);
-static void     sound_release(struct inode *inode, struct file *file);
-static long long sound_lseek(struct inode *inode, struct file *file,
-			     long long offset, int orig);
-static long     sound_read(struct inode *inode, struct file *file, char *buf,
-			   unsigned long count);
-static long     sound_write(struct inode *inode, struct file *file,
-			    const char *buf, unsigned long count);
-static inline int
-ioctl_return(int *addr, int value)
-{
-	if (value < 0)
-		return (value);
-
-	return put_user(value, addr);
-}
-static int      unknown_minor_dev(char *fname, int dev);
-static int      sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
-			    u_long arg);
+static int sound_open(struct inode *inode, struct file *file);
+static int sound_fsync(struct file *filp, struct dentry *dentry);
+static int sound_release(struct inode *inode, struct file *file);
+static long long sound_lseek(struct file *file, long long offset, int orig);
+static ssize_t sound_read(struct file *file, char *buf, size_t count,
+			  loff_t *ppos);
+static ssize_t sound_write(struct file *file, const char *buf, size_t count,
+			   loff_t *ppos);
+static inline int ioctl_return(int *addr, int value)
+{
+    if (value < 0)
+	return(value);
+
+    return put_user(value, addr);
+}
+static int unknown_minor_dev(char *fname, int dev);
+static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg);
 
 
 /*** Config & Setup **********************************************************/
 
 
-void            soundcard_init(void);
-void            dmasound_setup(char *str, int *ints);
-void            sound_setup(char *str, int *ints);	/* ++Martin: stub for now */
+void soundcard_init(void);
+void dmasound_setup(char *str, int *ints);
+void sound_setup(char *str, int *ints);		/* ++Martin: stub for now */
 
 
 /*** Translations ************************************************************/
 
 
 /* ++TeSche: radically changed for new expanding purposes...
-
+ *
  * These two routines now deal with copying/expanding/translating the samples
  * from user space into our buffer at the right frequency. They take care about
  * how much data there's actually to read, how much buffer space there is and
@@ -755,1014 +727,849 @@
  */
 
 #ifdef CONFIG_ATARI
-static long
-ata_ct_law(const u_char * userPtr, unsigned long userCount,
-	   u_char frame[], long *frameUsed, long frameLeft)
-{
-	char           *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-	long            count, used;
-	u_char         *p = &frame[*frameUsed];
-
-	count = min(userCount, frameLeft);
-	if (sound.soft.stereo)
-		count &= ~1;
-	used = count;
-	while (count > 0)
-	  {
-		  u_char          data;
-
-		  get_user(data, userPtr++);
-		  *p++ = table[data];
-		  count--;
-	  }
-	*frameUsed += used;
-	return (used);
-}
-
-
-static long
-ata_ct_s8(const u_char * userPtr, unsigned long userCount,
-	  u_char frame[], long *frameUsed, long frameLeft)
+static long ata_ct_law(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft)
 {
-	long            count, used;
-	void           *p = &frame[*frameUsed];
+    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+    long count, used;
+    u_char *p = &frame[*frameUsed];
 
-	count = min(userCount, frameLeft);
-	if (sound.soft.stereo)
-		count &= ~1;
-	used = count;
-	copy_from_user(p, userPtr, count);
-	*frameUsed += used;
-	return (used);
+    count = min(userCount, frameLeft);
+    if (sound.soft.stereo)
+	count &= ~1;
+    used = count;
+    while (count > 0) {
+	u_char data;
+	get_user(data, userPtr++);
+	*p++ = table[data];
+	count--;
+    }
+    *frameUsed += used;
+    return(used);
 }
 
 
-static long
-ata_ct_u8(const u_char * userPtr, unsigned long userCount,
-	  u_char frame[], long *frameUsed, long frameLeft)
+static long ata_ct_s8(const u_char *userPtr, unsigned long userCount,
+		      u_char frame[], long *frameUsed, long frameLeft)
 {
-	long            count, used;
-
-	if (!sound.soft.stereo)
-	  {
-		  u_char         *p = &frame[*frameUsed];
-
-		  count = min(userCount, frameLeft);
-		  used = count;
-		  while (count > 0)
-		    {
-			    u_char          data;
+    long count, used;
+    void *p = &frame[*frameUsed];
 
-			    get_user(data, userPtr++);
-			    *p++ = data ^ 0x80;
-			    count--;
-		    }
-	} else
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  count = min(userCount, frameLeft) >> 1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    u_short         data;
-
-			    get_user(data, ((u_short *) userPtr)++);
-			    *p++ = data ^ 0x8080;
-			    count--;
-		    }
-	  }
-	*frameUsed += used;
-	return (used);
+    count = min(userCount, frameLeft);
+    if (sound.soft.stereo)
+	count &= ~1;
+    used = count;
+    copy_from_user(p, userPtr, count);
+    *frameUsed += used;
+    return(used);
 }
 
 
-static long
-ata_ct_s16be(const u_char * userPtr, unsigned long userCount,
-	     u_char frame[], long *frameUsed, long frameLeft)
+static long ata_ct_u8(const u_char *userPtr, unsigned long userCount,
+		      u_char frame[], long *frameUsed, long frameLeft)
 {
-	long            count, used;
-	u_long          data;
+    long count, used;
 
-	if (!sound.soft.stereo)
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
+    if (!sound.soft.stereo) {
+	u_char *p = &frame[*frameUsed];
+	count = min(userCount, frameLeft);
+	used = count;
+	while (count > 0) {
+	    u_char data;
+	    get_user(data, userPtr++);
+	    *p++ = data ^ 0x80;
+	    count--;
+	}
+    } else {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>1;
+	used = count*2;
+	while (count > 0) {
+	    u_short data;
+	    get_user(data, ((u_short *)userPtr)++);
+	    *p++ = data ^ 0x8080;
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
+}
 
-		  count = min(userCount, frameLeft) >> 1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    *p++ = data;
-			    *p++ = data;
-			    count--;
-		    }
-		  *frameUsed += used * 2;
-	} else
-	  {
-		  void           *p = (u_short *) & frame[*frameUsed];
 
-		  count = min(userCount, frameLeft) & ~3;
-		  used = count;
-		  copy_from_user(p, userPtr, count);
-		  *frameUsed += used;
-	  }
-	return (used);
+static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>1;
+	used = count*2;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    *p++ = data;
+	    *p++ = data;
+	    count--;
+	}
+	*frameUsed += used*2;
+    } else {
+	void *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft) & ~3;
+	used = count;
+	copy_from_user(p, userPtr, count);
+	*frameUsed += used;
+    }
+    return(used);
 }
 
 
-static long
-ata_ct_u16be(const u_char * userPtr, unsigned long userCount,
-	     u_char frame[], long *frameUsed, long frameLeft)
+static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
 {
-	long            count, used;
-	u_long          data;
-
-	if (!sound.soft.stereo)
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  count = min(userCount, frameLeft) >> 1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    data ^= 0x8000;
-			    *p++ = data;
-			    *p++ = data;
-			    count--;
-		    }
-		  *frameUsed += used * 2;
-	} else
-	  {
-		  u_long         *p = (u_long *) & frame[*frameUsed];
-
-		  count = min(userCount, frameLeft) >> 2;
-		  used = count * 4;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_int *) userPtr)++);
-			    *p++ = data ^ 0x80008000;
-			    count--;
-		    }
-		  *frameUsed += used;
-	  }
-	return (used);
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>1;
+	used = count*2;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    data ^= 0x8000;
+	    *p++ = data;
+	    *p++ = data;
+	    count--;
+	}
+	*frameUsed += used*2;
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>2;
+	used = count*4;
+	while (count > 0) {
+	    get_user(data, ((u_int *)userPtr)++);
+	    *p++ = data ^ 0x80008000;
+	    count--;
+	}
+	*frameUsed += used;
+    }
+    return(used);
 }
 
 
-static long
-ata_ct_s16le(const u_char * userPtr, unsigned long userCount,
-	     u_char frame[], long *frameUsed, long frameLeft)
+static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
 {
-	long            count, used;
-	u_long          data;
-
-	count = frameLeft;
-	if (!sound.soft.stereo)
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  count = min(userCount, frameLeft) >> 1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    data = le2be16(data);
-			    *p++ = data;
-			    *p++ = data;
-			    count--;
-		    }
-		  *frameUsed += used * 2;
-	} else
-	  {
-		  u_long         *p = (u_long *) & frame[*frameUsed];
-
-		  count = min(userCount, frameLeft) >> 2;
-		  used = count * 4;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_int *) userPtr)++);
-			    data = le2be16dbl(data);
-			    *p++ = data;
-			    count--;
-		    }
-		  *frameUsed += used;
-	  }
-	return (used);
+    long count, used;
+    u_long data;
+
+    count = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>1;
+	used = count*2;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    data = le2be16(data);
+	    *p++ = data;
+	    *p++ = data;
+	    count--;
+	}
+	*frameUsed += used*2;
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>2;
+	used = count*4;
+	while (count > 0) {
+	    get_user(data, ((u_int *)userPtr)++);
+	    data = le2be16dbl(data);
+	    *p++ = data;
+	    count--;
+	}
+	*frameUsed += used;
+    }
+    return(used);
 }
 
 
-static long
-ata_ct_u16le(const u_char * userPtr, unsigned long userCount,
-	     u_char frame[], long *frameUsed, long frameLeft)
+static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
 {
-	long            count, used;
-	u_long          data;
-
-	count = frameLeft;
-	if (!sound.soft.stereo)
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  count = min(userCount, frameLeft) >> 1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    data = le2be16(data) ^ 0x8000;
-			    *p++ = data;
-			    *p++ = data;
-		    }
-		  *frameUsed += used * 2;
-	} else
-	  {
-		  u_long         *p = (u_long *) & frame[*frameUsed];
-
-		  count = min(userCount, frameLeft) >> 2;
-		  used = count;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_int *) userPtr)++);
-			    data = le2be16dbl(data) ^ 0x80008000;
-			    *p++ = data;
-			    count--;
-		    }
-		  *frameUsed += used;
-	  }
-	return (used);
+    long count, used;
+    u_long data;
+
+    count = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>1;
+	used = count*2;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    data = le2be16(data) ^ 0x8000;
+	    *p++ = data;
+	    *p++ = data;
+	}
+	*frameUsed += used*2;
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	count = min(userCount, frameLeft)>>2;
+	used = count;
+	while (count > 0) {
+	    get_user(data, ((u_int *)userPtr)++);
+	    data = le2be16dbl(data) ^ 0x80008000;
+	    *p++ = data;
+	    count--;
+	}
+	*frameUsed += used;
+    }
+    return(used);
 }
 
 
-static long
-ata_ctx_law(const u_char * userPtr, unsigned long userCount,
-	    u_char frame[], long *frameUsed, long frameLeft)
+static long ata_ctx_law(const u_char *userPtr, unsigned long userCount,
+			u_char frame[], long *frameUsed, long frameLeft)
 {
-	char           *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-
-	/* this should help gcc to stuff everything into registers */
-	u_long          data = sound.data;
-	long            bal = sound.bal;
-	long            hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long            used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo)
-	  {
-		  u_char         *p = &frame[*frameUsed];
-
-		  while (frameLeft)
-		    {
-			    u_char          c;
-
-			    if (bal < 0)
-			      {
-				      if (!userCount)
-					      break;
-				      get_user(c, userPtr++);
-				      data = table[c];
-				      userCount--;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    frameLeft--;
-			    bal -= sSpeed;
-		    }
-	} else
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  while (frameLeft >= 2)
-		    {
-			    u_char          c;
-
-			    if (bal < 0)
-			      {
-				      if (userCount < 2)
-					      break;
-				      get_user(c, userPtr++);
-				      data = table[c] << 8;
-				      get_user(c, userPtr++);
-				      data |= table[c];
-				      userCount -= 2;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    frameLeft -= 2;
-			    bal -= sSpeed;
-		    }
-	  }
-	sound.bal = bal;
-	sound.data = data;
-	used -= userCount;
-	*frameUsed += usedf - frameLeft;
-	return (used);
+    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_char *p = &frame[*frameUsed];
+	while (frameLeft) {
+	    u_char c;
+	    if (bal < 0) {
+		if (!userCount)
+		    break;
+		get_user(c, userPtr++);
+		data = table[c];
+		userCount--;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft--;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 2) {
+	    u_char c;
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		get_user(c, userPtr++);
+		data = table[c] << 8;
+		get_user(c, userPtr++);
+		data |= table[c];
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 2;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
 }
 
 
-static long
-ata_ctx_s8(const u_char * userPtr, unsigned long userCount,
-	   u_char frame[], long *frameUsed, long frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	u_long          data = sound.data;
-	long            bal = sound.bal;
-	long            hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long            used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo)
-	  {
-		  u_char         *p = &frame[*frameUsed];
-
-		  while (frameLeft)
-		    {
-			    if (bal < 0)
-			      {
-				      if (!userCount)
-					      break;
-				      get_user(data, userPtr++);
-				      userCount--;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    frameLeft--;
-			    bal -= sSpeed;
-		    }
-	} else
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  while (frameLeft >= 2)
-		    {
-			    if (bal < 0)
-			      {
-				      if (userCount < 2)
-					      break;
-				      get_user(data, ((u_short *) userPtr)++);
-				      userCount -= 2;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    frameLeft -= 2;
-			    bal -= sSpeed;
-		    }
-	  }
-	sound.bal = bal;
-	sound.data = data;
-	used -= userCount;
-	*frameUsed += usedf - frameLeft;
-	return (used);
+static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_char *p = &frame[*frameUsed];
+	while (frameLeft) {
+	    if (bal < 0) {
+		if (!userCount)
+		    break;
+		get_user(data, userPtr++);
+		userCount--;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft--;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 2) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		get_user(data, ((u_short *)userPtr)++);
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 2;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
 }
 
 
-static long
-ata_ctx_u8(const u_char * userPtr, unsigned long userCount,
-	   u_char frame[], long *frameUsed, long frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	u_long          data = sound.data;
-	long            bal = sound.bal;
-	long            hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long            used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo)
-	  {
-		  u_char         *p = &frame[*frameUsed];
-
-		  while (frameLeft)
-		    {
-			    if (bal < 0)
-			      {
-				      if (!userCount)
-					      break;
-				      get_user(data, userPtr++);
-				      data ^= 0x80;
-				      userCount--;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    frameLeft--;
-			    bal -= sSpeed;
-		    }
-	} else
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  while (frameLeft >= 2)
-		    {
-			    if (bal < 0)
-			      {
-				      if (userCount < 2)
-					      break;
-				      get_user(data, ((u_short *) userPtr)++);
-				      data ^= 0x8080;
-				      userCount -= 2;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    frameLeft -= 2;
-			    bal -= sSpeed;
-		    }
-	  }
-	sound.bal = bal;
-	sound.data = data;
-	used -= userCount;
-	*frameUsed += usedf - frameLeft;
-	return (used);
+static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_char *p = &frame[*frameUsed];
+	while (frameLeft) {
+	    if (bal < 0) {
+		if (!userCount)
+		    break;
+		get_user(data, userPtr++);
+		data ^= 0x80;
+		userCount--;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft--;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 2) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		get_user(data, ((u_short *)userPtr)++);
+		data ^= 0x8080;
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 2;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
 }
 
 
-static long
-ata_ctx_s16be(const u_char * userPtr, unsigned long userCount,
-	      u_char frame[], long *frameUsed, long frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	u_long          data = sound.data;
-	long            bal = sound.bal;
-	long            hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long            used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo)
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  while (frameLeft >= 4)
-		    {
-			    if (bal < 0)
-			      {
-				      if (userCount < 2)
-					      break;
-				      get_user(data, ((u_short *) userPtr)++);
-				      userCount -= 2;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    *p++ = data;
-			    frameLeft -= 4;
-			    bal -= sSpeed;
-		    }
-	} else
-	  {
-		  u_long         *p = (u_long *) & frame[*frameUsed];
-
-		  while (frameLeft >= 4)
-		    {
-			    if (bal < 0)
-			      {
-				      if (userCount < 4)
-					      break;
-				      get_user(data, ((u_int *) userPtr)++);
-				      userCount -= 4;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    frameLeft -= 4;
-			    bal -= sSpeed;
-		    }
-	  }
-	sound.bal = bal;
-	sound.data = data;
-	used -= userCount;
-	*frameUsed += usedf - frameLeft;
-	return (used);
+static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount,
+			  u_char frame[], long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		get_user(data, ((u_short *)userPtr)++);
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 4)
+		    break;
+		get_user(data, ((u_int *)userPtr)++);
+		userCount -= 4;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
 }
 
 
-static long
-ata_ctx_u16be(const u_char * userPtr, unsigned long userCount,
-	      u_char frame[], long *frameUsed, long frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	u_long          data = sound.data;
-	long            bal = sound.bal;
-	long            hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long            used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo)
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  while (frameLeft >= 4)
-		    {
-			    if (bal < 0)
-			      {
-				      if (userCount < 2)
-					      break;
-				      get_user(data, ((u_short *) userPtr)++);
-				      data ^= 0x8000;
-				      userCount -= 2;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    *p++ = data;
-			    frameLeft -= 4;
-			    bal -= sSpeed;
-		    }
-	} else
-	  {
-		  u_long         *p = (u_long *) & frame[*frameUsed];
-
-		  while (frameLeft >= 4)
-		    {
-			    if (bal < 0)
-			      {
-				      if (userCount < 4)
-					      break;
-				      get_user(data, ((u_int *) userPtr)++);
-				      data ^= 0x80008000;
-				      userCount -= 4;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    frameLeft -= 4;
-			    bal -= sSpeed;
-		    }
-	  }
-	sound.bal = bal;
-	sound.data = data;
-	used -= userCount;
-	*frameUsed += usedf - frameLeft;
-	return (used);
+static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount,
+			  u_char frame[], long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		get_user(data, ((u_short *)userPtr)++);
+		data ^= 0x8000;
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 4)
+		    break;
+		get_user(data, ((u_int *)userPtr)++);
+		data ^= 0x80008000;
+		userCount -= 4;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
 }
 
 
-static long
-ata_ctx_s16le(const u_char * userPtr, unsigned long userCount,
-	      u_char frame[], long *frameUsed, long frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	u_long          data = sound.data;
-	long            bal = sound.bal;
-	long            hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long            used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo)
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  while (frameLeft >= 4)
-		    {
-			    if (bal < 0)
-			      {
-				      if (userCount < 2)
-					      break;
-				      get_user(data, ((u_short *) userPtr)++);
-				      data = le2be16(data);
-				      userCount -= 2;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    *p++ = data;
-			    frameLeft -= 4;
-			    bal -= sSpeed;
-		    }
-	} else
-	  {
-		  u_long         *p = (u_long *) & frame[*frameUsed];
-
-		  while (frameLeft >= 4)
-		    {
-			    if (bal < 0)
-			      {
-				      if (userCount < 4)
-					      break;
-				      get_user(data, ((u_int *) userPtr)++);
-				      data = le2be16dbl(data);
-				      userCount -= 4;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    frameLeft -= 4;
-			    bal -= sSpeed;
-		    }
-	  }
-	sound.bal = bal;
-	sound.data = data;
-	used -= userCount;
-	*frameUsed += usedf - frameLeft;
-	return (used);
+static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount,
+			  u_char frame[], long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		get_user(data, ((u_short *)userPtr)++);
+		data = le2be16(data);
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 4)
+		    break;
+		get_user(data, ((u_int *)userPtr)++);
+		data = le2be16dbl(data);
+		userCount -= 4;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
 }
 
 
-static long
-ata_ctx_u16le(const u_char * userPtr, unsigned long userCount,
-	      u_char frame[], long *frameUsed, long frameLeft)
-{
-	/* this should help gcc to stuff everything into registers */
-	u_long          data = sound.data;
-	long            bal = sound.bal;
-	long            hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long            used, usedf;
-
-	used = userCount;
-	usedf = frameLeft;
-	if (!sound.soft.stereo)
-	  {
-		  u_short        *p = (u_short *) & frame[*frameUsed];
-
-		  while (frameLeft >= 4)
-		    {
-			    if (bal < 0)
-			      {
-				      if (userCount < 2)
-					      break;
-				      get_user(data, ((u_short *) userPtr)++);
-				      data = le2be16(data) ^ 0x8000;
-				      userCount -= 2;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    *p++ = data;
-			    frameLeft -= 4;
-			    bal -= sSpeed;
-		    }
-	} else
-	  {
-		  u_long         *p = (u_long *) & frame[*frameUsed];
-
-		  while (frameLeft >= 4)
-		    {
-			    if (bal < 0)
-			      {
-				      if (userCount < 4)
-					      break;
-				      get_user(data, ((u_int *) userPtr)++);
-				      data = le2be16dbl(data) ^ 0x80008000;
-				      userCount -= 4;
-				      bal += hSpeed;
-			      }
-			    *p++ = data;
-			    frameLeft -= 4;
-			    bal -= sSpeed;
-		    }
-	  }
-	sound.bal = bal;
-	sound.data = data;
-	used -= userCount;
-	*frameUsed += usedf - frameLeft;
-	return (used);
+static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount,
+			  u_char frame[], long *frameUsed, long frameLeft)
+{
+    /* this should help gcc to stuff everything into registers */
+    u_long data = sound.data;
+    long bal = sound.bal;
+    long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+    long used, usedf;
+
+    used = userCount;
+    usedf = frameLeft;
+    if (!sound.soft.stereo) {
+	u_short *p = (u_short *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 2)
+		    break;
+		get_user(data, ((u_short *)userPtr)++);
+		data = le2be16(data) ^ 0x8000;
+		userCount -= 2;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    } else {
+	u_long *p = (u_long *)&frame[*frameUsed];
+	while (frameLeft >= 4) {
+	    if (bal < 0) {
+		if (userCount < 4)
+		    break;
+		get_user(data, ((u_int *)userPtr)++);
+		data = le2be16dbl(data) ^ 0x80008000;
+		userCount -= 4;
+		bal += hSpeed;
+	    }
+	    *p++ = data;
+	    frameLeft -= 4;
+	    bal -= sSpeed;
+	}
+    }
+    sound.bal = bal;
+    sound.data = data;
+    used -= userCount;
+    *frameUsed += usedf-frameLeft;
+    return(used);
 }
-#endif				/* CONFIG_ATARI */
+#endif /* CONFIG_ATARI */
 
 
 #ifdef CONFIG_AMIGA
-static long
-ami_ct_law(const u_char * userPtr, unsigned long userCount,
-	   u_char frame[], long *frameUsed, long frameLeft)
-{
-	char           *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-	long            count, used;
-
-	if (!sound.soft.stereo)
-	  {
-		  u_char         *p = &frame[*frameUsed];
-
-		  count = min(userCount, frameLeft) & ~1;
-		  used = count;
-		  while (count > 0)
-		    {
-			    u_char          data;
-
-			    get_user(data, userPtr++);
-			    *p++ = table[data];
-			    count--;
-		    }
-	} else
-	  {
-		  u_char         *left = &frame[*frameUsed >> 1];
-		  u_char         *right = left + sq.block_size_half;
-
-		  count = min(userCount, frameLeft) >> 1 & ~1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    u_char          data;
-
-			    get_user(data, userPtr++);
-			    *left++ = table[data];
-			    get_user(data, userPtr++);
-			    *right++ = table[data];
-			    count--;
-		    }
-	  }
-	*frameUsed += used;
-	return (used);
-}
-
-
-static long
-ami_ct_s8(const u_char * userPtr, unsigned long userCount,
-	  u_char frame[], long *frameUsed, long frameLeft)
+static long ami_ct_law(const u_char *userPtr, unsigned long userCount,
+		       u_char frame[], long *frameUsed, long frameLeft)
 {
-	long            count, used;
-
-	if (!sound.soft.stereo)
-	  {
-		  void           *p = &frame[*frameUsed];
+    char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+    long count, used;
 
-		  count = min(userCount, frameLeft) & ~1;
-		  used = count;
-		  copy_from_user(p, userPtr, count);
-	} else
-	  {
-		  u_char         *left = &frame[*frameUsed >> 1];
-		  u_char         *right = left + sq.block_size_half;
-
-		  count = min(userCount, frameLeft) >> 1 & ~1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    get_user(*left++, userPtr++);
-			    get_user(*right++, userPtr++);
-			    count--;
-		    }
-	  }
-	*frameUsed += used;
-	return (used);
+    if (!sound.soft.stereo) {
+	u_char *p = &frame[*frameUsed];
+	count = min(userCount, frameLeft) & ~1;
+	used = count;
+	while (count > 0) {
+	    u_char data;
+	    get_user(data, userPtr++);
+	    *p++ = table[data];
+	    count--;
+	}
+    } else {
+	u_char *left = &frame[*frameUsed>>1];
+	u_char *right = left+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    u_char data;
+	    get_user(data, userPtr++);
+	    *left++ = table[data];
+	    get_user(data, userPtr++);
+	    *right++ = table[data];
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
 }
 
 
-static long
-ami_ct_u8(const u_char * userPtr, unsigned long userCount,
-	  u_char frame[], long *frameUsed, long frameLeft)
+static long ami_ct_s8(const u_char *userPtr, unsigned long userCount,
+		      u_char frame[], long *frameUsed, long frameLeft)
 {
-	long            count, used;
-
-	if (!sound.soft.stereo)
-	  {
-		  char           *p = &frame[*frameUsed];
-
-		  count = min(userCount, frameLeft) & ~1;
-		  used = count;
-		  while (count > 0)
-		    {
-			    u_char          data;
+    long count, used;
 
-			    get_user(data, userPtr++);
-			    *p++ = data ^ 0x80;
-			    count--;
-		    }
-	} else
-	  {
-		  u_char         *left = &frame[*frameUsed >> 1];
-		  u_char         *right = left + sq.block_size_half;
-
-		  count = min(userCount, frameLeft) >> 1 & ~1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    u_char          data;
-
-			    get_user(data, userPtr++);
-			    *left++ = data ^ 0x80;
-			    get_user(data, userPtr++);
-			    *right++ = data ^ 0x80;
-			    count--;
-		    }
-	  }
-	*frameUsed += used;
-	return (used);
+    if (!sound.soft.stereo) {
+	void *p = &frame[*frameUsed];
+	count = min(userCount, frameLeft) & ~1;
+	used = count;
+	copy_from_user(p, userPtr, count);
+    } else {
+	u_char *left = &frame[*frameUsed>>1];
+	u_char *right = left+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    get_user(*left++, userPtr++);
+	    get_user(*right++, userPtr++);
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
 }
 
 
-static long
-ami_ct_s16be(const u_char * userPtr, unsigned long userCount,
-	     u_char frame[], long *frameUsed, long frameLeft)
+static long ami_ct_u8(const u_char *userPtr, unsigned long userCount,
+		      u_char frame[], long *frameUsed, long frameLeft)
 {
-	long            count, used;
-	u_long          data;
-
-	if (!sound.soft.stereo)
-	  {
-		  u_char         *high = &frame[*frameUsed >> 1];
-		  u_char         *low = high + sq.block_size_half;
+    long count, used;
 
-		  count = min(userCount, frameLeft) >> 1 & ~1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    *high++ = data >> 8;
-			    *low++ = (data >> 2) & 0x3f;
-			    count--;
-		    }
-	} else
-	  {
-		  u_char         *lefth = &frame[*frameUsed >> 2];
-		  u_char         *leftl = lefth + sq.block_size_quarter;
-		  u_char         *righth = lefth + sq.block_size_half;
-		  u_char         *rightl = righth + sq.block_size_quarter;
-
-		  count = min(userCount, frameLeft) >> 2 & ~1;
-		  used = count * 4;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    *lefth++ = data >> 8;
-			    *leftl++ = (data >> 2) & 0x3f;
-			    get_user(data, ((u_short *) userPtr)++);
-			    *righth++ = data >> 8;
-			    *rightl++ = (data >> 2) & 0x3f;
-			    count--;
-		    }
-	  }
-	*frameUsed += used;
-	return (used);
+    if (!sound.soft.stereo) {
+	char *p = &frame[*frameUsed];
+	count = min(userCount, frameLeft) & ~1;
+	used = count;
+	while (count > 0) {
+	    u_char data;
+	    get_user(data, userPtr++);
+	    *p++ = data ^ 0x80;
+	    count--;
+	}
+    } else {
+	u_char *left = &frame[*frameUsed>>1];
+	u_char *right = left+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    u_char data;
+	    get_user(data, userPtr++);
+	    *left++ = data ^ 0x80;
+	    get_user(data, userPtr++);
+	    *right++ = data ^ 0x80;
+	    count--;
+        }
+    }
+    *frameUsed += used;
+    return(used);
 }
 
 
-static long
-ami_ct_u16be(const u_char * userPtr, unsigned long userCount,
-	     u_char frame[], long *frameUsed, long frameLeft)
-{
-	long            count, used;
-	u_long          data;
-
-	if (!sound.soft.stereo)
-	  {
-		  u_char         *high = &frame[*frameUsed >> 1];
-		  u_char         *low = high + sq.block_size_half;
-
-		  count = min(userCount, frameLeft) >> 1 & ~1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    data ^= 0x8000;
-			    *high++ = data >> 8;
-			    *low++ = (data >> 2) & 0x3f;
-			    count--;
-		    }
-	} else
-	  {
-		  u_char         *lefth = &frame[*frameUsed >> 2];
-		  u_char         *leftl = lefth + sq.block_size_quarter;
-		  u_char         *righth = lefth + sq.block_size_half;
-		  u_char         *rightl = righth + sq.block_size_quarter;
-
-		  count = min(userCount, frameLeft) >> 2 & ~1;
-		  used = count * 4;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    data ^= 0x8000;
-			    *lefth++ = data >> 8;
-			    *leftl++ = (data >> 2) & 0x3f;
-			    get_user(data, ((u_short *) userPtr)++);
-			    data ^= 0x8000;
-			    *righth++ = data >> 8;
-			    *rightl++ = (data >> 2) & 0x3f;
-			    count--;
-		    }
-	  }
-	*frameUsed += used;
-	return (used);
+static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_char *high = &frame[*frameUsed>>1];
+	u_char *low = high+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    *high++ = data>>8;
+	    *low++ = (data>>2) & 0x3f;
+	    count--;
+	}
+    } else {
+	u_char *lefth = &frame[*frameUsed>>2];
+	u_char *leftl = lefth+sq.block_size_quarter;
+	u_char *righth = lefth+sq.block_size_half;
+	u_char *rightl = righth+sq.block_size_quarter;
+	count = min(userCount, frameLeft)>>2 & ~1;
+	used = count*4;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    *lefth++ = data>>8;
+	    *leftl++ = (data>>2) & 0x3f;
+	    get_user(data, ((u_short *)userPtr)++);
+	    *righth++ = data>>8;
+	    *rightl++ = (data>>2) & 0x3f;
+	    count--;
+       }
+    }
+    *frameUsed += used;
+    return(used);
 }
 
 
-static long
-ami_ct_s16le(const u_char * userPtr, unsigned long userCount,
-	     u_char frame[], long *frameUsed, long frameLeft)
-{
-	long            count, used;
-	u_long          data;
-
-	if (!sound.soft.stereo)
-	  {
-		  u_char         *high = &frame[*frameUsed >> 1];
-		  u_char         *low = high + sq.block_size_half;
-
-		  count = min(userCount, frameLeft) >> 1 & ~1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    data = le2be16(data);
-			    *high++ = data >> 8;
-			    *low++ = (data >> 2) & 0x3f;
-			    count--;
-		    }
-	} else
-	  {
-		  u_char         *lefth = &frame[*frameUsed >> 2];
-		  u_char         *leftl = lefth + sq.block_size_quarter;
-		  u_char         *righth = lefth + sq.block_size_half;
-		  u_char         *rightl = righth + sq.block_size_quarter;
-
-		  count = min(userCount, frameLeft) >> 2 & ~1;
-		  used = count * 4;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    data = le2be16(data);
-			    *lefth++ = data >> 8;
-			    *leftl++ = (data >> 2) & 0x3f;
-			    get_user(data, ((u_short *) userPtr)++);
-			    data = le2be16(data);
-			    *righth++ = data >> 8;
-			    *rightl++ = (data >> 2) & 0x3f;
-			    count--;
-		    }
-	  }
-	*frameUsed += used;
-	return (used);
+static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_char *high = &frame[*frameUsed>>1];
+	u_char *low = high+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    data ^= 0x8000;
+	    *high++ = data>>8;
+	    *low++ = (data>>2) & 0x3f;
+	    count--;
+	}
+    } else {
+	u_char *lefth = &frame[*frameUsed>>2];
+	u_char *leftl = lefth+sq.block_size_quarter;
+	u_char *righth = lefth+sq.block_size_half;
+	u_char *rightl = righth+sq.block_size_quarter;
+	count = min(userCount, frameLeft)>>2 & ~1;
+	used = count*4;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    data ^= 0x8000;
+	    *lefth++ = data>>8;
+	    *leftl++ = (data>>2) & 0x3f;
+	    get_user(data, ((u_short *)userPtr)++);
+	    data ^= 0x8000;
+	    *righth++ = data>>8;
+	    *rightl++ = (data>>2) & 0x3f;
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
 }
 
 
-static long
-ami_ct_u16le(const u_char * userPtr, unsigned long userCount,
-	     u_char frame[], long *frameUsed, long frameLeft)
-{
-	long            count, used;
-	u_long          data;
+static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_char *high = &frame[*frameUsed>>1];
+	u_char *low = high+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    data = le2be16(data);
+	    *high++ = data>>8;
+	    *low++ = (data>>2) & 0x3f;
+	    count--;
+	}
+    } else {
+	u_char *lefth = &frame[*frameUsed>>2];
+	u_char *leftl = lefth+sq.block_size_quarter;
+	u_char *righth = lefth+sq.block_size_half;
+	u_char *rightl = righth+sq.block_size_quarter;
+	count = min(userCount, frameLeft)>>2 & ~1;
+	used = count*4;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    data = le2be16(data);
+	    *lefth++ = data>>8;
+	    *leftl++ = (data>>2) & 0x3f;
+	    get_user(data, ((u_short *)userPtr)++);
+	    data = le2be16(data);
+	    *righth++ = data>>8;
+	    *rightl++ = (data>>2) & 0x3f;
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
+}
 
-	if (!sound.soft.stereo)
-	  {
-		  u_char         *high = &frame[*frameUsed >> 1];
-		  u_char         *low = high + sq.block_size_half;
 
-		  count = min(userCount, frameLeft) >> 1 & ~1;
-		  used = count * 2;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    data = le2be16(data) ^ 0x8000;
-			    *high++ = data >> 8;
-			    *low++ = (data >> 2) & 0x3f;
-			    count--;
-		    }
-	} else
-	  {
-		  u_char         *lefth = &frame[*frameUsed >> 2];
-		  u_char         *leftl = lefth + sq.block_size_quarter;
-		  u_char         *righth = lefth + sq.block_size_half;
-		  u_char         *rightl = righth + sq.block_size_quarter;
-
-		  count = min(userCount, frameLeft) >> 2 & ~1;
-		  used = count * 4;
-		  while (count > 0)
-		    {
-			    get_user(data, ((u_short *) userPtr)++);
-			    data = le2be16(data) ^ 0x8000;
-			    *lefth++ = data >> 8;
-			    *leftl++ = (data >> 2) & 0x3f;
-			    get_user(data, ((u_short *) userPtr)++);
-			    data = le2be16(data) ^ 0x8000;
-			    *righth++ = data >> 8;
-			    *rightl++ = (data >> 2) & 0x3f;
-			    count--;
-		    }
-	  }
-	*frameUsed += used;
-	return (used);
+static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount,
+			 u_char frame[], long *frameUsed, long frameLeft)
+{
+    long count, used;
+    u_long data;
+
+    if (!sound.soft.stereo) {
+	u_char *high = &frame[*frameUsed>>1];
+	u_char *low = high+sq.block_size_half;
+	count = min(userCount, frameLeft)>>1 & ~1;
+	used = count*2;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    data = le2be16(data) ^ 0x8000;
+	    *high++ = data>>8;
+	    *low++ = (data>>2) & 0x3f;
+	    count--;
+	}
+    } else {
+	u_char *lefth = &frame[*frameUsed>>2];
+	u_char *leftl = lefth+sq.block_size_quarter;
+	u_char *righth = lefth+sq.block_size_half;
+	u_char *rightl = righth+sq.block_size_quarter;
+	count = min(userCount, frameLeft)>>2 & ~1;
+	used = count*4;
+	while (count > 0) {
+	    get_user(data, ((u_short *)userPtr)++);
+	    data = le2be16(data) ^ 0x8000;
+	    *lefth++ = data>>8;
+	    *leftl++ = (data>>2) & 0x3f;
+	    get_user(data, ((u_short *)userPtr)++);
+	    data = le2be16(data) ^ 0x8000;
+	    *righth++ = data>>8;
+	    *rightl++ = (data>>2) & 0x3f;
+	    count--;
+	}
+    }
+    *frameUsed += used;
+    return(used);
 }
-#endif				/* CONFIG_AMIGA */
+#endif /* CONFIG_AMIGA */
 
 
 #ifdef CONFIG_ATARI
-static TRANS    transTTNormal =
-{
-     ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
+static TRANS transTTNormal = {
+    ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
 };
 
-static TRANS    transTTExpanding =
-{
- ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
+static TRANS transTTExpanding = {
+    ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
 };
 
-static TRANS    transFalconNormal =
-{
-ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be,
-	ata_ct_s16le, ata_ct_u16le
+static TRANS transFalconNormal = {
+    ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be,
+    ata_ct_s16le, ata_ct_u16le
 };
 
-static TRANS    transFalconExpanding =
-{
-	ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be,
-	ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
+static TRANS transFalconExpanding = {
+    ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be,
+    ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
 };
-
-#endif				/* CONFIG_ATARI */
+#endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
-static TRANS    transAmiga =
-{
-ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be,
-	ami_ct_s16le, ami_ct_u16le
+static TRANS transAmiga = {
+    ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be,
+    ami_ct_s16le, ami_ct_u16le
 };
-
-#endif				/* CONFIG_AMIGA */
+#endif /* CONFIG_AMIGA */
 
 
 /*** Low level stuff *********************************************************/
@@ -1774,68 +1581,44 @@
  * Atari (TT/Falcon)
  */
 
-static void    *
-AtaAlloc(unsigned int size, int flags)
+static void *AtaAlloc(unsigned int size, int flags)
 {
-	int             order;
-	unsigned int    a_size;
+    return( atari_stram_alloc( size, NULL, "dmasound" ));
+}
+
+static void AtaFree(void *obj, unsigned int size)
+{
+    atari_stram_free( obj );
+}
 
-	order = 0;
-	a_size = PAGE_SIZE;
-	while (a_size < size)
-	  {
-		  order++;
-		  a_size <<= 1;
-	  }
-	return (void *) __get_dma_pages(flags, order);
-}
-
-static void
-AtaFree(void *obj, unsigned int size)
-{
-	int             order;
-	unsigned int    a_size;
-
-	order = 0;
-	a_size = PAGE_SIZE;
-	while (a_size < size)
-	  {
-		  order++;
-		  a_size <<= 1;
-	  }
-	free_pages((unsigned long) obj, order);
-}
-
-static int
-AtaIrqInit(void)
-{
-	/* Set up timer A. Timer A
-	   will receive a signal upon end of playing from the sound
-	   hardware. Furthermore Timer A is able to count events
-	   and will cause an interrupt after a programmed number
-	   of events. So all we need to keep the music playing is
-	   to provide the sound hardware with new data upon
-	   an interrupt from timer A. */
-	mfp.tim_ct_a = 0;	/* ++roman: Stop timer before programming! */
-	mfp.tim_dt_a = 1;	/* Cause interrupt after first event. */
-	mfp.tim_ct_a = 8;	/* Turn on event counting. */
-	/* Register interrupt handler. */
-	request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
-		    "DMA sound", ata_sq_interrupt);
-	mfp.int_en_a |= 0x20;	/* Turn interrupt on. */
-	mfp.int_mk_a |= 0x20;
-	return (1);
+static int AtaIrqInit(void)
+{
+    /* Set up timer A. Timer A
+    will receive a signal upon end of playing from the sound
+    hardware. Furthermore Timer A is able to count events
+    and will cause an interrupt after a programmed number
+    of events. So all we need to keep the music playing is
+    to provide the sound hardware with new data upon
+    an interrupt from timer A. */
+    mfp.tim_ct_a = 0;		/* ++roman: Stop timer before programming! */
+    mfp.tim_dt_a = 1;		/* Cause interrupt after first event. */
+    mfp.tim_ct_a = 8;		/* Turn on event counting. */
+    /* Register interrupt handler. */
+    request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
+                "DMA sound", ata_sq_interrupt);
+    mfp.int_en_a |= 0x20;	/* Turn interrupt on. */
+    mfp.int_mk_a |= 0x20;
+    return(1);
 }
 
 #ifdef MODULE
-static void
-AtaIrqCleanUp(void)
+static void AtaIrqCleanUp(void)
 {
-	mfp.tim_ct_a = 0;	/* stop timer */
-	mfp.int_en_a &= ~0x20;	/* turn interrupt off */
-	free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
+    mfp.tim_ct_a = 0;		/* stop timer */
+    mfp.int_en_a &= ~0x20;	/* turn interrupt off */
+    free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
 }
-#endif				/* MODULE */
+#endif /* MODULE */
 
 
 #define TONE_VOXWARE_TO_DB(v) \
@@ -1843,21 +1626,19 @@
 #define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)
 
 
-static int
-AtaSetBass(int bass)
+static int AtaSetBass(int bass)
 {
-	sound.bass = TONE_VOXWARE_TO_DB(bass);
-	atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
-	return (TONE_DB_TO_VOXWARE(sound.bass));
+    sound.bass = TONE_VOXWARE_TO_DB(bass);
+    atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
+    return(TONE_DB_TO_VOXWARE(sound.bass));
 }
 
 
-static int
-AtaSetTreble(int treble)
+static int AtaSetTreble(int treble)
 {
-	sound.treble = TONE_VOXWARE_TO_DB(treble);
-	atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
-	return (TONE_DB_TO_VOXWARE(sound.treble));
+    sound.treble = TONE_VOXWARE_TO_DB(treble);
+    atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
+    return(TONE_DB_TO_VOXWARE(sound.treble));
 }
 
 
@@ -1867,100 +1648,88 @@
  */
 
 
-static void
-TTSilence(void)
+static void TTSilence(void)
 {
-	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-	atari_microwire_cmd(MW_LM1992_PSG_HIGH);	/* mix in PSG signal 1:1 */
+    tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+    atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
 }
 
 
-static void
-TTInit(void)
+static void TTInit(void)
 {
-	int             mode, i, idx;
-	const int       freq[4] =
-	{50066, 25033, 12517, 6258};
-
-	/* search a frequency that fits into the allowed error range */
-
-	idx = -1;
-	for (i = 0; i < arraysize(freq); i++)
-		/* this isn't as much useful for a TT than for a Falcon, but
-		 * then it doesn't hurt very much to implement it for a TT too.
-		 */
-		if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
-			idx = i;
-	if (idx > -1)
-	  {
-		  sound.soft.speed = freq[idx];
-		  sound.trans = &transTTNormal;
-	} else
-		sound.trans = &transTTExpanding;
+    int mode, i, idx;
+    const int freq[4] = {50066, 25033, 12517, 6258};
 
-	TTSilence();
-	sound.hard = sound.soft;
+    /* search a frequency that fits into the allowed error range */
 
-	if (sound.hard.speed > 50066)
-	  {
-		  /* we would need to squeeze the sound, but we won't do that */
-		  sound.hard.speed = 50066;
-		  mode = DMASND_MODE_50KHZ;
-		  sound.trans = &transTTNormal;
-	} else if (sound.hard.speed > 25033)
-	  {
-		  sound.hard.speed = 50066;
-		  mode = DMASND_MODE_50KHZ;
-	} else if (sound.hard.speed > 12517)
-	  {
-		  sound.hard.speed = 25033;
-		  mode = DMASND_MODE_25KHZ;
-	} else if (sound.hard.speed > 6258)
-	  {
-		  sound.hard.speed = 12517;
-		  mode = DMASND_MODE_12KHZ;
-	} else
-	  {
-		  sound.hard.speed = 6258;
-		  mode = DMASND_MODE_6KHZ;
-	  }
-
-	tt_dmasnd.mode = (sound.hard.stereo ?
-			  DMASND_MODE_STEREO : DMASND_MODE_MONO) |
-	    DMASND_MODE_8BIT | mode;
-
-	sound.bal = -sound.soft.speed;
+    idx = -1;
+    for (i = 0; i < arraysize(freq); i++)
+	/* this isn't as much useful for a TT than for a Falcon, but
+	 * then it doesn't hurt very much to implement it for a TT too.
+	 */
+	if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+	    idx = i;
+    if (idx > -1) {
+	sound.soft.speed = freq[idx];
+	sound.trans = &transTTNormal;
+    } else
+	sound.trans = &transTTExpanding;
+
+    TTSilence();
+    sound.hard = sound.soft;
+
+    if (sound.hard.speed > 50066) {
+	/* we would need to squeeze the sound, but we won't do that */
+	sound.hard.speed = 50066;
+	mode = DMASND_MODE_50KHZ;
+	sound.trans = &transTTNormal;
+    } else if (sound.hard.speed > 25033) {
+	sound.hard.speed = 50066;
+	mode = DMASND_MODE_50KHZ;
+    } else if (sound.hard.speed > 12517) {
+	sound.hard.speed = 25033;
+	mode = DMASND_MODE_25KHZ;
+    } else if (sound.hard.speed > 6258) {
+	sound.hard.speed = 12517;
+	mode = DMASND_MODE_12KHZ;
+    } else {
+	sound.hard.speed = 6258;
+	mode = DMASND_MODE_6KHZ;
+    }
+
+    tt_dmasnd.mode = (sound.hard.stereo ?
+		      DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+		     DMASND_MODE_8BIT | mode;
+
+    sound.bal = -sound.soft.speed;
 }
 
 
-static int
-TTSetFormat(int format)
-{
-	/* TT sound DMA supports only 8bit modes */
-
-	switch (format)
-	  {
-	  case AFMT_QUERY:
-		  return (sound.soft.format);
-	  case AFMT_MU_LAW:
-	  case AFMT_A_LAW:
-	  case AFMT_S8:
-	  case AFMT_U8:
-		  break;
-	  default:
-		  format = AFMT_S8;
-	  }
-
-	sound.soft.format = format;
-	sound.soft.size = 8;
-	if (sound.minDev == SND_DEV_DSP)
-	  {
-		  sound.dsp.format = format;
-		  sound.dsp.size = 8;
-	  }
-	TTInit();
+static int TTSetFormat(int format)
+{
+    /* TT sound DMA supports only 8bit modes */
+
+    switch (format) {
+	case AFMT_QUERY:
+	    return(sound.soft.format);
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_S8:
+	case AFMT_U8:
+	    break;
+	default:
+	    format = AFMT_S8;
+    }
+
+    sound.soft.format = format;
+    sound.soft.size = 8;
+    if (sound.minDev == SND_DEV_DSP) {
+	sound.dsp.format = format;
+	sound.dsp.size = 8;
+    }
+    TTInit();
 
-	return (format);
+    return(format);
 }
 
 
@@ -1969,15 +1738,26 @@
 #define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
 
 
-static int
-TTSetVolume(int volume)
+static int TTSetVolume(int volume)
+{
+    sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
+    atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
+    sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
+    atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
+    return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
+	   (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
+}
+
+
+#define GAIN_VOXWARE_TO_DB(v) \
+	(((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80)
+#define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4)
+
+static int TTSetGain(int gain)
 {
-	sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
-	atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
-	sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
-	atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
-	return (VOLUME_DB_TO_VOXWARE(sound.volume_left) |
-		(VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
+    sound.gain = GAIN_VOXWARE_TO_DB(gain);
+    atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain));
+    return GAIN_DB_TO_VOXWARE(sound.gain);
 }
 
 
@@ -1987,151 +1767,135 @@
  */
 
 
-static void
-FalconSilence(void)
+static void FalconSilence(void)
 {
-	/* stop playback, set sample rate 50kHz for PSG sound */
-	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-	tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
-	tt_dmasnd.int_div = 0;	/* STE compatible divider */
-	tt_dmasnd.int_ctrl = 0x0;
-	tt_dmasnd.cbar_src = 0x0000;	/* no matrix inputs */
-	tt_dmasnd.cbar_dst = 0x0000;	/* no matrix outputs */
-	tt_dmasnd.dac_src = 1;	/* connect ADC to DAC, disconnect matrix */
-	tt_dmasnd.adc_src = 3;	/* ADC Input = PSG */
+    /* stop playback, set sample rate 50kHz for PSG sound */
+    tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+    tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
+    tt_dmasnd.int_div = 0; /* STE compatible divider */
+    tt_dmasnd.int_ctrl = 0x0;
+    tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
+    tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
+    tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
+    tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
 }
 
 
-static void
-FalconInit(void)
-{
-	int             divider, i, idx;
-	const int       freq[8] =
-	{49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
-
-	/* search a frequency that fits into the allowed error range */
-
-	idx = -1;
-	for (i = 0; i < arraysize(freq); i++)
-		/* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
-		 * be playable without expanding, but that now a kernel runtime
-		 * option
-		 */
-		if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
-			idx = i;
-	if (idx > -1)
-	  {
-		  sound.soft.speed = freq[idx];
-		  sound.trans = &transFalconNormal;
-	} else
-		sound.trans = &transFalconExpanding;
-
-	FalconSilence();
-	sound.hard = sound.soft;
+static void FalconInit(void)
+{
+    int divider, i, idx;
+    const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
 
-	if (sound.hard.size == 16)
-	  {
-		  /* the Falcon can play 16bit samples only in stereo */
-		  sound.hard.stereo = 1;
-	  }
-	if (sound.hard.speed > 49170)
-	  {
-		  /* we would need to squeeze the sound, but we won't do that */
-		  sound.hard.speed = 49170;
-		  divider = 1;
-		  sound.trans = &transFalconNormal;
-	} else if (sound.hard.speed > 32780)
-	  {
-		  sound.hard.speed = 49170;
-		  divider = 1;
-	} else if (sound.hard.speed > 24585)
-	  {
-		  sound.hard.speed = 32780;
-		  divider = 2;
-	} else if (sound.hard.speed > 19668)
-	  {
-		  sound.hard.speed = 24585;
-		  divider = 3;
-	} else if (sound.hard.speed > 16390)
-	  {
-		  sound.hard.speed = 19668;
-		  divider = 4;
-	} else if (sound.hard.speed > 12292)
-	  {
-		  sound.hard.speed = 16390;
-		  divider = 5;
-	} else if (sound.hard.speed > 9834)
-	  {
-		  sound.hard.speed = 12292;
-		  divider = 7;
-	} else if (sound.hard.speed > 8195)
-	  {
-		  sound.hard.speed = 9834;
-		  divider = 9;
-	} else
-	  {
-		  sound.hard.speed = 8195;
-		  divider = 11;
-	  }
-	tt_dmasnd.int_div = divider;
-
-	/* Setup Falcon sound DMA for playback */
-	tt_dmasnd.int_ctrl = 0x4;	/* Timer A int at play end */
-	tt_dmasnd.track_select = 0x0;	/* play 1 track, track 1 */
-	tt_dmasnd.cbar_src = 0x0001;	/* DMA(25MHz) --> DAC */
-	tt_dmasnd.cbar_dst = 0x0000;
-	tt_dmasnd.rec_track_select = 0;
-	tt_dmasnd.dac_src = 2;	/* connect matrix to DAC */
-	tt_dmasnd.adc_src = 0;	/* ADC Input = Mic */
-
-	tt_dmasnd.mode = (sound.hard.stereo ?
-			  DMASND_MODE_STEREO : DMASND_MODE_MONO) |
-	    ((sound.hard.size == 8) ?
-	     DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
-	    DMASND_MODE_6KHZ;
-
-	sound.bal = -sound.soft.speed;
-}
+    /* search a frequency that fits into the allowed error range */
 
+    idx = -1;
+    for (i = 0; i < arraysize(freq); i++)
+	/* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
+	 * be playable without expanding, but that now a kernel runtime
+	 * option
+	 */
+	if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+	    idx = i;
+    if (idx > -1) {
+	sound.soft.speed = freq[idx];
+	sound.trans = &transFalconNormal;
+    } else
+	sound.trans = &transFalconExpanding;
+
+    FalconSilence();
+    sound.hard = sound.soft;
+
+    if (sound.hard.size == 16) {
+	/* the Falcon can play 16bit samples only in stereo */
+	sound.hard.stereo = 1;
+    }
+
+    if (sound.hard.speed > 49170) {
+	/* we would need to squeeze the sound, but we won't do that */
+	sound.hard.speed = 49170;
+	divider = 1;
+	sound.trans = &transFalconNormal;
+    } else if (sound.hard.speed > 32780) {
+	sound.hard.speed = 49170;
+	divider = 1;
+    } else if (sound.hard.speed > 24585) {
+	sound.hard.speed = 32780;
+	divider = 2;
+    } else if (sound.hard.speed > 19668) {
+	sound.hard.speed = 24585;
+	divider = 3;
+    } else if (sound.hard.speed > 16390) {
+	sound.hard.speed = 19668;
+	divider = 4;
+    } else if (sound.hard.speed > 12292) {
+	sound.hard.speed = 16390;
+	divider = 5;
+    } else if (sound.hard.speed > 9834) {
+	sound.hard.speed = 12292;
+	divider = 7;
+    } else if (sound.hard.speed > 8195) {
+	sound.hard.speed = 9834;
+	divider = 9;
+    } else {
+	sound.hard.speed = 8195;
+	divider = 11;
+    }
+    tt_dmasnd.int_div = divider;
+
+    /* Setup Falcon sound DMA for playback */
+    tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
+    tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
+    tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
+    tt_dmasnd.cbar_dst = 0x0000;
+    tt_dmasnd.rec_track_select = 0;
+    tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
+    tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
+
+    tt_dmasnd.mode = (sound.hard.stereo ?
+		      DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+		     ((sound.hard.size == 8) ?
+		       DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
+		     DMASND_MODE_6KHZ;
+
+    sound.bal = -sound.soft.speed;
+}
+
+
+static int FalconSetFormat(int format)
+{
+    int size;
+    /* Falcon sound DMA supports 8bit and 16bit modes */
+
+    switch (format) {
+	case AFMT_QUERY:
+	    return(sound.soft.format);
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_U8:
+	case AFMT_S8:
+	    size = 8;
+	    break;
+	case AFMT_S16_BE:
+	case AFMT_U16_BE:
+	case AFMT_S16_LE:
+	case AFMT_U16_LE:
+	    size = 16;
+	    break;
+	default: /* :-) */
+	    size = 8;
+	    format = AFMT_S8;
+    }
+
+    sound.soft.format = format;
+    sound.soft.size = size;
+    if (sound.minDev == SND_DEV_DSP) {
+	sound.dsp.format = format;
+	sound.dsp.size = sound.soft.size;
+    }
 
-static int
-FalconSetFormat(int format)
-{
-	int             size;
-
-	/* Falcon sound DMA supports 8bit and 16bit modes */
-
-	switch (format)
-	  {
-	  case AFMT_QUERY:
-		  return (sound.soft.format);
-	  case AFMT_MU_LAW:
-	  case AFMT_A_LAW:
-	  case AFMT_U8:
-	  case AFMT_S8:
-		  size = 8;
-		  break;
-	  case AFMT_S16_BE:
-	  case AFMT_U16_BE:
-	  case AFMT_S16_LE:
-	  case AFMT_U16_LE:
-		  size = 16;
-		  break;
-	  default:		/* :-) */
-		  size = 8;
-		  format = AFMT_S8;
-	  }
-
-	sound.soft.format = format;
-	sound.soft.size = size;
-	if (sound.minDev == SND_DEV_DSP)
-	  {
-		  sound.dsp.format = format;
-		  sound.dsp.size = sound.soft.size;
-	  }
-	FalconInit();
+    FalconInit();
 
-	return (format);
+    return(format);
 }
 
 
@@ -2143,181 +1907,168 @@
 #define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)
 
 
-static int
-FalconSetVolume(int volume)
+static int FalconSetVolume(int volume)
 {
-	sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
-	sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
-	tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
-	return (VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
-		VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
+    sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
+    sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
+    tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
+    return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
+	   VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
 }
 
 
-static void
-ata_sq_play_next_frame(int index)
+static void ata_sq_play_next_frame(int index)
 {
-	char           *start, *end;
+    char *start, *end;
 
-	/* used by AtaPlay() if all doubts whether there really is something
-	 * to be played are already wiped out.
-	 */
-	start = sq_block_address(sq.front);
-	end = start + ((sq.count == index) ? sq.rear_size : sq.block_size);
-	/* end might not be a legal virtual address. */
-	DMASNDSetEnd(VTOP(end - 1) + 1);
-	DMASNDSetBase(VTOP(start));
+    /* used by AtaPlay() if all doubts whether there really is something
+     * to be played are already wiped out.
+     */
+    start = sq_block_address(sq.front);
+    end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
+    /* end might not be a legal virtual address. */
+    DMASNDSetEnd(VTOP(end - 1) + 1);
+    DMASNDSetBase(VTOP(start));
 	/* Since only an even number of samples per frame can
-	   be played, we might lose one byte here. (TO DO) */
-	sq.front = (sq.front + 1) % sq.max_count;
-	sq.playing++;
-	tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
+	be played, we might lose one byte here. (TO DO) */
+    sq.front = (sq.front+1) % sq.max_count;
+    sq.playing++;
+    tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
 }
 
 
-static void
-AtaPlay(void)
-{
-	/* ++TeSche: Note that sq.playing is no longer just a flag but holds
-	 * the number of frames the DMA is currently programmed for instead,
-	 * may be 0, 1 (currently being played) or 2 (pre-programmed).
-	 *
-	 * Changes done to sq.count and sq.playing are a bit more subtle again
-	 * so now I must admit I also prefer disabling the irq here rather
-	 * than considering all possible situations. But the point is that
-	 * disabling the irq doesn't have any bad influence on this version of
-	 * the driver as we benefit from having pre-programmed the DMA
-	 * wherever possible: There's no need to reload the DMA at the exact
-	 * time of an interrupt but only at some time while the pre-programmed
-	 * frame is playing!
-	 */
-	atari_disable_irq(IRQ_MFP_TIMA);
+static void AtaPlay(void)
+{
+    /* ++TeSche: Note that sq.playing is no longer just a flag but holds
+     * the number of frames the DMA is currently programmed for instead,
+     * may be 0, 1 (currently being played) or 2 (pre-programmed).
+     *
+     * Changes done to sq.count and sq.playing are a bit more subtle again
+     * so now I must admit I also prefer disabling the irq here rather
+     * than considering all possible situations. But the point is that
+     * disabling the irq doesn't have any bad influence on this version of
+     * the driver as we benefit from having pre-programmed the DMA
+     * wherever possible: There's no need to reload the DMA at the exact
+     * time of an interrupt but only at some time while the pre-programmed
+     * frame is playing!
+     */
+    atari_disable_irq(IRQ_MFP_TIMA);
 
-	if (sq.playing == 2 ||	/* DMA is 'full' */
-	    sq.count <= 0)
-	  {			/* nothing to do */
-		  atari_enable_irq(IRQ_MFP_TIMA);
-		  return;
-	  }
-	if (sq.playing == 0)
-	  {
-		  /* looks like there's nothing 'in' the DMA yet, so try
-		   * to put two frames into it (at least one is available).
-		   */
-		  if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing)
-		    {
-			    /* hmmm, the only existing frame is not
-			     * yet filled and we're not syncing?
-			     */
-			    atari_enable_irq(IRQ_MFP_TIMA);
-			    return;
-		    }
-		  ata_sq_play_next_frame(1);
-		  if (sq.count == 1)
-		    {
-			    /* no more frames */
-			    atari_enable_irq(IRQ_MFP_TIMA);
-			    return;
-		    }
-		  if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing)
-		    {
-			    /* hmmm, there were two frames, but the second
-			     * one is not yet filled and we're not syncing?
-			     */
-			    atari_enable_irq(IRQ_MFP_TIMA);
-			    return;
-		    }
-		  ata_sq_play_next_frame(2);
-	} else
-	  {
-		  /* there's already a frame being played so we may only stuff
-		   * one new into the DMA, but even if this may be the last
-		   * frame existing the previous one is still on sq.count.
-		   */
-		  if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing)
-		    {
-			    /* hmmm, the only existing frame is not
-			     * yet filled and we're not syncing?
-			     */
-			    atari_enable_irq(IRQ_MFP_TIMA);
-			    return;
-		    }
-		  ata_sq_play_next_frame(2);
-	  }
+    if (sq.playing == 2 ||	/* DMA is 'full' */
+	sq.count <= 0) {	/* nothing to do */
 	atari_enable_irq(IRQ_MFP_TIMA);
+	return;
+    }
+
+    if (sq.playing == 0) {
+	/* looks like there's nothing 'in' the DMA yet, so try
+	 * to put two frames into it (at least one is available).
+	 */
+	if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
+	    /* hmmm, the only existing frame is not
+	     * yet filled and we're not syncing?
+	     */
+	    atari_enable_irq(IRQ_MFP_TIMA);
+	    return;
+	}
+	ata_sq_play_next_frame(1);
+	if (sq.count == 1) {
+	    /* no more frames */
+	    atari_enable_irq(IRQ_MFP_TIMA);
+	    return;
+	}
+	if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+	    /* hmmm, there were two frames, but the second
+	     * one is not yet filled and we're not syncing?
+	     */
+	    atari_enable_irq(IRQ_MFP_TIMA);
+	    return;
+	}
+	ata_sq_play_next_frame(2);
+    } else {
+	/* there's already a frame being played so we may only stuff
+	 * one new into the DMA, but even if this may be the last
+	 * frame existing the previous one is still on sq.count.
+	 */
+	if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+	    /* hmmm, the only existing frame is not
+	     * yet filled and we're not syncing?
+	     */
+	    atari_enable_irq(IRQ_MFP_TIMA);
+	    return;
+	}
+	ata_sq_play_next_frame(2);
+    }
+    atari_enable_irq(IRQ_MFP_TIMA);
 }
 
 
-static void
-ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
+static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
 #if 0
-	/* ++TeSche: if you should want to test this... */
-	static int      cnt = 0;
-
-	if (sq.playing == 2)
-		if (++cnt == 10)
-		  {
-			  /* simulate losing an interrupt */
-			  cnt = 0;
-			  return;
-		  }
+    /* ++TeSche: if you should want to test this... */
+    static int cnt = 0;
+    if (sq.playing == 2)
+	if (++cnt == 10) {
+	    /* simulate losing an interrupt */
+	    cnt = 0;
+	    return;
+	}
 #endif
 
-	if (sq.ignore_int && (sound.mach.type == DMASND_FALCON))
-	  {
-		  /* ++TeSche: Falcon only: ignore first irq because it comes
-		   * immediately after starting a frame. after that, irqs come
-		   * (almost) like on the TT.
-		   */
-		  sq.ignore_int = 0;
-		  return;
-	  }
-	if (!sq.playing)
-	  {
-		  /* playing was interrupted and sq_reset() has already cleared
-		   * the sq variables, so better don't do anything here.
-		   */
-		  WAKE_UP(sq.sync_queue);
-		  return;
-	  }
-	/* Probably ;) one frame is finished. Well, in fact it may be that a
-	 * pre-programmed one is also finished because there has been a long
-	 * delay in interrupt delivery and we've completely lost one, but
-	 * there's no way to detect such a situation. In such a case the last
-	 * frame will be played more than once and the situation will recover
-	 * as soon as the irq gets through.
+    if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
+	/* ++TeSche: Falcon only: ignore first irq because it comes
+	 * immediately after starting a frame. after that, irqs come
+	 * (almost) like on the TT.
 	 */
-	sq.count--;
-	sq.playing--;
+	sq.ignore_int = 0;
+	return;
+    }
 
-	if (!sq.playing)
-	  {
-		  tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-		  sq.ignore_int = 1;
-	  }
-	WAKE_UP(sq.write_queue);
+    if (!sq.playing) {
+	/* playing was interrupted and sq_reset() has already cleared
+	 * the sq variables, so better don't do anything here.
+	 */
+	WAKE_UP(sq.sync_queue);
+	return;
+    }
+
+    /* Probably ;) one frame is finished. Well, in fact it may be that a
+     * pre-programmed one is also finished because there has been a long
+     * delay in interrupt delivery and we've completely lost one, but
+     * there's no way to detect such a situation. In such a case the last
+     * frame will be played more than once and the situation will recover
+     * as soon as the irq gets through.
+     */
+    sq.count--;
+    sq.playing--;
+
+    if (!sq.playing) {
+	tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+	sq.ignore_int = 1;
+    }
+
+    WAKE_UP(sq.write_queue);
 	/* At least one block of the queue is free now
-	   so wake up a writing process blocked because
-	   of a full queue. */
+	so wake up a writing process blocked because
+	of a full queue. */
 
-	if ((sq.playing != 1) || (sq.count != 1))
-		/* We must be a bit carefully here: sq.count indicates the
-		 * number of buffers used and not the number of frames to
-		 * be played. If sq.count==1 and sq.playing==1 that means
-		 * the only remaining frame was already programmed earlier
-		 * (and is currently running) so we mustn't call AtaPlay()
-		 * here, otherwise we'll play one frame too much.
-		 */
-		AtaPlay();
+    if ((sq.playing != 1) || (sq.count != 1))
+	/* We must be a bit carefully here: sq.count indicates the
+	 * number of buffers used and not the number of frames to
+	 * be played. If sq.count==1 and sq.playing==1 that means
+	 * the only remaining frame was already programmed earlier
+	 * (and is currently running) so we mustn't call AtaPlay()
+	 * here, otherwise we'll play one frame too much.
+	 */
+	AtaPlay();
 
-	if (!sq.playing)
-		WAKE_UP(sq.sync_queue);
+    if (!sq.playing) WAKE_UP(sq.sync_queue);
 	/* We are not playing after AtaPlay(), so there
-	   is nothing to play any more. Wake up a process
-	   waiting for audio output to drain. */
+	is nothing to play any more. Wake up a process
+	waiting for audio output to drain. */
 }
-#endif				/* CONFIG_ATARI */
+#endif /* CONFIG_ATARI */
 
 
 #ifdef CONFIG_AMIGA
@@ -2327,120 +2078,109 @@
  */
 
 
-static void    *
-AmiAlloc(unsigned int size, int flags)
+static void *AmiAlloc(unsigned int size, int flags)
 {
-	return (amiga_chip_alloc((long) size));
+    return(amiga_chip_alloc((long)size));
 }
 
-static void
-AmiFree(void *obj, unsigned int size)
+static void AmiFree(void *obj, unsigned int size)
 {
-	amiga_chip_free(obj);
+    amiga_chip_free (obj);
 }
 
-static int
-AmiIrqInit(void)
+static int AmiIrqInit(void)
 {
-	/* turn off DMA for audio channels */
-	custom.dmacon = AMI_AUDIO_OFF;
+    /* turn off DMA for audio channels */
+    custom.dmacon = AMI_AUDIO_OFF;
 
-	/* Register interrupt handler. */
-	if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
-			"DMA sound", ami_sq_interrupt))
-		return (0);
-	return (1);
+    /* Register interrupt handler. */
+    if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
+                    "DMA sound", ami_sq_interrupt))
+	return(0);
+    return(1);
 }
 
 #ifdef MODULE
-static void
-AmiIrqCleanUp(void)
+static void AmiIrqCleanUp(void)
 {
-	/* turn off DMA for audio channels */
-	custom.dmacon = AMI_AUDIO_OFF;
-	/* release the interrupt */
-	free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
+    /* turn off DMA for audio channels */
+    custom.dmacon = AMI_AUDIO_OFF;
+    /* release the interrupt */
+    free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
 }
-#endif				/* MODULE */
+#endif /* MODULE */
 
-static void
-AmiSilence(void)
+static void AmiSilence(void)
 {
-	/* turn off DMA for audio channels */
-	custom.dmacon = AMI_AUDIO_OFF;
+    /* turn off DMA for audio channels */
+    custom.dmacon = AMI_AUDIO_OFF;
 }
 
 
-static void
-AmiInit(void)
+static void AmiInit(void)
 {
-	int             period, i;
+    int period, i;
+
+    AmiSilence();
+
+    if (sound.soft.speed)
+	period = amiga_colorclock/sound.soft.speed-1;
+    else
+	period = amiga_audio_min_period;
+    sound.hard = sound.soft;
+    sound.trans = &transAmiga;
 
-	AmiSilence();
+    if (period < amiga_audio_min_period) {
+	/* we would need to squeeze the sound, but we won't do that */
+	period = amiga_audio_min_period;
+    } else if (period > 65535) {
+	period = 65535;
+    }
+    sound.hard.speed = amiga_colorclock/(period+1);
 
-	if (sound.soft.speed)
-		period = amiga_colorclock / sound.soft.speed - 1;
-	else
-		period = amiga_audio_min_period;
-	sound.hard = sound.soft;
-	sound.trans = &transAmiga;
-
-	if (period < amiga_audio_min_period)
-	  {
-		  /* we would need to squeeze the sound, but we won't do that */
-		  period = amiga_audio_min_period;
-	} else if (period > 65535)
-	  {
-		  period = 65535;
-	  }
-	sound.hard.speed = amiga_colorclock / (period + 1);
-
-	for (i = 0; i < 4; i++)
-		custom.aud[i].audper = period;
-	amiga_audio_period = period;
-
-	AmiSetTreble(50);	/* recommended for newer amiga models */
-}
-
-
-static int
-AmiSetFormat(int format)
-{
-	int             size;
-
-	/* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
-
-	switch (format)
-	  {
-	  case AFMT_QUERY:
-		  return (sound.soft.format);
-	  case AFMT_MU_LAW:
-	  case AFMT_A_LAW:
-	  case AFMT_U8:
-	  case AFMT_S8:
-		  size = 8;
-		  break;
-	  case AFMT_S16_BE:
-	  case AFMT_U16_BE:
-	  case AFMT_S16_LE:
-	  case AFMT_U16_LE:
-		  size = 16;
-		  break;
-	  default:		/* :-) */
-		  size = 8;
-		  format = AFMT_S8;
-	  }
-
-	sound.soft.format = format;
-	sound.soft.size = size;
-	if (sound.minDev == SND_DEV_DSP)
-	  {
-		  sound.dsp.format = format;
-		  sound.dsp.size = sound.soft.size;
-	  }
-	AmiInit();
+    for (i = 0; i < 4; i++)
+	custom.aud[i].audper = period;
+    amiga_audio_period = period;
 
-	return (format);
+    AmiSetTreble(50);  /* recommended for newer amiga models */
+}
+
+
+static int AmiSetFormat(int format)
+{
+    int size;
+
+    /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
+
+    switch (format) {
+	case AFMT_QUERY:
+	    return(sound.soft.format);
+	case AFMT_MU_LAW:
+	case AFMT_A_LAW:
+	case AFMT_U8:
+	case AFMT_S8:
+	    size = 8;
+	    break;
+	case AFMT_S16_BE:
+	case AFMT_U16_BE:
+	case AFMT_S16_LE:
+	case AFMT_U16_LE:
+	    size = 16;
+	    break;
+	default: /* :-) */
+	    size = 8;
+	    format = AFMT_S8;
+    }
+
+    sound.soft.format = format;
+    sound.soft.size = size;
+    if (sound.minDev == SND_DEV_DSP) {
+	sound.dsp.format = format;
+	sound.dsp.size = sound.soft.size;
+    }
+    AmiInit();
+
+    return(format);
 }
 
 
@@ -2448,26 +2188,24 @@
 	(((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
 #define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
 
-static int
-AmiSetVolume(int volume)
+static int AmiSetVolume(int volume)
 {
-	sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
-	custom.aud[0].audvol = sound.volume_left;
-	sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
-	custom.aud[1].audvol = sound.volume_right;
-	return (VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
-		(VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
-}
-
-static int
-AmiSetTreble(int treble)
-{
-	sound.treble = treble;
-	if (treble < 50)
-		ciaa.pra &= ~0x02;
-	else
-		ciaa.pra |= 0x02;
-	return (treble);
+    sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
+    custom.aud[0].audvol = sound.volume_left;
+    sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
+    custom.aud[1].audvol = sound.volume_right;
+    return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
+	   (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+}
+
+static int AmiSetTreble(int treble)
+{
+    sound.treble = treble;
+    if (treble < 50)
+	ciaa.pra &= ~0x02;
+    else
+	ciaa.pra |= 0x02;
+    return(treble);
 }
 
 
@@ -2476,302 +2214,286 @@
 #define AMI_PLAY_MASK		3
 
 
-static void
-ami_sq_play_next_frame(int index)
+static void ami_sq_play_next_frame(int index)
 {
-	u_char         *start, *ch0, *ch1, *ch2, *ch3;
-	u_long          size;
-
-	/* used by AmiPlay() if all doubts whether there really is something
-	 * to be played are already wiped out.
-	 */
-	start = sq_block_address(sq.front);
-	size = (sq.count == index ? sq.rear_size : sq.block_size) >> 1;
+    u_char *start, *ch0, *ch1, *ch2, *ch3;
+    u_long size;
 
-	if (sound.hard.stereo)
-	  {
-		  ch0 = start;
-		  ch1 = start + sq.block_size_half;
-		  size >>= 1;
-	} else
-	  {
-		  ch0 = start;
-		  ch1 = start;
-	  }
-	if (sound.hard.size == 8)
-	  {
-		  custom.aud[0].audlc = (u_short *) ZTWO_PADDR(ch0);
-		  custom.aud[0].audlen = size;
-		  custom.aud[1].audlc = (u_short *) ZTWO_PADDR(ch1);
-		  custom.aud[1].audlen = size;
-		  custom.dmacon = AMI_AUDIO_8;
-	} else
-	  {
-		  size >>= 1;
-		  custom.aud[0].audlc = (u_short *) ZTWO_PADDR(ch0);
-		  custom.aud[0].audlen = size;
-		  custom.aud[1].audlc = (u_short *) ZTWO_PADDR(ch1);
-		  custom.aud[1].audlen = size;
-		  if (sound.volume_left == 64 && sound.volume_right == 64)
-		    {
-			    /* We can play pseudo 14-bit only with the maximum volume */
-			    ch3 = ch0 + sq.block_size_quarter;
-			    ch2 = ch1 + sq.block_size_quarter;
-			    custom.aud[2].audvol = 1;	/* we are being affected by the beeps */
-			    custom.aud[3].audvol = 1;	/* restoring volume here helps a bit */
-			    custom.aud[2].audlc = (u_short *) ZTWO_PADDR(ch2);
-			    custom.aud[2].audlen = size;
-			    custom.aud[3].audlc = (u_short *) ZTWO_PADDR(ch3);
-			    custom.aud[3].audlen = size;
-			    custom.dmacon = AMI_AUDIO_14;
-		  } else
-			  custom.dmacon = AMI_AUDIO_8;
-	  }
-	sq.front = (sq.front + 1) % sq.max_count;
-	sq.playing |= AMI_PLAY_LOADED;
+    /* used by AmiPlay() if all doubts whether there really is something
+     * to be played are already wiped out.
+     */
+    start = sq_block_address(sq.front);
+    size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
+
+    if (sound.hard.stereo) {
+	ch0 = start;
+	ch1 = start+sq.block_size_half;
+	size >>= 1;
+    } else {
+	ch0 = start;
+	ch1 = start;
+    }
+    if (sound.hard.size == 8) {
+	custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+	custom.aud[0].audlen = size;
+	custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+	custom.aud[1].audlen = size;
+	custom.dmacon = AMI_AUDIO_8;
+    } else {
+	size >>= 1;
+	custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+	custom.aud[0].audlen = size;
+	custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+	custom.aud[1].audlen = size;
+	if (sound.volume_left == 64 && sound.volume_right == 64) {
+	    /* We can play pseudo 14-bit only with the maximum volume */
+	    ch3 = ch0+sq.block_size_quarter;
+	    ch2 = ch1+sq.block_size_quarter;
+	    custom.aud[2].audvol = 1;  /* we are being affected by the beeps */
+	    custom.aud[3].audvol = 1;  /* restoring volume here helps a bit */
+	    custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
+	    custom.aud[2].audlen = size;
+	    custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
+	    custom.aud[3].audlen = size;
+	    custom.dmacon = AMI_AUDIO_14;
+	} else
+	    custom.dmacon = AMI_AUDIO_8;
+    }
+    sq.front = (sq.front+1) % sq.max_count;
+    sq.playing |= AMI_PLAY_LOADED;
 }
 
 
-static void
-AmiPlay(void)
-{
-	int             minframes = 1;
-
-	custom.intena = IF_AUD0;
-
-	if (sq.playing & AMI_PLAY_LOADED)
-	  {
-		  /* There's already a frame loaded */
-		  custom.intena = IF_SETCLR | IF_AUD0;
-		  return;
-	  }
-	if (sq.playing & AMI_PLAY_PLAYING)
-		/* Increase threshold: frame 1 is already being played */
-		minframes = 2;
-
-	if (sq.count < minframes)
-	  {
-		  /* Nothing to do */
-		  custom.intena = IF_SETCLR | IF_AUD0;
-		  return;
-	  }
-	if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing)
-	  {
-		  /* hmmm, the only existing frame is not
-		   * yet filled and we're not syncing?
-		   */
-		  custom.intena = IF_SETCLR | IF_AUD0;
-		  return;
-	  }
-	ami_sq_play_next_frame(minframes);
+static void AmiPlay(void)
+{
+    int minframes = 1;
 
+    custom.intena = IF_AUD0;
+
+    if (sq.playing & AMI_PLAY_LOADED) {
+	/* There's already a frame loaded */
 	custom.intena = IF_SETCLR | IF_AUD0;
+	return;
+    }
+
+    if (sq.playing & AMI_PLAY_PLAYING)
+	/* Increase threshold: frame 1 is already being played */
+	minframes = 2;
+
+    if (sq.count < minframes) {
+	/* Nothing to do */
+	custom.intena = IF_SETCLR | IF_AUD0;
+	return;
+    }
+
+    if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
+	/* hmmm, the only existing frame is not
+	 * yet filled and we're not syncing?
+	 */
+	custom.intena = IF_SETCLR | IF_AUD0;
+	return;
+    }
+
+    ami_sq_play_next_frame(minframes);
+
+    custom.intena = IF_SETCLR | IF_AUD0;
 }
 
 
-static void
-ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
+static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
-	int             minframes = 1;
+    int minframes = 1;
+
+    if (!sq.playing) {
+	/* Playing was interrupted and sq_reset() has already cleared
+	 * the sq variables, so better don't do anything here.
+	 */
+	WAKE_UP(sq.sync_queue);
+	return;
+    }
+
+    if (sq.playing & AMI_PLAY_PLAYING) {
+	/* We've just finished a frame */
+	sq.count--;
+	WAKE_UP(sq.write_queue);
+    }
+
+    if (sq.playing & AMI_PLAY_LOADED)
+	/* Increase threshold: frame 1 is already being played */
+	minframes = 2;
+
+    /* Shift the flags */
+    sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
 
-	if (!sq.playing)
-	  {
-		  /* Playing was interrupted and sq_reset() has already cleared
-		   * the sq variables, so better don't do anything here.
-		   */
-		  WAKE_UP(sq.sync_queue);
-		  return;
-	  }
-	if (sq.playing & AMI_PLAY_PLAYING)
-	  {
-		  /* We've just finished a frame */
-		  sq.count--;
-		  WAKE_UP(sq.write_queue);
-	  }
-	if (sq.playing & AMI_PLAY_LOADED)
-		/* Increase threshold: frame 1 is already being played */
-		minframes = 2;
-
-	/* Shift the flags */
-	sq.playing = (sq.playing << 1) & AMI_PLAY_MASK;
-
-	if (!sq.playing)
-		/* No frame is playing, disable audio DMA */
-		custom.dmacon = AMI_AUDIO_OFF;
-
-	if (sq.count >= minframes)
-		/* Try to play the next frame */
-		AmiPlay();
-
-	if (!sq.playing)
-		/* Nothing to play anymore.
-		   Wake up a process waiting for audio output to drain. */
-		WAKE_UP(sq.sync_queue);
+    if (!sq.playing)
+	/* No frame is playing, disable audio DMA */
+	custom.dmacon = AMI_AUDIO_OFF;
+
+    if (sq.count >= minframes)
+    	/* Try to play the next frame */
+	AmiPlay();
+
+    if (!sq.playing)
+	/* Nothing to play anymore.
+	   Wake up a process waiting for audio output to drain. */
+	WAKE_UP(sq.sync_queue);
 }
-#endif				/* CONFIG_AMIGA */
+#endif /* CONFIG_AMIGA */
 
 
 /*** Machine definitions *****************************************************/
 
 
 #ifdef CONFIG_ATARI
-static MACHINE  machTT =
-{
-	DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
+static MACHINE machTT = {
+    DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
 #ifdef MODULE
-	AtaIrqCleanUp,
-#endif				/* MODULE */
-   TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble,
-	AtaPlay
+    AtaIrqCleanUp,
+#endif /* MODULE */
+    TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble,
+    TTSetGain,
+    AtaPlay
 };
 
-static MACHINE  machFalcon =
-{
-	DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
+static MACHINE machFalcon = {
+    DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
 #ifdef MODULE
-	AtaIrqCleanUp,
-#endif				/* MODULE */
- FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass,
-	AtaSetTreble, AtaPlay
+    AtaIrqCleanUp,
+#endif /* MODULE */
+    FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass,
+    AtaSetTreble, NULL, AtaPlay
 };
-
-#endif				/* CONFIG_ATARI */
+#endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
-static MACHINE  machAmiga =
-{
-	DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
+static MACHINE machAmiga = {
+    DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
 #ifdef MODULE
-	AmiIrqCleanUp,
-#endif				/* MODULE */
-     AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble,
-	AmiPlay
+    AmiIrqCleanUp,
+#endif /* MODULE */
+    AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble,
+    NULL,
+    AmiPlay
 };
-
-#endif				/* CONFIG_AMIGA */
+#endif /* CONFIG_AMIGA */
 
 
 /*** Mid level stuff *********************************************************/
 
 
-static void
-sound_silence(void)
+static void sound_silence(void)
 {
-	/* update hardware settings one more */
-	(*sound.mach.init) ();
+    /* update hardware settings one more */
+    (*sound.mach.init)();
 
-	(*sound.mach.silence) ();
+    (*sound.mach.silence)();
 }
 
 
-static void
-sound_init(void)
+static void sound_init(void)
 {
-	(*sound.mach.init) ();
+    (*sound.mach.init)();
 }
 
 
-static int
-sound_set_format(int format)
+static int sound_set_format(int format)
 {
-	return (*sound.mach.setFormat) (format);
+    return(*sound.mach.setFormat)(format);
 }
 
 
-static int
-sound_set_speed(int speed)
+static int sound_set_speed(int speed)
 {
-	if (speed < 0)
-		return (sound.soft.speed);
+    if (speed < 0)
+	return(sound.soft.speed);
 
-	sound.soft.speed = speed;
-	(*sound.mach.init) ();
-	if (sound.minDev == SND_DEV_DSP)
-		sound.dsp.speed = sound.soft.speed;
+    sound.soft.speed = speed;
+    (*sound.mach.init)();
+    if (sound.minDev == SND_DEV_DSP)
+	sound.dsp.speed = sound.soft.speed;
 
-	return (sound.soft.speed);
+    return(sound.soft.speed);
 }
 
 
-static int
-sound_set_stereo(int stereo)
+static int sound_set_stereo(int stereo)
 {
-	if (stereo < 0)
-		return (sound.soft.stereo);
+    if (stereo < 0)
+	return(sound.soft.stereo);
 
-	stereo = !!stereo;	/* should be 0 or 1 now */
+    stereo = !!stereo;    /* should be 0 or 1 now */
 
-	sound.soft.stereo = stereo;
-	if (sound.minDev == SND_DEV_DSP)
-		sound.dsp.stereo = stereo;
-	(*sound.mach.init) ();
+    sound.soft.stereo = stereo;
+    if (sound.minDev == SND_DEV_DSP)
+	sound.dsp.stereo = stereo;
+    (*sound.mach.init)();
 
-	return (stereo);
+    return(stereo);
 }
 
 
-static int
-sound_set_volume(int volume)
+static int sound_set_volume(int volume)
 {
-	return (*sound.mach.setVolume) (volume);
+    return(*sound.mach.setVolume)(volume);
 }
 
 
 #ifdef CONFIG_ATARI
-static int
-sound_set_bass(int bass)
+static int sound_set_bass(int bass)
 {
-	return (sound.mach.setBass ? (*sound.mach.setBass) (bass) : 50);
+    return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
 }
-#endif				/* CONFIG_ATARI */
 
-
-static int
-sound_set_treble(int treble)
-{
-	return (sound.mach.setTreble ? (*sound.mach.setTreble) (treble) : 50);
+static int sound_set_gain(int gain)
+{
+    return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
+}
+#endif /* CONFIG_ATARI */
+
+
+static int sound_set_treble(int treble)
+{
+    return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
 }
 
 
-static long
-sound_copy_translate(const u_char * userPtr,
-		     unsigned long userCount,
-		     u_char frame[], long *frameUsed,
-		     long frameLeft)
-{
-	long            (*ct_func) (const u_char *, unsigned long, u_char *, long *, long) = NULL;
-
-	switch (sound.soft.format)
-	  {
-	  case AFMT_MU_LAW:
-		  ct_func = sound.trans->ct_ulaw;
-		  break;
-	  case AFMT_A_LAW:
-		  ct_func = sound.trans->ct_alaw;
-		  break;
-	  case AFMT_S8:
-		  ct_func = sound.trans->ct_s8;
-		  break;
-	  case AFMT_U8:
-		  ct_func = sound.trans->ct_u8;
-		  break;
-	  case AFMT_S16_BE:
-		  ct_func = sound.trans->ct_s16be;
-		  break;
-	  case AFMT_U16_BE:
-		  ct_func = sound.trans->ct_u16be;
-		  break;
-	  case AFMT_S16_LE:
-		  ct_func = sound.trans->ct_s16le;
-		  break;
-	  case AFMT_U16_LE:
-		  ct_func = sound.trans->ct_u16le;
-		  break;
-	  }
-	if (ct_func)
-		return (ct_func(userPtr, userCount, frame, frameUsed, frameLeft));
-	else
-		return (0);
+static long sound_copy_translate(const u_char *userPtr,
+				 unsigned long userCount,
+				 u_char frame[], long *frameUsed,
+				 long frameLeft)
+{
+    long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL;
+
+    switch (sound.soft.format) {
+	case AFMT_MU_LAW:
+	    ct_func = sound.trans->ct_ulaw;
+	    break;
+	case AFMT_A_LAW:
+	    ct_func = sound.trans->ct_alaw;
+	    break;
+	case AFMT_S8:
+	    ct_func = sound.trans->ct_s8;
+	    break;
+	case AFMT_U8:
+	    ct_func = sound.trans->ct_u8;
+	    break;
+	case AFMT_S16_BE:
+	    ct_func = sound.trans->ct_s16be;
+	    break;
+	case AFMT_U16_BE:
+	    ct_func = sound.trans->ct_u16be;
+	    break;
+	case AFMT_S16_LE:
+	    ct_func = sound.trans->ct_s16le;
+	    break;
+	case AFMT_U16_LE:
+	    ct_func = sound.trans->ct_u16le;
+	    break;
+    }
+    if (ct_func)
+	return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft));
+    else
+	return(0);
 }
 
 
@@ -2785,215 +2507,203 @@
 #define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3)
 
 
-static void
-mixer_init(void)
+static void mixer_init(void)
 {
-	mixer.busy = 0;
-	sound.treble = 0;
-	sound.bass = 0;
-	switch (sound.mach.type)
-	  {
+    mixer.busy = 0;
+    sound.treble = 0;
+    sound.bass = 0;
+    switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
-	  case DMASND_TT:
-		  atari_microwire_cmd(MW_LM1992_VOLUME(0));
-		  sound.volume_left = 0;
-		  atari_microwire_cmd(MW_LM1992_BALLEFT(0));
-		  sound.volume_right = 0;
-		  atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
-		  atari_microwire_cmd(MW_LM1992_TREBLE(0));
-		  atari_microwire_cmd(MW_LM1992_BASS(0));
-		  break;
-	  case DMASND_FALCON:
-		  sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
-		  sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
-		  break;
-#endif				/* CONFIG_ATARI */
+	case DMASND_TT:
+	    atari_microwire_cmd(MW_LM1992_VOLUME(0));
+	    sound.volume_left = 0;
+	    atari_microwire_cmd(MW_LM1992_BALLEFT(0));
+	    sound.volume_right = 0;
+	    atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
+	    atari_microwire_cmd(MW_LM1992_TREBLE(0));
+	    atari_microwire_cmd(MW_LM1992_BASS(0));
+	    break;
+	case DMASND_FALCON:
+	    sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
+	    sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
+	    break;
+#endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-	  case DMASND_AMIGA:
-		  sound.volume_left = 64;
-		  sound.volume_right = 64;
-		  custom.aud[0].audvol = sound.volume_left;
-		  custom.aud[3].audvol = 1;	/* For pseudo 14bit */
-		  custom.aud[1].audvol = sound.volume_right;
-		  custom.aud[2].audvol = 1;	/* For pseudo 14bit */
-		  sound.treble = 50;
-		  break;
-#endif				/* CONFIG_AMIGA */
-	  }
+	case DMASND_AMIGA:
+	    sound.volume_left = 64;
+	    sound.volume_right = 64;
+	    custom.aud[0].audvol = sound.volume_left;
+	    custom.aud[3].audvol = 1;			/* For pseudo 14bit */
+	    custom.aud[1].audvol = sound.volume_right;
+	    custom.aud[2].audvol = 1;			/* For pseudo 14bit */
+	    sound.treble = 50;
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
 }
 
 
-static int
-mixer_open(int open_mode)
+static int mixer_open(int open_mode)
 {
-	if (mixer.busy)
-		return (-EBUSY);
-	mixer.busy = 1;
-	return (0);
+    if (mixer.busy)
+	return(-EBUSY);
+    mixer.busy = 1;
+    return(0);
 }
 
 
-static int
-mixer_release(void)
+static int mixer_release(void)
 {
-	mixer.busy = 0;
-	return (0);
+    mixer.busy = 0;
+    return(0);
 }
 
 
-static int
-mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
-	    u_long arg)
+static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg)
 {
-	int             data;
-
-	switch (sound.mach.type)
-	  {
+    int data;
+    switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
-	  case DMASND_FALCON:
-		  switch (cmd)
-		    {
-		    case SOUND_MIXER_READ_DEVMASK:
-			    return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
-		    case SOUND_MIXER_READ_RECMASK:
-			    return (IOCTL_OUT(arg, SOUND_MASK_MIC));
-		    case SOUND_MIXER_READ_STEREODEVS:
-			    return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
-		    case SOUND_MIXER_READ_CAPS:
-			    return (IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT));
-		    case SOUND_MIXER_READ_VOLUME:
-			    return (IOCTL_OUT(arg,
-			       VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
-					      VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8));
-		    case SOUND_MIXER_WRITE_MIC:
-			    IOCTL_IN(arg, data);
-			    tt_dmasnd.input_gain =
-				RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
-				RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
-			    /* fall thru, return set value */
-		    case SOUND_MIXER_READ_MIC:
-			    return (IOCTL_OUT(arg,
-					      RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
-					      RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8));
-		    case SOUND_MIXER_READ_SPEAKER:
-			    {
-				    int             porta;
-
-				    cli();
-				    sound_ym.rd_data_reg_sel = 14;
-				    porta = sound_ym.rd_data_reg_sel;
-				    sti();
-				    return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-			    }
-		    case SOUND_MIXER_WRITE_VOLUME:
-			    IOCTL_IN(arg, data);
-			    return (IOCTL_OUT(arg, sound_set_volume(data)));
-		    case SOUND_MIXER_WRITE_SPEAKER:
-			    {
-				    int             porta;
-
-				    IOCTL_IN(arg, data);
-				    cli();
-				    sound_ym.rd_data_reg_sel = 14;
-				    porta = (sound_ym.rd_data_reg_sel & ~0x40) |
-					(data < 50 ? 0x40 : 0);
-				    sound_ym.wd_data = porta;
-				    sti();
-				    return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-			    }
-		    }
-		  break;
-
-	  case DMASND_TT:
-		  switch (cmd)
-		    {
-		    case SOUND_MIXER_READ_DEVMASK:
-			    return (IOCTL_OUT(arg,
-					      SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
-			      ((atari_mch_cookie >> 16) == ATARI_MCH_TT ?
-			       SOUND_MASK_SPEAKER : 0)));
-		    case SOUND_MIXER_READ_RECMASK:
-			    return (IOCTL_OUT(arg, 0));
-		    case SOUND_MIXER_READ_STEREODEVS:
-			    return (IOCTL_OUT(arg, SOUND_MASK_VOLUME));
-		    case SOUND_MIXER_READ_VOLUME:
-			    return (IOCTL_OUT(arg,
-				VOLUME_DB_TO_VOXWARE(sound.volume_left) |
-					      (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)));
-		    case SOUND_MIXER_READ_BASS:
-			    return (IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass)));
-		    case SOUND_MIXER_READ_TREBLE:
-			    return (IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble)));
-		    case SOUND_MIXER_READ_SPEAKER:
-			    {
-				    int             porta;
-
-				    if ((atari_mch_cookie >> 16) == ATARI_MCH_TT)
-				      {
-					      cli();
-					      sound_ym.rd_data_reg_sel = 14;
-					      porta = sound_ym.rd_data_reg_sel;
-					      sti();
-					      return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-				    } else
-					    return (-EINVAL);
-			    }
-		    case SOUND_MIXER_WRITE_VOLUME:
-			    IOCTL_IN(arg, data);
-			    return (IOCTL_OUT(arg, sound_set_volume(data)));
-		    case SOUND_MIXER_WRITE_BASS:
-			    IOCTL_IN(arg, data);
-			    return (IOCTL_OUT(arg, sound_set_bass(data)));
-		    case SOUND_MIXER_WRITE_TREBLE:
-			    IOCTL_IN(arg, data);
-			    return (IOCTL_OUT(arg, sound_set_treble(data)));
-		    case SOUND_MIXER_WRITE_SPEAKER:
-			    if ((atari_mch_cookie >> 16) == ATARI_MCH_TT)
-			      {
-				      int             porta;
-
-				      IOCTL_IN(arg, data);
-				      cli();
-				      sound_ym.rd_data_reg_sel = 14;
-				      porta = (sound_ym.rd_data_reg_sel & ~0x40) |
-					  (data < 50 ? 0x40 : 0);
-				      sound_ym.wd_data = porta;
-				      sti();
-				      return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-			    } else
-				    return (-EINVAL);
-		    }
-		  break;
-#endif				/* CONFIG_ATARI */
+	case DMASND_FALCON:
+	    switch (cmd) {
+		case SOUND_MIXER_READ_DEVMASK:
+		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+		case SOUND_MIXER_READ_RECMASK:
+		    return(IOCTL_OUT(arg, SOUND_MASK_MIC));
+		case SOUND_MIXER_READ_STEREODEVS:
+		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
+		case SOUND_MIXER_READ_CAPS:
+		    return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT));
+		case SOUND_MIXER_READ_VOLUME:
+		    return(IOCTL_OUT(arg,
+			VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
+			VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8));
+		case SOUND_MIXER_WRITE_MIC:
+		    IOCTL_IN(arg, data);
+		    tt_dmasnd.input_gain =
+			RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
+			RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
+		    /* fall thru, return set value */
+		case SOUND_MIXER_READ_MIC:
+		    return(IOCTL_OUT(arg,
+			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
+			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8));
+		case SOUND_MIXER_READ_SPEAKER:
+		    {
+			int porta;
+			cli();
+			sound_ym.rd_data_reg_sel = 14;
+			porta = sound_ym.rd_data_reg_sel;
+			sti();
+			return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+		    }
+		case SOUND_MIXER_WRITE_VOLUME:
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_volume(data)));
+		case SOUND_MIXER_WRITE_SPEAKER:
+		    {
+			int porta;
+			IOCTL_IN(arg, data);
+			cli();
+			sound_ym.rd_data_reg_sel = 14;
+			porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+				(data < 50 ? 0x40 : 0);
+			sound_ym.wd_data = porta;
+			sti();
+			return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+		    }
+	    }
+	    break;
+
+	case DMASND_TT:
+	    switch (cmd) {
+		case SOUND_MIXER_READ_DEVMASK:
+		    return(IOCTL_OUT(arg,
+			SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
+			(MACH_IS_TT ? SOUND_MASK_SPEAKER : 0)));
+		case SOUND_MIXER_READ_RECMASK:
+		    return(IOCTL_OUT(arg, 0));
+		case SOUND_MIXER_READ_STEREODEVS:
+		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+		case SOUND_MIXER_READ_VOLUME:
+		    return(IOCTL_OUT(arg,
+			VOLUME_DB_TO_VOXWARE(sound.volume_left) |
+			(VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)));
+		case SOUND_MIXER_READ_BASS:
+		    return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass)));
+		case SOUND_MIXER_READ_TREBLE:
+		    return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble)));
+		case SOUND_MIXER_READ_OGAIN:
+		    return(IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain)));
+		case SOUND_MIXER_READ_SPEAKER:
+		    {
+			int porta;
+			if (MACH_IS_TT) {
+			    cli();
+			    sound_ym.rd_data_reg_sel = 14;
+			    porta = sound_ym.rd_data_reg_sel;
+			    sti();
+			    return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+			} else
+			    return(-EINVAL);
+		    }
+		case SOUND_MIXER_WRITE_VOLUME:
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_volume(data)));
+		case SOUND_MIXER_WRITE_BASS:
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_bass(data)));
+		case SOUND_MIXER_WRITE_TREBLE:
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_treble(data)));
+		case SOUND_MIXER_WRITE_OGAIN:
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_gain(data)));
+		case SOUND_MIXER_WRITE_SPEAKER:
+		    if (MACH_IS_TT) {
+			int porta;
+			IOCTL_IN(arg, data);
+			cli();
+			sound_ym.rd_data_reg_sel = 14;
+			porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+				(data < 50 ? 0x40 : 0);
+			sound_ym.wd_data = porta;
+			sti();
+			return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+		    } else
+			return(-EINVAL);
+	    }
+	    break;
+#endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
-	  case DMASND_AMIGA:
-		  switch (cmd)
-		    {
-		    case SOUND_MIXER_READ_DEVMASK:
-			    return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
-		    case SOUND_MIXER_READ_RECMASK:
-			    return (IOCTL_OUT(arg, 0));
-		    case SOUND_MIXER_READ_STEREODEVS:
-			    return (IOCTL_OUT(arg, SOUND_MASK_VOLUME));
-		    case SOUND_MIXER_READ_VOLUME:
-			    return (IOCTL_OUT(arg,
-			       VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
-					      VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
-		    case SOUND_MIXER_WRITE_VOLUME:
-			    IOCTL_IN(arg, data);
-			    return (IOCTL_OUT(arg, sound_set_volume(data)));
-		    case SOUND_MIXER_READ_TREBLE:
-			    return (IOCTL_OUT(arg, sound.treble));
-		    case SOUND_MIXER_WRITE_TREBLE:
-			    IOCTL_IN(arg, data);
-			    return (IOCTL_OUT(arg, sound_set_treble(data)));
-		    }
-		  break;
-#endif				/* CONFIG_AMIGA */
-	  }
+	case DMASND_AMIGA:
+	    switch (cmd) {
+		case SOUND_MIXER_READ_DEVMASK:
+		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
+		case SOUND_MIXER_READ_RECMASK:
+		    return(IOCTL_OUT(arg, 0));
+		case SOUND_MIXER_READ_STEREODEVS:
+		    return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+		case SOUND_MIXER_READ_VOLUME:
+		    return(IOCTL_OUT(arg,
+			VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
+			VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+		case SOUND_MIXER_WRITE_VOLUME:
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_volume(data)));
+		case SOUND_MIXER_READ_TREBLE:
+		    return(IOCTL_OUT(arg, sound.treble));
+		case SOUND_MIXER_WRITE_TREBLE:
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_treble(data)));
+	    }
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
 
-	return (-EINVAL);
+    return(-EINVAL);
 }
 
 
@@ -3003,216 +2713,198 @@
  */
 
 
-static void
-sq_init(int numBufs, int bufSize, char **buffers)
+static void sq_init(int numBufs, int bufSize, char **buffers)
 {
-	sq.max_count = numBufs;
-	sq.block_size = bufSize;
-	sq.buffers = buffers;
-
-	sq.front = sq.count = 0;
-	sq.rear = -1;
-	sq.write_queue = sq.open_queue = sq.sync_queue = 0;
-	sq.busy = 0;
-	sq.syncing = 0;
+    sq.max_count = numBufs;
+    sq.block_size = bufSize;
+    sq.buffers = buffers;
+
+    sq.front = sq.count = 0;
+    sq.rear = -1;
+    sq.write_queue = sq.open_queue = sq.sync_queue = 0;
+    sq.busy = 0;
+    sq.syncing = 0;
 
-	sq.playing = 0;
+    sq.playing = 0;
 
 #ifdef CONFIG_ATARI
-	sq.ignore_int = 0;
-#endif				/* CONFIG_ATARI */
+    sq.ignore_int = 0;
+#endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-	sq.block_size_half = sq.block_size >> 1;
-	sq.block_size_quarter = sq.block_size_half >> 1;
-#endif				/* CONFIG_AMIGA */
+    sq.block_size_half = sq.block_size>>1;
+    sq.block_size_quarter = sq.block_size_half>>1;
+#endif /* CONFIG_AMIGA */
+
+    sound_silence();
+
+    /* whatever you like as startup mode for /dev/dsp,
+     * (/dev/audio hasn't got a startup mode). note that
+     * once changed a new open() will *not* restore these!
+     */
+    sound.dsp.format = AFMT_S8;
+    sound.dsp.stereo = 0;
+    sound.dsp.size = 8;
 
-	sound_silence();
-
-	/* whatever you like as startup mode for /dev/dsp,
-	 * (/dev/audio hasn't got a startup mode). note that
-	 * once changed a new open() will *not* restore these!
-	 */
-	sound.dsp.format = AFMT_S8;
-	sound.dsp.stereo = 0;
-	sound.dsp.size = 8;
-
-	/* set minimum rate possible without expanding */
-	switch (sound.mach.type)
-	  {
+    /* set minimum rate possible without expanding */
+    switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
-	  case DMASND_TT:
-		  sound.dsp.speed = 6258;
-		  break;
-	  case DMASND_FALCON:
-		  sound.dsp.speed = 8195;
-		  break;
-#endif				/* CONFIG_ATARI */
+	case DMASND_TT:
+	    sound.dsp.speed = 6258;
+	    break;
+	case DMASND_FALCON:
+	    sound.dsp.speed = 8195;
+	    break;
+#endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-	  case DMASND_AMIGA:
-		  sound.dsp.speed = 8000;
-		  break;
-#endif				/* CONFIG_AMIGA */
-	  }
+	case DMASND_AMIGA:
+	    sound.dsp.speed = 8000;
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
 
-	/* before the first open to /dev/dsp this wouldn't be set */
-	sound.soft = sound.dsp;
-	sound.hard = sound.dsp;
+    /* before the first open to /dev/dsp this wouldn't be set */
+    sound.soft = sound.dsp;
+    sound.hard = sound.dsp;
 }
 
 
-static void
-sq_play(void)
+static void sq_play(void)
 {
-	(*sound.mach.play) ();
+    (*sound.mach.play)();
 }
 
 
 /* ++TeSche: radically changed this one too */
 
-static long
-sq_write(const char *src, unsigned long uLeft)
+static long sq_write(const char *src, unsigned long uLeft)
 {
-	long            uWritten = 0;
-	u_char         *dest;
-	long            uUsed, bUsed, bLeft;
-
-	/* ++TeSche: Is something like this necessary?
-	 * Hey, that's an honest question! Or does any other part of the
-	 * filesystem already checks this situation? I really don't know.
-	 */
-	if (uLeft == 0)
-		return (0);
+    long uWritten = 0;
+    u_char *dest;
+    long uUsed, bUsed, bLeft;
+
+    /* ++TeSche: Is something like this necessary?
+     * Hey, that's an honest question! Or does any other part of the
+     * filesystem already checks this situation? I really don't know.
+     */
+    if (uLeft == 0)
+	return(0);
+
+    /* The interrupt doesn't start to play the last, incomplete frame.
+     * Thus we can append to it without disabling the interrupts! (Note
+     * also that sq.rear isn't affected by the interrupt.)
+     */
+
+    if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
+	dest = sq_block_address(sq.rear);
+	bUsed = sq.rear_size;
+	uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
+	src += uUsed;
+	uWritten += uUsed;
+	uLeft -= uUsed;
+	sq.rear_size = bUsed;
+    }
+
+    do {
+	while (sq.count == sq.max_count) {
+	    sq_play();
+	    if (NON_BLOCKING(sq.open_mode))
+		return(uWritten > 0 ? uWritten : -EAGAIN);
+	    SLEEP(sq.write_queue, ONE_SECOND);
+	    if (SIGNAL_RECEIVED)
+		return(uWritten > 0 ? uWritten : -EINTR);
+	}
 
-	/* The interrupt doesn't start to play the last, incomplete frame.
-	 * Thus we can append to it without disabling the interrupts! (Note
-	 * also that sq.rear isn't affected by the interrupt.)
+	/* Here, we can avoid disabling the interrupt by first
+	 * copying and translating the data, and then updating
+	 * the sq variables. Until this is done, the interrupt
+	 * won't see the new frame and we can work on it
+	 * undisturbed.
 	 */
 
-	if (sq.count > 0 && (bLeft = sq.block_size - sq.rear_size) > 0)
-	  {
-		  dest = sq_block_address(sq.rear);
-		  bUsed = sq.rear_size;
-		  uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-		  src += uUsed;
-		  uWritten += uUsed;
-		  uLeft -= uUsed;
-		  sq.rear_size = bUsed;
-	  }
-	do
-	  {
-		  while (sq.count == sq.max_count)
-		    {
-			    sq_play();
-			    if (NON_BLOCKING(sq.open_mode))
-				    return (uWritten > 0 ? uWritten : -EAGAIN);
-			    SLEEP(sq.write_queue, ONE_SECOND);
-			    if (SIGNAL_RECEIVED)
-				    return (uWritten > 0 ? uWritten : -EINTR);
-		    }
-
-		  /* Here, we can avoid disabling the interrupt by first
-		   * copying and translating the data, and then updating
-		   * the sq variables. Until this is done, the interrupt
-		   * won't see the new frame and we can work on it
-		   * undisturbed.
-		   */
-
-		  dest = sq_block_address((sq.rear + 1) % sq.max_count);
-		  bUsed = 0;
-		  bLeft = sq.block_size;
-		  uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-		  src += uUsed;
-		  uWritten += uUsed;
-		  uLeft -= uUsed;
-		  if (bUsed)
-		    {
-			    sq.rear = (sq.rear + 1) % sq.max_count;
-			    sq.rear_size = bUsed;
-			    sq.count++;
-		    }
-	  }
-	while (bUsed);		/* uUsed may have been 0 */
+	dest = sq_block_address((sq.rear+1) % sq.max_count);
+	bUsed = 0;
+	bLeft = sq.block_size;
+	uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
+	src += uUsed;
+	uWritten += uUsed;
+	uLeft -= uUsed;
+	if (bUsed) {
+	    sq.rear = (sq.rear+1) % sq.max_count;
+	    sq.rear_size = bUsed;
+	    sq.count++;
+	}
+    } while (bUsed);   /* uUsed may have been 0 */
 
-	sq_play();
+    sq_play();
 
-	return (uWritten);
+    return(uWritten);
 }
 
 
-static int
-sq_open(int open_mode)
+static int sq_open(int open_mode)
 {
-	if (sq.busy)
-	  {
-		  if (NON_BLOCKING(open_mode))
-			  return (-EBUSY);
-		  while (sq.busy)
-		    {
-			    SLEEP(sq.open_queue, ONE_SECOND);
-			    if (SIGNAL_RECEIVED)
-				    return (-EINTR);
-		    }
-	  }
-	sq.open_mode = open_mode;
-	sq.busy = 1;
+    if (sq.busy) {
+	if (NON_BLOCKING(open_mode))
+	    return(-EBUSY);
+	while (sq.busy) {
+	    SLEEP(sq.open_queue, ONE_SECOND);
+	    if (SIGNAL_RECEIVED)
+		return(-EINTR);
+	}
+    }
+    sq.open_mode = open_mode;
+    sq.busy = 1;
 #ifdef CONFIG_ATARI
-	sq.ignore_int = 1;
-#endif				/* CONFIG_ATARI */
-	return (0);
+    sq.ignore_int = 1;
+#endif /* CONFIG_ATARI */
+    return(0);
 }
 
 
-static void
-sq_reset(void)
+static void sq_reset(void)
 {
-	sound_silence();
-	sq.playing = 0;
-	sq.count = 0;
-	sq.front = (sq.rear + 1) % sq.max_count;
+    sound_silence();
+    sq.playing = 0;
+    sq.count = 0;
+    sq.front = (sq.rear+1) % sq.max_count;
 }
 
 
-static int
-sq_sync(void)
+static int sq_sync(void)
 {
-	int             rc = 0;
+    int rc = 0;
 
-	sq.syncing = 1;
-	sq_play();		/* there may be an incomplete frame waiting */
+    sq.syncing = 1;
+    sq_play();	/* there may be an incomplete frame waiting */
 
-	while (sq.playing)
-	  {
-		  SLEEP(sq.sync_queue, ONE_SECOND);
-		  if (SIGNAL_RECEIVED)
-		    {
-			    /* While waiting for audio output to drain, an interrupt occurred.
-			       Stop audio output immediately and clear the queue. */
-			    sq_reset();
-			    rc = -EINTR;
-			    break;
-		    }
-	  }
+    while (sq.playing) {
+	SLEEP(sq.sync_queue, ONE_SECOND);
+	if (SIGNAL_RECEIVED) {
+	    /* While waiting for audio output to drain, an interrupt occurred.
+	       Stop audio output immediately and clear the queue. */
+	    sq_reset();
+	    rc = -EINTR;
+	    break;
+	}
+    }
 
-	sq.syncing = 0;
-	return (rc);
+    sq.syncing = 0;
+    return(rc);
 }
 
 
-static int
-sq_release(void)
+static int sq_release(void)
 {
-	int             rc = 0;
-
-	if (sq.busy)
-	  {
-		  rc = sq_sync();
-		  sq.busy = 0;
-		  WAKE_UP(sq.open_queue);
-		  /* Wake up a process waiting for the queue being released.
-		     Note: There may be several processes waiting for a call to open()
-		     returning. */
-	  }
-	return (rc);
+    int rc = 0;
+    if (sq.busy) {
+	rc = sq_sync();
+	sq.busy = 0;
+	WAKE_UP(sq.open_queue);
+	/* Wake up a process waiting for the queue being released.
+	   Note: There may be several processes waiting for a call to open()
+		 returning. */
+    }
+    return(rc);
 }
 
 
@@ -3222,136 +2914,128 @@
  */
 
 
-static void
-state_init(void)
+static void state_init(void)
 {
-	state.busy = 0;
+    state.busy = 0;
 }
 
 
 /* state.buf should not overflow! */
 
-static int
-state_open(int open_mode)
+static int state_open(int open_mode)
 {
-	char           *buffer = state.buf, *mach = "";
-	int             len = 0;
+    char *buffer = state.buf, *mach = "";
+    int len = 0;
 
-	if (state.busy)
-		return (-EBUSY);
+    if (state.busy)
+	return(-EBUSY);
 
-	state.ptr = 0;
-	state.busy = 1;
+    state.ptr = 0;
+    state.busy = 1;
 
-	switch (sound.mach.type)
-	  {
+    switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
-	  case DMASND_TT:
-	  case DMASND_FALCON:
-		  mach = "Atari ";
-		  break;
-#endif				/* CONFIG_ATARI */
+	case DMASND_TT:
+	case DMASND_FALCON:
+	    mach = "Atari ";
+	    break;
+#endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-	  case DMASND_AMIGA:
-		  mach = "Amiga ";
-		  break;
-#endif				/* CONFIG_AMIGA */
-	  }
-	len += sprintf(buffer + len, "%sDMA sound driver:\n", mach);
-
-	len += sprintf(buffer + len, "\tsound.format = 0x%x", sound.soft.format);
-	switch (sound.soft.format)
-	  {
-	  case AFMT_MU_LAW:
-		  len += sprintf(buffer + len, " (mu-law)");
-		  break;
-	  case AFMT_A_LAW:
-		  len += sprintf(buffer + len, " (A-law)");
-		  break;
-	  case AFMT_U8:
-		  len += sprintf(buffer + len, " (unsigned 8 bit)");
-		  break;
-	  case AFMT_S8:
-		  len += sprintf(buffer + len, " (signed 8 bit)");
-		  break;
-	  case AFMT_S16_BE:
-		  len += sprintf(buffer + len, " (signed 16 bit big)");
-		  break;
-	  case AFMT_U16_BE:
-		  len += sprintf(buffer + len, " (unsigned 16 bit big)");
-		  break;
-	  case AFMT_S16_LE:
-		  len += sprintf(buffer + len, " (signed 16 bit little)");
-		  break;
-	  case AFMT_U16_LE:
-		  len += sprintf(buffer + len, " (unsigned 16 bit little)");
-		  break;
-	  }
-	len += sprintf(buffer + len, "\n");
-	len += sprintf(buffer + len, "\tsound.speed = %dHz (phys. %dHz)\n",
-		       sound.soft.speed, sound.hard.speed);
-	len += sprintf(buffer + len, "\tsound.stereo = 0x%x (%s)\n",
-	       sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
-	switch (sound.mach.type)
-	  {
+	case DMASND_AMIGA:
+	    mach = "Amiga ";
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
+    len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
+
+    len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
+    switch (sound.soft.format) {
+	case AFMT_MU_LAW:
+	    len += sprintf(buffer+len, " (mu-law)");
+	    break;
+	case AFMT_A_LAW:
+	    len += sprintf(buffer+len, " (A-law)");
+	    break;
+	case AFMT_U8:
+	    len += sprintf(buffer+len, " (unsigned 8 bit)");
+	    break;
+	case AFMT_S8:
+	    len += sprintf(buffer+len, " (signed 8 bit)");
+	    break;
+	case AFMT_S16_BE:
+	    len += sprintf(buffer+len, " (signed 16 bit big)");
+	    break;
+	case AFMT_U16_BE:
+	    len += sprintf(buffer+len, " (unsigned 16 bit big)");
+	    break;
+	case AFMT_S16_LE:
+	    len += sprintf(buffer+len, " (signed 16 bit little)");
+	    break;
+	case AFMT_U16_LE:
+	    len += sprintf(buffer+len, " (unsigned 16 bit little)");
+	    break;
+    }
+    len += sprintf(buffer+len, "\n");
+    len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
+		   sound.soft.speed, sound.hard.speed);
+    len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+		   sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
+    switch (sound.mach.type) {
 #ifdef CONFIG_ATARI
-	  case DMASND_TT:
-		  len += sprintf(buffer + len, "\tsound.volume_left = %ddB [-40...0]\n",
-				 sound.volume_left);
-		  len += sprintf(buffer + len, "\tsound.volume_right = %ddB [-40...0]\n",
-				 sound.volume_right);
-		  len += sprintf(buffer + len, "\tsound.bass = %ddB [-12...+12]\n",
-				 sound.bass);
-		  len += sprintf(buffer + len, "\tsound.treble = %ddB [-12...+12]\n",
-				 sound.treble);
-		  break;
-	  case DMASND_FALCON:
-		  len += sprintf(buffer + len, "\tsound.volume_left = %ddB [-22.5...0]\n",
-				 sound.volume_left);
-		  len += sprintf(buffer + len, "\tsound.volume_right = %ddB [-22.5...0]\n",
-				 sound.volume_right);
-		  break;
-#endif				/* CONFIG_ATARI */
+	case DMASND_TT:
+	    len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
+			   sound.volume_left);
+	    len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
+			   sound.volume_right);
+	    len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
+			   sound.bass);
+	    len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
+			   sound.treble);
+	    break;
+	case DMASND_FALCON:
+	    len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
+			   sound.volume_left);
+	    len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
+			   sound.volume_right);
+	    break;
+#endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-	  case DMASND_AMIGA:
-		  len += sprintf(buffer + len, "\tsound.volume_left = %d [0...64]\n",
-				 sound.volume_left);
-		  len += sprintf(buffer + len, "\tsound.volume_right = %d [0...64]\n",
-				 sound.volume_right);
-		  break;
-#endif				/* CONFIG_AMIGA */
-	  }
-	len += sprintf(buffer + len, "\tsq.block_size = %d sq.max_count = %d\n",
-		       sq.block_size, sq.max_count);
-	len += sprintf(buffer + len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
-		       sq.rear_size);
-	len += sprintf(buffer + len, "\tsq.playing = %d sq.syncing = %d\n",
-		       sq.playing, sq.syncing);
-	state.len = len;
-	return (0);
+	case DMASND_AMIGA:
+	    len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
+			   sound.volume_left);
+	    len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
+			   sound.volume_right);
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
+    len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d\n",
+		   sq.block_size, sq.max_count);
+    len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
+		   sq.rear_size);
+    len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
+		   sq.playing, sq.syncing);
+    state.len = len;
+    return(0);
 }
 
 
-static int
-state_release(void)
-{
-	state.busy = 0;
-	return (0);
+static int state_release(void)
+{
+    state.busy = 0;
+    return(0);
 }
 
 
-static long
-state_read(char *dest, unsigned long count)
-{
-	int             n = state.len - state.ptr;
-
-	if (n > count)
-		n = count;
-	if (n <= 0)
-		return (0);
-	copy_to_user(dest, &state.buf[state.ptr], n);
-	state.ptr += n;
-	return (n);
+static long state_read(char *dest, unsigned long count)
+{
+    int n = state.len-state.ptr;
+    if (n > count)
+	n = count;
+    if (n <= 0)
+	return(0);
+    copy_to_user(dest, &state.buf[state.ptr], n);
+    state.ptr += n;
+    return(n);
 }
 
 
@@ -3359,241 +3043,232 @@
 /*** High level stuff ********************************************************/
 
 
-static int
-sound_open(struct inode *inode, struct file *file)
+static int sound_open(struct inode *inode, struct file *file)
 {
-	int             dev = MINOR(inode->i_rdev) & 0x0f;
-	int             rc = 0;
+    int dev = MINOR(inode->i_rdev) & 0x0f;
+    int rc = 0;
 
-	switch (dev)
-	  {
-	  case SND_DEV_STATUS:
-		  rc = state_open(file->f_flags);
-		  break;
-	  case SND_DEV_CTL:
-		  rc = mixer_open(file->f_flags);
-		  break;
-	  case SND_DEV_DSP:
-	  case SND_DEV_AUDIO:
-		  rc = sq_open(file->f_flags);
-		  if (rc == 0)
-		    {
-			    sound.minDev = dev;
-			    sound.soft = sound.dsp;
-			    sound.hard = sound.dsp;
-			    sound_init();
-			    if (dev == SND_DEV_AUDIO)
-			      {
-				      sound_set_speed(8000);
-				      sound_set_stereo(0);
-				      sound_set_format(AFMT_MU_LAW);
-			      }
-		    }
-		  break;
-	  default:
-		  rc = -ENXIO;
-	  }
+    switch (dev) {
+	case SND_DEV_STATUS:
+	    rc = state_open(file->f_flags);
+	    break;
+	case SND_DEV_CTL:
+	    rc = mixer_open(file->f_flags);
+	    break;
+	case SND_DEV_DSP:
+	case SND_DEV_AUDIO:
+	    rc = sq_open(file->f_flags);
+	    if (rc == 0) {
+		sound.minDev = dev;
+		sound.soft = sound.dsp;
+		sound.hard = sound.dsp;
+		sound_init();
+		if (dev == SND_DEV_AUDIO) {
+		    sound_set_speed(8000);
+		    sound_set_stereo(0);
+		    sound_set_format(AFMT_MU_LAW);
+		}
+	    }
+	    break;
+	default:
+	    rc = -ENXIO;
+    }
 #ifdef MODULE
-	if (rc >= 0)
-		MOD_INC_USE_COUNT;
+    if (rc >= 0)
+	MOD_INC_USE_COUNT;
 #endif
-	return (rc);
+    return(rc);
 }
 
 
-static int
-sound_fsync(struct inode *inode, struct file *filp)
+static int sound_fsync(struct file *filp, struct dentry *dentry)
 {
-	int             dev = MINOR(inode->i_rdev) & 0x0f;
+    int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f;
 
-	switch (dev)
-	  {
-	  case SND_DEV_STATUS:
-	  case SND_DEV_CTL:
-		  return (0);
-	  case SND_DEV_DSP:
-	  case SND_DEV_AUDIO:
-		  return (sq_sync());
-	  default:
-		  return (unknown_minor_dev("sound_fsync", dev));
-	  }
+    switch (dev) {
+	case SND_DEV_STATUS:
+	case SND_DEV_CTL:
+	    return(0);
+	case SND_DEV_DSP:
+	case SND_DEV_AUDIO:
+	    return(sq_sync());
+	default:
+	    return(unknown_minor_dev("sound_fsync", dev));
+    }
 }
 
 
-static void
-sound_release(struct inode *inode, struct file *file)
-{
-	int             dev = MINOR(inode->i_rdev);
-
-	switch (dev & 0x0f)
-	  {
-	  case SND_DEV_STATUS:
-		  state_release();
-		  break;
-	  case SND_DEV_CTL:
-		  mixer_release();
-		  break;
-	  case SND_DEV_DSP:
-	  case SND_DEV_AUDIO:
-		  sq_release();
-		  sound.soft = sound.dsp;
-		  sound.hard = sound.dsp;
-		  sound_silence();
-		  break;
-	  default:
-		  unknown_minor_dev("sound_release", dev);
-		  return;
-	  }
+static int sound_release(struct inode *inode, struct file *file)
+{
+    int dev = MINOR(inode->i_rdev);
+
+    switch (dev & 0x0f) {
+	case SND_DEV_STATUS:
+	    state_release();
+	    break;
+	case SND_DEV_CTL:
+	    mixer_release();
+	    break;
+	case SND_DEV_DSP:
+	case SND_DEV_AUDIO:
+	    sq_release();
+	    sound.soft = sound.dsp;
+	    sound.hard = sound.dsp;
+	    sound_silence();
+	    break;
+	default:
+	    return unknown_minor_dev("sound_release", dev);
+    }
 #ifdef MODULE
-	MOD_DEC_USE_COUNT;
+    MOD_DEC_USE_COUNT;
 #endif
+    return 0;
 }
 
 
-static long long
-sound_lseek(struct inode *inode, struct file *file,
-	    long long offset, int orig)
+static long long sound_lseek(struct file *file, long long offset, int orig)
 {
-	return -ESPIPE;
+    return -ESPIPE;
 }
 
 
-static ssize_t sound_read(struct file *file, char *buf, szie_t count, loff_t *ppos)
+static ssize_t sound_read(struct file *file, char *buf, size_t count,
+			  loff_t *ppos)
 {
-	int             dev = MINOR(file->f_dentry->d_inode->i_rdev);
+    struct inode *inode = file->f_dentry->d_inode;
+    int dev = MINOR(inode->i_rdev);
 
-	switch (dev & 0x0f)
-	{
-		case SND_DEV_STATUS:
-			return (state_read(buf, count));
-		case SND_DEV_CTL:
-		case SND_DEV_DSP:
-		case SND_DEV_AUDIO:
-			return (-EPERM);
-		default:
-			return (unknown_minor_dev("sound_read", dev));
-	}
+    switch (dev & 0x0f) {
+	case SND_DEV_STATUS:
+	    return(state_read(buf, count));
+	case SND_DEV_CTL:
+	case SND_DEV_DSP:
+	case SND_DEV_AUDIO:
+	    return(-EPERM);
+	default:
+	    return(unknown_minor_dev("sound_read", dev));
+    }
 }
 
 
-static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+static ssize_t sound_write(struct file *file, const char *buf, size_t count,
+			   loff_t *ppos)
 {
-	int             dev = MINOR(file->f_dentry->d_inode->i_rdev);
+    struct inode *inode = file->f_dentry->d_inode;
+    int dev = MINOR(inode->i_rdev);
 
-	switch (dev & 0x0f)
-	{
-		case SND_DEV_STATUS:
-		case SND_DEV_CTL:
-			return (-EPERM);
-		case SND_DEV_DSP:
-		case SND_DEV_AUDIO:
-			return (sq_write(buf, count));
-		default:
-			return (unknown_minor_dev("sound_write", dev));
-	}
+    switch (dev & 0x0f) {
+	case SND_DEV_STATUS:
+	case SND_DEV_CTL:
+	    return(-EPERM);
+	case SND_DEV_DSP:
+	case SND_DEV_AUDIO:
+	    return(sq_write(buf, count));
+	default:
+	    return(unknown_minor_dev("sound_write", dev));
+    }
 }
 
 
 static int unknown_minor_dev(char *fname, int dev)
 {
-	/* printk("%s: Unknown minor device %d\n", fname, dev); */
-	return (-ENXIO);
+    /* printk("%s: Unknown minor device %d\n", fname, dev); */
+    return(-ENXIO);
 }
 
 
-static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)
+static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg)
 {
-	int dev = MINOR(inode->i_rdev);
-	u_long fmt;
-	int data;
-
-	switch (dev & 0x0f)
-	{
-		case SND_DEV_STATUS:
-			return (-EPERM);
-		case SND_DEV_CTL:
-			return (mixer_ioctl(inode, file, cmd, arg));
-		case SND_DEV_AUDIO:
-		case SND_DEV_DSP:
-			switch (cmd)
-			{
-				case SNDCTL_DSP_RESET:
-					sq_reset();
-					return (0);
-				case SNDCTL_DSP_POST:
-				case SNDCTL_DSP_SYNC:
-					return (sound_fsync(inode, file));
-
-					/* ++TeSche: before changing any of these it's probably wise to
-			 		 * wait until sound playing has settled down
-			 		 */
-				case SNDCTL_DSP_SPEED:
-					sound_fsync(inode, file);
-					IOCTL_IN(arg, data);
-					return (IOCTL_OUT(arg, sound_set_speed(data)));
-				case SNDCTL_DSP_STEREO:
-					sound_fsync(inode, file);
-					IOCTL_IN(arg, data);
-					return (IOCTL_OUT(arg, sound_set_stereo(data)));
-				case SOUND_PCM_WRITE_CHANNELS:
-					sound_fsync(inode, file);
-					IOCTL_IN(arg, data);
-					return (IOCTL_OUT(arg, sound_set_stereo(data - 1) + 1));
-				case SNDCTL_DSP_SETFMT:
-					sound_fsync(inode, file);
-					IOCTL_IN(arg, data);
-					return (IOCTL_OUT(arg, sound_set_format(data)));
-				case SNDCTL_DSP_GETFMTS:
-					fmt = 0;
-					if (sound.trans)
-					{
-						if (sound.trans->ct_ulaw)
-							fmt |= AFMT_MU_LAW;
-						if (sound.trans->ct_alaw)
-							fmt |= AFMT_A_LAW;
-						if (sound.trans->ct_s8)
-							fmt |= AFMT_S8;
-						if (sound.trans->ct_u8)
-							fmt |= AFMT_U8;
-						if (sound.trans->ct_s16be)
-							fmt |= AFMT_S16_BE;
-						if (sound.trans->ct_u16be)
-							fmt |= AFMT_U16_BE;
-						if (sound.trans->ct_s16le)
-							fmt |= AFMT_S16_LE;
-						if (sound.trans->ct_u16le)
-							fmt |= AFMT_U16_LE;
-					}
-					return (IOCTL_OUT(arg, fmt));
-				case SNDCTL_DSP_GETBLKSIZE:
-					return (IOCTL_OUT(arg, 10240));
-				case SNDCTL_DSP_SUBDIVIDE:
-		 		case SNDCTL_DSP_SETFRAGMENT:
-					break;
-				default:
-					return (mixer_ioctl(inode, file, cmd, arg));
-			}
-			break;
+    int dev = MINOR(inode->i_rdev);
+    u_long fmt;
+    int data;
+
+    switch (dev & 0x0f) {
+	case SND_DEV_STATUS:
+	    return(-EPERM);
+	case SND_DEV_CTL:
+	    return(mixer_ioctl(inode, file, cmd, arg));
+	case SND_DEV_AUDIO:
+	case SND_DEV_DSP:
+	    switch (cmd) {
+		case SNDCTL_DSP_RESET:
+		    sq_reset();
+		    return(0);
+		case SNDCTL_DSP_POST:
+		case SNDCTL_DSP_SYNC:
+		    return(sound_fsync(file, file->f_dentry));
+
+		/* ++TeSche: before changing any of these it's probably wise to
+		 * wait until sound playing has settled down
+		 */
+		case SNDCTL_DSP_SPEED:
+		    sound_fsync(file, file->f_dentry);
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_speed(data)));
+		case SNDCTL_DSP_STEREO:
+		    sound_fsync(file, file->f_dentry);
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_stereo(data)));
+		case SOUND_PCM_WRITE_CHANNELS:
+		    sound_fsync(file, file->f_dentry);
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1));
+		case SNDCTL_DSP_SETFMT:
+		    sound_fsync(file, file->f_dentry);
+		    IOCTL_IN(arg, data);
+		    return(IOCTL_OUT(arg, sound_set_format(data)));
+		case SNDCTL_DSP_GETFMTS:
+		    fmt = 0;
+		    if (sound.trans) {
+			if (sound.trans->ct_ulaw)
+			    fmt |= AFMT_MU_LAW;
+			if (sound.trans->ct_alaw)
+			    fmt |= AFMT_A_LAW;
+			if (sound.trans->ct_s8)
+			    fmt |= AFMT_S8;
+			if (sound.trans->ct_u8)
+			    fmt |= AFMT_U8;
+			if (sound.trans->ct_s16be)
+			    fmt |= AFMT_S16_BE;
+			if (sound.trans->ct_u16be)
+			    fmt |= AFMT_U16_BE;
+			if (sound.trans->ct_s16le)
+			    fmt |= AFMT_S16_LE;
+			if (sound.trans->ct_u16le)
+			    fmt |= AFMT_U16_LE;
+		    }
+		    return(IOCTL_OUT(arg, fmt));
+		case SNDCTL_DSP_GETBLKSIZE:
+		    return(IOCTL_OUT(arg, 10240));
+		case SNDCTL_DSP_SUBDIVIDE:
+		case SNDCTL_DSP_SETFRAGMENT:
+		    break;
 
 		default:
-			return (unknown_minor_dev("sound_ioctl", dev));
-	}
-	return (-EINVAL);
+		    return(mixer_ioctl(inode, file, cmd, arg));
+	    }
+	    break;
+
+	default:
+	    return(unknown_minor_dev("sound_ioctl", dev));
+    }
+    return(-EINVAL);
 }
 
 
 static struct file_operations sound_fops =
 {
-	sound_lseek,
-	sound_read,
-	sound_write,
-	NULL,
-	NULL,			/* select */
-	sound_ioctl,
-	NULL,
-	sound_open,
-	sound_release,
-	sound_fsync
+    sound_lseek,
+    sound_read,
+    sound_write,
+    NULL,
+    NULL,                      /* select */
+    sound_ioctl,
+    NULL,
+    sound_open,
+    sound_release,
+    sound_fsync
 };
 
 
@@ -3601,186 +3276,171 @@
 /*** Config & Setup **********************************************************/
 
 
-void
-soundcard_init(void)
+void soundcard_init(void)
 {
-	int             has_sound = 0;
-	int             i;
+    int has_sound = 0;
+    int i;
 
-	switch (m68k_machtype)
-	{
+    switch (m68k_machtype) {
 #ifdef CONFIG_ATARI
-		case MACH_ATARI:
-			if (ATARIHW_PRESENT(PCM_8BIT))
-			{
-				if (ATARIHW_PRESENT(CODEC))
-					sound.mach = machFalcon;
-				else if (ATARIHW_PRESENT(MICROWIRE))
-					sound.mach = machTT;
-				else
-					break;
-				if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
-					has_sound = 1;
-				else
-					printk(KERN_ERR "DMA sound driver: Timer A interrupt already in use\n");
-			}
-			break;
+	case MACH_ATARI:
+	    if (ATARIHW_PRESENT(PCM_8BIT)) {
+		if (ATARIHW_PRESENT(CODEC))
+		    sound.mach = machFalcon;
+		else if (ATARIHW_PRESENT(MICROWIRE))
+		    sound.mach = machTT;
+		else
+		    break;
+		if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+		    has_sound = 1;
+		else
+		    printk("DMA sound driver: Timer A interrupt already in use\n");
+	    }
+	    break;
 
-#endif				/* CONFIG_ATARI */
+#endif /* CONFIG_ATARI */
 #ifdef CONFIG_AMIGA
-		case MACH_AMIGA:
-			if (AMIGAHW_PRESENT(AMI_AUDIO))
-			{
-				sound.mach = machAmiga;
-				has_sound = 1;
-			}
-			break;
-#endif				/* CONFIG_AMIGA */
-	}
-	if (!has_sound)
-		return;
-
-	/* Set up sound queue, /dev/audio and /dev/dsp. */
-	sound_buffers = kmalloc(numBufs * sizeof(char *), GFP_KERNEL);
+	case MACH_AMIGA:
+	    if (AMIGAHW_PRESENT(AMI_AUDIO)) {
+		sound.mach = machAmiga;
+		has_sound = 1;
+	    }
+	    break;
+#endif /* CONFIG_AMIGA */
+    }
+    if (!has_sound)
+	return;
 
-	if (!sound_buffers)
-	{
+    /* Set up sound queue, /dev/audio and /dev/dsp. */
+    sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
+    if (!sound_buffers) {
 out_of_memory:
-		printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
-		return;
-	}
-	for (i = 0; i < numBufs; i++)
-	{
-		sound_buffers[i] = sound.mach.dma_alloc(bufSize << 10, GFP_KERNEL);
-		if (!sound_buffers[i])
-		{
-			while (i--)
-				sound.mach.dma_free(sound_buffers[i], bufSize << 10);
-			kfree(sound_buffers);
-			sound_buffers = 0;
-			goto out_of_memory;
-		}
-	}
+	printk("DMA sound driver: Not enough buffer memory, driver disabled!\n");
+	return;
+    }
+    for (i = 0; i < numBufs; i++) {
+	sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
+	if (!sound_buffers[i]) {
+	    while (i--)
+		sound.mach.dma_free (sound_buffers[i], bufSize << 10);
+	    kfree (sound_buffers);
+	    sound_buffers = 0;
+	    goto out_of_memory;
+        }
+    }
 
 #ifndef MODULE
-	/* Register driver with the VFS. */
-	register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
+    /* Register driver with the VFS. */
+    register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
 #endif
 
-	sq_init(numBufs, bufSize << 10, sound_buffers);
+    sq_init(numBufs, bufSize << 10, sound_buffers);
 
-	/* Set up /dev/sndstat. */
-	state_init();
+    /* Set up /dev/sndstat. */
+    state_init();
 
-	/* Set up /dev/mixer. */
-	mixer_init();
+    /* Set up /dev/mixer. */
+    mixer_init();
 
-	if (!sound.mach.irqinit())
-	{
-		printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
-		return;
-	}
+    if (!sound.mach.irqinit()) {
+	printk("DMA sound driver: Interrupt initialization failed\n");
+	return;
+    }
 #ifdef MODULE
-	irq_installed = 1;
+    irq_installed = 1;
 #endif
 
-	printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n", numBufs,
-	       bufSize);
+    printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs,
+	   bufSize);
 
-	return;
+    return;
 }
 
 void sound_setup(char *str, int *ints)
 {
-	/* ++Martin: stub, could possibly be merged with soundcard.c et al later */
+    /* ++Martin: stub, could possibly be merged with soundcard.c et al later */
 }
 
 
 #define MAXARGS		8	/* Should be sufficient for now */
 
-void
-dmasound_setup(char *str, int *ints)
+void dmasound_setup(char *str, int *ints)
 {
-	/* check the bootstrap parameter for "dmasound=" */
+    /* check the bootstrap parameter for "dmasound=" */
 
-	switch (ints[0])
-	{
-		case 3:
-			if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
-				printk(KERN_WARNING "dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
-			else
-				catchRadius = ints[3];
-		  /* fall through */
-		case 2:
-			if (ints[1] < MIN_BUFFERS)
-				printk(KERN_WARNING "dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
-			else
-				numBufs = ints[1];
-			if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
-				printk(KERN_WARNING "dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
-			else
-				bufSize = ints[2];
-			break;
-		case 0:
-			break;
-		default:
-			printk(KERN_WARNING "dmasound_setup: illegal number of arguments\n");
-	}
+    switch (ints[0]) {
+	case 3:
+	    if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
+		printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+	    else
+		catchRadius = ints[3];
+	    /* fall through */
+	case 2:
+	    if (ints[1] < MIN_BUFFERS)
+		printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
+	    else
+		numBufs = ints[1];
+	    if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
+		printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
+	    else
+		bufSize = ints[2];
+	    break;
+	case 0:
+	    break;
+	default:
+	    printk("dmasound_setup: illegal number of arguments\n");
+    }
 }
 
 
 #ifdef MODULE
 
-static int      dmasound[MAXARGS] = {
-	0
-};
+static int dmasound[MAXARGS] = { 0 };
 
 int init_module(void)
 {
-	int             err, i = 0;
-	int             ints[MAXARGS + 1];
+    int err, i = 0;
+    int ints[MAXARGS+1];
 
-	while (i < MAXARGS && dmasound[i])
-		ints[i + 1] = dmasound[i++];
-	ints[0] = i;
-
-	if (i)
-		dmasound_setup("dmasound=", ints);
-
-	err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
-	if (err)
-	{
-		printk(KERN_ERR "dmasound: driver already loaded/included in kernel\n");
-		return err;
-	}
-	chrdev_registered = 1;
-	soundcard_init();
+    while (i < MAXARGS && dmasound[i])
+	ints[i + 1] = dmasound[i++];
+    ints[0] = i;
+
+    if (i)
+	dmasound_setup("dmasound=", ints);
+
+    err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
+    if (err) {
+	printk("dmasound: driver already loaded/included in kernel\n");
+	return err;
+    }
+    chrdev_registered = 1;
+    soundcard_init();
 
-	return 0;
+    return 0;
 }
 
 
 void cleanup_module(void)
 {
-	int             i;
+    int i;
 
-	if (MOD_IN_USE)
-		return;
+    if (MOD_IN_USE)
+	return;
 
-	if (chrdev_registered)
-		unregister_chrdev(SOUND_MAJOR, "sound");
+    if (chrdev_registered)
+	unregister_chrdev(SOUND_MAJOR, "sound");
 
-	if (irq_installed)
-	{
-		sound_silence();
-		sound.mach.irqcleanup();
-	}
-	if (sound_buffers)
-	{
-		for (i = 0; i < numBufs; i++)
-			sound.mach.dma_free(sound_buffers[i], bufSize << 10);
-		kfree(sound_buffers);
-	}
+    if (irq_installed) {
+	sound_silence();
+	sound.mach.irqcleanup();
+    }
+
+    if (sound_buffers) {
+	for (i = 0; i < numBufs; i++)
+	    sound.mach.dma_free(sound_buffers[i], bufSize << 10);
+	kfree(sound_buffers);
+    }
 }
 
-#endif				/* MODULE */
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c
--- v2.1.93/linux/drivers/sound/gus_card.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/sound/gus_card.c	Wed Apr  8 17:24:48 1998
@@ -30,7 +30,8 @@
 
 void attach_gus_card(struct address_info *hw_config)
 {
-	snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp, hw_config);
+	if(request_irq(hw_config->irq, gusintr, 0,  "Gravis Ultrasound", hw_config)<0)
+		printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq);
 
 	gus_wave_init(hw_config);
 
@@ -38,10 +39,10 @@
 	request_region(hw_config->io_base + 0x100, 12, "GUS");	/* 0x10c-> is MAX */
 
 	if (sound_alloc_dma(hw_config->dma, "GUS"))
-		printk("gus_card.c: Can't allocate DMA channel\n");
+		printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma);
 	if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
 		if (sound_alloc_dma(hw_config->dma2, "GUS(2)"))
-			printk("gus_card.c: Can't allocate DMA channel 2\n");
+			printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2);
 #if defined(CONFIG_MIDI)
 	gus_midi_init(hw_config);
 #endif
@@ -101,7 +102,7 @@
 
 	release_region(hw_config->io_base, 16);
 	release_region(hw_config->io_base + 0x100, 12);		/* 0x10c-> is MAX */
-	snd_release_irq(hw_config->irq, hw_config);
+	free_irq(hw_config->irq, hw_config);
 
 	sound_free_dma(hw_config->dma);
 
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v2.1.93/linux/drivers/sound/gus_wave.c	Mon Feb 23 18:12:09 1998
+++ linux/drivers/sound/gus_wave.c	Wed Apr  8 17:24:48 1998
@@ -859,26 +859,26 @@
 	int bank_sizes[4];
 	int i, j, bits = -1, nbanks = 0;
 
-/*
- * This routine determines what kind of RAM is installed in each of the four
- * SIMM banks and configures the DRAM address decode logic accordingly.
- */
+	/*
+	 * This routine determines what kind of RAM is installed in each of the four
+	 * SIMM banks and configures the DRAM address decode logic accordingly.
+	 */
 
-/*
- *    Place the chip into enhanced mode
- */
+	/*
+	 *    Place the chip into enhanced mode
+	 */
 	gus_write8(0x19, gus_read8(0x19) | 0x01);
 	gus_write8(0x53, gus_look8(0x53) & ~0x02);	/* Select DRAM I/O access */
 
-/*
- * Set memory configuration to 4 DRAM banks of 4M in each (16M total).
- */
+	/*
+	 * Set memory configuration to 4 DRAM banks of 4M in each (16M total).
+	 */
 
 	gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c);
 
-/*
- * Perform the DRAM size detection for each bank individually.
- */
+	/*
+	 * Perform the DRAM size detection for each bank individually.
+	 */
 	for (bank = 0; bank < 4; bank++)
 	{
 		int size = 0;
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/local.h.master linux/drivers/sound/local.h.master
--- v2.1.93/linux/drivers/sound/local.h.master	Tue Mar 10 10:03:33 1998
+++ linux/drivers/sound/local.h.master	Wed Apr  8 17:24:48 1998
@@ -42,7 +42,7 @@
   defined(CONFIG_MSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \
   defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \
   defined(CONFIG_CS4232_MODULE) || defined(CONFIG_OPL3SA1_MODULE) || \
-  defined(CONFIG_SOFTOSS_MODULE)
+  defined(CONFIG_SOFTOSS_MODULE) || defined(CONFIG_VIDC_SOUND)
 #       define CONFIG_AUDIO
 #endif
 
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v2.1.93/linux/drivers/sound/mad16.c	Sun Dec 21 17:41:24 1997
+++ linux/drivers/sound/mad16.c	Wed Apr  8 17:24:48 1998
@@ -56,6 +56,10 @@
  *      CD-ROM DMA (Mitsumi or IDE):    0x00=DMA5, 0x01=DMA6, 0x02=DMA7 or 0x03=disabled
  *
  *      For use with sbpcd, address 0x340, set MAD16_CDSEL to 0x03 or 0x23.
+ *
+ *	Changes
+ *	
+ *	Alan Cox		Clean up, added module selections.
  */
 
 #include "sound_config.h"
@@ -118,48 +122,47 @@
 #define DDB(x)
 #endif
 
-static unsigned char
-mad_read(int port)
+static unsigned char mad_read(int port)
 {
-	unsigned long   flags;
-	unsigned char   tmp;
+	unsigned long flags;
+	unsigned char tmp;
 
 	save_flags(flags);
 	cli();
 
 	switch (board_type)	/* Output password */
-	  {
-	  case C928:
-	  case MOZART:
-		  outb((0xE2), PASSWD_REG);
-		  break;
-
-	  case C929:
-		  outb((0xE3), PASSWD_REG);
-		  break;
-
-	  case C930:
-		  /* outb(( 0xE4),  PASSWD_REG); */
-		  break;
-
-	  case C924:
-		  outb((0xE5), PASSWD_REG);
-		  break;
-	  }
+	{
+		case C928:
+		case MOZART:
+			outb((0xE2), PASSWD_REG);
+			break;
+
+		case C929:
+			outb((0xE3), PASSWD_REG);
+			break;
+
+		case C930:
+			/* outb(( 0xE4),  PASSWD_REG); */
+			break;
+
+		case C924:
+			outb((0xE5), PASSWD_REG);
+			break;
+	}
 
 	if (board_type == C930)
-	  {
-		  outb((port - MC0_PORT), 0xe0e);	/* Write to index reg */
-		  tmp = inb(0xe0f);	/* Read from data reg */
-	} else
+	{
+		outb((port - MC0_PORT), 0xe0e);	/* Write to index reg */
+		tmp = inb(0xe0f);	/* Read from data reg */
+	}
+	else
 		tmp = inb(port);
 	restore_flags(flags);
 
 	return tmp;
 }
 
-static void
-mad_write(int port, int value)
+static void mad_write(int port, int value)
 {
 	unsigned long   flags;
 
@@ -167,65 +170,65 @@
 	cli();
 
 	switch (board_type)	/* Output password */
-	  {
-	  case C928:
-	  case MOZART:
-		  outb((0xE2), PASSWD_REG);
-		  break;
-
-	  case C929:
-		  outb((0xE3), PASSWD_REG);
-		  break;
-
-	  case C930:
-		  /* outb(( 0xE4),  PASSWD_REG); */
-		  break;
-
-	  case C924:
-		  outb((0xE5), PASSWD_REG);
-		  break;
-	  }
+	{
+		case C928:
+		case MOZART:
+			outb((0xE2), PASSWD_REG);
+			break;
+
+		case C929:
+			outb((0xE3), PASSWD_REG);
+			break;
+
+		case C930:
+			/* outb(( 0xE4),  PASSWD_REG); */
+			break;
+
+		case C924:
+			outb((0xE5), PASSWD_REG);
+			break;
+	}
 
 	if (board_type == C930)
-	  {
-		  outb((port - MC0_PORT), 0xe0e);	/* Write to index reg */
-		  outb(((unsigned char) (value & 0xff)), 0xe0f);
-	} else
+	{
+		outb((port - MC0_PORT), 0xe0e);	/* Write to index reg */
+		outb(((unsigned char) (value & 0xff)), 0xe0f);
+	}
+	else
 		outb(((unsigned char) (value & 0xff)), port);
 	restore_flags(flags);
 }
 
-static int
-detect_c930(void)
+static int detect_c930(void)
 {
 	unsigned char   tmp = mad_read(MC1_PORT);
 
 	if ((tmp & 0x06) != 0x06)
-	  {
-		  DDB(printk("Wrong C930 signature (%x)\n", tmp));
-		  /* return 0; */
-	  }
+	{
+		DDB(printk("Wrong C930 signature (%x)\n", tmp));
+		/* return 0; */
+	}
 	mad_write(MC1_PORT, 0);
 
 	if (mad_read(MC1_PORT) != 0x06)
-	  {
-		  DDB(printk("Wrong C930 signature2 (%x)\n", tmp));
-		  /* return 0; */
-	  }
+	{
+		DDB(printk("Wrong C930 signature2 (%x)\n", tmp));
+		/* return 0; */
+	}
 	mad_write(MC1_PORT, tmp);	/* Restore bits */
 
 	mad_write(MC7_PORT, 0);
 	if ((tmp = mad_read(MC7_PORT)) != 0)
-	  {
-		  DDB(printk("MC7 not writable (%x)\n", tmp));
-		  return 0;
-	  }
+	{
+		DDB(printk("MC7 not writable (%x)\n", tmp));
+		return 0;
+	}
 	mad_write(MC7_PORT, 0xcb);
 	if ((tmp = mad_read(MC7_PORT)) != 0xcb)
-	  {
-		  DDB(printk("MC7 not writable2 (%x)\n", tmp));
-		  return 0;
-	  }
+	{
+		DDB(printk("MC7 not writable2 (%x)\n", tmp));
+		return 0;
+	}
 
 	tmp = mad_read(MC0_PORT+18);
 	if (tmp == 0xff)
@@ -262,113 +265,109 @@
 	 * the PnP bios will not recognize the chip on the next
 	 * warm boot and may assignd different resources to other
 	 * PnP/PCI cards.
-	*/
+	 */
 	mad_write(MC0_PORT+17, 0x04);
 	return 1;
 }
 
-static int
-detect_mad16(void)
+static int detect_mad16(void)
 {
-	unsigned char   tmp, tmp2;
-	int             i;
+	unsigned char tmp, tmp2;
+	int i;
+
+	/*
+	 * Check that reading a register doesn't return bus float (0xff)
+	 * when the card is accessed using password. This may fail in case
+	 * the card is in low power mode. Normally at least the power saving mode
+	 * bit should be 0.
+	 */
 
-/*
- * Check that reading a register doesn't return bus float (0xff)
- * when the card is accessed using password. This may fail in case
- * the card is in low power mode. Normally at least the power saving mode
- * bit should be 0.
- */
 	if ((tmp = mad_read(MC1_PORT)) == 0xff)
-	  {
-		  DDB(printk("MC1_PORT returned 0xff\n"));
-		  return 0;
-	  }
+	{
+		DDB(printk("MC1_PORT returned 0xff\n"));
+		return 0;
+	}
 	for (i = 0xf8d; i <= 0xf98; i++)
 		DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i)));
 
 	if (board_type == C930)
 		return detect_c930();
-/*
- * Now check that the gate is closed on first I/O after writing
- * the password. (This is how a MAD16 compatible card works).
- */
+
+	/*
+	 * Now check that the gate is closed on first I/O after writing
+	 * the password. (This is how a MAD16 compatible card works).
+	 */
 
 	if ((tmp2 = inb(MC1_PORT)) == tmp)	/* It didn't close */
-	  {
-		  DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
-		  return 0;
-	  }
+	{
+		DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
+		return 0;
+	}
 	mad_write(MC1_PORT, tmp ^ 0x80);	/* Toggle a bit */
 	if ((tmp2 = mad_read(MC1_PORT)) != (tmp ^ 0x80))	/* Compare the bit */
-	  {
-		  mad_write(MC1_PORT, tmp);	/* Restore */
-		  DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
-		  return 0;
-	  }
+	{
+		mad_write(MC1_PORT, tmp);	/* Restore */
+		DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
+		return 0;
+	}
 	mad_write(MC1_PORT, tmp);	/* Restore */
 	return 1;		/* Bingo */
-
 }
 
-static int
-wss_init(struct address_info *hw_config)
+static int wss_init(struct address_info *hw_config)
 {
-	int             ad_flags = 0;
+	int ad_flags = 0;
 
-/*
- *    Verify the WSS parameters
- */
+	/*
+	 *    Verify the WSS parameters
+	 */
 
 	if (check_region(hw_config->io_base, 8))
-	  {
-		  printk("MSS: I/O port conflict\n");
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "MSS: I/O port conflict\n");
+		return 0;
+	}
 	if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp))
 		return 0;
 	/*
-	   * Check if the IO port returns valid signature. The original MS Sound
-	   * system returns 0x04 while some cards (AudioTrix Pro for example)
-	   * return 0x00.
+	 * Check if the IO port returns valid signature. The original MS Sound
+	 * system returns 0x04 while some cards (AudioTrix Pro for example)
+	 * return 0x00.
 	 */
 
 	if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 &&
 	    (inb(hw_config->io_base + 3) & 0x3f) != 0x00)
-	  {
-		  DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3)));
-		  return 0;
-	  }
+	{
+		DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3)));
+		return 0;
+	}
 	if (hw_config->irq > 11)
-	  {
-		  printk("MSS: Bad IRQ %d\n", hw_config->irq);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq);
+		return 0;
+	}
 	if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
-	  {
-		  printk("MSS: Bad DMA %d\n", hw_config->dma);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "MSS: Bad DMA %d\n", hw_config->dma);
+		return 0;
+	}
 	/*
-	   * Check that DMA0 is not in use with a 8 bit board.
+	 * Check that DMA0 is not in use with a 8 bit board.
 	 */
 
 	if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80)
-	  {
-		  printk("MSS: Can't use DMA0 with a 8 bit card/slot\n");
-		  return 0;
-	  }
+	{
+		printk("MSS: Can't use DMA0 with a 8 bit card/slot\n");
+		return 0;
+	}
 	if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80)
-	  {
-		  printk("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
-	  }
+		printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
 	return 1;
 }
 
-static int
-init_c930(struct address_info *hw_config)
+static int init_c930(struct address_info *hw_config)
 {
-	unsigned char   cfg = 0;
+	unsigned char cfg = 0;
 
 #ifdef MAD16_CONF
 	cfg |= (0x0f & MAD16_CONF);
@@ -384,24 +383,23 @@
 	}
 
 	switch (hw_config->io_base)
-	  {
-	  case 0x530:
-		  cfg |= 0x00;
-		  break;
-	  case 0xe80:
-		  cfg |= 0x10;
-		  break;
-	  case 0xf40:
-		  cfg |= 0x20;
-		  break;
-	  case 0x604:
-		  cfg |= 0x30;
-		  break;
-
-	  default:
-		  printk("MAD16: Invalid codec port %x\n", hw_config->io_base);
-		  return 0;
-	  }
+	{
+		case 0x530:
+			cfg |= 0x00;
+			break;
+		case 0xe80:
+			cfg |= 0x10;
+			break;
+		case 0xf40:
+			cfg |= 0x20;
+			break;
+		case 0x604:
+			cfg |= 0x30;
+			break;
+		default:
+			printk(KERN_ERR "MAD16: Invalid codec port %x\n", hw_config->io_base);
+			return 0;
+	}
 	mad_write(MC1_PORT, cfg);
 
 	/* MC2 is CD configuration. Don't touch it. */
@@ -423,94 +421,98 @@
 	return wss_init(hw_config);
 }
 
-static int
-chip_detect(void)
+static int chip_detect(void)
 {
-	int             i;
+	int i;
 
-/*
- *    Then try to detect with the old password
- */
+	/*
+	 *    Then try to detect with the old password
+	 */
 	board_type = C924;
 
 	DDB(printk("Detect using password = 0xE5\n"));
 
 	if (!detect_mad16())	/* No luck. Try different model */
-	  {
-		  board_type = C928;
-
-		  DDB(printk("Detect using password = 0xE2\n"));
-
-		  if (!detect_mad16())
-		    {
-			    board_type = C929;
-
-			    DDB(printk("Detect using password = 0xE3\n"));
-
-			    if (!detect_mad16())
-			      {
-				      if (inb(PASSWD_REG) != 0xff)
-					      return 0;
-
-/*
- * First relocate MC# registers to 0xe0e/0xe0f, disable password 
- */
-
-				      outb((0xE4), PASSWD_REG);
-				      outb((0x80), PASSWD_REG);
-
-				      board_type = C930;
+	{
+		board_type = C928;
 
-				      DDB(printk("Detect using password = 0xE4\n"));
+		DDB(printk("Detect using password = 0xE2\n"));
 
-				      for (i = 0xf8d; i <= 0xf93; i++)
-					      DDB(printk("port %03x = %02x\n", i, mad_read(i)));
-
-				      if (!detect_mad16())
-					      return 0;
-
-				      DDB(printk("mad16.c: 82C930 detected\n"));
-			    } else
-			      {
-				      DDB(printk("mad16.c: 82C929 detected\n"));
-			      }
-		  } else
-		    {
-			    unsigned char   model;
-
-			    if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03)
-			      {
-				      DDB(printk("mad16.c: Mozart detected\n"));
-				      board_type = MOZART;
-			    } else
-			      {
-				      DDB(printk("mad16.c: 82C928 detected???\n"));
-				      board_type = C928;
-			      }
-		    }
-	  }
+		if (!detect_mad16())
+		{
+			board_type = C929;
+
+			DDB(printk("Detect using password = 0xE3\n"));
+
+			if (!detect_mad16())
+			{
+				if (inb(PASSWD_REG) != 0xff)
+					return 0;
+
+				/*
+				 * First relocate MC# registers to 0xe0e/0xe0f, disable password 
+				 */
+
+				outb((0xE4), PASSWD_REG);
+				outb((0x80), PASSWD_REG);
+
+				board_type = C930;
+
+				DDB(printk("Detect using password = 0xE4\n"));
+
+				for (i = 0xf8d; i <= 0xf93; i++)
+					DDB(printk("port %03x = %02x\n", i, mad_read(i)));
+
+				if (!detect_mad16())
+					return 0;
+
+				DDB(printk("mad16.c: 82C930 detected\n"));
+			}
+			else
+			{
+				DDB(printk("mad16.c: 82C929 detected\n"));
+			}
+		}
+		else
+		{
+			unsigned char model;
+
+			if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03)
+			{
+				DDB(printk("mad16.c: Mozart detected\n"));
+				board_type = MOZART;
+			}
+			else
+			{
+				DDB(printk("mad16.c: 82C928 detected???\n"));
+				board_type = C928;
+			}
+		}
+	}
 	return 1;
 }
 
-int
-probe_mad16(struct address_info *hw_config)
+int probe_mad16(struct address_info *hw_config)
 {
-	int             i;
-	static int      valid_ports[] =
-	{0x530, 0xe80, 0xf40, 0x604};
-	unsigned char   tmp;
-	unsigned char   cs4231_mode = 0;
+	int i;
+	static int valid_ports[] = 
+	{
+		0x530, 0xe80, 0xf40, 0x604
+	};
+	unsigned char tmp;
+	unsigned char cs4231_mode = 0;
 
-	int             ad_flags = 0;
+	int ad_flags = 0;
 
 	if (already_initialized)
 		return 0;
 
 	mad16_osp = hw_config->osp;
-/*
- *    Check that all ports return 0xff (bus float) when no password
- *      is written to the password register.
- */
+
+	/*
+	 *    Check that all ports return 0xff (bus float) when no password
+	 *      is written to the password register.
+	 */
 
 	DDB(printk("--- Detecting MAD16 / Mozart ---\n"));
 	if (!chip_detect())
@@ -530,25 +532,25 @@
 	tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80;	/* Enable WSS, Disable SB */
 
 	for (i = 0; i < 5; i++)
-	  {
-		  if (i > 3)	/* Not a valid port */
-		    {
-			    printk("MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
-			    return 0;
-		    }
-		  if (valid_ports[i] == hw_config->io_base)
-		    {
-			    tmp |= i << 4;	/* WSS port select bits */
-			    break;
-		    }
-	  }
+	{
+		if (i > 3)	/* Not a valid port */
+		{
+			printk(KERN_ERR "MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
+			return 0;
+		}
+		if (valid_ports[i] == hw_config->io_base)
+		{
+			tmp |= i << 4;	/* WSS port select bits */
+			break;
+		}
+	}
 
-/*
- * Set optional CD-ROM and joystick settings.
- */
+	/*
+	 * Set optional CD-ROM and joystick settings.
+	 */
 
-#ifdef MAD16_CONF
 	tmp &= ~0x0f;
+#if defined(MAD16_CONF)
 	tmp |= ((MAD16_CONF) & 0x0f);	/* CD-ROM and joystick bits */
 #endif
 	mad_write(MC1_PORT, tmp);
@@ -567,11 +569,11 @@
 	mad_write(MC3_PORT, 0xf0);	/* Disable SB */
 
 	if (board_type == C924)	/* Specific C924 init values */
-	  {
-		  mad_write(MC4_PORT, 0xA0);
-		  mad_write(MC5_PORT, 0x05);
-		  mad_write(MC6_PORT, 0x03);
-	  }
+	{
+		mad_write(MC4_PORT, 0xA0);
+		mad_write(MC5_PORT, 0x05);
+		mad_write(MC6_PORT, 0x03);
+	}
 	if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp))
 		return 0;
 
@@ -579,15 +581,16 @@
 		cs4231_mode = 0x02;	/* CS4248/CS4231 sync delay switch */
 
 	if (board_type == C929)
-	  {
-		  mad_write(MC4_PORT, 0xa2);
-		  mad_write(MC5_PORT, 0xA5 | cs4231_mode);
-		  mad_write(MC6_PORT, 0x03);	/* Disable MPU401 */
-	} else
-	  {
-		  mad_write(MC4_PORT, 0x02);
-		  mad_write(MC5_PORT, 0x30 | cs4231_mode);
-	  }
+	{
+		mad_write(MC4_PORT, 0xa2);
+		mad_write(MC5_PORT, 0xA5 | cs4231_mode);
+		mad_write(MC6_PORT, 0x03);	/* Disable MPU401 */
+	}
+	else
+	{
+		mad_write(MC4_PORT, 0x02);
+		mad_write(MC5_PORT, 0x30 | cs4231_mode);
+	}
 
 	for (i = 0xf8d; i <= 0xf93; i++)
 		DDB(printk("port %03x after init = %02x\n", i, mad_read(i)));
@@ -597,24 +600,21 @@
 	return 1;
 }
 
-void
-attach_mad16(struct address_info *hw_config)
+void attach_mad16(struct address_info *hw_config)
 {
 
-	static char     interrupt_bits[12] =
-	{
+	static char     interrupt_bits[12] = {
 		-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
 	};
-	char            bits;
+	char bits;
 
-	static char     dma_bits[4] =
-	{
+	static char     dma_bits[4] = {
 		1, 2, 0, 3
 	};
 
-	int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
-	int             ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2;
-	unsigned char   dma2_bit = 0;
+	int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+	int ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2;
+	unsigned char dma2_bit = 0;
 
 	already_initialized = 1;
 
@@ -622,8 +622,9 @@
 		return;
 
 	/*
-	   * Set the IRQ and DMA addresses.
+	 * Set the IRQ and DMA addresses.
 	 */
+	
 	if (board_type == C930)
 		interrupt_bits[5] = 0x28;	/* Also IRQ5 is possible on C930 */
 
@@ -633,35 +634,35 @@
 
 	outb((bits | 0x40), config_port);
 	if ((inb(version_port) & 0x40) == 0)
-		printk("[IRQ Conflict?]");
+		printk(KERN_ERR "[IRQ Conflict?]\n");
 
-/*
- * Handle the capture DMA channel
- */
+	/*
+	 * Handle the capture DMA channel
+	 */
 
 	if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma)
-	  {
-		  if (!((dma == 0 && dma2 == 1) ||
+	{
+		if (!((dma == 0 && dma2 == 1) ||
 			(dma == 1 && dma2 == 0) ||
 			(dma == 3 && dma2 == 0)))
-		    {		/* Unsupported combination. Try to swap channels */
-			    int             tmp = dma;
+		{		/* Unsupported combination. Try to swap channels */
+			int tmp = dma;
 
-			    dma = dma2;
-			    dma2 = tmp;
-		    }
-		  if ((dma == 0 && dma2 == 1) ||
-		      (dma == 1 && dma2 == 0) ||
-		      (dma == 3 && dma2 == 0))
-		    {
-			    dma2_bit = 0x04;	/* Enable capture DMA */
-		  } else
-		    {
-			    printk("MAD16: Invalid capture DMA\n");
-			    dma2 = dma;
-		    }
-	} else
-		dma2 = dma;
+			dma = dma2;
+			dma2 = tmp;
+		}
+		if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) ||
+			(dma == 3 && dma2 == 0))
+		{
+			dma2_bit = 0x04;	/* Enable capture DMA */
+		}
+		else
+		{
+			printk("MAD16: Invalid capture DMA\n");
+			dma2 = dma;
+		}
+	}
+	else dma2 = dma;
 
 	outb((bits | dma_bits[dma] | dma2_bit), config_port);	/* Write IRQ+DMA setup */
 
@@ -673,24 +674,23 @@
 	request_region(hw_config->io_base, 4, "MAD16 WSS config");
 }
 
-void
-attach_mad16_mpu(struct address_info *hw_config)
+void attach_mad16_mpu(struct address_info *hw_config)
 {
 	if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
-	  {
-#if defined(CONFIG_MIDI)
+	{
+#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD)
 
-		  if (mad_read(MC1_PORT) & 0x20)
-			  hw_config->io_base = 0x240;
-		  else
-			  hw_config->io_base = 0x220;
+		if (mad_read(MC1_PORT) & 0x20)
+			hw_config->io_base = 0x240;
+		else
+			hw_config->io_base = 0x220;
 
-		  hw_config->name = "Mad16/Mozart";
-		  sb_dsp_init(hw_config);
+		hw_config->name = "Mad16/Mozart";
+		sb_dsp_init(hw_config);
 #endif
 
-		  return;
-	  }
+		return;
+	}
 #if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
 	if (!already_initialized)
 		return;
@@ -701,68 +701,67 @@
 #endif
 }
 
-int
-probe_mad16_mpu(struct address_info *hw_config)
+int probe_mad16_mpu(struct address_info *hw_config)
 {
 #if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
-	static int      mpu_attached = 0;
-	static int      valid_ports[] =
-	{0x330, 0x320, 0x310, 0x300};
-	static short    valid_irqs[] =
-	{9, 10, 5, 7};
-	unsigned char   tmp;
-
-	int             i;	/* A variable with secret power */
+	static int mpu_attached = 0;
+	static int valid_ports[] = {
+		0x330, 0x320, 0x310, 0x300
+	};
+	
+	static short valid_irqs[] = {9, 10, 5, 7};
+	unsigned char tmp;
+	int i;				/* A variable with secret power */
 
 	if (!already_initialized)	/* The MSS port must be initialized first */
 		return 0;
 
-	if (mpu_attached)	/* Don't let them call this twice */
+	if (mpu_attached)		/* Don't let them call this twice */
 		return 0;
 	mpu_attached = 1;
 
 	if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
-	  {
+	{
 
-#if defined(CONFIG_MIDI)
-		  unsigned char   tmp;
+#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD)
+		unsigned char   tmp;
 
-		  tmp = mad_read(MC3_PORT);
+		tmp = mad_read(MC3_PORT);
 
-		  /* 
-		   * MAD16 SB base is defined by the WSS base. It cannot be changed 
-		   * alone.
-		   * Ignore configured I/O base. Use the active setting. 
-		   */
-
-		  if (mad_read(MC1_PORT) & 0x20)
-			  hw_config->io_base = 0x240;
-		  else
-			  hw_config->io_base = 0x220;
-
-		  switch (hw_config->irq)
-		    {
-		    case 5:
-			    tmp = (tmp & 0x3f) | 0x80;
-			    break;
-		    case 7:
-			    tmp = (tmp & 0x3f);
-			    break;
-		    case 11:
-			    tmp = (tmp & 0x3f) | 0x40;
-			    break;
-		    default:
-			    printk("mad16/Mozart: Invalid MIDI IRQ\n");
-			    return 0;
-		    }
-
-		  mad_write(MC3_PORT, tmp | 0x04);
-		  hw_config->driver_use_1 = SB_MIDI_ONLY;
-		  return sb_dsp_detect(hw_config);
+		/* 
+		 * MAD16 SB base is defined by the WSS base. It cannot be changed 
+		 * alone.
+		 * Ignore configured I/O base. Use the active setting. 
+		 */
+
+		if (mad_read(MC1_PORT) & 0x20)
+			hw_config->io_base = 0x240;
+		else
+			hw_config->io_base = 0x220;
+
+		switch (hw_config->irq)
+		{
+			case 5:
+				tmp = (tmp & 0x3f) | 0x80;
+				break;
+			case 7:
+				tmp = (tmp & 0x3f);
+				break;
+			case 11:
+				tmp = (tmp & 0x3f) | 0x40;
+				break;
+			default:
+				printk(KERN_ERR "mad16/Mozart: Invalid MIDI IRQ\n");
+				return 0;
+		}
+
+		mad_write(MC3_PORT, tmp | 0x04);
+		hw_config->driver_use_1 = SB_MIDI_ONLY;
+		return sb_dsp_detect(hw_config);
 #else
-		  return 0;
+		return 0;
 #endif
-	  }
+	}
 	tmp = mad_read(MC6_PORT) & 0x83;
 	tmp |= 0x80;		/* MPU-401 enable */
 
@@ -771,36 +770,36 @@
  */
 
 	for (i = 0; i < 5; i++)
-	  {
-		  if (i > 3)	/* Out of array bounds */
-		    {
-			    printk("MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base);
-			    return 0;
-		    }
-		  if (valid_ports[i] == hw_config->io_base)
-		    {
-			    tmp |= i << 5;
-			    break;
-		    }
-	  }
+	{
+		if (i > 3)	/* Out of array bounds */
+		{
+			printk(KERN_ERR "MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base);
+			return 0;
+		}
+		if (valid_ports[i] == hw_config->io_base)
+		{
+			tmp |= i << 5;
+			break;
+		}
+	}
 
 /*
  * Set the MPU IRQ bits
  */
 
 	for (i = 0; i < 5; i++)
-	  {
-		  if (i > 3)	/* Out of array bounds */
-		    {
-			    printk("MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq);
-			    return 0;
-		    }
-		  if (valid_irqs[i] == hw_config->irq)
-		    {
-			    tmp |= i << 3;
-			    break;
-		    }
-	  }
+	{
+		if (i > 3)	/* Out of array bounds */
+		{
+			printk(KERN_ERR "MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq);
+			return 0;
+		}
+		if (valid_irqs[i] == hw_config->irq)
+		{
+			tmp |= i << 3;
+			break;
+		}
+	}
 	mad_write(MC6_PORT, tmp);	/* Write MPU401 config */
 
 	return probe_uart401(hw_config);
@@ -809,13 +808,12 @@
 #endif
 }
 
-void
-unload_mad16(struct address_info *hw_config)
+void unload_mad16(struct address_info *hw_config)
 {
 	ad1848_unload(hw_config->io_base + 4,
-		      hw_config->irq,
-		      hw_config->dma,
-		      hw_config->dma2, 0);
+			hw_config->irq,
+			hw_config->dma,
+			hw_config->dma2, 0);
 	release_region(hw_config->io_base, 4);
 	sound_unload_audiodev(hw_config->slots[0]);
 
@@ -824,12 +822,12 @@
 void
 unload_mad16_mpu(struct address_info *hw_config)
 {
-#if defined(CONFIG_MIDI)
+#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD)
 	if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
-	  {
-		  sb_dsp_unload(hw_config);
-		  return;
-	  }
+	{
+		sb_dsp_unload(hw_config);
+		return;
+	}
 #endif
 
 #if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
@@ -839,6 +837,8 @@
 
 #ifdef MODULE
 
+int		mpu_io = 0;
+int		mpu_irq = 0;
 int             io = -1;
 int             dma = -1;
 int             dma16 = -1;	/* Set this for modules that need it */
@@ -851,6 +851,8 @@
 int             opl4 = 0;
 int             joystick = 0;
 
+MODULE_PARM(mpu_io, "i");
+MODULE_PARM(mpu_irq, "i");
 MODULE_PARM(io,"i");
 MODULE_PARM(dma,"i");
 MODULE_PARM(dma16,"i");
@@ -862,17 +864,18 @@
 MODULE_PARM(opl4,"i");
 MODULE_PARM(joystick,"i");
 
+EXPORT_NO_SYMBOLS;
 
-static int      found_mpu;
+static int found_mpu;
 
 
-static int      dma_map[2][8] =
+static int dma_map[2][8] =
 {
 	{0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02},
 	{0x03, -1, 0x01, 0x00, -1, -1, -1, -1}
 };
 
-static int      irq_map[16] =
+static int irq_map[16] =
 {
 	0x00, -1, -1, 0x0A,
 	-1, 0x04, -1, 0x08,
@@ -881,80 +884,83 @@
 };
 
 struct address_info config;
+struct address_info config_mpu;
 
-int
-init_module(void)
+int init_module(void)
 {
-	int             dmatype = 0;
+	int dmatype = 0;
 
-	printk("MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
+	printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
 
 	if (io == -1 || dma == -1 || irq == -1)
-	  {
-		  printk("I/O, DMA and irq are mandatory\n");
-		  return -EINVAL;
-	  }
-	printk("CDROM ");
+	{
+		printk(KERN_ERR "I/O, DMA and irq are mandatory\n");
+		return -EINVAL;
+	}
+	printk(KERN_INFO "CDROM ");
 	switch (cdtype)
-	  {
-	  case 0x00:
-		  printk("Disabled");
-		  cdirq = 0;
-		  break;
-	  case 0x02:
-		  printk("Sony CDU31A");
-		  dmatype = 2;
-		  break;
-	  case 0x04:
-		  printk("Mitsumi");
-		  dmatype = 1;
-		  break;
-	  case 0x06:
-		  printk("Panasonic Lasermate");
-		  dmatype = 2;
-		  break;
-	  case 0x08:
-		  printk("Secondary IDE");
-		  dmatype = 1;
-		  break;
-	  case 0x0A:
-		  printk("Primary IDE");
-		  dmatype = 1;
-		  break;
-	  default:
-		  printk("\nInvalid CDROM type\n");
-		  return -EINVAL;
-	  }
+	{
+		case 0x00:
+			printk("Disabled");
+			cdirq = 0;
+			break;
+		case 0x02:
+			printk("Sony CDU31A");
+			dmatype = 2;
+			break;
+		case 0x04:
+			printk("Mitsumi");
+			dmatype = 1;
+			break;
+		case 0x06:
+			printk("Panasonic Lasermate");
+			dmatype = 2;
+			break;
+		case 0x08:
+			printk("Secondary IDE");
+			dmatype = 1;
+			break;
+		case 0x0A:
+			printk("Primary IDE");
+			dmatype = 1;
+			break;
+		default:
+			printk("\n");
+			printk(KERN_ERR "Invalid CDROM type\n");
+			return -EINVAL;
+	}
 
 	if (dmatype)
-	  {
-		  if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1)
-		    {
-			    printk("\nInvalid CDROM DMA\n");
-			    return -EINVAL;
-		    }
-		  if (cddma)
-			  printk(", DMA %d", cddma);
-		  else
-			  printk(", no DMA");
-	  }
+	{
+		if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1)
+		{
+			printk("\n");
+			printk(KERN_ERR "Invalid CDROM DMA\n");
+			return -EINVAL;
+		}
+		if (cddma)
+			printk(", DMA %d", cddma);
+		else
+			printk(", no DMA");
+	}
 	if (cdtype && !cdirq)
 		printk(", no IRQ");
 	else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1)
-	  {
+	{
 		  printk(", invalid IRQ (disabling)");
 		  cdirq = 0;
-	} else
-		printk(", IRQ %d", cdirq);
+	}
+	else printk(", IRQ %d", cdirq);
 
-	printk(".\nJoystick port ");
+	printk(".\n");
+	printk(KERN_INFO "Joystick port ");
 	if (joystick == 1)
 		printk("enabled.\n");
 	else
-	  {
-		  joystick = 0;
-		  printk("disabled.\n");
-	  }
+	{
+		joystick = 0;
+		printk("disabled.\n");
+	}
 
 	/*
 	 *    Build the config words
@@ -967,26 +973,26 @@
 	mad16_cdsel |= dma_map[dmatype][cddma];
 
 	if (cdtype < 0x08)
-	  {
-		  switch (cdport)
-		    {
-		    case 0x340:
-			    mad16_cdsel |= 0x00;
-			    break;
-		    case 0x330:
-			    mad16_cdsel |= 0x40;
-			    break;
-		    case 0x360:
-			    mad16_cdsel |= 0x80;
-			    break;
-		    case 0x320:
-			    mad16_cdsel |= 0xC0;
-			    break;
-		    default:
-			    printk("Unknown CDROM I/O base %d\n", cdport);
-			    return -EINVAL;
-		    }
-	  }
+	{
+		switch (cdport)
+		{
+			case 0x340:
+				mad16_cdsel |= 0x00;
+				break;
+			case 0x330:
+				mad16_cdsel |= 0x40;
+				break;
+			case 0x360:
+				mad16_cdsel |= 0x80;
+				break;
+			case 0x320:
+				mad16_cdsel |= 0xC0;
+				break;
+			default:
+				printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport);
+				return -EINVAL;
+		}
+	}
 	mad16_cdsel |= irq_map[cdirq];
 
 	config.io_base = io;
@@ -996,19 +1002,21 @@
 
 	if (!probe_mad16(&config))
 		return -ENODEV;
-	found_mpu = probe_mad16_mpu(&config);
+
+	config_mpu.io_base = mpu_io;
+	config_mpu.irq = mpu_irq;
+	found_mpu = probe_mad16_mpu(&config_mpu);
 
 	attach_mad16(&config);
 
 	if (found_mpu)
-		attach_mad16_mpu(&config);
+		attach_mad16_mpu(&config_mpu);
 
 	SOUND_LOCK;
 	return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
 	if (found_mpu)
 		unload_mad16_mpu(&config);
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/maui.c linux/drivers/sound/maui.c
--- v2.1.93/linux/drivers/sound/maui.c	Tue Mar 17 22:18:15 1998
+++ linux/drivers/sound/maui.c	Wed Apr  8 17:24:48 1998
@@ -20,6 +20,7 @@
  
 #include <linux/config.h>
 #include <linux/module.h>
+#include <asm/init.h>
 
 #define USE_SEQ_MACROS
 #define USE_SIMPLE_MACROS
@@ -452,6 +453,11 @@
 
 #ifdef MODULE
 
+MODULE_PARM(io,"i");
+MODULE_PARM(irq,"i");
+
+EXPORT_NO_SYMBOLS;
+
 int io = -1;
 int irq = -1;
 
@@ -489,7 +495,7 @@
 void cleanup_module(void)
 {
 	if (fw_load && maui_os)
-		kfree(maui_os);
+		vfree(maui_os);
 	unload_maui(&cfg);
 	SOUND_LOCK_END;
 }
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c
--- v2.1.93/linux/drivers/sound/midibuf.c	Tue Mar 17 22:18:15 1998
+++ linux/drivers/sound/midibuf.c	Wed Apr  8 17:24:48 1998
@@ -15,6 +15,7 @@
  */
 #include <linux/config.h>
 #include <linux/stddef.h>
+#include <linux/kmod.h>
 
 #define MIDIBUF_C
 
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/opl3sa.c linux/drivers/sound/opl3sa.c
--- v2.1.93/linux/drivers/sound/opl3sa.c	Sat Nov 29 10:33:21 1997
+++ linux/drivers/sound/opl3sa.c	Wed Apr  8 17:24:48 1998
@@ -3,14 +3,21 @@
  *
  * Low level driver for Yamaha YMF701B aka OPL3-SA chip
  * 
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
+ *
+ * Changes:
+ *	Alan Cox		Modularisation
+ *
+ * FIXME:
+ * 	Check for install of mpu etc is wrong, should check result of the mss stuff
  */
+ 
 #include <linux/config.h>
 
 #undef  SB_OK
@@ -18,22 +25,21 @@
 #include "sound_config.h"
 #ifdef SB_OK
 #include "sb.h"
-static int      sb_initialized = 0;
+static int sb_initialized = 0;
 
 #endif
 
 #ifdef CONFIG_OPL3SA1
 
-static int      kilroy_was_here = 0;	/* Don't detect twice */
-static int      mpu_initialized = 0;
+static int kilroy_was_here = 0;	/* Don't detect twice */
+static int mpu_initialized = 0;
 
-static int     *opl3sa_osp = NULL;
+static int *opl3sa_osp = NULL;
 
-static unsigned char
-opl3sa_read(int addr)
+static unsigned char opl3sa_read(int addr)
 {
-	unsigned long   flags;
-	unsigned char   tmp;
+	unsigned long flags;
+	unsigned char tmp;
 
 	save_flags(flags);
 	cli();
@@ -45,10 +51,9 @@
 	return tmp;
 }
 
-static void
-opl3sa_write(int addr, int data)
+static void opl3sa_write(int addr, int data)
 {
-	unsigned long   flags;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
@@ -58,31 +63,32 @@
 	restore_flags(flags);
 }
 
-static int
-opl3sa_detect(void)
+static int opl3sa_detect(void)
 {
-	int             tmp;
+	int tmp;
 
 	if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04)
-	  {
-		  DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01)));
-		  /* return 0; */
-	  }
-/*
- * Check that the password feature has any effect
- */
+	{
+		DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01)));
+		/* return 0; */
+	}
+
+	/*
+	 * Check that the password feature has any effect
+	 */
+	
 	if (inb(0xf87) == tmp)
-	  {
-		  DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87)));
-		  return 0;
-	  }
+	{
+		DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87)));
+		return 0;
+	}
 	tmp = (opl3sa_read(0x04) & 0xe0) >> 5;
 
 	if (tmp != 0 && tmp != 1)
-	  {
-		  DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp));
-		  return 0;
-	  }
+	{
+		DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp));
+		return 0;
+	}
 	DDB(printk("OPL3-SA mode %x detected\n", tmp));
 
 	opl3sa_write(0x01, 0x00);	/* Disable MSS */
@@ -97,49 +103,50 @@
  *     OPL3-SA
  */
 
-int
-probe_opl3sa_wss(struct address_info *hw_config)
+int probe_opl3sa_wss(struct address_info *hw_config)
 {
-	int             ret;
-	unsigned char   tmp = 0x24;	/* WSS enable */
+	int ret;
+	unsigned char tmp = 0x24;	/* WSS enable */
 
 	if (check_region(0xf86, 2))	/* Control port is busy */
 		return 0;
 	/*
-	   * Check if the IO port returns valid signature. The original MS Sound
-	   * system returns 0x04 while some cards (OPL3-SA for example)
-	   * return 0x00.
+	 * Check if the IO port returns valid signature. The original MS Sound
+	 * system returns 0x04 while some cards (OPL3-SA for example)
+	 * return 0x00.
 	 */
+
 	if (check_region(hw_config->io_base, 8))
-	  {
-		  printk("OPL3-SA: MSS I/O port conflict (%x)\n", hw_config->io_base);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "OPL3-SA: MSS I/O port conflict (%x)\n", hw_config->io_base);
+		return 0;
+	}
 	opl3sa_osp = hw_config->osp;
 
 	if (!opl3sa_detect())
-	  {
-		  printk("OSS: OPL3-SA chip not found\n");
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "OSS: OPL3-SA chip not found\n");
+		return 0;
+	}
+	
 	switch (hw_config->io_base)
-	  {
-	  case 0x530:
-		  tmp |= 0x00;
-		  break;
-	  case 0xe80:
-		  tmp |= 0x08;
-		  break;
-	  case 0xf40:
-		  tmp |= 0x10;
-		  break;
-	  case 0x604:
-		  tmp |= 0x18;
-		  break;
-	  default:
-		  printk("OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base);
+	{
+		case 0x530:
+			tmp |= 0x00;
+			break;
+		case 0xe80:
+			tmp |= 0x08;
+			break;
+		case 0xf40:
+			tmp |= 0x10;
+			break;
+		case 0x604:
+			tmp |= 0x18;
+			break;
+		default:
+			printk(KERN_ERR "OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base);
 		  return 0;
-	  }
+	}
 
 	opl3sa_write(0x01, tmp);	/* WSS setup register */
 	kilroy_was_here = 1;
@@ -151,23 +158,21 @@
 	return ret;
 }
 
-void
-attach_opl3sa_wss(struct address_info *hw_config)
+void attach_opl3sa_wss(struct address_info *hw_config)
 {
-	int             nm = num_mixers;
+	int nm = num_mixers;
 
 	attach_ms_sound(hw_config);
 	if (num_mixers > nm)	/* A mixer was installed */
-	  {
-		  AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
-		  AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
-		  AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
-	  }
+	{
+		AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
+		AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
+		AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
+	}
 }
 
 
-void
-attach_opl3sa_mpu(struct address_info *hw_config)
+void attach_opl3sa_mpu(struct address_info *hw_config)
 {
 #if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
 	hw_config->name = "OPL3-SA (MPU401)";
@@ -175,55 +180,54 @@
 #endif
 }
 
-int
-probe_opl3sa_mpu(struct address_info *hw_config)
+int probe_opl3sa_mpu(struct address_info *hw_config)
 {
 #if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
-	unsigned char   conf;
-	static char     irq_bits[] =
-	{-1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4};
+	unsigned char conf;
+	static char irq_bits[] = {
+		-1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4
+	};
 
 	if (!kilroy_was_here)
-	  {
-		  return 0;	/* OPL3-SA has not been detected earlier */
-	  }
+		return 0;	/* OPL3-SA has not been detected earlier */
+
 	if (mpu_initialized)
-	  {
-		  DDB(printk("OPL3-SA: MPU mode already initialized\n"));
-		  return 0;
-	  }
+	{
+		DDB(printk("OPL3-SA: MPU mode already initialized\n"));
+		return 0;
+	}
 	if (check_region(hw_config->io_base, 4))
-	  {
-		  printk("OPL3-SA: MPU I/O port conflict (%x)\n", hw_config->io_base);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "OPL3-SA: MPU I/O port conflict (%x)\n", hw_config->io_base);
+		return 0;
+	}
 	if (hw_config->irq > 10)
-	  {
-		  printk("OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
+		return 0;
+	}
 	if (irq_bits[hw_config->irq] == -1)
-	  {
-		  printk("OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
+		return 0;
+	}
 	switch (hw_config->io_base)
-	  {
-	  case 0x330:
-		  conf = 0x00;
-		  break;
-	  case 0x332:
-		  conf = 0x20;
-		  break;
-	  case 0x334:
-		  conf = 0x40;
-		  break;
-	  case 0x300:
-		  conf = 0x60;
-		  break;
-	  default:
-		  return 0;	/* Invalid port */
-	  }
+	{
+		case 0x330:
+			conf = 0x00;
+			break;
+		case 0x332:
+			conf = 0x20;
+			break;
+		case 0x334:
+			conf = 0x40;
+			break;
+		case 0x300:
+			conf = 0x60;
+			break;
+		default:
+			return 0;	/* Invalid port */
+	}
 
 	conf |= 0x83;		/* MPU & OPL3 (synth) & game port enable */
 	conf |= irq_bits[hw_config->irq] << 2;
@@ -238,10 +242,9 @@
 #endif
 }
 
-void
-unload_opl3sa_wss(struct address_info *hw_config)
+void unload_opl3sa_wss(struct address_info *hw_config)
 {
-	int             dma2 = hw_config->dma2;
+	int dma2 = hw_config->dma2;
 
 	if (dma2 == -1)
 		dma2 = hw_config->dma;
@@ -256,16 +259,15 @@
 		      0);
 }
 
-void
-unload_opl3sa_mpu(struct address_info *hw_config)
+void unload_opl3sa_mpu(struct address_info *hw_config)
 {
 #if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
 	unload_uart401(hw_config);
 #endif
 }
+
 #ifdef SB_OK
-void
-unload_opl3sa_sb(struct address_info *hw_config)
+void unload_opl3sa_sb(struct address_info *hw_config)
 {
 #ifdef CONFIG_SBDSP
 	sb_dsp_unload(hw_config);
@@ -273,5 +275,60 @@
 }
 #endif
 
+#ifdef MODULE
+int             io = -1;
+int             irq = -1;
+int             dma = -1;
+int             dma2 = -1;
+
+int		mpu_io = -1;
+int 		mpu_irq = -1;
+
+MODULE_PARM(io,"i");
+MODULE_PARM(irq,"i");
+MODULE_PARM(dma,"i");
+MODULE_PARM(dma2,"i");
+MODULE_PARM(mpu_io,"i");
+MODULE_PARM(mpu_irq,"i");
+
+struct address_info cfg;
+struct address_info mpu_cfg;
+
+int init_module(void)
+{
+	if (io == -1 || irq == -1 || dma == -1)
+	{
+		printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n");
+		return -EINVAL;
+	}
+	cfg.io_base = io;
+	cfg.irq = irq;
+	cfg.dma = dma;
+	cfg.dma2 = dma2;
+	
+	mpu_cfg.io_base = mpu_io;
+	mpu_cfg.irq = mpu_irq;
+
+	if (probe_opl3sa_wss(&cfg) == 0)
+		return -ENODEV;
+
+	found_mpu=probe_opl3_mpu(&mpu_cfg);
+
+	attach_opl3sa_wss(&cfg);
+	if(found_mpu)
+		attach_opl3sa_mpu(&mpu_cfg);
+	SOUND_LOCK;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	if(found_mpu)
+		unload_opl3sa_mpu(&mpu_cfg);
+	unload_opl3sa(&cfg);
+	SOUND_LOCK_END;
+}
+
+#endif
 
 #endif
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- v2.1.93/linux/drivers/sound/os.h	Mon Feb 23 18:12:09 1998
+++ linux/drivers/sound/os.h	Wed Apr  8 17:24:48 1998
@@ -18,6 +18,7 @@
 #include <linux/string.h>
 #include <linux/fs.h>
 #include <asm/dma.h>
+#include <asm/io.h>
 #include <asm/param.h>
 #include <linux/ptrace.h>
 #include <linux/sched.h>
@@ -32,7 +33,6 @@
 #include <asm/uaccess.h>
 #include <linux/poll.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #endif
 
 #include <linux/wrapper.h>
@@ -52,7 +52,6 @@
 #define USE_AUTOINIT_DMA
 
 extern caddr_t sound_mem_blocks[1024];
-extern int sound_mem_sizes[1024];
 extern int sound_nblocks;
 
 #undef PSEUDO_DMA_AUTOINIT
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v2.1.93/linux/drivers/sound/pas2_card.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/sound/pas2_card.c	Wed Apr  8 17:24:48 1998
@@ -164,7 +164,7 @@
 		}
 		else
 		{
-			if (request_irq(pas_irq, pasintr, 0, "PAS16", NULL) < 0)
+			if (request_irq(pas_irq, pasintr, 0, "PAS16",NULL) < 0)
 				ok = 0;
 		}
 	}
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- v2.1.93/linux/drivers/sound/pss.c	Tue Mar 17 22:18:15 1998
+++ linux/drivers/sound/pss.c	Wed Apr  8 17:24:48 1998
@@ -2,18 +2,29 @@
  * sound/pss.c
  *
  * The low level driver for the Personal Sound System (ECHO ESC614).
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
- */
-/*
+ *
+ *
  * Thomas Sailer	ioctl code reworked (vmalloc/vfree removed)
  * Alan Cox		modularisation, clean up.
+ *
+ * 98-02-21: Vladimir Michl <vladimir.michl@upol.cz>
+ *          Added mixer device for Beethoven ADSP-16 (master volume,
+ *	    bass, treble, synth), only for speakers.
+ *          Fixed bug in pss_write (exchange parameters)
+ *          Fixed config port of SB
+ *          Requested two regions for PSS (PSS mixer, PSS config)
+ *          Modified pss_download_boot
+ *          To probe_pss_mss added test for initialize AD1848
  */
+
+
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -39,7 +50,7 @@
  */
 #define CONF_PSS	0x10
 #define CONF_WSS	0x12
-#define CONF_SB		0x13
+#define CONF_SB		0x14
 #define CONF_CDROM	0x16
 #define CONF_MIDI	0x18
 
@@ -53,6 +64,20 @@
 #define PSS_WRITE_EMPTY  0x8000
 #define PSS_READ_FULL    0x4000
 
+/*
+ * WSS registers
+ */
+#define WSS_INDEX 4
+#define WSS_DATA 5
+
+/*
+ * WSS status bits
+ */
+#define WSS_INITIALIZING 0x80
+#define WSS_AUTOCALIBRATION 0x20
+
+#define NO_WSS_MIXER	-1
+
 #include "coproc.h"
 
 #ifdef CONFIG_PSS_HAVE_BOOT
@@ -62,23 +87,32 @@
 static int pss_synthLen = 0;
 #endif
 
-typedef struct pss_confdata
-{
-	int	base;
-	int	irq;
-	int	dma;
-	int	*osp;
-}
-
-pss_confdata;
+unsigned char pss_mixer = 1;
 
+typedef struct pss_mixerdata {
+	unsigned int volume_l;
+	unsigned int volume_r;
+	unsigned int bass;
+	unsigned int treble;
+	unsigned int synth;
+} pss_mixerdata;
+
+typedef struct pss_confdata {
+	int             base;
+	int             irq;
+	int             dma;
+	int            *osp;
+	pss_mixerdata   mixer;
+	int             ad_mixer_dev;
+} pss_confdata;
+  
 static pss_confdata pss_data;
 static pss_confdata *devc = &pss_data;
 
 static int      pss_initialized = 0;
 static int      nonstandard_microcode = 0;
 
-static void pss_write(int data)
+static void pss_write(pss_confdata *devc, int data)
 {
 	int i, limit;
 
@@ -92,14 +126,14 @@
 	 */
 
 	for (i = 0; i < 5000000 && jiffies < limit; i++)
-	{
-		if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY)
-		{
-			outw(devc->base + PSS_DATA, data);
-			return;
-		}
-	}
-	printk(KERN_ERR "PSS: DSP Command (%04x) Timeout.\n", data);
+ 	{
+ 		if (inw(REG(PSS_STATUS)) & PSS_WRITE_EMPTY)
+ 		{
+ 			outw(data, REG(PSS_DATA));
+ 			return;
+ 		}
+ 	}
+ 	printk(KERN_WARNING "PSS: DSP Command (%04x) Timeout.\n", data);
 }
 
 int probe_pss(struct address_info *hw_config)
@@ -116,7 +150,7 @@
 		if (devc->base != 0x230 && devc->base != 0x250)		/* Some cards use these */
 			return 0;
 
-	if (check_region(devc->base, 16)) { 
+	if (check_region(devc->base, 0x19 /*16*/)) { 
 		printk(KERN_ERR "PSS: I/O port conflict\n");
 		return 0;
 	}
@@ -249,7 +283,7 @@
 		pss_reset_dsp(devc);
 	}
 	count = 1;
-	while (1)
+	while ((flags&CPF_LAST) || count<size )
 	{
 		int j;
 
@@ -267,12 +301,22 @@
 				break;
 			else
 			{
-				printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size);
+				printk("\n");
+				printk(KERN_ERR "PSS: Download timeout problems, byte %d=%d\n", count, size);
 				return 0;
 			}
 		}
 /*_____ Send the next byte */
-		outw(*block++, REG(PSS_DATA));
+		if (count >= size) 
+		{
+			/* If not data in block send 0xffff */
+			outw (0xffff, REG (PSS_DATA));
+		}
+		else
+		{
+			/*_____ Send the next byte */
+			outw (*block++, REG (PSS_DATA));
+		};
 		count++;
 	}
 
@@ -309,6 +353,237 @@
 	return 1;
 }
 
+/* Mixer */
+static void set_master_volume(pss_confdata *devc, int left, int right)
+{
+	static unsigned char log_scale[101] =  {
+		0xdb, 0xe0, 0xe3, 0xe5, 0xe7, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee,
+		0xef, 0xef, 0xf0, 0xf0, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3,
+		0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7,
+		0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9,
+		0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb,
+		0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
+		0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd,
+		0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
+		0xfe, 0xfe, 0xff, 0xff, 0xff
+	};
+	pss_write(devc, 0x0010);
+	pss_write(devc, log_scale[left] | 0x0000);
+	pss_write(devc, 0x0010);
+	pss_write(devc, log_scale[right] | 0x0100);
+}
+
+static void set_synth_volume(pss_confdata *devc, int volume)
+{
+	/* Should use:
+		int vol = (int)(0x8000/100.0 * (float)volume);
+		
+	  Fixme: integerise the above cleanly
+	*/
+	int vol = (0x8000/(100L*volume));
+	pss_write(devc, 0x0080);
+	pss_write(devc, vol);
+	pss_write(devc, 0x0081);
+	pss_write(devc, vol);
+}
+
+static void set_bass(pss_confdata *devc, int level)
+{
+	/* Should use
+	   int vol = (int)((0xfd - 0xf0)/100.0 * (float)level) + 0xf0;     
+	   
+	   Fixme: integerise cleanly 
+	*/
+	int vol = (int)((0xfd - 0xf0)/100L * level) + 0xf0;
+	pss_write(devc, 0x0010);
+	pss_write(devc, vol | 0x0200);
+};
+
+static void set_treble(pss_confdata *devc, int level)
+{	
+	/* Should use 
+	   int vol = (int)((0xfd - 0xf0)/100.0 * (float)level) + 0xf0;
+	   
+	   Fixme: integerise properly
+	*/
+	
+	int vol = ((0xfd - 0xf0)/100L * level) + 0xf0;
+	pss_write(devc, 0x0010);
+	pss_write(devc, vol | 0x0300);
+};
+
+static void pss_mixer_reset(pss_confdata *devc)
+{
+	set_master_volume(devc, 23, 23);
+	set_bass(devc, 50);
+	set_treble(devc, 50);
+	set_synth_volume(devc, 30);
+	pss_write (devc, 0x0010);
+	pss_write (devc, 0x0800 | 0xce);	/* Stereo */
+	
+	if(pss_mixer)
+	{
+		devc->mixer.volume_l = devc->mixer.volume_r = 23;
+		devc->mixer.bass = 50;
+		devc->mixer.treble = 50;
+		devc->mixer.synth = 30;
+	}
+}
+
+static void arg_to_volume_mono(unsigned int volume, int *aleft)
+{
+	int left;
+	
+	left = volume & 0x00ff;
+	if (left > 100)
+		left = 100;
+	*aleft = left;
+}
+
+static void arg_to_volume_stereo(unsigned int volume, int *aleft, int *aright)
+{
+	arg_to_volume_mono(volume, aleft);
+	arg_to_volume_mono(volume >> 8, aright);
+}
+
+static int ret_vol_mono(int left)
+{
+	return ((left << 8) | left);
+}
+
+static int ret_vol_stereo(int left, int right)
+{
+	return ((right << 8) | left);
+}
+
+static int call_ad_mixer(pss_confdata *devc,unsigned int cmd, caddr_t arg)
+{
+	if (devc->ad_mixer_dev != NO_WSS_MIXER) 
+		return mixer_devs[devc->ad_mixer_dev]->ioctl(devc->ad_mixer_dev, cmd, arg);
+	else 
+		return -EINVAL;
+}
+
+static int pss_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
+{
+	pss_confdata *devc = mixer_devs[dev]->devc;
+	int cmdf = cmd & 0xff;
+	
+	if ((cmdf != SOUND_MIXER_VOLUME) && (cmdf != SOUND_MIXER_BASS) &&
+		(cmdf != SOUND_MIXER_TREBLE) && (cmdf != SOUND_MIXER_SYNTH) &&
+		(cmdf != SOUND_MIXER_DEVMASK) && (cmdf != SOUND_MIXER_STEREODEVS) &&
+		(cmdf != SOUND_MIXER_RECMASK) && (cmdf != SOUND_MIXER_CAPS) &&
+		(cmdf != SOUND_MIXER_RECSRC)) 
+	{
+		return call_ad_mixer(devc, cmd, arg);
+	}
+	
+	if (((cmd >> 8) & 0xff) != 'M')	
+		return -EINVAL;
+		
+	if (_SIOC_DIR (cmd) & _SIOC_WRITE)
+	{
+		switch (cmdf)	
+		{
+			case SOUND_MIXER_RECSRC:
+				if (devc->ad_mixer_dev != NO_WSS_MIXER)
+					return call_ad_mixer(devc, cmd, arg);
+				else
+				{
+					if (*(int *)arg != 0)
+						return -EINVAL;
+					return 0;
+				}
+			case SOUND_MIXER_VOLUME:
+				arg_to_volume_stereo(*(unsigned int *)arg, &devc->mixer.volume_l,
+					&devc->mixer.volume_r); 
+				set_master_volume(devc, devc->mixer.volume_l,
+					devc->mixer.volume_r);
+				return ret_vol_stereo(devc->mixer.volume_l,
+					devc->mixer.volume_r);
+		  
+			case SOUND_MIXER_BASS:
+				arg_to_volume_mono(*(unsigned int *)arg,
+					&devc->mixer.bass);
+				set_bass(devc, devc->mixer.bass);
+				return ret_vol_mono(devc->mixer.bass);
+		  
+			case SOUND_MIXER_TREBLE:
+				arg_to_volume_mono(*(unsigned int *)arg,
+					&devc->mixer.treble);
+				set_treble(devc, devc->mixer.treble);
+				return ret_vol_mono(devc->mixer.treble);
+		  
+			case SOUND_MIXER_SYNTH:
+				arg_to_volume_mono(*(unsigned int *)arg,
+					&devc->mixer.synth);
+				set_synth_volume(devc, devc->mixer.synth);
+				return ret_vol_mono(devc->mixer.synth);
+		  
+			default:
+				return -EINVAL;
+		}
+	}
+	else			
+	{
+		/*
+		 * Return parameters
+		 */
+		switch (cmdf)
+		{
+
+			case SOUND_MIXER_DEVMASK:
+				if (call_ad_mixer(devc, cmd, arg) == -EINVAL)
+					*(int *)arg = 0; /* no mixer devices */
+				return (*(int *)arg |= SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_SYNTH);
+		  
+			case SOUND_MIXER_STEREODEVS:
+				if (call_ad_mixer(devc, cmd, arg) == -EINVAL)
+					*(int *)arg = 0; /* no stereo devices */
+				return (*(int *)arg |= SOUND_MASK_VOLUME);
+		  
+			case SOUND_MIXER_RECMASK:
+				if (devc->ad_mixer_dev != NO_WSS_MIXER)
+					return call_ad_mixer(devc, cmd, arg);
+				else
+					return (*(int *)arg = 0); /* no record devices */
+
+			case SOUND_MIXER_CAPS:
+				if (devc->ad_mixer_dev != NO_WSS_MIXER)
+					return call_ad_mixer(devc, cmd, arg);
+				else
+					return (*(int *)arg = SOUND_CAP_EXCL_INPUT);
+
+			case SOUND_MIXER_RECSRC:
+				if (devc->ad_mixer_dev != NO_WSS_MIXER)
+					return call_ad_mixer(devc, cmd, arg);
+				else
+					return (*(int *)arg = 0); /* no record source */
+
+			case SOUND_MIXER_VOLUME:
+				return (*(int *)arg = ret_vol_stereo(devc->mixer.volume_l, devc->mixer.volume_r));
+			  
+			case SOUND_MIXER_BASS:
+				return (*(int *)arg = ret_vol_mono(devc->mixer.bass));
+			  
+			case SOUND_MIXER_TREBLE:
+				return (*(int *)arg = ret_vol_mono(devc->mixer.treble));
+			  
+			case SOUND_MIXER_SYNTH:
+				return (*(int *)arg = ret_vol_mono(devc->mixer.synth));
+			default:
+				return -EINVAL;
+		}
+	}
+}
+
+static struct mixer_operations pss_mixer_operations =
+{
+	"SOUNDPORT",
+	"PSS-AD1848",
+	 pss_mixer_ioctl
+};
+
 void attach_pss(struct address_info *hw_config)
 {
 	unsigned short  id;
@@ -318,10 +593,14 @@
 	devc->irq = hw_config->irq;
 	devc->dma = hw_config->dma;
 	devc->osp = hw_config->osp;
+	devc->ad_mixer_dev = NO_WSS_MIXER;
 
 	if (!probe_pss(hw_config))
 		return;
 
+	request_region(hw_config->io_base, 0x10, "PSS mixer, SB emulation");
+	request_region(hw_config->io_base + 0x10, 0x9, "PSS config");
+
 	id = inw(REG(PSS_ID)) & 0x00ff;
 
 	/*
@@ -356,21 +635,6 @@
 	conf_printf(tmp, hw_config);
 }
 
-static void pss_init_speaker(void)
-{
-/* Don't ask what are these commands. I really don't know */
-	pss_write(0x0010);
-	pss_write(0x0000 | 252);	/* Left master volume */
-	pss_write(0x0010);
-	pss_write(0x0100 | 252);	/* Right master volume */
-	pss_write(0x0010);
-	pss_write(0x0200 | 246);	/* Bass */
-	pss_write(0x0010);
-	pss_write(0x0300 | 246);	/* Treble */
-	pss_write(0x0010);
-	pss_write(0x0800 | 0x00ce);	/* Stereo switch? */
-}
-
 int probe_pss_mpu(struct address_info *hw_config)
 {
 	int timeout;
@@ -380,17 +644,17 @@
 
 	if (check_region(hw_config->io_base, 2))
 	{
-		printk("PSS: MPU I/O port conflict\n");
+		printk(KERN_ERR "PSS: MPU I/O port conflict\n");
 		return 0;
 	}
 	if (!set_io_base(devc, CONF_MIDI, hw_config->io_base))
 	{
-		  printk("PSS: MIDI base could not be set.\n");
+		  printk(KERN_ERR "PSS: MIDI base could not be set.\n");
 		  return 0;
 	}
 	if (!set_irq(devc, CONF_MIDI, hw_config->irq))
 	{
-		  printk("PSS: MIDI IRQ allocation error.\n");
+		  printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n");
 		  return 0;
 	}
 	if (!pss_synthLen)
@@ -403,7 +667,6 @@
 		printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n");
 		return 0;
 	}
-	pss_init_speaker();
 
 	/*
 	 * Finally wait until the DSP algorithm has initialized itself and
@@ -709,28 +972,51 @@
 	 * downloaded to the ADSP2115 spends some time initializing the card.
 	 * Let's try to wait until it finishes this task.
 	 */
-	for (timeout = 0;
-	timeout < 100000 && (inb(hw_config->io_base + 3) & 0x3f) != 0x04;
-	     timeout++);
-
-	outb((0x0b), hw_config->io_base + 4);	/* Required by some cards */
-
-	for (timeout = 0;
-	     timeout < 100000;
-	     timeout++);
+	for (timeout = 0; timeout < 100000 && (inb(hw_config->io_base + WSS_INDEX) & WSS_INITIALIZING); timeout++);
+
+	outb((0x0b), hw_config->io_base + WSS_INDEX);	/* Required by some cards */
+
+	for (timeout = 0; (inb(hw_config->io_base + WSS_DATA) & WSS_AUTOCALIBRATION) && (timeout < 100000); timeout++);
+
 	return probe_ms_sound(hw_config);
 }
 
 void attach_pss_mss(struct address_info *hw_config)
 {
+	int        my_mix = -999;	/* gcc shut up */
+	
+	devc->ad_mixer_dev = NO_WSS_MIXER;
+	if (pss_mixer) 
+	{
+		if ((my_mix = sound_install_mixer (MIXER_DRIVER_VERSION,
+			"PSS-SPEAKERS and AD1848 (through MSS audio codec)",
+			&pss_mixer_operations,
+			sizeof (struct mixer_operations),
+			devc)) < 0) 
+		{
+			printk(KERN_ERR "Could not install PSS mixer\n");
+			return;
+		}
+	}
+	pss_mixer_reset(devc);
 	attach_ms_sound(hw_config);	/* Slot 0 */
 
-	if (hw_config->slots[0] != -1)	/* The MSS driver installed itself */
+	if (hw_config->slots[0] != -1)
+	{
+		/* The MSS driver installed itself */
 		audio_devs[hw_config->slots[0]]->coproc = &pss_coproc_operations;
+		if (pss_mixer && (num_mixers == (my_mix + 2)))
+		{
+			/* The MSS mixer installed */
+			devc->ad_mixer_dev = audio_devs[hw_config->slots[0]]->mixer_dev;
+		}
+	}
 }
 
 void unload_pss(struct address_info *hw_config)
 {
+	release_region(hw_config->io_base, 0x10);
+	release_region(hw_config->io_base+0x10, 0x9);
 }
 
 void unload_pss_mpu(struct address_info *hw_config)
@@ -761,11 +1047,21 @@
 struct address_info cfgmss = { 0 /* mss_io */, 0 /* mss_irq */, 0 /* mss_dma */, -1 };
 
 MODULE_PARM(pss_io, "i");
+MODULE_PARM_DESC(pss_io, "Set i/o base of PSS card (probably 0x220 or 0x240)");
 MODULE_PARM(mss_io, "i");
+MODULE_PARM_DESC(mss_io, "Set WSS (audio) i/o base (0x530, 0x604, 0xE80, 0xF40, or other. Address must end in 0 or 4 and must be from 0x100 to 0xFF4)");
 MODULE_PARM(mss_irq, "i");
+MODULE_PARM_DESC(mss_irq, "Set WSS (audio) IRQ (3, 5, 7, 9, 10, 11, 12)");
 MODULE_PARM(mss_dma, "i");
+MODULE_PARM_DESC(mss_dma, "Set WSS (audio) DMA (0, 1, 3)");
 MODULE_PARM(mpu_io, "i");
+MODULE_PARM_DESC(mpu_io, "Set MIDI i/o base (0x330 or other. Address must be on 4 location boundaries and must be from 0x100 to 0xFFC)");
 MODULE_PARM(mpu_irq, "i");
+MODULE_PARM_DESC(mpu_irq, "Set MIDI IRQ (3, 5, 7, 9, 10, 11, 12)");
+MODULE_PARM(pss_mixer, "b");
+MODULE_PARM_DESC(pss_mixer, "Enable (1) or disable (0) PSS mixer (controlling of output volume, bass, treble synth volume). The mixer is not available on all PSS cards.");
+MODULE_AUTHOR("Hannu Savolainen, Vladimir Michl");
+MODULE_DESCRIPTION("Module for PSS sound cards (based on AD1848, ADSP-2115 and ESC614). This module includes control of output amplifier and synth volume of the Beethoven ADSP-16 card (this may work with other PSS cards).\n");
 
 static int fw_load = 0;
 static int pssmpu = 0, pssmss = 0;
@@ -816,7 +1112,7 @@
 void cleanup_module(void)
 {
 	if (fw_load && pss_synth)
-		kfree(pss_synth);
+		vfree(pss_synth);
 	if (pssmss)
 		unload_pss_mss(&cfgmss);
 	if (pssmpu)
@@ -825,5 +1121,4 @@
 	SOUND_LOCK_END;
 }
 #endif
-
 #endif
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb.h linux/drivers/sound/sb.h
--- v2.1.93/linux/drivers/sound/sb.h	Tue Dec 23 13:52:02 1997
+++ linux/drivers/sound/sb.h	Wed Apr  8 17:24:48 1998
@@ -47,6 +47,8 @@
 #define MDL_ES1868MIDI	14	/* MIDI port of ESS1868 */
 #define MDL_AEDSP	15	/* Audio Excel DSP 16 */
 
+#define SUBMDL_ALS007	42	/* ALS-007 differs from SB16 only in mixer */
+				/* register assignment */
 /*
  * Config flags
  */
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c
--- v2.1.93/linux/drivers/sound/sb_audio.c	Tue Mar 17 22:18:15 1998
+++ linux/drivers/sound/sb_audio.c	Wed Apr  8 17:24:48 1998
@@ -2,17 +2,22 @@
  * sound/sb_audio.c
  *
  * Audio routines for Sound Blaster compatible cards.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
+ *
+ * Changes
+ *	Alan Cox	:	Formatting and clean ups
+ *
+ * Status
+ *	Mostly working. mmap bug still present (swaps channels)
  */
-#include <linux/config.h>
-
 
+#include <linux/config.h>
 #include "sound_config.h"
 
 #if defined(CONFIG_SBDSP) || defined(MODULE)
@@ -20,67 +25,84 @@
 #include "sb_mixer.h"
 #include "sb.h"
 
-static int
-sb_audio_open(int dev, int mode)
+static int sb_audio_open(int dev, int mode)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
-	unsigned long   flags;
+	sb_devc *devc = audio_devs[dev]->devc;
+	unsigned long flags;
 
 	if (devc == NULL)
-	  {
-		  printk("SB: Incomplete initialization\n");
+	{
+		  printk(KERN_ERR "SB: Incomplete initialization\n");
 		  return -ENXIO;
-	  }
+	}
 	if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ)
-	  {
-		  printk("Notice: Recording is not possible with /dev/dsp%d\n", dev);
-		  if (mode == OPEN_READ)
-			  return -EPERM;
-	  }
+	{
+		if (mode == OPEN_READ)
+			return -EPERM;
+	}
 	save_flags(flags);
 	cli();
 	if (devc->opened)
-	  {
+	{
 		  restore_flags(flags);
 		  return -EBUSY;
-	  }
+	}
 	if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
-	  {
-		  if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit"))
-		    {
-			    restore_flags(flags);
-			    return -EBUSY;
-		    }
-	  }
+	{
+		if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit"))
+		{
+			restore_flags(flags);
+			return -EBUSY;
+		}
+	}
 	devc->opened = mode;
 	restore_flags(flags);
 
 	devc->irq_mode = IMODE_NONE;
 	sb_dsp_reset(devc);
 
+	/* The ALS007 seems to require that the DSP be removed from the output */
+	/* in order for recording to be activated properly.  This is done by   */
+	/* setting the appropriate bits of the output control register 4ch to  */
+	/* zero.  This code assumes that the output control registers are not  */
+	/* used anywhere else and therefore the DSP bits are *always* ON for   */
+	/* output and OFF for sampling.                                        */
+
+	if (devc->submodel == SUBMDL_ALS007) 
+	{
+		if (mode & OPEN_READ) 
+			sb_setmixer(devc,ALS007_OUTPUT_CTRL2,
+				sb_getmixer(devc,ALS007_OUTPUT_CTRL2) & 0xf9);
+		else
+			sb_setmixer(devc,ALS007_OUTPUT_CTRL2,
+				sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06);
+	}
 	return 0;
 }
 
-static void
-sb_audio_close(int dev)
+static void sb_audio_close(int dev)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
-	audio_devs[dev]->dmap_in->dma =
-	    audio_devs[dev]->dmap_out->dma =
-	    devc->dma8;
+	audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma = devc->dma8;
 
 	if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
 		sound_close_dma(devc->dma16);
 
+	/* For ALS007, turn DSP output back on if closing the device for read */
+	
+	if ((devc->submodel == SUBMDL_ALS007) && (devc->opened & OPEN_READ)) 
+	{
+		sb_setmixer(devc,ALS007_OUTPUT_CTRL2,
+			sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06);
+	}
 	devc->opened = 0;
 }
 
-static void
-sb_set_output_parms(int dev, unsigned long buf, int nr_bytes,
+static void sb_set_output_parms(int dev, unsigned long buf, int nr_bytes,
 		    int intrflag)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	devc->trg_buf = buf;
 	devc->trg_bytes = nr_bytes;
@@ -88,10 +110,9 @@
 	devc->irq_mode = IMODE_OUTPUT;
 }
 
-static void
-sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag)
+static void sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	devc->trg_buf = buf;
 	devc->trg_bytes = count;
@@ -103,13 +124,11 @@
  * SB1.x compatible routines 
  */
 
-static void
-sb1_audio_output_block(int dev, unsigned long buf, int nr_bytes,
-		       int intrflag)
+static void sb1_audio_output_block(int dev, unsigned long buf, int nr_bytes, int intrflag)
 {
-	unsigned long   flags;
-	int             count = nr_bytes;
-	sb_devc        *devc = audio_devs[dev]->devc;
+	unsigned long flags;
+	int count = nr_bytes;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
 
@@ -122,21 +141,21 @@
 	save_flags(flags);
 	cli();
 	if (sb_dsp_command(devc, 0x14))		/* 8 bit DAC using DMA */
-	  {
-		  sb_dsp_command(devc, (unsigned char) (count & 0xff));
-		  sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff));
-	} else
-		printk("SB: Unable to start DAC\n");
+	{
+		sb_dsp_command(devc, (unsigned char) (count & 0xff));
+		sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff));
+	}
+	else
+		printk(KERN_WARNING "soundblaster: Unable to start DAC\n");
 	restore_flags(flags);
 	devc->intr_active = 1;
 }
 
-static void
-sb1_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag)
+static void sb1_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag)
 {
-	unsigned long   flags;
-	int             count = nr_bytes;
-	sb_devc        *devc = audio_devs[dev]->devc;
+	unsigned long flags;
+	int count = nr_bytes;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	/*
 	 * Start a DMA input to the buffer pointed by dmaqtail
@@ -153,49 +172,47 @@
 	save_flags(flags);
 	cli();
 	if (sb_dsp_command(devc, 0x24))		/* 8 bit ADC using DMA */
-	  {
-		  sb_dsp_command(devc, (unsigned char) (count & 0xff));
-		  sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff));
-	} else
-		printk("SB Error: Unable to start ADC\n");
+	{
+		sb_dsp_command(devc, (unsigned char) (count & 0xff));
+		sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff));
+	}
+	else
+		printk(KERN_ERR "soundblaster: Unable to start ADC\n");
 	restore_flags(flags);
 
 	devc->intr_active = 1;
 }
 
-static void
-sb1_audio_trigger(int dev, int bits)
+static void sb1_audio_trigger(int dev, int bits)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	bits &= devc->irq_mode;
 
 	if (!bits)
 		sb_dsp_command(devc, 0xd0);	/* Halt DMA */
 	else
-	  {
-		  switch (devc->irq_mode)
-		    {
-		    case IMODE_INPUT:
-			    sb1_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
-						  devc->trg_intrflag);
-			    break;
-
-		    case IMODE_OUTPUT:
-			    sb1_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
-						   devc->trg_intrflag);
-			    break;
-		    }
-	  }
+	{
+		switch (devc->irq_mode)
+		{
+			case IMODE_INPUT:
+				sb1_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
+						devc->trg_intrflag);
+				break;
 
+			case IMODE_OUTPUT:
+				sb1_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
+						devc->trg_intrflag);
+				break;
+		}
+	}
 	devc->trigger_bits = bits;
 }
 
-static int
-sb1_audio_prepare_for_input(int dev, int bsize, int bcount)
+static int sb1_audio_prepare_for_input(int dev, int bsize, int bcount)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
-	unsigned long   flags;
+	sb_devc *devc = audio_devs[dev]->devc;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
@@ -208,11 +225,10 @@
 	return 0;
 }
 
-static int
-sb1_audio_prepare_for_output(int dev, int bsize, int bcount)
+static int sb1_audio_prepare_for_output(int dev, int bsize, int bcount)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
-	unsigned long   flags;
+	sb_devc *devc = audio_devs[dev]->devc;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
@@ -224,55 +240,48 @@
 	return 0;
 }
 
-static int
-sb1_audio_set_speed(int dev, int speed)
+static int sb1_audio_set_speed(int dev, int speed)
 {
-	int             max_speed = 23000;
-	sb_devc        *devc = audio_devs[dev]->devc;
-	int             tmp;
+	int max_speed = 23000;
+	sb_devc *devc = audio_devs[dev]->devc;
+	int tmp;
 
 	if (devc->opened & OPEN_READ)
 		max_speed = 13000;
 
 	if (speed > 0)
-	  {
-		  if (speed < 4000)
-			  speed = 4000;
-
-		  if (speed > max_speed)
-			  speed = max_speed;
+	{
+		if (speed < 4000)
+			speed = 4000;
 
-		  devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
+		if (speed > max_speed)
+			speed = max_speed;
 
-		  tmp = 256 - devc->tconst;
-		  speed = (1000000 + tmp / 2) / tmp;
+		devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
+		tmp = 256 - devc->tconst;
+		speed = (1000000 + tmp / 2) / tmp;
 
-		  devc->speed = speed;
-	  }
+		devc->speed = speed;
+	}
 	return devc->speed;
 }
 
-static short
-sb1_audio_set_channels(int dev, short channels)
+static short sb1_audio_set_channels(int dev, short channels)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
-
+	sb_devc *devc = audio_devs[dev]->devc;
 	return devc->channels = 1;
 }
 
-static unsigned int
-sb1_audio_set_bits(int dev, unsigned int bits)
+static unsigned int sb1_audio_set_bits(int dev, unsigned int bits)
 {
 	sb_devc        *devc = audio_devs[dev]->devc;
-
 	return devc->bits = 8;
 }
 
-static void
-sb1_audio_halt_xfer(int dev)
+static void sb1_audio_halt_xfer(int dev)
 {
-	unsigned long   flags;
-	sb_devc        *devc = audio_devs[dev]->devc;
+	unsigned long flags;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	save_flags(flags);
 	cli();
@@ -284,14 +293,13 @@
  * SB 2.0 and SB 2.01 compatible routines
  */
 
-static void
-sb20_audio_output_block(int dev, unsigned long buf, int nr_bytes,
+static void sb20_audio_output_block(int dev, unsigned long buf, int nr_bytes,
 			int intrflag)
 {
-	unsigned long   flags;
-	int             count = nr_bytes;
-	sb_devc        *devc = audio_devs[dev]->devc;
-	unsigned char   cmd;
+	unsigned long flags;
+	int count = nr_bytes;
+	sb_devc *devc = audio_devs[dev]->devc;
+	unsigned char cmd;
 
 	/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
 
@@ -304,31 +312,30 @@
 	save_flags(flags);
 	cli();
 	if (sb_dsp_command(devc, 0x48))		/* DSP Block size */
-	  {
-		  sb_dsp_command(devc, (unsigned char) (count & 0xff));
-		  sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff));
-
-		  if (devc->speed * devc->channels <= 23000)
-			  cmd = 0x1c;	/* 8 bit PCM output */
-		  else
-			  cmd = 0x90;	/* 8 bit high speed PCM output (SB2.01/Pro) */
+	{
+		sb_dsp_command(devc, (unsigned char) (count & 0xff));
+		sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff));
 
-		  if (!sb_dsp_command(devc, cmd))
-			  printk("SB: Unable to start DAC\n");
+		if (devc->speed * devc->channels <= 23000)
+			cmd = 0x1c;	/* 8 bit PCM output */
+		else
+			cmd = 0x90;	/* 8 bit high speed PCM output (SB2.01/Pro) */
 
-	} else
-		printk("SB: Unable to start DAC\n");
+		if (!sb_dsp_command(devc, cmd))
+			printk(KERN_ERR "soundblaster: Unable to start DAC\n");
+	}
+	else
+		printk(KERN_ERR "soundblaster: Unable to start DAC\n");
 	restore_flags(flags);
 	devc->intr_active = 1;
 }
 
-static void
-sb20_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag)
+static void sb20_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag)
 {
-	unsigned long   flags;
-	int             count = nr_bytes;
-	sb_devc        *devc = audio_devs[dev]->devc;
-	unsigned char   cmd;
+	unsigned long flags;
+	int count = nr_bytes;
+	sb_devc *devc = audio_devs[dev]->devc;
+	unsigned char cmd;
 
 	/*
 	 * Start a DMA input to the buffer pointed by dmaqtail
@@ -345,49 +352,46 @@
 	save_flags(flags);
 	cli();
 	if (sb_dsp_command(devc, 0x48))		/* DSP Block size */
-	  {
-		  sb_dsp_command(devc, (unsigned char) (count & 0xff));
-		  sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff));
-
-		  if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000))
-			  cmd = 0x2c;	/* 8 bit PCM input */
-		  else
-			  cmd = 0x98;	/* 8 bit high speed PCM input (SB2.01/Pro) */
-
-		  if (!sb_dsp_command(devc, cmd))
-			  printk("SB: Unable to start ADC\n");
-	} else
-		printk("SB Error: Unable to start ADC\n");
-	restore_flags(flags);
+	{
+		sb_dsp_command(devc, (unsigned char) (count & 0xff));
+		sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff));
 
+		if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000))
+			cmd = 0x2c;	/* 8 bit PCM input */
+		else
+			cmd = 0x98;	/* 8 bit high speed PCM input (SB2.01/Pro) */
+
+		if (!sb_dsp_command(devc, cmd))
+			printk(KERN_ERR "soundblaster: Unable to start ADC\n");
+	}
+	else
+		printk(KERN_ERR "soundblaster: Unable to start ADC\n");
+	restore_flags(flags);
 	devc->intr_active = 1;
 }
 
-static void
-sb20_audio_trigger(int dev, int bits)
+static void sb20_audio_trigger(int dev, int bits)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
-
+	sb_devc *devc = audio_devs[dev]->devc;
 	bits &= devc->irq_mode;
 
 	if (!bits)
 		sb_dsp_command(devc, 0xd0);	/* Halt DMA */
 	else
-	  {
-		  switch (devc->irq_mode)
-		    {
-		    case IMODE_INPUT:
-			    sb20_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
-						   devc->trg_intrflag);
-			    break;
+	{
+		switch (devc->irq_mode)
+		{
+			case IMODE_INPUT:
+				sb20_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
+						devc->trg_intrflag);
+				break;
 
-		    case IMODE_OUTPUT:
-			    sb20_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
-						    devc->trg_intrflag);
+			case IMODE_OUTPUT:
+				sb20_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
+						devc->trg_intrflag);
 			    break;
-		    }
-	  }
-
+		}
+	}
 	devc->trigger_bits = bits;
 }
 
@@ -395,32 +399,26 @@
  * SB2.01 specific speed setup
  */
 
-static int
-sb201_audio_set_speed(int dev, int speed)
+static int sb201_audio_set_speed(int dev, int speed)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
-	int             tmp;
-	int             s = speed * devc->channels;
+	sb_devc *devc = audio_devs[dev]->devc;
+	int tmp;
+	int s = speed * devc->channels;
 
 	if (speed > 0)
-	  {
-		  if (speed < 4000)
-			  speed = 4000;
-
-		  if (speed > 44100)
-			  speed = 44100;
-
-		  if (devc->opened & OPEN_READ && speed > 15000)
-			  speed = 15000;
-
-		  devc->tconst = ((65536 - ((256000000 + s / 2) /
-					    s)) >> 8) & 0xff;
-
-		  tmp = 256 - devc->tconst;
-		  speed = ((1000000 + tmp / 2) / tmp) / devc->channels;
+	{
+		if (speed < 4000)
+			speed = 4000;
+		if (speed > 44100)
+			speed = 44100;
+		if (devc->opened & OPEN_READ && speed > 15000)
+			speed = 15000;
+		devc->tconst = ((65536 - ((256000000 + s / 2) / s)) >> 8) & 0xff;
+		tmp = 256 - devc->tconst;
+		speed = ((1000000 + tmp / 2) / tmp) / devc->channels;
 
-		  devc->speed = speed;
-	  }
+		devc->speed = speed;
+	}
 	return devc->speed;
 }
 
@@ -428,17 +426,15 @@
  * SB Pro specific routines
  */
 
-static int
-sbpro_audio_prepare_for_input(int dev, int bsize, int bcount)
+static int sbpro_audio_prepare_for_input(int dev, int bsize, int bcount)
 {				/* For SB Pro and Jazz16 */
-	sb_devc        *devc = audio_devs[dev]->devc;
-	unsigned long   flags;
-	unsigned char   bits = 0;
+	sb_devc *devc = audio_devs[dev]->devc;
+	unsigned long flags;
+	unsigned char bits = 0;
 
 	if (devc->dma16 >= 0 && devc->dma16 != devc->dma8)
-		audio_devs[dev]->dmap_out->dma =
-		    audio_devs[dev]->dmap_in->dma =
-		    devc->bits == 16 ? devc->dma16 : devc->dma8;
+		audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma =
+			devc->bits == 16 ? devc->dma16 : devc->dma8;
 
 	if (devc->model == MDL_JAZZ || devc->model == MDL_SMW)
 		if (devc->bits == AFMT_S16_LE)
@@ -459,18 +455,15 @@
 	return 0;
 }
 
-static int
-sbpro_audio_prepare_for_output(int dev, int bsize, int bcount)
+static int sbpro_audio_prepare_for_output(int dev, int bsize, int bcount)
 {				/* For SB Pro and Jazz16 */
-	sb_devc        *devc = audio_devs[dev]->devc;
-	unsigned long   flags;
-	unsigned char   tmp;
-	unsigned char   bits = 0;
+	sb_devc *devc = audio_devs[dev]->devc;
+	unsigned long flags;
+	unsigned char tmp;
+	unsigned char bits = 0;
 
 	if (devc->dma16 >= 0 && devc->dma16 != devc->dma8)
-		audio_devs[dev]->dmap_out->dma =
-		    audio_devs[dev]->dmap_in->dma =
-		    devc->bits == 16 ? devc->dma16 : devc->dma8;
+		audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma = devc->bits == 16 ? devc->dma16 : devc->dma8;
 	if (devc->model == MDL_SBPRO)
 		sb_mixer_set_stereo(devc, devc->channels == 2);
 
@@ -481,92 +474,83 @@
 	sb_dsp_command(devc, DSP_CMD_SPKON);
 
 	if (devc->model == MDL_JAZZ || devc->model == MDL_SMW)
-	  {
-		  if (devc->bits == AFMT_S16_LE)
-			  bits = 0x04;	/* 16 bit mode */
-
-		  if (devc->channels == 1)
-			  sb_dsp_command(devc, 0xa0 | bits);	/* Mono output */
-		  else
-			  sb_dsp_command(devc, 0xa8 | bits);	/* Stereo output */
-	} else
-	  {
-		  tmp = sb_getmixer(devc, 0x0e);
-		  if (devc->channels == 1)
-			  tmp &= ~0x02;
-		  else
-			  tmp |= 0x02;
-		  sb_setmixer(devc, 0x0e, tmp);
-	  }
+	{
+		if (devc->bits == AFMT_S16_LE)
+			bits = 0x04;	/* 16 bit mode */
+
+		if (devc->channels == 1)
+			sb_dsp_command(devc, 0xa0 | bits);	/* Mono output */
+		else
+			sb_dsp_command(devc, 0xa8 | bits);	/* Stereo output */
+	}
+	else
+	{
+		tmp = sb_getmixer(devc, 0x0e);
+		if (devc->channels == 1)
+			tmp &= ~0x02;
+		else
+			tmp |= 0x02;
+		sb_setmixer(devc, 0x0e, tmp);
+	}
 	restore_flags(flags);
 	devc->trigger_bits = 0;
 	return 0;
 }
 
-static int
-sbpro_audio_set_speed(int dev, int speed)
+static int sbpro_audio_set_speed(int dev, int speed)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	if (speed > 0)
-	  {
-		  if (speed < 4000)
-			  speed = 4000;
-
-		  if (speed > 44100)
-			  speed = 44100;
-
-		  if (devc->channels > 1 && speed > 22050)
-			  speed = 22050;
-
-		  sb201_audio_set_speed(dev, speed);
-	  }
+	{
+		if (speed < 4000)
+			speed = 4000;
+		if (speed > 44100)
+			speed = 44100;
+		if (devc->channels > 1 && speed > 22050)
+			speed = 22050;
+		sb201_audio_set_speed(dev, speed);
+	}
 	return devc->speed;
 }
 
-static short
-sbpro_audio_set_channels(int dev, short channels)
+static short sbpro_audio_set_channels(int dev, short channels)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	if (channels == 1 || channels == 2)
+	{
 		if (channels != devc->channels)
-		  {
-			  devc->channels = channels;
-			  if (devc->model == MDL_SBPRO && devc->channels == 2)
-			    {
-				    if (devc->speed > 22050)
-					    printk("OSS: Application error. Wrong ioctl call order.\n");
-				    sbpro_audio_set_speed(dev, devc->speed);
-			    }
-		  }
+		{
+			devc->channels = channels;
+			if (devc->model == MDL_SBPRO && devc->channels == 2)
+				sbpro_audio_set_speed(dev, devc->speed);
+		}
+	}
 	return devc->channels;
 }
 
-static int
-jazz16_audio_set_speed(int dev, int speed)
+static int jazz16_audio_set_speed(int dev, int speed)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	if (speed > 0)
-	  {
-		  int             tmp;
-		  int             s = speed * devc->channels;
-
-		  if (speed < 5000)
-			  speed = 4000;
+	{
+		int tmp;
+		int s = speed * devc->channels;
 
-		  if (speed > 44100)
-			  speed = 44100;
+		if (speed < 5000)
+			speed = 5000;
+		if (speed > 44100)
+			speed = 44100;
 
-		  devc->tconst = ((65536 - ((256000000 + s / 2) /
-					    s)) >> 8) & 0xff;
+		devc->tconst = ((65536 - ((256000000 + s / 2) / s)) >> 8) & 0xff;
 
-		  tmp = 256 - devc->tconst;
-		  speed = ((1000000 + tmp / 2) / tmp) / devc->channels;
+		tmp = 256 - devc->tconst;
+		speed = ((1000000 + tmp / 2) / tmp) / devc->channels;
 
-		  devc->speed = speed;
-	  }
+		devc->speed = speed;
+	}
 	return devc->speed;
 }
 
@@ -574,124 +558,123 @@
  * ESS specific routines
  */
 
-static int
-ess_audio_set_speed(int dev, int speed)
+static int ess_audio_set_speed(int dev, int speed)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
-	int             divider;
+	sb_devc *devc = audio_devs[dev]->devc;
+	int divider;
 
 	if (speed > 0)
-	  {
-		  if (speed < 5000)
-			  speed = 4000;
-
-		  if (speed > 48000)
-			  speed = 48000;
-
-		  if (speed > 22000)
-		    {
-			    divider = (795500 + speed / 2) / speed;
-			    speed = (795500 + divider / 2) / divider;
-		  } else
-		    {
-			    divider = (397700 + speed / 2) / speed;
-			    speed = (397700 + divider / 2) / divider;
-		    }
+	{
+		if (speed < 5000)
+			speed = 5000;
+		if (speed > 48000)
+			speed = 48000;
 
-		  devc->speed = speed;
-	  }
+		if (speed > 22000)
+		{
+			divider = (795500 + speed / 2) / speed;
+			speed = (795500 + divider / 2) / divider;
+		}
+		else
+		{
+			divider = (397700 + speed / 2) / speed;
+			speed = (397700 + divider / 2) / divider;
+		}
+		devc->speed = speed;
+	}
 	return devc->speed;
 }
 
-static void
-ess_speed(sb_devc * devc)
+static void ess_speed(sb_devc * devc)
 {
-	int             divider;
-	unsigned char   bits = 0;
-	int             speed = devc->speed;
+	int divider;
+	unsigned char bits = 0;
+	int speed = devc->speed;
 
 	if (speed < 4000)
 		speed = 4000;
 	else if (speed > 48000)
 		speed = 48000;
-
+	
 	if (speed > 22000)
-	  {
-		  bits = 0x80;
-		  divider = 256 - (795500 + speed / 2) / speed;
-	} else
-	  {
-		  divider = 128 - (397700 + speed / 2) / speed;
-	  }
+	{
+		bits = 0x80;
+		divider = 256 - (795500 + speed / 2) / speed;
+	}
+	else
+	{
+		divider = 128 - (397700 + speed / 2) / speed;
+	}
 
 	bits |= (unsigned char) divider;
 	ess_write(devc, 0xa1, bits);
 
-/*
- * Set filter divider register
- */
+	/*
+	 * Set filter divider register
+	 */
 
 	speed = (speed * 9) / 20;	/* Set filter roll-off to 90% of speed/2 */
 	divider = 256 - 7160000 / (speed * 82);
 	ess_write(devc, 0xa2, divider);
-
 	return;
 }
 
-static int
-ess_audio_prepare_for_input(int dev, int bsize, int bcount)
+static int ess_audio_prepare_for_input(int dev, int bsize, int bcount)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
-
+	sb_devc *devc = audio_devs[dev]->devc;
 	ess_speed(devc);
 	sb_dsp_command(devc, DSP_CMD_SPKOFF);
 
 	ess_write(devc, 0xb8, 0x0e);	/* Auto init DMA mode */
-	ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) |
-		  (3 - devc->channels));	/* Mono/stereo */
+	ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | (3 - devc->channels));	/* Mono/stereo */
 	ess_write(devc, 0xb9, 2);	/* Demand mode (4 bytes/DMA request) */
 
 	if (devc->channels == 1)
-	  {
-		  if (devc->bits == AFMT_U8)
-		    {		/* 8 bit mono */
-			    ess_write(devc, 0xb7, 0x51);
-			    ess_write(devc, 0xb7, 0xd0);
-		  } else
-		    {		/* 16 bit mono */
-			    ess_write(devc, 0xb7, 0x71);
-			    ess_write(devc, 0xb7, 0xf4);
-		    }
-	} else
-	  {			/* Stereo */
-		  if (devc->bits == AFMT_U8)
-		    {		/* 8 bit stereo */
-			    ess_write(devc, 0xb7, 0x51);
-			    ess_write(devc, 0xb7, 0x98);
-		  } else
-		    {		/* 16 bit stereo */
-			    ess_write(devc, 0xb7, 0x71);
-			    ess_write(devc, 0xb7, 0xbc);
-		    }
-	  }
-
+	{
+		if (devc->bits == AFMT_U8)
+		{	
+			/* 8 bit mono */
+			ess_write(devc, 0xb7, 0x51);
+			ess_write(devc, 0xb7, 0xd0);
+		}
+		else
+		{
+			/* 16 bit mono */
+			ess_write(devc, 0xb7, 0x71);
+			ess_write(devc, 0xb7, 0xf4);
+		}
+	}
+	else
+	{	
+		/* Stereo */
+		if (devc->bits == AFMT_U8)
+		{
+			/* 8 bit stereo */
+			ess_write(devc, 0xb7, 0x51);
+			ess_write(devc, 0xb7, 0x98);
+		}
+		else
+		{	
+			/* 16 bit stereo */
+			ess_write(devc, 0xb7, 0x71);
+			ess_write(devc, 0xb7, 0xbc);
+		}
+	}
 	ess_write(devc, 0xb1, (ess_read(devc, 0xb1) & 0x0f) | 0x50);
 	ess_write(devc, 0xb2, (ess_read(devc, 0xb2) & 0x0f) | 0x50);
-
 	devc->trigger_bits = 0;
 	return 0;
 }
 
 static int ess_audio_prepare_for_output(int dev, int bsize, int bcount)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	sb_dsp_reset(devc);
 	ess_speed(devc);
 
 	ess_write(devc, 0xb8, 4);	/* Auto init DMA mode */
-	ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) |
-		  (3 - devc->channels));	/* Mono/stereo */
+	ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | (3 - devc->channels));	/* Mono/stereo */
 	ess_write(devc, 0xb9, 2);	/* Demand mode (4 bytes/request) */
 
 	if (devc->channels == 1)
@@ -701,7 +684,8 @@
 			ess_write(devc, 0xb6, 0x80);
 			ess_write(devc, 0xb7, 0x51);
 			ess_write(devc, 0xb7, 0xd0);
-		  } else
+		}
+		else
 		{	/* 16 bit mono */
 			ess_write(devc, 0xb6, 0x00);
 			ess_write(devc, 0xb7, 0x71);
@@ -733,11 +717,11 @@
 }
 
 static void ess_audio_output_block(int dev, unsigned long buf, int nr_bytes,
-		       int intrflag)
+			int intrflag)
 {
-	int             count = nr_bytes;
-	sb_devc        *devc = audio_devs[dev]->devc;
-	short           c = -nr_bytes;
+	int count = nr_bytes;
+	sb_devc *devc = audio_devs[dev]->devc;
+	short c = -nr_bytes;
 
 	/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
 
@@ -756,9 +740,9 @@
 
 static void ess_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag)
 {
-	int             count = nr_bytes;
-	sb_devc        *devc = audio_devs[dev]->devc;
-	short           c = -nr_bytes;
+	int count = nr_bytes;
+	sb_devc *devc = audio_devs[dev]->devc;
+	short c = -nr_bytes;
 
 	/*
 	 * Start a DMA input to the buffer pointed by dmaqtail
@@ -781,7 +765,7 @@
 
 static void ess_audio_trigger(int dev, int bits)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	bits &= devc->irq_mode;
 
@@ -812,7 +796,7 @@
 
 static int sb16_audio_set_speed(int dev, int speed)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	if (speed > 0)
 	{
@@ -829,7 +813,7 @@
 
 static unsigned int sb16_audio_set_bits(int dev, unsigned int bits)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	if (bits != 0)
 	{
@@ -844,7 +828,7 @@
 
 static int sb16_audio_prepare_for_input(int dev, int bsize, int bcount)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
 	audio_devs[dev]->dmap_out->dma =
 	    audio_devs[dev]->dmap_in->dma =
@@ -856,11 +840,10 @@
 
 static int sb16_audio_prepare_for_output(int dev, int bsize, int bcount)
 {
-	sb_devc        *devc = audio_devs[dev]->devc;
+	sb_devc *devc = audio_devs[dev]->devc;
 
-	audio_devs[dev]->dmap_out->dma =
-	    audio_devs[dev]->dmap_in->dma =
-	    devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;
+	audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma =
+			devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;
 
 	devc->trigger_bits = 0;
 	return 0;
@@ -1098,8 +1081,8 @@
 
 void sb_audio_init(sb_devc * devc, char *name)
 {
-	int             audio_flags = 0;
-	int             format_mask = AFMT_U8;
+	int audio_flags = 0;
+	int format_mask = AFMT_U8;
 
 	struct audio_driver *driver = &sb1_audio_driver;
 
@@ -1151,14 +1134,9 @@
 	}
 
 	if ((devc->my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
-						name,
-						driver,
-						sizeof(struct audio_driver),
-						audio_flags,
-						format_mask,
-						devc,
-						devc->dma8,
-						devc->dma8)) < 0)
+				name,driver, sizeof(struct audio_driver),
+				audio_flags, format_mask, devc,
+				devc->dma8, devc->dma8)) < 0)
 	{
 		  printk(KERN_ERR "sb: unable to install audio.\n");
 		  return;
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.1.93/linux/drivers/sound/sb_card.c	Tue Mar 17 22:18:15 1998
+++ linux/drivers/sound/sb_card.c	Wed Apr  8 17:24:48 1998
@@ -2,18 +2,18 @@
  * sound/sb_card.c
  *
  * Detection routine for the Sound Blaster cards.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+
 #include <linux/config.h>
 #include <linux/module.h>
 
-
 #include "sound_config.h"
 #include "soundmodule.h"
 
@@ -22,31 +22,30 @@
 #include "sb_mixer.h"
 #include "sb.h"
 
-void
-attach_sb_card(struct address_info *hw_config)
+void attach_sb_card(struct address_info *hw_config)
 {
 #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI)
 	sb_dsp_init(hw_config);
 #endif
 }
 
-int
-probe_sb(struct address_info *hw_config)
+int probe_sb(struct address_info *hw_config)
 {
 	if (check_region(hw_config->io_base, 16))
 	{
-		printk("\n\nsb_card.c: I/O port %x is already in use\n\n", hw_config->io_base);
+		printk(KERN_ERR "sb_card: I/O port %x is already in use\n\n", hw_config->io_base);
 		return 0;
 	}
 	return sb_dsp_detect(hw_config);
 }
 
-void
-unload_sb(struct address_info *hw_config)
+void unload_sb(struct address_info *hw_config)
 {
 	sb_dsp_unload(hw_config);
 }
 
+int sb_be_quiet=0;
+
 #ifdef MODULE
 
 static struct address_info config;
@@ -58,18 +57,17 @@
  *      to the 8bit channel.
  */
 
-int             mpu_io = 0;
-int             io = -1;
-int             irq = -1;
-int             dma = -1;
-int             dma16 = -1;	/* Set this for modules that need it */
-int             type = 0;	/* Can set this to a specific card type */
-int             mad16 = 0;	/* Set mad16=1 to load this as support for mad16 */
-int             trix = 0;	/* Set trix=1 to load this as support for trix */
-int             pas2 = 0;	/* Set pas2=1 to load this as support for pas2 */
-int             sm_games = 0;	/* Mixer - see sb_mixer.c */
-int             acer = 0;	/* Do acer notebook init */
-int		mwave_bug = 0;	/* Using the dreadful mwave sb emulation */
+int mpu_io = 0;
+int io = -1;
+int irq = -1;
+int dma = -1;
+int dma16 = -1;	/* Set this for modules that need it */
+int type = 0;	/* Can set this to a specific card type */
+int mad16 = 0;	/* Set mad16=1 to load this as support for mad16 */
+int trix = 0;	/* Set trix=1 to load this as support for trix */
+int pas2 = 0;	/* Set pas2=1 to load this as support for pas2 */
+int sm_games = 0;	/* Mixer - see sb_mixer.c */
+int acer = 0;	/* Do acer notebook init */
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
@@ -81,7 +79,6 @@
 MODULE_PARM(trix, "i");
 MODULE_PARM(pas2, "i");
 MODULE_PARM(sm_games, "i");
-MODULE_PARM(mwave_bug, "i");
 
 static int sbmpu = 0;
 
@@ -124,7 +121,7 @@
 void cleanup_module(void)
 {
 	if (smw_free)
-		kfree(smw_free);
+		vfree(smw_free);
 	if (!mad16 && !trix && !pas2)
 		unload_sb(&config);
 	if (sbmpu)
@@ -144,11 +141,6 @@
 #else
 int             acer = 0;
 #endif
-#ifdef CONFIG_SB_MWAVE
-int		mwave_bug = 1;
-#else
-int 		mwave_bug = 0;
-#endif
 #endif
 #endif
 
@@ -159,3 +151,4 @@
 EXPORT_SYMBOL(attach_sb_card);
 EXPORT_SYMBOL(probe_sb);
 EXPORT_SYMBOL(unload_sb);
+EXPORT_SYMBOL(sb_be_quiet);
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.1.93/linux/drivers/sound/sb_common.c	Tue Mar 17 22:18:15 1998
+++ linux/drivers/sound/sb_common.c	Wed Apr  8 17:24:48 1998
@@ -2,17 +2,18 @@
  * sound/sb_common.c
  *
  * Common routines for Sound Blaster compatible cards.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+
 #include <linux/config.h>
 #include <linux/delay.h>
-
+#include <asm/init.h>
 
 #include "sound_config.h"
 #include "sound_firmware.h"
@@ -28,9 +29,11 @@
 
 static sb_devc *detected_devc = NULL;	/* For communication from probe to init */
 static sb_devc *last_devc = NULL;	/* For MPU401 initialization */
+
 static unsigned char jazz_irq_bits[] = {
 	0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6
 };
+
 static unsigned char jazz_dma_bits[] = {
 	0, 1, 0, 2, 0, 3, 0, 4
 };
@@ -39,7 +42,7 @@
  * Jazz16 chipset specific control variables
  */
 
-static int      jazz16_base = 0;	/* Not detected */
+static int jazz16_base = 0;		/* Not detected */
 static unsigned char jazz16_bits = 0;	/* I/O relocation bits */
 
 /*
@@ -57,10 +60,11 @@
 
 int sb_dsp_command(sb_devc * devc, unsigned char val)
 {
-	int             i;
-	unsigned long   limit;
+	int i;
+	unsigned long limit;
 
 	limit = jiffies + HZ / 10;	/* Timeout */
+	
 	/*
 	 * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
 	 * called while interrupts are disabled. This means that the timer is
@@ -69,7 +73,7 @@
 	 * loops.
 	 */
 
-	for (i = 0; i < 500000 && jiffies < limit; i++)
+	for (i = 0; i < 500000 && (limit-jiffies)>0; i++)
 	{
 		if ((inb(DSP_STATUS) & 0x80) == 0)
 		{
@@ -77,20 +81,19 @@
 			return 1;
 		}
 	}
-
-	printk(KERN_WARNING "Sound Blaster: DSP Command(%x) Timeout.\n", val);
+	printk(KERN_WARNING "soundblaster: DSP Command(%x) Timeout.\n", val);
 	return 0;
 }
 
 static int sb_dsp_get_byte(sb_devc * devc)
 {
-	int             i;
+	int i;
 
 	for (i = 1000; i; i--)
+	{
 		if (inb(DSP_DATA_AVAIL) & 0x80)
-		{
 			return inb(DSP_READ);
-		}
+	}
 	return 0xffff;
 }
 
@@ -107,7 +110,6 @@
 int ess_read(sb_devc * devc, unsigned char reg)
 {
 /* Read a byte from an extended mode register of ES1688 */
-
 	if (!sb_dsp_command(devc, 0xc0))	/* Read register command */
 		return -1;
 
@@ -239,7 +241,7 @@
 
 	if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3)
 	{
-		printk(KERN_ERR "SB16: Invalid 8 bit DMA (%d)\n", devc->dma8);
+		printk(KERN_ERR "sb16: Invalid 8 bit DMA (%d)\n", devc->dma8);
 		return 0;
 	}
 	bits = (1 << devc->dma8);
@@ -355,14 +357,12 @@
 	/*
 	 * OK so far. Now configure the IRQ and DMA channel used by the card.
 	 */
-	if (hw_config->irq < 1 || hw_config->irq > 15 ||
-	    jazz_irq_bits[hw_config->irq] == 0)
+	if (hw_config->irq < 1 || hw_config->irq > 15 || jazz_irq_bits[hw_config->irq] == 0)
 	{
 		printk(KERN_ERR "Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq);
 		return 0;
 	}
-	if (hw_config->dma < 0 || hw_config->dma > 3 ||
-	    jazz_dma_bits[hw_config->dma] == 0)
+	if (hw_config->dma < 0 || hw_config->dma > 3 || jazz_dma_bits[hw_config->dma] == 0)
 	{
 		  printk(KERN_ERR "Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma);
 		  return 0;
@@ -372,8 +372,7 @@
 		printk(KERN_ERR "Jazz16: No 16 bit DMA channel defined\n");
 		return 0;
 	}
-	if (hw_config->dma2 < 5 || hw_config->dma2 > 7 ||
-	    jazz_dma_bits[hw_config->dma2] == 0)
+	if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || jazz_dma_bits[hw_config->dma2] == 0)
 	{
 		printk(KERN_ERR "Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2);
 		return 0;
@@ -384,7 +383,7 @@
 		return 0;
 
 	if (!sb_dsp_command(devc, jazz_dma_bits[hw_config->dma] |
-			    (jazz_dma_bits[hw_config->dma2] << 4)))
+			(jazz_dma_bits[hw_config->dma2] << 4)))
 		return 0;
 
 	if (!sb_dsp_command(devc, jazz_irq_bits[hw_config->irq]))
@@ -683,11 +682,7 @@
 	 */
 
 
-	detected_devc = (sb_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(sb_devc)));
-	sound_mem_sizes[sound_nblocks] = sizeof(sb_devc);
-	if (sound_nblocks < 1024)
-		sound_nblocks++;;
-
+	detected_devc = (sb_devc *)kmalloc(sizeof(sb_devc), GFP_KERNEL);
 	if (detected_devc == NULL)
 	{
 		printk(KERN_ERR "sb: Can't allocate memory for device information\n");
@@ -703,8 +698,8 @@
 	sb_devc *devc;
 	char name[100];
 	extern int sb_be_quiet;
-	extern int mwave_bug;
-
+	int	mixer3c, mixer4c;
+	
 /*
  * Check if we had detected a SB device earlier
  */
@@ -769,7 +764,7 @@
 		/* Skip IRQ detection if SMP (doesn't work) */
 		devc->irq_ok = 1;
 #else
-		if ((devc->major == 4 && devc->minor <= 11 ) || mwave_bug )	/* Won't work */
+		if (devc->major == 4 && devc->minor <= 11 )	/* Won't work */
 			devc->irq_ok = 1;
 		else
 		{
@@ -819,7 +814,23 @@
 
 		case 4:
 			devc->model = hw_config->card_subtype = MDL_SB16;
-			if (hw_config->name == NULL)
+			/*
+			 *	The ALS007 seems to return DSP version 4.2.  In addition it has 2
+			 *	output control registers (at 0x3c and 0x4c).  Both of these should
+			 *	be !=0 after a reset which forms the basis of the ALS007 test
+			 *	since a "standard" SoundBlaster does not have a register at 0x4c.
+			 */
+			mixer3c = sb_getmixer(devc,0x3c);
+			mixer4c = sb_getmixer(devc,0x4c);
+			if ((devc->minor == 2) && (mixer3c != 0) && (mixer4c != 0)) 
+			{
+				sb_setmixer(devc,0x3c,0x1f);   /* Enable all inputs */
+				sb_setmixer(devc,0x4c,0x1f);
+				devc->submodel = SUBMDL_ALS007;
+				if (hw_config->name == NULL)
+					hw_config->name = "Sound Blaster (ALS-007)";
+			}
+			else if (hw_config->name == NULL)
 				hw_config->name = "Sound Blaster 16";
 
 			if (hw_config->dma2 == -1)
@@ -885,15 +896,15 @@
 			printk(KERN_WARNING "SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8);
 		}
 		if (devc->dma16 >= 0 && devc->dma16 != devc->dma8)
+		{
 			if (sound_alloc_dma(devc->dma16, "SoundBlaster16"))
-			{
-				printk(KERN_WARNING "SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16);
-			}
+				printk(KERN_WARNING "soundblaster: Can't allocate 16 bit DMA channel %d\n", devc->dma16);
+		}
 		sb_audio_init(devc, name);
 	}
 	else
 	{
-		MDB(printk("sb: No audio devices found.\n"));
+		MDB(printk("soundblaster: No audio devices found.\n"));
 	}
 }
 
@@ -932,6 +943,8 @@
 	}
 	else
 		release_region(hw_config->io_base, 16);
+	if(detected_devc)
+		kfree(detected_devc);
 }
 
 /*
@@ -940,7 +953,7 @@
 
 void sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value)
 {
-	unsigned long   flags;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
@@ -1318,5 +1331,4 @@
 {
 }
 #endif
-
 #endif
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c
--- v2.1.93/linux/drivers/sound/sb_midi.c	Tue Dec 30 10:59:17 1997
+++ linux/drivers/sound/sb_midi.c	Wed Apr  8 17:24:48 1998
@@ -2,17 +2,16 @@
  * sound/sb_dsp.c
  *
  * The low level driver for the Sound Blaster DS chips.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
-#include <linux/config.h>
-
 
+#include <linux/config.h>
 #include "sound_config.h"
 
 #ifdef CONFIG_SBDSP
@@ -30,14 +29,13 @@
  */
 
 
-static int
-sb_midi_open(int dev, int mode,
+static int sb_midi_open(int dev, int mode,
 	     void            (*input) (int dev, unsigned char data),
 	     void            (*output) (int dev)
 )
 {
-	sb_devc        *devc = midi_devs[dev]->devc;
-	unsigned long   flags;
+	sb_devc *devc = midi_devs[dev]->devc;
+	unsigned long flags;
 
 	if (devc == NULL)
 		return -ENXIO;
@@ -45,10 +43,10 @@
 	save_flags(flags);
 	cli();
 	if (devc->opened)
-	  {
-		  restore_flags(flags);
-		  return -EBUSY;
-	  }
+	{
+		restore_flags(flags);
+		return -EBUSY;
+	}
 	devc->opened = 1;
 	restore_flags(flags);
 
@@ -58,25 +56,24 @@
 	sb_dsp_reset(devc);
 
 	if (!sb_dsp_command(devc, 0x35))	/* Start MIDI UART mode */
-	  {
+	{
 		  devc->opened = 0;
 		  return -EIO;
-	  }
+	}
 	devc->intr_active = 1;
 
 	if (mode & OPEN_READ)
-	  {
-		  devc->input_opened = 1;
-		  devc->midi_input_intr = input;
-	  }
+	{
+		devc->input_opened = 1;
+		devc->midi_input_intr = input;
+	}
 	return 0;
 }
 
-static void
-sb_midi_close(int dev)
+static void sb_midi_close(int dev)
 {
-	sb_devc        *devc = midi_devs[dev]->devc;
-	unsigned long   flags;
+	sb_devc *devc = midi_devs[dev]->devc;
+	unsigned long flags;
 
 	if (devc == NULL)
 		return;
@@ -90,10 +87,9 @@
 	restore_flags(flags);
 }
 
-static int
-sb_midi_out(int dev, unsigned char midi_byte)
+static int sb_midi_out(int dev, unsigned char midi_byte)
 {
-	sb_devc        *devc = midi_devs[dev]->devc;
+	sb_devc *devc = midi_devs[dev]->devc;
 
 	if (devc == NULL)
 		return 1;
@@ -102,23 +98,21 @@
 		return 1;
 
 	if (!sb_dsp_command(devc, midi_byte))
-	  {
-		  devc->midi_broken = 1;
-		  return 1;
-	  }
+	{
+		devc->midi_broken = 1;
+		return 1;
+	}
 	return 1;
 }
 
-static int
-sb_midi_start_read(int dev)
+static int sb_midi_start_read(int dev)
 {
 	return 0;
 }
 
-static int
-sb_midi_end_read(int dev)
+static int sb_midi_end_read(int dev)
 {
-	sb_devc        *devc = midi_devs[dev]->devc;
+	sb_devc *devc = midi_devs[dev]->devc;
 
 	if (devc == NULL)
 		return -ENXIO;
@@ -128,14 +122,12 @@
 	return 0;
 }
 
-/* why -EPERM and not -EINVAL?? */
 static int sb_midi_ioctl(int dev, unsigned cmd, caddr_t arg)
 {
-        return -EPERM;
+        return -EINVAL;
 }
 
-void
-sb_midi_interrupt(sb_devc * devc)
+void sb_midi_interrupt(sb_devc * devc)
 {
 	unsigned long   flags;
 	unsigned char   data;
@@ -159,7 +151,9 @@
 
 static struct midi_operations sb_midi_operations =
 {
-	{"Sound Blaster", 0, 0, SNDCARD_SB},
+	{
+		"Sound Blaster", 0, 0, SNDCARD_SB
+	},
 	&std_midi_synth,
 	{0},
 	sb_midi_open,
@@ -174,10 +168,9 @@
 	NULL
 };
 
-void
-sb_dsp_midi_init(sb_devc * devc)
+void sb_dsp_midi_init(sb_devc * devc)
 {
-	int             dev;
+	int dev;
 
 	if (devc->model < 2)	/* No MIDI support for SB 1.x */
 		return;
@@ -185,45 +178,34 @@
 	dev = sound_alloc_mididev();
 
 	if (dev == -1)
-	  {
-		  printk("Sound: Too many midi devices detected\n");
-		  return;
-	  }
+	{
+		printk("Sound: Too many midi devices detected\n");
+		return;
+	}
 	std_midi_synth.midi_dev = dev;
 	devc->my_mididev = dev;
-
 	std_midi_synth.midi_dev = devc->my_mididev = dev;
-
-
-	midi_devs[dev] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct midi_operations)));
-	sound_mem_sizes[sound_nblocks] = sizeof(struct midi_operations);
-
-	if (sound_nblocks < 1024)
-		sound_nblocks++;;
+	midi_devs[dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
 	if (midi_devs[dev] == NULL)
-	  {
-		  printk(KERN_WARNING "sb MIDI: Failed to allocate memory\n");
-		  sound_unload_mididev(dev);
+	{
+		printk(KERN_WARNING "soundblaster: Failed to allocate MIDI memory.\n");
+		sound_unload_mididev(dev);
 		  return;
-	  }
+	}
 	memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations,
 	       sizeof(struct midi_operations));
 
 	midi_devs[dev]->devc = devc;
 
 
-	midi_devs[dev]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations)));
-	sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations);
-
-	if (sound_nblocks < 1024)
-		sound_nblocks++;;
-
+	midi_devs[dev]->converter = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
 	if (midi_devs[dev]->converter == NULL)
-	  {
-		  printk(KERN_WARNING "sb MIDI: Failed to allocate memory\n");
+	{
+		  printk(KERN_WARNING "soundblaster: Failed to allocate MIDI memory.\n");
+		  kfree(midi_devs[dev]);
 		  sound_unload_mididev(dev);
 		  return;
-	  }
+	}
 	memcpy((char *) midi_devs[dev]->converter, (char *) &std_midi_synth,
 	       sizeof(struct synth_operations));
 
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v2.1.93/linux/drivers/sound/sb_mixer.c	Mon Jan  5 09:39:52 1998
+++ linux/drivers/sound/sb_mixer.c	Wed Apr  8 17:24:48 1998
@@ -10,13 +10,12 @@
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
- */
-/*
+ *
+ *
  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
  */
-#include <linux/config.h>
-
 
+#include <linux/config.h>
 #include "sound_config.h"
 
 #if defined(CONFIG_SBDSP) || defined(MODULE)
@@ -29,25 +28,22 @@
 
 static void     sb_mixer_reset(sb_devc * devc);
 
-void
-sb_mixer_set_stereo(sb_devc * devc, int mode)
+void sb_mixer_set_stereo(sb_devc * devc, int mode)
 {
 	sb_setmixer(devc, OUT_FILTER, ((sb_getmixer(devc, OUT_FILTER) & ~STEREO_DAC)
 				       | (mode ? STEREO_DAC : MONO_DAC)));
 }
 
-static int
-detect_mixer(sb_devc * devc)
+static int detect_mixer(sb_devc * devc)
 {
 	/* Just trust the mixer is there */
 	return 1;
 }
 
-static void
-change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval)
+static void change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval)
 {
-	unsigned char   mask;
-	int             shift;
+	unsigned char mask;
+	int shift;
 
 	mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1;
 	newval = (int) ((newval * mask) + 50) / 100;	/* Scale */
@@ -58,19 +54,16 @@
 	*regval |= (newval & mask) << shift;	/* Set the new value */
 }
 
-static int
-sb_mixer_get(sb_devc * devc, int dev)
+static int sb_mixer_get(sb_devc * devc, int dev)
 {
 	if (!((1 << dev) & devc->supported_devices))
 		return -EINVAL;
-
 	return devc->levels[dev];
 }
 
-void
-smw_mixer_init(sb_devc * devc)
+void smw_mixer_init(sb_devc * devc)
 {
-	int             i;
+	int i;
 
 	sb_setmixer(devc, 0x00, 0x18);	/* Mute unused (Telephone) line */
 	sb_setmixer(devc, 0x10, 0x38);	/* Config register 2 */
@@ -81,18 +74,15 @@
 			devc->supported_devices |= (1 << i);
 
 	devc->supported_rec_devices = devc->supported_devices &
-	    ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM |
-	      SOUND_MASK_VOLUME);
-
+		~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | SOUND_MASK_VOLUME);
 	sb_mixer_reset(devc);
 }
 
-static int
-smw_mixer_set(sb_devc * devc, int dev, int value)
+static int smw_mixer_set(sb_devc * devc, int dev, int value)
 {
-	int             left = value & 0x000000ff;
-	int             right = (value & 0x0000ff00) >> 8;
-	int             reg, val;
+	int left = value & 0x000000ff;
+	int right = (value & 0x0000ff00) >> 8;
+	int reg, val;
 
 	if (left > 100)
 		left = 100;
@@ -106,46 +96,45 @@
 		return -EINVAL;
 
 	switch (dev)
-	  {
-	  case SOUND_MIXER_VOLUME:
-		  sb_setmixer(devc, 0x0b, 96 - (96 * left / 100));	/* 96=mute, 0=max */
-		  sb_setmixer(devc, 0x0c, 96 - (96 * right / 100));
-		  break;
-
-	  case SOUND_MIXER_BASS:
-	  case SOUND_MIXER_TREBLE:
-		  devc->levels[dev] = left | (right << 8);
-
-		  /* Set left bass and treble values */
-		  val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4;
-		  val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f;
-		  sb_setmixer(devc, 0x0d, val);
-
-		  /* Set right bass and treble values */
-		  val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4;
-		  val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f;
-		  sb_setmixer(devc, 0x0e, val);
-		  break;
-
-	  default:
-		  reg = smw_mix_regs[dev];
-		  if (reg == 0)
-			  return -EINVAL;
-		  sb_setmixer(devc, reg, (24 - (24 * left / 100)) | 0x20);	/* 24=mute, 0=max */
-		  sb_setmixer(devc, reg + 1, (24 - (24 * right / 100)) | 0x40);
-	  }
+	{
+		case SOUND_MIXER_VOLUME:
+			sb_setmixer(devc, 0x0b, 96 - (96 * left / 100));	/* 96=mute, 0=max */
+			sb_setmixer(devc, 0x0c, 96 - (96 * right / 100));
+			break;
+
+		case SOUND_MIXER_BASS:
+		case SOUND_MIXER_TREBLE:
+			devc->levels[dev] = left | (right << 8);
+			/* Set left bass and treble values */
+			val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4;
+			val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f;
+			sb_setmixer(devc, 0x0d, val);
+
+			/* Set right bass and treble values */
+			val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4;
+			val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f;
+			sb_setmixer(devc, 0x0e, val);
+		
+			break;
+
+		default:
+			reg = smw_mix_regs[dev];
+			if (reg == 0)
+				return -EINVAL;
+			sb_setmixer(devc, reg, (24 - (24 * left / 100)) | 0x20);	/* 24=mute, 0=max */
+			sb_setmixer(devc, reg + 1, (24 - (24 * right / 100)) | 0x40);
+	}
 
 	devc->levels[dev] = left | (right << 8);
 	return left | (right << 8);
 }
 
-static int
-sb_mixer_set(sb_devc * devc, int dev, int value)
+static int sb_mixer_set(sb_devc * devc, int dev, int value)
 {
-	int             left = value & 0x000000ff;
-	int             right = (value & 0x0000ff00) >> 8;
+	int left = value & 0x000000ff;
+	int right = (value & 0x0000ff00) >> 8;
 
-	int             regoffs;
+	int regoffs;
 	unsigned char   val;
 
 	if (devc->model == MDL_SMW)
@@ -177,21 +166,21 @@
 	if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs)	/*
 								 * Change register
 								 */
-	  {
-		  sb_setmixer(devc, regoffs, val);	/*
+	{
+		sb_setmixer(devc, regoffs, val);	/*
 							 * Save the old one
 							 */
-		  regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno;
+		regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno;
 
-		  if (regoffs == 0)
-			  return left | (left << 8);	/*
+		if (regoffs == 0)
+			return left | (left << 8);	/*
 							 * Just left channel present
 							 */
 
-		  val = sb_getmixer(devc, regoffs);	/*
-							   * Read the new one
+		val = sb_getmixer(devc, regoffs);	/*
+							 * Read the new one
 							 */
-	  }
+	}
 	change_bits(devc, &val, dev, RIGHT_CHN, right);
 
 	sb_setmixer(devc, regoffs, val);
@@ -200,86 +189,107 @@
 	return left | (right << 8);
 }
 
-static void
-set_recsrc(sb_devc * devc, int src)
+static void set_recsrc(sb_devc * devc, int src)
 {
 	sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7));
 }
 
-static int
-set_recmask(sb_devc * devc, int mask)
+static int set_recmask(sb_devc * devc, int mask)
 {
-	int             devmask, i;
-	unsigned char   regimageL, regimageR;
+	int devmask, i;
+	unsigned char  regimageL, regimageR;
 
 	devmask = mask & devc->supported_rec_devices;
 
 	switch (devc->model)
-	  {
-	  case MDL_SBPRO:
-	  case MDL_ESS:
-	  case MDL_JAZZ:
-	  case MDL_SMW:
-
-		  if (devmask != SOUND_MASK_MIC &&
-		      devmask != SOUND_MASK_LINE &&
-		      devmask != SOUND_MASK_CD)
-		    {		/*
-				 * More than one devices selected. Drop the *
+	{
+		case MDL_SBPRO:
+		case MDL_ESS:
+		case MDL_JAZZ:
+		case MDL_SMW:
+
+			if (devmask != SOUND_MASK_MIC &&
+				devmask != SOUND_MASK_LINE &&
+				devmask != SOUND_MASK_CD)
+			{
+				/*
+				 * More than one device selected. Drop the
 				 * previous selection
 				 */
-			    devmask &= ~devc->recmask;
-		    }
-		  if (devmask != SOUND_MASK_MIC &&
-		      devmask != SOUND_MASK_LINE &&
-		      devmask != SOUND_MASK_CD)
-		    {		/*
-				 * More than one devices selected. Default to
-				 * * mic
+				devmask &= ~devc->recmask;
+			}
+			if (devmask != SOUND_MASK_MIC &&
+				devmask != SOUND_MASK_LINE &&
+				devmask != SOUND_MASK_CD)
+			{
+				/*
+				 * More than one device selected. Default to
+				 * mic
 				 */
-			    devmask = SOUND_MASK_MIC;
-		    }
-		  if (devmask ^ devc->recmask)	/*
-						   * Input source changed
-						 */
-		    {
-			    switch (devmask)
-			      {
-
-			      case SOUND_MASK_MIC:
-				      set_recsrc(devc, SRC__MIC);
-				      break;
-
-			      case SOUND_MASK_LINE:
-				      set_recsrc(devc, SRC__LINE);
-				      break;
-
-			      case SOUND_MASK_CD:
-				      set_recsrc(devc, SRC__CD);
-				      break;
-
-			      default:
-				      set_recsrc(devc, SRC__MIC);
-			      }
-		    }
-		  break;
-
-	  case MDL_SB16:
-		  if (!devmask)
-			  devmask = SOUND_MASK_MIC;
-
-		  regimageL = regimageR = 0;
-		  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-			  if ((1 << i) & devmask)
-			    {
-				    regimageL |= sb16_recmasks_L[i];
-				    regimageR |= sb16_recmasks_R[i];
-			    }
-		  sb_setmixer(devc, SB16_IMASK_L, regimageL);
-		  sb_setmixer(devc, SB16_IMASK_R, regimageR);
-		  break;
-	  }
+				devmask = SOUND_MASK_MIC;
+			}
+			if (devmask ^ devc->recmask)	/*
+							 *	Input source changed
+							 */
+			{
+				switch (devmask)
+				{
+					case SOUND_MASK_MIC:
+						set_recsrc(devc, SRC__MIC);
+						break;
+
+					case SOUND_MASK_LINE:
+						set_recsrc(devc, SRC__LINE);
+						break;
+
+					case SOUND_MASK_CD:
+						set_recsrc(devc, SRC__CD);
+						break;
+
+					default:
+						set_recsrc(devc, SRC__MIC);
+				}
+			}
+			break;
 
+		case MDL_SB16:
+			if (!devmask)
+				devmask = SOUND_MASK_MIC;
+
+			if (devc->submodel == SUBMDL_ALS007) 
+			{
+				switch (devmask) 
+				{
+					case SOUND_MASK_LINE:
+						sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_LINE);
+						break;
+					case SOUND_MASK_CD:
+						sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_CD);
+						break;
+					case SOUND_MASK_SYNTH:
+						sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_SYNTH);
+						break;
+					default:           /* Also takes care of SOUND_MASK_MIC case */
+						sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_MIC);
+						break;
+				}
+			}
+			else
+			{
+				regimageL = regimageR = 0;
+				for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+				{
+					if ((1 << i) & devmask)
+					{
+						regimageL |= sb16_recmasks_L[i];
+						regimageR |= sb16_recmasks_R[i];
+					}
+					sb_setmixer (devc, SB16_IMASK_L, regimageL);
+					sb_setmixer (devc, SB16_IMASK_R, regimageR);
+				}
+			}
+			break;
+	}
 	devc->recmask = devmask;
 	return devc->recmask;
 }
@@ -292,52 +302,57 @@
 	/*
 	 * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1).
 	 */
-	if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) {
+	if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) 
+	{
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
 		sb_setmixer(devc, 0x43, (~val) & 0x01);
 		return 0;
 	}
-	if (((cmd >> 8) & 0xff) == 'M') {
-		if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+	if (((cmd >> 8) & 0xff) == 'M') 
+	{
+		if (_SIOC_DIR(cmd) & _SIOC_WRITE) 
+		{
 			if (get_user(val, (int *)arg))
 				return -EFAULT;
-			switch (cmd & 0xff) {
-			case SOUND_MIXER_RECSRC:
-				ret = set_recmask(devc, val);
-				break;
+			switch (cmd & 0xff) 
+			{
+				case SOUND_MIXER_RECSRC:
+					ret = set_recmask(devc, val);
+					break;
 
-			default:
-				ret = sb_mixer_set(devc, cmd & 0xff, val);
+				default:
+					ret = sb_mixer_set(devc, cmd & 0xff, val);
 			}
-		  } else
-			  switch (cmd & 0xff) {
-			  case SOUND_MIXER_RECSRC:
-				  ret = devc->recmask;
-				  break;
+		}
+		else switch (cmd & 0xff) 
+		{
+			case SOUND_MIXER_RECSRC:
+				ret = devc->recmask;
+				break;
 				  
-			  case SOUND_MIXER_DEVMASK:
-				  ret = devc->supported_devices;
-				  break;
+			case SOUND_MIXER_DEVMASK:
+				ret = devc->supported_devices;
+				break;
 				  
-			  case SOUND_MIXER_STEREODEVS:
-				  ret = devc->supported_devices;
-				  if (devc->model != MDL_JAZZ && devc->model != MDL_SMW)
-					  ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
-				  break;
+			case SOUND_MIXER_STEREODEVS:
+				ret = devc->supported_devices;
+				if (devc->model != MDL_JAZZ && devc->model != MDL_SMW)
+					ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
+				break;
 				  
-			  case SOUND_MIXER_RECMASK:
-				  ret = devc->supported_rec_devices;
-				  break;
+			case SOUND_MIXER_RECMASK:
+				ret = devc->supported_rec_devices;
+				break;
 				  
-			  case SOUND_MIXER_CAPS:
-				  ret = devc->mixer_caps;
-				  break;
+			case SOUND_MIXER_CAPS:
+				ret = devc->mixer_caps;
+				break;
 				    
-			  default:
-				  ret = sb_mixer_get(devc, cmd & 0xff);
-				  break;
-			  }
+			default:
+				ret = sb_mixer_get(devc, cmd & 0xff);
+				break;
+		}
 		return put_user(ret, (int *)arg); 
 	} else
 		return -EINVAL;
@@ -350,12 +365,18 @@
 	sb_mixer_ioctl
 };
 
-static void
-sb_mixer_reset(sb_devc * devc)
+static struct mixer_operations als007_mixer_operations =
 {
-	char            name[32];
-	int             i;
-	extern int      sm_games;
+	"ALS007",
+	"Avance ALS-007",
+	sb_mixer_ioctl
+};
+
+static void sb_mixer_reset(sb_devc * devc)
+{
+	char name[32];
+	int i;
+	extern int sm_games;
 
 	sprintf(name, "SB_%d", devc->sbmixnum);
 
@@ -366,15 +387,13 @@
 
 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 		sb_mixer_set(devc, i, devc->levels[i]);
-
 	set_recmask(devc, SOUND_MASK_MIC);
 }
 
-int
-sb_mixer_init(sb_devc * devc)
+int sb_mixer_init(sb_devc * devc)
 {
-	int             mixer_type = 0;
-	int             m;
+	int mixer_type = 0;
+	int m;
 
 	devc->sbmixnum = sbmixnum++;
 	devc->levels = NULL;
@@ -385,64 +404,69 @@
 		return 0;	/* No mixer. Why? */
 
 	switch (devc->model)
-	  {
-	  case MDL_SBPRO:
-	  case MDL_AZTECH:
-	  case MDL_JAZZ:
-		  devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
-		  devc->supported_devices = SBPRO_MIXER_DEVICES;
-		  devc->supported_rec_devices = SBPRO_RECORDING_DEVICES;
-		  devc->iomap = &sbpro_mix;
-		  break;
-
-	  case MDL_ESS:
-		  devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
-		  devc->supported_devices = ES688_MIXER_DEVICES;
-		  devc->supported_rec_devices = ES688_RECORDING_DEVICES;
-		  devc->iomap = &es688_mix;
-		  break;
-
-	  case MDL_SMW:
-		  devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
-		  devc->supported_devices = 0;
-		  devc->supported_rec_devices = 0;
-		  devc->iomap = &sbpro_mix;
-		  smw_mixer_init(devc);
-		  break;
-
-	  case MDL_SB16:
-		  devc->mixer_caps = 0;
-		  devc->supported_devices = SB16_MIXER_DEVICES;
-		  devc->supported_rec_devices = SB16_RECORDING_DEVICES;
-		  devc->iomap = &sb16_mix;
-		  break;
-
-	  default:
-		  printk("SB Warning: Unsupported mixer type %d\n", devc->model);
-		  return 0;
-	  }
+	{
+		case MDL_SBPRO:
+		case MDL_AZTECH:
+		case MDL_JAZZ:
+			devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
+			devc->supported_devices = SBPRO_MIXER_DEVICES;
+			devc->supported_rec_devices = SBPRO_RECORDING_DEVICES;
+			devc->iomap = &sbpro_mix;
+			break;
+
+		case MDL_ESS:
+			devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
+			devc->supported_devices = ES688_MIXER_DEVICES;
+			devc->supported_rec_devices = ES688_RECORDING_DEVICES;
+			devc->iomap = &es688_mix;
+			break;
+
+		case MDL_SMW:
+			devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
+			devc->supported_devices = 0;
+			devc->supported_rec_devices = 0;
+			devc->iomap = &sbpro_mix;
+			smw_mixer_init(devc);
+			break;
+
+		case MDL_SB16:
+			devc->mixer_caps = 0;
+			devc->supported_rec_devices = SB16_RECORDING_DEVICES;
+			if (devc->submodel != SUBMDL_ALS007)
+			{
+				devc->supported_devices = SB16_MIXER_DEVICES;
+				devc->iomap = &sb16_mix;
+			}
+			else
+			{
+				devc->supported_devices = ALS007_MIXER_DEVICES;
+				devc->iomap = &als007_mix;
+			}
+			break;
+
+		default:
+			printk(KERN_WARNING "sb_mixer: Unsupported mixer type %d\n", devc->model);
+			return 0;
+	}
 
 	m = sound_alloc_mixerdev();
 	if (m == -1)
 		return 0;
 
-
-	mixer_devs[m] = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations)));
-	sound_mem_sizes[sound_nblocks] = sizeof(struct mixer_operations);
-
-	if (sound_nblocks < 1024)
-		sound_nblocks++;;
+	mixer_devs[m] = (struct mixer_operations *)kmalloc(sizeof(struct mixer_operations), GFP_KERNEL);
 	if (mixer_devs[m] == NULL)
-	  {
-		  printk(KERN_ERR "sb_mixer: Can't allocate memory\n");
-		  sound_unload_mixerdev(m);
-		  return 0;
-	  }
-	memcpy((char *) mixer_devs[m], (char *) &sb_mixer_operations,
-	       sizeof(struct mixer_operations));
+	{
+		printk(KERN_ERR "sb_mixer: Can't allocate memory\n");
+		sound_unload_mixerdev(m);
+		return 0;
+	}
 
-	mixer_devs[m]->devc = devc;
+	if (devc->submodel != SUBMDL_ALS007)
+		memcpy ((char *) mixer_devs[m], (char *) &sb_mixer_operations, sizeof (struct mixer_operations));
+	else
+		memcpy ((char *) mixer_devs[m], (char *) &als007_mixer_operations, sizeof (struct mixer_operations));
 
+	mixer_devs[m]->devc = devc;
 	devc->my_mixerdev = m;
 	sb_mixer_reset(devc);
 	return 1;
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h
--- v2.1.93/linux/drivers/sound/sb_mixer.h	Fri Jan 30 11:28:08 1998
+++ linux/drivers/sound/sb_mixer.h	Wed Apr  8 17:24:48 1998
@@ -49,6 +49,13 @@
 					 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \
 					SOUND_MASK_IMIX)
 
+/* These are the only devices that are working at the moment.  Others could
+ * be added once they are identified and a method is found to control them.
+ */
+#define ALS007_MIXER_DEVICES	(SOUND_MASK_SYNTH | SOUND_MASK_LINE | \
+				 SOUND_MASK_PCM | SOUND_MASK_MIC | \
+				 SOUND_MASK_CD | \
+				 SOUND_MASK_VOLUME)
 /*
  * Mixer registers
  * 
@@ -97,6 +104,13 @@
 #define LEFT_CHN	0
 #define RIGHT_CHN	1
 
+/*
+ * Mixer registers of ALS007
+ */
+#define ALS007_RECORD_SRC	0x6c
+#define ALS007_OUTPUT_CTRL1	0x3c
+#define ALS007_OUTPUT_CTRL2	0x4c
+
 #define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r)	\
 	{{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}}
 
@@ -173,6 +187,25 @@
 MIX_ENT(SOUND_MIXER_OGAIN,	0x41, 7, 2, 0x42, 7, 2)
 };
 
+static mixer_tab als007_mix = 
+{
+MIX_ENT(SOUND_MIXER_VOLUME,	0x62, 7, 4, 0x62, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,	0x66, 7, 4, 0x66, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,	0x64, 7, 4, 0x64, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,	0x6e, 7, 4, 0x6e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,	0x6a, 6, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD,		0x68, 7, 4, 0x68, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,	0x00, 0, 0, 0x00, 0, 0), /* Obsolete. Use IGAIN */
+MIX_ENT(SOUND_MIXER_IGAIN,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_OGAIN,	0x00, 0, 0, 0x00, 0, 0)
+};
+
+
 /* SM_GAMES          Master volume is lower and PCM & FM volumes
 			     higher than with SB Pro. This improves the
 			     sound quality */
@@ -283,6 +316,15 @@
 #define SRC__MIC         1	/* Select Microphone recording source */
 #define SRC__CD          3	/* Select CD recording source */
 #define SRC__LINE        7	/* Use Line-in for recording source */
+
+/*
+ *	Recording sources for ALS-007
+ */
+
+#define ALS007_MIC	4
+#define ALS007_LINE	6
+#define ALS007_CD	2
+#define ALS007_SYNTH	7
 
 #endif
 #endif
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v2.1.93/linux/drivers/sound/sequencer.c	Tue Mar 10 10:03:33 1998
+++ linux/drivers/sound/sequencer.c	Wed Apr  8 17:24:48 1998
@@ -16,6 +16,10 @@
  */
 #include <linux/config.h>
 
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
 
 #define SEQUENCER_C
 #include "sound_config.h"
@@ -478,7 +482,7 @@
 			parm = 64;
 		}
 	}
-	
+
 	switch (cmd)
 	{
 		case MIDI_NOTEON:
@@ -950,7 +954,7 @@
 			synth_devs[max_synthdev++] = midi_devs[dev]->converter;
 		}
 	}
-	
+
 	for (dev = 0; dev < max_synthdev; dev++)
 	{
 		int chn;
@@ -993,15 +997,20 @@
 		return -ENXIO;
 	}
 	if (dev)		/* Patch manager device (obsolete) */
-		  return -ENXIO;
+		return -ENXIO;
+
+#ifdef CONFIG_KMOD
+	if(synth_devs[dev] == NULL)
+		request_module("synth0");
+#endif
 
 	if (mode == OPEN_READ)
 	{
 		if (!num_midis)
 		{
-			  /*printk("Sequencer: No MIDI devices. Input not possible\n");*/
-			  sequencer_busy = 0;
-			  return -ENXIO;
+			/*printk("Sequencer: No MIDI devices. Input not possible\n");*/
+			sequencer_busy = 0;
+			return -ENXIO;
 		}
 	}
 	save_flags(flags);
@@ -1033,8 +1042,8 @@
 		for (i = 0; i < num_sound_timers; i++)
 			if (sound_timer_devs[i] && sound_timer_devs[i]->priority > best)
 			{
-				    tmr_no = i;
-				    best = sound_timer_devs[i]->priority;
+				tmr_no = i;
+				best = sound_timer_devs[i]->priority;
 			}
 		if (tmr_no == -1)	/* Should not be */
 			tmr_no = 0;
@@ -1066,7 +1075,7 @@
 	{
 		if (synth_devs[i]==NULL)
 			continue;
-			
+
 		if ((tmp = synth_devs[i]->open(i, mode)) < 0)
 		{
 			printk(KERN_WARNING "Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp);
@@ -1096,7 +1105,7 @@
 		/*
 		 * Initialize midi input devices
 		 */
-		
+
 		for (i = 0; i < max_mididev; i++)
 			if (!midi_opened[i])
 			{
@@ -1140,7 +1149,7 @@
 		/*
 		 * Let's have a delay
 		 */
-		
+
  		if (n) {
  			current->timeout = jiffies + HZ / 10;
  			interruptible_sleep_on(&seq_sleeper);
@@ -1173,7 +1182,7 @@
  			/* Extra delay */
 		}
 	}
-		  
+
 	if (mode != OPEN_READ)
 		seq_drain_midi_queues();	/*
 						 * Ensure the output queues are empty
@@ -1201,7 +1210,7 @@
 	for (i = 0; i < max_mididev; i++)
 	{
 		if (midi_opened[i])
-			  midi_devs[i]->close(i);
+			midi_devs[i]->close(i);
 	}
 
 	if (seq_mode == SEQ_2)
@@ -1329,7 +1338,7 @@
 
 	save_flags(flags);
 	cli();
-	
+
 	if (waitqueue_active(&seq_sleeper)) {
 		/*      printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */
 		wake_up(&seq_sleeper);
@@ -1368,7 +1377,7 @@
 
 	orig_dev = dev = dev >> 4;
 
-	switch (cmd) 
+	switch (cmd)
 	{
 		case SNDCTL_TMR_TIMEBASE:
 		case SNDCTL_TMR_TEMPO:
@@ -1380,13 +1389,13 @@
 			if (seq_mode != SEQ_2)
 				return -EINVAL;
 			return tmr->ioctl(tmr_no, cmd, arg);
-		
+
 		case SNDCTL_TMR_SELECT:
 			if (seq_mode != SEQ_2)
 				return -EINVAL;
 			if (get_user(pending_timer, (int *)arg))
 				return -EFAULT;
-			if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL) 
+			if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL)
 			{
 				pending_timer = -1;
 				return -EINVAL;
@@ -1397,14 +1406,14 @@
 		case SNDCTL_SEQ_PANIC:
 			seq_panic();
 			return -EINVAL;
-		
+
 		case SNDCTL_SEQ_SYNC:
 			if (mode == OPEN_READ)
 				return 0;
 			while (qlen > 0 && !signal_pending(current))
 				seq_sync();
 			return qlen ? -EINTR : 0;
-		
+
 		case SNDCTL_SEQ_RESET:
 			seq_reset();
 			return 0;
@@ -1414,8 +1423,8 @@
 				return -EFAULT;
 			if (midi_dev < 0 || midi_dev >= max_mididev)
 				return -ENXIO;
-		
-			if (!midi_opened[midi_dev] && 
+
+			if (!midi_opened[midi_dev] &&
 				(err = midi_devs[midi_dev]->open(midi_dev, mode, sequencer_midi_input,
 						     sequencer_midi_output)) < 0)
 				return err;
@@ -1427,13 +1436,13 @@
 				return 0;
 			val = iqlen;
 			break;
-		
+
 		case SNDCTL_SEQ_GETOUTCOUNT:
 			if (mode == OPEN_READ)
 				return 0;
 			val = SEQ_MAX_QUEUE - qlen;
 			break;
-		
+
 		case SNDCTL_SEQ_GETTIME:
 			if (seq_mode == SEQ_2)
 				return tmr->ioctl(tmr_no, cmd, arg);
@@ -1442,14 +1451,14 @@
 			else
 				val = jiffies - seq_time;
 			break;
-		
+
 		case SNDCTL_SEQ_CTRLRATE:
 			/*
 			 * If *arg == 0, just return the current rate
 			 */
 			if (seq_mode == SEQ_2)
 				return tmr->ioctl(tmr_no, cmd, arg);
-		
+
 			if (get_user(val, (int *)arg))
 				return -EFAULT;
 			if (val != 0)
@@ -1504,7 +1513,7 @@
 			if (!(synth_open_mask & (1 << dev)) && !orig_dev)
 				return -EBUSY;
 			return synth_devs[dev]->ioctl(dev, cmd, arg);
-		
+
 		/* Like SYNTH_INFO but returns ID in the name field */
 		case SNDCTL_SYNTH_ID:
 			if (get_user(dev, (int *)(&(((struct synth_info *)arg)->device))))
@@ -1517,7 +1526,7 @@
 			strncpy(inf.name, synth_devs[dev]->id, sizeof(inf.name));
 			inf.device = dev;
 			return copy_to_user(arg, &inf, sizeof(inf))?-EFAULT:0;
-		
+
 		case SNDCTL_SEQ_OUTOFBAND:
 			if (copy_from_user(&event_rec, arg, sizeof(event_rec)))
 				return -EFAULT;
@@ -1526,7 +1535,7 @@
 			play_event(event_rec.arr);
 			restore_flags(flags);
 			return 0;
-		  
+
 		case SNDCTL_MIDI_INFO:
 			if (get_user(dev, (int *)(&(((struct synth_info *)arg)->device))))
 				return -EFAULT;
@@ -1534,7 +1543,7 @@
 				return -ENXIO;
 			midi_devs[dev]->info.device = dev;
 			return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct synth_info))?-EFAULT:0;
-		
+
 		case SNDCTL_SEQ_THRESHOLD:
 			if (get_user(val, (int *)arg))
 				return -EFAULT;
@@ -1544,7 +1553,7 @@
 				val = SEQ_MAX_QUEUE - 1;
 			output_threshold = val;
 			return 0;
-		
+
 		case SNDCTL_MIDI_PRETIME:
 			if (get_user(val, (int *)arg))
 				return -EFAULT;
@@ -1584,7 +1593,7 @@
 
 	/* output */
 	poll_wait(file, &seq_sleeper, wait);
-	if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) 
+	if ((SEQ_MAX_QUEUE - qlen) >= output_threshold)
 		mask |= POLLOUT | POLLWRNORM;
 	restore_flags(flags);
 	return mask;
@@ -1665,8 +1674,8 @@
 	 */
 	while (bend > 2399)
 	{
-		  multiplier *= 4;
-		  bend -= 2400;
+		multiplier *= 4;
+		bend -= 2400;
 	}
 
 	semitones = bend / 100;
@@ -1693,8 +1702,8 @@
 	queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ);
 	if (queue == NULL)
 	{
-		  printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n");
-		  return;
+		printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n");
+		return;
 	}
 	iqueue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * IEV_SZ);
 	if (iqueue == NULL)
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c
--- v2.1.93/linux/drivers/sound/softoss.c	Mon Feb 23 18:12:09 1998
+++ linux/drivers/sound/softoss.c	Wed Apr  8 17:24:48 1998
@@ -2,15 +2,15 @@
  * sound/softoss.c
  *
  * Software based MIDI synthsesizer driver.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
- */
-/*
+ *
+ *
  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
  */
 #include <linux/config.h>
@@ -35,14 +35,15 @@
 #include "softoss.h"
 #include <linux/ultrasound.h>
 
-int             softsynth_disabled = 0;
+int softsynth_disabled = 0;
 
 static volatile int intr_pending = 0;
 
 #ifdef POLLED_MODE
 
-static struct timer_list poll_timer =
-{NULL, NULL, 0, 0, softsyn_poll};
+static struct timer_list poll_timer = {
+	NULL, NULL, 0, 0, softsyn_poll
+};
 
 #else
 #endif
@@ -101,11 +102,14 @@
 static volatile int is_running = 0;
 static int      softsynth_loaded = 0;
 
-static struct synth_info softsyn_info =
-{"SoftOSS", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH};
+static struct synth_info softsyn_info = {
+	"SoftOSS", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH
+};
+
+static struct softsyn_devc sdev_info = {
+	0
+};
 
-static struct softsyn_devc sdev_info =
-{0};
 softsyn_devc   *devc = &sdev_info;	/* used in softoss_rs.c */
 
 static struct voice_alloc_info *voice_alloc;
@@ -118,10 +122,9 @@
 static int      voice_limit = 24;
 
 
-static void
-set_max_voices(int nr)
+static void set_max_voices(int nr)
 {
-	int             i;
+	int i;
 
 	if (nr < 4)
 		nr = 4;
@@ -134,19 +137,18 @@
 
 	for (i = 31; i > 0; i--)
 		if (nr & (1 << i))
-		  {
-			  devc->afterscale = i + 1;
-			  return;
-		  }
+		{
+			devc->afterscale = i + 1;
+			return;
+		}
 }
 
-static void
-update_vibrato(int voice)
+static void update_vibrato(int voice)
 {
-	voice_info     *v = &softoss_voices[voice];
+	voice_info *v = &softoss_voices[voice];
 
 #ifdef HANDLE_LFO
-	int             x;
+	int x;
 
 	x = vibrato_table[v->vibrato_phase >> 8];
 	v->vibrato_phase = (v->vibrato_phase + v->vibrato_step) & 0x7fff;
@@ -161,11 +163,10 @@
 }
 
 #ifdef HANDLE_LFO
-static void
-update_tremolo(int voice)
+static void update_tremolo(int voice)
 {
-	voice_info     *v = &softoss_voices[voice];
-	int             x;
+	voice_info *v = &softoss_voices[voice];
+	int x;
 
 	x = tremolo_table[v->tremolo_phase >> 8];
 	v->tremolo_phase = (v->tremolo_phase + v->tremolo_step) & 0x7fff;
@@ -174,11 +175,10 @@
 }
 #endif
 
-static void
-start_vibrato(int voice)
+static void start_vibrato(int voice)
 {
-	voice_info     *v = &softoss_voices[voice];
-	int             rate;
+	voice_info *v = &softoss_voices[voice];
+	int rate;
 
 	if (!v->vibrato_depth)
 		return;
@@ -189,11 +189,10 @@
 	devc->vibratomap |= (1 << voice);	/* Enable vibrato */
 }
 
-static void
-start_tremolo(int voice)
+static void start_tremolo(int voice)
 {
-	voice_info     *v = &softoss_voices[voice];
-	int             rate;
+	voice_info *v = &softoss_voices[voice];
+	int rate;
 
 	if (!v->tremolo_depth)
 		return;
@@ -204,43 +203,43 @@
 	devc->tremolomap |= (1 << voice);	/* Enable tremolo */
 }
 
-static void
-update_volume(int voice)
+static void update_volume(int voice)
 {
-	voice_info     *v = &softoss_voices[voice];
-	unsigned int    vol;
+	voice_info *v = &softoss_voices[voice];
+	unsigned int vol;
 
-/*
- * Compute plain volume
- */
+	/*
+	 *	Compute plain volume
+	 */
 
 	vol = (v->velocity * v->expression_vol * v->main_vol) >> 12;
 
 #ifdef HANDLE_LFO
-/*
- * Handle LFO
- */
+	/*
+	 *	Handle LFO
+	 */
 
 	if (devc->tremolomap & (1 << voice))
-	  {
-		  int             t;
+	{
+		int t;
 
-		  t = 32768 - v->tremolo_level;
-		  vol = (vol * t) >> 15;
-		  update_tremolo(voice);
-	  }
+		t = 32768 - v->tremolo_level;
+		vol = (vol * t) >> 15;
+		update_tremolo(voice);
+	}
 #endif
-/*
- * Envelope
- */
+	/*
+	 *	Envelope
+	 */
+	 
 	if (v->mode & WAVE_ENVELOPES && !v->percussive_voice)
 		vol = (vol * (v->envelope_vol >> 16)) >> 19;
 	else
 		vol >>= 4;
 
-/*
- * Handle panning
- */
+	/*
+	 * Handle panning
+	 */
 
 	if (v->panning < 0)	/* Pan left */
 		v->rightvol = (vol * (128 + v->panning)) / 128;
@@ -253,45 +252,47 @@
 		v->leftvol = vol;
 }
 
-static void
-step_envelope(int voice, int do_release, int velocity)
+static void step_envelope(int voice, int do_release, int velocity)
 {
-	voice_info     *v = &softoss_voices[voice];
-	int             r, rate, time, dif;
-	unsigned int    vol;
-	unsigned long   flags;
+	voice_info *v = &softoss_voices[voice];
+	int r, rate, time, dif;
+	unsigned int vol;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
 
 	if (!voice_active[voice] || v->sample == NULL)
-	  {
-		  restore_flags(flags);
-		  return;
-	  }
+	{
+		restore_flags(flags);
+		return;
+	}
 	if (!do_release)
+	{
 		if (v->mode & WAVE_SUSTAIN_ON && v->envelope_phase == 2)
-		  {		/* Stop envelope until note off */
-			  v->envelope_volstep = 0;
-			  v->envelope_time = 0x7fffffff;
-			  if (v->mode & WAVE_VIBRATO)
-				  start_vibrato(voice);
-			  if (v->mode & WAVE_TREMOLO)
-				  start_tremolo(voice);
-			  restore_flags(flags);
-			  return;
-		  }
+		{	
+			/* Stop envelope until note off */
+			v->envelope_volstep = 0;
+			v->envelope_time = 0x7fffffff;
+			if (v->mode & WAVE_VIBRATO)
+				start_vibrato(voice);
+			if (v->mode & WAVE_TREMOLO)
+				start_tremolo(voice);
+			restore_flags(flags);
+			return;
+		}
+	}
 	if (do_release)
 		v->envelope_phase = 3;
 	else
 		v->envelope_phase++;
 
 	if (v->envelope_phase >= 5)	/* Finished */
-	  {
-		  init_voice(devc, voice);
-		  restore_flags(flags);
-		  return;
-	  }
+	{
+		init_voice(devc, voice);
+		restore_flags(flags);
+		return;
+	}
 	vol = v->envelope_target = v->sample->env_offset[v->envelope_phase] << 22;
 
 
@@ -308,72 +309,69 @@
 	if (dif < 0)
 		dif *= -1;
 	if (dif < rate * 2)	/* Too close */
-	  {
-		  step_envelope(voice, 0, 60);
-		  restore_flags(flags);
-		  return;
-	  }
+	{
+		step_envelope(voice, 0, 60);
+		restore_flags(flags);
+		return;
+	}
+
 	if (vol > v->envelope_vol)
-	  {
-		  v->envelope_volstep = rate;
-		  time = (vol - v->envelope_vol) / rate;
-	} else
-	  {
-		  v->envelope_volstep = -rate;
-		  time = (v->envelope_vol - vol) / rate;
-	  }
+	{
+		v->envelope_volstep = rate;
+		time = (vol - v->envelope_vol) / rate;
+	}
+	else
+	{
+		v->envelope_volstep = -rate;
+		time = (v->envelope_vol - vol) / rate;
+	}
 
 	time--;
 	if (time <= 0)
 		time = 1;
-
 	v->envelope_time = time;
-
-
 	restore_flags(flags);
 }
 
-static void
-step_envelope_lfo(int voice)
+static void step_envelope_lfo(int voice)
 {
-	voice_info     *v = &softoss_voices[voice];
+	voice_info *v = &softoss_voices[voice];
 
-/*
- * Update pitch (vibrato) LFO 
- */
+	/*
+	 * Update pitch (vibrato) LFO 
+	 */
 
 	if (devc->vibratomap & (1 << voice))
 		update_vibrato(voice);
 
-/* 
- * Update envelope
- */
+	/* 
+	 * Update envelope
+	 */
 
 	if (v->mode & WAVE_ENVELOPES)
-	  {
-		  v->envelope_vol += v->envelope_volstep;
-		  /* Overshoot protection */
-		  if (v->envelope_vol < 0)
-		    {
-			    v->envelope_vol = v->envelope_target;
-			    v->envelope_volstep = 0;
-		    }
-		  if (v->envelope_time-- <= 0)
-		    {
-			    v->envelope_vol = v->envelope_target;
-			    step_envelope(voice, 0, 60);
-		    }
-	  }
+	{
+		v->envelope_vol += v->envelope_volstep;
+		/* Overshoot protection */
+		if (v->envelope_vol < 0)
+		{
+			v->envelope_vol = v->envelope_target;
+			v->envelope_volstep = 0;
+		}
+		if (v->envelope_time-- <= 0)
+		{
+			v->envelope_vol = v->envelope_target;
+			step_envelope(voice, 0, 60);
+		}
+	}
 }
 
-static void
-compute_step(int voice)
+static void compute_step(int voice)
 {
-	voice_info     *v = &softoss_voices[voice];
+	voice_info *v = &softoss_voices[voice];
 
 	/*
-	 * Since the pitch bender may have been set before playing the note, we
-	 * have to calculate the bending now.
+	 *	Since the pitch bender may have been set before playing the note, we
+	 *	have to calculate the bending now.
 	 */
 
 	v->current_freq = compute_finetune(v->orig_freq,
@@ -386,11 +384,10 @@
 		v->step *= -1;	/* Reversed playback */
 }
 
-static void
-init_voice(softsyn_devc * devc, int voice)
+static void init_voice(softsyn_devc * devc, int voice)
 {
-	voice_info     *v = &softoss_voices[voice];
-	unsigned long   flags;
+	voice_info *v = &softoss_voices[voice];
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
@@ -433,18 +430,17 @@
 	restore_flags(flags);
 }
 
-static void
-reset_samples(softsyn_devc * devc)
+static void reset_samples(softsyn_devc * devc)
 {
-	int             i;
+	int i;
 
 	for (i = 0; i < MAX_VOICE; i++)
 		voice_active[i] = 0;
 	for (i = 0; i < devc->maxvoice; i++)
-	  {
-		  init_voice(devc, i);
-		  softoss_voices[i].instr = 0;
-	  }
+	{
+		init_voice(devc, i);
+		softoss_voices[i].instr = 0;
+	}
 
 	devc->ram_used = 0;
 
@@ -452,20 +448,18 @@
 		devc->programs[i] = NO_SAMPLE;
 
 	for (i = 0; i < devc->nrsamples; i++)
-	  {
-		  vfree(devc->samples[i]);
-		  vfree(devc->wave[i]);
-		  devc->samples[i] = NULL;
-		  devc->wave[i] = NULL;
-	  }
-
+	{
+		vfree(devc->samples[i]);
+		vfree(devc->wave[i]);
+		devc->samples[i] = NULL;
+		devc->wave[i] = NULL;
+	}
 	devc->nrsamples = 0;
 }
 
-static void
-init_engine(softsyn_devc * devc)
+static void init_engine(softsyn_devc * devc)
 {
-	int             i, fz, srate, sz = devc->channels;
+	int i, fz, srate, sz = devc->channels;
 
 	set_max_voices(devc->default_max_voices);
 	voice_alloc->timestamp = 0;
@@ -480,16 +474,15 @@
 	devc->usecs_per_frag = (1000000 * fz) / devc->speed;
 
 	for (i = 0; i < devc->maxvoice; i++)
-	  {
-		  init_voice(devc, i);
-		  softoss_voices[i].instr = 0;
-	  }
-
+	{
+		init_voice(devc, i);
+		softoss_voices[i].instr = 0;
+	}
 	devc->engine_state = ES_STOPPED;
 
-/*
- *    Initialize delay
- */
+	/*
+	 *    Initialize delay
+	 */
 
 	for (i = 0; i < DELAY_SIZE; i++)
 		left_delay[i] = right_delay[i] = 0;
@@ -502,34 +495,35 @@
 		devc->delay_size = DELAY_SIZE;
 }
 
-void
-softsyn_control_loop(void)
+void softsyn_control_loop(void)
 {
-	int             voice;
+	int voice;
 
-/*
- *    Recompute envlope, LFO, etc.
- */
+	/*
+	 *    Recompute envlope, LFO, etc.
+	 */
 	for (voice = 0; voice < devc->maxvoice; voice++)
+	{
 		if (voice_active[voice])
-		  {
-			  update_volume(voice);
-			  step_envelope_lfo(voice);
-		} else
+		{
+			update_volume(voice);
+			step_envelope_lfo(voice);
+		}
+		else
 			voice_alloc->map[voice] = 0;
+	}
 }
 
-static void     start_engine(softsyn_devc * devc);
+static void start_engine(softsyn_devc * devc);
 
-static void
-do_resample(int dummy)
+static void do_resample(int dummy)
 {
 	struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out;
 	struct voice_info *vinfo;
 	unsigned long   flags, jif;
 
-	int             voice, loops;
-	short          *buf;
+	int voice, loops;
+	short *buf;
 
 	if (softsynth_disabled)
 		return;
@@ -538,68 +532,70 @@
 	cli();
 
 	if (is_running)
-	  {
-		  printk("SoftOSS: Playback overrun\n");
-		  restore_flags(flags);
-		  return;
-	  }
+	{
+		printk(KERN_WARNING "SoftOSS: Playback overrun\n");
+		restore_flags(flags);
+		return;
+	}
 	jif = jiffies;
 	if (jif == last_resample_jiffies)
-	  {
-		  if (resample_counter++ > 50)
-		    {
-			    for (voice = 0; voice < devc->maxvoice; voice++)
-				    init_voice(devc, voice);
-			    voice_limit--;
-			    resample_counter = 0;
-			    printk("SoftOSS: CPU overload. Limiting # of voices to %d\n", voice_limit);
-
-			    if (voice_limit < 10)
-			      {
-				      voice_limit = 10;
-				      devc->speed = (devc->speed * 2) / 3;
-
-				      printk("SoftOSS: Dropping sampling rate and stopping the device.\n");
-				      softsynth_disabled = 1;
-			      }
-		    }
-	} else
-	  {
-		  last_resample_jiffies = jif;
-		  resample_counter = 0;
-	  }
+	{
+		if (resample_counter++ > 50)
+		{
+			for (voice = 0; voice < devc->maxvoice; voice++)
+				init_voice(devc, voice);
+			voice_limit--;
+			resample_counter = 0;
+			printk(KERN_WARNING "SoftOSS: CPU overload. Limiting # of voices to %d\n", voice_limit);
+
+			if (voice_limit < 10)
+			{
+				voice_limit = 10;
+				devc->speed = (devc->speed * 2) / 3;
+
+				printk(KERN_WARNING "SoftOSS: Dropping sampling rate and stopping the device.\n");
+				softsynth_disabled = 1;
+			}
+		}
+	}
+	else
+	{
+		last_resample_jiffies = jif;
+		resample_counter = 0;
+	}
 
 	/* is_running = 1; */
 
 	if (dmap->qlen > devc->max_playahead)
-	  {
-		  printk("SoftOSS: audio buffers full\n");
-		  is_running = 0;
-		  restore_flags(flags);
-		  return;
-	  }
-/*
- * First verify that all active voices are valid (do this just once per block).
- */
+	{
+		printk(KERN_WARNING "SoftOSS: audio buffers full\n");
+		is_running = 0;
+		restore_flags(flags);
+		return;
+	}
+	/*
+	 * First verify that all active voices are valid (do this just once per block).
+	 */
+
 	for (voice = 0; voice < devc->maxvoice; voice++)
+	{
 		if (voice_active[voice])
-		  {
-			  int             ptr;
+		{
+			int ptr;
 
-			  vinfo = &softoss_voices[voice];
-			  ptr = vinfo->ptr >> 9;
+			vinfo = &softoss_voices[voice];
+			ptr = vinfo->ptr >> 9;
 
-			  if (vinfo->wave == NULL ||
-			      ptr < 0 ||
-			      ptr > vinfo->sample->len)
-				  init_voice(devc, voice);
-			  else if (!(vinfo->mode & WAVE_LOOPING) &&
-			     (vinfo->ptr + vinfo->step) > vinfo->endloop)
+			if (vinfo->wave == NULL || ptr < 0 || ptr > vinfo->sample->len)
+				init_voice(devc, voice);
+			else if (!(vinfo->mode & WAVE_LOOPING) && (vinfo->ptr + vinfo->step) > vinfo->endloop)
 				  voice_active[voice] = 0;
-		  }
-/*
- *    Start the resampling process
- */
+		}
+	}
+	
+	/*
+	 *    Start the resampling process
+	 */
 
 	loops = devc->samples_per_fragment;
 	buf = (short *) (dmap->raw_buf + (dmap->qtail * dmap->fragment_size));
@@ -613,54 +609,51 @@
 	devc->usecs += devc->usecs_per_frag;
 
 	if (tmr_running)
-	  {
-		  sound_timer_interrupt();
-	  }
-/*
- *    Execute timer
- */
+		sound_timer_interrupt();
+	/*
+	 *    Execute timer
+	 */
 
 	if (!tmr_running)
+	{
 		if (devc->usecs >= devc->next_event_usecs)
-		  {
-			  devc->next_event_usecs = ~0;
-			  sequencer_timer(0);
-		  }
+		{
+			devc->next_event_usecs = ~0;
+			sequencer_timer(0);
+		}
+	}
+	
 	is_running = 0;
 	restore_flags(flags);
 }
 
-static void
-delayed_resample(int dummy)
+static void delayed_resample(int dummy)
 {
 	struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out;
-	int             n = 0;
+	int n = 0;
 
 	if (is_running)
 		return;
 
-	while (devc->engine_state != ES_STOPPED &&
-	       dmap->qlen < devc->max_playahead && n++ < 2)
+	while (devc->engine_state != ES_STOPPED && dmap->qlen < devc->max_playahead && n++ < 2)
 		do_resample(0);
 	intr_pending = 0;
 }
 
 #ifdef POLLED_MODE
-static void
-softsyn_poll(unsigned long dummy)
+static void softsyn_poll(unsigned long dummy)
 {
 	delayed_resample(0);
 
 	if (devc->engine_state != ES_STOPPED)
-
-	  {
-		  poll_timer.expires = (1) + jiffies;
+	{
+		  poll_timer.expires = jiffies+1;
 		  add_timer(&poll_timer);
-	  };
+	}
 }
+
 #else
-static void
-softsyn_callback(int dev, int parm)
+static void softsyn_callback(int dev, int parm)
 {
 	delayed_resample(0);
 }
@@ -686,13 +679,14 @@
 	devc->control_rate = 64;
 	devc->control_counter = 0;
 
-	if (devc->engine_state == ES_STOPPED) {
+	if (devc->engine_state == ES_STOPPED) 
+	{
 		n = trig = 0;
 		fs = get_fs();
 		set_fs(get_ds());
 		dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t)&trig);
 #ifdef POLLED_MODE
-		poll_timer.expires = (1) + jiffies;
+		poll_timer.expires = jiffies+1;
 		add_timer(&poll_timer);
 		/* Start polling */
 #else
@@ -711,13 +705,11 @@
 	}
 }
 
-static void
-stop_engine(softsyn_devc * devc)
+static void stop_engine(softsyn_devc * devc)
 {
 }
 
-static void
-request_engine(softsyn_devc * devc, int ticks)
+static void request_engine(softsyn_devc * devc, int ticks)
 {
 	if (ticks < 0)		/* Relative time */
 		devc->next_event_usecs = devc->usecs - ticks * (1000000 / HZ);
@@ -728,74 +720,72 @@
 /*
  * Softsync hook serves mode1 (timing) calls made by sequencer.c
  */
-static int
-softsynth_hook(int cmd, int parm1, int parm2, unsigned long parm3)
+ 
+static int softsynth_hook(int cmd, int parm1, int parm2, unsigned long parm3)
 {
 	switch (cmd)
-	  {
-	  case SSYN_START:
-		  start_engine(devc);
-		  break;
-
-	  case SSYN_STOP:
-		  stop_engine(devc);
-		  break;
-
-	  case SSYN_REQUEST:
-		  request_engine(devc, parm1);
-		  break;
-
-	  case SSYN_GETTIME:
-		  return devc->usecs / (1000000 / HZ);
-		  break;
-
-	  default:
-		  printk("SoftOSS: Unknown request %d\n", cmd);
-	  }
+	{
+		case SSYN_START:
+			start_engine(devc);
+			break;
+
+		case SSYN_STOP:
+			stop_engine(devc);
+			break;
+
+		case SSYN_REQUEST:
+			request_engine(devc, parm1);
+			break;
+
+		case SSYN_GETTIME:
+			return devc->usecs / (1000000 / HZ);
+			break;
 
+		default:
+			printk(KERN_WARNING "SoftOSS: Unknown request %d\n", cmd);
+	}
 	return 0;
 }
 
 static int softsyn_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-	switch (cmd) {
-
-	case SNDCTL_SYNTH_INFO:
-		softsyn_info.nr_voices = devc->maxvoice;
-		if (__copy_to_user(arg, &softsyn_info, sizeof(softsyn_info)))
-			return -EFAULT;
-		return 0;
-
-	case SNDCTL_SEQ_RESETSAMPLES:
-		stop_engine(devc);
-		reset_samples(devc);
-		return 0;
+	switch (cmd) 
+	{
+		case SNDCTL_SYNTH_INFO:
+			softsyn_info.nr_voices = devc->maxvoice;
+			if (copy_to_user(arg, &softsyn_info, sizeof(softsyn_info)))
+				return -EFAULT;
+			return 0;
+
+		case SNDCTL_SEQ_RESETSAMPLES:
+			stop_engine(devc);
+			reset_samples(devc);
+			return 0;
 		  
-	case SNDCTL_SYNTH_MEMAVL:
-		return devc->ram_size - devc->ram_used;
+		case SNDCTL_SYNTH_MEMAVL:
+			return devc->ram_size - devc->ram_used;
 
-	default:
-		return -EINVAL;
+		default:
+			return -EINVAL;
 	}
 }
 
-static int
-softsyn_kill_note(int devno, int voice, int note, int velocity)
+static int softsyn_kill_note(int devno, int voice, int note, int velocity)
 {
 	if (voice < 0 || voice > devc->maxvoice)
 		return 0;
 	voice_alloc->map[voice] = 0xffff;	/* Releasing */
 
 	if (softoss_voices[voice].sustain_mode & 1)	/* Sustain controller on */
-	  {
-		  softoss_voices[voice].sustain_mode = 3;	/* Note off pending */
-		  return 0;
-	  }
+	{
+		softoss_voices[voice].sustain_mode = 3;	/* Note off pending */
+		return 0;
+	}
 	if (velocity > 127 || softoss_voices[voice].mode & WAVE_FAST_RELEASE)
-	  {
-		  init_voice(devc, voice);	/* Mark it inactive */
-		  return 0;
-	  }
+	{
+		init_voice(devc, voice);	/* Mark it inactive */
+		return 0;
+	}
 	if (softoss_voices[voice].mode & WAVE_ENVELOPES)
 		step_envelope(voice, 1, velocity);	/* Enter sustain phase */
 	else
@@ -803,29 +793,26 @@
 	return 0;
 }
 
-static int
-softsyn_set_instr(int dev, int voice, int instr)
+static int softsyn_set_instr(int dev, int voice, int instr)
 {
 	if (voice < 0 || voice > devc->maxvoice)
 		return 0;
 
 	if (instr < 0 || instr > MAX_PATCH)
-	  {
-		  printk("SoftOSS: Invalid instrument number %d\n", instr);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "SoftOSS: Invalid instrument number %d\n", instr);
+		return 0;
+	}
 	softoss_voices[voice].instr = instr;
-
 	return 0;
 }
 
-static int
-softsyn_start_note(int dev, int voice, int note, int volume)
+static int softsyn_start_note(int dev, int voice, int note, int volume)
 {
-	int             instr = 0;
-	int             best_sample, best_delta, delta_freq, selected;
-	unsigned long   note_freq, freq, base_note, flags;
-	voice_info     *v = &softoss_voices[voice];
+	int instr = 0;
+	int best_sample, best_delta, delta_freq, selected;
+	unsigned long note_freq, freq, base_note, flags;
+	voice_info *v = &softoss_voices[voice];
 
 	struct patch_info *sample;
 
@@ -839,32 +826,32 @@
 	cli();
 
 	if (note == 255)
-	  {			/* Just volume update */
-		  v->velocity = volume;
-		  if (voice_active[voice])
-			  update_volume(voice);
-		  restore_flags(flags);
-		  return 0;
-	  }
+	{			/* Just volume update */
+		v->velocity = volume;
+		if (voice_active[voice])
+			update_volume(voice);
+		restore_flags(flags);
+		return 0;
+	}
 	voice_active[voice] = 0;	/* Stop the voice for a while */
 	devc->vibratomap &= ~(1 << voice);
 	devc->tremolomap &= ~(1 << voice);
 
 	instr = v->instr;
 	if (instr < 0 || instr > MAX_PATCH || devc->programs[instr] == NO_SAMPLE)
-	  {
-		  printk("SoftOSS: Undefined MIDI instrument %d\n", instr);
-		  restore_flags(flags);
-		  return 0;
-	  }
+	{
+		printk(KERN_WARNING "SoftOSS: Undefined MIDI instrument %d\n", instr);
+		restore_flags(flags);
+		return 0;
+	}
 	instr = devc->programs[instr];
 
 	if (instr < 0 || instr >= devc->nrsamples)
-	  {
-		  printk("SoftOSS: Corrupted MIDI instrument %d (%d)\n", v->instr, instr);
-		  restore_flags(flags);
-		  return 0;
-	  }
+	{
+		printk(KERN_WARNING "SoftOSS: Corrupted MIDI instrument %d (%d)\n", v->instr, instr);
+		restore_flags(flags);
+		return 0;
+	}
 	note_freq = note_to_freq(note);
 
 	selected = -1;
@@ -873,25 +860,26 @@
 	best_delta = 1000000;
 
 	while (instr != NO_SAMPLE && instr >= 0 && selected == -1)
-	  {
-		  delta_freq = note_freq - devc->samples[instr]->base_note;
+	{
+		delta_freq = note_freq - devc->samples[instr]->base_note;
+
+		if (delta_freq < 0)
+			delta_freq = -delta_freq;
+		if (delta_freq < best_delta)
+		{
+			best_sample = instr;
+			best_delta = delta_freq;
+		}
+		if (devc->samples[instr]->low_note <= note_freq &&
+			note_freq <= devc->samples[instr]->high_note)
+		{
+			selected = instr;
+		}
+		else instr = devc->samples[instr]->key;	/* Link to next sample */
 
-		  if (delta_freq < 0)
-			  delta_freq = -delta_freq;
-		  if (delta_freq < best_delta)
-		    {
-			    best_sample = instr;
-			    best_delta = delta_freq;
-		    }
-		  if (devc->samples[instr]->low_note <= note_freq &&
-		      note_freq <= devc->samples[instr]->high_note)
-			  selected = instr;
-		  else
-			  instr = devc->samples[instr]->key;	/* Link to next sample */
-
-		  if (instr < 0 || instr >= devc->nrsamples)
-			  instr = NO_SAMPLE;
-	  }
+		if (instr < 0 || instr >= devc->nrsamples)
+			instr = NO_SAMPLE;
+	}
 
 	if (selected == -1)
 		instr = best_sample;
@@ -899,37 +887,33 @@
 		instr = selected;
 
 	if (instr < 0 || instr == NO_SAMPLE || instr > devc->nrsamples)
-	  {
-		  printk("SoftOSS: Unresolved MIDI instrument %d\n", v->instr);
-		  restore_flags(flags);
-		  return 0;
-	  }
+	{
+		printk(KERN_WARNING "SoftOSS: Unresolved MIDI instrument %d\n", v->instr);
+		restore_flags(flags);
+		return 0;
+	}
 	sample = devc->samples[instr];
 	v->sample = sample;
 
 	if (v->percussive_voice)	/* No key tracking */
-	  {
 		  v->orig_freq = sample->base_freq;	/* Fixed pitch */
-	} else
-	  {
-		  base_note = sample->base_note / 100;
-		  note_freq /= 100;
-
-		  freq = sample->base_freq * note_freq / base_note;
-		  v->orig_freq = freq;
-	  }
+	else
+	{
+		base_note = sample->base_note / 100;
+		note_freq /= 100;
+
+		freq = sample->base_freq * note_freq / base_note;
+		v->orig_freq = freq;
+	}
 
 	if (!(sample->mode & WAVE_LOOPING))
-	  {
-		  sample->loop_end = sample->len;
-	  }
-	v->wave = devc->wave[instr];
+		sample->loop_end = sample->len;
 
+	v->wave = devc->wave[instr];
 	if (volume < 0)
 		volume = 0;
 	else if (volume > 127)
 		volume = 127;
-
 	v->ptr = 0;
 	v->startloop = sample->loop_start * 512;
 	v->startbackloop = 0;
@@ -954,40 +938,39 @@
 	if (!(v->mode & WAVE_LOOPING))
 		v->mode &= ~(WAVE_BIDIR_LOOP | WAVE_LOOP_BACK);
 	else if (v->mode & WAVE_LOOP_BACK)
-	  {
-		  v->ptr = sample->len;
-		  v->startbackloop = v->startloop;
-	  }
+	{
+		v->ptr = sample->len;
+		v->startbackloop = v->startloop;
+	}
 	if (v->mode & WAVE_VIBRATO)
-	  {
-		  v->vibrato_rate = sample->vibrato_rate;
-		  v->vibrato_depth = sample->vibrato_depth;
-	  }
+	{
+		v->vibrato_rate = sample->vibrato_rate;
+		v->vibrato_depth = sample->vibrato_depth;
+	}
 	if (v->mode & WAVE_TREMOLO)
-	  {
-		  v->tremolo_rate = sample->tremolo_rate;
-		  v->tremolo_depth = sample->tremolo_depth;
-	  }
+	{
+		v->tremolo_rate = sample->tremolo_rate;
+		v->tremolo_depth = sample->tremolo_depth;
+	}
 	if (v->mode & WAVE_ENVELOPES)
-	  {
-		  v->envelope_phase = -1;
-		  v->envelope_vol = 0;
-		  step_envelope(voice, 0, 60);
-	  }
+	{
+		v->envelope_phase = -1;
+		v->envelope_vol = 0;
+		step_envelope(voice, 0, 60);
+	}
 	update_volume(voice);
 	compute_step(voice);
 
 	voice_active[voice] = 1;	/* Mark it active */
-
 	restore_flags(flags);
 	return 0;
 }
 
 static int softsyn_open(int synthdev, int mode)
 {
-	int             err;
-	extern int      softoss_dev;
-	int             frags = 0x7fff0007;	/* fragment size of 128 bytes */
+	int err;
+	extern int softoss_dev;
+	int frags = 0x7fff0007;	/* fragment size of 128 bytes */
 	mm_segment_t fs;
 
 	if (devc->audio_opened)	/* Already opened */
@@ -1007,10 +990,10 @@
 	devc->audiodev = softoss_dev;
 
 	if (!(audio_devs[devc->audiodev]->format_mask & AFMT_S16_LE))
-	  {
-		  printk("SoftOSS: The audio device doesn't support 16 bits\n");
-		  return -ENXIO;
-	  }
+	{
+/*		printk(KERN_ERR "SoftOSS: The audio device doesn't support 16 bits\n"); */
+		return -ENXIO;
+	}
 	if ((err = audio_open((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo)) < 0)
 		return err;
 
@@ -1023,7 +1006,6 @@
 
 
 	DDB(printk("SoftOSS: Using audio dev %d, speed %d, bits %d, channels %d\n", devc->audiodev, devc->speed, devc->bits, devc->channels));
-
 	fs = get_fs();
 	set_fs(get_ds());
 	dma_ioctl(devc->audiodev, SNDCTL_DSP_SETFRAGMENT, (caddr_t) & frags);
@@ -1031,11 +1013,11 @@
 	set_fs(fs);
 
 	if (devc->bits != 16 || devc->channels != 2)
-	  {
-		  audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo);
-		  printk("SoftOSS: A 16 bit stereo soundcard is required\n");
-		  return 0;
-	  }
+	{
+		audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo);
+/*		printk("SoftOSS: A 16 bit stereo soundcard is required\n");*/
+		return -EINVAL;
+	}
 	if (devc->max_playahead >= audio_devs[devc->audiodev]->dmap_out->nbufs)
 		devc->max_playahead = audio_devs[devc->audiodev]->dmap_out->nbufs;
 
@@ -1064,12 +1046,11 @@
 	devc->audio_opened = 0;
 }
 
-static void
-softsyn_hw_control(int dev, unsigned char *event_rec)
+static void softsyn_hw_control(int dev, unsigned char *event_rec)
 {
-	int             voice, cmd;
-	unsigned short  p1, p2;
-	unsigned int    plong;
+	int voice, cmd;
+	unsigned short p1, p2;
+	unsigned int plong;
 
 	cmd = event_rec[2];
 	voice = event_rec[3];
@@ -1078,48 +1059,47 @@
 	plong = *(unsigned int *) &event_rec[4];
 
 	switch (cmd)
-	  {
+	{
 
-	  case _GUS_NUMVOICES:
-		  set_max_voices(p1);
-		  break;
+		case _GUS_NUMVOICES:
+			set_max_voices(p1);
+			break;
 
-
-	  default:;
-	  }
+		default:;
+	}
 }
 
-static int
-softsyn_load_patch(int dev, int format, const char *addr,
+static int softsyn_load_patch(int dev, int format, const char *addr,
 		   int offs, int count, int pmgr_flag)
 {
 	struct patch_info *patch = NULL;
 
-	int             i, p, instr;
-	long            sizeof_patch;
-	int             memlen, adj;
+	int i, p, instr;
+	long sizeof_patch;
+	int memlen, adj;
 	unsigned short  data;
-	short          *wave = NULL;
+	short *wave = NULL;
 
 	sizeof_patch = (long) &patch->data[0] - (long) patch;	/* Header size */
 
 	if (format != GUS_PATCH)
-	  {
-		  printk("SoftOSS: Invalid patch format (key) 0x%x\n", format);
-		  return -EINVAL;
-	  }
+	{
+/*		printk(KERN_ERR "SoftOSS: Invalid patch format (key) 0x%x\n", format);*/
+		return -EINVAL;
+	}
 	if (count < sizeof_patch)
-	  {
-		  printk("SoftOSS: Patch header too short\n");
-		  return -EINVAL;
-	  }
+	{
+/*		printk(KERN_ERR "SoftOSS: Patch header too short\n");*/
+		return -EINVAL;
+	}
 	count -= sizeof_patch;
 
 	if (devc->nrsamples >= MAX_SAMPLE)
-	  {
-		  printk("SoftOSS: Sample table full\n");
-		  return -ENOSPC;
-	  }
+	{
+/*		  printk(KERN_ERR "SoftOSS: Sample table full\n");*/
+		  return -ENOBUFS;
+	}
+	
 	/*
 	 * Copy the header from user space but ignore the first bytes which have
 	 * been transferred already.
@@ -1128,54 +1108,55 @@
 	patch = vmalloc(sizeof(*patch));
 
 	if (patch == NULL)
-	  {
-		  printk("SoftOSS: Out of memory\n");
-		  return -ENOSPC;
-	  }
-	copy_from_user(&((char *) patch)[offs], &(addr)[offs], sizeof_patch - offs);
+	{
+/*		printk(KERN_ERR "SoftOSS: Out of memory\n");*/
+		return -ENOMEM;
+	}
+	if(copy_from_user(&((char *) patch)[offs], &(addr)[offs], sizeof_patch - offs))
+		return -EFAULT;
 
 	if (patch->mode & WAVE_ROM)
-	  {
-		  vfree(patch);
-		  return -EINVAL;
-	  }
+	{
+		vfree(patch);
+		return -EINVAL;
+	}
 	instr = patch->instr_no;
 
 	if (instr < 0 || instr > MAX_PATCH)
-	  {
-		  printk("SoftOSS: Invalid patch number %d\n", instr);
-		  vfree(patch);
-		  return -EINVAL;
-	  }
+	{
+/*		printk(KERN_ERR "SoftOSS: Invalid patch number %d\n", instr);*/
+		vfree(patch);
+		return -EINVAL;
+	}
 	if (count < patch->len)
-	  {
-		  printk("SoftOSS: Patch record too short (%d<%d)\n", count, (int) patch->len);
-		  patch->len = count;
-	  }
+	{
+/*		printk(KERN_ERR "SoftOSS: Patch record too short (%d<%d)\n", count, (int) patch->len);*/
+		patch->len = count;
+	}
 	if (patch->len <= 0 || patch->len > (devc->ram_size - devc->ram_used))
-	  {
-		  printk("SoftOSS: Invalid sample length %d\n", (int) patch->len);
-		  vfree(patch);
-		  return -EINVAL;
-	  }
+	{
+/*		printk(KERN_ERR "SoftOSS: Invalid sample length %d\n", (int) patch->len); */
+		vfree(patch);
+		return -EINVAL;
+	}
 	if (patch->mode & WAVE_LOOPING)
-	  {
-		  if (patch->loop_start < 0 || patch->loop_start >= patch->len)
-		    {
-			    printk("SoftOSS: Invalid loop start %d\n", patch->loop_start);
-			    vfree(patch);
-			    return -EINVAL;
-		    }
-		  if (patch->loop_end < patch->loop_start || patch->loop_end > patch->len)
-		    {
-			    printk("SoftOSS: Invalid loop start or end point (%d, %d)\n", patch->loop_start, patch->loop_end);
-			    vfree(patch);
-			    return -EINVAL;
-		    }
-	  }
-/* 
- * Next load the wave data to memory
- */
+	{
+		if (patch->loop_start < 0 || patch->loop_start >= patch->len)
+		{
+/*			printk(KERN_ERR "SoftOSS: Invalid loop start %d\n", patch->loop_start);*/
+			vfree(patch);
+			return -EINVAL;
+		}
+		if (patch->loop_end < patch->loop_start || patch->loop_end > patch->len)
+		{
+/*			printk(KERN_ERR "SoftOSS: Invalid loop start or end point (%d, %d)\n", patch->loop_start, patch->loop_end);*/
+			vfree(patch);
+			return -EINVAL;
+		}
+	}
+	/* 
+	 *	Next load the wave data to memory
+	 */
 
 	memlen = patch->len;
 	adj = 1;
@@ -1188,48 +1169,47 @@
 	wave = vmalloc(memlen);
 
 	if (wave == NULL)
-	  {
-		  printk("SoftOSS: Can't allocate %d bytes of mem for a sample\n", memlen);
-		  vfree(patch);
-		  return -ENOSPC;
-	  }
+	{
+/*		printk(KERN_ERR "SoftOSS: Can't allocate %d bytes of mem for a sample\n", memlen);*/
+		vfree(patch);
+		return -ENOMEM;
+	}
 	p = 0;
 	for (i = 0; i < memlen / 2; i++)	/* Handle words */
-	  {
-		  unsigned char   tmp;
-
-		  data = 0;
-
-		  if (patch->mode & WAVE_16_BITS)
-		    {
-			    get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++]));		/* Get lsb */
-			    data = tmp;
-			    get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++]));		/* Get msb */
-			    if (patch->mode & WAVE_UNSIGNED)
-				    tmp ^= 0x80;	/* Convert to signed */
-			    data |= (tmp << 8);
-		  } else
-		    {
-			    get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++]));
-			    if (patch->mode & WAVE_UNSIGNED)
-				    tmp ^= 0x80;	/* Convert to signed */
+	{
+		unsigned char tmp;
+		data = 0;
+		if (patch->mode & WAVE_16_BITS)
+		{
+			get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++]));		/* Get lsb */
+			data = tmp;
+			get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++]));		/* Get msb */
+			if (patch->mode & WAVE_UNSIGNED)
+				tmp ^= 0x80;	/* Convert to signed */
+			data |= (tmp << 8);
+		}
+		else
+		{
+			get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++]));
+			if (patch->mode & WAVE_UNSIGNED)
+				tmp ^= 0x80;	/* Convert to signed */
 			    data = (tmp << 8);	/* Convert to 16 bits */
-		    }
-
-		  wave[i] = (short) data;
-	  }
+		}
+		wave[i] = (short) data;
+	}
 
 	devc->ram_used += patch->len;
-/*
- * Convert pointers to 16 bit indexes
- */
+
+	/*
+	 * Convert pointers to 16 bit indexes
+	 */
 	patch->len /= adj;
 	patch->loop_start /= adj;
 	patch->loop_end /= adj;
 
-/*
- * Finally link the loaded patch to the chain
- */
+	/*
+	 * Finally link the loaded patch to the chain
+	 */
 
 	patch->key = devc->programs[instr];
 	devc->programs[instr] = devc->nrsamples;
@@ -1239,8 +1219,7 @@
 	return 0;
 }
 
-static void
-softsyn_panning(int dev, int voice, int pan)
+static void softsyn_panning(int dev, int voice, int pan)
 {
 	if (voice < 0 || voice > devc->maxvoice)
 		return;
@@ -1255,13 +1234,11 @@
 		update_volume(voice);
 }
 
-static void
-softsyn_volume_method(int dev, int mode)
+static void softsyn_volume_method(int dev, int mode)
 {
 }
 
-static void
-softsyn_aftertouch(int dev, int voice, int pressure)
+static void softsyn_aftertouch(int dev, int voice, int pressure)
 {
 	if (voice < 0 || voice > devc->maxvoice)
 		return;
@@ -1270,10 +1247,9 @@
 		update_volume(voice);
 }
 
-static void
-softsyn_controller(int dev, int voice, int ctrl_num, int value)
+static void softsyn_controller(int dev, int voice, int ctrl_num, int value)
 {
-	unsigned long   flags;
+	unsigned long flags;
 
 	if (voice < 0 || voice > devc->maxvoice)
 		return;
@@ -1281,48 +1257,46 @@
 	cli();
 
 	switch (ctrl_num)
-	  {
-	  case CTRL_PITCH_BENDER:
-		  softoss_voices[voice].bender = value;
-
-		  if (voice_active[voice])
-			  compute_step(voice);	/* Update pitch */
-		  break;
-
-
-	  case CTRL_PITCH_BENDER_RANGE:
-		  softoss_voices[voice].bender_range = value;
-		  break;
-	  case CTL_EXPRESSION:
-		  value /= 128;
-	  case CTRL_EXPRESSION:
-		  softoss_voices[voice].expression_vol = value;
-		  if (voice_active[voice])
-			  update_volume(voice);
-		  break;
-
-	  case CTL_PAN:
-		  softsyn_panning(dev, voice, (value * 2) - 128);
-		  break;
-
-	  case CTL_MAIN_VOLUME:
-		  value = (value * 100) / 16383;
-
-	  case CTRL_MAIN_VOLUME:
-		  softoss_voices[voice].main_vol = value;
-		  if (voice_active[voice])
-			  update_volume(voice);
-		  break;
-
-	  default:
-		  break;
-	  }
+	{
+		case CTRL_PITCH_BENDER:
+			softoss_voices[voice].bender = value;
+			if (voice_active[voice])
+				compute_step(voice);	/* Update pitch */
+			break;
+
+
+		case CTRL_PITCH_BENDER_RANGE:
+			softoss_voices[voice].bender_range = value;
+			break;
+			
+		case CTL_EXPRESSION:
+			value /= 128;
+		case CTRL_EXPRESSION:
+			softoss_voices[voice].expression_vol = value;
+			if (voice_active[voice])
+				update_volume(voice);
+			break;
+
+		case CTL_PAN:
+			softsyn_panning(dev, voice, (value * 2) - 128);
+			break;
+
+		case CTL_MAIN_VOLUME:
+			value = (value * 100) / 16383;
+
+		case CTRL_MAIN_VOLUME:
+			softoss_voices[voice].main_vol = value;
+			if (voice_active[voice])
+				update_volume(voice);
+			break;
 
+		default:
+			break;
+	}
 	restore_flags(flags);
 }
 
-static void
-softsyn_bender(int dev, int voice, int value)
+static void softsyn_bender(int dev, int voice, int value)
 {
 	if (voice < 0 || voice > devc->maxvoice)
 		return;
@@ -1332,46 +1306,46 @@
 		compute_step(voice);	/* Update pitch */
 }
 
-static int
-softsyn_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc)
+static int softsyn_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc)
 {
-	int             i, p, best = -1, best_time = 0x7fffffff;
+	int i, p, best = -1, best_time = 0x7fffffff;
 
 	p = alloc->ptr;
+
 	/*
-	   * First look for a completely stopped voice
+	 * First look for a completely stopped voice
 	 */
 
 	for (i = 0; i < alloc->max_voice; i++)
-	  {
-		  if (alloc->map[p] == 0)
-		    {
-			    alloc->ptr = p;
-			    voice_active[p] = 0;
-			    return p;
-		    }
-		  if (alloc->alloc_times[p] < best_time)
-		    {
-			    best = p;
-			    best_time = alloc->alloc_times[p];
-		    }
-		  p = (p + 1) % alloc->max_voice;
-	  }
+	{
+		if (alloc->map[p] == 0)
+		{
+			alloc->ptr = p;
+			voice_active[p] = 0;
+			return p;
+		}
+		if (alloc->alloc_times[p] < best_time)
+		{
+			best = p;
+			best_time = alloc->alloc_times[p];
+		}
+		p = (p + 1) % alloc->max_voice;
+	}
 
 	/*
-	   * Then look for a releasing voice
+	 * Then look for a releasing voice
 	 */
 
 	for (i = 0; i < alloc->max_voice; i++)
-	  {
-		  if (alloc->map[p] == 0xffff)
-		    {
-			    alloc->ptr = p;
-			    voice_active[p] = 0;
-			    return p;
-		    }
-		  p = (p + 1) % alloc->max_voice;
-	  }
+	{
+		if (alloc->map[p] == 0xffff)
+		{
+			alloc->ptr = p;
+			voice_active[p] = 0;
+			return p;
+		}
+		p = (p + 1) % alloc->max_voice;
+	}
 
 	if (best >= 0)
 		p = best;
@@ -1381,23 +1355,20 @@
 	return p;
 }
 
-static void
-softsyn_setup_voice(int dev, int voice, int chn)
+static void softsyn_setup_voice(int dev, int voice, int chn)
 {
-	unsigned long   flags;
+	unsigned long flags;
 
-	struct channel_info *info =
-	&synth_devs[dev]->chn_info[chn];
+	struct channel_info *info = &synth_devs[dev]->chn_info[chn];
 
 	save_flags(flags);
 	cli();
+
 	/* init_voice(devc, voice); */
 	softsyn_set_instr(dev, voice, info->pgm_num);
 
-	softoss_voices[voice].expression_vol =
-	    info->controllers[CTL_EXPRESSION];	/* Just MSB */
-	softoss_voices[voice].main_vol =
-	    (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128;
+	softoss_voices[voice].expression_vol = info->controllers[CTL_EXPRESSION];	/* Just MSB */
+	softoss_voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128;
 	softsyn_panning(dev, voice, (info->controllers[CTL_PAN] * 2) - 128);
 	softoss_voices[voice].bender = 0;	/* info->bender_value; */
 	softoss_voices[voice].bender_range = info->bender_range;
@@ -1407,11 +1378,10 @@
 	restore_flags(flags);
 }
 
-static void
-softsyn_reset(int devno)
+static void softsyn_reset(int devno)
 {
-	int             i;
-	unsigned long   flags;
+	int i;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
@@ -1450,23 +1420,20 @@
  * Timer stuff (for /dev/music).
  */
 
-static unsigned int
-soft_tmr_start(int dev, unsigned int usecs)
+static unsigned int soft_tmr_start(int dev, unsigned int usecs)
 {
 	tmr_running = 1;
 	start_engine(devc);
 	return devc->usecs_per_frag;
 }
 
-static void
-soft_tmr_disable(int dev)
+static void soft_tmr_disable(int dev)
 {
 	stop_engine(devc);
 	tmr_running = 0;
 }
 
-static void
-soft_tmr_restart(int dev)
+static void soft_tmr_restart(int dev)
 {
 	tmr_running = 1;
 }
@@ -1480,10 +1447,9 @@
 	soft_tmr_restart
 };
 
-int
-probe_softsyn(struct address_info *hw_config)
+int probe_softsyn(struct address_info *hw_config)
 {
-	int             i;
+	int i;
 
 	if (softsynth_loaded)
 		return 0;
@@ -1492,10 +1458,10 @@
 	devc->ram_used = 0;
 	devc->nrsamples = 0;
 	for (i = 0; i < MAX_PATCH; i++)
-	  {
-		  devc->programs[i] = NO_SAMPLE;
-		  devc->wave[i] = NULL;
-	  }
+	{
+		devc->programs[i] = NO_SAMPLE;
+		devc->wave[i] = NULL;
+	}
 
 	devc->maxvoice = DEFAULT_VOICES;
 
@@ -1516,15 +1482,12 @@
 #else
 	devc->default_max_voices = 32;
 #endif
-
 	softsynth_loaded = 1;
 	return 1;
 }
 
-void
-attach_softsyn_card(struct address_info *hw_config)
+void attach_softsyn_card(struct address_info *hw_config)
 {
-
 	voice_alloc = &softsyn_operations.alloc;
 	synth_devs[devc->synthdev = num_synths++] = &softsyn_operations;
 	sequencer_init();
@@ -1536,14 +1499,10 @@
 #endif
 }
 
-void
-unload_softsyn(struct address_info *hw_config)
+void unload_softsyn(struct address_info *hw_config)
 {
 	if (!softsynth_loaded)
 		return;
-#ifndef POLLED_MODE
-#endif
-
 	softsynthp = NULL;
 	softsynth_loaded = 0;
 	reset_samples(devc);
@@ -1553,10 +1512,9 @@
 
 static struct address_info config;
 
-int
-init_module(void)
+int init_module(void)
 {
-	printk("SoftOSS driver Copyright (C) by Hannu Savolainen 1993-1997\n");
+	printk(KERN_INFO "SoftOSS driver Copyright (C) by Hannu Savolainen 1993-1997\n");
 	if (!probe_softsyn(&config))
 		return -ENODEV;
 	attach_softsyn_card(&config);
@@ -1564,8 +1522,7 @@
 	return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
 	unload_softsyn(&config);
 	sound_unload_synthdev(devc->synthdev);
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/softoss_rs.c linux/drivers/sound/softoss_rs.c
--- v2.1.93/linux/drivers/sound/softoss_rs.c	Sat Nov 29 10:33:21 1997
+++ linux/drivers/sound/softoss_rs.c	Wed Apr  8 17:24:48 1998
@@ -5,8 +5,8 @@
  * Software based MIDI synthsesizer driver, the actual mixing loop.
  * Keep the loop as simple as possible to make it easier to rewrite this 
  * routine in assembly.
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
@@ -21,10 +21,9 @@
 #if defined(CONFIG_SOFTOSS) || defined(MODULE)
 #include "softoss.h"
 
-void
-softsynth_resample_loop(short *buf, int loops)
+void softsynth_resample_loop(short *buf, int loops)
 {
-	int             iloop, voice;
+	int iloop, voice;
 	volatile voice_info *v;
 
 #ifdef OSS_BIG_ENDIAN
@@ -33,104 +32,102 @@
 #endif
 
 	for (iloop = 0; iloop < loops; iloop++)
-	  {			/* Mix one sample */
-
-		  int             accum, left = 0, right = 0;
-		  int             ix, position;
-
-		  for (voice = 0; voice < devc->maxvoice; voice++)
-			  if (voice_active[voice])
-			    {	/* Compute voice */
-
-				    v = &softoss_voices[voice];
+	{			/* Mix one sample */
+		int accum, left = 0, right = 0;
+		int ix, position;
+
+		for (voice = 0; voice < devc->maxvoice; voice++)
+		{
+			if (voice_active[voice])
+			{	/* Compute voice */
+				v = &softoss_voices[voice];
 #ifdef SOFTOSS_TEST
-				    ix = iloop << 3;
-				    position = v->ptr;
+				ix = iloop << 3;
+				position = v->ptr;
 #else
-				    ix = (position = v->ptr) >> 9;
+				ix = (position = v->ptr) >> 9;
 #endif
-				    /* Interpolation (resolution of 512 steps) */
-				    {
-					    int             fract = v->ptr & 0x1f;	/* 9 bits */
-
-					    /* This method works with less arithmetic operations */
-					    register int    v1 = v->wave[ix];
-
-					    accum = v1 + ((((v->wave[ix + 1] - v1)) * (fract)) >> 9);
-				    }
-
-				    left += (accum * v->leftvol);
-				    right += (accum * v->rightvol);
-
-				    /* Update sample pointer */
-
-				    position += v->step;
-				    if (position <= v->endloop)
-					    v->ptr = position;
-				    else if (v->mode & WAVE_LOOPING)
-				      {
-					      if (v->mode & WAVE_BIDIR_LOOP)
-						{
-							v->mode ^= WAVE_LOOP_BACK;	/* Turn around */
-							v->step *= -1;
-					      } else
-						{
-							position -= v->looplen;
-							v->ptr = position;
-						}
-				      }
-				    /*  else leave the voice looping the current sample */
-
-				    if (v->mode & WAVE_LOOP_BACK && position < v->startloop)
-				      {
-					      if (v->mode & WAVE_BIDIR_LOOP)
-						{
-							v->mode ^= WAVE_LOOP_BACK;	/* Turn around */
-							v->step *= -1;
-					      } else
-						{
-							position += v->looplen;
-							v->ptr = position;
-						}
-				      }
-			    }	/* Compute voice */
+				/* Interpolation (resolution of 512 steps) */
+				{
+					int fract = v->ptr & 0x1f;	/* 9 bits */
+
+					/* This method works with less arithmetic operations */
+					register int v1 = v->wave[ix];
+					accum = v1 + ((((v->wave[ix + 1] - v1)) * (fract)) >> 9);
+				}
+
+				left += (accum * v->leftvol);
+				right += (accum * v->rightvol);
+
+				/* Update sample pointer */
+				position += v->step;
+				if (position <= v->endloop)
+					v->ptr = position;
+				else if (v->mode & WAVE_LOOPING)
+				{
+					if (v->mode & WAVE_BIDIR_LOOP)
+					{							v->mode ^= WAVE_LOOP_BACK;	/* Turn around */
+						v->step *= -1;
+					}
+					else
+					{
+						position -= v->looplen;
+						v->ptr = position;
+					}
+				}
+				/*  else leave the voice looping the current sample */
+
+				if (v->mode & WAVE_LOOP_BACK && position < v->startloop)
+				{
+					if (v->mode & WAVE_BIDIR_LOOP)
+					{							v->mode ^= WAVE_LOOP_BACK;	/* Turn around */
+						v->step *= -1;
+					}
+					else
+					{
+						position += v->looplen;
+						v->ptr = position;
+					}
+				}
+			}	/* Compute voice */
+		}
 #if 1				/* Delay */
-		  left += left_delay[delayp];
-		  right += right_delay[delayp];
+		left += left_delay[delayp];
+		right += right_delay[delayp];
 
-		  left_delay[delayp] = right >> 2;
-		  right_delay[delayp] = left >> 2;
-		  delayp = (delayp + 1) % devc->delay_size;
+		left_delay[delayp] = right >> 2;
+		right_delay[delayp] = left >> 2;
+		delayp = (delayp + 1) % devc->delay_size;
 #endif
 
 #define AFTERSCALE devc->afterscale;
 
-		  left >>= AFTERSCALE;
-		  right >>= AFTERSCALE;
+		left >>= AFTERSCALE;
+		right >>= AFTERSCALE;
 
-		  if (left > 32767)
-			  left = 32767;
-		  if (left < -32768)
-			  left = -32768;
-		  if (right > 32767)
-			  right = 32767;
-		  if (right < -32768)
-			  right = -32768;
+		if (left > 32767)
+			left = 32767;
+		if (left < -32768)
+			left = -32768;
+		if (right > 32767)
+			right = 32767;
+		if (right < -32768)
+			right = -32768;
 
 #ifdef OSS_BIG_ENDIAN
-		  *cbuf++ = left & 0xff;
-		  *cbuf++ = (left >> 8) & 0xff;
-		  *cbuf++ = right & 0xff;
-		  *cbuf++ = (right >> 8) & 0xff;
+		*cbuf++ = left & 0xff;
+		*cbuf++ = (left >> 8) & 0xff;
+		*cbuf++ = right & 0xff;
+		*cbuf++ = (right >> 8) & 0xff;
 #else
-		  *buf++ = left;
-		  *buf++ = right;
+		*buf++ = left;
+		*buf++ = right;
 #endif
-		  if (devc->control_counter++ >= devc->control_rate)
-		    {
-			    devc->control_counter = 0;
-			    softsyn_control_loop();
-		    }
-	  }			/* Mix one sample */
+		if (devc->control_counter++ >= devc->control_rate)
+		{
+			devc->control_counter = 0;
+			softsyn_control_loop();
+		}
+	}			/* Mix one sample */
 }
 #endif
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h
--- v2.1.93/linux/drivers/sound/sound_calls.h	Tue Mar 17 22:18:15 1998
+++ linux/drivers/sound/sound_calls.h	Wed Apr  8 17:24:48 1998
@@ -11,6 +11,7 @@
 int DMAbuf_move_wrpointer(int dev, int l);
 /* int DMAbuf_ioctl(int dev, unsigned int cmd, caddr_t arg, int local); */
 void DMAbuf_init(int dev, int dma1, int dma2);
+void DMAbuf_deinit(int dev);
 int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
 int DMAbuf_open_dma (int dev);
 void DMAbuf_close_dma (int dev);
@@ -83,15 +84,8 @@
 /*	From soundcard.c	*/
 void request_sound_timer (int count);
 void sound_stop_timer(void);
-/* These two are about to die.. */
-int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp, void *dev_id);
-void snd_release_irq(int vect, void *ptr);
-void sound_dma_malloc(int dev);
-void sound_dma_free(int dev);
 void conf_printf(char *name, struct address_info *hw_config);
 void conf_printf2(char *name, int base, int irq, int dma, int dma2);
-int ioctl_in(caddr_t arg);
-int ioctl_out(caddr_t arg, int result);
 
 /*	From opl3.c	*/
 int opl3_detect (int ioaddr, int *osp);
@@ -187,7 +181,7 @@
 #define AD_F_CS4231	0x0001	/* Returned if a CS4232 (or compatible) detected */
 #define AD_F_CS4248	0x0001	/* Returned if a CS4248 (or compatible) detected */
 
-void	 ad1848_control(int cmd, int arg);
+int	 ad1848_control(int cmd, int arg);
 #define		AD1848_SET_XTAL		1
 #define		AD1848_MIXER_REROUTE	2
 #define AD1848_REROUTE(oldctl, newctl) \
@@ -196,9 +190,6 @@
 void adintr(int irq, void *dev_id, struct pt_regs * dummy);
 void attach_ms_sound(struct address_info * hw_config);
 int probe_ms_sound(struct address_info *hw_config);
-void attach_pnp_ad1848(struct address_info * hw_config);
-int probe_pnp_ad1848(struct address_info *hw_config);
-void unload_pnp_ad1848(struct address_info *hw_info);
 
 /* 	From pss.c */
 int probe_pss (struct address_info *hw_config);
@@ -235,7 +226,6 @@
 int probe_mad16 (struct address_info *hw_config);
 void attach_mad16_mpu (struct address_info *hw_config);
 int probe_mad16_mpu (struct address_info *hw_config);
-int mad16_sb_dsp_detect (struct address_info *hw_config);
 
 /*	Unload routines from various source files*/
 void unload_pss(struct address_info *hw_info);
@@ -278,3 +268,7 @@
 int probe_v_midi (struct address_info *hw_config);
 void unload_v_midi (struct address_info *hw_config);
 
+/*	From vidc.c */
+void attach_vidc(struct address_info *hw_config);
+int probe_vidc(struct address_info *hw_config);
+void unload_vidc(struct address_info *hw_config);
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sound_firmware.c linux/drivers/sound/sound_firmware.c
--- v2.1.93/linux/drivers/sound/sound_firmware.c	Tue Mar 10 10:03:33 1998
+++ linux/drivers/sound/sound_firmware.c	Wed Apr  8 17:24:48 1998
@@ -1,3 +1,4 @@
+#include "os.h"
 #define __KERNEL_SYSCALLS__
 #include <linux/fs.h>
 #include <linux/mm.h>
@@ -19,14 +20,14 @@
 		return 0;
 	}
 	l = lseek(fd, 0L, 2);
-	if (l <= 0 || l > 65535)
+	if (l <= 0 || l > 131072)
 	{
 		printk(KERN_INFO "Invalid firmware '%s'\n", fn);
 		sys_close(fd);
-		  return 0;
+		return 0;
 	}
 	lseek(fd, 0L, 0);
-	dp = kmalloc(l, GFP_KERNEL);
+	dp = vmalloc(l);
 	if (dp == NULL)
 	{
 		printk(KERN_INFO "Out of memory loading '%s'.\n", fn);
@@ -36,7 +37,7 @@
 	if (read(fd, dp, l) != l)
 	{
 		printk(KERN_INFO "Failed to read '%s'.\n", fn);
-		kfree(dp);
+		vfree(dp);
 		sys_close(fd);
 		return 0;
 	}
@@ -45,7 +46,7 @@
 	return (int) l;
 }
 
-int  mod_firmware_load(const char *fn, char **fp)
+int mod_firmware_load(const char *fn, char **fp)
 {
 	int r;
 	mm_segment_t fs = get_fs();
@@ -55,3 +56,4 @@
 	set_fs(fs);
 	return r;
 }
+
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sound_syms.c linux/drivers/sound/sound_syms.c
--- v2.1.93/linux/drivers/sound/sound_syms.c	Mon Dec 29 10:22:46 1997
+++ linux/drivers/sound/sound_syms.c	Wed Apr  8 17:24:48 1998
@@ -1,6 +1,6 @@
 /*
- *    The sound core exports the following symbols to the rest of
- *      modulespace.
+ *	The sound core exports the following symbols to the rest of
+ *	modulespace.
  *
  *      (C) Copyright 1997      Alan Cox, Licensed under the GNU GPL
  */
@@ -9,6 +9,8 @@
 #include "sound_config.h"
 #define _MIDI_SYNTH_C_
 #include "midi_synth.h"
+#define _SEQUENCER_C_
+#include "tuning.h"
 #include <linux/notifier.h>
 #include "sound_firmware.h"
 
@@ -31,16 +33,13 @@
 EXPORT_SYMBOL(sound_install_mixer);
 EXPORT_SYMBOL(sound_alloc_dma);
 EXPORT_SYMBOL(sound_free_dma);
-EXPORT_SYMBOL(snd_set_irq_handler);
-EXPORT_SYMBOL(snd_release_irq);
+EXPORT_SYMBOL(sound_open_dma);
+EXPORT_SYMBOL(sound_close_dma);
 EXPORT_SYMBOL(sound_alloc_audiodev);
 EXPORT_SYMBOL(sound_alloc_mididev);
 EXPORT_SYMBOL(sound_alloc_mixerdev);
 EXPORT_SYMBOL(sound_alloc_timerdev);
 EXPORT_SYMBOL(sound_alloc_synthdev);
-EXPORT_SYMBOL(sound_mem_blocks);
-EXPORT_SYMBOL(sound_mem_sizes);
-EXPORT_SYMBOL(sound_nblocks);
 EXPORT_SYMBOL(sound_unload_audiodev);
 EXPORT_SYMBOL(sound_unload_mididev);
 EXPORT_SYMBOL(sound_unload_mixerdev);
@@ -90,3 +89,14 @@
 EXPORT_SYMBOL(midi_synth_bender);
 EXPORT_SYMBOL(midi_synth_load_patch);
 
+/* Firmware */
+
+EXPORT_SYMBOL(mod_firmware_load);
+
+/* Tuning */
+
+EXPORT_SYMBOL(cent_tuning);
+EXPORT_SYMBOL(semitone_tuning);
+
+MODULE_DESCRIPTION("Sound subsystem");
+MODULE_AUTHOR("Hannu Savolainen, et al.");
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.1.93/linux/drivers/sound/soundcard.c	Tue Mar 17 22:18:15 1998
+++ linux/drivers/sound/soundcard.c	Wed Apr  8 17:24:48 1998
@@ -16,8 +16,8 @@
  * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat,
  *                   which should disappear in the near future)
  */
-#include <linux/config.h>
 
+#include <linux/config.h>
 
 #include "sound_config.h"
 #include <linux/types.h>
@@ -28,6 +28,7 @@
 #include <linux/stddef.h>
 #include <linux/kmod.h>
 #ifdef __KERNEL__
+#include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <linux/wait.h>
@@ -48,6 +49,13 @@
 #define modular 0
 #endif
 
+/*
+ * This ought to be moved into include/asm/dma.h
+ */
+#ifndef valid_dma
+#define valid_dma(n) ((n) >= 0 && (n) < MAX_DMA_CHANNELS && (n) != 4)
+#endif
+
 static int      chrdev_registered = 0;
 static int      sound_major = SOUND_MAJOR;
 
@@ -57,12 +65,11 @@
  * Table for permanently allocated memory (used when unloading the module)
  */
 caddr_t         sound_mem_blocks[1024];
-int             sound_mem_sizes[1024];
 int             sound_nblocks = 0;
 
 static int      soundcard_configured = 0;
 
-static char     dma_alloc_map[8] =
+static char     dma_alloc_map[MAX_DMA_CHANNELS] =
 {0};
 
 #define DMA_MAP_UNAVAIL		0
@@ -788,31 +795,9 @@
 
 }
 
-static unsigned int irqs = 0;
-
-#ifdef MODULE
-static void
-free_all_irqs(void)
-{
-	int i;
-
-	for (i = 0; i < 31; i++)
-	{
-		if (irqs & (1ul << i))
-		{
-			printk(KERN_WARNING "Sound warning: IRQ%d was left allocated - fixed.\n", i);
-			snd_release_irq(i, NULL);
-		}
-	}
-	irqs = 0;
-}
-
-char            kernel_version[] = UTS_RELEASE;
-
-#endif
-
-static int      sound[20] =
-{0};
+static int      sound[20] = {
+	0
+};
 
 int init_module(void)
 {
@@ -876,10 +861,9 @@
 	}
 #endif
 	sound_unload_drivers();
-	free_all_irqs();	/* If something was left allocated by accident */
 	sequencer_unload();
 
-	for (i = 0; i < 8; i++)
+	for (i = 0; i < MAX_DMA_CHANNELS; i++)
 	{
 		if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
 		{
@@ -895,35 +879,6 @@
 }
 #endif
 
-int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp, void *dev_id)
-{
-	int retcode;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	retcode = request_irq(interrupt_level, iproc, 0, name, dev_id);
-	
-	if (retcode < 0)
-	{
-		printk(KERN_ERR "Sound: IRQ%d already in use\n", interrupt_level);
-	}
-	else
-		irqs |= (1ul << interrupt_level);
-
-	restore_flags(flags);
-	return retcode;
-}
-
-void snd_release_irq(int vect, void *dev_id)
-{
-	if (!(irqs & (1ul << vect)))
-		return;
-
-	irqs &= ~(1ul << vect);
-	free_irq(vect, dev_id);
-}
-
 int sound_alloc_dma(int chn, char *deviceID)
 {
 	int err;
@@ -940,7 +895,7 @@
 {
 	unsigned long   flags;
 
-	if (chn < 0 || chn > 7 || chn == 4)
+	if (!valid_dma(chn))
 	{
 		printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn);
 		return 1;
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v2.1.93/linux/drivers/sound/trix.c	Tue Feb 17 13:12:47 1998
+++ linux/drivers/sound/trix.c	Wed Apr  8 17:24:48 1998
@@ -3,14 +3,18 @@
  *
  * Low level driver for the MediaTrix AudioTrix Pro
  * (MT-0002-PC Control Chip)
- */
-/*
+ *
+ *
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
+ *
+ * Changes
+ *	Alan Cox		Modularisation, cleanup.
  */
+ 
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -35,30 +39,27 @@
 #endif
 
 
-static int      kilroy_was_here = 0;	/* Don't detect twice */
-static int      sb_initialized = 0;
-static int      mpu_initialized = 0;
+static int kilroy_was_here = 0;	/* Don't detect twice */
+static int sb_initialized = 0;
+static int mpu_initialized = 0;
 
-static int     *trix_osp = NULL;
+static int *trix_osp = NULL;
 
-static unsigned char
-trix_read(int addr)
+static unsigned char trix_read(int addr)
 {
 	outb(((unsigned char) addr), 0x390);	/* MT-0002-PC ASIC address */
 	return inb(0x391);	/* MT-0002-PC ASIC data */
 }
 
-static void
-trix_write(int addr, int data)
+static void trix_write(int addr, int data)
 {
 	outb(((unsigned char) addr), 0x390);	/* MT-0002-PC ASIC address */
 	outb(((unsigned char) data), 0x391);	/* MT-0002-PC ASIC data */
 }
 
-static void
-download_boot(int base)
+static void download_boot(int base)
 {
-	int             i = 0, n = trix_boot_len;
+	int i = 0, n = trix_boot_len;
 
 	if (trix_boot_len == 0)
 		return;
@@ -83,24 +84,23 @@
 
 }
 
-static int
-trix_set_wss_port(struct address_info *hw_config)
+static int trix_set_wss_port(struct address_info *hw_config)
 {
 	unsigned char   addr_bits;
 
 	if (check_region(0x390, 2))
-	  {
-		  printk(KERN_ERR "AudioTrix: Config port I/O conflict\n");
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "AudioTrix: Config port I/O conflict\n");
+		return 0;
+	}
 	if (kilroy_was_here)	/* Already initialized */
 		return 0;
 
 	if (trix_read(0x15) != 0x71)	/* No ASIC signature */
-	  {
-		  MDB(printk("No AudioTrix ASIC signature found\n"));
-		  return 0;
-	  }
+	{
+		MDB(printk(KERN_ERR "No AudioTrix ASIC signature found\n"));
+		return 0;
+	}
 	kilroy_was_here = 1;
 
 	/*
@@ -111,26 +111,26 @@
 	trix_write(0x14, 0);
 
 	/*
-	   * Configure the ASIC to place the codec to the proper I/O location
+	 * Configure the ASIC to place the codec to the proper I/O location
 	 */
 
 	switch (hw_config->io_base)
-	  {
-	  case 0x530:
-		  addr_bits = 0;
-		  break;
-	  case 0x604:
-		  addr_bits = 1;
-		  break;
-	  case 0xE80:
-		  addr_bits = 2;
-		  break;
-	  case 0xF40:
-		  addr_bits = 3;
-		  break;
-	  default:
-		  return 0;
-	  }
+	{
+		case 0x530:
+			addr_bits = 0;
+			break;
+		case 0x604:
+			addr_bits = 1;
+			break;
+		case 0xE80:
+			addr_bits = 2;
+			break;
+		case 0xF40:
+			addr_bits = 3;
+			break;
+		default:
+			return 0;
+	}
 
 	trix_write(0x19, (trix_read(0x19) & 0x03) | addr_bits);
 	return 1;
@@ -141,120 +141,123 @@
  *      AudioTrix Pro
  */
 
-int
-probe_trix_wss(struct address_info *hw_config)
+int probe_trix_wss(struct address_info *hw_config)
 {
-	int             ret;
+	int ret;
 
 	/*
-	   * Check if the IO port returns valid signature. The original MS Sound
-	   * system returns 0x04 while some cards (AudioTrix Pro for example)
-	   * return 0x00.
+	 * Check if the IO port returns valid signature. The original MS Sound
+	 * system returns 0x04 while some cards (AudioTrix Pro for example)
+	 * return 0x00.
 	 */
 	if (check_region(hw_config->io_base, 8))
-	  {
-		  printk("AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base);
+		return 0;
+	}
 	trix_osp = hw_config->osp;
 
 	if (!trix_set_wss_port(hw_config))
 		return 0;
 
 	if ((inb(hw_config->io_base + 3) & 0x3f) != 0x00)
-	  {
-		  MDB(printk("No MSS signature detected on port 0x%x\n", hw_config->io_base));
-		  return 0;
-	  }
+	{
+		MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x\n", hw_config->io_base));
+		return 0;
+	}
 	if (hw_config->irq > 11)
-	  {
-		  printk("AudioTrix: Bad WSS IRQ %d\n", hw_config->irq);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "AudioTrix: Bad WSS IRQ %d\n", hw_config->irq);
+		return 0;
+	}
 	if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
-	  {
-		  printk("AudioTrix: Bad WSS DMA %d\n", hw_config->dma);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "AudioTrix: Bad WSS DMA %d\n", hw_config->dma);
+		return 0;
+	}
 	if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
 		if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3)
-		  {
-			  printk("AudioTrix: Bad capture DMA %d\n", hw_config->dma2);
+		{
+			  printk(KERN_ERR "AudioTrix: Bad capture DMA %d\n", hw_config->dma2);
 			  return 0;
-		  }
+		}
 	/*
-	   * Check that DMA0 is not in use with a 8 bit board.
+	 * Check that DMA0 is not in use with a 8 bit board.
 	 */
 
 	if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80)
-	  {
-		  printk("AudioTrix: Can't use DMA0 with a 8 bit card slot\n");
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "AudioTrix: Can't use DMA0 with a 8 bit card slot\n");
+		return 0;
+	}
 	if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80)
-	  {
-		  printk("AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq);
+		return 0;
+	}
 	ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp);
 
 	if (ret)
-	  {
+	{
 #ifdef TRIX_ENABLE_JOYSTICK
-		  trix_write(0x15, 0x80);
+		trix_write(0x15, 0x80);
 #endif
-		  request_region(0x390, 2, "AudioTrix");
-	  }
+		request_region(0x390, 2, "AudioTrix");
+	}
 	return ret;
 }
 
 void
 attach_trix_wss(struct address_info *hw_config)
 {
-	static unsigned char interrupt_bits[12] =
-	{0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20};
-	char            bits;
-
-	static unsigned char dma_bits[4] =
-	{1, 2, 0, 3};
-
-	int             config_port = hw_config->io_base + 0;
-	int             dma1 = hw_config->dma, dma2 = hw_config->dma2;
-	int             old_num_mixers = num_mixers;
+	static unsigned char interrupt_bits[12] = {
+		0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20
+	};
+	char bits;
+
+	static unsigned char dma_bits[4] = {
+		1, 2, 0, 3
+	};
+
+	int config_port = hw_config->io_base + 0;
+	int dma1 = hw_config->dma, dma2 = hw_config->dma2;
+	int old_num_mixers = num_mixers;
 
 	trix_osp = hw_config->osp;
 
 	if (!kilroy_was_here)
-	  {
-		  DDB(printk("AudioTrix: Attach called but not probed yet???\n"));
-		  return;
-	  }
+	{
+		DDB(printk("AudioTrix: Attach called but not probed yet???\n"));
+		return;
+	}
+	
 	/*
-	   * Set the IRQ and DMA addresses.
+	 * Set the IRQ and DMA addresses.
 	 */
 
 	bits = interrupt_bits[hw_config->irq];
 	if (bits == 0)
-	  {
-		  printk("AudioTrix: Bad IRQ (%d)\n", hw_config->irq);
-		  return;
-	  }
+	{
+		printk("AudioTrix: Bad IRQ (%d)\n", hw_config->irq);
+		return;
+	}
 	outb((bits | 0x40), config_port);
 
 	if (hw_config->dma2 == -1 || hw_config->dma2 == hw_config->dma)
-	  {
+	{
 		  bits |= dma_bits[dma1];
 		  dma2 = dma1;
-	} else
-	  {
-		  unsigned char   tmp;
-
-		  tmp = trix_read(0x13) & ~30;
-		  trix_write(0x13, tmp | 0x80 | (dma1 << 4));
-
-		  tmp = trix_read(0x14) & ~30;
-		  trix_write(0x14, tmp | 0x80 | (dma2 << 4));
-	  }
+	}
+	else
+	{
+		unsigned char tmp;
+
+		tmp = trix_read(0x13) & ~30;
+		trix_write(0x13, tmp | 0x80 | (dma1 << 4));
+
+		tmp = trix_read(0x14) & ~30;
+		trix_write(0x14, tmp | 0x80 | (dma2 << 4));
+	}
 
 	outb((bits), config_port);	/* Write IRQ+DMA setup */
 
@@ -267,22 +270,22 @@
 	request_region(hw_config->io_base, 4, "MSS config");
 
 	if (num_mixers > old_num_mixers)	/* Mixer got installed */
-	  {
-		  AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);	/* Line in */
-		  AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
-		  AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH);		/* OPL4 */
-		  AD1848_REROUTE(SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM);	/* SB */
-	  }
-}
-
-int
-probe_trix_sb(struct address_info *hw_config)
-{
-
-	int             tmp;
-	unsigned char   conf;
-	static char     irq_translate[] =
-	{-1, -1, -1, 0, 1, 2, -1, 3};
+	{
+		AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);	/* Line in */
+		AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
+		AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH);		/* OPL4 */
+		AD1848_REROUTE(SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM);	/* SB */
+	}
+}
+
+int probe_trix_sb(struct address_info *hw_config)
+{
+
+	int tmp;
+	unsigned char conf;
+	static char irq_translate[] = {
+		-1, -1, -1, 0, 1, 2, -1, 3
+	};
 
 	if (trix_boot_len == 0)
 		return 0;	/* No boot code -> no fun */
@@ -294,10 +297,10 @@
 		return 0;
 
 	if (check_region(hw_config->io_base, 16))
-	  {
-		  printk("AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base);
+		return 0;
+	}
 	if ((hw_config->io_base & 0xffffff8f) != 0x200)
 		return 0;
 
@@ -329,11 +332,10 @@
 #endif
 }
 
-void
-attach_trix_sb(struct address_info *hw_config)
+void attach_trix_sb(struct address_info *hw_config)
 {
-	extern int      sb_be_quiet;
-	int             old_quiet;
+	extern int sb_be_quiet;
+	int old_quiet;
 
 #ifdef CONFIG_SBDSP
 	hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING;
@@ -348,8 +350,7 @@
 #endif
 }
 
-void
-attach_trix_mpu(struct address_info *hw_config)
+void attach_trix_mpu(struct address_info *hw_config)
 {
 #if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
 	hw_config->name = "AudioTrix Pro";
@@ -357,78 +358,74 @@
 #endif
 }
 
-int
-probe_trix_mpu(struct address_info *hw_config)
+int probe_trix_mpu(struct address_info *hw_config)
 {
 #ifdef DO_MIDI
-	unsigned char   conf;
-	static char     irq_bits[] =
-	{-1, -1, -1, 1, 2, 3, -1, 4, -1, 5};
+	unsigned char conf;
+	static char irq_bits[] = {
+		-1, -1, -1, 1, 2, 3, -1, 4, -1, 5
+	};
 
 	if (!kilroy_was_here)
-	  {
-		  DDB(printk("Trix: WSS and SB modes must be initialized before MPU\n"));
-		  return 0;	/* AudioTrix Pro has not been detected earlier */
-	  }
+	{
+		DDB(printk("Trix: WSS and SB modes must be initialized before MPU\n"));
+		return 0;	/* AudioTrix Pro has not been detected earlier */
+	}
 	if (!sb_initialized)
-	  {
-		  DDB(printk("Trix: SB mode must be initialized before MPU\n"));
-		  return 0;
-	  }
+	{
+		DDB(printk("Trix: SB mode must be initialized before MPU\n"));
+		return 0;
+	}
 	if (mpu_initialized)
-	  {
-		  DDB(printk("Trix: MPU mode already initialized\n"));
-		  return 0;
-	  }
+	{
+		DDB(printk("Trix: MPU mode already initialized\n"));
+		return 0;
+	}
 	if (check_region(hw_config->io_base, 4))
-	  {
-		  printk("AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base);
+		return 0;
+	}
 	if (hw_config->irq > 9)
-	  {
-		  printk("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq);
+		return 0;
+	}
 	if (irq_bits[hw_config->irq] == -1)
-	  {
-		  printk("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq);
-		  return 0;
-	  }
+	{
+		printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq);
+		return 0;
+	}
 	switch (hw_config->io_base)
-	  {
-	  case 0x330:
-		  conf = 0x00;
-		  break;
-	  case 0x370:
-		  conf = 0x04;
-		  break;
-	  case 0x3b0:
-		  conf = 0x08;
-		  break;
-	  case 0x3f0:
-		  conf = 0x0c;
-		  break;
-	  default:
-		  return 0;	/* Invalid port */
-	  }
+	{
+		case 0x330:
+			conf = 0x00;
+			break;
+		case 0x370:
+			conf = 0x04;
+			break;
+		case 0x3b0:
+			conf = 0x08;
+			break;
+		case 0x3f0:
+			conf = 0x0c;
+			break;
+		default:
+			return 0;	/* Invalid port */
+	}
 
 	conf |= irq_bits[hw_config->irq] << 4;
-
 	trix_write(0x19, (trix_read(0x19) & 0x83) | conf);
-
 	mpu_initialized = 1;
-
 	return probe_uart401(hw_config);
 #else
 	return 0;
 #endif
 }
 
-void
-unload_trix_wss(struct address_info *hw_config)
+void unload_trix_wss(struct address_info *hw_config)
 {
-	int             dma2 = hw_config->dma2;
+	int dma2 = hw_config->dma2;
 
 	if (dma2 == -1)
 		dma2 = hw_config->dma;
@@ -444,15 +441,14 @@
 	sound_unload_audiodev(hw_config->slots[0]);
 }
 
-void
-unload_trix_mpu(struct address_info *hw_config)
+void unload_trix_mpu(struct address_info *hw_config)
 {
 #ifdef DO_MIDI
 	unload_uart401(hw_config);
 #endif
 }
-void
-unload_trix_sb(struct address_info *hw_config)
+
+void unload_trix_sb(struct address_info *hw_config)
 {
 #ifdef CONFIG_SBDSP
 	sb_dsp_unload(hw_config);
@@ -473,6 +469,18 @@
 int             mpu_io = -1;
 int             mpu_irq = -1;
 
+EXPORT_NO_SYMBOLS;
+
+MODULE_PARM(io,"i");
+MODULE_PARM(irq,"i");
+MODULE_PARM(dma,"i");
+MODULE_PARM(dma2,"i");
+MODULE_PARM(sb_io,"i");
+MODULE_PARM(sb_dma,"i");
+MODULE_PARM(sb_irq,"i");
+MODULE_PARM(mpu_io,"i");
+MODULE_PARM(mpu_irq,"i");
+
 struct address_info config;
 struct address_info sb_config;
 struct address_info mpu_config;
@@ -482,16 +490,15 @@
 
 static int      fw_load;
 
-int 
-init_module(void)
+int init_module(void)
 {
-	printk("MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
+	printk(KERN_INFO "MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
 
 	if (io == -1 || dma == -1 || irq == -1)
-	  {
-		  printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n");
-		  return -EINVAL;
-	  }
+	{
+		printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n");
+		return -EINVAL;
+	}
 	config.io_base = io;
 	config.irq = irq;
 	config.dma = dma;
@@ -505,21 +512,21 @@
 	mpu_config.irq = mpu_irq;
 
 	if (sb_io != -1 && (sb_irq == -1 || sb_dma == -1))
-	  {
-		  printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n");
-		  return -EINVAL;
-	  }
+	{
+		printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n");
+		return -EINVAL;
+	}
 	if (mpu_io != -1 && mpu_irq == -1)
-	  {
-		  printk(KERN_INFO "CONFIG_MPU_IRQ must be specified if MPU_IO is set.\n");
-		  return -EINVAL;
-	  }
+	{
+		printk(KERN_INFO "CONFIG_MPU_IRQ must be specified if MPU_IO is set.\n");
+		return -EINVAL;
+	}
 	if (!trix_boot)
-	  {
-		  fw_load = 1;
-		  trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin",
+	{
+		fw_load = 1;
+		trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin",
 						    (char **) &trix_boot);
-	  }
+	}
 	if (!probe_trix_wss(&config))
 		return -ENODEV;
 	attach_trix_wss(&config);
@@ -530,26 +537,26 @@
 	 */
 
 	if (sb_io != -1)
-	  {
-		  sb = probe_trix_sb(&sb_config);
-		  if (sb)
-			  attach_trix_sb(&sb_config);
-	  }
+	{
+		sb = probe_trix_sb(&sb_config);
+		if (sb)
+			attach_trix_sb(&sb_config);
+	}
+	
 	if (mpu_io != -1)
-	  {
-		  mpu = probe_trix_mpu(&mpu_config);
-		  if (mpu)
-			  attach_trix_mpu(&mpu_config);
-	  }
+	{
+		mpu = probe_trix_mpu(&mpu_config);
+		if (mpu)
+			attach_trix_mpu(&mpu_config);
+	}
 	SOUND_LOCK;
 	return 0;
 }
 
-void 
-cleanup_module(void)
+void cleanup_module(void)
 {
 	if (fw_load && trix_boot)
-		kfree(trix_boot);
+		vfree(trix_boot);
 	if (sb)
 		unload_trix_sb(&sb_config);
 	if (mpu)
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c
--- v2.1.93/linux/drivers/sound/uart401.c	Tue Mar 17 22:18:15 1998
+++ linux/drivers/sound/uart401.c	Wed Apr  8 17:24:48 1998
@@ -12,7 +12,8 @@
  *
  * Changes:
  *	Alan Cox	Reformatted, removed sound_mem usage, use normal Linux
- *			interrupt allocation.
+ *			interrupt allocation. Protect against bogus unload
+ *			Fixed to allow IRQ > 15
  *
  * Status:
  *		Untested
@@ -244,6 +245,7 @@
 	uart401_devc *devc;
 	char *name = "MPU-401 (UART) MIDI";
 
+	
 	if (hw_config->name)
 		name = hw_config->name;
 
@@ -269,12 +271,6 @@
 	else
 		devc->share_irq = 0;
 
-	if (devc->irq < 1 || devc->irq > 15)
-	{
-		kfree(devc);
-		return;
-	}
-
 	if (!devc->share_irq)
 	{
 		if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0)
@@ -345,6 +341,7 @@
 		for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
 		devc->input_byte = 0;
 		uart401_cmd(devc, MPU_RESET);
+
 		/*
 		 * Wait at least 25 msec. This method is not accurate so let's make the
 		 * loop bit longer. Cannot sleep since this is called during boot.
@@ -387,6 +384,8 @@
 
 	DDB(printk("Entered probe_uart401()\n"));
 
+	/* Default to "not found" */
+	hw_config->slots[4] = -1;
 	detected_devc = NULL;
 
 	if (check_region(hw_config->io_base, 4))
@@ -415,6 +414,14 @@
 void unload_uart401(struct address_info *hw_config)
 {
 	uart401_devc *devc;
+	int n=hw_config->slots[4];
+	
+	/* Not set up */
+	if(n==-1 || midi_devs[n]==NULL)
+		return;
+		
+	/* Not allocated (erm ??) */
+	
 	devc = midi_devs[hw_config->slots[4]]->devc;
 	if (devc == NULL)
 		return;
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c
--- v2.1.93/linux/drivers/sound/uart6850.c	Tue Mar 17 22:18:15 1998
+++ linux/drivers/sound/uart6850.c	Wed Apr  8 17:24:48 1998
@@ -325,6 +325,8 @@
 MODULE_PARM(io,"i");
 MODULE_PARM(irq,"i");
 
+EXPORT_NO_SYMBOLS;
+
 struct address_info cfg;
 
 int init_module(void)
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c
--- v2.1.93/linux/drivers/sound/vidc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/vidc.c	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,83 @@
+/*
+ *	drivers/sound/vidc.c
+ *
+ *	Detection routine for the VIDC.
+ *
+ *	Copyright (C) 1997 by Russell King <rmk@arm.uk.linux.org>
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include "sound_config.h"
+
+#include "vidc.h"
+
+int vidc_busy;
+
+void vidc_update_filler(int bits, int channels)
+{
+	int filltype;
+
+	filltype = bits + channels;
+	switch (filltype)
+	{
+		default:
+		case 9:
+			vidc_filler = vidc_fill_1x8;
+			break;
+		case 10:
+			vidc_filler = vidc_fill_2x8;
+			break;
+		case 17:
+			vidc_filler = vidc_fill_1x16;
+			break;
+		case 18:
+			vidc_filler = vidc_fill_2x16;
+			break;
+	}
+}
+
+void attach_vidc(struct address_info *hw_config)
+{
+	char name[32];
+	int i;
+
+	sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype);
+	conf_printf(name, hw_config);
+
+	for (i = 0; i < 2; i++)
+	{
+		dma_buf[i] = get_free_page(GFP_KERNEL);
+		dma_pbuf[i] = virt_to_phys(dma_buf[i]);
+	}
+
+	if (sound_alloc_dma(hw_config->dma, "VIDCsound"))
+	{
+		printk(KERN_ERR "VIDCsound: can't allocate virtual DMA channel\n");
+		return;
+	}
+	if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, "VIDCsound", NULL))
+	{
+		printk(KERN_ERR "VIDCsound: can't allocate DMA interrupt\n");
+		return;
+	}
+	vidc_synth_init(hw_config);
+	vidc_audio_init(hw_config);
+	vidc_mixer_init(hw_config);
+}
+
+int probe_vidc(struct address_info *hw_config)
+{
+	hw_config->irq = IRQ_DMAS0;
+	hw_config->dma = DMA_VIRTUAL_SOUND;
+	hw_config->dma2 = -1;
+	hw_config->card_subtype = 16;
+	return 1;
+}
+
+void unload_vidc(struct address_info *hw_config)
+{
+	free_irq(hw_config->irq, NULL);
+	sound_free_dma(hw_config->dma);
+}
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc.h linux/drivers/sound/vidc.h
--- v2.1.93/linux/drivers/sound/vidc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/vidc.h	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,68 @@
+/*
+ * drivers/sound/vidc.h
+ *
+ * VIDC sound function prototypes
+ *
+ * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
+ */
+
+/* vidc.c */
+
+extern int vidc_busy;
+
+/* vidc_fill.S */
+
+/*
+ * Filler routines for different channels and sample sizes
+ */
+
+extern unsigned long vidc_fill_1x8(unsigned long ibuf, unsigned long iend,
+				   unsigned long obuf, int mask);
+extern unsigned long vidc_fill_2x8(unsigned long ibuf, unsigned long iend,
+				   unsigned long obuf, int mask);
+extern unsigned long vidc_fill_1x16(unsigned long ibuf, unsigned long iend,
+				    unsigned long obuf, int mask);
+extern unsigned long vidc_fill_2x16(unsigned long ibuf, unsigned long iend,
+				    unsigned long obuf, int mask);
+
+/*
+ * DMA Interrupt handler
+ */
+
+extern void vidc_sound_dma_irq(int irqnr, void *ref, struct pt_regs *regs);
+
+/*
+ * Filler routine pointer
+ */
+
+extern unsigned long (*vidc_filler) (unsigned long ibuf, unsigned long iend,
+				     unsigned long obuf, int mask);
+
+/*
+ * Virtual DMA buffer exhausted
+ */
+
+extern void     (*dma_interrupt) (void);
+
+/*
+ * Virtual DMA buffer addresses
+ */
+
+extern unsigned long dma_start, dma_count, dma_bufsize;
+extern unsigned long dma_buf[2], dma_pbuf[2];
+
+/* vidc_audio.c */
+
+extern void     vidc_audio_init(struct address_info *hw_config);
+extern int      vidc_audio_get_volume(void);
+extern int      vidc_audio_set_volume(int vol);
+
+/* vidc_mixer.c */
+
+extern void     vidc_mixer_init(struct address_info *hw_config);
+
+/* vidc_synth.c */
+
+extern void     vidc_synth_init(struct address_info *hw_config);
+extern int      vidc_synth_get_volume(void);
+extern int      vidc_synth_set_volume(int vol);
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc_audio.c linux/drivers/sound/vidc_audio.c
--- v2.1.93/linux/drivers/sound/vidc_audio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/vidc_audio.c	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,322 @@
+/*
+ * drivers/sound/vidc_audio.c
+ *
+ * Audio routines for the VIDC
+ *
+ * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
+ */
+
+#include <linux/config.h>
+#include "sound_config.h"
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include "vidc.h"
+
+/*
+ * VIDC sound
+ *
+ * When using SERIAL SOUND mode (external DAC), the number of physical
+ * channels is fixed at 2.  Therefore, the sample rate = vidc sample rate.
+ */
+
+static int      vidc_adev;
+
+static int      vidc_audio_volume;
+static int      vidc_audio_rate;
+static char     vidc_audio_bits;
+static char     vidc_audio_channels;
+
+extern void     vidc_update_filler(int bits, int channels);
+
+int  vidc_audio_get_volume(void)
+{
+	return vidc_audio_volume;
+}
+
+int vidc_audio_set_volume(int newvol)
+{
+	vidc_audio_volume = newvol;
+	return vidc_audio_volume;
+}
+
+static int vidc_audio_set_bits(int bits)
+{
+	switch (bits)
+	{
+		case AFMT_QUERY:
+			break;
+		case AFMT_U8:
+		case AFMT_S16_LE:
+			vidc_audio_bits = bits;
+			vidc_update_filler(vidc_audio_bits, vidc_audio_channels);
+			break;
+		default:
+			vidc_audio_bits = 16;
+			vidc_update_filler(vidc_audio_bits, vidc_audio_channels);
+			break;
+	}
+	return vidc_audio_bits;
+}
+
+static int vidc_audio_set_rate(int rate)
+{
+	if (rate)
+	{
+		int newsize, new2size;
+
+		vidc_audio_rate = ((500000 / rate) + 1) >> 1;
+		if (vidc_audio_rate < 3)
+			vidc_audio_rate = 3;
+		if (vidc_audio_rate > 255)
+			vidc_audio_rate = 255;
+		outl((vidc_audio_rate - 2) | 0xb0000000, VIDC_BASE);
+		outl(0xb1000003, VIDC_BASE);
+		newsize = (10000 / vidc_audio_rate) & ~3;
+		if (newsize < 208)
+			newsize = 208;
+		if (newsize > 4096)
+			newsize = 4096;
+		for (new2size = 128; new2size < newsize; new2size <<= 1);
+			if (new2size - newsize > newsize - (new2size >> 1))
+				new2size >>= 1;
+		dma_bufsize = new2size;
+	}
+	return 250000 / vidc_audio_rate;
+}
+
+static int vidc_audio_set_channels(int channels)
+{
+	switch (channels)
+	{
+		case 0:
+			break;
+		case 1:
+		case 2:
+			vidc_audio_channels = channels;
+			vidc_update_filler(vidc_audio_bits, vidc_audio_channels);
+			break;
+		default:
+			vidc_audio_channels = 2;
+			vidc_update_filler(vidc_audio_bits, vidc_audio_channels);
+			break;
+	}
+	return vidc_audio_channels;
+}
+
+/*
+ * Open the device
+ *
+ * dev  - device
+ * mode - mode to open device (logical OR of OPEN_READ and OPEN_WRITE)
+ *
+ * Called when opening the DMAbuf               (dmabuf.c:259)
+ */
+
+static int vidc_audio_open(int dev, int mode)
+{
+	if (vidc_busy)
+		return -EBUSY;
+
+	if ((mode & OPEN_READ) && (!mode & OPEN_WRITE))
+	{
+		/* This audio device doesn't have recording capability */
+		return -EIO;
+	}
+	vidc_busy = 1;
+	return 0;
+}
+
+/*
+ * Close the device
+ *
+ * dev  - device
+ *
+ * Called when closing the DMAbuf               (dmabuf.c:477)
+ *      after halt_xfer
+ */
+
+static void vidc_audio_close(int dev)
+{
+	vidc_busy = 0;
+}
+
+static int vidc_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+	int ret;
+
+	switch (cmd)
+	{
+		case SOUND_PCM_WRITE_RATE:
+			if (get_user(ret, (int *) arg))
+				return -EFAULT;
+			ret = vidc_audio_set_rate(ret);
+			break;
+
+		case SOUND_PCM_READ_RATE:
+			ret = vidc_audio_set_rate(0);
+			break;
+
+		case SNDCTL_DSP_STEREO:
+			if (get_user(ret, (int *) arg))
+				return -EFAULT;
+			ret = vidc_audio_set_channels(ret + 1) - 1;
+			break;
+
+		case SOUND_PCM_WRITE_CHANNELS:
+			if (get_user(ret, (int *) arg))
+				return -EFAULT;
+			ret = vidc_audio_set_channels(ret);
+			break;
+
+		case SOUND_PCM_READ_CHANNELS:
+			ret = vidc_audio_set_channels(0);
+			break;
+
+		case SNDCTL_DSP_SETFMT:
+			if (get_user(ret, (int *) arg))
+				return -EFAULT;
+			ret = vidc_audio_set_bits(ret);
+			break;
+
+		case SOUND_PCM_READ_BITS:
+			ret = vidc_audio_set_bits(0);
+			break;
+
+		case SOUND_PCM_WRITE_FILTER:
+		case SOUND_PCM_READ_FILTER:
+			return -EINVAL;
+
+		default:
+			return -EINVAL;
+	}
+	return put_user(ret, (int *) arg);
+}
+
+/*
+ * Output a block via DMA to sound device
+ *
+ * dev          - device number
+ * buf          - physical address of buffer
+ * total_count  - total byte count in buffer
+ * intrflag     - set if this has been called from an interrupt (via DMAbuf_outputintr)
+ * restart_dma  - set if DMA needs to be re-initialised
+ *
+ * Called when:
+ *  1. Starting output                                  (dmabuf.c:1327)
+ *  2.                                                  (dmabuf.c:1504)
+ *  3. A new buffer needs to be sent to the device      (dmabuf.c:1579)
+ */
+ 
+static void vidc_audio_dma_interrupt(void)
+{
+	DMAbuf_outputintr(vidc_adev, 1);
+}
+
+static void vidc_audio_output_block(int dev, unsigned long buf, int total_count,
+			int intrflag)
+{
+	dma_start = buf;
+	dma_count = total_count;
+
+	if (!intrflag)
+	{
+		dma_interrupt = vidc_audio_dma_interrupt;
+		vidc_sound_dma_irq(0, NULL, NULL);
+		outb(DMA_CR_D | DMA_CR_E, IOMD_SD0CR);
+	}
+}
+
+static void vidc_audio_start_input(int dev, unsigned long buf, int count,
+		       int intrflag)
+{
+}
+
+static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount)
+{
+	return -EINVAL;
+}
+
+/*
+ * Prepare for outputting samples to `dev'
+ *
+ * Each buffer that will be passed will be `bsize' bytes long,
+ * with a total of `bcount' buffers.
+ *
+ * Called when:
+ *  1. A trigger enables audio output                   (dmabuf.c:978)
+ *  2. We get a write buffer without dma_mode setup     (dmabuf.c:1152)
+ *  3. We restart a transfer                            (dmabuf.c:1324)
+ */
+
+static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount)
+{
+	return 0;
+}
+
+static void vidc_audio_reset(int dev)
+{
+}
+
+/*
+ * Halt a DMA transfer to `dev'
+ *
+ * Called when:
+ *  1. We close the DMAbuf                                      (dmabuf.c:476)
+ *  2. We run out of output buffers to output to the device.    (dmabuf.c:1456)
+ *  3. We run out of output buffers and we're closing down.     (dmabuf.c:1546)
+ *  4. We run out of input buffers in AUTOMODE.                 (dmabuf.c:1651)
+ */
+ 
+static void vidc_audio_halt_xfer(int dev)
+{
+	dma_count = 0;
+}
+
+static int vidc_audio_local_qlen(int dev)
+{
+	return dma_count != 0;
+}
+
+static struct audio_driver vidc_audio_driver =
+{
+	vidc_audio_open,		/* open                 */
+	vidc_audio_close,		/* close                */
+	vidc_audio_output_block,	/* output_block         */
+	vidc_audio_start_input,		/* start_input          */
+	vidc_audio_ioctl,		/* ioctl                */
+	vidc_audio_prepare_for_input,	/* prepare_for_input    */
+	vidc_audio_prepare_for_output,	/* prepare_for_output   */
+	vidc_audio_reset,		/* reset                */
+	vidc_audio_halt_xfer,		/* halt_xfer            */
+	vidc_audio_local_qlen,		/*+local_qlen           */
+	NULL,				/*+copy_from_user       */
+	NULL,				/*+halt_input           */
+	NULL,				/*+halt_output          */
+	NULL,				/*+trigger              */
+	NULL,				/*+set_speed            */
+	NULL,				/*+set_bits             */
+	NULL,				/*+set_channels         */
+};
+
+static struct audio_operations vidc_audio_operations =
+{
+	"VIDCsound",
+	0,
+	AFMT_U8 | AFMT_S16_LE,
+	NULL,
+	&vidc_audio_driver
+};
+
+void vidc_audio_init(struct address_info *hw_config)
+{
+	vidc_audio_volume = 100 | (100 << 8);
+	if ((vidc_adev = sound_alloc_audiodev())!=-1)
+	{
+		audio_devs[vidc_adev] = &vidc_audio_operations;
+		audio_devs[vidc_adev]->min_fragment = 10;	/* 1024 bytes => 64 buffers */
+		audio_devs[vidc_adev]->mixer_dev = num_mixers;
+		audio_devs[vidc_adev]->flags |= 0;
+	}
+	else printk(KERN_ERR "VIDCsound: Too many PCM devices available\n");
+}
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc_fill.S linux/drivers/sound/vidc_fill.S
--- v2.1.93/linux/drivers/sound/vidc_fill.S	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/vidc_fill.S	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,184 @@
+/*
+ * sound/vidc_fill.S
+ *
+ * Filler routines for DMA buffers
+ *
+ * Copyright (C) 1997 Russell King
+ */
+#define __ASSEMBLY__
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+
+		.text
+
+ENTRY(vidc_fill_1x8)
+		mov	ip, #0xff00
+1:		cmp	r0, r1
+		bge	SYMBOL_NAME(vidc_clear)
+		ldrb	r4, [r0], #1
+		and	r4, ip, r4, lsl #8
+		orr	r4, r4, r4, lsl #16
+		str	r4, [r2], #4
+		cmp	r2, r3
+		blt	1b
+		mov	pc, lr
+
+ENTRY(vidc_fill_2x8)
+		mov	ip, #0xff00
+1:		cmp	r0, r1
+		bge	SYMBOL_NAME(vidc_clear)
+		ldr	r4, [r0], #2
+		and	r5, r4, ip
+		and	r4, ip, r4, lsl #8
+		orr	r4, r4, r5, lsl #16
+		orr	r4, r4, r4, lsr #8
+		str	r4, [r2], #4
+		cmp	r2, r3
+		blt	1b
+		mov	pc, lr
+
+ENTRY(vidc_fill_1x16)
+		mov	ip, #0xff00
+		orr	ip, ip, ip, lsr #8
+1:		cmp	r0, r1
+		bge	SYMBOL_NAME(vidc_clear)
+		ldr	r5, [r0], #2
+		and	r4, r5, ip
+		orr	r4, r4, r4, lsl #16
+		str	r4, [r2], #4
+		cmp	r0, r1
+		addlt	r0, r0, #2
+		andlt	r4, r5, ip, lsl #16
+		orrlt	r4, r4, r4, lsr #16
+		strlt	r4, [r2], #4
+		cmp	r2, r3
+		blt	1b
+		mov	pc, lr
+
+ENTRY(vidc_fill_2x16)
+		mov	ip, #0xff00
+		orr	ip, ip, ip, lsr #8
+1:		cmp	r0, r1
+		bge	SYMBOL_NAME(vidc_clear)
+		ldr	r4, [r0], #4
+		str	r4, [r2], #4
+		cmp	r0, r1
+		ldrlt	r4, [r0], #4
+		strlt	r4, [r2], #4
+		cmp	r2, r3
+		blt	1b
+		mov	pc, lr
+
+ENTRY(vidc_fill_noaudio)
+		mov	r0, #0
+		mov	r1, #0
+2:		mov	r4, #0
+		mov	r5, #0
+1:		cmp	r2, r3
+		stmltia	r2!, {r0, r1, r4, r5}
+		blt	1b
+		mov	pc, lr
+
+ENTRY(vidc_clear)
+		mov	r0, #0
+		mov	r1, #0
+		tst	r2, #4
+		str	r0, [r2], #4
+		tst	r2, #8
+		stmia	r2!, {r0, r1}
+		b	2b
+
+/*
+ * Call filler routines with:
+ *  r0 = phys address
+ *  r1 = phys end
+ *  r2 = buffer
+ * Returns:
+ *  r0 = new buffer address
+ *  r2 = new buffer finish
+ *  r4 = corrupted
+ *  r5 = corrupted
+ *  ip = corrupted
+ */
+
+ENTRY(vidc_sound_dma_irq)
+		stmfd	sp!, {r4 - r9, lr}
+		ldr	r9, =SYMBOL_NAME(dma_start)
+		ldmia	r9, {r0, r1, r2, r3, r4, r5}
+		teq	r1, #0
+		adreq	r4, SYMBOL_NAME(vidc_fill_noaudio)
+		moveq	r8, #1 << 31
+		movne	r8, #0
+		mov	ip, #IOMD_BASE & 0xff000000
+		orr	ip, ip, #IOMD_BASE & 0x00ff0000
+		ldrb	r7, [ip, #IOMD_SD0ST]
+		tst	r7, #DMA_ST_OFL			@ Check for overrun
+		eorne	r7, r7, #DMA_ST_AB
+		tst	r7, #DMA_ST_AB
+		moveq	r2, r3				@ DMAing A, update B
+		add	r3, r2, r5			@ End of DMA buffer
+		add	r1, r1, r0			@ End of virtual DMA buffer
+		mov	lr, pc
+		mov	pc, r4				@ Call fill routine
+		sub	r1, r1, r0			@ Remaining length
+		stmia	r9, {r0, r1}
+		mov	r0, #0
+		tst	r2, #4				@ Round buffer up to 4 words
+		strne	r0, [r2], #4
+		tst	r2, #8
+		strne	r0, [r2], #4
+		strne	r0, [r2], #4
+		sub	r2, r2, #16
+		mov	r2, r2, lsl #20
+		movs	r2, r2, lsr #20
+		orreq	r2, r2, #1 << 30		@ Set L bit
+		orr	r2, r2, r8
+		ldmdb	r9, {r3, r4, r5}
+		tst	r7, #DMA_ST_AB
+		mov	ip, #IOMD_BASE & 0xff000000
+		orr	ip, ip, #IOMD_BASE & 0x00ff0000
+		streq	r4, [ip, #IOMD_SD0CURB]
+		strne	r5, [ip, #IOMD_SD0CURA]
+		streq	r2, [ip, #IOMD_SD0ENDB]
+		strne	r2, [ip, #IOMD_SD0ENDA]
+		ldr	r6, [ip, #IOMD_SD0ST]
+		tst	r6, #DMA_ST_OFL
+		bne	1f
+		tst	r7, #DMA_ST_AB
+		strne	r4, [ip, #IOMD_SD0CURB]
+		streq	r5, [ip, #IOMD_SD0CURA]
+		strne	r2, [ip, #IOMD_SD0ENDB]
+		streq	r2, [ip, #IOMD_SD0ENDA]
+1:		teq	r8, #0
+		mov	r0, #0x10
+		strneb	r0, [ip, #IOMD_SD0CR]
+		teqeq	r1, #0
+		ldmfd	sp!, {r4 - r9, lr}
+		moveq	pc, r3				@ Call interrupt routine
+		mov	pc, lr
+
+		.data
+		.globl	SYMBOL_NAME(dma_interrupt)
+SYMBOL_NAME(dma_interrupt):
+		.long	0
+		.globl	SYMBOL_NAME(dma_pbuf)
+SYMBOL_NAME(dma_pbuf):
+		.long	0
+		.long	0
+		.globl	SYMBOL_NAME(dma_start)
+SYMBOL_NAME(dma_start):
+		.long	0
+		.globl	SYMBOL_NAME(dma_count)
+SYMBOL_NAME(dma_count):
+		.long	0
+		.globl	SYMBOL_NAME(dma_buf)
+SYMBOL_NAME(dma_buf):
+		.long	0
+		.long	0
+		.globl	SYMBOL_NAME(vidc_filler)
+SYMBOL_NAME(vidc_filler):
+		.long	SYMBOL_NAME(vidc_fill_noaudio)
+		.globl	SYMBOL_NAME(dma_bufsize)
+SYMBOL_NAME(dma_bufsize):
+		.long	0x1000
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc_mixer.c linux/drivers/sound/vidc_mixer.c
--- v2.1.93/linux/drivers/sound/vidc_mixer.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/vidc_mixer.c	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,151 @@
+/*
+ * drivers/sound/vidc_mixer.c
+ *
+ * Mixer routines for VIDC
+ *
+ * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
+ */
+
+#include <linux/config.h>
+#include "sound_config.h"
+
+#include "vidc.h"
+
+int vidc_volume;
+
+static int vidc_get_volume(void)
+{
+	return vidc_volume;
+}
+
+static int vidc_set_volume(int newvol)
+{
+	vidc_volume = newvol;
+/*  printk ("vidc_set_volume: %X\n", newvol); */
+	return newvol;
+}
+
+static int vidc_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+	int ret;
+
+	switch (cmd)
+	{
+		case SOUND_MIXER_READ_VOLUME:
+			ret = vidc_get_volume();
+			break;
+
+		case SOUND_MIXER_WRITE_VOLUME:
+			if (get_user(ret, (int *) arg))
+				return -EINVAL;
+			ret = vidc_set_volume(ret);
+			break;
+
+		case SOUND_MIXER_READ_BASS:
+		case SOUND_MIXER_WRITE_BASS:
+		case SOUND_MIXER_READ_TREBLE:
+		case SOUND_MIXER_WRITE_TREBLE:
+			ret = 50;
+			break;
+
+		case SOUND_MIXER_READ_SYNTH:
+			ret = vidc_synth_get_volume();
+			break;
+
+		case SOUND_MIXER_WRITE_SYNTH:
+			if (get_user(ret, (int *) arg))
+				return -EINVAL;
+			ret = vidc_synth_set_volume(ret);
+			break;
+
+		case SOUND_MIXER_READ_PCM:
+			ret = vidc_audio_get_volume();
+			break;
+
+		case SOUND_MIXER_WRITE_PCM:
+			if (get_user(ret, (int *) arg))
+				return -EINVAL;
+			ret = vidc_audio_set_volume(ret);
+			break;
+
+		case SOUND_MIXER_READ_SPEAKER:
+			ret = 100;
+			break;
+
+		case SOUND_MIXER_WRITE_SPEAKER:
+			ret = 100;
+			break;
+
+		case SOUND_MIXER_READ_LINE:
+		case SOUND_MIXER_WRITE_LINE:
+		case SOUND_MIXER_READ_MIC:
+		case SOUND_MIXER_WRITE_MIC:
+			ret = 0;
+			break;
+
+		case SOUND_MIXER_READ_CD:
+		case SOUND_MIXER_WRITE_CD:
+			ret = 100 | (100 << 8);
+			break;
+
+		case SOUND_MIXER_READ_IMIX:
+		case SOUND_MIXER_WRITE_IMIX:
+		case SOUND_MIXER_READ_ALTPCM:
+		case SOUND_MIXER_WRITE_ALTPCM:
+		case SOUND_MIXER_READ_LINE1:
+		case SOUND_MIXER_WRITE_LINE1:
+		case SOUND_MIXER_READ_LINE2:
+		case SOUND_MIXER_WRITE_LINE2:
+		case SOUND_MIXER_READ_LINE3:
+		case SOUND_MIXER_WRITE_LINE3:
+			ret = 0;
+			break;
+
+		case SOUND_MIXER_READ_RECSRC:
+			ret = 0;
+			break;
+
+		case SOUND_MIXER_WRITE_RECSRC:
+			return -EINVAL;
+			break;
+
+		case SOUND_MIXER_READ_DEVMASK:
+			ret = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH;
+			break;
+
+		case SOUND_MIXER_READ_RECMASK:
+			ret = 0;
+			break;
+
+		case SOUND_MIXER_READ_STEREODEVS:
+			ret = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH;
+			break;
+
+		case SOUND_MIXER_READ_CAPS:
+			ret = 0;
+			break;
+
+		case SOUND_MIXER_READ_MUTE:
+			return -EINVAL;
+			break;
+
+		default:
+			return -EINVAL;
+			break;
+	}
+	return put_user(ret, (int *) arg);
+}
+
+static struct mixer_operations vidc_mixer_operations = {
+	"VIDC",
+	"VIDCsound",
+	vidc_default_mixer_ioctl	/* ioctl                */
+};
+
+void vidc_mixer_init(struct address_info *hw_config)
+{
+	int vidc_mixer = sound_alloc_mixerdev();
+	vidc_volume = 100 | (100 << 8);
+	if (num_mixers < MAX_MIXER_DEV)
+		mixer_devs[vidc_mixer] = &vidc_mixer_operations;
+}
diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc_synth.c linux/drivers/sound/vidc_synth.c
--- v2.1.93/linux/drivers/sound/vidc_synth.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/vidc_synth.c	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,90 @@
+/*
+ * drivers/sound/vidc_synth.c
+ *
+ * Synthesizer routines for the VIDC
+ *
+ * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
+ */
+#include <linux/config.h>
+#include "sound_config.h"
+
+#include "vidc.h"
+
+static struct synth_info vidc_info =
+{
+	"VIDCsound",		/* name                 */
+	0,			/* device               */
+	SYNTH_TYPE_SAMPLE,	/* synth_type           */
+	0,			/* synth_subtype        */
+	0,			/* perc_mode            */
+	16,			/* nr_voices            */
+	0,			/* nr_drums             */
+	0,			/* instr_bank_size      */
+	0,			/* capabilities         */
+};
+
+int             vidc_sdev;
+int             vidc_synth_volume;
+
+static int vidc_synth_open(int dev, int mode)
+{
+	if (vidc_busy)
+		return -EBUSY;
+
+	vidc_busy = 1;
+	return 0;
+}
+
+static void vidc_synth_close(int dev)
+{
+	vidc_busy = 0;
+}
+
+
+static struct synth_operations vidc_synth_operations =
+{
+	&vidc_info,		/* info                 */
+	0,			/* midi_dev             */
+	SYNTH_TYPE_SAMPLE,	/* synth_type           */
+				/*SAMPLE_TYPE_XXX */ 0,
+				/* SAMPLE_TYPE GUS *//* synth_subtype                */
+	vidc_synth_open,	/* open                 */
+	vidc_synth_close,	/* close                */
+	NULL,			/* ioctl                */
+	NULL,			/* kill_note            */
+	NULL,			/* start_note           */
+	NULL,			/* set_instr            */
+	NULL,			/* reset                */
+	NULL,			/* hw_control           */
+	NULL,			/* load_patch           */
+	NULL,			/* aftertouch           */
+	NULL,			/* controller           */
+	NULL,			/* panning              */
+	NULL,			/* volume_method        */
+	NULL,			/* patchmgr             */
+	NULL,			/* bender               */
+	NULL,			/* alloc                */
+	NULL,			/* setup_voice          */
+	NULL,			/* send_sysex           */
+				/* alloc                */
+				/* chn_info[16]         */
+};
+
+int  vidc_synth_get_volume(void)
+{
+	return vidc_synth_volume;
+}
+
+int vidc_synth_set_volume(int newvol)
+{
+	return vidc_synth_volume = newvol;
+}
+
+void vidc_synth_init(struct address_info *hw_config)
+{
+	vidc_synth_volume = 100 | (100 << 8);
+	if ((vidc_sdev=sound_alloc_synthdev())!=-1)
+		synth_devs[vidc_sdev] = &vidc_synth_operations;
+	else
+		printk(KERN_ERR "VIDCsound: Too many synthesizers\n");
+}
diff -u --recursive --new-file v2.1.93/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c
--- v2.1.93/linux/drivers/video/cyberfb.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/cyberfb.c	Tue Apr  7 07:52:04 1998
@@ -20,7 +20,7 @@
  * for more details.
  */
 
-
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-afb.c linux/drivers/video/fbcon-afb.c
--- v2.1.93/linux/drivers/video/fbcon-afb.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/fbcon-afb.c	Tue Apr  7 07:52:04 1998
@@ -13,7 +13,6 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/fb.h>
 
 #include "fbcon.h"
diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb16.c linux/drivers/video/fbcon-cfb16.c
--- v2.1.93/linux/drivers/video/fbcon-cfb16.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/fbcon-cfb16.c	Tue Apr  7 07:52:04 1998
@@ -13,7 +13,6 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/fb.h>
 
 #include "fbcon.h"
diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb2.c linux/drivers/video/fbcon-cfb2.c
--- v2.1.93/linux/drivers/video/fbcon-cfb2.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/fbcon-cfb2.c	Tue Apr  7 07:52:04 1998
@@ -14,7 +14,6 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/fb.h>
 
 #include "fbcon.h"
diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb24.c linux/drivers/video/fbcon-cfb24.c
--- v2.1.93/linux/drivers/video/fbcon-cfb24.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/fbcon-cfb24.c	Tue Apr  7 07:52:04 1998
@@ -13,7 +13,6 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/fb.h>
 
 #include "fbcon.h"
diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb32.c linux/drivers/video/fbcon-cfb32.c
--- v2.1.93/linux/drivers/video/fbcon-cfb32.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/fbcon-cfb32.c	Tue Apr  7 07:52:04 1998
@@ -13,7 +13,6 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/fb.h>
 
 #include "fbcon.h"
diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb4.c linux/drivers/video/fbcon-cfb4.c
--- v2.1.93/linux/drivers/video/fbcon-cfb4.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/fbcon-cfb4.c	Tue Apr  7 07:52:04 1998
@@ -14,7 +14,6 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/fb.h>
 
 #include "fbcon.h"
diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb8.c linux/drivers/video/fbcon-cfb8.c
--- v2.1.93/linux/drivers/video/fbcon-cfb8.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/fbcon-cfb8.c	Tue Apr  7 07:52:05 1998
@@ -13,7 +13,6 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/fb.h>
 
 #include "fbcon.h"
diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-mac.c linux/drivers/video/fbcon-mac.c
--- v2.1.93/linux/drivers/video/fbcon-mac.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/fbcon-mac.c	Tue Apr  7 07:52:05 1998
@@ -16,7 +16,6 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/fb.h>
 #include <linux/delay.h>
 
diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-mfb.c linux/drivers/video/fbcon-mfb.c
--- v2.1.93/linux/drivers/video/fbcon-mfb.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/fbcon-mfb.c	Tue Apr  7 07:52:05 1998
@@ -13,7 +13,6 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
-#include <linux/config.h>
 #include <linux/fb.h>
 
 #include "fbcon.h"
diff -u --recursive --new-file v2.1.93/linux/drivers/video/skeletonfb.c linux/drivers/video/skeletonfb.c
--- v2.1.93/linux/drivers/video/skeletonfb.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/skeletonfb.c	Tue Apr  7 07:52:05 1998
@@ -8,6 +8,7 @@
  * for more details.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.93/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.93/linux/fs/buffer.c	Wed Apr  1 20:11:53 1998
+++ linux/fs/buffer.c	Mon Apr  6 17:48:34 1998
@@ -1335,6 +1335,8 @@
 			atomic_read(&nr_async_pages));
 #endif
 	}
+	if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
+		swap_after_unlock_page(page->offset);
 	if (test_and_clear_bit(PG_free_after, &page->flags))
 		__free_page(page);
 }
diff -u --recursive --new-file v2.1.93/linux/fs/devpts/root.c linux/fs/devpts/root.c
--- v2.1.93/linux/fs/devpts/root.c	Mon Apr  6 17:41:00 1998
+++ linux/fs/devpts/root.c	Tue Apr  7 08:05:05 1998
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/param.h>
+#include <linux/string.h>
 #include "devpts_i.h"
 
 static int devpts_root_readdir(struct file *,void *,filldir_t);
diff -u --recursive --new-file v2.1.93/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v2.1.93/linux/fs/ext2/file.c	Mon Apr  6 17:41:00 1998
+++ linux/fs/ext2/file.c	Wed Apr  8 11:36:53 1998
@@ -205,21 +205,23 @@
 			return -EFBIG;
 	}
 #else
-	off_t max = ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)];
+	{
+		off_t max = ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)];
 
-	if (pos + count > max) {
-		count = max - pos;
-		if (!count)
-			return -EFBIG;
-	}
-	if (((pos + count) >> 32) && 
-	    !(sb->u.ext2_sb.s_es->s_feature_ro_compat &
-	      cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) {
-		/* If this is the first large file created, add a flag
-		   to the superblock */
-		sb->u.ext2_sb.s_es->s_feature_ro_compat |=
-			cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
-		mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+		if (pos + count > max) {
+			count = max - pos;
+			if (!count)
+				return -EFBIG;
+		}
+		if (((pos + count) >> 32) && 
+		    !(sb->u.ext2_sb.s_es->s_feature_ro_compat &
+		      cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) {
+			/* If this is the first large file created, add a flag
+			   to the superblock */
+			sb->u.ext2_sb.s_es->s_feature_ro_compat |=
+				cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
+			mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+		}
 	}
 #endif
 
diff -u --recursive --new-file v2.1.93/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.1.93/linux/fs/sysv/inode.c	Mon Apr  6 17:41:01 1998
+++ linux/fs/sysv/inode.c	Tue Apr  7 07:22:23 1998
@@ -495,7 +495,7 @@
 	if (!sb->s_root) {
 		printk("SysV FS: get root inode failed\n");
 		sysv_put_super(sb);
-		sb->sb_dev = 0;
+		sb->s_dev = 0;
 		unlock_super(sb);
 		return NULL;
 	}
diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/README-WIP.txt linux/fs/umsdos/README-WIP.txt
--- v2.1.93/linux/fs/umsdos/README-WIP.txt	Tue Mar 17 22:18:15 1998
+++ linux/fs/umsdos/README-WIP.txt	Wed Apr  8 11:39:46 1998
@@ -8,7 +8,7 @@
 YOU'VE BEEN WARNED.
 --------- WARNING --------- WARNING --------- WARNING -----------
 
-Current status (980220) - UMSDOS dentry-WIP-Beta 0.82-1:
+Current status (980220) - UMSDOS dentry-WIP-Beta 0.82-3:
 
 (1) pure MSDOS (no --linux-.--- EMD file):
 
@@ -19,7 +19,7 @@
 - creat file - works
 - write file - works
 - mkdir - works
-- rmdir - questionable. probable problem on non-empty dirs.
+- rmdir - QUESTIONABLE. probable problem on non-empty dirs.
 
 Notes: possible very minor problems with dentry/inode/... kernel structures (very rare)
 
@@ -42,28 +42,29 @@
 - other ioctls - MOSTLY UNTESTED
 - dangling symlink - UNTESTED !
 
-- create symlink		- works on short names, but fails (gets
-				  truncated on long ones) (also
-				  due to some dentries problems, it may not
-				  be visible right away always - eg. before
-				  umount/mount)
+- create symlink		- seems to work both on short & long names now !
 - create hardlink		- WARNING: NOT FIXED YET!
-- create file			- creates short names, but probs with long ones ?
-- create special file		- seems to work on short names.
-- write to file			- seems to work on short names.
+- create file			- seems to work both on short & long names now !
+- create special file		- seems to work both on short & long names now !
+- write to file			- seems to work both on short & long names now !
 - rename file (same dir)	- WARNING: NOT FIXED YET!
 - rename file (dif. dir)	- WARNING: NOT FIXED YET!
 - rename dir (same dir)		- WARNING: NOT FIXED YET!
 - rename dir (dif. dir)		- WARNING: NOT FIXED YET!
-- delete file			- WARNING: NOT FIXED YET!
+- delete file			- seems to work fully now!
 - notify_change (chown,perms)	- seems to work!
 - delete hardlink		- WARNING: NOT FIXED YET!
-- mkdir				- seems to work, even with long names ! (but
-				  due to some dentries problems, it may not
-				  be visible right away always - eg. before
-				  umount/mount)
+- mkdir				- seems to work both on short & long names now !
 - rmdir 			- WARNING: NOT FIXED YET!
-- umssyncing			- does something :-), but NEEDS EXTENSIVE TESTING
+- umssyncing			- seems to work, but NEEDS EXTENSIVE TESTING
+
+- CVF-FAT stuff (compressed DOS filesystem) - there is some support from
+  Frank Gockel <gockel@sent13.uni-duisburg.de> to use it even under
+  umsdosfs. But I have no way of testing it -- please let me know if there
+  are problems that are specific to umsdos (eg. it works under msdosfs, but
+  not under umsdosfs)
+
+
 
 Notes: moderate dentry/inode kernel structures trashing. Probably some other
 kernel structures compromised. Have SysRq support compiled in, and use
@@ -77,16 +78,18 @@
 is supposed to be fixed enough to work, but I haven't got the time to test
 it.
 
-Note4: on failure of creating of long filenames: MSDOS filename gets
-created, and EMD entry gets created. Check: either they mismatch, or EMD
-entry contains some wrong flags.
-
-Note5: rmdir(2) probably fails because do_rmdir calls lock_parent, which
-uses dentry->d_parent, which we neglect to set, so it returns -ENOENT.
-Probably same problem on unlink(2) ? What to do ? How to set
-dentry->d_parent to something useful ?? Must I recurse down whole pathname
-and set one by one all directory components ?! or only last one is really
-needed ? help !
+Note5: rmdir(2) fails with EBUSY - sdir->i_count > 1 (like 7 ??). It must be
+some error with dir->i_count++, or something related to iput() ? See if
+number changes if we access the dir in different ways..
+
+Note6: there is problem with unmounting umsdosfs, it seems to stay
+registered or something. Remounting same device on any mount point with
+different fstype (like msdos or vfat) ignores fstype and umsdosfs kicks back
+in. 
+
+Note7: also we screwed umount(2)-ing the fs at times (EBUSY), by removing
+all those iput/dput's. When rest of code is fixed, we'll put them back at
+(hopefully) correct places.
 
 ------------------------------------------------------------------------------
 
@@ -110,10 +113,10 @@
 dput them ?
 
 I'm unfortunatelly somewhat out of time to read linux-kernel, but I do check
-for any messages having UMSDOS in subject, and read them. I should reply to
-any direct Email in few days. If I don't - probably I never got your
-message. You can try mnalis@open.hr or mnalis@voyager.hr; however
-mnalis@jagor.srce.hr is preferable one.
+for any messages having UMSDOS in subject, and read them. I might miss it in
+all that volume, though. I should reply to any direct Email in few days. If
+I don't - probably I never got your message. You can try mnalis@open.hr or
+mnalis@voyager.hr; however mnalis@jagor.srce.hr is preferable one.
 
 
 ------------------------------------------------------------------------------
@@ -122,7 +125,7 @@
 + hardlinks/symlinks. test with files in not_the_same_dir
 - also test not_the_same_dir for other file operations like rename etc.
 - iput: device 00:00 inode 318 still has aliases! problem. Check in iput()
-  for device 0,0. Probably null pointer passed arount when it shouldn't be ?
+  for device 0,0. Probably null pointer passed around when it shouldn't be ?
 - dput/iput problem...
 - what about .dotfiles ? working ? multiple dots ? etc....
 - fix stuff like dir->i_count++ to atomic_inc(&dir->i_count) and simular?
@@ -133,11 +136,23 @@
 
 - when should dput()/iput() be used ?!!
 
-- probably problem with filename mangling somewhere, since both create and
-  write to file work on short filenames, but fail on long ones. Path
-  components may be of any size (eg. mkfifo /mnt/Very_long_dir2/blah1 will
-  succeed, but mkfifo /mnt/very_long_filename.txt won't)
-
-
 - what is dir->i_count++ ? locking directory ? should this be lock_parent or
 something ?
+
+- i_binary=2 is for CVF (compressed filesystem).
+
+- SECURITY WARNING: short dentries should be invalidated, or they could be
+  accessed instead of proper long names.
+
+- as for iput() : (my only pointer so far. anyone else ?)
+
+>development I only know about iput. All functions that get an inode as
+>argument and don't return it have to call iput on it before exit, i.e. when
+>it is no longer needed and the code returns to vfs layer. The rest is quite
+>new to me, but it might be similar for dput. Typical side effect of a
+>missing iput was a memory runout (but no crash). You also couldn't unmount
+>the filesystem later though no process was using it. On the other hand, one
+>iput too much lead to serious pointer corruption and crashed the system
+>very soon. I used to look at the FAT filesystem and copy those pieces of
+>
+> Frank
diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.1.93/linux/fs/umsdos/dir.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/umsdos/dir.c	Wed Apr  8 11:39:46 1998
@@ -36,7 +36,7 @@
   int rv;
   struct dentry *dentry;
 
-  dentry = creat_dentry (name, len, NULL);
+  dentry = creat_dentry (name, len, NULL, NULL);
   rv = umsdos_real_lookup(dir,dentry);
   if (inode) *inode = dentry->d_inode;
   kill_dentry (dentry);
@@ -50,7 +50,7 @@
   int rv;
   struct dentry *dentry;
 
-  dentry = creat_dentry (name, len, NULL);
+  dentry = creat_dentry (name, len, NULL, NULL);
   rv = msdos_create(dir,dentry,mode);
   if(inode != NULL) *inode = dentry->d_inode;
   
@@ -270,10 +270,10 @@
 	      }
 	      Printk (("Trouve ino %ld ",inode->i_ino));
 	      if (u_entry != NULL) *u_entry = entry;
-	      iput (inode);
+	      /* iput (inode); FIXME */
 	      break;
 	    }
-	    iput (inode);
+	    /* iput (inode); FIXME */
 	  }else{
 	    /* #Specification: umsdos / readdir / not in MSDOS
 	       During a readdir operation, if the file is not
@@ -295,7 +295,7 @@
 	the special offset.
       */
       if (filp->f_pos == 0) filp->f_pos = start_fpos;
-      iput(emd_dir);
+      /* iput(emd_dir); FIXME */
     }
   }
   umsdos_endlookup(dir);	
@@ -530,7 +530,7 @@
     ret = 0;
   }else{
     struct inode *emddir = umsdos_emd_dir_lookup(dir,0);
-    iput (emddir);
+    /* iput (emddir); FIXME */
     if (emddir == NULL){
       /* This is a DOS directory */
       struct UMSDOS_DIR_SEARCH bufk;
@@ -639,7 +639,7 @@
       while (dir != root_inode){
 	struct inode *adir;
 	ret = umsdos_locate_ancestor (dir,&adir,&entry);
-	iput (dir);
+	/* iput (dir); FIXME */
 	dir = NULL;
 	Printk (("ancestor %d ",ret));
 	if (ret == 0){
@@ -657,7 +657,7 @@
     kfree (bpath);
   }
   Printk (("\n"));
-  iput (dir);
+  /* iput (dir); FIXME */
   return ret;
 }
 
@@ -697,12 +697,16 @@
   struct inode *pseudo_root_inode=NULL;
   int len = dentry->d_name.len;
   const char *name = dentry->d_name.name;
+  
+  Printk ((KERN_DEBUG "umsdos_lookup_x: /mn/ name=%.*s, dir=%lu, d_parent=%p\n", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino, dentry->d_parent));	/* FIXME /mn/ debug only */
+  if (dentry->d_parent) Printk ((KERN_DEBUG "   d_parent is %.*s\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name)); /* FIXME : delme /mn/ */
+  
   root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO);
   /*	pseudo_root_inode = iget( ... ) ? */
   dentry->d_inode = NULL;
-  umsdos_startlookup(dir);	
+  umsdos_startlookup(dir);
   if (len == 1 && name[0] == '.'){
-    dentry->d_inode = dir;
+    d_add (dentry, dir);
     dir->i_count++;
     ret = 0;
   }else if (len == 2 && name[0] == '.' && name[1] == '.'){
@@ -713,7 +717,7 @@
 	 pseudo root is returned.
       */
       ret = 0;
-      dentry->d_inode = pseudo_root;
+      d_add (dentry, pseudo_root);
       pseudo_root->i_count++;
     }else{
       /* #Specification: locating .. / strategy
@@ -735,7 +739,7 @@
 	struct inode *aadir;
 	struct umsdos_dirent entry;
 	ret = umsdos_locate_ancestor (dentry->d_inode,&aadir,&entry);
-	iput (aadir);
+	/* iput (aadir); FIXME */
       }
     }
   }else if (umsdos_is_pseudodos(dir,dentry)){
@@ -743,7 +747,7 @@
        A lookup of DOS in the pseudo root will always succeed
        and return the inode of the real root.
     */
-    dentry->d_inode = root_inode;
+    d_add (dentry, root_inode);
     (dentry->d_inode)->i_count++;
     ret = 0;
   }else{
@@ -776,7 +780,7 @@
         Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", inode->i_ino));
 
         /* we've found it. now get inode and put it in dentry. Is this ok /mn/ ? */
-        dentry->d_inode = iget(dir->i_sb, inode->i_ino);
+        d_add (dentry, iget(dir->i_sb, inode->i_ino));
         
 	umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
 	Printk (("lookup ino %ld flags %d\n",inode->i_ino
@@ -796,7 +800,7 @@
 	    mode.
 	  */
 	  Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n"));
-	  iput (pseudo_root);
+	  /* iput (pseudo_root); FIXME */
 	  dentry->d_inode = NULL;
 	  ret = -ENOENT;
 	}
@@ -804,7 +808,7 @@
     }
   }
   umsdos_endlookup(dir);	
-  iput (dir);
+  /* iput (dir); FIXME */
   Printk ((KERN_DEBUG "umsdos_lookup_x: returning %d\n", ret));
   return ret;
 }
@@ -858,7 +862,7 @@
   *result = NULL;
   if (path == NULL){
     ret = -ENOMEM;
-    iput (hlink);
+    /* iput (hlink); FIXME */
   }else{
     struct file filp;
     loff_t offs = 0;
@@ -866,7 +870,7 @@
     fill_new_filp (&filp, NULL);
       
 
-    dentry_src = creat_dentry ("hlink-mn", 8, hlink);
+    dentry_src = creat_dentry ("hlink-mn", 8, hlink, NULL);
 
     memset (&filp, 0, sizeof (filp));
 
@@ -894,7 +898,7 @@
 	    if (*pt == '/') *pt++ = '\0';
 	    /* FIXME. /mn/ fixed ? */
 
-            dentry_dst = creat_dentry (start, len, NULL);
+            dentry_dst = creat_dentry (start, len, NULL, NULL);
 
 	    if (dir->u.umsdos_i.i_emd_dir == 0){
 	      /* This is a DOS directory */
@@ -917,7 +921,7 @@
 	  }
       }else{
 	  Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n"));
-	  iput (hlink); /* FIXME */
+	  /* iput (hlink); / * FIXME */
       }
     Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, *result));
     kfree (path);
diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c
--- v2.1.93/linux/fs/umsdos/emd.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/umsdos/emd.c	Wed Apr  8 11:39:46 1998
@@ -52,9 +52,11 @@
  *
  */
  
-struct dentry *creat_dentry (const char *name, const int len, struct inode *inode)
+struct dentry *creat_dentry (const char *name, const int len, struct inode *inode, struct dentry *parent)
 {
-    struct dentry *ret, *parent=NULL;	/* FIXME /mn/: whatis parent ?? */
+/* FIXME /mn/: parent is not passed many times... if it is not, dentry should be destroyed before someone else gets to use it */
+
+    struct dentry *ret;
     struct qstr qname;
     
     if (inode)
@@ -71,10 +73,10 @@
 
     if (inode) d_add (ret, inode);
       
-/*    ret->d_inode = inode; /mn/ FIXME this was old, replaced by d_add, delete this ! */
     return ret;
 }
 
+
 /*
  * removes temporary dentry created by creat_dentry
  *
@@ -123,7 +125,7 @@
     set_fs (KERNEL_DS);
 
     old_dentry=filp->f_dentry;	/* save it */
-    filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir);
+    filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, NULL);
     *offs = filp->f_pos;
     
     PRINTK ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
@@ -138,6 +140,7 @@
     PRINTK ((KERN_DEBUG "  f_version=%ld\n", filp->f_version));
     PRINTK ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
 
+    MSDOS_I(filp->f_dentry->d_inode)->i_binary=2;
     ret = fat_file_read(filp,buf,count,offs);
     PRINTK ((KERN_DEBUG "fat_file_read returned with %d!\n", ret));
 
@@ -195,21 +198,28 @@
 	
 	set_fs (KERNEL_DS);
 
-        Printk ((KERN_ERR "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
-        Printk ((KERN_ERR "  struct dentry=%p\n", filp->f_dentry));
-        Printk ((KERN_ERR "  struct inode=%p\n", filp->f_dentry->d_inode));
-        Printk ((KERN_ERR "  inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
-        Printk ((KERN_ERR "  ofs=%ld\n",(unsigned long) *offs));
-        Printk ((KERN_ERR "  f_pos=%Lu\n", filp->f_pos));
-        Printk ((KERN_ERR "  name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
-        Printk ((KERN_ERR "  i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary ));
-        Printk ((KERN_ERR "  f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
-        Printk ((KERN_ERR "  f_owner=%d\n", filp->f_owner.uid));
-        Printk ((KERN_ERR "  f_version=%ld\n", filp->f_version));
-        Printk ((KERN_ERR "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
+        Printk ((KERN_DEBUG "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
+        Printk ((KERN_DEBUG "  struct dentry=%p\n", filp->f_dentry));
+        Printk ((KERN_DEBUG "  struct inode=%p\n", filp->f_dentry->d_inode));
+        Printk ((KERN_DEBUG "  inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
+        Printk ((KERN_DEBUG "  ofs=%ld\n",(unsigned long) *offs));
+        Printk ((KERN_DEBUG "  f_pos=%Lu\n", filp->f_pos));
+        Printk ((KERN_DEBUG "  name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
+        Printk ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary ));
+        Printk ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
+        Printk ((KERN_DEBUG "  f_owner=%d\n", filp->f_owner.uid));
+        Printk ((KERN_DEBUG "  f_version=%ld\n", filp->f_version));
+        Printk ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
+
+	/* note: i_binary=2 is for CVF-FAT. We put it here, instead of
+	   umsdos_file_write_kmem, since it is also wise not to compress symlinks
+	   (in unlikely event that they are > 512 bytes and can be compressed 
+	   FIXME: should we set it when reading symlink too ? */
 
+        MSDOS_I(filp->f_dentry->d_inode)->i_binary=2;
+        
 	ret = fat_file_write (filp, buf, count, offs);
-	PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret));
+	PRINTK ((KERN_DEBUG "fat_file_write returned with %ld!\n", ret));
 
 	set_fs (old_fs);
 	return ret;
@@ -231,11 +241,11 @@
 	struct dentry *old_dentry;
 
 	
-	Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n"));
-        Printk ((KERN_ERR "  using emd=%ld\n", emd_dir->i_ino));
+	Printk ((KERN_DEBUG " STARTED WRITE_KMEM /mn/\n"));
+        Printk ((KERN_DEBUG "  using emd=%ld\n", emd_dir->i_ino));
 
 	old_dentry=filp->f_dentry;	/* save it */
-	filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir);
+	filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, NULL);
 
 	*offs = filp->f_pos;	/* FIXME, in read_kmem also: offs is not used so why pass it ?!!! /mn/ */
 
@@ -500,7 +510,7 @@
         fill_new_filp (&filp, NULL);
 
 	Printk (("umsdos_writeentry /mn/: entering...\n"));
-	emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir);
+	emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir, NULL);
 	
 	if (free_entry){
 		/* #Specification: EMD file / empty entries
@@ -650,7 +660,7 @@
 
 		memset (&buf.filp, 0, sizeof (buf.filp));
 
-		dentry = creat_dentry ("umsfind-mn", 10, emd_dir);
+		dentry = creat_dentry ("umsfind-mn", 10, emd_dir, NULL);
 	
 		fill_new_filp (&buf.filp, dentry);
 
@@ -743,7 +753,7 @@
 		ret = umsdos_writeentry(dir,emd_dir,info,0);
 		Printk (("umsdos_newentry EMD ret = %d\n",ret));
 	}
-	iput (emd_dir);
+	/* iput (emd_dir); FIXME */
 	return ret;
 }
 
@@ -760,7 +770,7 @@
 	umsdos_parse ("..LINK",6,info);
 	info->entry.name_len = 0;
 	ret = umsdos_find (dir,info,&emd_dir);
-	iput (emd_dir);
+	/* iput (emd_dir); FIXME */
 	if (ret == -ENOENT || ret == 0){
 		/* #Specification: hard link / hidden name
 			When a hard link is created, the original file is renamed
@@ -799,7 +809,7 @@
 			}
 		}
 	}
-	iput(emd_dir);
+	/* iput(emd_dir); FIXME */
 	return ret;
 }
 
@@ -824,7 +834,7 @@
 		/* Find an empty slot */
 		memset (&filp, 0, sizeof (filp));
 
-		dentry = creat_dentry ("isempty-mn", 10, dir);
+		dentry = creat_dentry ("isempty-mn", 10, dir, NULL);
 	
 		filp.f_pos = 0;
 		filp.f_reada = 1;
@@ -843,7 +853,7 @@
 				break;
 			}	
 		}
-		iput (emd_dir);
+		/* iput (emd_dir); FIXME */
 	}
 	return ret;
 }
@@ -870,7 +880,7 @@
 			}
 		}
 	}
-	iput (emd_dir);
+	/* iput (emd_dir); FIXME */
 	Printk (("umsdos_findentry: returning %d\n", ret));
 	return ret;
 }
diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/file.c linux/fs/umsdos/file.c
--- v2.1.93/linux/fs/umsdos/file.c	Tue Feb 17 13:12:48 1998
+++ linux/fs/umsdos/file.c	Wed Apr  8 11:39:46 1998
@@ -144,3 +144,38 @@
 	NULL,			/* smap */
 };
 
+/* For other with larger and unaligned file system with readpage */
+struct file_operations umsdos_file_operations_readpage = {
+	NULL,				/* lseek - default */
+	UMSDOS_file_read,		/* read */
+	UMSDOS_file_write,		/* write */
+	NULL,				/* readdir - bad */
+	NULL,				/* poll - default */
+	NULL,				/* ioctl - default */
+	generic_file_mmap,		/* mmap */
+	NULL,				/* no special open is needed */
+	NULL,				/* release */
+	file_fsync			/* fsync */
+};
+
+struct inode_operations umsdos_file_inode_operations_readpage = {
+	&umsdos_file_operations_readpage,	/* default file operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,                   /* follow link */
+	fat_readpage,		/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	UMSDOS_truncate,	/* truncate */
+	NULL,			/* permission */
+	NULL,			/* smap */
+};
+
diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.1.93/linux/fs/umsdos/inode.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/umsdos/inode.c	Wed Apr  8 11:39:46 1998
@@ -125,7 +125,7 @@
     Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino));
     inode->u.umsdos_i.i_dir_owner = dir->i_ino;
     inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
-    iput (emd_owner);
+    /* iput (emd_owner); FIXME */
     inode->u.umsdos_i.pos = f_pos;
 }
 
@@ -176,12 +176,22 @@
   if (!umsdos_isinit(inode)){
     inode->u.umsdos_i.i_emd_dir = 0;
     if (S_ISREG(inode->i_mode)){
-      if (inode->i_op->bmap != NULL){
-        Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n"));
-	inode->i_op = &umsdos_file_inode_operations;
-      }else{
-        Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
-	inode->i_op = &umsdos_file_inode_operations_no_bmap;
+       if (MSDOS_SB(inode->i_sb)->cvf_format){
+         if (MSDOS_SB(inode->i_sb)->cvf_format->flags&CVF_USE_READPAGE){
+           Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_readpage\n"));
+           inode->i_op = &umsdos_file_inode_operations_readpage;
+         }else{
+           Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
+           inode->i_op = &umsdos_file_inode_operations_no_bmap;
+         }
+       }else{      
+         if (inode->i_op->bmap != NULL){
+           Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n"));
+	   inode->i_op = &umsdos_file_inode_operations;
+         }else{
+           Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
+           inode->i_op = &umsdos_file_inode_operations_no_bmap;
+         }
       }
     }else if (S_ISDIR(inode->i_mode)){
       if (dir != NULL){
@@ -223,7 +233,7 @@
       struct inode *emd_owner;
       Printk ((KERN_WARNING "umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n"));
       emd_owner = umsdos_emd_dir_lookup(dir,1);
-      iput (emd_owner);
+      /* iput (emd_owner); FIXME */
       if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){
 	  printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld "
 		  ,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner);
@@ -323,7 +333,7 @@
 {
   int ret = 0;
   
-  Printk ((KERN_ERR "UMSDOS_notify_change: /mn/ completly untested\n"));
+  PRINTK ((KERN_DEBUG "UMSDOS_notify_change: entering\n"));
   
   if ((ret = inode_change_ok(inode, attr)) != 0)
     return ret;
@@ -366,7 +376,7 @@
 	struct dentry *emd_dentry;
 	loff_t offs;
 	
-	emd_dentry = creat_dentry ("notify_emd", 10, emd_owner);
+	emd_dentry = creat_dentry ("notify_emd", 10, emd_owner, NULL);
 	fill_new_filp (&filp, emd_dentry);
 	
 	filp.f_pos = inode->u.umsdos_i.pos;
@@ -403,7 +413,7 @@
 	     EMD file. The msdos fs is not even called.
 	  */
 	}
-	iput (emd_owner);
+	/* iput (emd_owner); FIXME */
       }
       Printk (("\n"));
     }
@@ -472,7 +482,7 @@
     PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n",sb));
     res = msdos_read_super(sb,data,silent);
     PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n",res));
-    printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-2 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE);
+    printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-3 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE);
 	  
     if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; }
 
@@ -480,7 +490,7 @@
     res->s_op = &umsdos_sops;
     Printk ((KERN_DEBUG "umsdos /mn/: here goes the iget ROOT_INO\n"));
 
-    pseudo = iget(res,UMSDOS_ROOT_INO); 		
+    pseudo = iget(res,UMSDOS_ROOT_INO);
     Printk ((KERN_DEBUG "umsdos_read_super %p\n",pseudo));
 
     umsdos_setup_dir_inode (pseudo);
@@ -521,8 +531,8 @@
       */
       struct dentry *root, *etc, *etc_rc, *init, *sbin;
 
-      root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL);
-      sbin = creat_dentry ("sbin", 4, NULL);
+      root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL, NULL);
+      sbin = creat_dentry ("sbin", 4, NULL, NULL);
       
       Printk ((KERN_DEBUG "Mounting root\n"));
       if (umsdos_real_lookup (pseudo,root)==0
@@ -531,7 +541,7 @@
 	
 	int pseudo_ok = 0;
 	Printk ((KERN_DEBUG "/%s is there\n",UMSDOS_PSDROOT_NAME));
-	etc = creat_dentry ("etc", 3, NULL);
+	etc = creat_dentry ("etc", 3, NULL, NULL);
 	
 	
 	/* if (umsdos_real_lookup (pseudo,"etc",3,etc)==0 */
@@ -540,8 +550,8 @@
 
 	    Printk ((KERN_DEBUG "/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
 	    
-	    init = creat_dentry ("init", 4, NULL);
-	    etc_rc = creat_dentry ("rc", 2, NULL);
+	    init = creat_dentry ("init", 4, NULL, NULL);
+	    etc_rc = creat_dentry ("rc", 2, NULL, NULL);
 	  
 	    /* if ((umsdos_real_lookup (etc,"init",4,init)==0*/
 	    if((umsdos_real_lookup(pseudo, init) == 0
@@ -585,7 +595,7 @@
       
       Printk ((KERN_WARNING "umsdos_read_super /mn/: Pseudo should be iput-ed here...\n"));
 
-      iput (pseudo); /* FIXME */
+      /* iput (pseudo); / * FIXME */
     }
 
 #endif /* disabled */
diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v2.1.93/linux/fs/umsdos/ioctl.c	Tue Feb 17 13:12:48 1998
+++ linux/fs/umsdos/ioctl.c	Wed Apr  8 11:39:46 1998
@@ -60,6 +60,21 @@
 {
   int ret = -EPERM;
   int err;
+
+       /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
+       if(cmd!=UMSDOS_GETVERSION
+          &&cmd!=UMSDOS_READDIR_DOS
+          &&cmd!=UMSDOS_READDIR_EMD
+          &&cmd!=UMSDOS_INIT_EMD
+          &&cmd!=UMSDOS_CREAT_EMD
+          &&cmd!=UMSDOS_RENAME_DOS
+          &&cmd!=UMSDOS_UNLINK_EMD
+          &&cmd!=UMSDOS_UNLINK_DOS
+          &&cmd!=UMSDOS_RMDIR_DOS
+          &&cmd!=UMSDOS_STAT_DOS
+          &&cmd!=UMSDOS_DOS_SETUP)
+              return fat_dir_ioctl(dir,filp,cmd,data);
+
   /* #Specification: ioctl / acces
      Only root (effective id) is allowed to do IOCTL on directory
      in UMSDOS. EPERM is returned for other user.
@@ -162,7 +177,7 @@
 	    }
 	  }
 	}
-	iput (emd_dir);
+	/* iput (emd_dir); FIXME */
       }else{
 				/* The absence of the EMD is simply seen as an EOF */
 	ret = 0;
@@ -182,7 +197,7 @@
       extern struct inode_operations umsdos_rdir_inode_operations;
       struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1);
       ret = emd_dir != NULL;
-      iput (emd_dir);
+      /* iput (emd_dir); FIXME */
       
       dir->i_op = ret
 	? &umsdos_dir_inode_operations
@@ -225,8 +240,8 @@
 	  ,dir
 	  ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
 	*/
-	old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL);
-	new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL);
+	old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL, NULL);	/* FIXME: prolly should fill inode part */
+	new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL, NULL);
 	ret = msdos_rename(dir,old_dentry,dir,new_dentry);
       }else if (cmd == UMSDOS_UNLINK_EMD){
        /* #Specification: ioctl / UMSDOS_UNLINK_EMD
@@ -297,7 +312,7 @@
 	  data.stat.st_ctime = inode->i_ctime;
 	  data.stat.st_mtime = inode->i_mtime;
 	  copy_to_user (&idata->stat,&data.stat,sizeof(data.stat));
-	  iput (inode);
+	  /* iput (inode); FIXME */
 	}
       }else if (cmd == UMSDOS_DOS_SETUP){
       /* #Specification: ioctl / UMSDOS_DOS_SETUP
diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.1.93/linux/fs/umsdos/namei.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/umsdos/namei.c	Wed Apr  8 11:39:46 1998
@@ -216,6 +216,7 @@
 {
     
   int ret;
+  struct dentry *fake;
   
   Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino));
   ret = umsdos_nevercreat(dir,dentry,-EEXIST);
@@ -238,17 +239,16 @@
       ret = umsdos_newentry (dir,&info);
       if (ret == 0){
 	dir->i_count++;
-      /* FIXME
-	 ret = msdos_create (dir,info.fake.fname,info.fake.len
-	 ,S_IFREG|0777,result);
-      */
-	ret =msdos_create(dir,dentry,S_IFREG|0777);
+        fake = creat_dentry (info.fake.fname, info.fake.len, NULL, dentry->d_parent);	/* create short name dentry */
+	ret = msdos_create (dir, fake, S_IFREG|0777);
 	if (ret == 0){
-	  struct inode *inode = dentry->d_inode;
+	  struct inode *inode = fake->d_inode;
 	  umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
 	  Printk (("inode %p[%lu], count=%d ",inode, inode->i_ino, inode->i_count));
 	  Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino,
 		   info.fake.len, info.fake.fname, current->pid, info.f_pos));
+	  
+	  d_instantiate(dentry, inode);	/* long name also gets inode info */
 	}else{
 	  /* #Specification: create / file exist in DOS
 	     Here is a situation. Trying to create a file with
@@ -367,8 +367,8 @@
 	  PRINTK (("ret %d %d ",ret,new_info.fake.len));
 	  if (ret == 0){
 	    struct dentry *old, *new;
-	    old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL);
-	    new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL);
+	    old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL, NULL);
+	    new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL, NULL);
 
 	    PRINTK (("msdos_rename "));
 	    old_dir->i_count++;
@@ -471,7 +471,7 @@
     fill_new_filp (&filp, dentry);
 
     /* Make the inode acceptable to MSDOS FIXME */
-    Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n"));
+    Printk ((KERN_WARNING "umsdos_symlink_x: /mn/ Is this ok?\n"));
     Printk ((KERN_WARNING "   symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino));
     ret = umsdos_file_write_kmem_real (&filp, symname, len, &myofs);
     /* dput(dentry); ?? where did this come from FIXME */
@@ -489,7 +489,7 @@
       dir = NULL;
     }
   }
-  d_instantiate(dentry,dir);
+  /* d_instantiate(dentry,dir);   //already done in umsdos_create_any */
   Printk (("\n"));
   return ret;
 }
@@ -634,7 +634,7 @@
 		ret = -ENOMEM;
 	      }else{
 		struct dentry *temp;
-		temp = creat_dentry (entry.name, entry.name_len, NULL);
+		temp = creat_dentry (entry.name, entry.name_len, NULL, NULL);
 		Printk (("olddir[%d] ",olddir->i_count));
 		ret = umsdos_locate_path (oldinode,path);
 		Printk (("olddir[%d] ",olddir->i_count));
@@ -673,7 +673,7 @@
       umsdos_unlockcreate(olddir);
       umsdos_unlockcreate(dir);
     }
-    iput (olddir);
+    /* iput (olddir); FIXME */
   }
   if (ret == 0){
     struct iattr newattrs;
@@ -681,8 +681,10 @@
     newattrs.ia_valid = 0;
     ret = UMSDOS_notify_change(olddentry, &newattrs);
   }
-  dput (olddentry);
-  dput (dentry);
+
+/*  dput (olddentry);
+  dput (dentry); FIXME.... */
+  
   Printk (("umsdos_link %d\n",ret));
   return ret;
 }
@@ -735,10 +737,12 @@
       ret = umsdos_newentry (dir,&info);
       Printk (("newentry %d ",ret));
       if (ret == 0){
-	struct dentry *temp;
-	temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+	struct dentry *temp, *tdir;
+	tdir = creat_dentry ("mkd-dir", 7, dir, NULL);
+	temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
 	dir->i_count++;
 	ret = msdos_mkdir (dir, temp, mode);
+	
 	if (ret != 0){
 	  umsdos_delentry (dir,&info,1);
 	  /* #Specification: mkdir / Directory already exist in DOS
@@ -756,17 +760,22 @@
 	  ret = compat_umsdos_real_lookup (dir,info.fake.fname,
 					   info.fake.len,&subdir);
 	  if (ret == 0){
-/*	    struct inode *result;	FIXME /mn/ hmmm what is this supposed to be ? */
-	    struct dentry *tdentry;
-	    tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
-
-	    ret = msdos_create (subdir, tdentry,S_IFREG|0777);
+	    struct dentry *tdentry, *tdsub;
+	    tdsub = creat_dentry ("mkd-emd", 7, subdir, NULL);
+	    tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tdsub);
+	    ret = msdos_create (subdir, tdentry, S_IFREG|0777);
+	    kill_dentry (tdentry);	/* we don't want empty EMD file to be visible ! too bad kill_dentry does nothing at the moment :-)  FIXME */
+	    kill_dentry (tdsub);
+	    umsdos_setup_dir_inode (subdir);	/* this should setup dir so it is promoted to EMD, and EMD file is not visible inside it */
 	    subdir = NULL;
+	    d_instantiate(dentry, temp->d_inode);
 	    /* iput (result); FIXME */
 	  }
 	  if (ret < 0){
 	    printk ("UMSDOS: Can't create empty --linux-.---\n");
 	  }
+	  
+	
 	  /* iput (subdir); FIXME */
 	}
       }
@@ -774,7 +783,7 @@
     }
   }
   Printk (("umsdos_mkdir %d\n",ret));
-/*  dput (dentry); FIXME /mn/ */
+  /* dput (dentry); / * FIXME /mn/ */
   return ret;
 }
 
@@ -803,7 +812,7 @@
   */
 
   int ret = umsdos_create_any (dir,dentry,mode,rdev,0);
-/*  dput(dentry); /mn/ FIXME! */
+  /* dput(dentry); / * /mn/ FIXME! */
   return ret;
 }
 
@@ -902,7 +911,9 @@
      as possible.
   */		
 
-  int ret = umsdos_nevercreat(dir,dentry,-EPERM);
+  int ret;
+  
+  ret = umsdos_nevercreat(dir,dentry,-EPERM);
   if (ret == 0){
     volatile struct inode *sdir;
     dir->i_count++;
@@ -913,18 +924,22 @@
       int empty;
       umsdos_lockcreate(dir);
       if (sdir->i_count > 1){
+        Printk ((" /mn/ rmdir: FIXME EBUSY: hmmm, i_count is %d > 1\n", sdir->i_count));
 	ret = -EBUSY;
       }else if ((empty = umsdos_isempty (sdir)) != 0){
-	struct dentry *tdentry;
-	tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
+	struct dentry *tdentry, *tedir;
+	tedir = creat_dentry ("emd-rmd", 7, dir, NULL);
+	tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tedir);
+        umsdos_real_lookup (dir, tdentry);	/* fill inode part */
 	Printk (("isempty %d i_count %d ",empty,sdir->i_count));
 				/* check sticky bit */
 	if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
 	     current->fsuid == sdir->i_uid ||
 	     current->fsuid == dir->i_uid ) {
 	  if (empty == 1){
-	    /* We have to removed the EMD file */
+	    /* We have to remove the EMD file */
 	    ret = msdos_unlink (sdir, tdentry);
+	    Printk (("UMSDOS_rmdir: unlinking empty EMD ret=%d", ret));
 	    sdir = NULL;
 	  }
 	  /* sdir must be free before msdos_rmdir() */
@@ -933,17 +948,34 @@
 	  Printk (("isempty ret %d nlink %d ",ret,dir->i_nlink));
 	  if (ret == 0){
 	    struct umsdos_info info;
-	    struct dentry *temp;
+	    struct dentry *temp, *tdir;
 	    dir->i_count++;
 	    umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
 	    /* The findentry is there only to complete */
 	    /* the mangling */
 	    umsdos_findentry (dir,&info,2);
-	    temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
-	    
+
+            tdir = creat_dentry ("dir-rmd", 7, dir, NULL);
+            temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
+            umsdos_real_lookup (dir, temp);	/* fill inode part */
+            
+	      Printk ((KERN_ERR "  rmdir start dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb)); /* FIXME: /mn/ debug only */
+	      Printk ((KERN_ERR "    dentry=%.*s d_count=%d ino=%lu\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode->i_ino));
+	      Printk ((KERN_ERR "    d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino));
+
 	    ret = msdos_rmdir (dir, temp);
+
+	      Printk ((KERN_ERR "  rmdir passed %d\n", ret)); /* FIXME: /mn/ debug only */
+	      Printk ((KERN_ERR "  rmdir end dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb));
+	      Printk ((KERN_ERR "    dentry=%.*s d_count=%d ino=%p\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode));
+	      Printk ((KERN_ERR "    d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino));
+
+            kill_dentry (tdir);
+            kill_dentry (temp);
+            
 	    if (ret == 0){
 	      ret = umsdos_delentry (dir,&info,1);
+              d_delete (dentry);
 	    }
 	  }
 	}else{
@@ -961,7 +993,7 @@
       umsdos_unlockcreate(dir);
     }	
   }
-  dput(dentry);
+ /*  dput(dentry); FIXME /mn/ */
   Printk (("umsdos_rmdir %d\n",ret));
   return ret;
 }
@@ -1036,13 +1068,21 @@
 	  if (ret == 0){
 	    ret = umsdos_delentry (dir,&info,0);
 	    if (ret == 0){
-	      struct dentry *temp;
+	      struct dentry *temp, *tdir;
 	      Printk (("Avant msdos_unlink %.*s ",info.fake.len,info.fake.fname));
-	      dir->i_count++;
-	      temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+	      dir->i_count++;  /* FIXME /mn/ is this needed anymore now that msdos_unlink locks dir using d_parent ? */
+	      tdir = creat_dentry ("dir-del", 7, dir, NULL);	/* FIXME /mn/: do we need iget(dir->i_ino) or would dir itself suffice ? */
+	      temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
+	      umsdos_real_lookup (dir, temp);	/* fill inode part */
+	      
 	      ret = msdos_unlink_umsdos (dir, temp);
 	      Printk (("msdos_unlink %.*s %o ret %d ",info.fake.len,info.fake.fname
 		       ,info.entry.mode,ret));
+
+	      d_delete (dentry);
+	      
+	      kill_dentry (tdir);
+	      kill_dentry (temp);
 	    }
 	  }
 	}else{
@@ -1054,7 +1094,7 @@
       umsdos_unlockcreate(dir);
     }
   }	
-  dput(dentry);
+  /* dput(dentry); FIXME: shouldn't this be done in msdos_unlink ? */
   Printk (("umsdos_unlink %d\n",ret));
   return ret;
 }
@@ -1140,8 +1180,9 @@
       }
     }
   }
+  /*
   dput (new_dentry);
-  dput (old_dentry);
+  dput (old_dentry); FIXME /mn/ */
   return ret;
 }
 
diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v2.1.93/linux/fs/umsdos/rdir.c	Mon Feb 23 18:12:11 1998
+++ linux/fs/umsdos/rdir.c	Wed Apr  8 11:39:46 1998
@@ -135,7 +135,7 @@
       */
         Printk ((KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n"));
 	ret = -ENOENT;
-	iput (pseudo_root);
+	/* iput (pseudo_root); FIXME */
        
       }else if (S_ISDIR(inode->i_mode)){
 	/* We must place the proper function table */
@@ -145,7 +145,7 @@
       }
     }
   }
-  iput (dir);
+  /* iput (dir); FIXME */
   PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
   return ret;
 }
@@ -215,7 +215,7 @@
 	  }else if (empty == 1){
 	    /* We have to removed the EMD file */
 	    struct dentry *temp;
-	    temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
+	    temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, NULL); /* FIXME: prolly should fill inode part ? */
 	    ret = msdos_unlink(sdir, temp);
 	    sdir = NULL;
 	    if (ret == 0){
@@ -226,12 +226,12 @@
 	}else{
 	  ret = -ENOTEMPTY;
 	}
-	iput (sdir);
+	/* iput (sdir); FIXME */
       }
     }
     umsdos_unlockcreate (dir);
   }
-  iput (dir);
+  /* iput (dir); FIXME */
   return ret;
 }
 
diff -u --recursive --new-file v2.1.93/linux/include/asm-alpha/lca.h linux/include/asm-alpha/lca.h
--- v2.1.93/linux/include/asm-alpha/lca.h	Wed Apr  1 20:11:53 1998
+++ linux/include/asm-alpha/lca.h	Tue Apr  7 07:52:05 1998
@@ -52,6 +52,7 @@
  * ugh).
  */
 
+#include <linux/config.h>
 #include <asm/system.h>
 
 #ifdef CONFIG_ALPHA_SRM_SETUP
diff -u --recursive --new-file v2.1.93/linux/include/asm-alpha/string.h linux/include/asm-alpha/string.h
--- v2.1.93/linux/include/asm-alpha/string.h	Fri Oct 18 01:53:20 1996
+++ linux/include/asm-alpha/string.h	Tue Apr  7 08:05:05 1998
@@ -3,29 +3,40 @@
 
 #ifdef __KERNEL__
 
-extern void * __constant_c_memset(void *, unsigned long, long);
-extern void * __memset(void *, char, size_t);
-
 /*
- * Ugh. Gcc uses "bcopy()" internally for structure assignments.
+ * GCC of any recent vintage doesn't do stupid things with bcopy.  Of
+ * EGCS-devel vintage, it knows all about expanding memcpy inline.
+ * For things other than EGCS-devel but still recent, GCC will expand
+ * __builtin_memcpy as a simple call to memcpy.
+ *
+ * Similarly for a memset with data = 0.
  */
-#define __HAVE_ARCH_BCOPY
 
-/*
- * Define "memcpy()" to something else, otherwise gcc will
- * corrupt that too into a "bcopy".  Also, some day we might
- * want to do a separate inlined constant-size memcpy (for 8
- * and 16 byte user<->kernel structure copying).
- */
 #define __HAVE_ARCH_MEMCPY
+/* For backward compatibility with modules.  Unused otherwise.  */
 extern void * __memcpy(void *, const void *, size_t);
-#define memcpy __memcpy
+
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 8
+#define memcpy __builtin_memcpy
+#endif
 
 #define __HAVE_ARCH_MEMSET
-#define memset(s, c, count) \
-(__builtin_constant_p(c) ? \
- __constant_c_memset((s),(0x0101010101010101UL*(unsigned char)c),(count)) : \
- __memset((s),(c),(count)))
+extern void * __constant_c_memset(void *, unsigned long, long);
+extern void * __memset(void *, char, size_t);
+
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 8
+#define memset(s, c, n)							    \
+(__builtin_constant_p(c)						    \
+ ? (__builtin_constant_p(n) && (c) == 0					    \
+    ? __builtin_memset((s),0,(n)) 					    \
+    : __constant_c_memset((s),0x0101010101010101UL*(unsigned char)(c),(n))) \
+ : __memset((s),(c),(n)))
+#else
+#define memset(s, c, n)							\
+(__builtin_constant_p(c)						\
+ ? __constant_c_memset((s),0x0101010101010101UL*(unsigned char)(c),(n)) \
+ : __memset((s),(c),(n)))
+#endif
 
 #define __HAVE_ARCH_STRCPY
 #define __HAVE_ARCH_STRNCPY
diff -u --recursive --new-file v2.1.93/linux/include/asm-alpha/termios.h linux/include/asm-alpha/termios.h
--- v2.1.93/linux/include/asm-alpha/termios.h	Fri Apr  4 08:52:25 1997
+++ linux/include/asm-alpha/termios.h	Wed Apr  8 17:31:27 1998
@@ -72,6 +72,8 @@
 #define N_MOUSE		2
 #define N_PPP		3
 #define N_AX25		5
+#define N_X25		6
+#define N_6PACK		7
 
 #ifdef __KERNEL__
 /*	eof=^D		eol=\0		eol2=\0		erase=del
diff -u --recursive --new-file v2.1.93/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- v2.1.93/linux/include/asm-alpha/unistd.h	Thu Mar 26 15:57:05 1998
+++ linux/include/asm-alpha/unistd.h	Tue Apr  7 08:05:05 1998
@@ -421,12 +421,6 @@
 	return sys_read(fd, buf, nr);
 }
 
-extern int sys_fork(void);
-static inline int fork(void)
-{
-	return sys_fork();
-}
-
 extern int __kernel_execve(char *, char **, char **, struct pt_regs *);
 static inline int execve(char * file, char ** argvp, char ** envp)
 {
diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/proc-armo/pgtable.h linux/include/asm-arm/proc-armo/pgtable.h
--- v2.1.93/linux/include/asm-arm/proc-armo/pgtable.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/pgtable.h	Wed Apr  8 15:44:24 1998
@@ -9,6 +9,7 @@
 
 #include <asm/arch/mmu.h>
 #include <linux/slab.h>
+#include <asm/arch/processor.h>		/* For TASK_SIZE */
 
 #define LIBRARY_TEXT_START 0x0c000000
 
@@ -116,6 +117,7 @@
 #define PTRS_PER_PTE    32
 #define PTRS_PER_PMD    1
 #define PTRS_PER_PGD    32
+#define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SHIFT)
 
 /* Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 8MB value just means that there will be a 8MB "hole" after the
@@ -321,43 +323,111 @@
  * used to allocate a kernel page table - this turns on ASN bits
  * if any.
  */
-#define pte_free_kernel(pte) pte_free((pte))
-#define pte_alloc_kernel(pmd,address) pte_alloc((pmd),(address))
 
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-#define pmd_free_kernel(pmdp)
-#define pmd_alloc_kernel(pgd,address) ((pmd_t *)(pgd))
+#ifndef __SMP__
+extern struct pgtable_cache_struct {
+	unsigned long *pgd_cache;
+	unsigned long *pte_cache;
+	unsigned long pgtable_cache_sz;
+} quicklists;
+
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (quicklists.pte_cache)
+#define pgd_quicklist (quicklists.pgd_cache)
+#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+
+#else
+#error Pgtable caches have to be per-CPU, so that no locking is needed.
+#endif
+
+extern pgd_t *get_pgd_slow(void);
+
+extern __inline__ pgd_t *get_pgd_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = pgd_quicklist) != NULL) {
+		pgd_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
+	} else
+		ret = (unsigned long *)get_pgd_slow();
+	return (pgd_t *)ret;
+}
+
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	pgtable_cache_size++;
+}
+
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
+{
+	kfree(pgd);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = (unsigned long *)pte_quicklist) != NULL) {
+		pte_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
+	}
+	return (pte_t *)ret;
+}
 
-extern __inline__ void pte_free(pte_t * pte)
+extern __inline__ void free_pte_fast(pte_t *pte)
 {
-	kfree (pte);
+	*(unsigned long *)pte = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	pgtable_cache_size++;
 }
 
-extern const char bad_pmd_string[];
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+	kfree(pte);
+}
+
+/* We don't use pmd cache, so this is a dummy routine */
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+	return (pmd_t *)0;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+}
+
+extern void __bad_pte(pmd_t *pmd);
+
+#define pte_free_kernel(pte)    free_pte_fast(pte)
+#define pte_free(pte)           free_pte_fast(pte)
+#define pgd_free(pgd)           free_pgd_fast(pgd)
+#define pgd_alloc()             get_pgd_fast()
 
 extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address)
 {
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 
 	if (pmd_none (*pmd)) {
-		pte_t *page = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
-		if (pmd_none (*pmd)) {
-			if (page) {
-				memzero (page, PTRS_PER_PTE * BYTES_PER_PTR);
-				set_pmd(pmd, mk_pmd(page));
-				return page + address;
-			}
-			set_pmd (pmd, mk_pmd (BAD_PAGETABLE));
-			return NULL;
-		}
-		kfree (page);
+		pte_t *page = (pte_t *) get_pte_fast();
+
+		if (!page)
+			return get_pte_slow(pmd, address);
+		set_pmd(pmd, mk_pmd(page));
+		return page + address;
 	}
 	if (pmd_bad (*pmd)) {
-		printk(bad_pmd_string, pmd_val(*pmd));
-		set_pmd (pmd, mk_pmd (BAD_PAGETABLE));
+		__bad_pte(pmd);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
@@ -367,28 +437,33 @@
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-#define pmd_free(pmd)
-#define pmd_alloc(pgd,address) ((pmd_t *)(pgd))
+extern __inline__ void pmd_free(pmd_t *pmd)
+{
+}
 
-/*
- * Free a page directory.  Takes the virtual address.
- */
-extern __inline__ void pgd_free(pgd_t * pgd)
+extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
 {
-	kfree ((void *)pgd);
+	return (pmd_t *) pgd;
 }
 
-/*
- * Allocate a new page directory.  Return the virtual address of it.
- */
-extern __inline__ pgd_t * pgd_alloc(void)
+#define pmd_free_kernel         pmd_free
+#define pmd_alloc_kernel        pmd_alloc
+#define pte_alloc_kernel        pte_alloc
+
+extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
 {
+	struct task_struct * p;
 	pgd_t *pgd;
-	
-	pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
-	if (pgd)
-		memzero (pgd, PTRS_PER_PGD * BYTES_PER_PTR);
-	return pgd;
+
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+	read_unlock(&tasklist_lock);
+	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+		pgd[address >> PGDIR_SHIFT)] = entry;
 }
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.1.93/linux/include/asm-arm/proc-armv/pgtable.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/proc-armv/pgtable.h	Wed Apr  8 15:44:24 1998
@@ -10,6 +10,7 @@
 #define __ASM_PROC_PGTABLE_H
 
 #include <asm/arch/mmu.h>
+#include <asm/arch/processor.h>		/* For TASK_SIZE */
 
 #define LIBRARY_TEXT_START 0x0c000000
 
@@ -132,6 +133,7 @@
 #define PTRS_PER_PTE    256
 #define PTRS_PER_PMD    1
 #define PTRS_PER_PGD    4096
+#define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
 
 /* Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 8MB value just means that there will be a 8MB "hole" after the
@@ -263,6 +265,9 @@
 
 extern __inline__ int pte_present(pte_t pte)
 {
+#if 0
+	/* This is what it really does, the else
+	   part is just to make it easier for the compiler */
 	switch (pte_val(pte) & PTE_TYPE_MASK) {
 	case PTE_TYPE_LARGE:
 	case PTE_TYPE_SMALL:
@@ -270,6 +275,9 @@
 	default:
 		return 0;
 	}
+#else
+	return ((pte_val(pmd) + 1) & PMD_TYPE_MASK);
+#endif
 }
 
 extern __inline__ int pmd_none(pmd_t pmd)
@@ -281,6 +289,9 @@
 
 extern __inline__ int pmd_bad(pmd_t pmd)
 {
+#if 0
+	/* This is what it really does, the else
+	   part is just to make it easier for the compiler */
 	switch (pmd_val(pmd) & PMD_TYPE_MASK) {
 	case PMD_TYPE_FAULT:
 	case PMD_TYPE_TABLE:
@@ -288,6 +299,9 @@
 	default:
 		return 1;
 	}
+#else
+	return (pmd_val(pmd) & PMD_TYPE_SECT);
+#endif
 }
 
 extern __inline__ int pmd_present(pmd_t pmd)
@@ -479,7 +493,7 @@
 /* to find an entry in a page-table-directory */
 extern __inline__ pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
 {
-        return mm->pgd + (address >> PGDIR_SHIFT);
+	return mm->pgd + (address >> PGDIR_SHIFT);
 }
 
 /* Find an entry in the second-level page table.. */
@@ -488,7 +502,7 @@
 /* Find an entry in the third-level page table.. */
 extern __inline__ pte_t * pte_offset(pmd_t * dir, unsigned long address)
 {
-        return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 }
 
 extern unsigned long get_small_page(int priority);
@@ -499,69 +513,129 @@
  * used to allocate a kernel page table - this turns on ASN bits
  * if any.
  */
-extern __inline__ void pte_free_kernel(pte_t * pte)
+ 
+#ifndef __SMP__
+extern struct pgtable_cache_struct {
+	unsigned long *pgd_cache;
+	unsigned long *pte_cache;
+	unsigned long pgtable_cache_sz;
+} quicklists;
+#define pgd_quicklist (quicklists.pgd_cache)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (quicklists.pte_cache)
+#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+#else
+#error Pgtable caches have to be per-CPU, so that no locking is needed.
+#endif
+
+extern pgd_t *get_pgd_slow(void);
+
+extern __inline__ pgd_t *get_pgd_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = pgd_quicklist) != NULL) {
+		pgd_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
+	} else
+		ret = (unsigned long *)get_pgd_slow();
+	return (pgd_t *)ret;
+}
+
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	pgtable_cache_size++;
+}
+
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
+{
+	free_pages((unsigned long) pgd, 2);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = (unsigned long *)pte_quicklist) != NULL) {
+		pte_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		pgtable_cache_size--;
+	}
+	return (pte_t *)ret;
+}
+
+extern __inline__ void free_pte_fast(pte_t *pte)
+{
+	*(unsigned long *)pte = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	pgtable_cache_size++;
+}
+
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+	free_small_page((unsigned long)pte);
+}
+
+/* We don't use pmd cache, so this is a dummy routine */
+extern __inline__ pmd_t *get_pmd_fast(void)
 {
-	free_small_page((unsigned long) pte);
+	return (pmd_t *)0;
 }
 
-extern const char bad_pmd_string[];
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+}
+
+extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pte_kernel(pmd_t *pmd);
+
+#define pte_free_kernel(pte)	free_pte_fast(pte)
+#define pte_free(pte)		free_pte_fast(pte)
+#define pgd_free(pgd)		free_pgd_fast(pgd)
+#define pgd_alloc()		get_pgd_fast()
 
 extern __inline__ pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 {
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 	if (pmd_none(*pmd)) {
-		pte_t *page = (pte_t *) get_small_page(GFP_KERNEL);
-		if (pmd_none(*pmd)) {
-			if (page) {
-				memzero (page, PTRS_PER_PTE * BYTES_PER_PTR);
-				set_pmd(pmd, mk_kernel_pmd(page));
-				return page + address;
-			}
-			set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
-			return NULL;
-		}
-		free_small_page((unsigned long) page);
+		pte_t *page = (pte_t *) get_pte_fast();
+
+		if (!page)
+			return get_pte_kernel_slow(pmd, address);
+		set_pmd(pmd, mk_kernel_pmd(page));
+		return page + address;
 	}
 	if (pmd_bad(*pmd)) {
-		printk(bad_pmd_string, pmd_val(*pmd));
-		set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
+		__bad_pte_kernel(pmd);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
 }
 
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-#define pmd_free_kernel(pmdp) pmd_val(*(pmdp)) = 0;
-#define pmd_alloc_kernel(pgdp, address) ((pmd_t *)(pgdp))
-
-extern __inline__ void pte_free(pte_t * pte)
-{
-	free_small_page((unsigned long) pte);
-}
-
 extern __inline__ pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
 {
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 
 	if (pmd_none(*pmd)) {
-		pte_t *page = (pte_t *) get_small_page(GFP_KERNEL);
-		if (pmd_none(*pmd)) {
-			if (page) {
-				memzero (page, PTRS_PER_PTE * BYTES_PER_PTR);
-				set_pmd(pmd, mk_user_pmd(page));
-				return page + address;
-			}
-			set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
-			return NULL;
-		}
-		free_small_page ((unsigned long) page);
+		pte_t *page = (pte_t *) get_pte_fast();
+		
+		if (!page)
+			return get_pte_slow(pmd, address);
+		set_pmd(pmd, mk_user_pmd(page);
+		return page + address;
 	}
 	if (pmd_bad(*pmd)) {
-		printk(bad_pmd_string, pmd_val(*pmd));
-		set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
+		__bad_pte(pmd);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
@@ -571,31 +645,32 @@
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-#define pmd_free(pmdp) pmd_val(*(pmdp)) = 0;
-#define pmd_alloc(pgdp, address) ((pmd_t *)(pgdp))
+extern __inline__ void pmd_free(pmd_t *pmd)
+{
+}
 
-/*
- * Free a page directory.  Takes the virtual address.
- */
-extern __inline__ void pgd_free(pgd_t * pgd)
+extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
 {
-	free_pages((unsigned long) pgd, 2);
+	return (pmd_t *) pgd;
 }
 
-/*
- * Allocate a new page directory.  Return the virtual address of it.
- */
-extern __inline__ pgd_t * pgd_alloc(void)
+#define pmd_free_kernel         pmd_free
+#define pmd_alloc_kernel        pmd_alloc
+
+extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
 {
-	unsigned long pgd;
+	struct task_struct * p;
+	pgd_t *pgd;
 
-	/*
-	 * need to get a 16k page for level 1
-	 */
-	pgd = __get_free_pages(GFP_KERNEL,2,0);
-	if (pgd)
-		memzero ((void *)pgd, PTRS_PER_PGD * BYTES_PER_PTR);
-	return (pgd_t *)pgd;
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+	read_unlock(&tasklist_lock);
+	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+		pgd[address >> PGDIR_SHIFT] = entry;
 }
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/proc-armv/processor.h linux/include/asm-arm/proc-armv/processor.h
--- v2.1.93/linux/include/asm-arm/proc-armv/processor.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/proc-armv/processor.h	Wed Apr  8 15:44:24 1998
@@ -95,7 +95,7 @@
  * NOTE! The task struct and the stack go together
  */
 #define alloc_task_struct() \
-	((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+	((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
 #define free_task_struct(p)	free_pages((unsigned long)(p),1)
 
 #endif
diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/stat.h linux/include/asm-arm/stat.h
--- v2.1.93/linux/include/asm-arm/stat.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/stat.h	Wed Apr  8 15:44:24 1998
@@ -38,4 +38,40 @@
 	unsigned long  __unused5;
 };
 
+typedef struct {
+	unsigned int	minor;
+	unsigned int	major;
+} __new_dev_t;
+
+struct stat64 {
+	__new_dev_t	st_dev;
+	__u64		st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+	__new_dev_t	st_rdev;
+	__s64		st_size;
+	__u64		st_blocks;
+	unsigned long	st_atime;
+	unsigned long	__unused1;
+	unsigned long	st_mtime;
+	unsigned long	__unused2;
+	unsigned long	st_ctime;
+	unsigned long	__unused3;
+	unsigned long	st_blksize;
+	unsigned long	__unused4;
+};
+
+#define __XSTAT_VER_1		1
+#define __XSTAT_VER_2		2
+#define __XSTAT_VER_MASK	0xff
+
+#define __XSTAT_VER_XSTAT	0x000
+#define __XSTAT_VER_LXSTAT	0x100
+#define __XSTAT_VER_FXSTAT	0x200
+#define __XSTAT_VER_TYPEMASK	0xff00
+
+#define __XMKNOD_VER_1		1
+
 #endif
diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/termios.h linux/include/asm-arm/termios.h
--- v2.1.93/linux/include/asm-arm/termios.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/termios.h	Wed Apr  8 17:31:27 1998
@@ -54,6 +54,7 @@
 #define N_STRIP		4
 #define N_AX25		5
 #define N_X25		6	/* X.25 async */
+#define N_6PACK		7
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h
--- v2.1.93/linux/include/asm-arm/unistd.h	Thu Mar 26 15:57:05 1998
+++ linux/include/asm-arm/unistd.h	Wed Apr  8 15:44:24 1998
@@ -189,6 +189,8 @@
 #define __NR_rt_sigsuspend		(__NR_SYSCALL_BASE+179)
 #define __NR_pread			(__NR_SYSCALL_BASE+180)
 #define __NR_pwrite			(__NR_SYSCALL_BASE+181)
+#define __NR_xstat			(__NR_SYSCALL_BASE+182)
+#define __NR_xmknod			(__NR_SYSCALL_BASE+183)
 
 #define __sys2(x) #x
 #define __sys1(x) __sys2(x)
@@ -311,8 +313,6 @@
  */
 #define __NR__exit __NR_exit
 static inline _syscall0(int,idle);
-static inline _syscall0(int,fork);
-static inline _syscall2(int,clone,unsigned long,flags,char *,esp);
 static inline _syscall0(int,pause);
 static inline _syscall1(int,setup,int,magic);
 static inline _syscall0(int,sync);
diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/xstat.h linux/include/asm-arm/xstat.h
--- v2.1.93/linux/include/asm-arm/xstat.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/xstat.h	Wed Apr  8 15:44:24 1998
@@ -0,0 +1,35 @@
+/* $Id: xstat.h,v 1.1 1998/02/06 12:52:45 jj Exp $
+ * xstat.h: sys_xstat/xmknod architecture dependent stuff.
+ *
+ * Copyright (C) 1998  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
+ */
+ 
+extern __inline__ int cp_xstat(struct inode *inode, struct stat64 *s, unsigned long blocks, int blksize)
+{
+	struct stat64 tmp;
+	
+	memset (&tmp, 0, sizeof(tmp));
+	tmp.st_dev.major = MAJOR(inode->i_dev);
+	tmp.st_dev.minor = MINOR(inode->i_dev);
+	tmp.st_ino = inode->i_ino;
+	tmp.st_mode = inode->i_mode;
+	tmp.st_nlink = inode->i_nlink;
+	tmp.st_uid = inode->i_uid;
+	tmp.st_gid = inode->i_gid;
+	tmp.st_rdev.major = MAJOR(inode->i_rdev);
+	tmp.st_rdev.minor = MINOR(inode->i_rdev);
+	tmp.st_size = inode->i_size;
+	tmp.st_blksize = blksize;
+	tmp.st_blocks = blocks;
+	tmp.st_atime = inode->i_atime;
+	tmp.st_mtime = inode->i_mtime;
+	tmp.st_ctime = inode->i_ctime;
+	return copy_to_user(s,&tmp,sizeof(tmp));
+}
+
+extern __inline__ int get_user_new_dev_t(kdev_t *kdev, __new_dev_t *udev) {
+	__new_dev_t ndev;
+	if (copy_from_user (&ndev, udev, sizeof(__new_dev_t))) return -EFAULT;
+	*kdev = MKDEV(ndev.major, ndev.minor);
+	return 0;
+}
diff -u --recursive --new-file v2.1.93/linux/include/asm-i386/page.h linux/include/asm-i386/page.h
--- v2.1.93/linux/include/asm-i386/page.h	Tue Mar 17 22:18:15 1998
+++ linux/include/asm-i386/page.h	Wed Apr  8 18:05:18 1998
@@ -1,8 +1,6 @@
 #ifndef _I386_PAGE_H
 #define _I386_PAGE_H
 
-#include <linux/config.h>
-
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
@@ -60,8 +58,30 @@
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-/* This handles the memory map.. */
-#define __PAGE_OFFSET		((0x1000-CONFIG_MAX_MEMSIZE)<<20)
+/*
+ * This handles the memory map.. We could make this a config
+ * option, but too many people screw it up, and too few need
+ * it.
+ *
+ * A __PAGE_OFFSET of 0xC0000000 means that the kernel has
+ * a virtual address space of one gigabyte, which limits the
+ * amount of physical memory you can use to about 950MB. If
+ * you want to use more physical memory, change this define.
+ *
+ * For example, if you have 2GB worth of physical memory, you
+ * could change this define to 0x70000000, which gives the
+ * kernel slightly more than 2GB of virtual memory (enough to
+ * map all your physical memory + a bit extra for various
+ * io-memory mappings)
+ *
+ * IF YOU CHANGE THIS, PLEASE ALSO CHANGE
+ *
+ *	arch/i386/vmlinux.lds
+ *
+ * which has the same constant encoded..
+ */
+#define __PAGE_OFFSET		(0xC0000000)
+
 #define PAGE_OFFSET		((unsigned long)__PAGE_OFFSET)
 #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
diff -u --recursive --new-file v2.1.93/linux/include/asm-i386/termios.h linux/include/asm-i386/termios.h
--- v2.1.93/linux/include/asm-i386/termios.h	Tue Dec  9 00:07:19 1997
+++ linux/include/asm-i386/termios.h	Wed Apr  8 17:31:27 1998
@@ -46,6 +46,7 @@
 #define N_STRIP		4
 #define N_AX25		5
 #define N_X25		6	/* X.25 async */
+#define N_6PACK		7
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.93/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v2.1.93/linux/include/asm-i386/unistd.h	Wed Apr  1 20:11:54 1998
+++ linux/include/asm-i386/unistd.h	Tue Apr  7 08:05:05 1998
@@ -282,8 +282,6 @@
  */
 #define __NR__exit __NR_exit
 static inline _syscall0(int,idle)
-static inline _syscall0(int,fork)
-static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
 static inline _syscall0(int,pause)
 static inline _syscall1(int,setup,int,magic)
 static inline _syscall0(int,sync)
diff -u --recursive --new-file v2.1.93/linux/include/asm-m68k/termios.h linux/include/asm-m68k/termios.h
--- v2.1.93/linux/include/asm-m68k/termios.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-m68k/termios.h	Wed Apr  8 17:31:27 1998
@@ -54,6 +54,7 @@
 #define N_STRIP		4
 #define N_AX25		5
 #define N_X25		6	/* X.25 async */
+#define N_6PACK		7
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.93/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h
--- v2.1.93/linux/include/asm-m68k/unistd.h	Thu Mar 26 15:57:05 1998
+++ linux/include/asm-m68k/unistd.h	Tue Apr  7 08:05:05 1998
@@ -303,8 +303,6 @@
  */
 #define __NR__exit __NR_exit
 static inline _syscall0(int,idle)
-static inline _syscall0(int,fork)
-static inline _syscall2(int,clone,unsigned long,flags,char *,usp)
 static inline _syscall0(int,pause)
 static inline _syscall1(int,setup,int,magic)
 static inline _syscall0(int,sync)
diff -u --recursive --new-file v2.1.93/linux/include/asm-mips/termios.h linux/include/asm-mips/termios.h
--- v2.1.93/linux/include/asm-mips/termios.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/termios.h	Wed Apr  8 17:31:27 1998
@@ -92,6 +92,7 @@
 #define N_STRIP		4
 #define N_AX25		5
 #define N_X25		6		/* X.25 async */
+#define N_6PACK		7
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.93/linux/include/asm-mips/unistd.h linux/include/asm-mips/unistd.h
--- v2.1.93/linux/include/asm-mips/unistd.h	Thu Mar 26 15:57:05 1998
+++ linux/include/asm-mips/unistd.h	Tue Apr  7 08:05:05 1998
@@ -1397,8 +1397,6 @@
  */
 #define __NR__exit __NR_exit
 static inline _syscall0(int,idle)
-static inline _syscall0(int,fork)
-static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
 static inline _syscall0(int,pause)
 static inline _syscall1(int,setup,int,magic)
 static inline _syscall0(int,sync)
diff -u --recursive --new-file v2.1.93/linux/include/asm-sparc/termios.h linux/include/asm-sparc/termios.h
--- v2.1.93/linux/include/asm-sparc/termios.h	Mon Mar 17 14:54:33 1997
+++ linux/include/asm-sparc/termios.h	Wed Apr  8 17:31:27 1998
@@ -61,6 +61,8 @@
 #define N_PPP		3
 #define N_STRIP		4
 #define N_AX25		5
+#define N_X25		6
+#define N_6PACK		7
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.93/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h
--- v2.1.93/linux/include/asm-sparc/unistd.h	Thu Mar 26 15:57:05 1998
+++ linux/include/asm-sparc/unistd.h	Tue Apr  7 08:05:05 1998
@@ -425,8 +425,6 @@
  */
 #define __NR__exit __NR_exit
 static __inline__ _syscall0(int,idle)
-static __inline__ _syscall0(int,fork)
-static __inline__ _syscall2(int,clone,unsigned long,flags,char *,ksp)
 static __inline__ _syscall0(int,pause)
 static __inline__ _syscall1(int,setup,int,magic)
 static __inline__ _syscall0(int,sync)
diff -u --recursive --new-file v2.1.93/linux/include/asm-sparc64/termios.h linux/include/asm-sparc64/termios.h
--- v2.1.93/linux/include/asm-sparc64/termios.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/termios.h	Wed Apr  8 17:31:27 1998
@@ -61,6 +61,8 @@
 #define N_PPP		3
 #define N_STRIP		4
 #define N_AX25		5
+#define N_X25		6
+#define N_6PACK		7
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.93/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h
--- v2.1.93/linux/include/asm-sparc64/unistd.h	Thu Mar 26 15:57:05 1998
+++ linux/include/asm-sparc64/unistd.h	Tue Apr  7 08:05:05 1998
@@ -413,8 +413,6 @@
  */
 #define __NR__exit __NR_exit
 static __inline__ _syscall0(int,idle)
-static __inline__ _syscall0(int,fork)
-static __inline__ _syscall2(int,clone,unsigned long,flags,char *,ksp)
 static __inline__ _syscall0(int,pause)
 static __inline__ _syscall1(int,setup,int,magic)
 static __inline__ _syscall0(int,sync)
diff -u --recursive --new-file v2.1.93/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v2.1.93/linux/include/linux/binfmts.h	Wed Apr  1 20:11:54 1998
+++ linux/include/linux/binfmts.h	Wed Apr  8 18:15:11 1998
@@ -11,6 +11,8 @@
  */
 #define MAX_ARG_PAGES 32
 
+#ifdef __KERNEL__
+
 /*
  * This structure is used to hold the arguments that are used when loading binaries.
  */
@@ -70,4 +72,5 @@
 /* this eventually goes away */
 #define change_ldt(a,b) setup_arg_pages(a,b)
 
-#endif
+#endif /* __KERNEL__ */
+#endif /* _LINUX_BINFMTS_H */
diff -u --recursive --new-file v2.1.93/linux/include/linux/joystick.h linux/include/linux/joystick.h
--- v2.1.93/linux/include/linux/joystick.h	Fri Feb  6 15:33:20 1998
+++ linux/include/linux/joystick.h	Wed Apr  8 17:24:48 1998
@@ -2,19 +2,18 @@
 #define _LINUX_JOYSTICK_H
 
 /*
- *  $Id: joystick.h,v 1.2 1997/10/31 19:11:57 mj Exp $
+ *  $Id: joystick.h,v 1.3 1998/03/30 11:10:40 mj Exp $
  *
- *  Copyright (C) 1997 Vojtech Pavlik
+ *  Copyright (C) 1997, 1998 Vojtech Pavlik
  */
 
-#include <linux/ioctl.h>
 #include <asm/types.h>
 
 /*
  * Version
  */
 
-#define JS_VERSION		0x00010006L		/* 1.0.6 BCD */
+#define JS_VERSION		0x00010007L		/* 1.0.7 BCD */
 
 /*
  * IOCTL commands for joystick driver
diff -u --recursive --new-file v2.1.93/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.1.93/linux/include/linux/mm.h	Thu Mar 26 15:57:05 1998
+++ linux/include/linux/mm.h	Wed Apr  8 18:15:11 1998
@@ -133,7 +133,7 @@
 #define PG_uptodate		 3
 #define PG_free_after		 4
 #define PG_decr_after		 5
-/* Unused			 6 */
+#define PG_swap_unlock_after	 6
 #define PG_DMA			 7
 #define PG_Slab			 8
 #define PG_swap_cache		 9
@@ -146,6 +146,7 @@
 #define PageUptodate(page)	(test_bit(PG_uptodate, &(page)->flags))
 #define PageFreeAfter(page)	(test_bit(PG_free_after, &(page)->flags))
 #define PageDecrAfter(page)	(test_bit(PG_decr_after, &(page)->flags))
+#define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags))
 #define PageDMA(page)		(test_bit(PG_DMA, &(page)->flags))
 #define PageSlab(page)		(test_bit(PG_Slab, &(page)->flags))
 #define PageSwapCache(page)	(test_bit(PG_swap_cache, &(page)->flags))
diff -u --recursive --new-file v2.1.93/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.93/linux/include/linux/pci.h	Mon Apr  6 17:41:01 1998
+++ linux/include/linux/pci.h	Tue Apr  7 08:05:05 1998
@@ -977,6 +977,9 @@
 
 #ifdef __KERNEL__
 
+/* Create an index into the pci_dev base_address[] array from an offset.  */
+#define PCI_BASE_INDEX(o) (((o)-PCI_BASE_ADDRESS_0)>>2)
+
 /*
  * Error values that may be returned by the PCI bios.  Use
  * pcibios_strerror() to convert to a printable string.
diff -u --recursive --new-file v2.1.93/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.1.93/linux/include/linux/swap.h	Thu Mar 26 15:57:06 1998
+++ linux/include/linux/swap.h	Mon Apr  6 17:48:34 1998
@@ -23,6 +23,7 @@
 	kdev_t swap_device;
 	struct dentry * swap_file;
 	unsigned char * swap_map;
+	unsigned char * swap_lockmap;
 	unsigned int lowest_bit;
 	unsigned int highest_bit;
 	unsigned int cluster_next;
@@ -64,6 +65,7 @@
 extern void show_swap_cache_info(void);
 extern int add_to_swap_cache(struct page *, unsigned long);
 extern void swap_duplicate(unsigned long);
+extern void swap_after_unlock_page (unsigned long entry);
 extern struct page * read_swap_cache_async(unsigned long, int);
 #define read_swap_cache(entry) read_swap_cache_async(entry, 1);
 
diff -u --recursive --new-file v2.1.93/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h
--- v2.1.93/linux/include/linux/umsdos_fs.h	Tue Feb 17 13:12:49 1998
+++ linux/include/linux/umsdos_fs.h	Wed Apr  8 18:17:22 1998
@@ -141,6 +141,7 @@
 extern struct file_operations  umsdos_file_operations;
 extern struct inode_operations umsdos_file_inode_operations;
 extern struct inode_operations umsdos_file_inode_operations_no_bmap;
+extern struct inode_operations umsdos_file_inode_operations_readpage;
 extern struct inode_operations umsdos_symlink_inode_operations;
 extern int init_umsdos_fs(void);
 
diff -u --recursive --new-file v2.1.93/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
--- v2.1.93/linux/include/linux/umsdos_fs.p	Tue Mar 17 22:18:15 1998
+++ linux/include/linux/umsdos_fs.p	Wed Apr  8 11:39:46 1998
@@ -31,7 +31,8 @@
 void kill_dentry (struct dentry *dentry);
 struct dentry *creat_dentry (const char *name,
 			     const int len,
-			     struct inode *inode);
+			     struct inode *inode,
+			     struct dentry *parent);
 ssize_t umsdos_file_write_kmem_real (struct file *filp,
 				const char *buf,
 				size_t  count,
diff -u --recursive --new-file v2.1.93/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.1.93/linux/include/linux/videodev.h	Fri Jan 23 18:10:32 1998
+++ linux/include/linux/videodev.h	Wed Apr  8 17:24:48 1998
@@ -17,14 +17,20 @@
 	int (*ioctl)(struct video_device *, unsigned int , void *);
 	int (*mmap)(struct video_device *, const char *, unsigned long);
 	int (*initialize)(struct video_device *);	
-	void *private;
+	void *priv;		/* Used to be 'private' but that upsets C++ */
 	int busy;
 	int minor;
 };
 
 extern int videodev_init(void);
 #define VIDEO_MAJOR	81
-extern int video_register_device(struct video_device *);
+extern int video_register_device(struct video_device *, int type);
+
+#define VFL_TYPE_GRABBER	0
+#define VFL_TYPE_VBI		1
+#define VFL_TYPE_RADIO		2
+#define VFL_TYPE_VTX		3
+
 extern void video_unregister_device(struct video_device *);
 #endif
 
@@ -39,10 +45,9 @@
 #define VID_TYPE_SCALES		128	/* Scalable */
 #define VID_TYPE_MONOCHROME	256	/* Monochrome only */
 
-
 struct video_capability
 {
-	char	name[32];
+	char name[32];
 	int type;
 	int channels;	/* Num channels */
 	int audios;	/* Num audio devices */
@@ -111,6 +116,11 @@
 #define VIDEO_AUDIO_BASS	8
 #define VIDEO_AUDIO_TREBLE	16	
 	char    name[16];
+#define VIDEO_SOUND_MONO	1
+#define VIDEO_SOUND_STEREO	2
+#define VIDEO_SOUND_LANG1	3
+#define VIDEO_SOUND_LANG2	4
+        __u16   mode;
 };
 
 struct video_clip
@@ -139,6 +149,12 @@
 	int	bytesperline;
 };
 
+struct video_mmap
+{
+	unsigned int frame;		/* Frame (0 or 1) for double buffer */
+	int height,width;
+	unsigned int format;
+};
 
 struct video_key
 {
@@ -163,6 +179,8 @@
 #define VIDIOCSFREQ		_IOW('v',15, unsigned long)		/* Set tuner */
 #define VIDIOCGAUDIO		_IOR('v',16, struct video_audio)	/* Get audio info */
 #define VIDIOCSAUDIO		_IOW('v',17, struct video_audio)	/* Audio source, mute etc */
+#define VIDIOCSYNC		_IO('v',18)				/* Sync with mmap grabbing */
+#define VIDIOCMCAPTURE		_IOW('v',19, struct video_mmap)		/* Grab frames */
 
 
 #define BASE_VIDIOCPRIVATE	192		/* 192-255 are private */
@@ -172,6 +190,8 @@
 #define VID_HARDWARE_QCAM_BW	2
 #define VID_HARDWARE_PMS	3
 #define VID_HARDWARE_QCAM_C	4
+#define VID_HARDWARE_PSEUDO	5
+#define VID_HARDWARE_SAA5249	6
 
 /*
  *	Initialiser list
diff -u --recursive --new-file v2.1.93/linux/include/linux/videotext.h linux/include/linux/videotext.h
--- v2.1.93/linux/include/linux/videotext.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/videotext.h	Wed Apr  8 17:24:48 1998
@@ -0,0 +1,144 @@
+#ifndef _VTX_H
+#define _VTX_H
+
+/* $Id: videotext.h,v 1.1 1998/03/30 22:26:39 alan Exp $
+ *
+ * Copyright (c) 1994-97 Martin Buck  <martin-2.buck@student.uni-ulm.de>
+ * Read COPYING for more information
+ *
+ */
+
+
+/*
+ *	Videotext ioctls
+ */
+#define VTXIOCGETINFO  0x7101  /* get version of driver & capabilities of vtx-chipset */
+#define VTXIOCCLRPAGE  0x7102  /* clear page-buffer */
+#define VTXIOCCLRFOUND 0x7103  /* clear bits indicating that page was found */
+#define VTXIOCPAGEREQ  0x7104  /* search for page */
+#define VTXIOCGETSTAT  0x7105  /* get status of page-buffer */
+#define VTXIOCGETPAGE  0x7106  /* get contents of page-buffer */
+#define VTXIOCSTOPDAU  0x7107  /* stop data acquisition unit */
+#define VTXIOCPUTPAGE  0x7108  /* display page on TV-screen */
+#define VTXIOCSETDISP  0x7109  /* set TV-mode */
+#define VTXIOCPUTSTAT  0x710a  /* set status of TV-output-buffer */
+#define VTXIOCCLRCACHE 0x710b  /* clear cache on VTX-interface (if avail.) */
+#define VTXIOCSETVIRT  0x710c  /* turn on virtual mode (this disables TV-display) */
+
+
+/* 
+ *	Definitions for VTXIOCGETINFO
+ */
+ 
+#define SAA5243 0
+#define SAA5246 1
+#define SAA5249 2
+#define SAA5248 3
+#define XSTV5346 4
+
+typedef struct {
+	int version_major, version_minor;	/* version of driver; if version_major changes, driver */
+						/* is not backward compatible!!! CHECK THIS!!! */  
+	int numpages;				/* number of page-buffers of vtx-chipset */
+	int cct_type;				/* type of vtx-chipset (SAA5243, SAA5246, SAA5248 or
+  						 * SAA5249) */
+}
+vtx_info_t;
+
+
+/*
+ *	Definitions for VTXIOC{CLRPAGE,CLRFOUND,PAGEREQ,GETSTAT,GETPAGE,STOPDAU,PUTPAGE,SETDISP}
+ */
+
+#define MIN_UNIT   (1<<0)
+#define MIN_TEN    (1<<1)
+#define HR_UNIT    (1<<2)
+#define HR_TEN     (1<<3)
+#define PG_UNIT    (1<<4)
+#define PG_TEN     (1<<5)
+#define PG_HUND    (1<<6)
+#define PGMASK_MAX (1<<7)
+#define PGMASK_PAGE (PG_HUND | PG_TEN | PG_UNIT)
+#define PGMASK_HOUR (HR_TEN | HR_UNIT)
+#define PGMASK_MINUTE (MIN_TEN | MIN_UNIT)
+
+typedef struct 
+{
+	int page;	/* number of requested page (hexadecimal) */
+	int hour;	/* requested hour (hexadecimal) */
+	int minute;	/* requested minute (hexadecimal) */
+	int pagemask;	/* mask defining which values of the above are set */
+	int pgbuf;	/* buffer where page will be stored */
+	int start;	/* start of requested part of page */
+	int end;	/* end of requested part of page */
+	void *buffer;	/* pointer to beginning of destination buffer */
+}
+vtx_pagereq_t;
+
+
+/*
+ *	Definitions for VTXIOC{GETSTAT,PUTSTAT}
+ */
+ 
+#define VTX_PAGESIZE (40 * 24)
+#define VTX_VIRTUALSIZE (40 * 49)
+
+typedef struct 
+{
+	int pagenum;			/* number of page (hexadecimal) */
+	int hour;			/* hour (hexadecimal) */
+	int minute;			/* minute (hexadecimal) */
+	int charset;			/* national charset */
+	unsigned delete : 1;		/* delete page (C4) */
+	unsigned headline : 1;		/* insert headline (C5) */
+	unsigned subtitle : 1;		/* insert subtitle (C6) */
+	unsigned supp_header : 1;	/* suppress header (C7) */
+	unsigned update : 1;		/* update page (C8) */
+	unsigned inter_seq : 1;		/* interrupted sequence (C9) */
+	unsigned dis_disp : 1;		/* disable/suppress display (C10) */
+	unsigned serial : 1;		/* serial mode (C11) */
+	unsigned notfound : 1;		/* /FOUND */
+	unsigned pblf : 1;		/* PBLF */
+	unsigned hamming : 1;		/* hamming-error occured */
+}
+vtx_pageinfo_t;
+
+
+/*
+ *	Definitions for VTXIOCSETDISP
+ */
+ 
+typedef enum { 
+	DISPOFF, DISPNORM, DISPTRANS, DISPINS, INTERLACE_OFFSET 
+} vtxdisp_t;
+
+
+
+/*
+ *	Tuner ioctls
+ */
+ 
+#define TUNIOCGETINFO  0x7201  /* get version of driver & capabilities of tuner */
+#define TUNIOCRESET    0x7202  /* reset tuner */
+#define TUNIOCSETFREQ  0x7203  /* set tuning frequency (unit: kHz) */
+#define TUNIOCGETFREQ  0x7204  /* get tuning frequency (unit: kHz) */
+#define TUNIOCSETCHAN  0x7205  /* set tuning channel */
+#define TUNIOCGETCHAN  0x7206  /* get tuning channel */
+
+
+typedef struct 
+{
+	int version_major, version_minor;	/* version of driver; if version_major changes, driver */
+						/* is not backward compatible!!! CHECK THIS!!! */  
+	unsigned freq : 1;			/* tuner can be set to given frequency */
+	unsigned chan : 1;			/* tuner stores several channels */
+	unsigned scan : 1;			/* tuner supports scanning */
+	unsigned autoscan : 1;		/* tuner supports scanning with automatic stop */
+	unsigned afc : 1;			/* tuner supports AFC */
+	unsigned dummy1, dummy2, dummy3, dummy4, dummy5, dummy6, dummy7, dummy8, dummy9, dummy10,
+ 		dummy11 : 1;
+	int dummy12, dummy13, dummy14, dummy15, dummy16, dummy17, dummy18, dummy19;
+} tuner_info_t;
+
+
+#endif /* _VTX_H */
diff -u --recursive --new-file v2.1.93/linux/include/net/ip.h linux/include/net/ip.h
--- v2.1.93/linux/include/net/ip.h	Mon Apr  6 17:41:01 1998
+++ linux/include/net/ip.h	Wed Apr  8 18:17:32 1998
@@ -142,15 +142,7 @@
 	skb->protocol = __constant_htons(ETH_P_IP);
 
 	if (hh) {
-#ifdef __alpha__
-		/* Alpha has disguisting memcpy. Help it. */
-	        u64 *aligned_hdr = (u64*)(skb->data - 16);
-		u64 *aligned_hdr0 = hh->hh_data;
-		aligned_hdr[0] = aligned_hdr0[0];
-		aligned_hdr[1] = aligned_hdr0[1];
-#else
 		memcpy(skb->data - 16, hh->hh_data, 16);
-#endif
 	        skb_push(skb, dev->hard_header_len);
 		return hh->hh_output(skb);
 	} else if (dst->neighbour)
diff -u --recursive --new-file v2.1.93/linux/init/main.c linux/init/main.c
--- v2.1.93/linux/init/main.c	Mon Apr  6 17:41:01 1998
+++ linux/init/main.c	Wed Apr  8 18:10:01 1998
@@ -70,7 +70,7 @@
 extern long console_init(long, long);
 extern void sock_init(void);
 extern void uidcache_init(void);
-extern long mca_init(long, long);
+extern void mca_init(void);
 extern long sbus_init(long, long);
 extern long powermac_init(unsigned long, unsigned long);
 extern void sysctl_init(void);
@@ -1012,6 +1012,12 @@
 	sched_init();
 	time_init();
 	parse_options(command_line);
+
+	/*
+	 * HACK ALERT! This is early. We're enabling the console before
+	 * we've done PCI setups etc, and console_init() must be aware of
+	 * this. But we do want output early, in case something goes wrong.
+	 */
 	memory_start = console_init(memory_start,memory_end);
 #ifdef CONFIG_MODULES
 	init_modules();
@@ -1027,14 +1033,6 @@
 	}
 #endif
 
-/*
- * HACK ALERT! This is early. We're enabling the console before
- * we've done PCI setups etc, and console_init() must be aware of
- * this. But we do want output early, in case something goes wrong.
- */
-#if HACK
-	memory_start = console_init(memory_start,memory_end);
-#endif
 	memory_start = kmem_cache_init(memory_start, memory_end);
 	sti();
 	calibrate_delay();
diff -u --recursive --new-file v2.1.93/linux/kernel/kmod.c linux/kernel/kmod.c
--- v2.1.93/linux/kernel/kmod.c	Thu Mar 26 15:57:06 1998
+++ linux/kernel/kmod.c	Tue Apr  7 08:05:05 1998
@@ -15,8 +15,8 @@
 int kmod_unload_delay = 60;
 char modprobe_path[256] = "/sbin/modprobe";
 static char module_name[64] = "";
-static char * argv[] = { "modprobe", "-k", module_name, NULL, };
-static char * envp[] = { "HOME=/", "TERM=linux", NULL, };
+static char * argv[] = { modprobe_path, "-s", "-k", module_name, NULL };
+static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };
 
 /*
 	kmod_queue synchronizes the kmod thread and the rest of the system
@@ -27,10 +27,23 @@
 static struct timer_list kmod_unload_timer;
 
 /*
+	It is not easy to implement a full fork in kernel-space on some
+	systems (Alpha), and it is not necessary for us here.  This is 
+	a new thread that does the exec.
+*/
+static int kmod_exec_modprobe(void * data)
+{
+	sigemptyset(&current->blocked);
+	execve(modprobe_path, argv, envp);
+	printk(KERN_ERR "kmod: failed to load module %s\n", module_name);
+	return 0;
+}
+
+/*
 	kmod_thread is the thread that does most of the work.  kmod_unload and
 	request_module tell it to wake up and do work.
 */
-int kmod_thread(void * data)
+static int kmod_thread(void * data)
 {
 	int pid;
 
@@ -60,24 +73,13 @@
 		if (module_name[0] == '\0') {
 			delete_module(NULL);
 		} else {
-			pid = fork();
+			pid = kernel_thread(kmod_exec_modprobe, NULL, SIGCHLD);
 			if (pid > 0) {
 				waitpid(pid, NULL, 0);
 				module_name[0] = '\0';
 				wake_up(&kmod_queue);
-			} else
-			if (pid == 0) {
-
-				/*
-					Call modprobe with module_name.  If execve returns,
-					print out an error.
-				*/
-				execve(modprobe_path, argv, envp);
-
-				printk("kmod: failed to load module %s\n", module_name);
-				_exit(0);
 			} else {
-				printk("error, fork failed in kmod\n");
+				printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid);
 			}
 		}
 	}
@@ -104,7 +106,7 @@
 
 int kmod_init(void)
 {
-	printk ("Starting kmod\n");
+	printk("Starting kmod\n");
 
 	kernel_thread(kmod_thread, NULL, 0);
 
diff -u --recursive --new-file v2.1.93/linux/mm/page_io.c linux/mm/page_io.c
--- v2.1.93/linux/mm/page_io.c	Tue Mar 10 10:03:36 1998
+++ linux/mm/page_io.c	Mon Apr  6 17:48:34 1998
@@ -28,6 +28,8 @@
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
 
+static struct wait_queue * lock_queue = NULL;
+
 /*
  * Reads or writes a swap page.
  * wait=1: start I/O and wait for completion. wait=0: start asynchronous I/O.
@@ -87,6 +89,12 @@
 		return;
 	}
 	
+	/* Make sure we are the only process doing I/O with this swap page. */
+	while (test_and_set_bit(offset,p->swap_lockmap)) {
+		run_task_queue(&tq_disk);
+		sleep_on(&lock_queue);
+	}
+	
 	if (rw == READ) {
 		clear_bit(PG_uptodate, &page->flags);
 		kstat.pswpin++;
@@ -115,6 +123,7 @@
 		if (!wait) {
 			set_bit(PG_free_after, &page->flags);
 			set_bit(PG_decr_after, &page->flags);
+			set_bit(PG_swap_unlock_after, &page->flags);
 			atomic_inc(&nr_async_pages);
 		}
 		ll_rw_page(rw,p->swap_device,offset,buf);
@@ -173,11 +182,36 @@
 		printk("rw_swap_page: no swap file or device\n");
 
 	atomic_dec(&page->count);
+	if (offset && !test_and_clear_bit(offset,p->swap_lockmap))
+		printk("rw_swap_page: lock already cleared\n");
+	wake_up(&lock_queue);
 #ifdef DEBUG_SWAP
 	printk ("DebugVM: %s_swap_page finished on page %p (count %d)\n",
 		(rw == READ) ? "read" : "write", 
 		buf, atomic_read(&page->count));
 #endif
+}
+
+/* This is run when asynchronous page I/O has completed. */
+void swap_after_unlock_page (unsigned long entry)
+{
+	unsigned long type, offset;
+	struct swap_info_struct * p;
+
+	type = SWP_TYPE(entry);
+	if (type >= nr_swapfiles) {
+		printk("swap_after_unlock_page: bad swap-device\n");
+		return;
+	}
+	p = &swap_info[type];
+	offset = SWP_OFFSET(entry);
+	if (offset >= p->max) {
+		printk("swap_after_unlock_page: weirdness\n");
+		return;
+	}
+	if (!test_and_clear_bit(offset,p->swap_lockmap))
+		printk("swap_after_unlock_page: lock already cleared\n");
+	wake_up(&lock_queue);
 }
 
 /*
diff -u --recursive --new-file v2.1.93/linux/mm/simp.c linux/mm/simp.c
--- v2.1.93/linux/mm/simp.c	Thu Jan 15 20:44:18 1998
+++ linux/mm/simp.c	Tue Apr  7 08:05:05 1998
@@ -70,7 +70,8 @@
 	/* next cache line */
 	struct header * usable_list;
 	spinlock_t lock;
-	char fill[sizeof(void*) - sizeof(spinlock_t)];
+	/* This value is negative on Alpha SMP.  */
+	/* char fill[sizeof(void*) - sizeof(spinlock_t)]; */
 	long real_size;
 	long max_elems;
 	structor again_ctor;
diff -u --recursive --new-file v2.1.93/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.93/linux/mm/swapfile.c	Tue Mar 10 10:03:36 1998
+++ linux/mm/swapfile.c	Mon Apr  6 17:48:34 1998
@@ -52,6 +52,8 @@
 			offset = si->cluster_next++;
 			if (si->swap_map[offset])
 				continue;
+			if (test_bit(offset, si->swap_lockmap))
+				continue;
 			si->cluster_nr--;
 			goto got_page;
 		}
@@ -60,6 +62,8 @@
 	for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) {
 		if (si->swap_map[offset])
 			continue;
+		if (test_bit(offset, si->swap_lockmap))
+			continue;
 		si->lowest_bit = offset;
 got_page:
 		si->swap_map[offset] = 1;
@@ -424,6 +428,8 @@
 	p->swap_device = 0;
 	vfree(p->swap_map);
 	p->swap_map = NULL;
+	free_page((long) p->swap_lockmap);
+	p->swap_lockmap = NULL;
 	p->flags = 0;
 	err = 0;
 out:
@@ -483,7 +489,6 @@
 	int error = -EPERM;
 	struct file filp;
 	static int least_priority = 0;
-	unsigned char *avail_map = 0;
 
 	lock_kernel();
 	if (!suser())
@@ -501,6 +506,7 @@
 	p->swap_file = NULL;
 	p->swap_device = 0;
 	p->swap_map = NULL;
+	p->swap_lockmap = NULL;
 	p->lowest_bit = 0;
 	p->highest_bit = 0;
 	p->cluster_nr = 0;
@@ -543,24 +549,24 @@
 		}
 	} else if (!S_ISREG(swap_dentry->d_inode->i_mode))
 		goto bad_swap;
-	avail_map = (unsigned char *) get_free_page(GFP_USER);
-	if (!avail_map) {
+	p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER);
+	if (!p->swap_lockmap) {
 		printk("Unable to start swapping: out of memory :-)\n");
 		error = -ENOMEM;
 		goto bad_swap;
 	}
-	rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) avail_map);
-	if (memcmp("SWAP-SPACE",avail_map+PAGE_SIZE-10,10)) {
+	rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) p->swap_lockmap);
+	if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) {
 		printk("Unable to find swap-space signature\n");
 		error = -EINVAL;
 		goto bad_swap;
 	}
-	memset(avail_map+PAGE_SIZE-10,0,10);
+	memset(p->swap_lockmap+PAGE_SIZE-10,0,10);
 	j = 0;
 	p->lowest_bit = 0;
 	p->highest_bit = 0;
 	for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
-		if (test_bit(i,avail_map)) {
+		if (test_bit(i,p->swap_lockmap)) {
 			if (!p->lowest_bit)
 				p->lowest_bit = i;
 			p->highest_bit = i;
@@ -579,12 +585,13 @@
 		goto bad_swap;
 	}
 	for (i = 1 ; i < p->max ; i++) {
-		if (test_bit(i,avail_map))
+		if (test_bit(i,p->swap_lockmap))
 			p->swap_map[i] = 0;
 		else
 			p->swap_map[i] = 0x80;
 	}
 	p->swap_map[0] = 0x80;
+	memset(p->swap_lockmap,0,PAGE_SIZE);
 	p->flags = SWP_WRITEOK;
 	p->pages = j;
 	nr_swap_pages += j;
@@ -611,15 +618,15 @@
 	if(filp.f_op && filp.f_op->release)
 		filp.f_op->release(filp.f_dentry->d_inode,&filp);
 bad_swap_2:
+	free_page((long) p->swap_lockmap);
 	vfree(p->swap_map);
 	dput(p->swap_file);
 	p->swap_device = 0;
 	p->swap_file = NULL;
 	p->swap_map = NULL;
+	p->swap_lockmap = NULL;
 	p->flags = 0;
 out:
-	if (avail_map)
-		free_page((long) avail_map);
 	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.93/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.93/linux/net/ipv4/tcp_ipv4.c	Mon Apr  6 17:41:01 1998
+++ linux/net/ipv4/tcp_ipv4.c	Tue Apr  7 07:48:54 1998
@@ -1483,7 +1483,7 @@
 		skb->csum = csum_partial((char *)th, len, 0);
 	case CHECKSUM_HW:
 		if (tcp_v4_check(th,len,skb->nh.iph->saddr,skb->nh.iph->daddr,skb->csum)) {
-			printk(KERN_DEBUG "TCPv4 bad checksum from %d.%d.%d.%d:%04x to %d.%d.%d.%d:%04x, "
+			printk(KERN_DEBUG "TCPv4 bad checksum from %ld.%ld.%ld.%ld:%04x to %ld.%ld.%ld.%ld:%04x, "
 			       "len=%d/%d/%d\n",
  			       NIPQUAD(ntohl(skb->nh.iph->saddr)),
 			       ntohs(th->source), 
