Index: oldkernel/linux/Documentation/Configure.help
diff -u linux/Documentation/Configure.help:1.6 linux/Documentation/Configure.help:1.7
--- linux/Documentation/Configure.help:1.6	Thu Jun  1 16:47:27 2000
+++ linux/Documentation/Configure.help	Thu Jun  1 16:52:14 2000
@@ -10169,6 +10169,11 @@
   of PCI sound chips.  These include the Maestro 1, Maestro 2, and
   Maestro 2E.  See Documentation/sound/Maestro for more details.
 
+EMU10K1 derived boards
+CONFIG_SOUND_EMU10k1
+  Say Y or M if you have a Creative SBLive! sound card, as this
+  is the only card currently supported by this driver.
+
 Are you using a crosscompiler
 CONFIG_CROSSCOMPILE
   Say Y here if you are compiling the kernel on a different
Index: oldkernel/linux/Documentation/sound/EMU10K1
diff -u /dev/null linux/Documentation/sound/EMU10K1:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/Documentation/sound/EMU10K1	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,75 @@
+Installation Instructions for Creative EMU10K1 drivers (v0.4)
+English v1.0
+-------------------------------------------------------------
+
+Card support
+------------
+- Creative Sound Blaster Live!
+
+Features
+--------
+- Open Sound System (OSS) compatible
+- Full duplex wave playback/recording functionality (/dev/dsp)
+- Simultaneous wave playback streams
+- Analog mixer (AC97) support (/dev/mixer)
+- Sound status reporting (/dev/sndstat)
+- MIDI UART support (/dev/midi)
+- Joystick interface support (>= 2.2.x kernels only)
+- Supports multiple EMU10K1-based cards
+
+
+Requirements
+------------
+- The kernel must be compiled:
+  - With loadable modules support            (CONFIG_MODULES = y)
+  - With soundcard support as a module       (CONFIG_SOUND = m)
+  - Without any integrated soundcard drivers (CONFIG_SOUND_* = n)
+- "PnP-compatible OS installed" option in BIOS must be disabled
+- Recommended system configuration: Min. 200 MHz Pentium-class w/ 32 MB RAM
+- Kernel headers matching the kernel for which you are compiling the 
+  driver.
+
+
+Compilation
+-----------
+To compile the driver, simply type "make" in the main
+directory.
+Make sure the "KERNELVERSION", "SMPSUPP" and "MODVERSIONS"
+options are correctly detected, if not edit the "Makefile"
+and manually override them.
+This will generate the file "emu10k1.o".
+
+Installation
+------------
+1. As root type "make install".
+2. Add a new reference to the driver in /etc/conf.modules:
+     (eg. "alias sound emu10k1" or "alias char-major-14 emu10k1")
+3. Play some sound. The module should be auto-loaded.
+
+If this doesn't work:
+1. Determine your kernel sound modules installation location
+     (usually /lib/modules/2.x.y/misc)
+2. Copy the driver to that location as emu10k1.o
+     (eg. /lib/modules/2.x.y/misc/emu10k1.o)
+3. Unload all existing soundcard drivers, including soundcore
+4. Remove all old soundcard references from /etc/conf.modules
+5. Add a new reference to the driver in /etc/conf.modules:
+     (eg. "alias sound emu10k1" or "alias char-major-14 emu10k1")
+6. Generate module dependencies: "depmod -a"
+7. Load the driver: "modprobe emu10k1"
+
+Note for Debians' users: use /etc/modutils directory,
+   create file emu10k1 here with the same content as is suggested in
+   the paragraph (5.) and run update-modules afterwards - this
+   will create the correct /etc/modules.conf file)
+
+Joystick support
+----------------
+1. Load the driver with parameter "joystick=0x200"
+     eg. insmod emu10k1 joystick=0x200
+2. Load base joystick driver
+     eg. insmod joystick
+3. Load specific joystick driver
+     eg. insmod joy-analog (If you are using an analog joystick)
+
+Read /usr/src/linux/Documentation/joystick.txt for more info.
Index: oldkernel/linux/drivers/sound/Config.in
diff -u linux/drivers/sound/Config.in:1.1.1.1 linux/drivers/sound/Config.in:1.2
--- linux/drivers/sound/Config.in:1.1.1.1	Wed May 31 12:33:52 2000
+++ linux/drivers/sound/Config.in	Thu Jun  1 16:52:15 2000
@@ -30,6 +30,7 @@
 fi
 
 dep_tristate 'ESS Maestro' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
+dep_tristate 'EMU10K1' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    dep_tristate 'ESS Solo1 (Experimental)' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
Index: oldkernel/linux/drivers/sound/Makefile
diff -u linux/drivers/sound/Makefile:1.1.1.1 linux/drivers/sound/Makefile:1.2
--- linux/drivers/sound/Makefile:1.1.1.1	Wed May 31 12:33:52 2000
+++ linux/drivers/sound/Makefile	Thu Jun  1 16:52:15 2000
@@ -10,13 +10,17 @@
 SUB_DIRS	:= 
 MOD_SUB_DIRS	:=
 MOD_IN_SUB_DIRS	:=
-ALL_SUB_DIRS	:= $(SUB_DIRS) lowlevel
+ALL_SUB_DIRS	:= $(SUB_DIRS) lowlevel emu10k1
 
 ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
     SUB_DIRS		+= lowlevel
     MOD_IN_SUB_DIRS	+= lowlevel
 endif
 
+ifeq ($(CONFIG_SOUND_EMU10K1),m)
+    SUB_DIRS		+= emu10k1
+    MOD_IN_SUB_DIRS	+= emu10k1
+endif
 
 
 # All of the (potential) objects that export symbols.
@@ -160,6 +164,10 @@
 
 ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
     L_OBJS	+= lowlevel/lowlevel.o
+endif
+
+ifeq ($(CONFIG_SOUND_EMU10K1),y)
+	M_OBJS	+= emu10k1/emu10k1.o
 endif
 
 include $(TOPDIR)/Rules.make
Index: oldkernel/linux/drivers/sound/emu10k1/8010.h
diff -u /dev/null linux/drivers/sound/emu10k1/8010.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/8010.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,602 @@
+/*
+ **********************************************************************
+ *     8010.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date		    Author	    Summary of changes
+ *     ----		    ------	    ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox	    Cleaned of 8bit chars, DOS
+ *					    line endings
+ *     December 8, 1999     Jon Taylor	    Added lots of new register info
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ *
+ **********************************************************************
+ */
+
+
+#ifndef _8010_H
+#define _8010_H
+
+/* ------------------- DEFINES -------------------- */
+
+#define EMUPAGESIZE	4096
+#define MAXREQVOICES	8
+#define MAXPAGES	(16384 * 64 / PAGE_SIZE)	/* WAVEOUT_MAXBUFSIZE * NUM_G / PAGE_SIZE */
+#define RESERVED	0
+#define NUM_MIDI	16
+#define NUM_G		64		/* use all channels */
+#define NUM_FXSENDS	4
+
+
+#define TMEMSIZE	256*1024
+#define TMEMSIZEREG	4
+
+#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL))
+
+/************************************************************************************************/
+/* PCI function 0 registers, address = <val> + PCIBASE0						*/
+/************************************************************************************************/
+
+#define PTR			0x00		/* Indexed register set pointer register	*/
+#define PTR_CHANNELNUM_MASK	0x0000003f	/* For each per-channel register, indicates the	*/
+/* channel number of the specific register to be*/
+/* accessed.  For non per-channel registers, the*/
+/* value should be set to zero.			*/
+#define PTR_ADDRESS_MASK	0x07ff0000	/* Register index				*/
+
+#define DATA			0x04		/* Indexed register set data register		*/
+
+#define IPR			0x08		/* Global interrupt pending register		*/
+#define IPR_SAMPLERATETRACKER	0x01000000	/* Sample rate tracker lock status change	*/
+#define IPR_FXDSP		0x00800000	/* Enable FX DSP interrupts			*/
+#define IPR_FORCEINT		0x00400000	/* Force Sound Blaster interrupt		*/
+#define IPR_PCIERROR		0x00200000	/* PCI bus error				*/
+#define IPR_VOLINCR		0x00100000	/* Volume increment button pressed		*/
+#define IPR_VOLDECR		0x00080000	/* Volume decrement button pressed		*/
+#define IPR_MUTE		0x00040000	/* Mute button pressed				*/
+#define IPR_MICBUFFULL		0x00020000	/* Microphone buffer full			*/
+#define IPR_MICBUFHALFFULL	0x00010000	/* Microphone buffer half full			*/
+#define IPR_ADCBUFFULL		0x00008000	/* ADC buffer full				*/
+#define IPR_ADCBUFHALFFULL	0x00004000	/* ADC buffer half full				*/
+#define IPR_EFXBUFFULL		0x00002000	/* Effects buffer full				*/
+#define IPR_EFXBUFHALFFULL	0x00001000	/* Effects buffer half full			*/
+#define IPR_GPSPDIFSTATUSCHANGE	0x00000800	/* GPSPDIF channel status change		*/
+#define IPR_CDROMSTATUSCHANGE	0x00000400	/* CD-ROM channel status change			*/
+#define IPR_INTERVALTIMER	0x00000200	/* Interval timer terminal count		*/
+#define IPR_MIDITRANSBUFEMPTY	0x00000100	/* MIDI UART transmit buffer empty		*/
+#define IPR_MIDIRECVBUFEMPTY	0x00000080	/* MIDI UART receive buffer empty		*/
+#define IPR_CHANNELLOOP		0x00000040	/* One or more channel loop interrupts pending	*/
+#define IPR_CHANNELNUMBERMASK	0x0000003f	/* When IPR_CHANNELLOOP is set, indicates the	*/
+/* Highest set channel in [finish]		*/
+
+#define INTE			0x0c		/* Interrupt enable register			*/
+#define INTE_VIRTUALSB_MASK	0xc0000000	/* Virtual Soundblaster I/O port capture	*/
+#define INTE_VIRTUALSB_220	0x00000000	/* Capture at I/O base address 0x220-0x22f	*/
+#define INTE_VIRTUALSB_240	0x40000000	/* Capture at I/O base address 0x240		*/
+#define INTE_VIRTUALSB_260	0x80000000	/* Capture at I/O base address 0x260		*/
+#define INTE_VIRTUALSB_280	0xc0000000	/* Capture at I/O base address 0x280		*/
+#define INTE_VIRTUALMPU_MASK	0x30000000	/* Virtual MPU I/O port capture			*/
+#define INTE_VIRTUALMPU_300	0x00000000	/* Capture at I/O base address 0x300-0x301	*/
+#define INTE_VIRTUALMPU_310	0x10000000	/* Capture at I/O base address 0x310		*/
+#define INTE_VIRTUALMPU_320	0x20000000	/* Capture at I/O base address 0x320		*/
+#define INTE_VIRTUALMPU_330	0x30000000	/* Capture at I/O base address 0x330		*/
+#define INTE_MASTERDMAENABLE	0x08000000	/* Master DMA emulation at 0x000-0x00f		*/
+#define INTE_SLAVEDMAENABLE	0x04000000	/* Slave DMA emulation at 0x0c0-0x0df		*/
+#define INTE_MASTERPICENABLE	0x02000000	/* Master PIC emulation at 0x020-0x021		*/
+#define INTE_SLAVEPICENABLE	0x01000000	/* Slave PIC emulation at 0x0a0-0x0a1		*/
+#define INTE_VSBENABLE		0x00800000	/* Enable virtual Soundblaster			*/
+#define INTE_ADLIBENABLE	0x00400000	/* Enable AdLib emulation at 0x388-0x38b	*/
+#define INTE_MPUENABLE		0x00200000	/* Enable virtual MPU				*/
+#define INTE_FORCEINT		0x00100000	/* Continuously assert INTAN			*/
+
+#define INTE_MRHANDENABLE	0x00080000	/* Enable the "Mr. Hand" logic			*/
+// Not implemented or relevant under Linux.  It will cause odd behaviour
+// and may cause seg faults if implemented
+
+#define INTE_SAMPLERATETRACKER	0x00002000	/* Enable sample rate tracker interrupts MUST BE ENABLED */
+#define INTE_FXDSPENABLE	0x00001000	/* Enable FX DSP interrupts			*/
+#define INTE_PCIERRORENABLE	0x00000800	/* Enable PCI bus error interrupts		*/
+#define INTE_VOLINCRENABLE	0x00000400	/* Enable volume increment button interrupts	*/
+#define INTE_VOLDECRENABLE	0x00000200	/* Enable volume decrement button interrupts	*/
+#define INTE_MUTEENABLE		0x00000100	/* Enable mute button interrupts		*/
+#define INTE_MICBUFENABLE	0x00000080	/* Enable microphone buffer interrupts		*/
+#define INTE_ADCBUFENABLE	0x00000040	/* Enable ADC buffer interrupts			*/
+#define INTE_EFXBUFENABLE	0x00000020	/* Enable Effects buffer interrupts		*/
+#define INTE_GPSPDIFENABLE	0x00000010	/* Enable GPSPDIF status interrupts		*/
+#define INTE_CDSPDIFENABLE	0x00000008	/* Enable CDSPDIF status interrupts		*/
+#define INTE_INTERVALTIMERENB	0x00000004	/* Enable interval timer interrupts		*/
+#define INTE_MIDITXENABLE	0x00000002	/* Enable MIDI transmit-buffer-empty interrupts	*/
+#define INTE_MIDIRXENABLE	0x00000001	/* Enable MIDI receive-buffer-empty interrupts	*/
+
+#define WC			0x10		/* Wall Clock register				*/
+#define WC_SAMPLECOUNTER_MASK	0x03FFFFC0	/* Sample periods elapsed since reset		*/
+#define WC_SAMPLECOUNTER	0x14060010
+#define WC_CURRENTCHANNEL	0x0000003F	/* Channel [0..63] currently being serviced	*/
+
+#define HCFG			0x14		/* Hardware config register			*/
+#define HCFG_LEGACYFUNC_MASK	0xe0000000	/* Legacy function number - DO NOT USE		*/
+#define HCFG_LEGACYFUNC_MPU	0x00000000	/* Legacy MPU - DO NOT USE under Linux		*/
+#define HCFG_LEGACYFUNC_SB	0x40000000	/* Legacy SB - DO NOT USE under Linux		*/
+#define HCFG_LEGACYFUNC_AD	0x60000000	/* Legacy AD - DO NOT USE under Linux		*/
+#define HCFG_LEGACYFUNC_MPIC	0x80000000	/* Legacy MPIC - DO NOT USE under Linux		*/
+#define HCFG_LEGACYFUNC_MDMA	0x90000000	/* Legacy MDMA - DO NOT USE under Linux		*/
+#define HCFG_LEGACYFUNC_SPCI	0xa0000000	/* Legacy SPCI - DO NOT USE under Linux		*/
+#define HCFG_LEGACYFUNC_SDMA	0xe0000000	/* Legacy SDMA - DO NOT USE under Linux		*/
+#define HCFG_IOCAPTUREADDR	0x1f000000	/* The 4 LSBs of the captured I/O address.  DO NOT USE under Linux	*/
+#define HCFG_LEGACYWRITE	0x00800000	/* 1 = write, 0 = read - DO NOT USE under Linux	*/
+#define HCFG_LEGACYWORD		0x00400000	/* 1 = word, 0 = byte - DO NOT USE under Linux	*/
+#define HCFG_LEGACYINT		0x00200000	/* 1 = legacy event captured. Write 1 to clear. DO NOT USE under Linux */
+#define HCFG_CODECFORMAT_MASK	0x00070000	/* CODEC format					*/
+#define HCFG_CODECFORMAT_AC97	0x00000000	/* AC97 CODEC format -- Primary Output		*/
+#define HCFG_CODECFORMAT_I2S	0x00020000	/* I2S CODEC format -- Secondary (Rear) Output	*/
+#define HCFG_GPINPUT0		0x00004000	/* External pin112				*/
+#define HCFG_GPINPUT1		0x00002000	/* External pin110				*/
+#define HCFG_GPOUTPUTMASK	0x00001c00	/* External pins which may be controlled	*/
+#define HCFG_JOYENABLE		0x00000200	/* Joystick enable				*/
+#define HCFG_PHASETRACKENABLE	0x00000100	/* Phase tracking enable			*/
+#define HCFG_AC3ENABLE_MASK	0x0x0000e0	/* AC3 async input control - Not implemented	*/
+#define HCFG_AC3ENABLE_ZVIDEO	0x00000080	/* Channels 0 and 1 replace ZVIDEO		*/
+#define HCFG_AC3ENABLE_CDSPDIF	0x00000040	/* Channels 0 and 1 replace CDSPDIF		*/
+#define HCFG_AUTOMUTE		0x00000010	/* When set, the async sample rate convertors	*/
+/* will automatically mute their output when	*/
+/* they are not rate-locked to the external	*/
+/* audio source					*/
+#define HCFG_LOCKSOUNDCACHE	0x00000008	/* 1 = Cancel bustmaster accesses to soundcache - Do not adjust this */
+#define HCFG_LOCKTANKCACHE	0x00000004	/* 1 = Cancel bustmaster accesses to tankcache - Do not adjust this */
+#define HCFG_MUTEBUTTONENABLE	0x00000002	/* 1 = Enable master mute button		*/
+#define HCFG_AUDIOENABLE	0x00000001	/* 0 = CODECs transmit zero-valued samples	*/
+
+#define MUDATA			0x18		/* MPU401 data register 			*/
+
+#define MUCMD			0x19		/* MPU401 command register			*/
+#define MUCMD_RESET		0xff		/* RESET command				*/
+#define MUCMD_ENTERUARTMODE	0x3f		/* Enter_UART_mode command			*/
+
+#define MUSTAT			MUCMD		/* MPU401 status register			*/
+#define MUSTAT_IRDYN		0x80		/* 0 = MIDI data or command ACK			*/
+#define MUSTAT_ORDYN		0x40		/* 0 = MUDATA can accept a command or data	*/
+
+#define TIMR			0x1a		/* Timer terminal count register		*/
+#define TIMR_RATE_MASK		0x000003ff	/* Timer interrupt rate in sample periods	*/
+#define TIMR_RATE		0x0a00001a
+
+#define AC97DATA		0x1c		/* AC97 indexed register set data register	*/
+
+#define AC97ADDRESS		0x1e		/* AC97 indexed register set address register	*/
+#define AC97ADDRESS_READY	0x80		/* Read-only bit, reflects CODEC READY signal	*/
+#define AC97ADDRESS_ADDRESS	0x7f		/* Address of indexed AC97 register		*/
+
+/************************************************************************************************/
+/* PCI function 1 registers, address = <val> + PCIBASE1						*/
+/************************************************************************************************/
+
+#define JOYSTICK1		0x00		/* Analog joystick port register		*/
+#define JOYSTICK2		0x01		/* Analog joystick port register		*/
+#define JOYSTICK3		0x02		/* Analog joystick port register		*/
+#define JOYSTICK4		0x03		/* Analog joystick port register		*/
+#define JOYSTICK5		0x04		/* Analog joystick port register		*/
+#define JOYSTICK6		0x05		/* Analog joystick port register		*/
+#define JOYSTICK7		0x06		/* Analog joystick port register		*/
+#define JOYSTICK8		0x07		/* Analog joystick port register		*/
+#define JOYSTICK_BUTTONS	0x0f		/* Joystick button data				*/
+#define JOYSTICK_COMPARATOR	0xf0		/* Joystick comparator data			*/
+
+/********************************************************************************************************/
+/* AC97 pointer-offset register set, accessed through the AC97ADDRESS and AC97DATA registers		*/
+/********************************************************************************************************/
+
+#define AC97_RESET		0x00
+#define AC97_MASTERVOLUME	0x02		/* Master volume					*/
+#define AC97_HEADPHONEVOLUME	0x04		/* Headphone volume					*/
+#define AC97_MASTERVOLUMEMONO	0x06		/* Mast volume mono					*/
+#define AC97_MASTERTONE		0x08
+#define AC97_PCBEEPVOLUME	0x0a		/* PC speaker system beep volume			*/
+#define AC97_PHONEVOLUME	0x0c
+#define AC97_MICVOLUME		0x0e
+#define AC97_LINEINVOLUME	0x10
+#define AC97_CDVOLUME		0x12
+#define AC97_VIDEOVOLUME	0x14
+#define AC97_AUXVOLUME		0x16
+#define AC97_PCMOUTVOLUME	0x18
+#define AC97_RECORDSELECT	0x1a
+#define AC97_RECORDGAIN		0x1c
+#define AC97_RECORDGAINMIC	0x1e
+#define AC97_GENERALPUPOSE	0x20
+#define AC97_3DCONTROL		0x22
+#define AC97_MODEMRATE		0x24
+#define AC97_POWERDOWN		0x26
+#define AC97_RESERVED4		0x28
+#define AC97_VENDORRESERVED1	0x5a
+#define AC97_VENDORRESERVED2	0x7a
+#define AC97_VENDORID1		0x7c
+#define AC97_VENDORID2		0x7e
+#define AC97_ZVIDEOVOLUME	0xec
+#define AC97_AC3VOLUME		0xed
+
+/********************************************************************************************************/
+/* Emu10k1 pointer-offset register set, accessed through the PTR and DATA registers			*/
+/********************************************************************************************************/
+
+#define CPF			0x00		/* Current pitch and fraction register			*/
+#define CPF_CURRENTPITCH_MASK	0xffff0000	/* Current pitch (0x4000 == unity pitch shift)		*/
+#define CPF_CURRENTPITCH	0x10100000
+#define CPF_STEREO_MASK		0x00008000	/* 1 = Even channel interleave, odd channel locked	*/
+#define CPF_STOP_MASK		0x00004000	/* 1 = Current pitch forced to 0			*/
+#define CPF_FRACADDRESS_MASK	0x00003fff	/* Linear fractional address of the current channel	*/
+
+#define PTRX			0x01		/* Pitch target and send A/B amounts register		*/
+#define PTRX_PITCHTARGET_MASK	0xffff0000	/* Pitch target of specified channel			*/
+#define PTRX_PITCHTARGET	0x10100001
+#define PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00	/* Linear level of channel output sent to FX send bus A	*/
+#define PTRX_FXSENDAMOUNT_A	0x08080001
+#define PTRX_FXSENDAMOUNT_B_MASK 0x000000ff	/* Linear level of channel output sent to FX send bus B	*/
+#define PTRX_FXSENDAMOUNT_B	0x08000001
+
+#define CVCF			0x02		/* Current volume and filter cutoff register		*/
+#define CVCF_CURRENTVOL_MASK	0xffff0000	/* Current linear volume of specified channel		*/
+#define CVCF_CURRENTVOL		0x10100002
+#define CVCF_CURRENTFILTER_MASK	0x0000ffff	/* Current filter cutoff frequency of specified channel	*/
+#define CVCF_CURRENTFILTER	0x10000002
+
+#define VTFT			0x03		/* Volume target and filter cutoff target register	*/
+#define VTFT_VOLUMETARGET_MASK	0xffff0000	/* Volume target of specified channel			*/
+#define VTFT_FILTERTARGET_MASK	0x0000ffff	/* Filter cutoff target of specified channel		*/
+
+#define Z1			0x05		/* Filter delay memory 1 register			*/
+
+#define Z2			0x04		/* Filter delay memory 2 register			*/
+
+#define PSST			0x06		/* Send C amount and loop start address register	*/
+#define PSST_FXSENDAMOUNT_C_MASK	0xff000000	/* Linear level of channel output sent to FX send bus C	*/
+
+#define PSST_FXSENDAMOUNT_C	0x08180006
+
+#define PSST_LOOPSTARTADDR_MASK	0x00ffffff	/* Loop start address of the specified channel		*/
+#define PSST_LOOPSTARTADDR	0x18000006
+
+#define DSL			0x07		/* Send D amount and loop start address register	*/
+#define DSL_FXSENDAMOUNT_D_MASK	0xff000000	/* Linear level of channel output sent to FX send bus D	*/
+
+#define DSL_FXSENDAMOUNT_D	0x08180007
+
+#define DSL_LOOPENDADDR_MASK	0x00ffffff	/* Loop end address of the specified channel		*/
+#define DSL_LOOPENDADDR		0x18000007
+
+#define CCCA			0x08		/* Filter Q, interp. ROM, byte size, cur. addr register */
+#define CCCA_RESONANCE		0xf0000000	/* Lowpass filter resonance height			*/
+#define CCCA_INTERPROMMASK	0x0e000000	/* Selects passband of interpolation ROM		*/
+#define CCCA_INTERPROM_0	0x00000000	/* Select interpolation ROM 0				*/
+#define CCCA_INTERPROM_1	0x02000000	/* Select interpolation ROM 1				*/
+#define CCCA_INTERPROM_2	0x04000000	/* Select interpolation ROM 2				*/
+#define CCCA_INTERPROM_3	0x06000000	/* Select interpolation ROM 3				*/
+#define CCCA_INTERPROM_4	0x08000000	/* Select interpolation ROM 4				*/
+#define CCCA_INTERPROM_5	0x0a000000	/* Select interpolation ROM 5				*/
+#define CCCA_INTERPROM_6	0x0c000000	/* Select interpolation ROM 6				*/
+#define CCCA_INTERPROM_7	0x0e000000	/* Select interpolation ROM 7				*/
+#define CCCA_8BITSELECT		0x01000000	/* 1 = Sound memory for this channel uses 8-bit samples	*/
+#define CCCA_CURRADDR_MASK	0x00ffffff	/* Current address of the selected channel		*/
+#define CCCA_CURRADDR		0x18000008
+
+#define CCR			0x09		/* Cache control register				*/
+#define CCR_CACHEINVALIDSIZE	0xfe000000	/* Number of invalid samples in the cache		*/
+#define CCR_CACHELOOPFLAG	0x01000000	/* 1 = Cache has a loop service pending			*/
+#define CCR_INTERLEAVEDSAMPLES	0x00800000	/* 1 = A cache service will fetch interleaved samples	*/
+#define CCR_WORDSIZEDSAMPLES	0x00400000	/* 1 = A cache service will fetch word sized samples	*/
+#define CCR_READADDRESS_MASK	0x003f0000	/* Location of cache just beyond current cache service	*/
+#define CCR_LOOPINVALSIZE	0x0000fe00	/* Number of invalid samples in cache prior to loop	*/
+#define CCR_LOOPFLAG		0x00000100	/* Set for a single sample period when a loop occurs	*/
+#define CCR_CACHELOOPADDRHI	0x000000ff	/* DSL_LOOPSTARTADDR's hi byte if CCR_CACHELOOPFLAG = 1 */
+
+/* NOTE: This register is normally not used */
+#define CLP			0x0a		/* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */
+#define CLP_CACHELOOPADDR	0x0000ffff	/* Cache loop address (copy of DSL_LOOPSTARTADDR)	*/
+
+#define FXRT			0x0b		/* Effects send routing register			*/
+#define FXRT_CHANNELA		0x000f0000	/* Effects send bus number for channel's effects send A	*/
+#define FXRT_CHANNELB		0x00f00000	/* Effects send bus number for channel's effects send B	*/
+#define FXRT_CHANNELC		0x0f000000	/* Effects send bus number for channel's effects send C	*/
+#define FXRT_CHANNELD		0xf0000000	/* Effects send bus number for channel's effects send D	*/
+
+#define MAPA			0x0c		/* Cache map A						*/
+#define MAP_PTE_MASK		0xffffe000	/* The 19 MSBs of the PTE indexed by PTI		*/
+#define MAP_PTI_MASK		0x00001fff	/* The 13 bit index to one of the PTE dwords		*/
+
+#define MAPB			0x0d		/* Cache map B						*/
+
+#define ENVVOL			0x10		/* Volume envelope register				*/
+#define ENVVOL_MASK		0x0000ffff	/* 16-bit value						*/
+
+#define ATKHLDV 		0x11		/* Volume envelope hold and attack register		*/
+#define ATKHLDV_PHASE0		0x00008000	/* 0 = Begin attack phase				*/
+#define ATKHLDV_HOLDTIME_MASK	0x00007f00	/* Envelope hold time (127-n == n*88.2msec)		*/
+#define ATKHLDV_ATTACKTIME_MASK	0x0000007f	/* Envelope attack time, log encoded			*/
+/* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec	*/
+
+#define DCYSUSV 		0x12		/* Volume envelope sustain and decay register		*/
+#define DCYSUSV_PHASE1_MASK	0x00008000	/* 0 = Begin attack phase, 1 = begin release phase	*/
+#define DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00	/* 127 = full, 0 = off, 0.75dB increments		*/
+#define DCYSUSV_CHANNELENABLE_MASK 0x00000080	/* 1 = Inhibit envelope engine from writing to registers*/
+#define DCYSUSV_DECAYTIME_MASK	0x0000007f	/* Envelope decay time, log encoded			*/
+/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec		*/
+
+#define LFOVAL1 		0x13		/* Modulation LFO value					*/
+#define LFOVAL_MASK		0x0000ffff	/* 16-bit value						*/
+
+#define ENVVAL			0x14		/* Modulation envelope register				*/
+#define ENVVAL_MASK		0x0000ffff	/* 16-bit value						*/
+
+#define ATKHLDM			0x15		/* Modulation envelope hold and attack register		*/
+#define ATKHLDM_PHASE0		0x00008000	/* 0 = Begin attack phase				*/
+#define ATKHLDM_HOLDTIME	0x00007f00	/* Envelope hold time (127-n == n*42msec)		*/
+#define ATKHLDM_ATTACKTIME	0x0000007f	/* Envelope attack time, log encoded			*/
+/* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec		*/
+
+#define DCYSUSM			0x16		/* Modulation envelope decay and sustain register	*/
+#define DCYSUSM_PHASE1_MASK	0x00008000	/* 0 = Begin attack phase, 1 = begin release phase	*/
+#define DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00	/* 127 = full, 0 = off, 0.75dB increments		*/
+#define DCYSUSM_DECAYTIME_MASK	0x0000007f	/* Envelope decay time, log encoded			*/
+/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec		*/
+
+#define LFOVAL2 		0x17		/* Vibrato LFO register					*/
+#define LFOVAL2_MASK		0x0000ffff	/* 16-bit value						*/
+
+#define IP			0x18		/* Initial pitch register				*/
+#define IP_MASK			0x0000ffff	/* Exponential initial pitch shift (16-bit value)	*/
+/* 4 bits of octave, 12 bits of fractional octave	*/
+#define IP_UNITY		0x0000e000	/* Unity pitch shift					*/
+
+#define IFATN			0x19		/* Initial filter cutoff and attenuation register	*/
+#define IFATN_FILTERCUTOFF_MASK	0x0000ff00	/* Initial filter cutoff frequency in exponential units	*/
+/* 6 most significant bits are semitones		*/
+/* 2 least significant bits are fractions		*/
+#define IFATN_FILTERCUTOFF	0x08080019
+#define IFATN_ATTENUATION_MASK	0x000000ff	/* Initial attenuation in 0.375dB steps			*/
+#define IFATN_ATTENUATION	0x08000019
+
+
+#define PEFE			0x1a		/* Pitch envelope and filter envelope amount register	*/
+#define PEFE_PITCHAMOUNT_MASK	0x0000ff00	/* Pitch envlope amount					*/
+/* Signed 2's complement, +/- one octave peak extremes	*/
+#define PEFE_PITCHAMOUNT	0x0808001a
+#define PEFE_FILTERAMOUNT_MASK	0x000000ff	/* Filter envlope amount				*/
+/* Signed 2's complement, +/- six octaves peak extremes */
+#define PEFE_FILTERAMOUNT	0x0800001a
+#define FMMOD			0x1b		/* Vibrato/filter modulation from LFO register		*/
+#define FMMOD_MODVIBRATO	0x0000ff00	/* Vibrato LFO modulation depth				*/
+/* Signed 2's complement, +/- one octave extremes	*/
+#define FMMOD_MOFILTER		0x000000ff	/* Filter LFO modulation depth				*/
+/* Signed 2's complement, +/- three octave extremes	*/
+
+
+#define TREMFRQ 		0x1c		/* Tremolo amount and modulation LFO frequency register	*/
+#define TREMFRQ_DEPTH		0x0000ff00	/* Tremolo depth					*/
+/* Signed 2's complement, with +/- 12dB extremes	*/
+
+#define FM2FRQ2 		0x1d		/* Vibrato amount and vibrato LFO frequency register	*/
+#define FM2FRQ2_DEPTH		0x0000ff00	/* Vibrato LFO vibrato depth				*/
+/* Signed 2's complement, +/- one octave extremes	*/
+#define FM2FRQ2_FREQUENCY	0x000000ff	/* Vibrato LFO frequency				*/
+/* 0.039Hz steps, maximum of 9.85 Hz.			*/
+
+#define TEMPENV 		0x1e		/* Tempory envelope register				*/
+#define TEMPENV_MASK		0x0000ffff	/* 16-bit value						*/
+
+#define CD0			0x20		/* Reserved Bit - Do not program			*/
+#define CD1			0x21		/* Reserved Bit - Do not program			*/
+#define CD2			0x22		/* Reserved Bit - Do not program			*/
+#define CD3			0x23		/* Reserved Bit - Do not program			*/
+#define CD4			0x24		/* Reserved Bit - Do not program			*/
+#define CD5			0x25		/* Reserved Bit - Do not program			*/
+#define CD6			0x26		/* Reserved Bit - Do not program			*/
+#define CD7			0x27		/* Reserved Bit - Do not program			*/
+#define CD8			0x28		/* Reserved Bit - Do not program			*/
+#define CD9			0x29		/* Reserved Bit - Do not program			*/
+#define CDA			0x2a		/* Reserved Bit - Do not program			*/
+#define CDB			0x2b		/* Reserved Bit - Do not program			*/
+#define CDC			0x2c		/* Reserved Bit - Do not program			*/
+#define CDD			0x2d		/* Reserved Bit - Do not program			*/
+#define CDE			0x2e		/* Reserved Bit - Do not program			*/
+#define CDF			0x2f		/* Reserved Bit - Do not program			*/
+
+#define PTB			0x40		/* Page table base register				*/
+#define PTB_MASK		0xfffff000	/* Physical address of the page table in host memory	*/
+
+#define TCB			0x41		/* Tank cache base register    				*/
+#define TCB_MASK		0xfffff000	/* Physical address of the bottom of host based tank memory	*/
+
+#define ADCCR			0x42		/* ADC sample rate/stereo control register		*/
+#define ADCCR_RCHANENABLE	0x00000010	/* Right channel enable					*/
+#define ADCCR_LCHANENABLE	0x00000008	/* Left channel enable					*/
+#define ADCCR_SAMPLERATE_MASK	0x00000007	/* Sample rate convertor output rate			*/
+#define ADCCR_SAMPLERATE_48	0x00000000	/* 48kHz sample rate					*/
+#define ADCCR_SAMPLERATE_44	0x00000001	/* 44.1kHz sample rate					*/
+#define ADCCR_SAMPLERATE_32	0x00000002	/* 32kHz sample rate					*/
+#define ADCCR_SAMPLERATE_24	0x00000003	/* 24kHz sample rate					*/
+#define ADCCR_SAMPLERATE_22	0x00000004	/* 22.05kHz sample rate					*/
+#define ADCCR_SAMPLERATE_16	0x00000005	/* 16kHz sample rate					*/
+#define ADCCR_SAMPLERATE_11	0x00000006	/* 11.025kHz sample rate				*/
+#define ADCCR_SAMPLERATE_8	0x00000007	/* 8kHz sample rate					*/
+
+#define FXWC			0x43		/* FX output write channels register			*/
+
+#define TCBS			0x44		/* Tank cache buffer size register			*/
+#define TCBS_MASK		0x00000007	/* Tank cache buffer size field				*/
+#define TCBS_BUFFSIZE_16K	0x00000000
+#define TCBS_BUFFSIZE_32K	0x00000001
+#define TCBS_BUFFSIZE_64K	0x00000002
+#define TCBS_BUFFSIZE_128K	0x00000003
+#define TCBS_BUFFSIZE_256K	0x00000004
+#define TCBS_BUFFSIZE_512K	0x00000005
+#define TCBS_BUFFSIZE_1024K	0x00000006
+#define TCBS_BUFFSIZE_2048K	0x00000007
+
+#define MICBA			0x45		/* AC97 microphone buffer address register		*/
+#define MICBA_MASK		0xfffff000	/* 20 bit base address					*/
+
+#define ADCBA			0x46		/* ADC buffer address register				*/
+#define ADCBA_MASK		0xfffff000	/* 20 bit base address					*/
+
+#define FXBA			0x47		/* FX Buffer Address */
+
+#define MICBS			0x49		/* Microphone buffer size register			*/
+
+#define ADCBS			0x4a		/* ADC buffer size register				*/
+
+/* The following mask values define the size of the ADC buffers in bytes */
+#define ADCBS_BUFSIZE_NONE	0x00000000
+#define ADCBS_BUFSIZE_384	0x00000001
+#define ADCBS_BUFSIZE_448	0x00000002
+#define ADCBS_BUFSIZE_512	0x00000003
+#define ADCBS_BUFSIZE_640	0x00000004
+#define ADCBS_BUFSIZE_768	0x00000005
+#define ADCBS_BUFSIZE_896	0x00000006
+#define ADCBS_BUFSIZE_1024	0x00000007
+#define ADCBS_BUFSIZE_1280	0x00000008
+#define ADCBS_BUFSIZE_1536	0x00000009
+#define ADCBS_BUFSIZE_1792	0x0000000a
+#define ADCBS_BUFSIZE_2048	0x0000000b
+#define ADCBS_BUFSIZE_2560	0x0000000c
+#define ADCBS_BUFSIZE_3072	0x0000000d
+#define ADCBS_BUFSIZE_3584	0x0000000e
+#define ADCBS_BUFSIZE_4096	0x0000000f
+#define ADCBS_BUFSIZE_5120	0x00000010
+#define ADCBS_BUFSIZE_6144	0x00000011
+#define ADCBS_BUFSIZE_7168	0x00000012
+#define ADCBS_BUFSIZE_8192	0x00000013
+#define ADCBS_BUFSIZE_10240	0x00000014
+#define ADCBS_BUFSIZE_12288	0x00000015
+#define ADCBS_BUFSIZE_14366	0x00000016
+#define ADCBS_BUFSIZE_16384	0x00000017
+#define ADCBS_BUFSIZE_20480	0x00000018
+#define ADCBS_BUFSIZE_24576	0x00000019
+#define ADCBS_BUFSIZE_28672	0x0000001a
+#define ADCBS_BUFSIZE_32768	0x0000001b
+#define ADCBS_BUFSIZE_40960	0x0000001c
+#define ADCBS_BUFSIZE_49152	0x0000001d
+#define ADCBS_BUFSIZE_57344	0x0000001e
+#define ADCBS_BUFSIZE_65536	0x0000001f
+
+#define FXBS			0x4b		/* FX buffer size register			*/
+
+#define CDCS			0x50		/* CD-ROM digital channel status register	*/
+
+#define GPSCS			0x51		/* General Purpose SPDIF channel status register*/
+
+#define DBG			0x52		/* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
+
+#define REG53			0x53		/* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
+
+#define SPCS0			0x54		/* SPDIF output Channel Status 0 register	*/
+
+#define SPCS1			0x55		/* SPDIF output Channel Status 1 register	*/
+
+#define SPCS2			0x56		/* SPDIF output Channel Status 2 register	*/
+
+#define SPCS_CLKACCYMASK	0x30000000	/* Clock accuracy				*/
+#define SPCS_CLKACCY_1000PPM	0x00000000	/* 1000 parts per million			*/
+#define SPCS_CLKACCY_50PPM	0x10000000	/* 50 parts per million				*/
+#define SPCS_CLKACCY_VARIABLE	0x20000000	/* Variable accuracy				*/
+#define SPCS_SAMPLERATEMASK	0x0f000000	/* Sample rate					*/
+#define SPCS_SAMPLERATE_44	0x00000000	/* 44.1kHz sample rate				*/
+#define SPCS_SAMPLERATE_48	0x02000000	/* 48kHz sample rate				*/
+#define SPCS_SAMPLERATE_32	0x03000000	/* 32kHz sample rate				*/
+#define SPCS_CHANNELNUMMASK	0x00f00000	/* Channel number				*/
+#define SPCS_CHANNELNUM_UNSPEC	0x00000000	/* Unspecified channel number			*/
+#define SPCS_CHANNELNUM_LEFT	0x00100000	/* Left channel					*/
+#define SPCS_CHANNELNUM_RIGHT	0x00200000	/* Right channel				*/
+#define SPCS_SOURCENUMMASK	0x000f0000	/* Source number				*/
+#define SPCS_SOURCENUM_UNSPEC	0x00000000	/* Unspecified source number			*/
+#define SPCS_GENERATIONSTATUS	0x00008000	/* Originality flag (see IEC-958 spec)		*/
+#define SPCS_CATEGORYCODEMASK	0x00007f00	/* Category code (see IEC-958 spec)		*/
+#define SPCS_MODEMASK		0x000000c0	/* Mode (see IEC-958 spec)			*/
+#define SPCS_EMPHASISMASK	0x00000038	/* Emphasis					*/
+#define SPCS_EMPHASIS_NONE	0x00000000	/* No emphasis					*/
+#define SPCS_EMPHASIS_50_15	0x00000008	/* 50/15 usec 2 channel				*/
+#define SPCS_COPYRIGHT		0x00000004	/* Copyright asserted flag -- do not modify	*/
+#define SPCS_NOTAUDIODATA	0x00000002	/* 0 = Digital audio, 1 = not audio		*/
+#define SPCS_PROFESSIONAL	0x00000001	/* 0 = Consumer (IEC-958), 1 = pro (AES3-1992)	*/
+
+/* The 32-bit CLIx registers all have one bit per channel control/status			*/
+#define CLIEL			0x58		/* Channel loop interrupt enable low register	*/
+
+#define CLIEH			0x59		/* Channel loop interrupt enable high register	*/
+
+#define CLIPL			0x5a		/* Channel loop interrupt pending low register	*/
+
+#define CLIPH			0x5b		/* Channel loop interrupt pending high register	*/
+
+#define SOLEL			0x5c		/* Stop on loop enable low register		*/
+
+#define SOLEH			0x5d		/* Stop on loop enable high register		*/
+
+#define SPBYPASS		0x5e		/* SPDIF BYPASS mode register			*/
+
+#define CDSRCS			0x60		/* CD-ROM Sample Rate Converter status register	*/
+
+#define GPSRCS			0x61		/* General Purpose SPDIF sample rate cvt status */
+
+#define ZVSRCS			0x62		/* ZVideo sample rate converter status		*/
+/* NOTE: This one has no SPDIFLOCKED field	*/
+/* Assumes sample lock				*/
+
+/* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS.			*/
+#define SRCS_SPDIFLOCKED	0x02000000	/* SPDIF stream locked				*/
+#define SRCS_RATELOCKED		0x01000000	/* Sample rate locked				*/
+#define SRCS_ESTSAMPLERATE	0x0007ffff	/* Do not modify this field.			*/
+
+#define ADCIDX			0x63		/* ADC recording buffer index register		*/
+#define ADCIDX_MASK		0x0000ffff	/* 16 bit index field				*/
+
+#define MICIDX			0x64		/* Microphone recording buffer index register	*/
+#define MICIDX_MASK		0x0000ffff	/* 16-bit value					*/
+
+#define FXIDX			0x65		/* FX recording buffer index register		*/
+
+/* Each FX general purpose register is 32 bits in length, all bits are used			*/
+#define FXGPREGBASE		0x100		/* FX general purpose registers base       	*/
+
+/* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is	*/
+/* decompressed back to 20 bits on a read.  There are a total of 160 locations, the last 32	*/
+/* locations are for external TRAM. 								*/
+#define TANKMEMDATAREGBASE	0x200		/* Tank memory data registers base     		*/
+#define TANKMEMDATAREG_MASK	0x000fffff	/* 20 bit tank audio data field			*/
+
+/* Combined address field and memory opcode or flag field.  160 locations, last 32 are external	*/
+#define TANKMEMADDRREGBASE	0x300		/* Tank memory address registers base		*/
+#define TANKMEMADDRREG_ADDR_MASK 0x000fffff	/* 20 bit tank address field			*/
+#define TANKMEMADDRREG_CLEAR	0x00800000	/* Clear tank memory				*/
+#define TANKMEMADDRREG_ALIGN	0x00400000	/* Align read or write relative to tank access	*/
+#define TANKMEMADDRREG_WRITE	0x00200000	/* Write to tank memory				*/
+#define TANKMEMADDRREG_READ	0x00100000	/* Read from tank memory			*/
+
+#define MICROCODEBASE		0x400		/* Microcode data base address			*/
+
+/* Each DSP microcode instruction is mapped into 2 doublewords 					*/
+/* NOTE: When writing, always write the HI doubleword first.  Reads can be in either order.	*/
+#define LOWORD_OPX_MASK		0x000ffc00	/* Instruction operand X			*/
+#define LOWORD_OPY_MASK		0x000003ff	/* Instruction operand Y			*/
+#define HIWORD_OPCODE_MASK	0x00f00000	/* Instruction opcode				*/
+#define HIWORD_RESULT_MASK	0x000ffc00	/* Instruction result				*/
+#define HIWORD_OPA_MASK		0x000003ff	/* Instruction operand A			*/
+
+#endif /* _8010_H */
Index: oldkernel/linux/drivers/sound/emu10k1/Makefile
diff -u /dev/null linux/drivers/sound/emu10k1/Makefile:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/Makefile	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,14 @@
+
+#MOD_LIST_NAME := SOUND_MODULES
+
+EMU = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o osutils.o recmgr.o sndstat.o timer.o voicemgr.o
+
+M_OBJS := emu10k1.o
+
+$(EMU): %.o: %.c
+	$(CC) -c $(CFLAGS) -I. $< -o $@
+
+emu10k1.o: $(EMU)
+	$(LD) -r $(EMU) -o $@
+
+include $(TOPDIR)/Rules.make
Index: oldkernel/linux/drivers/sound/emu10k1/audio.c
diff -u /dev/null linux/drivers/sound/emu10k1/audio.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/audio.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,1801 @@
+/*
+ **********************************************************************
+ *     audio.c -- /dev/dsp interface for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999	    Alan Cox        cleaned up types/leaks
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+/*
+ *	FIXME:
+ *		There are some 32bit assumptions here
+ *		Cast of pointers to 32bit values is unsafe
+ *			- Wave callbacks and elsewhere
+ */
+
+#include "hwaccess.h"
+#include "mycommon.h"
+#include "mmwave.h"
+#include "cardwo.h"
+#include "cardwi.h"
+#include "audio.h"
+
+static void calculate_ofrag(struct woinst *woinst);
+static void calculate_ifrag(struct wiinst *wiinst);
+
+/* Audio file operations */
+static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int nOrigin)
+{
+	DPF(2, "emu10k1_audio_lseek() called\n");
+	return -ESPIPE;
+}
+
+static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, loff_t * ppos)
+{
+	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
+	struct wiinst *wiinst = wave_dev->wiinst;
+	ssize_t ret = 0;
+	u32 flags;
+
+	spin_lock_irqsave(&wiinst->lock, flags);
+
+	DPD(4, "emu10k1_audio_read() called, buffer=%x, count=%d\n", (unsigned int) buffer, count);
+
+	if (wiinst->mapped)
+	{
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+		return -ENXIO;
+	}
+
+	if (file->f_mode & FMODE_READ)
+	{
+		struct wave_in *wave_in = wiinst->wave_in;
+
+		if (!wave_in)
+		{
+			calculate_ifrag(wiinst);
+
+			if (sblive_waveinOpen(wave_dev->sb_hw, &wiinst->wave_fmt,
+					      &wiinst->fragment_size,
+					      wiinst->numfrags, &wiinst->wave_in) != CTSTATUS_SUCCESS)
+			{
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+
+				DPF(2, "sblive_waveinOpen failed!\n");
+				return -EINVAL;
+			}
+
+			DPD(2, "fragment_size size is -> %x\n", wiinst->fragment_size);
+
+			wave_in = wiinst->wave_in;
+		}
+
+		if (!access_ok(VERIFY_WRITE, buffer, count))
+		{
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+
+			DPF(2, "Cannot write to buffer!\n");
+
+			return -EFAULT;
+		}
+
+		while (count > 0)
+		{
+			u32 bytestocopy, pending;
+
+			if (wave_dev->enablebits & PCM_ENABLE_INPUT && wave_in->state != CARDWAVE_STATE_STARTED)
+			{
+				if (sblive_waveinStart(wave_dev) != CTSTATUS_SUCCESS)
+				{
+					spin_unlock_irqrestore(&wiinst->lock, flags);
+
+					DPF(2, "sblive_waveinStart() failed.\n");
+					return -EFAULT;
+				}
+
+				DPF(2, "sblive_waveinStart() succeeded.\n");
+			}
+
+			if (sblive_waveinGetXferSize(wave_dev->sb_hw->card_wavein, wave_in, &bytestocopy, &pending) != CTSTATUS_SUCCESS)
+			{
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+
+				DPF(2, "sblive_waveinGetXferSize failed\n");
+				return -EFAULT;
+			}
+
+			DPD(4, "bytestocopy --> %x\n", bytestocopy);
+
+			if (bytestocopy) {
+
+				bytestocopy = min(bytestocopy, count);
+
+				if (sblive_waveinXferData(wave_dev->sb_hw->card_wavein, wave_in, (u8 *)buffer, &bytestocopy) != CTSTATUS_SUCCESS)
+				{
+					spin_unlock_irqrestore(&wiinst->lock, flags);
+					DPF(2, "sblive_waveinXferData failed.\n");
+					return ret ? ret : -EFAULT;
+				}
+
+				count -= bytestocopy;
+				buffer += bytestocopy;
+				ret += bytestocopy;
+			}
+
+			if (count > 0)
+			{
+				if ((file->f_flags & O_NONBLOCK)
+				    || (!(wave_dev->enablebits & PCM_ENABLE_INPUT)))
+				{
+					spin_unlock_irqrestore(&wiinst->lock, flags);
+					return (ret ? ret : -EAGAIN);
+				}
+
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+
+				interruptible_sleep_on(&wiinst->wait_queue);
+
+				if (signal_pending(current))
+					return (ret ? ret : -ERESTARTSYS);
+
+				spin_lock_irqsave(&wiinst->lock, flags);
+			}
+		}
+		DPD(4, "bytes copied -> %x\n", ret);
+	}
+
+	spin_unlock_irqrestore(&wiinst->lock, flags);
+
+	return ret;
+}
+
+ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
+{
+	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
+	struct woinst *woinst = wave_dev->woinst;
+	struct wave_out *wave_out = woinst->wave_out;
+	ssize_t ret;
+	u32 flags;
+	GET_INODE_STRUCT();
+
+	spin_lock_irqsave(&woinst->lock, flags);
+
+	DPD(4, "emu10k1_audio_write() called, buffer=%#x, count=%d\n", (unsigned int) buffer, count);
+
+	if (woinst->mapped)
+	{
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		return -ENXIO;
+	}
+
+
+	if (wave_out == NULL)
+	{
+
+		calculate_ofrag(woinst);
+
+		while (sblive_waveoutOpen(wave_dev->sb_hw, &woinst->wave_fmt,
+					  &woinst->fragment_size,
+					  woinst->numfrags, &woinst->wave_out) != CTSTATUS_SUCCESS)
+		{
+			if (file->f_flags & O_NONBLOCK)
+			{
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				return -EAGAIN;
+			}
+
+			UP_INODE_SEM(&inode->i_sem);
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			interruptible_sleep_on(&wave_dev->sb_hw->open_wait);
+			DOWN_INODE_SEM(&inode->i_sem);
+			if (signal_pending(current))
+				return -ERESTARTSYS;
+
+			spin_lock_irqsave(&woinst->lock, flags);
+		}
+		wave_out = woinst->wave_out;
+	}
+
+	if (!access_ok(VERIFY_READ, buffer, count))
+	{
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		return -EFAULT;
+	}
+
+	ret = 0;
+	while (count > 0)
+	{
+		u32 bytestocopy, pending;
+		int status;
+
+		status = sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout,
+						   wave_out, &bytestocopy, &pending);
+
+		if (status != CTSTATUS_SUCCESS)
+		{
+			spin_unlock_irqrestore(&woinst->lock, flags);
+			DPF(2, "sblive_waveoutGetXferSize failed\n");
+			return -EFAULT;
+		}
+
+		if (woinst->silence_filled > 0)
+		{
+			if (woinst->silence_filled == 1)
+			{
+				if (pending <= woinst->fragment_size)
+					woinst->silence_filled = 2;
+				else
+					bytestocopy += woinst->fragment_size;
+			}
+
+			if (woinst->silence_filled == 2)
+				bytestocopy = woinst->fragment_size * woinst->numfrags;
+		}
+
+		DPD(4, "bytestocopy --> %x\n", bytestocopy);
+
+		if (bytestocopy) {
+
+			bytestocopy = min(bytestocopy, count);
+
+			if (woinst->silence_filled > 0)
+			{
+				u32 tmp;
+
+				if (woinst->silence_filled == 1)
+					tmp = woinst->silence_start;
+				else
+				{
+					sblive_waveoutGetControl(wave_dev->sb_hw->card_waveout,
+								 wave_out, WAVECURPOS, &tmp);
+					pending = 0;
+				}
+
+				if (pending + bytestocopy < woinst->fragment_size)
+				{
+					woinst->silence_filled = 1;
+					woinst->silence_start = tmp + bytestocopy;
+
+					if (woinst->silence_start > woinst->fragment_size * woinst->numfrags)
+						woinst->silence_start -= woinst->fragment_size * woinst->numfrags;
+				}
+				else
+					woinst->silence_filled = 0;
+
+				sblive_waveoutSetControl(wave_dev->sb_hw, wave_out,
+							 WAVEWRITEPOINTER, &tmp);
+			}
+
+			status = sblive_waveoutXferData(wave_dev->sb_hw->card_waveout,
+							wave_out, (u8 *)buffer, &bytestocopy);
+
+			if (woinst->silence_filled)
+			{
+				u32 tmp = woinst->fragment_size;
+				sblive_waveoutFillSilence(wave_dev->sb_hw->card_waveout, wave_out, &tmp);
+			}
+
+			if (status != CTSTATUS_SUCCESS)
+			{
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				DPF(2, "sblive_waveoutXferData failed.\n");
+				return (ret ? ret : -EFAULT);
+			}
+
+			count -= bytestocopy;
+			buffer += bytestocopy;
+			ret += bytestocopy;
+			woinst->total_copied += bytestocopy;
+
+			if ((wave_dev->enablebits & PCM_ENABLE_OUTPUT)
+			    && (wave_out->state != CARDWAVE_STATE_STARTED)
+			    && (woinst->total_copied >= woinst->fragment_size))
+			{
+				if (sblive_waveoutStart(wave_dev) != CTSTATUS_SUCCESS)
+				{
+					spin_unlock_irqrestore(&woinst->lock, flags);
+					DPF(2, "sblive_waveoutStart failed.\n");
+					return -EFAULT;
+				}
+				else
+					DPF(2, "sblive_waveoutStart\n");
+			}
+		}
+
+		if (count > 0)
+		{
+			if ((file->f_flags & O_NONBLOCK)
+			    || (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT)))
+			{
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				return (ret ? ret : -EAGAIN);
+			}
+
+			UP_INODE_SEM(&inode->i_sem);
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			interruptible_sleep_on(&woinst->wait_queue);
+			DOWN_INODE_SEM(&inode->i_sem);
+			if (signal_pending(current))
+				return (ret ? ret : -ERESTARTSYS);
+
+			spin_lock_irqsave(&woinst->lock, flags);
+		}
+
+	}
+
+	spin_unlock_irqrestore(&woinst->lock, flags);
+
+	DPD(4, "bytes copied -> %x\n", ret);
+
+	return ret;
+}
+
+static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
+	int val = 0;
+	struct woinst *woinst = NULL;
+	struct wave_out *wave_out = NULL;
+	struct wiinst *wiinst = NULL;
+	struct wave_in *wave_in = NULL;
+	u32 flags, pending, bytestocopy, dummy;
+
+	DPF(4, "emu10k1_audio_ioctl() called:\n");
+
+	if (file->f_mode & FMODE_WRITE){
+		woinst = wave_dev->woinst;
+		wave_out = woinst->wave_out;
+	}
+
+	if (file->f_mode & FMODE_READ){
+		wiinst = wave_dev->wiinst;
+		wave_in = wiinst->wave_in;
+	}
+
+	switch (cmd)
+	{
+	case OSS_GETVERSION:
+		DPF(2, "OSS_GETVERSION:\n");
+		return put_user(SOUND_VERSION, (int *) arg);
+
+	case SNDCTL_DSP_RESET:
+		DPF(2, "SNDCTL_DSP_RESET:\n");
+		wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT;
+
+		if (file->f_mode & FMODE_WRITE)
+		{
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			if (wave_out)
+			{
+				sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
+				wave_out->wavexferbuf->xferpos = 0;
+				wave_out->wavexferbuf->stopposition = 0;
+			}
+
+			woinst->total_copied = 0;
+			woinst->total_played = 0;
+			woinst->silence_filled = 0;
+			woinst->silence_start = 0;
+			woinst->getoptr_blocks = 0;
+			woinst->wave_ptr = 0;
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+		}
+
+		if (file->f_mode & FMODE_READ)
+		{
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			if (wave_in)
+				sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+		}
+
+		break;
+
+	case SNDCTL_DSP_SYNC:
+		DPF(2, "SNDCTL_DSP_SYNC:\n");
+
+		if (file->f_mode & FMODE_WRITE)
+		{
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			if (wave_out && wave_out->state == CARDWAVE_STATE_STARTED)
+				while ((woinst->total_played < woinst->total_copied)
+				       && !signal_pending(current))
+				{
+					spin_unlock_irqrestore(&woinst->lock, flags);
+					interruptible_sleep_on(&woinst->wait_queue);
+					spin_lock_irqsave(&woinst->lock, flags);
+				}
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+		}
+
+		break;
+
+	case SNDCTL_DSP_SETDUPLEX:
+		DPF(2, "SNDCTL_DSP_SETDUPLEX:\n");
+		break;
+
+	case SNDCTL_DSP_GETCAPS:
+		DPF(2, "SNDCTL_DSP_GETCAPS:\n");
+		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_COPROC, (int *)arg);
+
+	case SNDCTL_DSP_SPEED:
+		DPF(2, "SNDCTL_DSP_SPEED:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+		DPD(2, "val is %d\n", val);
+
+		if (val >= 0)
+		{
+			if (file->f_mode & FMODE_WRITE)
+			{
+				struct wave_format *wave_fmt;
+
+				spin_lock_irqsave(&woinst->lock, flags);
+
+				if (wave_out)
+					sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
+
+				wave_fmt = &woinst->wave_fmt;
+				wave_fmt->samplingrate = val;
+
+				sblive_waveoutQueryFormat(wave_dev->sb_hw->card_waveout, wave_fmt, CARDWAVE_QF_RATE);
+
+				if (woinst->mapped)
+				{
+					struct wave_format wave_fmt = woinst->wave_fmt;
+
+					if (sblive_waveoutSetControl(wave_dev->sb_hw, wave_out, WAVEINSTANCEFORMAT, (u32 *)&wave_fmt)
+					    != CTSTATUS_SUCCESS)
+					{
+						spin_unlock_irqrestore(&woinst->lock, flags);
+						return -EINVAL;
+					}
+				}
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+
+				DPD(2, "Set playback sampling rate -> %d\n", woinst->wave_fmt.samplingrate);
+			}
+
+			if (file->f_mode & FMODE_READ)
+			{
+				struct wave_format *wave_fmt;
+
+				spin_lock_irqsave(&wiinst->lock, flags);
+
+				if (wave_in)
+					sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
+
+				wave_fmt = &wiinst->wave_fmt;
+				wave_fmt->samplingrate = val;
+
+				sblive_waveinQueryFormat(wave_dev->sb_hw->card_wavein, wave_fmt, CARDWAVE_QF_RATE);
+
+				DPD(2, "Set recording sampling rate -> %d\n", wave_fmt->samplingrate);
+
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+			}
+
+			return put_user(val, (int *) arg);
+		} else
+		{
+			if (file->f_mode & FMODE_READ)
+				val = wiinst->wave_fmt.samplingrate;
+			else if (file->f_mode & FMODE_WRITE)
+				val = woinst->wave_fmt.samplingrate;
+
+			return put_user(val, (int *) arg);
+		}
+		break;
+
+	case SNDCTL_DSP_STEREO:
+		DPF(2, "SNDCTL_DSP_STEREO:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+		DPD(2, " val is %d\n", val);
+
+		if (file->f_mode & FMODE_WRITE)
+		{
+			struct wave_format *wave_fmt;
+
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			if (wave_out)
+				sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
+
+			wave_fmt = &woinst->wave_fmt;
+			wave_fmt->channels = val ? 2 : 1;
+
+			if (sblive_waveoutQueryFormat(wave_dev->sb_hw->card_waveout, wave_fmt, CARDWAVE_QF_STEREO) != CTSTATUS_SUCCESS)
+			{
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				DPF(2, "waveoutQueryFormat() failed!\n");
+				return -EINVAL;
+			}
+
+			if (woinst->mapped)
+			{
+				if (sblive_waveoutSetControl(wave_dev->sb_hw, wave_out, WAVEINSTANCEFORMAT, (u32 *)&wave_fmt) != CTSTATUS_SUCCESS)
+				{
+					spin_unlock_irqrestore(&woinst->lock, flags);
+					DPF(2, "waveoutSetControl() failed!\n");
+					return -EINVAL;
+				}
+			}
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			DPD(2, "Set playback stereo -> %d\n", wave_fmt->channels);
+		}
+
+		if (file->f_mode & FMODE_READ)
+		{
+			struct wave_format *wave_fmt;
+
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			if (wave_in)
+				sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
+
+			wave_fmt = &wiinst->wave_fmt;
+			wave_fmt->channels = val ? 2 : 1;
+
+			if (sblive_waveinQueryFormat(wave_dev->sb_hw->card_wavein, wave_fmt, CARDWAVE_QF_STEREO) != CTSTATUS_SUCCESS)
+			{
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+				DPF(2, "waveinQueryFormat() failed!\n");
+				return -EINVAL;
+			}
+
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+			DPD(2, "Set recording stereo -> %d\n", wave_fmt->channels);
+		}
+
+		break;
+
+	case SNDCTL_DSP_CHANNELS:
+		DPF(2, "SNDCTL_DSP_CHANNELS:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+		DPD(2, " val is %d\n", val);
+
+		if (val != 0)
+		{
+			if (file->f_mode & FMODE_WRITE)
+			{
+				struct wave_format *wave_fmt;
+
+				spin_lock_irqsave(&woinst->lock, flags);
+
+				if (wave_out)
+					sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
+
+				wave_fmt = &woinst->wave_fmt;
+				wave_fmt->channels = val;
+
+				if (sblive_waveoutQueryFormat(wave_dev->sb_hw->card_waveout, wave_fmt, CARDWAVE_QF_CHANNEL) != CTSTATUS_SUCCESS)
+				{
+					spin_unlock_irqrestore(&woinst->lock, flags);
+					DPF(2, "waveoutQueryFormat() called!\n");
+					return -EINVAL;
+				}
+				/*
+				if (woinst->mapped)
+				{
+					struct wave_format wave_fmt = woinst->wave_fmt;
+
+					if (sblive_waveoutSetControl(wave_dev->sb_hw, wave_out, WAVEINSTANCEFORMAT, (u32 *)&wave_fmt) != CTSTATUS_SUCCESS)
+					{
+						spin_unlock_irqrestore(&woinst->lock, flags);
+						DPF(2, "waveoutSetControl() failed!\n");
+						return -EINVAL;
+					}
+				}
+				*/
+				DPD(2, "Set playback number of channels -> %d\n", wave_fmt->channels);
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+			}
+
+			if (file->f_mode & FMODE_READ)
+			{
+				struct wave_format *wave_fmt;
+
+				spin_lock_irqsave(&wiinst->lock, flags);
+
+				if (wave_in)
+					sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
+
+				wave_fmt = &wiinst->wave_fmt;
+				wave_fmt->channels = val;
+
+				if (sblive_waveinQueryFormat(wave_dev->sb_hw->card_wavein, wave_fmt, CARDWAVE_QF_CHANNEL) != CTSTATUS_SUCCESS)
+				{
+					spin_unlock_irqrestore(&wiinst->lock, flags);
+					DPF(2, "waveinQueryFormat() called!\n");
+					return -EINVAL;
+				}
+
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+
+				DPD(2, "Set recording number of channels -> %d\n", wave_fmt->channels);
+			}
+
+			return put_user(val, (int *) arg);
+		} else
+		{
+			if (file->f_mode & FMODE_READ)
+				val = wiinst->wave_fmt.channels;
+			else if (file->f_mode & FMODE_WRITE)
+				val = woinst->wave_fmt.channels;
+
+			return put_user(val, (int *) arg);
+		}
+		break;
+
+	case SNDCTL_DSP_GETFMTS:
+		DPF(2, "SNDCTL_DSP_GETFMTS:\n");
+		return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
+
+	case SNDCTL_DSP_SETFMT:	/* Same as SNDCTL_DSP_SAMPLESIZE */
+		DPF(2, "SNDCTL_DSP_SETFMT:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+		DPD(2, " val is %d\n", val);
+
+		if (val != AFMT_QUERY)
+		{
+			if (file->f_mode & FMODE_WRITE)
+			{
+				struct wave_format *wave_fmt;
+
+				spin_lock_irqsave(&woinst->lock, flags);
+
+				if (wave_out)
+					sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
+
+				wave_fmt = &woinst->wave_fmt;
+				wave_fmt->bitspersample = val;
+
+				sblive_waveoutQueryFormat(wave_dev->sb_hw->card_waveout, wave_fmt, CARDWAVE_QF_BITS);
+
+				if (woinst->mapped)
+				{
+					struct wave_format wave_fmt = woinst->wave_fmt;
+
+					if (sblive_waveoutSetControl(wave_dev->sb_hw, wave_out, WAVEINSTANCEFORMAT, (u32 *) &wave_fmt) != CTSTATUS_SUCCESS)
+					{
+						spin_unlock_irqrestore(&woinst->lock, flags);
+						DPF(2, "waveoutSetControl() failed!\n");
+						return -EINVAL;
+					}
+				}
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+
+				DPD(2, "Set playback sample size -> %d\n", wave_fmt->bitspersample);
+			}
+
+			if (file->f_mode & FMODE_READ)
+			{
+				struct wave_format *wave_fmt;
+
+				spin_lock_irqsave(&wiinst->lock, flags);
+
+				if (wave_in)
+					sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
+
+				wave_fmt = &wiinst->wave_fmt;
+				wave_fmt->bitspersample = val;
+
+				sblive_waveinQueryFormat(wave_dev->sb_hw->card_wavein, wave_fmt, CARDWAVE_QF_BITS);
+
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+
+				DPD(2, "set recording sample size -> %d\n", wave_fmt->bitspersample);
+			}
+
+			return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *)arg);
+		} else
+		{
+			if (file->f_mode & FMODE_READ)
+				val = wiinst->wave_fmt.bitspersample;
+			else if (file->f_mode & FMODE_WRITE)
+				val = woinst->wave_fmt.bitspersample;
+
+			return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg);
+		}
+		break;
+
+	case SOUND_PCM_READ_BITS:
+
+		if (file->f_mode & FMODE_READ)
+			val = wiinst->wave_fmt.bitspersample;
+		else if ( file->f_mode & FMODE_WRITE )
+			val = woinst->wave_fmt.bitspersample;
+
+		return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *)arg);
+
+	case SOUND_PCM_READ_RATE:
+
+		if (file->f_mode & FMODE_READ)
+			val = wiinst->wave_fmt.samplingrate;
+		else if ( file->f_mode & FMODE_WRITE )
+			val = woinst->wave_fmt.samplingrate;
+
+		return put_user(val, (int *)arg);
+
+	case SOUND_PCM_READ_CHANNELS:
+
+		if (file->f_mode & FMODE_READ)
+			val = wiinst->wave_fmt.channels;
+		else if ( file->f_mode & FMODE_WRITE )
+			val = woinst->wave_fmt.channels;
+
+		return put_user(val, (int *)arg);
+
+	case SOUND_PCM_WRITE_FILTER:
+		DPF(2, "SNDCTL_DSP_POST: not implemented\n");
+		break;
+
+	case SOUND_PCM_READ_FILTER:
+		DPF(2, "SNDCTL_DSP_POST: not implemented\n");
+		break;
+
+	case SNDCTL_DSP_SETSYNCRO:
+		DPF(2, "SNDCTL_DSP_POST: not implemented\n");
+		break;
+
+	case SNDCTL_DSP_GETTRIGGER:
+		DPF(2, "SNDCTL_DSP_GETTRIGGER:\n");
+
+		if (file->f_mode & FMODE_WRITE && (wave_dev->enablebits & PCM_ENABLE_OUTPUT))
+			val |= PCM_ENABLE_OUTPUT;
+		if (file->f_mode & FMODE_READ && (wave_dev->enablebits & PCM_ENABLE_INPUT))
+			val |= PCM_ENABLE_INPUT;
+
+		return put_user(val, (int *) arg);
+
+	case SNDCTL_DSP_SETTRIGGER:
+		DPF(2, "SNDCTL_DSP_SETTRIGGER:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+
+		if (file->f_mode & FMODE_WRITE)
+		{
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			if (wave_out)
+			{
+				if (val & PCM_ENABLE_OUTPUT)
+				{
+					sblive_waveoutStart(wave_dev);
+					wave_dev->enablebits |= PCM_ENABLE_OUTPUT;
+				} else
+				{
+					sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
+					wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT;
+				}
+			}
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+		}
+
+		if (file->f_mode & FMODE_READ)
+		{
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			if (wave_in)
+			{
+				if (val & PCM_ENABLE_INPUT)
+				{
+					sblive_waveinStart(wave_dev);
+					wave_dev->enablebits |= PCM_ENABLE_INPUT;
+				} else
+				{
+					sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
+					wave_dev->enablebits &= ~PCM_ENABLE_INPUT;
+				}
+			}
+
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+		}
+		break;
+
+	case SNDCTL_DSP_GETOSPACE:
+		{
+			audio_buf_info info;
+
+			DPF(4, "SNDCTL_DSP_GETOSPACE:\n");
+
+			if (!(file->f_mode & FMODE_WRITE))
+				return -EINVAL;
+
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			if (wave_out)
+			{
+				if (sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy, &pending)
+				    != CTSTATUS_SUCCESS)
+				{
+					DPF(2, "sblive_waveoutGetXferSize failed\n");
+
+					spin_unlock_irqrestore(&woinst->lock, flags);
+					return -EFAULT;
+				}
+				info.bytes = bytestocopy;
+			} else
+			{
+				calculate_ofrag(woinst);
+				info.bytes = woinst->numfrags * woinst->fragment_size;
+			}
+
+			if (woinst->silence_filled > 0)
+			{
+				if (woinst->silence_filled == 1)
+				{
+					if (pending <= woinst->fragment_size)
+						woinst->silence_filled = 2;
+					else
+						info.bytes += woinst->fragment_size;
+				}
+
+				if (woinst->silence_filled == 2)
+					info.bytes = woinst->numfrags * woinst->fragment_size;
+			}
+
+			info.fragstotal = woinst->numfrags;
+			info.fragments = info.bytes / woinst->fragment_size;
+			info.fragsize = woinst->fragment_size;
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			if (copy_to_user((int *) arg, &info, sizeof(info)))
+				return -EFAULT;
+		}
+		break;
+
+	case SNDCTL_DSP_GETISPACE:
+		{
+			audio_buf_info info;
+
+			DPF(4, "SNDCTL_DSP_GETISPACE:\n");
+
+			if (!(file->f_mode & FMODE_READ))
+				return -EINVAL;
+
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			if (wave_in)
+			{
+				if (sblive_waveinGetXferSize(wave_dev->sb_hw->card_wavein, wave_in, &bytestocopy, &pending)
+				    != CTSTATUS_SUCCESS)
+				{
+					DPF(2, "sblive_waveinGetXferSize failed\n");
+
+					spin_unlock_irqrestore(&wiinst->lock, flags);
+					return -EFAULT;
+				}
+
+				info.bytes = bytestocopy;
+
+			} else
+			{
+				calculate_ifrag(wiinst);
+				info.bytes = wiinst->numfrags * wiinst->fragment_size;
+			}
+
+			info.fragstotal = wiinst->numfrags;
+			info.fragments = info.bytes / wiinst->fragment_size;
+			info.fragsize = wiinst->fragment_size;
+
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+
+			if (copy_to_user((int *) arg, &info, sizeof(info)))
+				return -EFAULT;
+		}
+		break;
+
+	case SNDCTL_DSP_NONBLOCK:
+		DPF(2, "SNDCTL_DSP_NONBLOCK:\n");
+
+		file->f_flags |= O_NONBLOCK;
+		break;
+
+	case SNDCTL_DSP_GETODELAY:
+		DPF(4, "SNDCTL_DSP_GETODELAY:\n");
+
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+
+		spin_lock_irqsave(&woinst->lock, flags);
+
+		if (wave_out)
+		{
+			if (sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy, &pending)
+			    != CTSTATUS_SUCCESS)
+			{
+				DPF(2, "sblive_waveoutGetXferSize failed\n");
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				return -EFAULT;
+			}
+
+			if (woinst->silence_filled > 0)
+			{
+				if (woinst->silence_filled == 1)
+				{
+					if (pending <= woinst->fragment_size)
+						woinst->silence_filled = 2;
+					else
+						pending -= woinst->fragment_size;
+				}
+
+				if (woinst->silence_filled == 2)
+					pending = 0;
+			}
+
+			val = pending;
+		}
+
+		spin_unlock_irqrestore(&woinst->lock, flags);
+
+		return put_user(val, (int *) arg);
+
+	case SNDCTL_DSP_GETIPTR:
+		{
+			count_info cinfo;
+
+			DPF(4, "SNDCTL_DSP_GETIPTR: \n");
+
+			if (!(file->f_mode & FMODE_READ))
+				return -EINVAL;
+
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			if (wave_in)
+			{
+				if (sblive_waveinGetControl(wave_dev->sb_hw->card_wavein, wave_in, WAVECURPOS, (u32 *)&cinfo.ptr)
+				    != CTSTATUS_SUCCESS)
+				{
+					spin_unlock_irqrestore(&wiinst->lock, flags);
+					return -EINVAL;
+				}
+			} else
+				cinfo.ptr = 0;
+
+			DPD(4, "cinfo.ptr -> %d\n", cinfo.ptr);
+
+			cinfo.bytes = cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % (wiinst->fragment_size * wiinst->numfrags);
+			cinfo.blocks = wiinst->getiptr_blocks;
+
+			wiinst->getiptr_blocks = 0;
+
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+
+			if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo)))
+				return -EFAULT;
+		}
+		break;
+
+	case SNDCTL_DSP_GETOPTR:
+		{
+			count_info cinfo;
+
+			DPF(4, "SNDCTL_DSP_GETOPTR:\n");
+
+			if (!(file->f_mode & FMODE_WRITE))
+				return -EINVAL;
+
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			if (wave_out)
+			{
+				if (sblive_waveoutGetControl(wave_dev->sb_hw->card_waveout, wave_out, WAVECURPOS, (u32 *)&cinfo.ptr)
+				    != CTSTATUS_SUCCESS)
+				{
+					spin_unlock_irqrestore(&woinst->lock, flags);
+					return -EINVAL;
+				}
+			} else
+				cinfo.ptr = 0;
+
+			DPD(4, "cinfo.ptr -> %d\n", cinfo.ptr);
+
+			cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % (woinst->fragment_size * woinst->numfrags);
+			cinfo.blocks = cinfo.bytes / woinst->fragment_size - woinst->getoptr_blocks;
+
+			woinst->getoptr_blocks = cinfo.bytes / woinst->fragment_size;
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo)))
+				return -EFAULT;
+		}
+		break;
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		DPF(2, "SNDCTL_DSP_GETBLKSIZE:\n");
+
+		if (file->f_mode & FMODE_WRITE)
+		{
+			spin_lock_irqsave(&woinst->lock, flags);
+
+			calculate_ofrag(woinst);
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			return put_user(woinst->fragment_size, (int *) arg);
+		}
+
+		if (file->f_mode & FMODE_READ)
+		{
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			calculate_ifrag(wiinst);
+
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+
+			return put_user(wiinst->fragment_size, (int *) arg);
+		}
+		break;
+
+	case SNDCTL_DSP_POST:
+		DPF(2, "SNDCTL_DSP_POST: not implemented\n");
+		break;
+
+	case SNDCTL_DSP_SUBDIVIDE:
+		DPF(2, "SNDCTL_DSP_SUBDIVIDE: not implemented\n");
+		break;
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		DPF(2, "SNDCTL_DSP_SETFRAGMENT:\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+
+		DPD(2, "val is %x\n", val);
+
+		if (val == 0)
+			return -EIO;
+
+		if (file->f_mode & FMODE_WRITE)
+		{
+			if (wave_out)
+				return -EINVAL;		/* too late to change */
+
+			woinst->ossfragshift = val & 0xffff;
+			woinst->numfrags = (val >> 16) & 0xffff;
+		}
+
+		if (file->f_mode & FMODE_READ)
+		{
+			if (wave_in)
+				return -EINVAL;		/* too late to change */
+
+			wiinst->ossfragshift = val & 0xffff;
+			wiinst->numfrags = (val >> 16) & 0xffff;
+		}
+
+		break;
+
+	case SNDCTL_COPR_LOAD:
+		{
+			copr_buffer buf;
+			u32 i;
+			
+			DPF(2, "SNDCTL_COPR_LOAD:\n");
+
+			if (copy_from_user(&buf, (copr_buffer *) arg, sizeof(buf)))
+				return -EFAULT;
+			
+			if ((buf.command != 1) && (buf.command != 2))
+				return -EINVAL;
+
+			if ((buf.offs < 0) || (buf.offs + buf.len > 0x500) || (buf.len > 1000))
+				return -EINVAL;
+
+			buf.offs += 0x100;
+
+			if (buf.command == 1) {
+				for (i = 0; i < buf.len; i++)
+					((u32 *) buf.data)[i] = sblive_readptr(wave_dev->sb_hw, buf.offs + i, 0);
+                                if (copy_to_user((copr_buffer *) arg, &buf, sizeof(buf)))
+					return -EFAULT;											
+			} else {
+				for (i = 0; i < buf.len; i++)
+					sblive_writeptr(wave_dev->sb_hw, buf.offs + i, 0, ((u32 *) buf.data)[i]);
+			}
+			break;
+		}
+		
+	default:		/* Default is unrecognized command */
+		DPD(2, "default: %x\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
+
+	DPF(2, "emu10k1_audio_mmap() called\n");
+
+	if (vma_get_pgoff(vma) != 0)
+		return -ENXIO;
+
+	if (vma->vm_flags & VM_WRITE){
+		struct woinst *woinst = wave_dev->woinst;
+		u32 size, flags;
+		int i;
+
+		spin_lock_irqsave(&woinst->lock, flags);
+
+		if (!woinst->wave_out)
+		{
+			calculate_ofrag(woinst);
+
+			if (sblive_waveoutOpen(wave_dev->sb_hw, &woinst->wave_fmt, &woinst->fragment_size, woinst->numfrags, &woinst->wave_out)
+			    != CTSTATUS_SUCCESS)
+			{
+				DPF(2, "sblive_waveoutOpen failed!\n");
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				return -EINVAL;
+			}
+
+			/* Now mark the pages as reserved, otherwise remap_page_range doesn't do what we want */
+			for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++)
+				set_bit(PG_reserved, &mem_map[MAP_NR(woinst->wave_out->pagetable[i])].flags);
+		}
+
+		size = vma->vm_end - vma->vm_start;
+
+		if (size > (PAGE_SIZE * woinst->wave_out->wavexferbuf->numpages)) {
+			spin_unlock_irqrestore(&woinst->lock, flags);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++) {
+			if (remap_page_range(vma->vm_start + (i * 4096), virt_to_phys(woinst->wave_out->pagetable[i]), 4096, vma->vm_page_prot)) {
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				return -EAGAIN;
+			}
+		}
+
+		woinst->mapped = TRUE;
+
+		spin_unlock_irqrestore(&woinst->lock, flags);
+	}
+
+	if (vma->vm_flags & VM_READ){
+		struct wiinst *wiinst = wave_dev->wiinst;
+		u32 flags;
+
+		spin_lock_irqsave(&wiinst->lock, flags);
+		wiinst->mapped = TRUE;
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+	}
+
+	return 0;
+}
+
+static int emu10k1_audio_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct sblive_hw *sb_hw = sblive_devs;
+	struct sblive_wavedevice *wave_dev;
+
+	DPF(2, "emu10k1_audio_open() called\n");
+
+	/* Check for correct device to open */
+	while (sb_hw && ((sb_hw->audio_num ^ minor) & ~0x0f))
+		sb_hw = sb_hw->next;
+
+	if (!sb_hw)
+		return -ENODEV;
+
+	/* Wait for device to become free */
+	down(&sb_hw->open_sem);
+
+	while ((file->f_mode & FMODE_READ) && (sb_hw->open_mode & FMODE_READ))
+	{
+		if (file->f_flags & O_NONBLOCK)
+		{
+			up(&sb_hw->open_sem);
+			return -EAGAIN;
+		}
+
+		up(&sb_hw->open_sem);
+
+		DPF(2, "open sleep....\n");
+		interruptible_sleep_on(&sb_hw->open_wait);
+
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+
+		down(&sb_hw->open_sem);
+	}
+
+	wave_dev = (struct sblive_wavedevice *)kmalloc(sizeof(struct sblive_wavedevice), GFP_KERNEL);
+	if (!wave_dev)
+	{
+		DPF(2, "struct sblive_wavedevice alloc fail.\n");
+		up(&sb_hw->open_sem);
+		return -EINVAL;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", wave_dev);
+
+	wave_dev->sb_hw = sb_hw;
+	wave_dev->wiinst = NULL;
+	wave_dev->woinst = NULL;
+	wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT;	/* Default */
+
+	if (file->f_mode & FMODE_WRITE)
+	{
+		struct woinst *woinst;
+
+		woinst = (struct woinst *) kmalloc(sizeof(struct woinst), GFP_KERNEL);
+		if (woinst == NULL)
+		{
+			DPF(2, "struct woinst alloc failed.\n");
+			up(&sb_hw->open_sem);
+			return -ENODEV;
+		}
+
+		DPD(3, "kmalloc: [%p]\n", woinst);
+
+		/* Set default format to : mono 8-bit 8kHz */
+		woinst->wave_fmt.flags = 0;
+		woinst->wave_fmt.samplingrate = 8000;
+		woinst->wave_fmt.bitspersample = 8;
+		woinst->wave_fmt.channels = 1;
+		woinst->wave_fmt.isinput = (file->f_mode == FMODE_READ) ? TRUE : FALSE;
+		woinst->ossfragshift = 0;
+		woinst->fragment_size = 0;
+		woinst->numfrags = 0;
+		woinst->wave_out = NULL;	// wave_out instance
+
+		init_waitqueue_head(&woinst->wait_queue);
+
+		woinst->mapped = FALSE;
+		woinst->total_copied = 0;
+		woinst->total_played = 0;
+		woinst->silence_filled = 0;
+		woinst->silence_start = 0;
+		woinst->getoptr_blocks = 0;
+		woinst->wave_ptr = 0;
+		woinst->lock = SPIN_LOCK_UNLOCKED;
+		wave_dev->woinst = woinst;
+	}
+
+	if (file->f_mode & FMODE_READ)
+	{
+		/* Recording */
+		struct wiinst *wiinst;
+
+		/* Only support one wave input instance */
+		if (sb_hw->card_wavein->numrecordinst >= 1)
+		{
+			DPF(2, "exceed one wave input instance\n");
+			up(&sb_hw->open_sem);
+			return -ENODEV;
+		}
+
+		wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL);
+		if (wiinst == NULL)
+		{
+			DPF(2, "struct wiinst alloc failed\n");
+			up(&sb_hw->open_sem);
+			return -ENODEV;
+		}
+
+		DPD(3, "kmalloc: [%p]\n", wiinst);
+
+		/* Set default format to : mono 8-bit 8kHz */
+		wiinst->wave_fmt.flags = 0;
+		wiinst->wave_fmt.samplingrate = 8000;
+		wiinst->wave_fmt.bitspersample = 8;
+		wiinst->wave_fmt.channels = 1;
+		wiinst->wave_fmt.isinput = (file->f_mode == FMODE_READ) ? TRUE : FALSE;
+		wiinst->ossfragshift = 0;
+		wiinst->fragment_size = 0;
+		wiinst->numfrags = 0;
+		wiinst->wave_in = NULL;	/* sblive_wavein instance */
+
+		init_waitqueue_head(&wiinst->wait_queue);
+
+		wiinst->mapped = FALSE;
+		wiinst->total_recorded = 0;
+		wiinst->getiptr_blocks = 0;
+		wiinst->lock = SPIN_LOCK_UNLOCKED;
+		wave_dev->wiinst = wiinst;
+		wave_dev->sb_hw->card_wavein->numrecordinst++;
+
+#ifdef EMU10K1_DEBUG
+		if (wave_dev->woinst != NULL)
+			DPF(2, "audio_open opened both WAVEOUT and WAVEIN!\n");
+#endif
+
+	}
+
+	file->private_data = (void *) wave_dev;
+
+	sb_hw->open_mode |= file->f_mode & FMODE_READ;
+	up(&sb_hw->open_sem);
+
+	MOD_INC_USE_COUNT;
+	return 0; /* Success? */
+}
+
+
+static int emu10k1_audio_release(struct inode *inode, struct file *file)
+{
+	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
+	struct sblive_hw *sb_hw = wave_dev->sb_hw;
+
+	/* FIXME: Do we need a spinlock here? */
+
+	DPF(2, "emu10k1_audio_release() called\n");
+
+	if (file->f_mode & FMODE_WRITE)
+	{
+		struct woinst *woinst = wave_dev->woinst;
+		struct wave_out *wave_out = woinst->wave_out;
+
+		if (wave_out)
+		{
+			if ((wave_out->state == CARDWAVE_STATE_STARTED) && !(file->f_flags & O_NONBLOCK))
+			{
+				while (!signal_pending(current)
+				       && (woinst->total_played < woinst->total_copied))
+				{
+					DPF(2, "Buffer hasn't been totally played, sleep....\n");
+					interruptible_sleep_on(&woinst->wait_queue);
+				}
+			}
+
+			if (woinst->mapped && wave_out->pagetable)
+			{
+				int i;
+				/* Undo marking the pages as reserved */
+				for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++)
+					set_bit(PG_reserved, &mem_map[MAP_NR(woinst->wave_out->pagetable[i])].flags);
+			}
+
+			woinst->mapped = FALSE;
+			sblive_waveoutClose(wave_dev->sb_hw, wave_out);
+		}
+		kfree((void *) wave_dev->woinst);
+	}
+
+	if (file->f_mode & FMODE_READ)
+	{
+		struct wiinst *wiinst = wave_dev->wiinst;
+		struct wave_in *wave_in = wiinst->wave_in;
+
+		if (wave_in)
+		{
+			wiinst->mapped = FALSE;
+			sblive_waveinClose(wave_dev->sb_hw, wave_in);
+		}
+
+		kfree((void *) wave_dev->wiinst);
+
+		wave_dev->sb_hw->card_wavein->numrecordinst--;
+	}
+
+	kfree((void *) wave_dev);
+
+	down(&sb_hw->open_sem);
+	sb_hw->open_mode &= ~(file->f_mode & FMODE_READ);
+	up(&sb_hw->open_sem);
+	wake_up(&sb_hw->open_wait);
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+
+static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
+	u16 mask = 0;
+
+	DPF(4, "emu10k1_audio_poll() called\n");
+
+	if (file->f_mode & FMODE_READ)
+	{
+		struct wiinst *wiinst = wave_dev->wiinst;
+		struct wave_in *wave_in = wiinst->wave_in;
+
+		if (wave_in == NULL)
+			mask |= POLLIN | POLLRDNORM;
+		else
+		{
+			u32 flags, bytestocopy, pending;
+			int status;
+
+			poll_wait(file, &wiinst->wait_queue, wait);
+
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			status = sblive_waveinGetXferSize(wave_dev->sb_hw->card_wavein, wave_in, &bytestocopy, &pending);
+
+			spin_unlock_irqrestore(&wiinst->lock, flags);
+
+			if (status == CTSTATUS_SUCCESS)
+				if (bytestocopy > 0)
+					mask |= POLLIN | POLLRDNORM;
+		}
+	}
+
+	if (file->f_mode & FMODE_WRITE)
+	{
+		struct woinst *woinst = wave_dev->woinst;
+		struct wave_out *wave_out = woinst->wave_out;
+
+		if (wave_out == NULL)
+			mask |= POLLOUT | POLLWRNORM;
+		else
+		{
+			u32 flags, bytestocopy, pending;
+			int status;
+
+			poll_wait(file, &woinst->wait_queue, wait);
+
+			spin_lock_irqsave(&woinst->lock, flags);
+                        status = sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy, &pending); 
+
+			if(status != CTSTATUS_SUCCESS)
+			{
+				spin_unlock_irqrestore(&woinst->lock, flags);
+				return -EFAULT;
+			}
+
+			if (woinst->silence_filled > 0)
+			{
+				if (woinst->silence_filled == 1)
+				{
+					if (pending <= woinst->fragment_size)
+						woinst->silence_filled = 2;
+					else
+						bytestocopy += woinst->fragment_size;
+                        	}
+
+				if (woinst->silence_filled == 2)
+					bytestocopy = woinst->fragment_size * woinst->numfrags;
+			}
+
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
+			while(bytestocopy < woinst->fragment_size){
+				interruptible_sleep_on(&woinst->wait_queue);
+
+				if(signal_pending(current))
+					return -ERESTARTSYS;
+
+				spin_lock_irqsave(&woinst->lock, flags);
+				status = sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy, &pending);
+
+				if(status != CTSTATUS_SUCCESS)
+				{
+					spin_unlock_irqrestore(&woinst->lock, flags);
+                                        return -EFAULT;
+				}
+
+				if (woinst->silence_filled > 0)
+				{
+					if (woinst->silence_filled == 1)
+					{
+						if (pending <= woinst->fragment_size)
+							woinst->silence_filled = 2;
+						else
+							bytestocopy += woinst->fragment_size;
+					}
+
+					if (woinst->silence_filled == 2)
+						bytestocopy = woinst->fragment_size * woinst->numfrags;
+				}
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+			}
+
+			mask |= POLLOUT | POLLWRNORM;	
+		}
+	}
+
+	return mask;
+}
+
+
+static void calculate_ofrag(struct woinst *woinst)
+{
+	u32 fragsize = 0, bytespersec;
+
+	if (woinst->fragment_size)
+	{
+		DPF(2, "fragment_size already calculated!\n");
+		return;
+	}
+
+	bytespersec = woinst->wave_fmt.channels * (woinst->wave_fmt.bitspersample >> 3) * woinst->wave_fmt.samplingrate;
+
+	woinst->fragment_size = 1;
+
+	if (woinst->ossfragshift)
+		woinst->fragment_size <<= (woinst->ossfragshift < MINFRAGSHIFT ? MINFRAGSHIFT : woinst->ossfragshift);
+	else
+		fragsize = (bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1;
+
+	while (fragsize)
+	{
+		fragsize >>= 1;
+		woinst->fragment_size <<= 1;
+	}
+
+	if (!woinst->numfrags)
+	{
+		u32 numfrags;
+
+		numfrags = (bytespersec * WAVEOUT_DEFAULTBUFLEN)  / (woinst->fragment_size * 1000) - 1;
+
+		woinst->numfrags = 1;
+
+		while (numfrags)
+		{
+			numfrags >>= 1;
+			woinst->numfrags <<= 1;
+		}
+	}
+
+	if (woinst->numfrags < MINFRAGS)
+		woinst->numfrags = MINFRAGS;
+
+	if (woinst->numfrags * woinst->fragment_size > WAVEOUT_MAXBUFSIZE)
+	{
+		woinst->numfrags = WAVEOUT_MAXBUFSIZE / woinst->fragment_size;
+
+		if (woinst->numfrags < MINFRAGS)
+		{
+			woinst->numfrags = MINFRAGS;
+			woinst->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS;
+		}
+
+	} else
+		if (woinst->numfrags * woinst->fragment_size < WAVEOUT_MINBUFSIZE)
+			woinst->numfrags = WAVEOUT_MINBUFSIZE / woinst->fragment_size;
+
+	DPD(2, " calculated playback fragment_size -> %d\n", woinst->fragment_size);
+	DPD(2, " calculated playback numfrags -> %d\n", woinst->numfrags);
+}
+
+static void calculate_ifrag(struct wiinst *wiinst)
+{
+	u32 fragsize, bytespersec;
+
+	if (wiinst->fragment_size)
+	{
+		DPF(2, "fragment_size already calculated!\n");
+		return;
+	}
+
+	bytespersec = wiinst->wave_fmt.channels * (wiinst->wave_fmt.bitspersample >> 3) * wiinst->wave_fmt.samplingrate;
+
+	wiinst->fragment_size = 1;
+
+	if (wiinst->ossfragshift)
+		wiinst->fragment_size <<= (wiinst->ossfragshift < MINFRAGSHIFT ? MINFRAGSHIFT : wiinst->ossfragshift);
+	else
+	{
+		fragsize = (bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1;
+
+		while (fragsize)
+		{
+			fragsize >>= 1;
+			wiinst->fragment_size <<= 1;
+		}
+	}
+
+	if (!wiinst->numfrags)
+		wiinst->numfrags = (WAVEIN_DEFAULTBUFLEN * bytespersec) / (wiinst->fragment_size * 1000);
+
+	if (wiinst->numfrags < MINFRAGS)
+		wiinst->numfrags = MINFRAGS;
+
+	if (wiinst->numfrags * wiinst->fragment_size > WAVEIN_MAXBUFSIZE) {
+		wiinst->numfrags = WAVEIN_MAXBUFSIZE / wiinst->fragment_size;
+		if (wiinst->numfrags < MINFRAGS) {
+			wiinst->numfrags = MINFRAGS;
+			wiinst->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS;
+		}
+	}
+
+	DPD(2, " calculated recording fragment_size -> %d\n", wiinst->fragment_size);
+	DPD(2, " calculated recording numfrags -> %d\n", wiinst->numfrags);
+}
+
+void waveInCallbackFn(void *refdata)
+{
+	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) refdata;
+	struct wiinst *wiinst = wave_dev->wiinst;
+	struct wave_in *wave_in = wiinst->wave_in;
+	u32 bytestocopy, pending;
+	unsigned long flags;
+
+	/* Are these locks necessary around the wake_up ? kabi@i.am */
+	spin_lock_irqsave(&wiinst->lock, flags);
+
+	wiinst->getiptr_blocks++;
+
+	wiinst->total_recorded += wiinst->fragment_size;
+
+	if (wiinst->mapped){
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+		return;
+	}
+
+	if (sblive_waveinGetXferSize(wave_dev->sb_hw->card_wavein, wave_in, &bytestocopy, &pending) == CTSTATUS_SUCCESS)
+	{
+		if (bytestocopy >= wiinst->fragment_size)
+		{
+			DPF(2, "Wake UP!\n");
+			wake_up(&wiinst->wait_queue);
+		} else
+			DPD(4, "Not enough transfer size, %d\n", bytestocopy);
+	}
+
+	spin_unlock_irqrestore(&wiinst->lock, flags);
+
+	return;
+}
+
+void waveOutCallbackFn(void *refdata)
+{
+	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) refdata;
+	struct woinst *woinst = wave_dev->woinst;
+	struct wave_out *wave_out = woinst->wave_out;
+	u32 bytestocopy, pending, waveptr;
+	unsigned long flags;
+
+	if(wave_out->state == CARDWAVE_STATE_STOPPED)
+		return;
+
+	spin_lock_irqsave(&woinst->lock, flags);
+
+	if (sblive_waveoutGetControl(wave_dev->sb_hw->card_waveout, wave_out, WAVECURPOS, (u32 *)&waveptr) == CTSTATUS_SUCCESS)
+	{
+		woinst->total_played += waveptr - woinst->wave_ptr;
+
+		if (waveptr < woinst->wave_ptr)
+			woinst->total_played += woinst->fragment_size * woinst->numfrags;
+
+		woinst->wave_ptr = waveptr;
+	}
+
+	if (woinst->mapped)
+	{
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		return;
+	}
+
+	if (sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy, &pending) == CTSTATUS_SUCCESS)
+	{
+		if (bytestocopy >= woinst->fragment_size || woinst->silence_filled > 0)
+		{
+			if (pending <= woinst->fragment_size && bytestocopy >= woinst->fragment_size)
+			{
+				if (woinst->silence_filled == 0)
+					sblive_waveoutGetControl(wave_dev->sb_hw->card_waveout, wave_out, WAVEWRITEPOINTER, &woinst->silence_start);
+
+				bytestocopy = woinst->fragment_size;
+
+				sblive_waveoutFillSilence(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy);
+
+				if (woinst->silence_filled < 2)
+					woinst->silence_filled++;
+			}
+
+			wake_up(&woinst->wait_queue);
+		} else
+			DPD(4, "Not enough transfer size -> %x\n", bytestocopy);
+	}
+
+	spin_unlock_irqrestore(&woinst->lock, flags);
+
+	return;
+}
+
+int audio_init(struct sblive_hw * sb_hw, u8 * pname)
+{
+	/* Initialize CardwaveOut struct */
+	sb_hw->card_waveout = kmalloc(sizeof(struct sblive_waveout), GFP_KERNEL);
+	if (sb_hw->card_waveout == NULL)
+	{
+		printk(KERN_WARNING "sblive: Unable to allocate struct sblive_waveout: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", sb_hw->card_waveout);
+
+	/* Initialize CardwaveIn struct */
+	sb_hw->card_wavein = kmalloc(sizeof(struct sblive_wavein), GFP_KERNEL);
+	if (sb_hw->card_wavein == NULL)
+	{
+		kfree(sb_hw->card_waveout);
+		sb_hw->card_waveout = NULL;
+		printk(KERN_WARNING "sblive: Unable to allocate struct sblive_wavein: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", sb_hw->card_wavein);
+
+	sblive_waveoutInit(sb_hw->card_waveout, pname);
+	sblive_waveinInit(sb_hw->card_wavein, pname);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int audio_exit(struct sblive_hw *sb_hw)
+{
+	sblive_waveoutExit(sb_hw->card_waveout);
+	sblive_waveinExit(sb_hw->card_wavein);
+
+	kfree(sb_hw->card_waveout);
+	DPD(3, "kfree: [%p]\n", sb_hw->card_waveout);
+	sb_hw->card_waveout = NULL;
+
+	kfree(sb_hw->card_wavein);
+	DPD(3, "kfree: [%p]\n", sb_hw->card_wavein);
+	sb_hw->card_wavein = NULL;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+struct file_operations emu10k1_audio_fops =
+{
+	&emu10k1_audio_llseek,
+	&emu10k1_audio_read,
+	&emu10k1_audio_write,
+	NULL,
+	&emu10k1_audio_poll,
+	&emu10k1_audio_ioctl,
+	&emu10k1_audio_mmap,
+	&emu10k1_audio_open,
+	NULL,
+	&emu10k1_audio_release,
+	NULL,
+};
Index: oldkernel/linux/drivers/sound/emu10k1/audio.h
diff -u /dev/null linux/drivers/sound/emu10k1/audio.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/audio.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,60 @@
+/*
+ **********************************************************************
+ *     audio.c -- /dev/dsp interface for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999	    Alan Cox        cleaned up types/leaks
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+/*
+ *	FIXME:
+ *		There are some 32bit assumptions here
+ *		Cast of pointers to 32bit values is unsafe
+ *			- Wave callbacks and elsewhere
+ */
+
+#ifndef _AUDIO_H
+#define _AUDIO_H
+
+#ifdef MODULE
+#define __NO_VERSION__
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#define MINFRAGS	2
+#define MINFRAGSHIFT	4
+
+void waveOutCallbackFn(void *);
+void waveInCallbackFn(void *);
+
+int audio_init(struct sblive_hw *sb_hw, u8 *pname);
+int audio_exit(struct sblive_hw *sb_hw);
+
+#endif /* _AUDIO_H */
Index: oldkernel/linux/drivers/sound/emu10k1/cardmi.c
diff -u /dev/null linux/drivers/sound/emu10k1/cardmi.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/cardmi.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,1107 @@
+/*
+ **********************************************************************
+ *     sblive_mi.c - MIDI UART input HAL for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox        clean up
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "cardmi.h"
+
+static struct
+{
+	int (*Fn) (struct sblive_mpuin * card_mpuin, u8 data);
+} midistatefn[] =
+{
+	{ sblive_miStateParse },
+	{ sblive_miState3Byte }, 	/* 0x8n, 0x9n, 0xAn, 0xBn, 0xEn */
+	{ sblive_miState3ByteKey },    	/* Byte 1                       */
+	{ sblive_miState3ByteVel },    	/* Byte 2                       */
+	{ sblive_miState2Byte },       	/* 0xCn, 0xDn                   */
+	{ sblive_miState2ByteKey },    	/* Byte 1                       */
+	{ sblive_miStateSysCommon2 },	/* 0xF1 , 0xF3                  */
+	{ sblive_miStateSysCommon2Key },/* 0xF1 , 0xF3, Byte 1          */
+	{ sblive_miStateSysCommon3 },  	/* 0xF2                         */
+	{ sblive_miStateSysCommon3Key },/* 0xF2 , Byte 1                */
+	{ sblive_miStateSysCommon3Vel },/* 0xF2 , Byte 2                */
+	{ sblive_miStateSysExNorm },	/* 0xF0, 0xF7, Normal mode      */
+	{ sblive_miStateSysReal }	/* 0xF4 - 0xF6 ,0xF8 - 0xFF     */
+};
+
+/****************************************************************************/
+/* int    sblive_mpuinInit(struct sblive_mpuin *card_mpuin, PICARD pICard ) */
+/*                                                                          */
+/* Function:   Initialize the parameters and reset the MPU port             */
+/****************************************************************************/
+int sblive_mpuinInit(struct sblive_mpuin *card_mpuin, struct sblive_hw *sb_hw)
+{
+	char name[128];
+
+	DPF(2, "sblive_mpuinInit\n");
+
+	memset(card_mpuin, 0, sizeof(struct sblive_mpuin));
+
+	card_mpuin->status = FLAGS_AVAILABLE;	// clear
+
+	card_mpuin->caps.cbsize = sizeof(struct midi_caps);
+	card_mpuin->caps.support = MIDICAPS_INPUT;
+	card_mpuin->caps.technology = 0;
+	card_mpuin->caps.product = MM_CREATIVE_MIDIIN;
+	card_mpuin->caps.manufacturer = MM_CREATIVE;
+	card_mpuin->caps.voices = 0;
+	card_mpuin->caps.notes = 0;
+	card_mpuin->caps.channelmask = 0;
+	card_mpuin->caps.caps = CARDMIDI_IN;
+
+	card_mpuin->task.next = NULL;
+	card_mpuin->task.sync = 0;
+	card_mpuin->task.routine = sblive_mpuinDpcCallback;
+	card_mpuin->task.data = card_mpuin;
+
+	spin_lock_init(&card_mpuin->lock);
+
+	strcpy(name, IDS_EMU_MIDIIN_PNAME);
+
+	/* Fill in card caps */
+	sprintf(card_mpuin->caps.MIDIname, "%s [%lx]", name, sb_hw->hwaddr );
+
+	/* Reset the MPU port */
+	if (hwmpuReset(sb_hw) != CTSTATUS_SUCCESS)
+	{
+		DPF(2, "cardmi.c: MPU hardware reset failure\n");
+		return CTSTATUS_NOTENABLED;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinExit(struct sblive_mpuin *card_mpuin)                 */
+/*                                                                          */
+/* Function:   Disable the IRQ TX and uninstall the IRQ handler             */
+/****************************************************************************/
+int sblive_mpuinExit(struct sblive_hw *sb_hw)
+{
+	DPF(2, "sblive_mpuinExit\n");
+
+	/* Disable RX interrupt */
+	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDIRXENABLE);
+
+	return CTSTATUS_SUCCESS;
+}
+
+/****************************************************************************/
+/* int    sblive_mpuinGetCaps(struct sblive_mpuin *card_mpuin,              */
+/*                              struct midi_caps *midi_caps)                */
+/*                                                                          */
+/* Function:   Returns the MPU IN capabilities                              */
+/****************************************************************************/
+int sblive_mpuinGetCaps(struct sblive_mpuin *card_mpuin, struct midi_caps *midi_caps)
+{
+	u32 cbsize;
+
+	DPF(2, "sblive_mpuinGetCaps\n");
+
+	cbsize = min(midi_caps->cbsize, card_mpuin->caps.cbsize);
+	memcpy(midi_caps, &card_mpuin->caps, cbsize);
+	midi_caps->cbsize = cbsize;
+
+	return CTSTATUS_SUCCESS;
+}
+
+/****************************************************************************/
+/* int    sblive_mpuinOpen(struct sblive_mpuin *card_mpuin,                 */
+/*                           struct midi_openinfo *openinfo,                */
+/*                           u32 * handle)                                  */
+/*                                                                          */
+/* Function:   Installs the IRQ handler for the MPU in port                 */
+/*             and initialize parameters                                    */
+/****************************************************************************/
+int sblive_mpuinOpen(struct sblive_hw *sb_hw, struct midi_openinfo *openinfo)
+{
+	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+
+	DPF(2, "sblive_mpuinOpen\n");
+
+	if (!(card_mpuin->status & FLAGS_AVAILABLE))
+		return CTSTATUS_INUSE;
+
+	/* Copy open info and mark channel as in use */
+	card_mpuin->openinfo = *openinfo;
+	card_mpuin->status &= ~FLAGS_AVAILABLE;	/* clear */
+	card_mpuin->status |= FLAGS_READY;	/* set */
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
+	card_mpuin->firstmidiq = NULL;
+	card_mpuin->lastmidiq = NULL;
+	card_mpuin->qhead = 0;
+	card_mpuin->qtail = 0;
+
+	sblive_miStateInit(card_mpuin);
+
+	hwmpuReset(sb_hw);
+	hwmpuAcquire(sb_hw);
+
+	return CTSTATUS_SUCCESS;
+}
+
+/****************************************************************************/
+/* int    sblive_mpuinClose(struct sblive_mpuin *card_mpuin,                */
+/*                            u32 handle)                                   */
+/*                                                                          */
+/* Function:   If Midi Buffers are present,                                 */
+/*             return CTSTATUS_STILLPLAYING                                 */
+/*             Otherwise disable and uninstall IRQ handler                  */
+/****************************************************************************/
+int sblive_mpuinClose(struct sblive_hw *sb_hw)
+{
+	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+
+	DPF(2, "sblive_mpuinClose\n");
+
+	/* Check if there are pending input SysEx buffers */
+	if (card_mpuin->firstmidiq != NULL)
+	{
+		DPF(2, "Cannot close, MIDI buffers are present.\n");
+		return CTSTATUS_STILLPLAYING;
+	}
+
+	/* Disable RX interrupt */
+	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDIRXENABLE);
+
+	hwmpuRelease(sb_hw);
+
+	card_mpuin->status |= FLAGS_AVAILABLE;	   /* set */
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
+
+	return CTSTATUS_SUCCESS;
+}
+
+/****************************************************************************/
+/* int    sblive_mpuinAddBuffer(struct sblive_mpuin *card_mpuin,            */
+/*                                u32 handle,                               */
+/*                                struct midi_hdr *INFO midihdrInfo)        */
+/*                                                                          */
+/* Function:   Adds MIDI buffer to local queue list                         */
+/****************************************************************************/
+int sblive_mpuinAddBuffer(struct sblive_mpuin *card_mpuin, struct midi_hdr *midihdr)
+{
+	struct midi_queue *midiq;
+	unsigned long flags;
+
+	DPF(2, "sblive_mpuinAddBuffer\n");
+
+	/* Update MIDI buffer flags */
+	midihdr->flags |= MIDIBUF_INQUEUE; /* set */
+	midihdr->flags &= ~MIDIBUF_DONE;   /* clear */
+
+	midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC);
+	if (midiq == NULL)
+	{
+		/* Message lost */
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", midiq);
+
+	midiq->next = NULL;
+	midiq->qtype = 1;
+	midiq->length = midihdr->bufferlength;
+	midiq->sizeLeft = midihdr->bufferlength;
+	midiq->midibyte = midihdr->lpData;
+	midiq->refdata = (unsigned long) midihdr;
+
+	spin_lock_irqsave(&card_mpuin->lock, flags);
+
+	if (card_mpuin->firstmidiq == NULL)
+	{
+		card_mpuin->firstmidiq = midiq;
+		card_mpuin->lastmidiq = midiq;
+	} else
+	{
+		(card_mpuin->lastmidiq)->next = midiq;
+		card_mpuin->lastmidiq = midiq;
+	}
+
+	spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinStart(struct sblive_mpuin *card_mpuin,                */
+/*                            u32 handle,                                   */
+/*                                                                          */
+/* Function:   First set the Time Stamp if MIDI IN has not started.         */
+/*             Then enable RX Irq.                                          */
+/****************************************************************************/
+int sblive_mpuinStart(struct sblive_hw *sb_hw)
+{
+	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+	u8 dummy;
+
+	DPF(2, "sblive_mpuinStart\n");
+
+	/* Set timestamp if not set */
+	if (card_mpuin->status & FLAGS_MIDM_STARTED)
+	{
+		DPF(2, "Time Stamp not changed\n");
+	} else
+	{
+		while (hwmpuReadData(sb_hw, &dummy) == CTSTATUS_SUCCESS);
+
+		card_mpuin->status |= FLAGS_MIDM_STARTED; /* set */
+
+		/* Set new time stamp */
+		card_mpuin->timestart = (jiffies * 1000)/HZ;
+		DPD(2, "New Time Stamp = %d\n", card_mpuin->timestart);
+
+		card_mpuin->qhead = 0;
+		card_mpuin->qtail = 0;
+
+		sblive_irqmgrEnableIrq(sb_hw, INTE_MIDIRXENABLE);
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinStop(struct sblive_mpuin *card_mpuin,                 */
+/*                           u32 handle,                                    */
+/*                                                                          */
+/* Function:   Disable the RX Irq.  If a partial recorded buffer            */
+/*             exist, send it up to IMIDI level.                            */
+/****************************************************************************/
+int sblive_mpuinStop(struct sblive_hw *sb_hw)
+{
+	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+	struct midi_queue *midiq;
+	unsigned long flags;
+
+	DPF(2, "sblive_mpuinStop\n");
+
+	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDIRXENABLE);
+
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
+
+	if (card_mpuin->firstmidiq)
+	{
+		spin_lock_irqsave(&card_mpuin->lock, flags);
+
+		midiq = card_mpuin->firstmidiq;
+		if (midiq != NULL)
+		{
+			if (midiq->sizeLeft == midiq->length)
+				midiq = NULL;
+			else
+			{
+				card_mpuin->firstmidiq = midiq->next;
+				if (card_mpuin->firstmidiq == NULL)
+					card_mpuin->lastmidiq = NULL;
+			}
+		}
+
+		spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+		if (midiq)
+		{
+			sblive_mpuinMidiCallback (card_mpuin, ICARDMIDI_INLONGERROR, (u32)midiq, 0);
+			kfree(midiq);
+			DPD(3, "kfree: [%p]\n", midiq);
+		}
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinWriteShortData(struct sblive_mpuin *card_mpuin,       */
+/*                                     u32 handle,                          */
+/*                                     u32 midimsg)                         */
+/*                                                                          */
+/* Function:   Not Used                                                     */
+/****************************************************************************/
+int sblive_mpuinWriteShortData(struct sblive_mpuin *card_mpuin, u32 midimsg)
+{
+	DPF(2, "sblive_mpuinWriteShortData(): not supported\n");
+	return CTSTATUS_NOTSUPPORTED;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinPause(struct sblive_mpuin *card_mpuin,                */
+/*                            u32 handle,                                   */
+/*                                                                          */
+/* Function:   Not Used                                                     */
+/****************************************************************************/
+int sblive_mpuinPause(struct sblive_mpuin *card_mpuin)
+{
+	DPF(2, "sblive_mpuinPause(): not supported\n");
+	return CTSTATUS_NOTSUPPORTED;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinStream(struct sblive_mpuin * card_mpuin,              */
+/*                             u32 handle,                                  */
+/*                             struct midi_hdr *INFO midihdrInfo)           */
+/*                                                                          */
+/* Function:   Not Used                                                     */
+/****************************************************************************/
+int sblive_mpuinStream(struct sblive_mpuin *card_mpuin, struct midi_hdr *midihdr)
+{
+	DPF(2, "sblive_mpuinStream(): not supported\n");
+	return CTSTATUS_NOTSUPPORTED;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinRestart(struct sblive_mpuin *card_mpuin,              */
+/*                              u32 handle,                                 */
+/*                                                                          */
+/* Function:   Not Used                                                     */
+/****************************************************************************/
+int sblive_mpuinRestart(struct sblive_mpuin *card_mpuin)
+{
+	DPF(2, "sblive_mpuinRestart(): not supported\n");
+	return CTSTATUS_NOTSUPPORTED;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinReset(struct sblive_mpuin *card_mpuin,                */
+/*                            u32 handle,                                   */
+/*                                                                          */
+/* Function:   Disable the RX Irq.  If any buffer                           */
+/*             exist, send it up to IMIDI level.                            */
+/****************************************************************************/
+int sblive_mpuinReset(struct sblive_hw *sb_hw)
+{
+	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+	struct midi_queue *midiq;
+
+	DPF(2, "sblive_mpuinReset: start\n");
+
+	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDIRXENABLE);
+
+	while (card_mpuin->firstmidiq)
+	{
+		midiq = card_mpuin->firstmidiq;
+		card_mpuin->firstmidiq = midiq->next;
+
+		if (midiq->sizeLeft == midiq->length)
+			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INLONGDATA, (u32) midiq, 0);
+		else
+			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INLONGERROR, (u32) midiq, 0);
+
+		kfree(midiq);
+		DPD(3, "kfree: [%p]\n", midiq);
+	}
+
+	card_mpuin->lastmidiq = NULL;
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinCache(struct sblive_mpuin *card_mpuin,                */
+/*                            u32 handle,                                   */
+/*                            struct midi_cache * midicache)                */
+/*                                                                          */
+/* Function:   Not Used                                                     */
+/****************************************************************************/
+int sblive_mpuinCache(struct sblive_mpuin *card_mpuin, struct midi_cache *midicache)
+{
+	DPF(2, "sblive_mpuinCache(): not supported\n");
+	return CTSTATUS_NOTSUPPORTED;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinGetPosition(struct sblive_mpuin *card_mpuin,          */
+/*                                  u32 handle,                             */
+/*                                  u32 *position)                          */
+/*                                                                          */
+/* Function:   Not Used                                                     */
+/****************************************************************************/
+int sblive_mpuinGetPosition(struct sblive_mpuin *card_mpuin, u32 *position)
+{
+	DPF(2, "sblive_mpuinGetPosition(): not supported\n");
+	return CTSTATUS_NOTSUPPORTED;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinGetControl(struct sblive_mpuin *card_mpuin,           */
+/*                                 u32 handle,                              */
+/*                                 u32 controlid,                           */
+/*                                 u32 *value)                              */
+/*                                                                          */
+/* Function:   Not Used                                                     */
+/****************************************************************************/
+int sblive_mpuinGetControl(struct sblive_mpuin *card_mpuin, u32 controlid, u32 *value)
+{
+	DPF(2, "sblive_mpuinGetControl\n");
+
+	switch (controlid)
+	{
+	case MIDIQUERYACTIVEINST:
+		DPF(2, "controlid = MIDIQUERYACTIVE\n");
+		if (card_mpuin == NULL)
+			return CTSTATUS_ERROR;
+		if (!(card_mpuin->status & FLAGS_AVAILABLE))
+			return CTSTATUS_SUCCESS;
+		else
+			return CTSTATUS_ERROR;
+	default:
+		break;
+	}
+
+	return CTSTATUS_NOTSUPPORTED;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinSetControl(struct sblive_mpuin *card_mpuin,           */
+/*                                 u32 handle,                              */
+/*                                 u32 controlid,                           */
+/*                                 u32 *value)                              */
+/*                                                                          */
+/* Function:   Not Used                                                     */
+/****************************************************************************/
+int sblive_mpuinSetControl(struct sblive_mpuin *card_mpuin, u32 controlid, u32 *value)
+{
+	DPF(2, "sblive_mpuinSetControl(): not supported\n");
+	return CTSTATUS_NOTSUPPORTED;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinMidiCallback(struct sblive_mpuin *card_mpuin,         */
+/*                                   u32 msg,                               */
+/*                                   u32 data)                              */
+/*                                                                          */
+/* Function:   Passes the message with the data back to the client          */
+/*             via IRQ & DPC callbacks to Ring 3                            */
+/****************************************************************************/
+int sblive_mpuinMidiCallback(struct sblive_mpuin *card_mpuin, u32 msg, u32 data, u32 bytesvalid)
+{
+	u32 timein;
+	struct midi_queue *midiq;
+	unsigned long callback_msg[3];
+	struct midi_hdr *midihdr;
+
+	/* Called during ISR. The data & code touched are:
+	 * 1. card_mpuin
+	 * 2. The function to be called
+	 */
+
+	timein = card_mpuin->timein;
+	if (card_mpuin->timestart <= timein)
+		callback_msg[0] = timein - card_mpuin->timestart;
+	else
+		callback_msg[0] = (~0x0L- card_mpuin->timestart) + timein;
+
+	if (msg == ICARDMIDI_INDATA || msg == ICARDMIDI_INDATAERROR)
+	{
+		callback_msg[1] = data;
+		callback_msg[2] = bytesvalid;
+		DPD(2, "sblive_mpuinMidiCallback: midimsg = %x\n", data);
+	} else
+	{
+		midiq = (struct midi_queue *) data;
+		midihdr = (struct midi_hdr *) midiq->refdata;
+
+		callback_msg[1] = midiq->length - midiq->sizeLeft;
+		callback_msg[2] = midiq->refdata;
+		midihdr->flags &= ~MIDIBUF_INQUEUE;
+		midihdr->flags |= MIDIBUF_DONE;
+
+		midihdr->bytesrecorded = midiq->length - midiq->sizeLeft;
+	}
+
+	/* Notify client that Sysex buffer has been sent */
+	midiCallbackFn(msg, card_mpuin->openinfo.refdata, callback_msg);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* int sblive_mpuinDpcCallback ()                                           */
+/****************************************************************************/
+void sblive_mpuinDpcCallback(void *refdata)
+{
+	u8 data;
+	unsigned idx;
+	struct sblive_mpuin *card_mpuin = (struct sblive_mpuin *) refdata;
+	unsigned long flags;
+
+	while (card_mpuin->qhead != card_mpuin->qtail)
+	{
+		spin_lock_irqsave(&card_mpuin->lock, flags);
+		idx = card_mpuin->qhead;
+		data = card_mpuin->midiq[idx].data;
+		card_mpuin->timein = card_mpuin->midiq[idx].timein;
+		idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
+		card_mpuin->qhead = idx;
+		spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+		sblive_miStateEntry(card_mpuin, data);
+	}
+
+	return;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuinIrqCallback(u32 event,                                */
+/*                                  u32 refdata,                            */
+/*                                  u32 param)                              */
+/*                                                                          */
+/* Function:   IRQ callback handler routine for the MPU in port             */
+/****************************************************************************/
+int sblive_mpuinIrqCallback(struct sblive_hw *sb_hw)
+{
+	unsigned idx;
+	unsigned count;
+	u8 MPUIvalue;
+	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+
+
+	/* IRQ service routine. The data and code touched are:
+	 * 1. card_mpuin
+	 */
+
+	count = 0;
+	idx = card_mpuin->qtail;
+
+	while (1)
+	{
+		if (hwmpuReadData(sb_hw, &MPUIvalue) == CTSTATUS_SUCCESS)
+		{
+			++count;
+			card_mpuin->midiq[idx].data = MPUIvalue;
+			card_mpuin->midiq[idx].timein = (jiffies * 1000)/HZ;
+			idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
+		} else
+		{
+			break;
+		}
+	}
+
+	if (count)
+	{
+		card_mpuin->qtail = idx;
+
+		queue_task(&card_mpuin->task, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/*   Supporting functions for Midi-In Interpretation State Machine           */
+/*****************************************************************************/
+
+/* FIXME: This should be a macro */
+int sblive_miStateInit(struct sblive_mpuin *card_mpuin)
+{
+	card_mpuin->status = 0;	/* For MIDI running status */
+	card_mpuin->fstatus = 0; /* For 0xFn status only */
+	card_mpuin->curstate = STIN_PARSE;
+	card_mpuin->laststate = STIN_PARSE;
+	card_mpuin->data = 0;
+	card_mpuin->timestart = 0;
+	card_mpuin->timein = 0;
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* FIXME: This should be a macro */
+int sblive_miStateEntry(struct sblive_mpuin *card_mpuin, u8 data)
+{
+	return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
+}
+
+
+int sblive_miStateParse(struct sblive_mpuin *card_mpuin, u8 data)
+{
+	switch (data & 0xf0)
+	{
+	case 0x80:
+	case 0x90:
+	case 0xA0:
+	case 0xB0:
+	case 0xE0:
+		card_mpuin->curstate = STIN_3BYTE;
+		break;
+
+	case 0xC0:
+	case 0xD0:
+		card_mpuin->curstate = STIN_2BYTE;
+		break;
+
+	case 0xF0:
+		/* System messages do not affect the previous running status! */
+		switch (data & 0x0f)
+		{
+		case 0x0:
+			card_mpuin->laststate = card_mpuin->curstate;
+			card_mpuin->curstate = STIN_SYS_EX_NORM;
+
+			if (card_mpuin->firstmidiq)
+			{
+				struct midi_queue *midiq;
+
+				midiq = card_mpuin->firstmidiq;
+				*midiq->midibyte = data;
+				--midiq->sizeLeft;
+				++midiq->midibyte;
+			}
+
+			return CTSTATUS_NEXT_BYTE;
+
+		case 0x7:
+			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, 0xF7, 0);
+			return CTSTATUS_ERROR;
+
+		case 0x2:
+			card_mpuin->laststate = card_mpuin->curstate;
+			card_mpuin->curstate = STIN_SYS_COMMON_3;
+			break;
+
+		case 0x1:
+		case 0x3:
+			card_mpuin->laststate = card_mpuin->curstate;
+			card_mpuin->curstate = STIN_SYS_COMMON_2;
+			break;
+
+		default:
+			/* includes 0xF4 - 0xF6, 0xF8 - 0xFF */
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+		}
+
+		break;
+
+	default:
+		DPF(2, "BUG: default case hit\n");
+		return CTSTATUS_ERROR;
+	}
+
+	return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
+}
+
+
+int sblive_miState3Byte(struct sblive_mpuin *card_mpuin, u8 data)
+{
+	u8 bTemp = data & 0xF0;
+
+	if (bTemp < 0x80)
+	{
+		return midistatefn[STIN_3BYTE_KEY].Fn(card_mpuin, data);
+	} else
+		if (bTemp <= 0xE0 && bTemp != 0xC0 && bTemp != 0xD0)
+		{
+			card_mpuin->status = data;
+			card_mpuin->curstate = STIN_3BYTE_KEY;
+
+			return CTSTATUS_NEXT_BYTE;
+		}
+
+	return midistatefn[STIN_PARSE].Fn(card_mpuin, data);
+}
+
+
+int sblive_miState3ByteKey(struct sblive_mpuin *card_mpuin, u8 data)
+/* byte 1 */
+{
+	u32 tmp;
+
+	if (data > 0x7F)
+	{
+		/* Real-time messages check */
+		if (data > 0xF7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = STIN_PARSE;
+		tmp = ((u32) data) << 8;
+		tmp |= card_mpuin->status;
+
+		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->data = data;
+	card_mpuin->curstate = STIN_3BYTE_VEL;
+
+	return CTSTATUS_NEXT_BYTE;
+}
+
+
+int sblive_miState3ByteVel(struct sblive_mpuin *card_mpuin, u8 data)
+/* byte 2 */
+{
+	u32 tmp;
+
+	if (data > 0x7F)
+	{
+		/* Real-time messages check */
+		if (data > 0xF7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = STIN_PARSE;
+		tmp = ((u32) data) << 8;
+		tmp |= card_mpuin->data;
+		tmp = tmp << 8;
+		tmp |= card_mpuin->status;
+
+		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->curstate = STIN_3BYTE;
+	tmp = (u32) data;
+	tmp = tmp << 8;
+	tmp |= card_mpuin->data;
+	tmp = tmp << 8;
+	tmp |= card_mpuin->status;
+
+	sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+int sblive_miState2Byte(struct sblive_mpuin *card_mpuin, u8 data)
+{
+	u8 bTemp = data & 0xF0;
+
+	if ((bTemp == 0xC0) || (bTemp == 0xD0))
+	{
+		card_mpuin->status = data;
+		card_mpuin->curstate = STIN_2BYTE_KEY;
+
+		return CTSTATUS_NEXT_BYTE;
+	}
+
+	if (bTemp < 0x80)
+		return midistatefn[STIN_2BYTE_KEY].Fn(card_mpuin, data);
+
+	return midistatefn[STIN_PARSE].Fn(card_mpuin, data);
+}
+
+
+int sblive_miState2ByteKey(struct sblive_mpuin *card_mpuin, u8 data)
+/* byte 1 */
+{
+	u32 tmp;
+
+	if (data > 0x7F)
+	{
+		/* Real-time messages check */
+		if (data > 0xF7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = STIN_PARSE;
+		tmp = (u32) data;
+		tmp = tmp << 8;
+		tmp |= card_mpuin->status;
+
+		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->curstate = STIN_2BYTE;
+	tmp = (u32) data;
+	tmp = tmp << 8;
+	tmp |= card_mpuin->status;
+
+	sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+int sblive_miStateSysCommon2(struct sblive_mpuin *card_mpuin, u8 data)
+{
+	card_mpuin->fstatus = data;
+	card_mpuin->curstate = STIN_SYS_COMMON_2_KEY;
+
+	return CTSTATUS_NEXT_BYTE;
+}
+
+
+int sblive_miStateSysCommon2Key(struct sblive_mpuin *card_mpuin, u8 data)
+/* byte 1 */
+{
+	u32 tmp;
+
+	if (data > 0x7F)
+	{
+		/* Real-time messages check */
+		if (data > 0xF7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = card_mpuin->laststate;
+		tmp = (u32) data;
+		tmp = tmp << 8;
+		tmp |= card_mpuin->fstatus;
+
+		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->curstate = card_mpuin->laststate;
+	tmp = (u32) data;
+	tmp = tmp << 8;
+	tmp |= card_mpuin->fstatus;
+
+	sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+int sblive_miStateSysCommon3(struct sblive_mpuin *card_mpuin, u8 data)
+{
+	card_mpuin->fstatus = data;
+	card_mpuin->curstate = STIN_SYS_COMMON_3_KEY;
+
+	return CTSTATUS_NEXT_BYTE;
+}
+
+
+int sblive_miStateSysCommon3Key(struct sblive_mpuin *card_mpuin, u8 data)
+/* byte 1 */
+{
+	u32 tmp;
+
+	if (data > 0x7F)
+	{
+		/* Real-time messages check */
+		if (data > 0xF7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = card_mpuin->laststate;
+		tmp = (u32) data;
+		tmp = tmp << 8;
+		tmp |= card_mpuin->fstatus;
+
+		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->data = data;
+	card_mpuin->curstate = STIN_SYS_COMMON_3_VEL;
+
+	return CTSTATUS_NEXT_BYTE;
+}
+
+
+int sblive_miStateSysCommon3Vel(struct sblive_mpuin *card_mpuin, u8 data)
+/* byte 2 */
+{
+	u32 tmp;
+
+	if (data > 0x7F)
+	{
+		/* Real-time messages check */
+		if (data > 0xF7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = card_mpuin->laststate;
+		tmp = (u32) data;
+		tmp = tmp << 8;
+		tmp |= card_mpuin->data;
+		tmp = tmp << 8;
+		tmp |= card_mpuin->fstatus;
+
+		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+
+		return CTSTATUS_ERROR;
+	}
+
+	card_mpuin->curstate = card_mpuin->laststate;
+	tmp = (u32) data;
+	tmp = tmp << 8;
+	tmp |= card_mpuin->data;
+	tmp = tmp << 8;
+	tmp |= card_mpuin->fstatus;
+
+	sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+int sblive_miStateSysExNorm(struct sblive_mpuin *card_mpuin, u8 data)
+{
+	unsigned long flags;
+
+	if ((data > 0x7F) && (data != 0xF7))
+	{
+		/* Real-time messages check */
+		if (data > 0xF7)
+			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
+
+		/* Invalid Data! */
+		DPF(2, "Invalid data!\n");
+
+		card_mpuin->curstate = card_mpuin->laststate;
+
+		if (card_mpuin->firstmidiq)
+		{
+			struct midi_queue * midiq;
+
+			midiq = card_mpuin->firstmidiq;
+			*midiq->midibyte = data;
+			--midiq->sizeLeft;
+			++midiq->midibyte;
+
+			spin_lock_irqsave(&card_mpuin->lock, flags);
+
+			card_mpuin->firstmidiq = midiq->next;
+			if (card_mpuin->firstmidiq == NULL)
+				card_mpuin->lastmidiq = NULL;
+
+			spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INLONGERROR, (u32) midiq, 0);
+
+			kfree(midiq);
+		}
+
+		return CTSTATUS_ERROR;
+	}
+
+	if (card_mpuin->firstmidiq)
+	{
+		struct midi_queue *midiq;
+
+		midiq = card_mpuin->firstmidiq;
+		*midiq->midibyte = data;
+		--midiq->sizeLeft;
+		++midiq->midibyte;
+	}
+
+	if (data == 0xF7)
+	{
+		/* End of Sysex buffer */
+		/* Send down the buffer */
+
+		card_mpuin->curstate = card_mpuin->laststate;
+
+		if (card_mpuin->firstmidiq)
+		{
+			struct midi_queue * midiq;
+
+			midiq = card_mpuin->firstmidiq;
+
+			spin_lock_irqsave(&card_mpuin->lock, flags);
+
+			card_mpuin->firstmidiq = midiq->next;
+			if (card_mpuin->firstmidiq == NULL)
+				card_mpuin->lastmidiq = NULL;
+
+			spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INLONGDATA, (u32) midiq, 0);
+
+			kfree(midiq);
+		}
+
+		return CTSTATUS_SUCCESS;
+	}
+
+	if (card_mpuin->firstmidiq)
+	{
+		struct midi_queue *midiq;
+
+		midiq = card_mpuin->firstmidiq;
+
+		if (midiq->sizeLeft == 0)
+		{
+			/* Special case */
+
+			spin_lock_irqsave(&card_mpuin->lock, flags);
+
+			card_mpuin->firstmidiq = midiq->next;
+			if (card_mpuin->firstmidiq == NULL)
+				card_mpuin->lastmidiq = NULL;
+
+			spin_unlock_irqrestore(&card_mpuin->lock, flags);
+
+			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INLONGDATA, (u32) midiq, 0);
+
+			kfree(midiq);
+
+			return CTSTATUS_NEXT_BYTE;
+		}
+	}
+
+	return CTSTATUS_NEXT_BYTE;
+}
+
+
+int sblive_miStateSysReal(struct sblive_mpuin *card_mpuin, u8 data)
+{
+	sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATA, data, 1);
+
+	return CTSTATUS_NEXT_BYTE;
+}
Index: oldkernel/linux/drivers/sound/emu10k1/cardmi.h
diff -u /dev/null linux/drivers/sound/emu10k1/cardmi.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/cardmi.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,128 @@
+/*
+ **********************************************************************
+ *     sblive_mi.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox        cleaned up
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _CARDMI_H
+#define _CARDMI_H
+
+#include "icardmid.h"
+
+typedef enum
+{
+	STIN_PARSE = 0,
+	STIN_3BYTE,                     /* 0x80, 0x90, 0xA0, 0xB0, 0xE0 */
+	STIN_3BYTE_KEY,                 /* Byte 1 */
+	STIN_3BYTE_VEL,                 /* Byte 1 */
+	STIN_2BYTE,                     /* 0xC0, 0xD0 */
+	STIN_2BYTE_KEY,                 /* Byte 1 */
+	STIN_SYS_COMMON_2,              /* 0xF1, 0xF3  */
+	STIN_SYS_COMMON_2_KEY,
+	STIN_SYS_COMMON_3,              /* 0xF2 */
+	STIN_SYS_COMMON_3_KEY,
+	STIN_SYS_COMMON_3_VEL,
+	STIN_SYS_EX_NORM,               /* 0xF0, Normal mode */
+	STIN_SYS_REAL
+} midi_in_state;
+
+
+/* flags for card MIDI in object */
+#define FLAGS_MIDM_STARTED          0x00001000      // Data has started to come in after Midm Start
+#define MIDIIN_MAX_BUFFER_SIZE      200             // Definition for struct sblive_mpuin
+
+struct midi_data
+{
+	u8 data;
+	u32 timein;
+};
+
+struct sblive_mpuin
+{
+	spinlock_t        lock;
+	struct midi_queue *firstmidiq;
+	struct midi_queue *lastmidiq;
+	unsigned          qhead, qtail;
+	struct midi_data  midiq[MIDIIN_MAX_BUFFER_SIZE];
+	struct tq_struct task;
+	struct midi_openinfo    openinfo;
+	struct midi_caps        caps;
+
+	/* For MIDI state machine */
+	u8              status;        /* For MIDI running status */
+	u8              fstatus;       /* For 0xFn status only */
+	midi_in_state   curstate;
+	midi_in_state   laststate;
+	u32             timestart;
+	u32             timein;
+	u8              data;
+};
+
+int sblive_mpuinInit(struct sblive_mpuin *, struct sblive_hw *);
+int sblive_mpuinExit(struct sblive_hw *);
+
+int sblive_mpuinGetCaps(struct sblive_mpuin *, struct midi_caps *);
+int sblive_mpuinOpen(struct sblive_hw *, struct midi_openinfo *);
+int sblive_mpuinClose(struct sblive_hw *);
+int sblive_mpuinAddBuffer(struct sblive_mpuin *, struct midi_hdr *);
+int sblive_mpuinStart(struct sblive_hw *);
+int sblive_mpuinStop(struct sblive_hw *);
+int sblive_mpuinWriteShortData(struct sblive_mpuin *, u32);
+int sblive_mpuinPause(struct sblive_mpuin *);
+int sblive_mpuinStream(struct sblive_mpuin *, struct midi_hdr *);
+int sblive_mpuinRestart(struct sblive_mpuin *);
+int sblive_mpuinReset(struct sblive_hw *);
+int sblive_mpuinCache(struct sblive_mpuin *, struct midi_cache *);
+int sblive_mpuinGetPosition(struct sblive_mpuin *, u32 *);
+int sblive_mpuinGetControl(struct sblive_mpuin *, u32, u32 *);
+int sblive_mpuinSetControl(struct sblive_mpuin *, u32, u32 *);
+
+#define IDS_EMU_MIDIIN_PNAME                "SB Live! In"
+
+int sblive_miStateInit(struct sblive_mpuin *);
+int sblive_miStateEntry(struct sblive_mpuin *, u8);
+int sblive_miStateParse(struct sblive_mpuin *, u8);
+int sblive_miState3Byte(struct sblive_mpuin *, u8);
+int sblive_miState3ByteKey(struct sblive_mpuin *, u8);
+int sblive_miState3ByteVel(struct sblive_mpuin *, u8);
+int sblive_miState2Byte(struct sblive_mpuin *, u8);
+int sblive_miState2ByteKey(struct sblive_mpuin *, u8);
+int sblive_miStateSysCommon2(struct sblive_mpuin *, u8);
+int sblive_miStateSysCommon2Key(struct sblive_mpuin *, u8);
+int sblive_miStateSysCommon3(struct sblive_mpuin *, u8);
+int sblive_miStateSysCommon3Key(struct sblive_mpuin *, u8);
+int sblive_miStateSysCommon3Vel(struct sblive_mpuin *, u8);
+int sblive_miStateSysExNorm(struct sblive_mpuin *, u8);
+int sblive_miStateSysReal(struct sblive_mpuin *, u8);
+
+int sblive_mpuinIrqCallback(struct sblive_hw *);
+void sblive_mpuinDpcCallback(void *);
+int sblive_mpuinMidiCallback(struct sblive_mpuin *card_mpuin, u32 msg, u32 data, u32 bytesvalid);
+
+#endif  /* _CARDMI_H */
Index: oldkernel/linux/drivers/sound/emu10k1/cardmo.c
diff -u /dev/null linux/drivers/sound/emu10k1/cardmo.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/cardmo.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,474 @@
+/*     
+ **********************************************************************
+ *     cardmo.c - MIDI UART output HAL for emu10k1 driver 
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ *     November 2, 1999     Alan Cox        cleaned up
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#include "hwaccess.h"
+#include "cardmo.h"
+
+/****************************************************************************/
+/*int    sblive_mpuoutInit(PICARDMIDI pICardMidi, PICARD pICard )           */
+/*                                                                          */
+/*Function:   Initialize the parameters + reset the MPU port                */
+/****************************************************************************/
+int sblive_mpuoutInit(struct sblive_mpuout *card_mpuout, struct sblive_hw *sb_hw)
+{
+	u8 name[128];
+	
+	DPF(2, "sblive_mpuoutInit\n");
+
+	memset(card_mpuout, 0, sizeof(struct sblive_mpuout));
+
+	card_mpuout->intr = TRUE;
+	card_mpuout->status = FLAGS_AVAILABLE;
+	card_mpuout->state = CARDMIDIOUT_STATE_DEFAULT;
+	card_mpuout->caps.cbsize = sizeof(struct midi_caps);
+	card_mpuout->caps.support = MIDICAPS_OUTPUT;
+	card_mpuout->caps.technology = MT_MIDIPORT;
+	card_mpuout->caps.product = MM_CREATIVE_MIDIOUT;
+	card_mpuout->caps.manufacturer = MM_CREATIVE;
+	card_mpuout->caps.voices = 0;
+	card_mpuout->caps.notes = 0;
+	card_mpuout->caps.channelmask = 0xffff;
+	card_mpuout->caps.caps = CARDMIDI_OUT;
+
+	card_mpuout->task.next = NULL;
+	card_mpuout->task.sync = 0;
+	card_mpuout->task.routine = sblive_mpuoutDpcCallback;
+	card_mpuout->task.data = sb_hw;
+
+	spin_lock_init(&card_mpuout->lock);
+
+	strcpy(name, IDS_EMU_MIDIOUT_PNAME);
+
+	/* Fill in card caps */
+	sprintf(card_mpuout->caps.MIDIname, "%s [%lx]", name, sb_hw->hwaddr);
+
+	/* Reset the MPU port */
+	if (hwmpuReset(sb_hw) != CTSTATUS_SUCCESS) 
+	{
+		DPF(2, "MPU hardware reset failure\n");
+		return CTSTATUS_NOTENABLED;
+	}
+	
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/*int    sblive_mpuoutExit(struct sblive_mpuout *card_mpuout)               */
+/*                                                                          */
+/*Function:   Disable the IRQ TX and uninstall the IRQ handler              */
+/****************************************************************************/
+int sblive_mpuoutExit(struct sblive_hw *sb_hw)
+{
+	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
+	
+	DPF(2, "sblive_mpuoutExit\n");
+
+	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDITXENABLE);
+
+	card_mpuout->status |= FLAGS_AVAILABLE;
+	card_mpuout->state = CARDMIDIOUT_STATE_DEFAULT;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuoutOpen(PICARDMIDI pICardMidi,                          */
+/*                            struct midi_openinfo *openinfo,               */
+/*                            u32 *handle)                                  */
+/*                                                                          */
+/* Function:   Installs the IRQ handler for the MPU out port                */
+/*             and initialize parameters                                    */
+/****************************************************************************/
+int sblive_mpuoutOpen(struct sblive_hw *sb_hw, struct midi_openinfo *openinfo)
+{
+	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout; 
+	
+	DPF(2, "sblive_mpuoutOpen\n");
+
+	if (!(card_mpuout->status & FLAGS_AVAILABLE))
+	  return CTSTATUS_INUSE;
+
+	/* Copy open info and mark channel as in use */
+	card_mpuout->intr = TRUE;
+	card_mpuout->openinfo = *openinfo;
+	card_mpuout->status &= ~FLAGS_AVAILABLE;
+	card_mpuout->laststatus = 0x80;
+	card_mpuout->firstmidiq = NULL;
+	card_mpuout->lastmidiq = NULL;
+
+	hwmpuReset(sb_hw);
+	hwmpuAcquire(sb_hw);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuoutClose(PICARDMIDI pICardMidi,                         */
+/*                             u32 handle)                                  */
+/*                                                                          */
+/* Function:   If local buffer is not empty,                                */
+/*             return CTSTATUS_STILLPLAYING                                 */
+/*             Otherwise, disable and uninstall TX IRQ                      */
+/****************************************************************************/
+int sblive_mpuoutClose(struct sblive_hw *sb_hw)
+{
+	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
+	struct midi_queue *midiq;
+	struct midi_hdr *midihdr;
+	unsigned long flags;
+	
+	DPF(2, "sblive_mpuoutClose\n");
+
+	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDITXENABLE);
+
+	spin_lock_irqsave(&card_mpuout->lock, flags);
+
+	while(card_mpuout->firstmidiq != NULL){
+		midiq = card_mpuout->firstmidiq;
+		midihdr = (struct midi_hdr *) midiq->refdata;
+
+		card_mpuout->firstmidiq = midiq->next; 
+
+                kfree(midihdr->lpData);
+
+		DPD(3, "kfree: [%p]\n", midihdr->lpData);
+
+		kfree(midihdr);
+
+                DPD(3, "kfree: [%p]\n", midihdr);
+
+		kfree(midiq);
+		DPD(3, "kfree: [%p]\n", midiq);	
+	}
+
+	card_mpuout->lastmidiq = NULL;
+
+	hwmpuRelease(sb_hw);
+
+	card_mpuout->status |= FLAGS_AVAILABLE;
+
+	spin_unlock_irqrestore(&card_mpuout->lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuoutAddBuffer(PICARDMIDI pICardMidi,                     */
+/*                                 u32 handle,                              */
+/*                                 struct midi_hdr *INFO midihdrInfo)       */
+/*                                                                          */
+/* Function:   If there isn't enough buffer space, reject Midi Buffer.      */
+/*             Otherwise, disable TX, create object to hold Midi            */
+/*             Buffer, update buffer flags and other parameters             */
+/*             before enabling TX again.                                    */
+/****************************************************************************/
+int sblive_mpuoutAddBuffer(struct sblive_hw *sb_hw, struct midi_hdr *midihdr)
+{
+	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
+	struct midi_queue *midiq;
+	unsigned long flags;
+
+	DPF(2, "sblive_mpuoutAddBuffer\n");
+
+	if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND)
+	  return CTSTATUS_SUCCESS;
+
+	midihdr->flags |= MIDIBUF_INQUEUE;
+	midihdr->flags &= ~MIDIBUF_DONE;
+
+	midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL);
+	if (midiq == NULL) 
+	{
+		/* Message lost */
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", midiq);
+	
+	midiq->next = NULL;
+	midiq->qtype = 1;
+	midiq->length = midihdr->bufferlength;
+	midiq->sizeLeft = midihdr->bufferlength;
+	midiq->midibyte = midihdr->lpData;
+
+	midiq->refdata = (unsigned long) midihdr;
+
+	spin_lock_irqsave(&card_mpuout->lock, flags);
+
+	if (card_mpuout->firstmidiq == NULL) 
+	{
+		card_mpuout->firstmidiq = midiq;
+		card_mpuout->lastmidiq = midiq;
+	} else 
+	{
+		(card_mpuout->lastmidiq)->next = midiq;
+		card_mpuout->lastmidiq = midiq;
+	}
+
+	card_mpuout->intr = FALSE;
+	
+	sblive_irqmgrEnableIrq(sb_hw, INTE_MIDITXENABLE);
+
+	spin_unlock_irqrestore(&card_mpuout->lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+#if 0 /* what is this function for? (rsousa) */
+
+/****************************************************************************/
+/* int    sblive_mpuoutWriteShortData(PICARDMIDI pICardMidi,                */
+/*                                      u32 handle,                         */
+/*                                      u32 midimsg)                        */
+/*                                                                          */
+/* Function:   Adds the short message to our local buffer                   */
+/* Note:       This writeout must succeed at all cost ... else UART output  */
+/*             will sound wierd at a sound module.                          */
+/****************************************************************************/
+int sblive_mpuoutWriteShortData(struct sblive_hw *sb_hw, u32 midimsg)
+{
+	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
+	int msglen;
+	struct midi_queue *midiq;
+	int status;
+	unsigned long flags;
+
+
+	if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND)
+	  return CTSTATUS_SUCCESS;
+
+	if (midimsg & 0x80) 
+	{
+		if (((u8) midimsg) < 0xF0) 
+		{
+			card_mpuout->laststatus = (u8) midimsg;
+			msglen = gabMsgLenChannel[((midimsg & 0xF0) - 0x80) >> 4];
+		} else
+		  msglen = gabMsgLenSystem[midimsg & 0x0F];
+	} else 
+	{
+		if (card_mpuout->laststatus)
+		  msglen = gabMsgLenChannel[((card_mpuout->laststatus & 0xF0) - 0x80) >> 4];
+		else 
+		{
+			DPD(2, "sblive_mpuoutWriteShortData error!!: midimsg = %x\n", midimsg);
+			return CTSTATUS_ERROR;
+		}
+		--msglen;
+	}
+
+	if (card_mpuout->lastmidiq == NULL) 
+	{
+		unsigned long flags;
+		/* Wait until TX interrupt has occurred.
+		 * This means that the FIFO is empty.
+		 */
+		while (card_mpuout->intr != TRUE);
+
+		spin_lock_irqsave(&card_mpuout->lock, flags);
+
+		while (msglen--) 
+		{
+			status = hwmpuWriteData(sb_hw, (u8)midimsg);
+
+			if (status != CTSTATUS_SUCCESS) 
+			{
+				DPD(2, "sblive_mpuoutWriteShortData error!!: byte = %x\n", (u8) midimsg);
+				DPD(2, "UART BYTE OUT (MISSED) = %x\n", (u8)midimsg);
+				msglen++;
+			} else 
+			{
+				DPD(2, "UART BYTE OUT = %x\n", (u8)midimsg);
+				midimsg >>= 8;
+			}
+		}
+
+		card_mpuout->intr = FALSE;
+		sblive_irqmgrEnableIrq(sb_hw, INTE_MIDITXENABLE);
+		spin_unlock_irqrestore(&card_mpuout->lock, flags);
+
+		return CTSTATUS_SUCCESS;
+	}
+	
+	midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL);
+	if (midiq == NULL) 
+	{
+		/* Message lost */
+		DPD(2, "sblive_mpuoutWriteShortData error!!: midimsg = %x\n", midimsg);
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", midiq);
+	
+	midiq->next = NULL;
+	midiq->qtype = 0;
+	midiq->length = msglen;
+	midiq->sizeLeft = msglen;
+	midiq->midibyte = (u8 *) &midiq->refdata;
+	midiq->refdata = midimsg;
+
+	spin_lock_irqsave(&card_mpuout->lock, flags);
+
+	if (card_mpuout->firstmidiq == NULL) 
+	{
+		card_mpuout->lastmidiq = midiq;
+		card_mpuout->firstmidiq = midiq;
+	} else 
+	{
+		(card_mpuout->lastmidiq)->next = midiq;
+		card_mpuout->lastmidiq = midiq;
+	}
+
+	card_mpuout->intr = FALSE;
+	sblive_irqmgrEnableIrq(sb_hw, INTE_MIDITXENABLE);
+	spin_unlock_irqrestore(&card_mpuout->lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+#endif
+
+/****************************************************************************/
+/* int sblive_mpuoutDpcCallback ()                                          */
+/****************************************************************************/
+void sblive_mpuoutDpcCallback(void *refdata)
+{
+	int cByteSent = 0;
+	int status;
+	struct midi_queue *midiq;
+	struct midi_queue *doneq = NULL;
+	struct sblive_hw *sb_hw = (struct sblive_hw *) refdata;
+	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card_mpuout->lock, flags);
+
+	while (card_mpuout->firstmidiq != NULL) 
+	{
+		midiq = card_mpuout->firstmidiq;
+		
+		while (cByteSent < 4 && midiq->sizeLeft) 
+		{
+			status = hwmpuWriteData(sb_hw, *midiq->midibyte);
+
+			if (status == CTSTATUS_SUCCESS) 
+			{
+				++cByteSent;
+				--midiq->sizeLeft;
+				++midiq->midibyte;
+			} else 
+			{
+				DPF(2, "sblive_mpuoutDpcCallback error!!\n");
+			}
+		}
+		
+		if (midiq->sizeLeft == 0) 
+		{
+			if (doneq == NULL)
+			  doneq = midiq;
+			card_mpuout->firstmidiq = midiq->next;
+		} else
+		  break;
+	}
+
+	if (card_mpuout->firstmidiq == NULL)
+	  card_mpuout->lastmidiq = NULL;
+
+	if (doneq != NULL) 
+	{
+		while (doneq != card_mpuout->firstmidiq) 
+		{
+			unsigned long callback_msg[3];
+
+			midiq = doneq;
+			doneq = midiq->next;
+			
+			if (midiq->qtype) 
+			{
+				callback_msg[0] = 0;
+				callback_msg[1] = midiq->length;
+				callback_msg[2] = midiq->refdata;
+				
+				midiCallbackFn(ICARDMIDI_OUTLONGDATA, card_mpuout->openinfo.refdata, callback_msg);
+			} else 
+			  if (((u8) midiq->refdata) < 0xF0 &&
+			      ((u8) midiq->refdata) > 0x7F)
+			    card_mpuout->laststatus = (u8) midiq->refdata;
+
+			kfree(midiq);
+			DPD(3, "kfree: [%p]\n", midiq);
+		}
+	}
+	
+	if ((card_mpuout->firstmidiq != NULL) || cByteSent) 
+	{
+		card_mpuout->intr = FALSE;
+		sblive_irqmgrEnableIrq(sb_hw, INTE_MIDITXENABLE);
+	}
+
+	spin_unlock_irqrestore(&card_mpuout->lock, flags);
+	
+	return;
+}
+
+
+/****************************************************************************/
+/* int    sblive_mpuoutIrqCallback(unsigned long event,                     */
+/*                                   unsigned long refdata,                 */
+/*                                   unsigned long param)                   */
+/*                                                                          */
+/* Function:   IRQ callback handler routine for the MPU out port            */
+/****************************************************************************/
+int sblive_mpuoutIrqCallback(struct sblive_hw *sb_hw)
+{
+	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
+
+	/* Called during ISR. The data & code touched are:
+	 * 1. card_mpuout
+	 * 2. sblive_irqmgrDisableIrq()
+	 */
+
+	DPF(4, "sblive_mpuoutIrqCallback\n");
+
+	card_mpuout->intr = TRUE;
+	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDITXENABLE);
+
+	queue_task(&card_mpuout->task, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+
+	return CTSTATUS_SUCCESS;
+}
Index: oldkernel/linux/drivers/sound/emu10k1/cardmo.h
diff -u /dev/null linux/drivers/sound/emu10k1/cardmo.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/cardmo.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,70 @@
+/*
+ **********************************************************************
+ *     cardmo.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox	    cleaned up
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _CARDMO_H
+#define _CARDMO_H
+
+#include "icardmid.h"
+
+#define IDS_EMU_MIDIOUT_PNAME        "SB Live! MIDI Out"
+#define CARDMIDIOUT_STATE_DEFAULT    0x00000000
+#define CARDMIDIOUT_STATE_SUSPEND    0x00000001
+
+struct sblive_mpuout
+{
+	u32			status;
+	u32			state;
+	volatile int		intr;
+	struct midi_queue	*firstmidiq;
+	struct midi_queue	*lastmidiq;
+	u8			laststatus;
+	struct tq_struct 	task;
+	spinlock_t		lock;
+	struct midi_caps	caps;
+	struct midi_openinfo	openinfo;
+};
+
+int sblive_mpuoutInit(struct sblive_mpuout *, struct sblive_hw *);
+int sblive_mpuoutExit(struct sblive_hw *);
+
+int sblive_mpuoutOpen(struct sblive_hw *, struct midi_openinfo *);
+int sblive_mpuoutClose(struct sblive_hw *);
+int sblive_mpuoutAddBuffer(struct sblive_hw *, struct midi_hdr *);
+
+#if 0
+int sblive_mpuoutWriteShortData(struct sblive_hw *, u32);
+#endif
+
+int sblive_mpuoutIrqCallback(struct sblive_hw *);
+void sblive_mpuoutDpcCallback(void *);
+
+#endif  /* _CARDMO_H */
Index: oldkernel/linux/drivers/sound/emu10k1/cardwi.c
diff -u /dev/null linux/drivers/sound/emu10k1/cardwi.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/cardwi.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,880 @@
+/*
+ **********************************************************************
+ *     cardwi.c - PCM input HAL for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+
+#include "hwaccess.h"
+#include "mycommon.h"
+#include "mmwave.h"
+#include "recmgr.h"
+#include "audio.h"
+#include "cardwi.h"
+
+/****************************************************************************/
+/* Function : sblive_waveinInit                                             */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            sb_hw - pointer to hardware object                            */
+/*            mixer - pointer to card mixer                                 */
+/*            carddesc - card description                                   */
+/*                                                                          */
+/* Return   : CTSTATUS_SUCCESS  -- successful                               */
+/*            CTSTATUS_ERROR    -- failure                                  */
+/*                                                                          */
+/* About    : initialize card wave input device.                            */
+/****************************************************************************/
+int sblive_waveinInit(struct sblive_wavein *card_wavein, u8 *carddesc)
+{
+	/* Init Cardwave Caps */
+	memset(card_wavein, 0, sizeof(struct sblive_wavein));
+	card_wavein->caps.product_id = MM_CREATIVE_WAVEIN_PID;
+	card_wavein->caps.caps = CARDWAVE_IN;
+	card_wavein->caps.controls = 0;
+	card_wavein->caps.maxchannels = 2;
+	card_wavein->caps.minrate = 8000;
+	card_wavein->caps.maxrate = 48000;
+	strcpy(card_wavein->caps.wavedesc, carddesc);
+
+	card_wavein->numrecordinst = 0;
+	card_wavein->wave_inlist = NULL;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveinExit                                             */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*                                                                          */
+/* Return   : CTSTATUS_SUCCESS  -- successful                               */
+/*            CTSTATUS_ERROR    -- failure                                  */
+/*                                                                          */
+/* About    : exit card wave operation.                                     */
+/****************************************************************************/
+int sblive_waveinExit(struct sblive_wavein *card_wavein)
+{
+
+	return CTSTATUS_SUCCESS;
+}
+
+/****************************************************************************/
+/* Function : sblive_waveinQueryFormat                                      */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            wave_fmt - pointer to wave format object                      */
+/*            flags - flags that identifies the format to be queried.       */
+/*                                                                          */
+/* About    : query whether a specified wave format is supported by wave    */
+/*            device.                                                       */
+/****************************************************************************/
+int sblive_waveinQueryFormat(struct sblive_wavein *card_wavein,
+			     struct wave_format *wave_fmt, u32 flags)
+{
+	if (flags & CARDWAVE_QF_CHANNEL)
+	{
+		/* Only support one wave input instance */
+		if (card_wavein->numrecordinst > 1)
+			return CTSTATUS_INUSE;
+	}
+
+	if (flags & CARDWAVE_QF_STEREO)
+	{
+		if((wave_fmt->channels != 2) && (wave_fmt->channels != 1))
+			return CTSTATUS_BADFORMAT_STEREO;
+	}
+
+	if (flags & CARDWAVE_QF_RATE)
+	{
+		/* Recording
+		 * Sampling rates supported:
+		 * 48kHz, 44.1kHz, 32kHz, 24kHz, 22.05kHz, 16kHz, 11.025kHz, 8kHz.
+		 */
+
+		if(wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2 )
+			wave_fmt->samplingrate = 0xBB80;
+		else if (wave_fmt->samplingrate >= (0xAC44 + 0x7D00) / 2)
+			wave_fmt->samplingrate = 0xAC44;
+		else if (wave_fmt->samplingrate >= (0x7D00 + 0x5DC0) / 2)
+			wave_fmt->samplingrate = 0x7D00;
+		else if (wave_fmt->samplingrate >= (0x5DC0 + 0x5622) / 2)
+			wave_fmt->samplingrate = 0x5DC0;
+		else if (wave_fmt->samplingrate >= (0x5622 + 0x3E80) / 2)
+			wave_fmt->samplingrate = 0x5622;
+		else if (wave_fmt->samplingrate >= (0x3E80 + 0x2B11) / 2)
+			wave_fmt->samplingrate = 0x3E80;
+		else if (wave_fmt->samplingrate >= (0x2B11 + 0x1F40) / 2)
+			wave_fmt->samplingrate = 0x2B11;
+		else
+			wave_fmt->samplingrate = 0x1F40;
+	}
+
+	if (flags & CARDWAVE_QF_BITS)
+	{
+		/* 16 bit and 8 bit recording are supported */
+		if ((wave_fmt->bitspersample != 16) && (wave_fmt->bitspersample != 8))
+			wave_fmt->bitspersample = 16;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveinOpen                                             */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            wave_fmt - pointer to wave format object                      */
+/*            CallbackFn - IRQ call back function                           */
+/*            refdata - reference data for call back function               */
+/*            pcallback_size - pointer to the size of data to transfer      */
+/*                              before CallbackFn is called.                */
+/*            numfrags - number of buffer fragments                         */
+/*                                                                          */
+/* Output   : pcallback_size - pointer to the actual call back size.        */
+/*            phandle - pointer to the open handle.                         */
+/*                                                                          */
+/* About    : Open card wave device.                                        */
+/*            1. query whether a specified wave format is supported by      */
+/*               device.                                                    */
+/*            2. allocate emu channel for the specified channel object.     */
+/*            3. attach this wave instance to the channel object list.      */
+/*            4. install wave IRQ handler.                                  */
+/*            5. get wave transfer buffer.                                  */
+/*            6. get wave instance format.                                  */
+/*            7. for recording, install IRQ handler.                        */
+/****************************************************************************/
+int sblive_waveinOpen(struct sblive_hw *sb_hw, struct wave_format *wave_fmt, u32 *callback_size, u32 numfrags, struct wave_in **handle)
+{
+	struct sblive_wavein *card_wavein = sb_hw->card_wavein;
+	struct wave_in *wave_in;
+	int status;
+	u32 bufsiz;
+	u8 *buffer;
+
+	if (!(wave_in = (struct wave_in *)kmalloc(sizeof(struct wave_in), GFP_KERNEL)))
+	{
+		DPF(2, "Failed to allocate wave instance!\n");
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", wave_in);
+
+	/* Init wave in instance */
+	wave_in->next = NULL;
+	wave_in->status &= ~FLAGS_AVAILABLE;
+	wave_in->state = CARDWAVE_STATE_STOPPED;
+	wave_in->synchstart = FALSE;
+	wave_in->wave_fmt = *wave_fmt;
+	wave_in->emu_voice = NULL;
+	wave_in->memhandle = NULL;
+	wave_in->callbacksize = 0;
+	wave_in->process_id = 0;
+	wave_in->setpos = FALSE;
+	wave_in->position = 0;
+
+	/* Recording */
+
+	if (!(wave_in->rec_ptr = (struct record *) kmalloc(sizeof(struct record), GFP_KERNEL)))
+	{
+		DPF(2, "Failed to allocate recording buffer!\n");
+		kfree((void *) wave_in);
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", wave_in->rec_ptr);
+
+	initRecordObject(sb_hw, wave_in);
+
+	/* Attach this wave instance to the channel object list */
+	osListAttach((struct sblive_list **) & card_wavein->wave_inlist, (struct sblive_list *) wave_in);
+
+	if (callback_size != NULL)
+		wave_in->callbacksize = *callback_size;
+	else
+		wave_in->callbacksize = 0;
+
+	bufsiz = (wave_in->callbacksize ? wave_in->callbacksize * numfrags : 0xffff);
+
+	if ((status = sblive_emuGetRecBuffer(card_wavein, wave_in, &bufsiz, &buffer)) != CTSTATUS_SUCCESS)
+	{
+		DPF(2, "WaveOpen GetBuffer Fail");
+		sblive_waveinClose(sb_hw, wave_in);
+		return CTSTATUS_ERROR;
+	}
+
+	wave_in->callbacksize = bufsiz / numfrags;
+	*callback_size = bufsiz / numfrags;
+
+	/* This callback size returned is the size in the play buffer.
+	 * For 8-bit samples, callbacksize of user buffer should be
+	 * half of the callbacksize in play buffer. */
+	if (wave_in->wave_fmt.bitspersample == 8)
+		*callback_size >>= 1;
+
+	*handle = wave_in;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveinClose                                            */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            wave_in  - open handle which is the pointer to the            */
+/*                          specified channel object                        */
+/*                                                                          */
+/* About    : Close wave device.                                            */
+/*            1. deallocate transfer buffer, for playback,                  */
+/*               free emu addx space.                                       */
+/*            2. free voice channels.                                       */
+/*            3. uninstall wave IRQ handler.                                */
+/*            4. remove wave instance from channel object list.             */
+/****************************************************************************/
+int sblive_waveinClose(struct sblive_hw *sb_hw, struct wave_in *wave_in)
+{
+	struct sblive_wavein *card_wavein= sb_hw->card_wavein;
+	struct wave_in *tmp;
+	u32 dummy;
+
+	/* FIXME: Do we need spinlocks in here? */
+
+	if (wave_in->state != CARDWAVE_STATE_STOPPED)
+		sblive_waveinStop(sb_hw, wave_in, &dummy);
+
+	tmp = card_wavein->wave_inlist;
+	while (tmp)
+	{
+		if (tmp == wave_in)
+		{
+			if (sblive_emuDeallocRecBuffer(wave_in) != CTSTATUS_SUCCESS)
+			{
+				DPF(2, "Failed to deallocate recbuffer\n");
+			}
+
+			wave_in->status |= FLAGS_AVAILABLE;
+			wave_in->state = CARDWAVE_STATE_STOPPED;
+			wave_in->synchstart = FALSE;
+
+			kfree((void *) wave_in->rec_ptr);
+
+			osListRemove((struct sblive_list **) & card_wavein->wave_inlist, (struct sblive_list *) wave_in);
+
+			/* Free channel object which is allocated in sblive_waveOpen(). */
+			kfree((void *) wave_in);
+
+			break;
+		}
+
+		tmp = (struct wave_in *) tmp->next;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_emuGetRecBuffer                                        */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            wave_in - pointer to the specified wavein instance            */
+/*            size - pointer to the size requested                          */
+/*                                                                          */
+/* Output   : size - pointer to the size allocated                          */
+/*            buffer - pointer to the buffer pointer allocated              */
+/*                                                                          */
+/* About    : alloc record buffer.                                          */
+/****************************************************************************/
+int sblive_emuGetRecBuffer(struct sblive_wavein *card_wavein, struct wave_in *wave_in, u32 *size, u8 **buffer)
+{
+	DPF(2, "CARDWAVE : GetBuffer\n");
+
+	if (!size || !buffer)
+		return CTSTATUS_INVALIDPARAM;
+
+	if (*size < wave_in->callbacksize)
+	{
+		*size = wave_in->callbacksize;
+		return CTSTATUS_INVALIDVALUE;
+	}
+
+	/* Allocate buffer here */
+	if (sblive_emuAllocRecBuffer(wave_in, size, buffer) != CTSTATUS_SUCCESS)
+	{
+		DPF(2, "CARDWAVE: allocate buffer fail.");
+		return CTSTATUS_ERROR;
+	}
+
+	/* recbufsize contains actual record buffer size */
+	*size = wave_in->rec_ptr->recbufsize;
+
+	wave_in->rec_ptr->recbuffer = *buffer;
+	wave_in->rec_ptr->recpos = 0;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_emuAllocRecBuffer                                      */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            size - pointer to the size requested                          */
+/*                                                                          */
+/* Output   : size - pointer to the size returned                           */
+/*            buffer - pointer to the buffer pointer allocated              */
+/*                                                                          */
+/* About    : allocate buffer for wave transfer.                            */
+/*            recording: a) allocate page-aligned, continous PC memory      */
+/*                          for recording buffer.                           */
+/*                       b) determine start, end, startloop and             */
+/*                          endloop.                                        */
+/****************************************************************************/
+int sblive_emuAllocRecBuffer(struct wave_in *wave_in, u32 *bufsize, u8 **buffer)
+{
+	int status;
+	u32 numpages, reqsize;
+	int i, j;
+	u32 size[4];
+
+	/* NOTE: record buffer size only can be certain sizes.  If the requested
+	 * size is not a nice size, use the smaller nearest size. The minimum size is 1k. */
+	if (!wave_in->rec_ptr->is16bit)
+		*bufsize <<= 1;
+
+	if (*bufsize >= 0x10000)
+	{
+		*bufsize = reqsize = 0x10000;
+		wave_in->rec_ptr->bufsizereg = 31;
+	} else
+	{
+		reqsize = 0;
+		size[0] = 384;
+		size[1] = 448;
+		size[2] = 512;
+		size[3] = 640;
+
+		for (i = 0; i < 8; i++)
+			for (j = 0; j < 4; j++)
+				if (*bufsize >= size[j])
+				{
+					reqsize = size[j];
+					size[j] = size[j] * 2;
+					wave_in->rec_ptr->bufsizereg = i * 4 + j + 1;
+				} else
+					goto exitloop;
+	exitloop:
+		if (reqsize == 0)
+		{
+			reqsize = 384;
+			wave_in->rec_ptr->bufsizereg = 1;
+		}
+
+		*bufsize = reqsize;
+	}
+
+	DPD(2, "bufsizereg: %x\n", wave_in->rec_ptr->bufsizereg);
+
+	if (wave_in->rec_ptr->is_stereo)
+	{
+		numpages = (reqsize / (PAGE_SIZE * 2)) * 2;
+		if (reqsize % (PAGE_SIZE * 2))
+			numpages += 2;
+	} else
+	{
+		numpages = reqsize / PAGE_SIZE;
+		if (reqsize % PAGE_SIZE)
+			numpages += 1;
+	}
+
+	reqsize = numpages * PAGE_SIZE;
+
+	/* Recording buffer must be continuous and page-aligned */
+	status = osAllocMemPhysical(reqsize, &wave_in->memhandle);
+
+	if (status != CTSTATUS_SUCCESS)
+		return CTSTATUS_NOMEMORY;
+
+	wave_in->rec_ptr->recbuffer = (u8 *) wave_in->memhandle->virtaddx;
+	wave_in->rec_ptr->physaddx = wave_in->memhandle->physaddx;
+	wave_in->rec_ptr->recbufsize = *bufsize;
+
+	DPD(2, "recbufsize: %x\n", wave_in->rec_ptr->recbufsize);
+
+	*buffer = (u8 *) wave_in->memhandle->virtaddx;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_emuDeallocRecBuffer                                    */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*                                                                          */
+/* About    : deallocate transfer buffer                                    */
+/*            1. for playback, free emu address space.                      */
+/*            2. free PC memory allocated for transfer buffer.              */
+/*            3. clear VioceParam.                                          */
+/****************************************************************************/
+int sblive_emuDeallocRecBuffer(struct wave_in *wave_in)
+{
+	if (wave_in->memhandle == NULL)
+		return CTSTATUS_ERROR;
+
+	osFreeMemPhysical(&wave_in->memhandle);
+
+	if (wave_in->emu_voice != NULL)
+	{
+		struct voice_param *left = &wave_in->emu_voice->voice_params;
+		struct voice_param *right = &wave_in->emu_voice->linked_voice->voice_params;
+
+		/* Clear VoiceParam */
+		left->start = 0;
+		left->startloop = 0;
+		left->end = 0;
+		left->endloop = 0;
+
+		if (wave_in->wave_fmt.channels == 2)
+		{
+			right->start = 0;
+			right->startloop = 0;
+			right->end = 0;
+			right->endloop = 0;
+		}
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : initRecordObject                                              */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*                                                                          */
+/* About    : init recording object                                         */
+/****************************************************************************/
+/* FIXME: This should be a macro [jtaylor] */
+void initRecordObject(struct sblive_hw *sb_hw, struct wave_in *wave_in)
+{
+	wave_in->rec_ptr->reserved = NULL;
+	wave_in->rec_ptr->sb_hw = sb_hw;
+	wave_in->rec_ptr->recpos = 0;
+	wave_in->rec_ptr->recbufsize = 0;
+	wave_in->rec_ptr->recbuffer = NULL;
+	wave_in->rec_ptr->physaddx = 0;
+	wave_in->rec_ptr->samplingrate = wave_in->wave_fmt.samplingrate;
+	wave_in->rec_ptr->is_stereo = (wave_in->wave_fmt.channels == 2) ? 1 : 0;
+	wave_in->rec_ptr->is16bit = (wave_in->wave_fmt.bitspersample == 16) ? 1 : 0;
+	wave_in->rec_ptr->fSetRecSrc = FALSE;
+	wave_in->rec_ptr->prevadcidx = 0;
+	wave_in->rec_ptr->pong = FALSE;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveinStart                                            */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            wave_in - pointer to the specified wavein instance            */
+/*                                                                          */
+/* About    : start wave in transfer.                                       */
+/*            recording: a) setup voices.                                   */
+/*                       b) set recording source.(CCCA_CC, ADCCR)           */
+/*                       c) enable IRQ.                                     */
+/*                       d) start recording.                                */
+/*                       e) start CA (for get position).                    */
+/****************************************************************************/
+int sblive_waveinStart(struct sblive_wavedevice *wave_dev)
+{
+	struct sblive_hw *sb_hw = wave_dev->sb_hw;
+	struct wave_in *wave_in = wave_dev->wiinst->wave_in;
+
+	/* If already started, return success */
+	if (wave_in->state == CARDWAVE_STATE_STARTED)
+		return CTSTATUS_SUCCESS;
+
+	/* Recording */
+	if (recmgrInit(wave_in->rec_ptr) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	/* If recording source is not set yet, use default: AC97 ADC */
+	if (!wave_in->rec_ptr->fSetRecSrc)
+	{
+		if (recmgrSetControl(wave_in->rec_ptr, WAVERECORD_AC97, 0) != CTSTATUS_SUCCESS)
+			return CTSTATUS_SUCCESS;
+		wave_in->rec_ptr->fSetRecSrc = TRUE;
+	}
+
+	wave_in->task = (struct tq_struct *) kmalloc(sizeof(struct tq_struct), GFP_KERNEL);
+	if (wave_in->task == NULL)
+	{
+		DPF(2, "task alloc\n");
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", wave_in->task);
+	wave_in->task->next = NULL;
+	wave_in->task->sync = 0;
+	wave_in->task->routine = waveInCallbackFn;
+	wave_in->task->data = wave_dev;
+
+	if (sblive_irqmgrEnableIrq(sb_hw, INTE_ADCBUFENABLE) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	/* Actual start */
+	if (!wave_in->synchstart)
+	{
+		/* Recording */
+		if (recmgrStartRecord(wave_in->rec_ptr) != CTSTATUS_SUCCESS)
+			return CTSTATUS_ERROR;
+		wave_in->rec_ptr->prevadcidx = recmgrGetRecIdx(wave_in->rec_ptr->sb_hw);
+	}
+
+	wave_in->state = CARDWAVE_STATE_STARTED;
+	wave_in->setpos = FALSE;
+
+	DPF(2, "sblive_wave Started.\n");
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveinStop                                             */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            wave_in - pointer to the specified wavein instance            */
+/*            pending - for later use                                       */
+/*                                                                          */
+/* About    : stop wave transfer, disable IRQ.                              */
+/****************************************************************************/
+int sblive_waveinStop(struct sblive_hw *sb_hw, struct wave_in *wave_in, u32 *pending)
+{
+	if (wave_in->emu_voice != NULL)
+		if (sblive_voiceStop(wave_in->emu_voice) != CTSTATUS_SUCCESS)
+			return CTSTATUS_ERROR;
+
+	/* Recording */
+	if (recmgrStopRecord(wave_in->rec_ptr) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+	if (sblive_irqmgrDisableIrq(sb_hw, INTE_ADCBUFENABLE) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	if (wave_in->emu_voice != NULL)
+	{
+		struct voice_param *left = &wave_in->emu_voice->voice_params;
+
+		left->startloop = left->start;
+
+		if (wave_in->rec_ptr->is_stereo)
+		{
+			struct voice_param *right = &wave_in->emu_voice->linked_voice->voice_params;
+
+			right->startloop = right->start;
+		}
+	}
+
+	kfree(wave_in->task);
+
+	DPD(3, "kfree: [%p]\n", wave_in->task);
+
+	wave_in->rec_ptr->fSetRecSrc = FALSE;
+	wave_in->rec_ptr->recpos = 0;
+	wave_in->rec_ptr->pong = FALSE;
+	wave_in->state = CARDWAVE_STATE_STOPPED;
+	wave_in->process_id = 0;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveinGetXferSize                                      */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            wave_in - pointer to the specified wavein instance            */
+/*                                                                          */
+/* Output   : size - pointer to the transfer size                           */
+/*            pending - pointer to the size to be transfered                */
+/*                                                                          */
+/* About    : get the size of data in bytes that the specified wave device  */
+/*            can process at the time of this function is called.           */
+/*                                                                          */
+/* Note     : this transfer size returned is referring to user buffer.      */
+/****************************************************************************/
+int sblive_waveinGetXferSize(struct sblive_wavein *card_wavein,
+			     struct wave_in *wave_in, u32 *size, u32 *pending)
+{
+	struct record *rec_ptr = wave_in->rec_ptr;
+	u32 curpos;
+
+	/* Get position of current address, this is in no. of bytes in play buffer */
+	if (sblive_waveinGetControl(card_wavein, wave_in, WAVECURPOS, &curpos)
+	    != CTSTATUS_SUCCESS)
+	{
+		DPF(2, "sblive_waveinGetControl() failed!\n");
+		return CTSTATUS_ERROR;
+	}
+
+	curpos *= (rec_ptr->is_stereo + 1);
+
+	/* Recpos is the actual position in user buffer and play buffer */
+	if (curpos >= rec_ptr->recpos)
+		*size = curpos - rec_ptr->recpos;
+	else
+		*size = rec_ptr->recbufsize - (rec_ptr->recpos - curpos);
+
+	/* FIXME: Handle this at runtime [jtaylor] */
+#if defined(EMUA0)
+	/* Only emu8010 A0 silicon needs this workaround,
+	 * A1 silicon, take out this part.
+	 */
+	if (*size > 32)
+		*size -= 32;
+#endif
+
+	if (!rec_ptr->is16bit)
+		*size >>= 1;
+
+	*pending = rec_ptr->recbufsize - *size;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveinXferData                                         */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            wave_in - pointer to the specified wavein instance            */
+/*            Data - pointer to the data to be transfered                   */
+/*            size - data size to be transfered(size in user buffer,        */
+/*                      for 8-bit sample, this is different from play       */
+/*                      buffer.                                             */
+/*                                                                          */
+/* Output   : size - data size transfered                                   */
+/*                                                                          */
+/* About    : transfer the data to/from the wave device.                    */
+/****************************************************************************/
+int sblive_waveinXferData(struct sblive_wavein *card_wavein, struct wave_in *wave_in, u8 *data, u32 *size)
+{
+	struct record *rec_ptr = wave_in->rec_ptr;
+	u32 sizeToCopy, sizeToCopyNow, sizeCopied;
+
+	if (!data || !size)
+		return CTSTATUS_INVALIDPARAM;
+
+	DPD(2, "Size request to xfer = %x\n", *size);
+
+	sizeToCopy = min(rec_ptr->recbufsize * (rec_ptr->is16bit + 1) / 2, *size);
+	sizeCopied = 0;
+
+	if (!sizeToCopy)
+	{
+		*size = 0;
+		return CTSTATUS_SUCCESS;
+	}
+
+	while (sizeCopied < sizeToCopy)
+	{
+		sizeToCopyNow = sizeToCopy - sizeCopied;
+		sizeToCopyNow = min(sizeToCopyNow,(rec_ptr->recbufsize - rec_ptr->recpos) * (rec_ptr->is16bit + 1) / 2);
+
+		if (rec_ptr->is16bit)
+			copy_to_user(&data[sizeCopied], &rec_ptr->recbuffer[rec_ptr->recpos], sizeToCopyNow);
+		else
+		{
+			u8 *DstBuf = &data[sizeCopied];
+			u16 *SrcBuf = (u16 *) & rec_ptr->recbuffer[rec_ptr->recpos];
+			u32 count = sizeToCopyNow;
+
+			while (count--)
+			{
+				long lSample;
+				u8 bSample;
+
+				lSample = (short) *SrcBuf++;
+#ifdef RECTEST
+				DPD(2, " lSample -> %x", lSample);
+#endif
+				lSample += 128;
+				if (lSample > 32767)
+					lSample = 32767;
+				bSample = (u8)((lSample >> 8) ^ 0x80);
+				copy_to_user(DstBuf, &bSample, 1);
+				DstBuf++;
+			}
+		}
+
+		rec_ptr->recpos += sizeToCopyNow * 2 / (rec_ptr->is16bit + 1);
+		rec_ptr->recpos %= rec_ptr->recbufsize;
+		sizeCopied += sizeToCopyNow;
+	}
+
+	*size = sizeToCopy;
+
+	DPD(2, "Size copied = %x\n", *size);
+
+	return CTSTATUS_SUCCESS;
+}
+
+/****************************************************************************/
+/* Function : sblive_waveinGetControl                                       */
+/*                                                                          */
+/* Input    : card_wavein - pointer to card wavein object                   */
+/*            wave_in - pointer to the specified wavein instance            */
+/*            ctrlid - control type                                         */
+/*                                                                          */
+/* Output   : value - pointer to the control value                          */
+/*                                                                          */
+/* About    : get the specified control value of the wave device.           */
+/****************************************************************************/
+int sblive_waveinGetControl(struct sblive_wavein *card_wavein, struct wave_in *wave_in, u32 ctrlid, u32 *value)
+{
+	switch (ctrlid)
+	{
+	case WAVEOBJVOLUME:
+	case WAVEOBJREVERB:
+	case WAVEOBJCHORUS:
+		return CTSTATUS_NOTSUPPORTED;
+
+	case WAVEQUERYACTIVEINST:
+		if (card_wavein->wave_inlist != NULL)
+			return CTSTATUS_SUCCESS;
+		else
+			return CTSTATUS_ERROR;
+
+	default:
+		break;
+	}
+
+	if (wave_in == NULL)
+		return CTSTATUS_ERROR;
+
+	switch (ctrlid)
+	{
+	case WAVEINSTANCEVOLUME:
+	case WAVEINSTANCEREVERB:
+	case WAVEINSTANCECHORUS:
+		return CTSTATUS_NOTSUPPORTED;
+
+	case WAVECURPOS:
+		/* There is no actual start yet */
+		if (wave_in->state == CARDWAVE_STATE_STOPPED)
+		{
+			*value = 0;
+			break;
+		}
+
+		if (wave_in->emu_voice == NULL)
+		{
+			/* No voices used for recording, get position from wall clock */
+			if (recmgrGetPos(wave_in->rec_ptr, value) != CTSTATUS_SUCCESS)
+			{
+				DPF(2, "recmgrGetPos() failed!\n");
+				return CTSTATUS_ERROR;
+			}
+
+			*value /= (wave_in->rec_ptr->is_stereo + 1);
+		}
+		else
+		{
+			if (sblive_voiceGetControl(wave_in->emu_voice, CCCA_CURRADDR, value) != CTSTATUS_SUCCESS)
+				return CTSTATUS_ERROR;
+
+			/* There is no actual start yet */
+			if (wave_in->state == CARDWAVE_STATE_STOPPED)
+				*value = 0;
+			else
+			{
+				*value -= wave_in->emu_voice->voice_params.start;
+				*value <<= wave_in->rec_ptr->is16bit;
+			}
+		}
+
+		break;
+
+	case WAVESTARTLOOP:
+		if (sblive_voiceGetControl(wave_in->emu_voice, PSST_LOOPSTARTADDR, value) != CTSTATUS_SUCCESS)
+			return CTSTATUS_ERROR;
+
+		*value -= wave_in->emu_voice->voice_params.start;
+		*value <<= wave_in->rec_ptr->is16bit;
+		break;
+
+	case WAVEENDLOOP:
+		if (sblive_voiceGetControl(wave_in->emu_voice, DSL_LOOPENDADDR, value) != CTSTATUS_SUCCESS)
+			return CTSTATUS_ERROR;
+		*value -= wave_in->emu_voice->voice_params.start;
+		*value <<= wave_in->rec_ptr->is16bit;
+		break;
+
+	case WAVEWRITEPOINTER:
+		/* Get write pointer for a particular wave instance */
+		*value = wave_in->rec_ptr->recpos;
+		break;
+
+	default:
+		DPF(2, "BUG: Default case\n");
+		return CTSTATUS_ERROR;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveinIrqCallback                                      */
+/*                                                                          */
+/* Input    : event - event that cause the callback                         */
+/*            refdata - reference data for this callback                    */
+/*            param - parameter used for this callback                      */
+/*                                                                          */
+/* About    : wave IRQ callback function.                                   */
+/****************************************************************************/
+int sblive_waveinIrqCallback(struct sblive_hw *sb_hw)
+{
+	struct wave_in *wave_in = sb_hw->card_wavein->wave_inlist;
+
+	if (wave_in->state == CARDWAVE_STATE_STOPPED)
+		return CTSTATUS_SUCCESS;
+
+	wave_in->rec_ptr->prevadcidx = recmgrGetRecIdx(wave_in->rec_ptr->sb_hw);
+	wave_in->rec_ptr->pong ^= 1;
+
+	queue_task(wave_in->task, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+
+	return CTSTATUS_SUCCESS;
+}
+
Index: oldkernel/linux/drivers/sound/emu10k1/cardwi.h
diff -u /dev/null linux/drivers/sound/emu10k1/cardwi.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/cardwi.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,109 @@
+/*
+ **********************************************************************
+ *     cardwi.h -- header file for card wave input functions
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+#ifndef _CARDWI_H
+#define _CARDWI_H
+
+#include "icardwav.h"
+
+struct wave_in 
+{
+	struct wave_in *next;
+	u32 status;
+	u32 state;
+	int synchstart;
+	struct emu_voice *emu_voice;
+	struct record *rec_ptr;
+	struct memhandle *memhandle;
+	u32 callbacksize;
+	u32 process_id;		/* used for synchonize start */
+	int setpos;
+	u32 position;
+	struct wave_format wave_fmt;
+	struct tq_struct *task;
+};
+
+struct wiinst
+{
+	struct wave_in *wave_in;
+	struct wave_format wave_fmt;
+	u16 ossfragshift;
+	u32 fragment_size;
+	u32 numfrags;
+	wait_queue_head_t wait_queue;
+	int mapped;
+	u32 total_recorded;
+	u32 getiptr_blocks;
+	spinlock_t lock;
+};
+
+/* sblive_wave states */
+#define CARDWAVE_STATE_STOPPED     0x0001
+#define CARDWAVE_STATE_STARTED     0x0002
+#define CARDWAVE_STATE_SUSPEND     0x0004
+
+/* transfer buffer format */
+#define M8                        0x00
+#define M16                       0x01
+#define S8                        0x02
+#define S16                       0x03
+
+#define INTERPOLATION_BYTES       8
+#define WAVEIN_MAXBUFSIZE         65536
+#define WAVEIN_DEFAULTFRAGLEN     50
+#define WAVEIN_DEFAULTBUFLEN      1000
+
+struct sblive_wavein 
+{
+	struct wave_caps caps;
+	u32 numrecordinst;
+	struct wave_in *wave_inlist;
+	u32 lineid;
+	u32 ctrlid;
+};
+
+
+int sblive_waveinInit(struct sblive_wavein *, u8 *);
+int sblive_waveinExit(struct sblive_wavein *);
+int sblive_waveinQueryFormat(struct sblive_wavein *, struct wave_format *, u32);
+int sblive_waveinOpen(struct sblive_hw *, struct wave_format *, u32 *, u32, struct wave_in **);
+int sblive_waveinClose(struct sblive_hw *, struct wave_in *);
+int sblive_waveinStart(struct sblive_wavedevice *);
+int sblive_waveinStop(struct sblive_hw *, struct wave_in *, u32 *);
+int sblive_waveinGetXferSize(struct sblive_wavein *, struct wave_in *, u32 *, u32 *);
+int sblive_waveinXferData(struct sblive_wavein *, struct wave_in *, u8 *, u32 *);
+int sblive_waveinGetControl(struct sblive_wavein *, struct wave_in *, u32, u32 *);
+int sblive_emuAllocRecBuffer(struct wave_in *, u32 *, u8 **);
+int sblive_emuGetRecBuffer(struct sblive_wavein *, struct wave_in *, u32 *, u8 **);
+int sblive_emuDeallocRecBuffer(struct wave_in *);
+void initRecordObject(struct sblive_hw *, struct wave_in *);
+
+
+#endif /* _CARDWI_H */
Index: oldkernel/linux/drivers/sound/emu10k1/cardwo.c
diff -u /dev/null linux/drivers/sound/emu10k1/cardwo.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/cardwo.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,1774 @@
+/*
+ **********************************************************************
+ *     cardwo.c - PCM output HAL for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "mycommon.h"
+#include "mmwave.h"
+#include "cardwo.h"
+#include "audio.h"
+
+/* Volume calcs */
+static int set_volume_instance(struct sblive_waveout * card_waveout, struct wave_out * wave_out, struct voice_param * left)
+{
+	/* only applicable for playback */
+	u32 volL, volR, vol = 0;
+
+	volL = (wave_out->localvol & 0xffff);
+	volR = ((wave_out->localvol >> 16) & 0xffff);
+
+	if (wave_out->globalvolFactor)
+	{
+		volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * (u16) volL)) / 0xffff;
+		volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) volR))) / 0xffff;
+	}
+
+	/* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */
+	/* New volume and pan */
+
+	if (volL == volR)
+	{
+		vol = volL;
+		left->unSends.tSends.pan_send = 0xff;
+		left->unSends.tSends.aux_send = 0xff;
+	} else
+	{
+		if (volL > volR)
+		{
+			vol = volL;
+			left->unSends.tSends.pan_send = 0xff;
+			left->unSends.tSends.aux_send = (char) ((volR * 255) / vol);
+		} else
+		{
+			vol = volR;
+			left->unSends.tSends.aux_send = 0xff;
+			left->unSends.tSends.pan_send = (char) ((volL * 255) / vol);
+		}
+	}
+
+	left->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2);
+
+	return vol;
+}
+
+static void set_volume(struct sblive_waveout * card_waveout)
+{
+	struct wave_out * currinst = card_waveout->wave_outlist;
+	struct voice_cntlset setting[3];
+
+	while (currinst && currinst->emu_voice)
+	{
+		struct voice_param * left = &currinst->emu_voice->voice_params;
+
+		/* This flag allows a wave instance to be unaffected by changes to global volume. */
+
+		if (currinst->globalvolFactor)
+		{
+			u32 volL, volR, vol;
+
+			/* Calculate individual channel volumes based on obj and instance volume */
+
+			volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * ((u16) currinst->localvol & 0xffff))) / 0xffff;
+			volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) (currinst->localvol >> 16) & 0xffff))) / 0xffff;
+
+			/* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */
+			/* New volume and pan */
+			if (volL == volR)
+			{
+				vol = volL;
+				left->unSends.tSends.pan_send = 0xff;
+				left->unSends.tSends.aux_send = 0xff;
+			} else
+			{
+				if (volL > volR)
+				{
+					vol = volL;
+					left->unSends.tSends.pan_send = 0xff;
+					left->unSends.tSends.aux_send = (char) ((volR * 255) / vol);
+				} else
+				{
+					vol = volR;
+					left->unSends.tSends.aux_send = 0xff;
+					left->unSends.tSends.pan_send = (char) ((volL * 255) / vol);
+				}
+			}
+
+			left->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2);
+
+			if (currinst->wavexferbuf->is_stereo && currinst->emu_voice->linked_voice)
+			{
+				struct voice_param * right = &currinst->emu_voice->linked_voice->voice_params;
+
+				right->unSends.tSends.pan_send = 0; /* Left output of right channel is always zero */
+				right->unSends.tSends.aux_send = left->unSends.tSends.aux_send; /* Update right channel aux */
+				left->unSends.tSends.aux_send = 0; /* Zero out right output of left channel */
+				right->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2); /* Update right channel attenuation */
+
+				setting[0].paramID = PSST_FXSENDAMOUNT_C;
+				setting[0].value = 0;
+				setting[1].paramID = PTRX_FXSENDAMOUNT_B;
+				setting[1].value = right->unSends.tSends.aux_send;
+				setting[2].paramID = IFATN_ATTENUATION;
+				setting[2].value = right->initial_attn;
+
+				sblive_voiceSetControl(currinst->emu_voice->linked_voice, setting, 3);
+			}
+
+			setting[0].paramID = PSST_FXSENDAMOUNT_C;
+			setting[0].value = left->unSends.tSends.pan_send;
+			setting[1].paramID = PTRX_FXSENDAMOUNT_B;
+			setting[1].value = left->unSends.tSends.aux_send;
+			setting[2].paramID = IFATN_ATTENUATION;
+			setting[2].value = left->initial_attn;
+			sblive_voiceSetControl(currinst->emu_voice, setting, 3);
+		}
+
+		currinst = currinst->next;
+	}
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveVolumeControlFn                                    */
+/*                                                                          */
+/* About    : Callback function for volume control.                         */
+/****************************************************************************/
+int sblive_waveVolumeControlFn(u32 event, struct sblive_waveout * card_waveout, u32 left, u32 right)
+{
+	switch (event)
+	{
+	case 0:	/* Get */
+		*(u32 *)left = card_waveout->left;
+		*(u32 *)right = card_waveout->right;
+		break;
+
+	case 1:	/* Set */
+		/*
+		 ** this is a general set volume affecting all wave instances.
+		 ** WODM_SETVOLUME should result in this controlId and affect
+		 ** the volume of all wave instances. Apps which can set the
+		 ** volume of individual wave instances should use
+		 ** WAVEINSTANCEVOLUME instead
+		 */
+		card_waveout->left = left;
+		card_waveout->right = right;
+
+		if (!card_waveout->mute)
+		{
+			card_waveout->globalvol = (left & 0xffff) | (right << 16);
+			set_volume(card_waveout);
+		}
+		break;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+
+/****************************************************************************/
+/* Function : sblive_waveoutInit                                            */
+/*                                                                          */
+/* Input    : card_waveout - pointer to card wave out object structure      */
+/*            sb_hw - pointer to hardware object                            */
+/*                                                                          */
+/* Return   : CTSTATUS_SUCCESS  -- successful                               */
+/*            CTSTATUS_ERROR    -- failure                                  */
+/*                                                                          */
+/* About    : initialize card wave output device.                           */
+/****************************************************************************/
+/* FIXME: This should be a macro */
+int sblive_waveoutInit(struct sblive_waveout *card_waveout, u8 *carddesc)
+{
+	/* Init cardwave caps */
+	memset(card_waveout, 0, sizeof(struct sblive_waveout));
+	card_waveout->caps.product_id = MM_CREATIVE_WAVEOUT_PID;
+	card_waveout->caps.caps = CARDWAVE_OUT;
+	card_waveout->caps.caps |= CARDWAVE_ALLOW_DIRECTXFER;
+	card_waveout->caps.controls = CARDWAVE_CONTROL_VOLUME;
+	card_waveout->caps.maxchannels = 2;
+	card_waveout->caps.minrate = 100;
+	card_waveout->caps.maxrate = 100000;
+	strcpy(card_waveout->caps.wavedesc, carddesc);
+
+	card_waveout->numplaybackinst = 0;
+	card_waveout->maxnumplayinst = CARDWAVE_DEFAULT_MAXPLAYINST;
+	card_waveout->wave_outlist = NULL;
+
+	/* Init to invalid values */
+	card_waveout->lineid = 0xeeeeeeee;
+	card_waveout->ctrlid = 0xffffffff;
+
+	/* Assign default global volume, reverb, chorus */
+	card_waveout->globalvol = 0xFFFFFFFF;
+	card_waveout->left = 0xFFFF;
+	card_waveout->right = 0xFFFF;
+	card_waveout->mute = 0;
+	card_waveout->globalreverb = 0xFFFFFFFF;
+	card_waveout->globalchorus = 0xFFFFFFFF;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveoutExit                                            */
+/*                                                                          */
+/* Input    : card_waveout - pointer to card wave object structure          */
+/*                                                                          */
+/* Return   : CTSTATUS_SUCCESS  -- successful                               */
+/*            CTSTATUS_ERROR    -- failure                                  */
+/*                                                                          */
+/* About    : exit card wave operation.                                     */
+/****************************************************************************/
+int sblive_waveoutExit(struct sblive_waveout *card_waveout)
+{
+	DPF(2, "sblive_waveoutExit()\n");
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/**************************************************************************/
+/* Function : sblive_waveoutQueryFormat                                   */
+/*                                                                        */
+/* Input    : card_waveout - pointer to card wave out object structure    */
+/*            pwave_fmt - pointer to wave format object                   */
+/*            flags - flags that identifies the format to be queried.     */
+/*                                                                        */
+/* About    : query whether a specified wave format is supported by wave  */
+/*            out device.                                                 */
+/**************************************************************************/
+int sblive_waveoutQueryFormat(struct sblive_waveout *card_waveout, struct wave_format * wave_fmt, u32 flags)
+{
+	if (flags & CARDWAVE_QF_CHANNEL)
+		if ((card_waveout->numplaybackinst) > card_waveout->maxnumplayinst)
+			return CTSTATUS_INUSE;
+
+	if (flags & CARDWAVE_QF_STEREO)
+		if (wave_fmt->channels != 1 && wave_fmt->channels != 2)
+			return CTSTATUS_BADFORMAT_STEREO;
+
+	if (flags & CARDWAVE_QF_RATE)
+		if (wave_fmt->samplingrate >= 0x2EE00) /* FIXME: 0x2ee00 = 192000! Is this valid??? */
+			wave_fmt->samplingrate = 0x2EE00;
+
+	if (flags & CARDWAVE_QF_BITS)
+		if (wave_fmt->bitspersample != 8 && wave_fmt->bitspersample != 16)
+			wave_fmt->bitspersample = 16;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/**************************************************************************/
+/* Function : sblive_waveoutOpen                                          */
+/*                                                                        */
+/* Input    : card_waveout - pointer to card wave object structure        */
+/*            wave_fmt - pointer to wave format object                    */
+/*            CallbackFn - IRQ call back function                         */
+/*            refdata - reference data for call back function             */
+/*            fragment_size - size of buffer fragment                     */
+/*            numfrags - number of buffer fragments                       */
+/*                                                                        */
+/* Output   : fragment_size - pointer to the actual fragment size.        */
+/*            handle - pointer to the open handle.                        */
+/*                                                                        */
+/* About    : Open card wave out device.                                  */
+/*            1. query whether a specified wave format is supported by    */
+/*               device.                                                  */
+/*            2. allocate emu channel for the specified channel object.   */
+/*            3. attach this wave instance to the channel object list.    */
+/*            4. install wave IRQ handler.                                */
+/*            5. get wave transfer buffer.                                */
+/*            6. get wave instance format.                                */
+/**************************************************************************/
+int sblive_waveoutOpen(struct sblive_hw *sb_hw, struct wave_format *wave_fmt, u32 *fragment_size, u32 numfrags, struct wave_out **handle)
+{
+	struct sblive_waveout *card_waveout = sb_hw->card_waveout;
+	struct wave_out *wave_out;
+	struct voice_allocdesc voice_allocdesc;
+	int status;
+	u32 buffsize;
+	void **buffer;
+
+	/* If number of wave instances is greater than the maximum instances allowed, fail the open. */
+	if (card_waveout->numplaybackinst + 1 > card_waveout->maxnumplayinst)
+		return CTSTATUS_ERROR;
+
+	wave_out = (struct wave_out *) kmalloc(sizeof(struct wave_out), GFP_KERNEL);
+	if (wave_out == NULL)
+	{
+		DPF(2, "struct wave_out alloc fail\n");
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", wave_out);
+
+	/* Init channel object */
+	wave_out->next = NULL;
+	wave_out->status = 0;
+	wave_out->state = CARDWAVE_STATE_STOPPED;
+	wave_out->synchstart = FALSE;
+	wave_out->wave_fmt = *wave_fmt;
+	wave_out->emu_voice = NULL;
+	wave_out->emuaddr = NULL;
+	wave_out->wavexferbuf = NULL;
+	wave_out->pagetable = NULL;
+	wave_out->callbacksize = 0;
+
+	/* Assign default local volume */
+	/* FIXME: Should we be maxing the initial values like this? */
+	wave_out->localvol = 0xffffffff;
+	wave_out->localreverb = 0xffffffff;
+	wave_out->localchorus = 0xffffffff;
+	wave_out->globalvolFactor = 0xffff;
+	wave_out->globalreverbFactor = 0xffff;
+	wave_out->globalchorusFactor = 0xffff;
+
+	wave_out->process_id = 0;
+	wave_out->setpos = FALSE;
+	wave_out->position = 0;
+
+	wave_out->playflags = CARDWAVE_PLAY_LOOPING;
+
+	wave_out->wavexferbuf = (struct wave_xferbuf *) kmalloc(sizeof(struct wave_xferbuf ), GFP_KERNEL);
+
+	if (!wave_out->wavexferbuf)
+	{
+		DPF(2, "struct wave_xferbuf alloc failed\n");
+		kfree((void *) wave_out);
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", wave_out->wavexferbuf);
+	initWaveOutXferBuffer(wave_out);
+
+	/* Allocate voices here, if no voices available, return error.
+	 * Init voice_allocdesc first.*/
+
+	voice_allocdesc.sb_hw = sb_hw;
+	voice_allocdesc.ownertype = VOICEMGR_USAGE_PLAYBACK;
+
+	voice_allocdesc.callback = NULL;
+	voice_allocdesc.callback_data = 0;
+	voice_allocdesc.numvoicereqs = 1;
+	voice_allocdesc.flags[0] = 0;
+
+	if (wave_fmt->channels == 1)
+		voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_MONO;
+
+	if (wave_fmt->bitspersample == 16)
+		voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_16BIT;
+
+	voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_PLAYBACK;
+
+	status = sblive_voiceAlloc(&voice_allocdesc, &wave_out->emu_voice);
+	if (status != CTSTATUS_SUCCESS)
+	{
+		DPF(2, "Channel allocation fail\n");
+		kfree((void *) wave_out->wavexferbuf);
+		kfree((void *) wave_out);
+		return status;
+	}
+
+	DPD(2, "voicenum -> %d\n", wave_out->emu_voice->voicenum);
+
+	/* Attach this wave instance to the channel object list */
+	card_waveout->numplaybackinst++;
+
+	osListAttach((struct sblive_list **) & card_waveout->wave_outlist, (struct sblive_list *) wave_out);
+
+	wave_out->callbacksize = *fragment_size;
+
+	buffsize = (*fragment_size ? *fragment_size * numfrags : 0xffff);
+
+	if (sblive_emuGetXferBuffer(sb_hw, wave_out, &buffsize, &buffer) != CTSTATUS_SUCCESS)
+	{
+		if (buffsize < *fragment_size)
+		{
+			*fragment_size = buffsize;
+			sblive_waveoutClose(sb_hw, wave_out);
+			return CTSTATUS_INVALIDVALUE;
+		}
+
+		DPF(2, "WaveOpen GetBuffer Fail\n");
+		sblive_waveoutClose(sb_hw, wave_out);
+		return CTSTATUS_ERROR;
+	}
+
+	wave_out->callbacksize = buffsize / numfrags;
+	*fragment_size = buffsize / numfrags;
+
+	*handle = wave_out;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/**************************************************************************/
+/* Function : sblive_waveoutClose                                         */
+/*                                                                        */
+/* Input    : card_waveout - pointer to card wave object structure        */
+/*            wave_out - pointer to the specified wave out instance       */
+/*                                                                        */
+/* About    : Close wave device.                                          */
+/*            1. deallocate transfer buffer, for playback,                */
+/*               free emu addx space.                                     */
+/*            2. free voice channels.                                     */
+/*            3. remove wave instance from channel object list.           */
+/**************************************************************************/
+int sblive_waveoutClose(struct sblive_hw *sb_hw, struct wave_out *wave_out)
+{
+	struct sblive_waveout *card_waveout = sb_hw->card_waveout;
+	struct wave_out *tempchan;
+	u32 dummy;
+
+	if (wave_out->state != CARDWAVE_STATE_STOPPED)
+		sblive_waveoutStop(sb_hw, wave_out, &dummy);
+
+	tempchan = card_waveout->wave_outlist;
+	while (tempchan)
+	{
+		if ((tempchan->wavexferbuf->xferbuffer
+		     == wave_out->wavexferbuf->xferbuffer)
+		    && (tempchan != wave_out))
+			break;
+		tempchan = (struct wave_out *) tempchan->next;
+	}
+
+	osListRemove((struct sblive_list **) & card_waveout->wave_outlist, (struct sblive_list *) wave_out);
+
+	if (tempchan == NULL)
+	{
+		if (sblive_emuDeallocXferBuffer(wave_out) != CTSTATUS_SUCCESS)
+		{
+			DPF(2, "Failed to deallocate buffer\n");
+		}
+
+		kfree((void *) wave_out->wavexferbuf);
+		DPD(3, "kfree: [%p]\n", wave_out->wavexferbuf);
+	}
+
+	wave_out->status |= FLAGS_AVAILABLE;
+	wave_out->state = CARDWAVE_STATE_STOPPED;
+	wave_out->synchstart = FALSE;
+
+	card_waveout->numplaybackinst--;
+
+	if (sblive_voiceFree(wave_out->emu_voice) != CTSTATUS_SUCCESS)
+	{
+		DPF(2, "Failed to free voice\n");
+	}
+
+	kfree((void *) wave_out);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/**************************************************************************/
+/* Function : sblive_emuGetXferBuffer                                     */
+/*                                                                        */
+/* Input    : card_waveout - pointer to card wave object                  */
+/*            wave_out - pointer to the specified wave out instance       */
+/*            size - pointer to the size requested                        */
+/*                                                                        */
+/* Output   : size - pointer to the size allocated                        */
+/*            buffer - pointer to the buffer pointer allocated            */
+/*                                                                        */
+/* About    : alloc transfer buffer.                                      */
+/**************************************************************************/
+int sblive_emuGetXferBuffer(struct sblive_hw *sb_hw, struct wave_out * wave_out, u32 *size, void ***buffer)
+{
+	DPF(2, "sblive_emuGetXferBuffer()\n");
+
+	if (!size || !buffer)
+		return CTSTATUS_INVALIDPARAM;
+
+	if (!wave_out)
+	{
+		DPF(2, "wave_out == NULL\n");
+		return CTSTATUS_ERROR;
+	}
+
+	if (*size < wave_out->callbacksize)
+	{
+		*size = wave_out->callbacksize;
+		return CTSTATUS_INVALIDVALUE;
+	}
+
+	if (sblive_emuAllocXferBuffer(sb_hw, wave_out, size, buffer) != CTSTATUS_SUCCESS)
+	{
+		DPF(2, "Allocate buffer failed\n");
+		return CTSTATUS_ERROR;
+	}
+
+	/* xferbufsize contains actual transfer buffer size */
+	wave_out->wavexferbuf->xferbufsize = *size;
+	wave_out->wavexferbuf->xferbuffer = *buffer;
+	wave_out->wavexferbuf->xferpos = 0;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveoutSynchStart                                      */
+/*                                                                          */
+/* Input    : card_waveout - pointer to card wave object                    */
+/*                                                                          */
+/* About    : Synchronize start all wave playback and recording instances   */
+/*            in a particular application according to process ID.          */
+/*            Application needs to call SYNCHSTART twice, one is to start   */
+/*            all wave playback instances, another to start all wave        */
+/*            recording instances. Because wave out and wave in are         */
+/*            separate devices.                                             */
+/****************************************************************************/
+int sblive_waveoutSynchStart(struct sblive_waveout * card_waveout, u32 process_id)
+{
+	struct wave_out * currinst;
+
+	currinst = card_waveout->wave_outlist;
+
+	/* Start wave playback instances */
+	while (currinst)
+	{
+		if (currinst->process_id == process_id)
+		{
+			if (sblive_voiceStart(currinst->emu_voice) != CTSTATUS_SUCCESS)
+				return CTSTATUS_ERROR;
+
+		}
+		currinst = currinst->next;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_emuAllocXferBuffer                                     */
+/*                                                                          */
+/* Input    : wave_out - pointer to the specified wave out instance         */
+/*            size - pointer to the size requested                          */
+/*                                                                          */
+/* Output   : size - pointer to the size returned                           */
+/*            buffer - pointer to the buffer pointer allocated              */
+/*                                                                          */
+/* About    : allocate buffer for wave out transfer.                        */
+/*            1. playback: a) request for emu address space.                */
+/*                         b) allocate page-aligned PC memory for playback  */
+/*                            buffer.                                       */
+/*                         c) allocate memory for physical address table,   */
+/*                            copy page table.                              */
+/*                         d) determine start, end, startloop and           */
+/*                            endloop.                                      */
+/*                         e) fill in virtual memory table.                 */
+/*                         f) free physical address table.                  */
+/****************************************************************************/
+int sblive_emuAllocXferBuffer(struct sblive_hw *sb_hw, struct wave_out *wave_out, u32 *size, void ***buffer)
+{
+	u32 numpages, reqsize;
+	struct emuaddr_allocdesc dsEmuAddxAllocDesc;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	u32 pagecount;
+
+	reqsize = *size;
+	numpages = reqsize / PAGE_SIZE;
+
+	/* If size is not a multiple of PAGE_SIZE then we need to round up */
+	if (reqsize % PAGE_SIZE)
+		numpages += 1;
+
+	DPD(2, "requested pages is: %d\n", numpages);
+
+	wavexferbuf->numpages = numpages;
+
+	/* Only for playback, request for emu address space */
+	dsEmuAddxAllocDesc.sb_hw = sb_hw;
+	dsEmuAddxAllocDesc.ownertype = 0;
+	dsEmuAddxAllocDesc.callback = 0;
+	dsEmuAddxAllocDesc.callback_data = 0;
+
+	/* Support non page-aligned buffer, don't need interpolation page */
+	dsEmuAddxAllocDesc.size = numpages * PAGE_SIZE;
+	dsEmuAddxAllocDesc.flags = 0;
+
+	if (emu10kaddxmgrAlloc(&dsEmuAddxAllocDesc, &wave_out->emuaddr) != CTSTATUS_SUCCESS){
+		DPF(2, "no memory, increase MAXPAGES\n");
+		return CTSTATUS_NOMEMORY;
+	}
+
+	wave_out->pagetable = (void **) kmalloc(sizeof(void *) * numpages, GFP_KERNEL);
+
+	if (!wave_out->pagetable) {
+		DPF(2, "no memory\n");
+		emu10kaddxmgrFree(wave_out->emuaddr);
+		return CTSTATUS_NOMEMORY;
+	}
+	
+	/* Fill in virtual memory table */
+	for (pagecount = 0; pagecount < numpages; pagecount++)
+	{
+		/* Preserve emu page number */
+		((u32 *) sb_hw->virtualpagetable->virtaddx)[(wave_out->emuaddr->emustartaddr >> 11) + pagecount] &= 0x1fff;
+
+		if (!(wave_out->pagetable[pagecount] = (void *)__get_free_page(GFP_KERNEL))) {
+			DPF(2, "no memory\n");
+			while (pagecount--)
+				free_page((unsigned long)wave_out->pagetable[pagecount]);
+			emu10kaddxmgrFree(wave_out->emuaddr);
+			kfree(wave_out->pagetable);
+			return CTSTATUS_NOMEMORY;
+		}
+		
+		/* OR with physical address */
+		((u32 *) sb_hw->virtualpagetable->virtaddx)[(wave_out->emuaddr->emustartaddr >> 11) + pagecount] |= (((u32) virt_to_bus((char *) wave_out->pagetable[pagecount])) & 0xfffff000) << 1;
+
+		DPD(2, "Physical Addx: %x\n", ((u32 *) sb_hw->virtualpagetable->virtaddx)[(wave_out->emuaddr->emustartaddr >> 11) + pagecount]);
+	}
+
+	*buffer = wave_out->pagetable;
+
+	{
+		struct voice_param *left = &wave_out->emu_voice->voice_params;
+
+		reqsize = reqsize * (2 - wavexferbuf->is16bit) / (wavexferbuf->is_stereo + 1) / 2;
+		left->start = wave_out->emuaddr->emustartaddr;
+		left->start = left->start / (wavexferbuf->is_stereo + 1) * (2 - wavexferbuf->is16bit);
+		left->end = left->start + reqsize;
+		left->startloop = left->start;
+		left->endloop = left->end;
+
+		DPD(2, "sblive_emuAllocXferBuf: start=%x, end=%x, startloop=%x, endloop=%x\n",
+		    left->start, left->end, left->startloop, left->endloop);
+
+		if (wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
+		{
+			struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
+
+			/* Do the same thing for right channel */
+			right->start = left->start;
+			right->end = left->end;
+			right->startloop = left->startloop;
+			right->endloop = left->endloop;
+		}
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_emuDeallocXferBuffer                                   */
+/*                                                                          */
+/* Input    : wave_out - pointer to the specified wave out instance         */
+/*                                                                          */
+/* About    : deallocate transfer buffer                                    */
+/*            1. for playback, free emu address space.                      */
+/*            2. free PC memory allocated for transfer buffer.              */
+/*            3. clear VioceParam.                                          */
+/****************************************************************************/
+int sblive_emuDeallocXferBuffer(struct wave_out *wave_out)
+{
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	int pagecount;
+
+	/* For playback, free emu address space */
+	if (wave_out->emuaddr)
+		emu10kaddxmgrFree(wave_out->emuaddr);
+
+	if (wave_out->pagetable) {
+		for (pagecount = 0; pagecount < wavexferbuf->numpages; pagecount++)
+			free_page((unsigned long)wave_out->pagetable[pagecount]);
+		kfree(wave_out->pagetable);
+		wave_out->wavexferbuf->xferbuffer = NULL;
+	}
+
+	/* Clear VoiceParam */
+	if (wave_out->emu_voice != NULL)
+	{
+		struct voice_param *left = &wave_out->emu_voice->voice_params;
+
+		left->start = 0;
+		left->startloop = 0;
+		left->end = 0;
+		left->endloop = 0;
+
+		if ((wave_out->wave_fmt.channels == 2) && wave_out->emu_voice->linked_voice)
+		{
+			struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
+
+			right->start = 0;
+			right->startloop = 0;
+			right->end = 0;
+			right->endloop = 0;
+		}
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : initWaveOutXferBuffer                                         */
+/*                                                                          */
+/* Input    : wave_out - pointer to the specified wave out instance         */
+/*                                                                          */
+/* About    : init card wave buffer structure                               */
+/****************************************************************************/
+/* FIXME: This should be a macor [jtaylor] */
+void initWaveOutXferBuffer(struct wave_out *wave_out)
+{
+	wave_out->wavexferbuf->xferpos = 0;
+	wave_out->wavexferbuf->xferbufsize = 0;
+	wave_out->wavexferbuf->numpages = 0;
+	wave_out->wavexferbuf->xferbuffer = NULL;
+	wave_out->wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
+	wave_out->wavexferbuf->is16bit = (wave_out->wave_fmt.bitspersample == 16) ? 1 : 0;
+
+	if (wave_out->wave_fmt.channels == 2)
+	{
+		if (wave_out->wave_fmt.bitspersample == 16)
+			wave_out->wavexferbuf->format = S16;
+		else
+			wave_out->wavexferbuf->format = S8;
+	} else
+	{
+		if (wave_out->wave_fmt.bitspersample == 16)
+			wave_out->wavexferbuf->format = M16;
+		else
+			wave_out->wavexferbuf->format = M8;
+	}
+
+	wave_out->wavexferbuf->conv = 0;
+	wave_out->wavexferbuf->interpolationbytes = INTERPOLATION_BYTES * (wave_out->wavexferbuf->is16bit + 1) * (wave_out->wavexferbuf->is_stereo + 1);
+	wave_out->wavexferbuf->offset = 0;
+	wave_out->wavexferbuf->stopposition = 0;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveoutSetFormat                                       */
+/*                                                                          */
+/* Input    : card_waveout - pointer to card wave object                    */
+/*            wave_out - pointer to the specified wave out instance         */
+/*                                                                          */
+/* About    : sets a new format for the wave instance                       */
+/****************************************************************************/
+int sblive_waveoutSetFormat(struct sblive_hw *sb_hw, struct wave_out *wave_out, struct wave_format *wave_fmt)
+{
+	int status;
+	struct voice_allocdesc voice_allocdesc;
+
+	if (wave_out->state != CARDWAVE_STATE_STOPPED)
+		return CTSTATUS_ERROR;
+
+	if ((wave_fmt->channels != wave_out->wave_fmt.channels) ||
+	    (wave_fmt->bitspersample != wave_out->wave_fmt.bitspersample))
+	{
+		sblive_voiceFree(wave_out->emu_voice);
+
+		/* Allocate voices here, if no voices available, return error.  Init voice_allocdesc first. */
+		voice_allocdesc.sb_hw = sb_hw;
+		voice_allocdesc.ownertype = VOICEMGR_USAGE_PLAYBACK;
+
+		/* for P10, this is to allocate main voices, don't need IRQ callback */
+		voice_allocdesc.callback = NULL;
+		voice_allocdesc.callback_data = 0;
+		voice_allocdesc.numvoicereqs = 1;
+		voice_allocdesc.flags[0] = 0;
+
+		if (wave_fmt->channels == 1)
+			voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_MONO;
+		if (wave_fmt->bitspersample == 16)
+			voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_16BIT;
+
+		voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_PLAYBACK;
+
+		if ((status = sblive_voiceAlloc(&voice_allocdesc, &wave_out->emu_voice)) != CTSTATUS_SUCCESS)
+			return status;
+	}
+
+	wave_out->wave_fmt = *wave_fmt;
+	wave_out->wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
+	wave_out->wavexferbuf->is16bit = (wave_out->wave_fmt.bitspersample == 16) ? 1 : 0;
+
+	if (wave_out->wave_fmt.channels == 2)
+	{
+		if (wave_out->wave_fmt.bitspersample == 16)
+			wave_out->wavexferbuf->format = S16;
+		else
+			wave_out->wavexferbuf->format = S8;
+	} else
+	{
+		if (wave_out->wave_fmt.bitspersample == 16)
+			wave_out->wavexferbuf->format = M16;
+		else
+			wave_out->wavexferbuf->format = M8;
+	}
+
+	wave_out->wavexferbuf->interpolationbytes = INTERPOLATION_BYTES * (wave_out->wavexferbuf->is16bit + 1) * (wave_out->wavexferbuf->is_stereo + 1);
+
+	{
+		u32 reqsize;
+		struct wave_xferbuf * wavexferbuf = wave_out->wavexferbuf;
+		struct voice_param * left = &wave_out->emu_voice->voice_params;
+
+		/* emu address space is in words, use start and end for actual
+		 * emu start and end address allocated, startloop and endloop
+		 * for loop points.  startloop and endloop contain number of samples. */
+		reqsize = wavexferbuf->xferbufsize * (2 - wavexferbuf->is16bit) / (wavexferbuf->is_stereo + 1) / 2;
+		left->start = wave_out->emuaddr->emustartaddr;
+		left->start = left->start / (wavexferbuf->is_stereo + 1) * (2 - wavexferbuf->is16bit);
+		left->end = left->start + reqsize;
+		left->startloop = left->start;
+		left->endloop = left->end;
+
+		DPD(2, "SetFormat: start=%x, end=%x, startloop=%x, endloop=%x\n",
+		    left->start, left->end, left->startloop, left->endloop);
+
+		if (wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
+		{
+			struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
+
+			/* Do the same thing for right channel */
+			right->start = left->start;
+			right->end = left->end;
+			right->startloop = left->startloop;
+			right->endloop = left->endloop;
+		}
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveoutStart                                           */
+/*                                                                          */
+/* Input    : card_waveout - pointer to card wave object                    */
+/*            wave_out - pointer to the specified wave out instance         */
+/*                                                                          */
+/* About    : start wave transfer.                                          */
+/*            playback: a) setup voices.  b) set volume.                    */
+/*                      c) enable IRQ.    d) start playback.                */
+/****************************************************************************/
+int sblive_waveoutStart(struct sblive_wavedevice *wave_dev)
+{
+	struct sblive_hw *sb_hw = wave_dev->sb_hw;
+	struct wave_out *wave_out = wave_dev->woinst->wave_out;
+	struct sblive_waveout * card_waveout= sb_hw->card_waveout;
+	struct voice_param *left = &wave_out->emu_voice->voice_params;
+	u32 start, startPosition;
+	u32 delay, bytespersec;
+
+	/* If already started, return success */
+	if (wave_out->state == CARDWAVE_STATE_STARTED)
+		return CTSTATUS_SUCCESS;
+
+	/* Calculate pitch */
+	left->initial_pitch = (u16) (srToPitch(wave_out->wave_fmt.samplingrate) >> 8);
+
+	DPD(2, "Initial pitch --> %x\n", left->initial_pitch);
+
+	/* Easy way out.. gotta calculate value */
+	left->pitch_target = 0;
+	left->volume_target = 0;
+	left->FC_target = 0;
+
+	left->byampl_env_sustain = 0x7f;
+	left->byampl_env_decay = 0x7f;
+
+	if (wave_out->globalreverbFactor)
+	{
+		u8 t = (card_waveout->globalreverb & 0xff) + (wave_out->localreverb & 0xff);
+		left->unSends.tSends.reverb_send = (t > 255) ? 255 : t;
+	} else
+	{
+		left->unSends.tSends.reverb_send = 0;
+	}
+
+	if (wave_out->globalchorusFactor)
+	{
+		u8 t = (card_waveout->globalchorus & 0xff) + (wave_out->localchorus & 0xff);
+		left->unSends.tSends.chorus_send = (t > 255) ? 255 : t;
+	} else
+	{
+		left->unSends.tSends.chorus_send = 0;
+	}
+
+	set_volume_instance(card_waveout, wave_out, left);
+
+	left->pan_target = left->unSends.tSends.pan_send;
+	left->aux_target = left->unSends.tSends.aux_send;
+
+	if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
+	{
+		struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
+
+		right->initial_pitch = left->initial_pitch;
+
+		/* Easy way out.. gotta calculate value */
+		right->pitch_target = 0;
+		right->volume_target = 0;
+		right->FC_target = 0;
+
+		right->byampl_env_sustain = 0x7f;
+		right->byampl_env_decay = 0x7f;
+
+		right->unSends.tSends.chorus_send = left->unSends.tSends.chorus_send;
+		right->unSends.tSends.reverb_send = left->unSends.tSends.reverb_send;
+
+		/* Left output of right channel is always zero */
+		right->unSends.tSends.pan_send = 0;
+
+		/* Update right channel aux */
+		right->pan_target = 0;
+		right->unSends.tSends.aux_send = left->unSends.tSends.aux_send;
+		right->aux_target = right->unSends.tSends.aux_send;
+
+		/* Zero out right output of left channel */
+		left->unSends.tSends.aux_send = 0;
+		left->aux_target = 0;
+
+		/* Update right channel attenuation */
+		right->initial_attn = left->initial_attn;
+	}
+
+	if (wave_out->state == CARDWAVE_STATE_STOPPED && wave_out->setpos)
+		startPosition = wave_out->position / (wave_out->wavexferbuf->is16bit + 1) / (wave_out->wavexferbuf->is_stereo + 1);
+	else
+		startPosition = wave_out->wavexferbuf->stopposition;
+
+	start = wave_out->emu_voice->voice_params.start;
+	wave_out->emu_voice->voice_params.start += startPosition;
+
+	DPD(2, "CA is %x\n", wave_out->emu_voice->voice_params.start);
+
+	if (sblive_voicePlaybackSetup(wave_out->emu_voice) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	wave_out->emu_voice->voice_params.start = start;
+
+	wave_out->task = (struct tq_struct *) kmalloc(sizeof(struct tq_struct), GFP_KERNEL);
+	if (wave_out->task == NULL)
+	{
+		DPF(2, "task alloc\n");
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", wave_out->task);
+	wave_out->task->next = NULL;
+	wave_out->task->sync = 0;
+	wave_out->task->routine = waveOutCallbackFn;
+	wave_out->task->data = wave_dev;
+
+	bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitspersample >> 3) * (wave_out->wave_fmt.samplingrate);
+	delay = (48000 * wave_out->callbacksize) / bytespersec;
+
+	if (sblive_timerinstall(sb_hw, &wave_out->timer, wave_out->task, delay / 2) != CTSTATUS_SUCCESS)
+	{
+		sblive_voiceStop(wave_out->emu_voice);
+		return CTSTATUS_ERROR;
+	}
+
+	/* Actual start */
+	if (!wave_out->synchstart)
+		if (sblive_voiceStart(wave_out->emu_voice) != CTSTATUS_SUCCESS)
+			return CTSTATUS_ERROR;
+
+	wave_out->state = CARDWAVE_STATE_STARTED;
+	wave_out->setpos = FALSE;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveoutStop                                            */
+/*                                                                          */
+/* Input    : card_waveout - pointer to card wave object                    */
+/*            wave_out - pointer to the specified wave out instance         */
+/*            ppending - for later use                                      */
+/*                                                                          */
+/* About    : stop wave transfer, disable IRQ.                              */
+/****************************************************************************/
+int sblive_waveoutStop(struct sblive_hw *sb_hw, struct wave_out *wave_out, u32 *pending)
+{
+	struct sblive_waveout *card_waveout = sb_hw->card_waveout;
+	struct wave_xferbuf *wavexferbuf;
+	u32 dummy;
+	u32 samples = 32;
+	u32 position;
+
+	if (!wave_out)
+		return CTSTATUS_INVALIDPARAM;
+
+	wavexferbuf = wave_out->wavexferbuf;
+
+	if (wave_out->state == CARDWAVE_STATE_STOPPING)
+		return CTSTATUS_SUCCESS;
+
+	if (!wave_out->emu_voice)
+	{
+		wave_out->state = CARDWAVE_STATE_STOPPED;
+		return CTSTATUS_SUCCESS;
+	}
+
+	if (wave_out->state == CARDWAVE_STATE_STOPPED)
+		return CTSTATUS_SUCCESS;
+
+	wave_out->state = CARDWAVE_STATE_STOPPING;
+
+	sblive_waveoutGetXferSize(card_waveout, wave_out, &dummy, pending);
+
+	/* Save the stop position */
+	if (sblive_voiceGetControl(wave_out->emu_voice, CCCA_CURRADDR, &wave_out->wavexferbuf->stopposition) != CTSTATUS_SUCCESS)
+	{
+		wave_out->wavexferbuf->stopposition = 0;
+		return CTSTATUS_ERROR;
+	}
+
+	wave_out->wavexferbuf->stopposition -= wave_out->emu_voice->voice_params.start;
+
+	/* Refer to voicemgr.c, CA is not started at zero.  We need to take this into account. */
+	position = wave_out->wavexferbuf->stopposition * (wave_out->wavexferbuf->is16bit + 1) * (wave_out->wavexferbuf->is_stereo + 1);
+
+	if (!wave_out->wavexferbuf->is16bit)
+		samples <<= 1;
+
+	if (wave_out->wavexferbuf->is_stereo)
+		samples <<= 1;
+
+	samples -= 4;
+
+	if (position >= samples * (wave_out->wavexferbuf->is16bit + 1))
+		position -= samples * (wave_out->wavexferbuf->is16bit + 1);
+	else
+		position += wave_out->wavexferbuf->xferbufsize - samples * (wave_out->wavexferbuf->is16bit + 1);
+
+	wave_out->wavexferbuf->stopposition = position / (wave_out->wavexferbuf->is16bit + 1) / (wave_out->wavexferbuf->is_stereo + 1);
+
+	DPD(2, "sblive_waveoutstop, position is %x\n", wave_out->wavexferbuf->stopposition);
+
+	/* Stop actual voice */
+	if (sblive_voiceStop(wave_out->emu_voice) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	if (sblive_timeruninstall(sb_hw, wave_out->timer) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	kfree(wave_out->task);
+
+	DPD(3, "kfree: [%p]\n", wave_out->task);
+
+	wave_out->state = CARDWAVE_STATE_STOPPED;
+	wave_out->process_id = 0;
+	wave_out->setpos = FALSE;
+	wave_out->position = 0;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveoutGetXferSize                                     */
+/*                                                                          */
+/* Input    : card_waveout - pointer to card wave object                    */
+/*            wave_out - pointer to the specified wave out instance         */
+/*                                                                          */
+/* Output   : size - pointer to the transfer size                           */
+/*            pending - pointer to the size to be transfered                */
+/*                                                                          */
+/* About    : get the size of data in bytes that the specified wave device  */
+/*            can process at the time of this function is called.           */
+/*                                                                          */
+/* Note     : this transfer size returned is referring to user buffer.      */
+/****************************************************************************/
+int sblive_waveoutGetXferSize(struct sblive_waveout *card_waveout, struct wave_out *wave_out, u32 *size, u32 *pending)
+{
+	u32 curpos;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+
+	/* Get position of current address, this is in no. of bytes in play buffer */
+	if (sblive_waveoutGetControl(card_waveout, wave_out, WAVECURPOS, &curpos) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	if ((curpos > wavexferbuf->xferpos) || ((curpos == wavexferbuf->xferpos) && (wave_out->state == CARDWAVE_STATE_STARTED))
+	    || ((curpos == wavexferbuf->xferpos) && (wavexferbuf->xferpos != 0) && (wave_out->state == CARDWAVE_STATE_STOPPED)))
+	{
+		*size = curpos - wavexferbuf->xferpos;
+		*pending = wavexferbuf->xferbufsize - *size;
+	} else
+	{
+		*pending = wavexferbuf->xferpos - curpos;
+		*size = wavexferbuf->xferbufsize - *pending;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+static void copy_block(u32 dst, u8 *src, u32 len, void **pt)
+{
+	int i, j, k;
+	i = dst / 4096;
+	j = dst % 4096;
+	k = (len > 4096 - j) ? 4096 - j : len;
+	copy_from_user(pt[i] + j, src, k);
+	len -= k;	
+	while (len >= 4096) {
+		copy_from_user(pt[++i], src + k, 4096);
+		k += 4096;
+		len -= 4096;
+	}
+	copy_from_user(pt[++i], src + k, len);	
+}
+
+static void fill_block(u32 dst, u8 val, u32 len, void **pt)
+{
+	int i, j, k;
+	i = dst / 4096;
+	j = dst % 4096;
+	k = (len > 4096 - j) ? 4096 -j : len;
+	memset(pt[i] + j, val, k);
+	len -= k;
+	while (len >= 4096) {
+		memset(pt[++i], val, 4096);
+		len -= 4096;
+	}
+	memset(pt[++i], val, len);
+}
+
+/**************************************************************************/
+/* Function : sblive_waveoutXferData                                      */
+/*                                                                        */
+/* Input    : card_waveout - pointer to card wave object                  */
+/*            wave_out - pointer to the specified wave out instance       */
+/*            data - pointer to the data to be transfered                 */
+/*            size - data size to be transfered(size in user buffer,      */
+/*                      for 8-bit sample, this is different from play     */
+/*                      buffer.                                           */
+/*                                                                        */
+/* Output   : size - data size transfered                                 */
+/*                                                                        */
+/* About    : transfer the data to/from the wave device.                  */
+/**************************************************************************/
+int sblive_waveoutXferData(struct sblive_waveout *card_waveout, struct wave_out *wave_out, u8 *data, u32 *size)
+{
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	u32 sizetocopy, sizetocopynow;
+
+	/* FIXME: Do we need spinlocks in here? */
+
+	if (!data || !size)
+		return CTSTATUS_INVALIDPARAM;
+
+	sizetocopy = min(wavexferbuf->xferbufsize, *size);
+	*size = sizetocopy;
+
+	if (!sizetocopy)
+		return CTSTATUS_SUCCESS;
+
+	sizetocopynow = wavexferbuf->xferbufsize - wavexferbuf->xferpos;
+
+	if(sizetocopy > sizetocopynow)
+	{
+		copy_block(wavexferbuf->xferpos, data, sizetocopynow, wavexferbuf->xferbuffer);
+                sizetocopy -= sizetocopynow;
+		copy_block(0, data + sizetocopynow, sizetocopy, wavexferbuf->xferbuffer);
+		wavexferbuf->xferpos = sizetocopy;
+	}
+	else
+	{
+		copy_block(wavexferbuf->xferpos, data, sizetocopy, wavexferbuf->xferbuffer);
+		if(sizetocopy == sizetocopynow)
+			wavexferbuf->xferpos = 0;
+		else
+			wavexferbuf->xferpos += sizetocopy;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/**************************************************************************/
+/* Function : sblive_waveoutFillSilence                                   */
+/*                                                                        */
+/* Input    : card_waveout - pointer to card wave object                  */
+/*            wave_out - pointer to the specified wave out instance       */
+/*            size - data size to be filled                               */
+/*                                                                        */
+/* Output   : size - data size filled                                     */
+/*                                                                        */
+/* About    : fill silent data to play buffer,only used for wave output.  */
+/**************************************************************************/
+int sblive_waveoutFillSilence(struct sblive_waveout *card_waveout, struct wave_out *wave_out, u32 *size)
+{
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	u16 wFillData;
+	u32 sizetocopy, sizetocopyNow, sizecopied;
+
+	/* FIXME: Do we need spinlocks here? */
+
+	if (!size)
+		return CTSTATUS_INVALIDPARAM;
+
+	sizetocopy = min(wavexferbuf->xferbufsize, *size);
+	sizecopied = 0;
+
+	if (!sizetocopy)
+	{
+		*size = 0;
+		return CTSTATUS_SUCCESS;
+	}
+
+	if (wave_out->wave_fmt.bitspersample == 8)
+		wFillData = 0x8080;
+	else
+		wFillData = 0x0000;
+
+	while (sizecopied < sizetocopy)
+	{
+		sizetocopyNow = sizetocopy - sizecopied;
+		sizetocopyNow = min(sizetocopyNow, wavexferbuf->xferbufsize - wavexferbuf->xferpos);
+
+		fill_block(wavexferbuf->xferpos, wFillData, sizetocopyNow, wavexferbuf->xferbuffer);
+
+		wavexferbuf->xferpos += sizetocopyNow;
+		wavexferbuf->xferpos %= wavexferbuf->xferbufsize;
+		sizecopied += sizetocopyNow;
+	}
+
+	*size = sizetocopy;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveoutSetControl                                      */
+/*                                                                          */
+/* Input    : pICardWave - pointer to card wave object                      */
+/*            wave_out - pointer to the specified wave out instance         */
+/*            ctrl_id - control type                                        */
+/*            value - the value of the specified control to be set          */
+/*                                                                          */
+/* About    : set the specified control value of the wave device.           */
+/****************************************************************************/
+int sblive_waveoutSetControl(struct sblive_hw *sb_hw, struct wave_out *wave_out, u32 ctrl_id, u32 *control_value)
+{
+	struct sblive_waveout *card_waveout = sb_hw->card_waveout;
+	struct wave_out *currinst = NULL;
+	u32 value;
+	struct voice_cntlset setting[6];
+
+	if (card_waveout == NULL)
+		return CTSTATUS_ERROR;
+
+	if (control_value)
+		value = *control_value;
+	else
+		value = 0;
+
+	switch (ctrl_id)
+	{
+	case WAVEOBJVOLUME:
+		return CTSTATUS_SUCCESS;
+
+	case WAVEOBJMUTE:
+		/* This is a general mute affecting all wave instances */
+		card_waveout->mute = value;
+		currinst = card_waveout->wave_outlist;
+
+		if (value)
+		{
+			/* Mute */
+			card_waveout->globalvol = 0;
+		} else
+		{
+			/* Unmute */
+			card_waveout->globalvol = (0xffff & card_waveout->left) | ((0xffff & card_waveout->right) << 16);
+
+			set_volume(card_waveout);
+		}
+
+		return CTSTATUS_SUCCESS;
+
+	case WAVEOBJREVERB:
+		/* This is a general set reverb affecting all wave instances.
+		 * Apps which can set the reverb of individual wave instances
+		 * should use WAVEINSTANCEREVERB instead. */
+
+		card_waveout->globalreverb = value;
+		currinst = card_waveout->wave_outlist;
+
+		while (currinst && currinst->emu_voice)
+		{
+			struct voice_param * left = &currinst->emu_voice->voice_params;
+
+			/* This flag allows a wave instance to be unaffected by changes to global volume. */
+			if (currinst->globalreverbFactor)
+			{
+				u8 t = (card_waveout->globalreverb & 0xff) + (currinst->localreverb & 0xff);
+				left->unSends.tSends.reverb_send = (t > 255) ? 255 : t;
+
+				if (currinst->wavexferbuf->is_stereo && currinst->emu_voice->linked_voice)
+				{
+					struct voice_param *right = &currinst->emu_voice->linked_voice->voice_params;
+
+					right->unSends.tSends.reverb_send = left->unSends.tSends.reverb_send;
+
+					setting[0].paramID = PTRX_FXSENDAMOUNT_A;
+					setting[0].value = right->unSends.tSends.reverb_send;
+
+					sblive_voiceSetControl(currinst->emu_voice->linked_voice, setting, 1);
+				}
+
+				setting[0].paramID = PTRX_FXSENDAMOUNT_A;
+				setting[0].value = left->unSends.tSends.reverb_send;
+
+				sblive_voiceSetControl(currinst->emu_voice, setting, 1);
+			}
+			currinst = currinst->next;
+		}
+		return CTSTATUS_SUCCESS;
+
+	case WAVEOBJCHORUS:
+		/* This is a general set chorus affecting all wave instances.
+		 * Apps which can set the chorus of individual wave instances
+		 * should use WAVEINSTANCECHORUS instead. */
+
+		card_waveout->globalchorus = value;
+		currinst = card_waveout->wave_outlist;
+
+		while (currinst && currinst->emu_voice)
+		{
+			struct voice_param *left = &currinst->emu_voice->voice_params;
+
+			if (currinst->globalchorusFactor)
+			{
+				u8 t = (card_waveout->globalchorus & 0xff) + (currinst->localchorus & 0xff);
+				left->unSends.tSends.chorus_send = (t > 255) ? 255 : t;
+
+				if (currinst->wavexferbuf->is_stereo && currinst->emu_voice->linked_voice)
+				{
+					struct voice_param *right = &currinst->emu_voice->linked_voice->voice_params;
+
+					right->unSends.tSends.chorus_send = left->unSends.tSends.chorus_send;
+
+					setting[0].paramID = DSL_FXSENDAMOUNT_D;
+					setting[0].value = right->unSends.tSends.chorus_send;
+
+					sblive_voiceSetControl(currinst->emu_voice->linked_voice, setting, 1);
+				}
+				setting[0].paramID = DSL_FXSENDAMOUNT_D;
+				setting[0].value = left->unSends.tSends.chorus_send;
+
+				sblive_voiceSetControl(currinst->emu_voice, setting, 1);
+			}
+			currinst = currinst->next;
+		}
+		return CTSTATUS_SUCCESS;
+
+	case WAVESYNCHSTART:
+		if (sblive_waveoutSynchStart(card_waveout, value) != CTSTATUS_SUCCESS)
+			return CTSTATUS_ERROR;
+		return CTSTATUS_SUCCESS;
+
+	default:
+		break;
+	}
+
+	if (!wave_out)
+		return CTSTATUS_ERROR;
+
+	switch (ctrl_id)
+	{
+	case WAVECURPOS:
+		if (wave_out->emu_voice == NULL)
+			return CTSTATUS_ERROR;
+
+		if (wave_out->state == CARDWAVE_STATE_STOPPED)
+		{
+			wave_out->setpos = TRUE;
+			wave_out->position = value;
+		} else
+		{
+			struct voice_param * left = &wave_out->emu_voice->voice_params;
+			/* struct wave_xferbuf * wavexferbuf = wave_out->wavexferbuf; */
+
+			if (wave_out->wave_fmt.bitspersample == 8)
+				value <<= 1;
+			if (wave_out->wave_fmt.channels == 2)
+				value >>= 1;
+			/* get no. of samples per channel */
+			value >>= 1;
+
+			/* if the position is already beyond the loop, return error. */
+			/* we could check this value before lock can't we ? */
+			if (value >= (left->end - left->start))
+				return CTSTATUS_ERROR;
+
+			/* Set current position */
+			setting[0].paramID = CCCA_CURRADDR;
+			setting[0].value = value + left->start;
+			sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
+
+			if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
+			{
+				setting[0].paramID = CCCA_CURRADDR;
+				setting[0].value = value + wave_out->emu_voice->linked_voice->voice_params.start;
+
+				sblive_voiceSetControl(wave_out->emu_voice->linked_voice, setting, 1);
+			}
+		}
+		break;
+
+	case WAVESTOPPOSITION:
+		wave_out->wavexferbuf->stopposition = value;
+		break;
+
+	case WAVEWRITEPOINTER:
+		/* For wave output device, set write pointer for a particular wave instance.
+		 * For wave input device, set the offset of write pointer. */
+		wave_out->wavexferbuf->xferpos = value;
+		break;
+
+	case WAVEINSTANCEVOLUME:
+		/* This is a specific set volume affecting only 1 wave instance and can be only called by the owner.
+		 * Apps which can set the volume of individual wave instances should use this message. */
+
+		/* update wave instance volume */
+		wave_out->localvol = value;
+
+		if (wave_out->emu_voice != NULL)
+		{
+			u32 vol;
+			struct voice_param * left = &wave_out->emu_voice->voice_params;
+
+			vol = set_volume_instance(card_waveout, wave_out, left);
+
+			if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
+			{
+				struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
+
+				right->unSends.tSends.pan_send = 0; /* Left output of right channel is always zero */
+				right->unSends.tSends.aux_send = left->unSends.tSends.aux_send; /* Update right channel aux */
+				left->unSends.tSends.aux_send = 0; /* Zero out right output of left channel */
+				right->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2); /* Update right channel attenuation */
+
+				setting[0].paramID = IFATN_ATTENUATION;
+				setting[0].value = right->initial_attn;
+
+				sblive_voiceSetControl(wave_out->emu_voice->linked_voice, setting, 1);
+			}
+
+			setting[0].paramID = IFATN_ATTENUATION;
+			setting[0].value = left->initial_attn;
+
+			sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
+		}
+		break;
+
+
+	case WAVESYNCHSETUP:
+		wave_out->process_id = value;
+		wave_out->synchstart = TRUE;
+		break;
+
+	case WAVESETFREQUENCY:
+		if (wave_out->emu_voice != NULL)
+		{
+			struct voice_param * left = &wave_out->emu_voice->voice_params;
+
+			left->initial_pitch = (u16) (srToPitch(value) >> 8); /* Calculate pitch */
+
+			setting[0].paramID = IP;
+			setting[0].value = left->initial_pitch;
+			sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
+
+			if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
+			{
+				struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
+
+				right->initial_pitch = left->initial_pitch;
+				setting[0].paramID = IP;
+				setting[0].value = right->initial_pitch;
+
+				sblive_voiceSetControl(wave_out->emu_voice->linked_voice, setting, 1);
+			}
+		}
+		wave_out->wave_fmt.samplingrate = value;
+		break;
+
+	case WAVESTARTLOOP:
+		if (wave_out->emu_voice != NULL)
+		{
+			struct voice_param *left = &wave_out->emu_voice->voice_params;
+
+			setting[0].paramID = PSST_LOOPSTARTADDR;
+			setting[0].value = left->startloop;
+
+			sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
+
+			if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
+			{
+				struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
+
+				setting[0].paramID = PSST_LOOPSTARTADDR;
+				setting[0].value = right->startloop;
+
+				sblive_voiceSetControl(wave_out->emu_voice->linked_voice, setting, 1);
+			}
+		}
+		break;
+
+	case WAVEINSTANCEFORMAT:
+		return sblive_waveoutSetFormat(sb_hw, wave_out, (struct wave_format *) control_value);
+	case WAVEVOLFACTOR:
+		wave_out->globalvolFactor = value;
+		break;
+
+	case WAVEREVERBFACTOR:
+		wave_out->globalreverbFactor = value;
+		break;
+
+	case WAVECHORUSFACTOR:
+		wave_out->globalchorusFactor = value;
+		break;
+
+	case WAVESETSTARTFLAG:
+		if (wave_out->playflags != value && (wave_out->state == CARDWAVE_STATE_STARTED))
+		{
+			struct sblive_hw *sb_hw = wave_out->emu_voice->sb_hw;
+
+			if (value & CARDWAVE_PLAY_LOOPING)
+			{
+				halClearStopOnLoop(sb_hw, wave_out->emu_voice->voicenum);
+				if (wave_out->emu_voice->linked_voice)
+					halClearStopOnLoop(sb_hw, wave_out->emu_voice->linked_voice->voicenum);
+			} else
+			{
+				halSetStopOnLoop(sb_hw, wave_out->emu_voice->voicenum);
+				if (wave_out->emu_voice->linked_voice)
+					halSetStopOnLoop(sb_hw, wave_out->emu_voice->linked_voice->voicenum);
+			}
+		}
+		wave_out->playflags = value;
+		break;
+
+	case WAVESETSTOPONLOOP:
+		if (wave_out->state == CARDWAVE_STATE_STARTED)
+		{
+			struct sblive_hw * sb_hw = wave_out->emu_voice->sb_hw;
+			u32 CA, offset, endloop;
+			struct voice_param * left = &wave_out->emu_voice->voice_params;
+			struct voice_cntlset setting[3];
+
+			CA = sblive_readptr(sb_hw, CCCA_CURRADDR, wave_out->emu_voice->voicenum) - left->startloop;
+			offset = (CA / wave_out->callbacksize) * wave_out->callbacksize;
+
+			if (CA % wave_out->callbacksize)
+				offset += wave_out->callbacksize;
+
+			if (CA > (offset - 32))
+				offset += 32;
+
+			offset = CA;
+			endloop = offset + left->startloop;
+			setting[0].paramID = DSL_LOOPENDADDR;
+			setting[0].value = endloop;
+
+			sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
+
+			if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
+			{
+				struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
+
+				endloop = offset + right->startloop;
+				setting[0].paramID = DSL_LOOPENDADDR;
+				setting[0].value = endloop;
+
+				sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
+			}
+
+			halSetStopOnLoop(sb_hw, wave_out->emu_voice->voicenum);
+
+			if (wave_out->emu_voice->linked_voice)
+				halSetStopOnLoop(sb_hw, wave_out->emu_voice->linked_voice->voicenum);
+		}
+		break;
+
+	default:
+		return CTSTATUS_NOTSUPPORTED;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/* Function : sblive_waveoutGetControl                                      */
+/*                                                                          */
+/* Input    : card_waveout - pointer to card wave object                    */
+/*            wave_out - pointer to the specified wave out instance         */
+/*            ctrl_id - control type                                        */
+/*                                                                          */
+/* Output   : value - pointer to the control value                          */
+/*                                                                          */
+/* About    : get the specified control value of the wave device.           */
+/****************************************************************************/
+int sblive_waveoutGetControl(struct sblive_waveout *card_waveout, struct wave_out *wave_out, u32 ctrl_id, u32 *value)
+{
+	switch (ctrl_id)
+	{
+	case WAVEOBJVOLUME:
+		*value = card_waveout->globalvol;
+		return CTSTATUS_SUCCESS;
+
+	case WAVEOBJREVERB:
+		*value = card_waveout->globalreverb;
+		return CTSTATUS_SUCCESS;
+
+	case WAVEOBJCHORUS:
+		*value = card_waveout->globalchorus;
+		return CTSTATUS_SUCCESS;
+
+	case WAVEQUERYACTIVEINST:
+		if (card_waveout->wave_outlist != NULL)
+			return CTSTATUS_SUCCESS;
+		else
+			return CTSTATUS_ERROR;
+
+	default:
+		break;
+	}
+
+	if (!wave_out)
+		return CTSTATUS_ERROR;
+
+	switch (ctrl_id)
+	{
+	case WAVECURPOS:
+		if (wave_out->emu_voice == NULL)
+			return CTSTATUS_ERROR;
+
+		/* There is no actual start yet */
+		if (wave_out->state == CARDWAVE_STATE_STOPPED || wave_out->state == CARDWAVE_STATE_SUSPEND)
+		{
+			if (wave_out->setpos)
+				*value = wave_out->position;
+			else
+				*value = wave_out->wavexferbuf->stopposition * (wave_out->wavexferbuf->is_stereo + 1) * (wave_out->wavexferbuf->is16bit + 1);
+		} else
+		{
+			if (sblive_voiceGetControl(wave_out->emu_voice, CCCA_CURRADDR, value) != CTSTATUS_SUCCESS)
+				return CTSTATUS_ERROR;
+
+			*value -= wave_out->emu_voice->voice_params.start;
+
+			/* Get number of bytes in play buffer per channel.
+			 * If 8 bit mode is enabled, this needs to be changed. */
+			{
+				u32 samples = 64 * (wave_out->wavexferbuf->is_stereo + 1);
+
+				*value *= (wave_out->wavexferbuf->is_stereo + 1) * (wave_out->wavexferbuf->is16bit + 1);
+
+				/* Refer to voicemgr.c, CA is not started at zero.
+				 * We need to take this into account. */
+
+				samples -= 4 * (wave_out->wavexferbuf->is16bit + 1);
+
+				if (*value >= samples)
+					*value -= samples;
+				else
+					*value += wave_out->wavexferbuf->xferbufsize - samples;
+			}
+		}
+
+		break;
+
+	case WAVEWRITEPOINTER:
+		/* Get write pointer for a particular wave instance */
+		*value = wave_out->wavexferbuf->xferpos;
+		break;
+
+	case WAVEINSTANCEVOLUME:
+		*value = wave_out->localvol;
+		return CTSTATUS_SUCCESS;
+
+	case WAVEINSTANCEREVERB:
+		*value = wave_out->localreverb;
+		return CTSTATUS_SUCCESS;
+
+	case WAVEINSTANCECHORUS:
+		*value = wave_out->localchorus;
+		return CTSTATUS_SUCCESS;
+
+	case WAVESTARTLOOP:
+		if (wave_out->emu_voice == NULL)
+			return CTSTATUS_ERROR;
+
+		if (sblive_voiceGetControl(wave_out->emu_voice, PSST_LOOPSTARTADDR, value) != CTSTATUS_SUCCESS)
+			return CTSTATUS_ERROR;
+
+		*value -= wave_out->emu_voice->voice_params.start;
+
+		/* Get number of bytes in play buffer per channel.
+		 * If 8 bit mode is enabled, this needs to be changed. */
+		*value <<= 1;
+		*value *= (wave_out->wavexferbuf->is_stereo + 1);
+		*value /= (2 - wave_out->wavexferbuf->is16bit);
+		break;
+
+	case WAVEENDLOOP:
+		if (wave_out->emu_voice == NULL)
+			return CTSTATUS_ERROR;
+
+		if (sblive_voiceGetControl(wave_out->emu_voice, DSL_LOOPENDADDR, value) != CTSTATUS_SUCCESS)
+			return CTSTATUS_ERROR;
+
+		*value -= wave_out->emu_voice->voice_params.start;
+
+		/* Get number of bytes in play buffer per channel.
+		 * Iif 8 bit mode is enabled, this needs to be changed. */
+		*value <<= 1;
+		*value *= (wave_out->wavexferbuf->is_stereo + 1);
+		*value /= (2 - wave_out->wavexferbuf->is16bit);
+		break;
+
+	default:
+		return CTSTATUS_NOTSUPPORTED;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
Index: oldkernel/linux/drivers/sound/emu10k1/cardwo.h
diff -u /dev/null linux/drivers/sound/emu10k1/cardwo.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/cardwo.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,166 @@
+/*     
+ **********************************************************************
+ *     cardwo.h -- header file for card wave out functions
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#ifndef _CARDWO_H
+#define _CARDWO_H
+
+#include "icardwav.h"
+
+struct wave_xferbuf 
+{
+	u32     xferpos;
+	u32     xferbufsize;     /* transfer buffer size */
+	u32     numpages;        /* number of pages in transfer buffer */
+	void    **xferbuffer;    /* pointer to the transfer buffer */
+	u32     format;
+	int     is_stereo;
+	int     is16bit;
+	u32     conv;
+	u32     interpolationbytes;
+	u32     offset;          /* used for non-pagealigned buffer in P10 */
+	u32     stopposition;
+};
+
+typedef struct tCARDMIXEROBJ  *PCARDMIXEROBJ;
+
+struct wave_out
+{
+    struct wave_out  *next;
+    u32             status;
+    u32             state;
+    int              synchstart;
+    struct emu_voice *emu_voice;
+    struct emu_page *emuaddr;
+    struct emu_timer *timer;
+    struct wave_xferbuf *wavexferbuf;
+    void 	    **pagetable;
+    u32             callbacksize;
+    u32             localvol;
+    u32             localreverb;
+    u32             localchorus;
+    u32             globalvolFactor;
+    u32             globalreverbFactor;
+    u32             globalchorusFactor;
+    u32             process_id;        /* used for synchonize start */
+    int              setpos;
+    u32             position;
+    short               ZL[6];              /* for pre-comp */
+    short               ZR[6];              /* for pre-comp */
+    struct wave_format      wave_fmt;
+    u32             playflags;
+    struct tq_struct *task;
+};
+
+
+/* sblive_wave states */
+#define CARDWAVE_STATE_STOPPED      0x0001
+#define CARDWAVE_STATE_STOPPING     0x0008
+#define CARDWAVE_STATE_STARTED      0x0002
+#define CARDWAVE_STATE_SUSPEND      0x0004
+
+
+/* Transfer buffer formats */
+#define M8                          0x00
+#define M16                         0x01
+#define S8                          0x02
+#define S16                         0x03
+
+#define INTERPOLATION_BYTES         8
+/* setting this to other than a power of two
+   may break some applications */
+#define WAVEOUT_MAXBUFSIZE          16384
+#define WAVEOUT_MINBUFSIZE	    2048
+
+#define WAVEOUT_DEFAULTFRAGLEN      100 /* Time to play a fragment in ms (latency) */
+#define WAVEOUT_DEFAULTBUFLEN       1000 /* Time to play the entire buffer in ms */
+
+#define CARDWAVE_DEFAULT_MAXPLAYINST 64
+
+struct woinst 
+{
+        struct wave_out *wave_out;
+        struct wave_format wave_fmt;
+        u16 ossfragshift;
+        u32 fragment_size;
+        u32 numfrags;
+        wait_queue_head_t wait_queue;
+        int mapped;
+        u32 total_copied;
+        u32 total_played;
+        int silence_filled;
+        u32 silence_start;
+        u32 getoptr_blocks;
+	u32 wave_ptr;
+	spinlock_t lock;
+};
+
+struct sblive_waveout
+{
+    PCARDMIXEROBJ   mixer;
+    int          fWhql;
+
+    struct wave_caps	caps;
+    struct wave_out *wave_outlist;
+	
+    u32	numplaybackinst;
+    u32 maxnumplayinst;
+    u32 globalvol;
+    u32 mute;
+    u32 left;
+    u32 right;
+    u32 globalreverb;
+    u32 globalchorus;
+    u32 lineid;
+    u32 ctrlid;
+};
+
+int sblive_waveoutInit(struct sblive_waveout *, u8 *);
+int sblive_waveoutExit(struct sblive_waveout *);
+int sblive_waveoutQueryFormat(struct sblive_waveout *, struct wave_format *, u32);
+int sblive_waveoutOpen(struct sblive_hw *, struct wave_format *, u32 *, u32, struct wave_out **);
+int sblive_waveoutClose(struct sblive_hw *, struct wave_out *);
+int sblive_waveoutStart(struct sblive_wavedevice *);
+int sblive_waveoutStop(struct sblive_hw *, struct wave_out *, u32 *);
+int sblive_waveoutGetXferSize(struct sblive_waveout *, struct wave_out *, u32 *, u32 *);
+int sblive_waveoutXferData(struct sblive_waveout *, struct wave_out *, u8 *, u32 *);
+int sblive_waveoutFillSilence(struct sblive_waveout *, struct wave_out *, u32 *);
+int sblive_waveoutSetControl(struct sblive_hw *, struct wave_out *, u32, u32 *);
+int sblive_waveoutGetControl(struct sblive_waveout *, struct wave_out *, u32, u32 *);
+int sblive_emuAllocXferBuffer(struct sblive_hw *, struct wave_out *, u32 *, void ***);
+int sblive_emuGetXferBuffer(struct sblive_hw *, struct wave_out *, u32 *, void ***);
+int sblive_emuDeallocXferBuffer(struct wave_out *);
+void initWaveOutXferBuffer(struct wave_out *);
+int sblive_waveoutSynchStart(struct sblive_waveout *, u32);
+
+int sblive_mixerLineChange(PCARDMIXEROBJ, u32, u32);
+int sblive_mixerSetControlValue(PCARDMIXEROBJ, u32, u32, u32, u32, u32);
+
+#endif /* _CARDWO_H */
Index: oldkernel/linux/drivers/sound/emu10k1/efxmgr.c
diff -u /dev/null linux/drivers/sound/emu10k1/efxmgr.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/efxmgr.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,190 @@
+/*     
+ **********************************************************************
+ *     sblive_fx.c
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#include "hwaccess.h"
+#include "efxmgr.h"
+
+int sblive_fxInit(struct sblive_hw *sb_hw)
+{
+	int i;
+	u32 z, w, x, y, pc = 16;
+
+	for (i = 0; i < 512; i++) 
+	{
+		WRITE_EFX(sb_hw, i * 2, 0x10040);
+		WRITE_EFX(sb_hw, i * 2 + 1, 0x610040);
+	}
+
+	for (i = 0; i < 256; i++)
+	  sblive_writeptr(sb_hw, FXGPREGBASE + i, 0, 0);
+
+	w = 0x40;
+	x = 1;
+	y = 0x44;
+	z = 0x101;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (4 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x101;
+	x = 0x115;
+	y = 0x11;
+	z = 0x101;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x101;
+	x = 0x113;
+	y = 0x13;
+	z = 0x101;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x101;
+	x = 0x40;
+	y = 0x40;
+	z = 0x21;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
+	++pc;
+
+	z = 0x23;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x40;
+	x = 0x40;
+	y = 0x40;
+	z = 0x25;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
+	++pc;
+
+	z = 0x27;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x40;
+	x = 0x111;
+	y = 0x101;
+	z = 0x29;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x40;
+	x = 0x11;
+	y = 0x40;
+	z = 0x2B;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x40;
+	x = 0;
+	y = 0x44;
+	z = 0x100;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (4 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x100;
+	x = 0x114;
+	y = 0x10;
+	z = 0x100;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x100;
+	x = 0x112;
+	y = 0x12;
+	z = 0x100;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x100;
+	x = 0x40;
+	y = 0x40;
+	z = 0x20;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
+	++pc;
+
+	z = 0x22;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x40;
+	x = 0x40;
+	y = 0x40;
+	z = 0x24;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
+	++pc;
+
+	z = 0x26;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x40;
+	x = 0x110;
+	y = 0x100;
+	z = 0x28;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
+	++pc;
+
+	w = 0x40;
+	x = 0x10;
+	y = 0x40;
+	z = 0x2A;
+	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
+	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
+	++pc;
+
+	sblive_writeptr(sb_hw, DBG, 0, 0);
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* FIXME: We should probably be doing something here */
+int sblive_fxExit(struct sblive_hw *sb_hw)
+{
+	return CTSTATUS_SUCCESS;
+}
Index: oldkernel/linux/drivers/sound/emu10k1/efxmgr.h
diff -u /dev/null linux/drivers/sound/emu10k1/efxmgr.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/efxmgr.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,38 @@
+/*     
+ **********************************************************************
+ *     sblive_fx.h
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#ifndef _EFXMGR_H
+#define _EFXMGR_H
+
+int sblive_fxInit(struct sblive_hw *);
+int sblive_fxExit(struct sblive_hw *);
+
+#endif /* _EFXMGR_H */
Index: oldkernel/linux/drivers/sound/emu10k1/emu_wrapper.h
diff -u /dev/null linux/drivers/sound/emu10k1/emu_wrapper.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/emu_wrapper.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,25 @@
+#ifndef __EMU_WRAPPER_H
+#define __EMU_WRAPPER_H
+
+/* wrapper for 2.2 kernel */
+
+#include <linux/wrapper.h>
+
+#define vma_get_pgoff(v)	 vma_get_offset(v)
+#define wait_queue_head_t	 struct wait_queue *
+#define DECLARE_WAITQUEUE(a, b)  struct wait_queue a = {b, NULL};
+#define init_waitqueue_head(a)	 init_waitqueue(a)
+
+#define RSRCADDRESS(dev,num)    ((dev)->base_address[(num)])
+
+#define RSRCISIOREGION(dev,num) (RSRCADDRESS(dev,num) != 0 && \
+	(RSRCADDRESS(dev,num) & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+
+#define init_MUTEX(a) *(a) = MUTEX
+
+#define UP_INODE_SEM(a)		up(a)
+#define DOWN_INODE_SEM(a)	down(a)
+
+#define GET_INODE_STRUCT()	struct inode *inode = file->f_dentry->d_inode
+
+#endif
Index: oldkernel/linux/drivers/sound/emu10k1/emuadxmg.c
diff -u /dev/null linux/drivers/sound/emu10k1/emuadxmg.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/emuadxmg.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,262 @@
+/*     
+ **********************************************************************
+ *     emuadxmg.c - Address space manager for emu10k1 driver 
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#include "hwaccess.h"
+
+/************************************************************************
+*
+*   int emu10kaddxmgrInit(struct sblive_hw * sb_hw)
+*
+*   ENTRY
+*       sb_hw  -    Pointer to the HWOBJ to init voice manager
+*
+*   RETURNS
+*       Always returns CTSTATUS_SUCCESS
+*
+*   ABOUT
+*       Inits data
+*
+************************************************************************/
+int emu10kaddxmgrInit(struct sblive_hw *sb_hw)
+{
+	u32 count;
+
+	for (count = 0; count < MAXPAGES; count++) 
+	  sb_hw->emu_addrmgr.emupagetable[count].flags = 0;
+
+	/* Mark first page as used */
+	/* This page is reserved by the driver */
+	sb_hw->emu_addrmgr.emupagetable[0].flags = 0x8001;
+	sb_hw->emu_addrmgr.emupagetable[1].flags = MAXPAGES - RESERVED - 1;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/************************************************************************
+*
+*   int emu10kaddxmgrExit(struct sblive_hw * sb_hw)
+*
+*   ENTRY
+*       sb_hw  -    Pointer to the HWOBJ to exit
+*
+*   RETURNS
+*       Always returns CTSTATUS_SUCCESS
+*
+*   ABOUT
+*       Exits
+*
+************************************************************************/
+int emu10kaddxmgrExit(struct sblive_hw *sb_hw)
+{
+	u32 count;
+
+	/* TODO : callback all address owners */
+
+	for (count = 0; count < MAXPAGES; count++)
+	  sb_hw->emu_addrmgr.emupagetable[count].flags = 0;
+	
+	sb_hw->emu_addrmgr.emupagetable[0].flags = MAXPAGES - RESERVED;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/************************************************************************
+*
+*   u32 emu10kaddxmgrMaxContigPages(struct sblive_hw * sb_hw)
+*
+*   ENTRY
+*       sb_hw  -    Pointer to the HWOBJ to check
+*
+*   RETURNS
+*       largest free contiguous block in pages
+*
+*   ABOUT
+*       Gets largest free contiguous block in pages
+*
+************************************************************************/
+u32 emu10kaddxmgrMaxContigPages(struct sblive_hw *sb_hw)
+{
+	u32 maxpages = 0;
+	u16 pageindex = 0;
+	struct emu_addrmgr *mgr;
+
+	mgr = &sb_hw->emu_addrmgr;
+
+	while (pageindex < (MAXPAGES - RESERVED - 1)) 
+	{
+		if (mgr->emupagetable[pageindex].flags & 0x8000) 
+		{
+			/* This block of pages is in use, jump to the start of the next block */
+			pageindex += (mgr->emupagetable[pageindex].flags & 0x7fff);
+		} else 
+		{ 
+			/* Found free block */
+			if (mgr->emupagetable[pageindex].flags > (u16) maxpages) 
+			  maxpages = mgr->emupagetable[pageindex].flags; /* Block is large enough */
+			else 
+			  pageindex += mgr->emupagetable[pageindex].flags; /* Block too small - jump to the start of the next block */
+		}
+	}
+
+	return maxpages;
+}
+
+
+/************************************************************************
+*
+*   int emu10kaddxmgrAlloc(struct emuaddr_allocdesc * emuaddrAllocDesc,
+*                         struct emu_page **pemuaddrObj)
+*
+*   ENTRY
+*       emuaddrAllocDesc -
+*           Pointer to a struct emuaddr_allocdesc that describes the
+*           address space needed.
+*
+*       pemuaddrObj      -
+*           Address to return allocated struct emu_page
+*
+*   RETURNS
+*       SUCCESS -   CTSTATUS_SUCCESS
+*       FAILURE -   CTSTATUS_NOMEMORY (not enough available address space)
+*
+*   ABOUT
+*       Allocates emu address space
+*
+************************************************************************/
+int emu10kaddxmgrAlloc(struct emuaddr_allocdesc *allocdesc, struct emu_page **emu_pageptr)
+{
+	struct sblive_hw * sb_hw;
+	u32 emupageindex = 0;
+	u32 pages;
+	struct emu_page * pemupagetable;
+	unsigned long flags;
+
+	sb_hw = allocdesc->sb_hw;
+	pemupagetable = sb_hw->emu_addrmgr.emupagetable;
+	*emu_pageptr = NULL;
+
+	/* Convert bytes to pages */
+	pages = (allocdesc->size / PAGE_SIZE) +
+	    ((allocdesc->size % PAGE_SIZE) ? 1 : 0);
+
+	while (emupageindex < (MAXPAGES - RESERVED - 1)) 
+	{
+		if (pemupagetable[emupageindex].flags & 0x8000) 
+		{
+			/* This block of pages is in use, jump to the start of the next block. */
+			emupageindex += (pemupagetable[emupageindex].flags & 0x7fff);
+		} else 
+		{
+			/* Found free block */
+			if (pemupagetable[emupageindex].flags >= (u16) pages) 
+			{
+				spin_lock_irqsave(&sb_hw->emu_lock, flags);
+
+				/* Block is large enough */
+				
+				/* If free block is larger than the block requested
+				 * then adjust the size of the block remaining */
+				if (pemupagetable[emupageindex].flags > (u16) pages) 
+				  pemupagetable[emupageindex + pages].flags = pemupagetable[emupageindex].flags - (u16) pages;
+				
+				pemupagetable[emupageindex].flags = (u16) (pages | 0x8000); /* Mark block as used */
+
+				/* Return emu address */
+				pemupagetable[emupageindex].sb_hw = sb_hw;
+				pemupagetable[emupageindex].emustartaddr = emupageindex << 11;
+				*emu_pageptr = &pemupagetable[emupageindex];
+
+				spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+				return CTSTATUS_SUCCESS;
+			} else 
+			{
+				/* Block too small, jump to the start of the next block */
+				emupageindex += pemupagetable[emupageindex].flags;
+			}
+		}
+	}
+
+	return CTSTATUS_NOMEMORY;
+}
+
+/************************************************************************
+*
+*   int emu10kaddxmgrFree(struct emu_page * emuaddrObj)
+*
+*   ENTRY
+*       emuaddrObj -
+*           pointer to a struct emu_page returned
+*           by a call to emu10kaddxmgrAlloc()
+*
+*   RETURNS
+*       SUCCESS -   CTSTATUS_SUCCESS
+*       FAILURE -   CTSTATUS_ERROR
+*
+*   ABOUT
+*       Frees a previously allocated emu address space.
+*
+************************************************************************/
+int emu10kaddxmgrFree(struct emu_page *page)
+{
+	struct sblive_hw * sb_hw;
+	u16 origsize = 0;
+	u32 pageindex;
+	struct emu_page * pemupagetable;
+	unsigned long flags;
+
+	sb_hw = page->sb_hw;
+	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+
+	pemupagetable = sb_hw->emu_addrmgr.emupagetable;
+	pageindex = page->emustartaddr;
+
+	/* Convert Emu address to Emu page number */
+	pageindex >>= 11;
+
+	if (pemupagetable[pageindex].flags & 0x8000) 
+	{
+		/* Block is allocated - mark block as free */
+		origsize = pemupagetable[pageindex].flags & 0x7fff;
+		pemupagetable[pageindex].flags = origsize;
+		pemupagetable[pageindex].emustartaddr = 0;
+
+		/* If next block is free, we concat both blocks */
+		if (!(pemupagetable[pageindex + origsize].flags & 0x8000)) 
+		  pemupagetable[pageindex].flags += pemupagetable[pageindex + origsize].flags & 0x7fff;
+	}
+	
+	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+	return origsize;
+}
Index: oldkernel/linux/drivers/sound/emu10k1/hwaccess.c
diff -u /dev/null linux/drivers/sound/emu10k1/hwaccess.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/hwaccess.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,891 @@
+/*
+ **********************************************************************
+ *     hwaccess.c -- Hardware access layer
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     December 9, 1999     Jon Taylor      rewrote the I/O subsystem
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "mycommon.h"
+#include "emu_wrapper.h"
+
+
+spinlock_t sblive_spinlock = SPIN_LOCK_UNLOCKED;
+
+int halHWInit(struct sblive_hw *sb_hw);
+
+int halInit(struct sblive_hw *sb_hw, struct sblive_config *config, u32 *hwflags)
+{
+	unsigned long ioaddr;
+
+	/* should fill in default values here */
+	sb_hw->paneffectsbus = 0;
+	sb_hw->auxeffectsbus = 1;
+	sb_hw->choruseffectsbus = 2;
+	sb_hw->reverbeffectsbus = 3;
+
+	/* Setup Critical Sections */
+	spin_lock_init(&sb_hw->emu_lock);
+
+	sb_hw->numvoices = NUM_G;
+	sb_hw->dsCardCfg = *config;
+
+	sb_hw->hwaddr = config->ioportbase[0];
+	ioaddr = config->ioportbase[0];
+
+	sb_hw->mixeraddx = (u32) (ioaddr + AC97DATA);
+	sb_hw->hwconfigaddx = (u32) (ioaddr + HCFG);
+
+	sb_hw->hw_irq.irq = config->IRQregs[0];
+	if (sb_hw->hw_irq.irq)
+	{
+		if (sb_hw->hw_irq.irq == 2)
+			sb_hw->hw_irq.irq = 9;
+	}
+
+	sb_hw->hw_irq.sb_hw = sb_hw;
+
+	/* Init Card */
+	if (halHWInit(sb_hw) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	if (sblive_irqmgrInit(&sb_hw->hw_irq) != CTSTATUS_SUCCESS)
+	{
+		DPF(2, "Failed to initialize IRQ manager\n");
+		sb_hw->hw_irq.irq = 0;
+	}
+
+	sblive_voiceInit(sb_hw);
+	sblive_timerinit(sb_hw);
+	emu10kaddxmgrInit(sb_hw);
+
+	DPD(2, "  hw control register -> %x\n", sblive_readfn0(sb_hw, HCFG));
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/*   halExit(struct sblive_hw * sb_hw)                                      */
+/****************************************************************************/
+int halExit(struct sblive_hw * sb_hw)
+{
+	int ch;
+
+	sblive_voiceExit(sb_hw);
+	emu10kaddxmgrExit(sb_hw);
+
+	if (sb_hw->hw_irq.irq)
+	{
+		sblive_writefn0(sb_hw,INTE, DISABLE);
+		sblive_irqmgrExit(&sb_hw->hw_irq);
+	}
+
+	/** Shutdown the chip **/
+	for (ch = 0; ch < NUM_G; ch++)
+		sblive_writeptr(sb_hw, DCYSUSV, ch, ENV_OFF);
+
+	for (ch = 0; ch < NUM_G; ch++)
+	{
+		sblive_writeptr(sb_hw, VTFT, ch, 0);
+		sblive_writeptr(sb_hw, CVCF, ch, 0);
+		sblive_writeptr(sb_hw, PTRX, ch, 0);
+		sblive_writeptr(sb_hw, CPF, ch, 0);
+	}
+
+	/* Reset recording buffers */
+	sblive_writeptr(sb_hw, MICBS, 0, 0);
+	sblive_writeptr(sb_hw, MICBA, 0, 0);
+	sblive_writeptr(sb_hw, FXBS, 0, 0);
+	sblive_writeptr(sb_hw, FXBA, 0, 0);
+	sblive_writeptr(sb_hw, FXWC, 0, 0);
+	sblive_writeptr(sb_hw, ADCBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(sb_hw, ADCBA, 0, 0);
+	sblive_writeptr(sb_hw, TCBS, 0, TCBS_BUFFSIZE_16K);
+	sblive_writeptr(sb_hw, TCB, 0, 0);
+	sblive_writeptr(sb_hw, DBG, 0, 0x8000);
+
+	/* Disable channel interrupt */
+	sblive_writeptr(sb_hw, CLIEL, 0, 0);
+	sblive_writeptr(sb_hw, CLIEH, 0, 0);
+	sblive_writeptr(sb_hw, SOLEL, 0, 0);
+	sblive_writeptr(sb_hw, SOLEH, 0, 0);
+
+	/* Disable audio and lock cache */
+	sblive_writefn0(sb_hw, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE);
+	sblive_writeptr(sb_hw, PTB, 0, 0);
+
+	osFreeMemPhysical(&sb_hw->silentpage);
+	osFreeMemPhysical(&sb_hw->virtualpagetable);
+	osFreeMemPhysical(&sb_hw->tankmem);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/*  halHWInit (struct sblive_hw *sb_hw)                                     */
+/****************************************************************************/
+int halHWInit(struct sblive_hw *sb_hw)
+{
+	int nCh;
+	u32 size = 0;
+	u32 sizeIdx = 0;
+	u16 count;
+	int status;
+
+	/* Disable audio and lock cache */
+	sblive_writefn0(sb_hw, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE);
+
+	/* Reset recording buffers */
+	sblive_writeptr(sb_hw, MICBS, 0, 0);
+	sblive_writeptr(sb_hw, MICBA, 0, 0);
+	sblive_writeptr(sb_hw, FXBS, 0, 0);
+	sblive_writeptr(sb_hw, FXBA, 0, 0);
+	sblive_writeptr(sb_hw, ADCBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(sb_hw, ADCBA, 0, 0);
+
+	/* Disable channel interrupt */
+	sblive_writefn0(sb_hw,INTE, DISABLE);
+	sblive_writeptr(sb_hw, CLIEL, 0, 0);
+	sblive_writeptr(sb_hw, CLIEH, 0, 0);
+	sblive_writeptr(sb_hw, SOLEL, 0, 0);
+	sblive_writeptr(sb_hw, SOLEH, 0, 0);
+
+	/* Init envelope engine */
+	for (nCh = 0; nCh < NUM_G; nCh++)
+	{
+		sblive_writeptr(sb_hw, DCYSUSV, nCh, ENV_OFF);
+		sblive_writeptr(sb_hw, IP, nCh, 0);
+		sblive_writeptr(sb_hw, VTFT, nCh, 0xffff);
+		sblive_writeptr(sb_hw, CVCF, nCh, 0xffff);
+		sblive_writeptr(sb_hw, PTRX, nCh, 0);
+		sblive_writeptr(sb_hw, CPF, nCh, 0);
+		sblive_writeptr(sb_hw, CCR, nCh, 0);
+
+		sblive_writeptr(sb_hw, PSST, nCh, 0);
+		sblive_writeptr(sb_hw, DSL, nCh, 0x10);
+		sblive_writeptr(sb_hw, CCCA, nCh, 0);
+		sblive_writeptr(sb_hw, Z1, nCh, 0);
+		sblive_writeptr(sb_hw, Z2, nCh, 0);
+		sblive_writeptr(sb_hw, FXRT, nCh, 0xd01c0000);
+
+		sblive_writeptr(sb_hw, ATKHLDM, nCh, 0);
+		sblive_writeptr(sb_hw, DCYSUSM, nCh, 0);
+		sblive_writeptr(sb_hw, IFATN, nCh, 0xffff);
+		sblive_writeptr(sb_hw, PEFE, nCh, 0);
+		sblive_writeptr(sb_hw, FMMOD, nCh, 0);
+		sblive_writeptr(sb_hw, TREMFRQ, nCh, 24);	/* 1 Hz */
+		sblive_writeptr(sb_hw, FM2FRQ2, nCh, 24);	/* 1 Hz */
+		sblive_writeptr(sb_hw, TEMPENV, nCh, 0);
+
+		/*** These are last so OFF prevents writing ***/
+		sblive_writeptr(sb_hw, LFOVAL2, nCh, 0);
+		sblive_writeptr(sb_hw, LFOVAL1, nCh, 0);
+		sblive_writeptr(sb_hw, ATKHLDV, nCh, 0);
+		sblive_writeptr(sb_hw, ENVVOL, nCh, 0);
+		sblive_writeptr(sb_hw, ENVVAL, nCh, 0);
+	}
+
+
+	/*
+	 ** Init to 0x02109204 :
+	 ** Clock accuracy    = 0     (1000ppm)
+	 ** Sample Rate       = 2     (48kHz)
+	 ** Audio Channel     = 1     (Left of 2)
+	 ** Source Number     = 0     (Unspecified)
+	 ** Generation Status = 1     (Original for Cat Code 12)
+	 ** Cat Code          = 12    (Digital Signal Mixer)
+	 ** Mode              = 0     (Mode 0)
+	 ** Emphasis          = 0     (None)
+	 ** CP                = 1     (Copyright unasserted)
+	 ** AN                = 0     (Digital audio)
+	 ** P                 = 0     (Consumer)
+	 */
+
+	sblive_writeptr(sb_hw, SPCS0, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
+			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC|
+			SPCS_GENERATIONSTATUS | 0x00001200 |
+			SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);	/* SPDIF0 */
+
+	sblive_writeptr(sb_hw, SPCS1, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
+			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC|
+			SPCS_GENERATIONSTATUS | 0x00001200 |
+			SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);	/* SPDIF1 */
+
+	sblive_writeptr(sb_hw, SPCS2, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
+			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC|
+			SPCS_GENERATIONSTATUS | 0x00001200 |
+			SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);	/* SPDIF2 & SPDIF3 */
+
+	sblive_fxInit(sb_hw);	/* initialize effects engine */
+
+#ifdef TANKMEM
+	size = TMEMSIZE;
+	sizeIdx = TMEMSIZEREG;
+	while (size > 16384)
+	{
+		status = osAllocMemPhysical(size,&sb_hw->tankmem);
+
+		if(status == CTSTATUS_SUCCESS)
+			break;
+
+		size /= 2;
+		sizeIdx -= 1;
+	}
+
+	if(status != CTSTATUS_SUCCESS){
+		sb_hw->tmemsize = 0;
+		return CTSTATUS_ERROR;
+	}
+
+	sb_hw->tmemsize = size;
+
+#else /* !TANKMEM */
+	sb_hw->tankmem = NULL;
+	sb_hw->tmemsize = 0;
+#endif /* TANKMEM */
+
+	status = osAllocMemPhysical((MAXPAGES - RESERVED) * sizeof(u32),&sb_hw->virtualpagetable);
+
+	if (status != CTSTATUS_SUCCESS)
+	{
+		DPF(2, "Failed to allocate physical memory (1)\n");
+		osFreeMemPhysical(&sb_hw->tankmem);
+		return status;
+	}
+
+	status = osAllocMemPhysical(EMUPAGESIZE, &sb_hw->silentpage);
+
+	if (status != CTSTATUS_SUCCESS)
+	{
+		DPF(2, "Failed to allocate physical memory (2)\n");
+		osFreeMemPhysical(&sb_hw->tankmem);
+		osFreeMemPhysical(&sb_hw->virtualpagetable);
+		return status;
+	} else
+		memset(sb_hw->silentpage->virtaddx, 0, EMUPAGESIZE); /* FIXME: Use bzero() */
+
+	/* Init page table */
+	/* All the entries are inialized to point to themselves */
+	/* so that when illegal memory access occurs, the system */
+	/* won't hang. */
+	for (count = 0; count < (MAXPAGES - RESERVED); count++)
+		((u32 *) sb_hw->virtualpagetable->virtaddx)[count] = (sb_hw->silentpage->physaddx * 2) | count;
+
+	/* Init page table & tank memory base register */
+	/* is this correct? PTB_MASK is 0xfffff000, it may be a 4k alignment... */
+	sblive_writeptr(sb_hw, PTB, 0, sb_hw->virtualpagetable->physaddx);
+#ifdef TANKMEM
+	sblive_writeptr(sb_hw, TCB, 0, sb_hw->tankmem->physaddx);
+#else
+	sblive_writeptr(sb_hw, TCB, 0, 0);
+#endif
+	sblive_writeptr(sb_hw, TCBS, 0, sizeIdx);
+
+	for (nCh = 0; nCh < NUM_G; nCh++)
+	{
+		sblive_writeptr(sb_hw, MAPA, nCh, MAP_PTI_MASK | (sb_hw->silentpage->physaddx * 2));
+		sblive_writeptr(sb_hw, MAPB, nCh, MAP_PTI_MASK | (sb_hw->silentpage->physaddx * 2));
+	}
+
+	/* Hokay, now enable the AUD bit */
+	/* Enable Audio = 1 */
+	/* Mute Disable Audio = 0 */
+	/* Lock Tank Memory = 1 */
+	/* Lock Sound Memory = 0 */
+	/* Auto Mute = 1 */
+
+	sblive_rmwac97(sb_hw, AC97_MASTERVOLUME, 0x8000, 0x8000);
+
+	sblive_writeac97(sb_hw, AC97_MASTERVOLUME, 0);
+	sblive_writeac97(sb_hw, AC97_PCMOUTVOLUME, 0);
+
+	if (sb_hw->dsCardCfg.chiprev < 6)
+		sblive_writefn0(sb_hw, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE);
+	else
+		/* With on-chip joystick */
+		sblive_writefn0(sb_hw, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE | HCFG_JOYENABLE);
+	/* TOSLink detection */
+	sb_hw->has_toslink = 0;
+
+	size = sblive_readfn0(sb_hw, HCFG);
+	if (size & (HCFG_GPINPUT0 | HCFG_GPINPUT1))
+	{
+		volatile unsigned delay;
+		sblive_writefn0(sb_hw, HCFG, size | 0x800);
+
+		for (delay = 0; delay < 512; delay++); 	/* FIXME: Use udelay() */
+
+		if (size != (sblive_readfn0(sb_hw, HCFG) & ~0x800))
+		{
+			sb_hw->has_toslink = 1;
+			sblive_writefn0(sb_hw, HCFG, size);
+		}
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+/* FIXME: This belongs in a headerfile */
+/** Channel status message lengths **/
+u8 gabMsgLenChannel[] =
+{
+	3,			/* 0x80 note off        */
+	3,			/* 0x90 note on         */
+	3,			/* 0xA0 key pressure    */
+	3,			/* 0xB0 control change  */
+	2,			/* 0xC0 program change  */
+	2,			/* 0xD0 channel pressure */
+	3,			/* 0xE0 pitch bend      */
+	1
+};
+
+/** System status message lengths **/
+u8 gabMsgLenSystem[] =
+{
+	1,			/* 0xF0 sysex begin     */
+	2,			/* 0xF1 midi tcqf       */
+	3,			/* 0xF2 song position   */
+	2,			/* 0xF3 song select     */
+	1,			/* 0xF4 undefined       */
+	1,			/* 0xF5 undefined       */
+	1,			/* 0xF6 tune request    */
+	1,			/* 0xF7 sysex eox       */
+
+	1,			/* 0xF8 timing clock    */
+	1,			/* 0xF9 undefined       */
+	1,			/* 0xFA start           */
+	1,			/* 0xFB continue        */
+	1,			/* 0xFC stop            */
+	1,			/* 0xFD undefined       */
+	1,			/* 0xFE active sensing  */
+	1			/* 0xFF system reset    */
+};
+
+
+/****************************************************************************/
+/** Function : srToPitch                                                   **/
+/**                                                                        **/
+/** Input    : sampleRate - sampling rate                                  **/
+/**                                                                        **/
+/** Return   : pitch value                                                 **/
+/**                                                                        **/
+/** About    : convert sampling rate to pitch                              **/
+/**                                                                        **/
+/** Note     : for 8010, sampling rate is at 48kHz, this function should   **/
+/**            be changed.                                                 **/
+/****************************************************************************/
+u32 srToPitch(u32 sampleRate)
+{
+	int i;
+
+	/* FIXME: These tables should be defined in a headerfile */
+	static u32 logMagTable[128] =
+	{
+		0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
+		0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
+		0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
+		0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
+		0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
+		0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
+		0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
+		0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
+		0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
+		0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
+		0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
+		0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
+		0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
+		0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
+		0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
+		0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
+	};
+
+static char logSlopeTable[128] =
+{
+	0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
+	0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
+	0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
+	0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
+	0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
+	0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
+	0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
+	0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
+	0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
+	0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
+	0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
+	0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
+	0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
+	0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
+	0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
+	0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
+};
+
+if (sampleRate == 0)
+	return (0);	/* Bail out if no leading "1" */
+
+sampleRate *= 11185;	/* Scale 48000 to 0x20002380 */
+
+for (i = 31; i > 0; i--)
+{
+	if (sampleRate & 0x80000000)
+	{	/* Detect leading "1" */
+		return (u32) (((s32) (i - 15) << 20) +
+			      logMagTable[0x7f & (sampleRate >> 24)] +
+			      (0x7f & (sampleRate >> 17)) *
+			      logSlopeTable[0x7f & (sampleRate >> 24)]);
+	}
+	sampleRate = sampleRate << 1;
+}
+
+DPF(2, "srToPitch: BUG!\n");
+return 0;		/* Should never reach this point */
+}
+
+
+/****************************************************************************/
+/** Function : sumVolumeToAttenuation                                      **/
+/**                                                                        **/
+/** Input    : inputValue - input volume                                   **/
+/**                                                                        **/
+/** Return   : attenuation value                                           **/
+/**                                                                        **/
+/** About    : convert volume to attenuation                               **/
+/****************************************************************************/
+/* Returns an attenuation based upon a cumulative volume value */
+/* Algorithm calculates 0x200 - 0x10 log2 (input) */
+u8 sumVolumeToAttenuation(u32 value)
+{
+	u16 count = 16;
+	s16 ans;
+
+	if (value == 0)
+		return 0xFF;
+
+	/* Find first SET bit. This is the integer part of the value */
+	while ((value & 0x10000) == 0)
+	{
+		value <<= 1;
+		count--;
+	}
+
+	/* The REST of the data is the fractional part. */
+	ans = (s16) (0x110 - ((count << 4) + ((value & 0x0FFFFL) >> 12)));
+	if (ans > 0xFF)
+		ans = 0xFF;
+
+	return (u8) ans;
+}
+
+/**************************************************************/
+/* write/read PCI function 0 registers                        */
+/**************************************************************/
+void sblive_writefn0(struct sblive_hw *sb_hw, u8 reg, u32 data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+	outl(data, sb_hw->hwaddr + reg);
+	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+	return;
+}
+
+void sblive_wrtmskfn0(struct sblive_hw *sb_hw, u8 reg, u32 mask, u32 data)
+{
+	unsigned long flags;
+
+	data &= mask;
+
+	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+	data |= inl(sb_hw->hwaddr + reg) & ~mask;
+	outl(data, sb_hw->hwaddr + reg);
+	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+	return;
+}
+
+u32 sblive_readfn0(struct sblive_hw *sb_hw, u8 reg)
+{
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+	val = inl(sb_hw->hwaddr + reg);
+	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	return val;
+}
+
+u32 sblive_rdmskfn0(struct sblive_hw *sb_hw, u8 reg, u32 mask)
+{
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+	val = inl(sb_hw->hwaddr + reg);
+	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	return val & mask;
+}
+
+/****************************************************************************/
+/* write/read Emu10k1 pointer-offset register set, accessed through         */
+/*  the PTR and DATA registers                                              */
+/****************************************************************************/
+void sblive_writeptr(struct sblive_hw *sb_hw, u32 reg, u32 channel, u32 data)
+{
+	u32 regptr;
+	unsigned long flags;
+
+	regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
+
+	if (reg & 0xff000000)
+	{
+		u32 mask;
+		u8 size, offset;
+
+		size = (reg >> 24) & 0x3f;
+		offset = (reg >> 16) & 0x1f;
+		mask = ((1 << size) - 1) << offset;
+		data = (data << offset ) & mask;
+
+		spin_lock_irqsave(&sb_hw->emu_lock, flags);
+		outl(regptr, sb_hw->hwaddr + PTR);
+		data |= inl(sb_hw->hwaddr + DATA) & ~mask;
+		outl(data, sb_hw->hwaddr + DATA);
+		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	} else
+	{
+		spin_lock_irqsave(&sb_hw->emu_lock, flags);
+		outl(regptr, sb_hw->hwaddr + PTR);
+		outl(data, sb_hw->hwaddr + DATA);
+		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	}
+
+	return;
+}
+
+u32 sblive_readptr(struct sblive_hw *sb_hw, u32 reg, u32 channel)
+{
+	u32 regptr,val;
+	unsigned long flags;
+
+	regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
+
+	if (reg & 0xff000000)
+	{
+		u32 mask;
+		u8 size, offset;
+
+		size = (reg >> 24) & 0x3f;
+		offset = (reg >> 16) & 0x1f;
+		mask = ((1 << size) - 1) << offset;
+
+		spin_lock_irqsave(&sb_hw->emu_lock, flags);
+		outl(regptr, sb_hw->hwaddr + PTR);
+		val = inl(sb_hw->hwaddr + DATA);
+		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+		return (val & mask) >> offset;
+	} else
+	{
+		spin_lock_irqsave(&sb_hw->emu_lock, flags);
+		outl(regptr, sb_hw->hwaddr + PTR);
+		val = inl(sb_hw->hwaddr + DATA);
+		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+		return val;
+	}
+}
+
+/*****************************************************************************/
+/*  halSetStopOnLoop (struct sblive_hw *sb_hw, u32 voicenum)                 */
+/*****************************************************************************/
+void halSetStopOnLoop(struct sblive_hw *sb_hw, u32 voicenum)
+{
+	/* Voice interrupt */
+	if (voicenum >= 32)
+		sblive_writeptr(sb_hw, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 1);
+	else
+		sblive_writeptr(sb_hw, SOLEL | ((0x0100 | voicenum) << 16), 0, 1);
+
+	return;
+}
+
+/*****************************************************************************/
+/*  halClearStopOnLoop (struct sblive_hw *sb_hw, u32 voicenum )              */
+/*****************************************************************************/
+void halClearStopOnLoop(struct sblive_hw *sb_hw, u32 voicenum)
+{
+	/* Voice interrupt */
+	if (voicenum >= 32)
+		sblive_writeptr(sb_hw, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0);
+	else
+		sblive_writeptr(sb_hw, SOLEL | ((0x0100 | voicenum) << 16), 0, 0);
+
+	return;
+}
+
+/*****************************************************************************/
+/*  halWC_WAIT (struct sblive_hw *sb_hw, u32 wait)                           */
+/*****************************************************************************/
+void halWC_WAIT(struct sblive_hw *sb_hw, u32 wait)
+{
+	volatile unsigned uCount;
+	u32 newtime = 0, curtime;
+
+	curtime = READ_FN0(sb_hw, WC_SAMPLECOUNTER);
+	while (wait--)
+	{
+		uCount = 0;
+		while (uCount++ < TIMEOUT)
+		{
+			newtime = READ_FN0(sb_hw, WC_SAMPLECOUNTER);
+			if (newtime != curtime)
+				break;
+		}
+
+		if (uCount >= TIMEOUT)
+			break;
+
+		curtime = newtime;
+	}
+}
+
+
+/*****************************************************************************/
+/*  sblive_readac97 (struct sblive_hw *sb_hw, u8 index, u16 *pdata)          */
+/*****************************************************************************/
+int sblive_readac97(struct sblive_hw *sb_hw, u8 index, u16 *pdata)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+
+	outb(index, sb_hw->mixeraddx + 2);
+	*pdata = inw(sb_hw->mixeraddx);
+
+	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/*  sblive_writeac97(struct sblive_hw *sb_hw, u8 index, u16 data)            */
+/*****************************************************************************/
+int sblive_writeac97(struct sblive_hw *sb_hw, u8 index, u16 data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+
+	outb(index, sb_hw->mixeraddx + 2);
+	outw(data, sb_hw->mixeraddx);
+
+	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/*  sblive_rmwac97(struct sblive_hw *sb_hw, u8 index, u16 data, u16 mask)    */
+/*****************************************************************************/
+int sblive_rmwac97(struct sblive_hw *sb_hw, u8 index, u16 data, u16 mask)
+{
+	u16 temp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+
+	outb(index, sb_hw->mixeraddx + 2);
+	temp = inw(sb_hw->mixeraddx);
+	temp &= ~mask;
+	data &= mask;
+	temp |= data;
+	outw(temp, sb_hw->mixeraddx);
+
+	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+/****************************************************************/
+/*            MPU access functions                              */
+/****************************************************************/
+
+/*****************************************************************************/
+/* Function Name : hwmpuWriteData                                            */
+/*                                                                           */
+/* Description   : Writing data to MPU with timeout                          */
+/*                                                                           */
+/* Input         : sb_hw | Port object                                       */
+/*                 bData | contain the command                               */
+/*                                                                           */
+/* Return        : int | contain the status of this call                     */
+/*                                                                           */
+/*****************************************************************************/
+int hwmpuWriteData(struct sblive_hw *sb_hw, u8 data)
+{
+	unsigned long flags;
+        int ret;
+
+	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+
+	if ((inb(sb_hw->hwaddr + MUSTAT) & MUSTAT_ORDYN) == 0)
+	{
+		outb(data,  sb_hw->hwaddr + MUDATA);
+                ret = CTSTATUS_SUCCESS;
+	} else
+                ret = CTSTATUS_BUSY;
+
+	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+	return ret;
+}
+
+
+/*****************************************************************************/
+/* Function Name : hwmpuReadData                                             */
+/*                                                                           */
+/* Description  : Reading data from MPU with timeout                         */
+/*                                                                           */
+/* Input         : sb_hw | Port object                                       */
+/*                 bData | contain the command                               */
+/*                                                                           */
+/* Return        : int | contain the status of this call                     */
+/*                                                                           */
+/*****************************************************************************/
+int hwmpuReadData(struct sblive_hw *sb_hw, u8 *data)
+{
+	unsigned long flags;
+        int ret;
+
+	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+
+	if ((inb(sb_hw->hwaddr + MUSTAT) & MUSTAT_IRDYN) == 0)
+	{
+		*data = inb(sb_hw->hwaddr + MUDATA);
+                ret = CTSTATUS_SUCCESS;
+	} else
+		ret = CTSTATUS_NODATA;
+
+	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+	return ret;
+}
+
+
+/*****************************************************************************/
+/* Function Name : hwmpuReset                                                */
+/*                                                                           */
+/* Description  : Hardware reset the MPU                                     */
+/*                                                                           */
+/* Input         : sb_hw | Port object                                       */
+/*                                                                           */
+/* Return        : int | contain the status of this call                     */
+/*                                                                           */
+/*****************************************************************************/
+int hwmpuReset(struct sblive_hw *sb_hw)
+{
+	u8 status;
+	unsigned long flags;
+
+	DPF(2, "hwmpuReset() called\n");
+
+	if (sb_hw->mpuacqcount == 0)
+	{
+		spin_lock_irqsave(&sb_hw->emu_lock, flags);
+		outb(MUCMD_RESET, sb_hw->hwaddr + MUCMD);
+		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+		halWC_WAIT(sb_hw, 8);
+
+		spin_lock_irqsave(&sb_hw->emu_lock, flags);
+		outb(MUCMD_RESET, sb_hw->hwaddr + MUCMD);
+		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+		halWC_WAIT(sb_hw, 8);
+
+		spin_lock_irqsave(&sb_hw->emu_lock, flags);
+		outb(MUCMD_ENTERUARTMODE , sb_hw->hwaddr + MUCMD);
+		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+		halWC_WAIT(sb_hw, 8);
+
+		spin_lock_irqsave(&sb_hw->emu_lock, flags);
+		status = inb(sb_hw->hwaddr + MUDATA);
+		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+		if (status == 0xfe)
+			return CTSTATUS_SUCCESS;
+		else
+			return CTSTATUS_ERROR;
+	}
+
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/* Function Name : hwmpuAcquire                                              */
+/*                                                                           */
+/* Description   : Increase MPU acquire count                                */
+/*                                                                           */
+/* Input         : sb_hw | Port object                                       */
+/*                                                                           */
+/* Return        : int | contain the status of this call                     */
+/*                                                                           */
+/*****************************************************************************/
+int hwmpuAcquire(struct sblive_hw *sb_hw)
+{
+	/* FIXME: This should be a macro */
+	++sb_hw->mpuacqcount;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/* Function Name : hwmpuRelease                                              */
+/*                                                                           */
+/* Description   : Decrease MPU acquire count                                */
+/*                                                                           */
+/* Input         : sb_hw | Port object                                       */
+/*                                                                           */
+/* Return        : int | contain the status of this call                     */
+/*                                                                           */
+/*****************************************************************************/
+int hwmpuRelease(struct sblive_hw *sb_hw)
+{
+	/* FIXME: this should be a macro */
+	--sb_hw->mpuacqcount;
+
+	return CTSTATUS_SUCCESS;
+}
Index: oldkernel/linux/drivers/sound/emu10k1/hwaccess.h
diff -u /dev/null linux/drivers/sound/emu10k1/hwaccess.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/hwaccess.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,336 @@
+/*
+ **********************************************************************
+ *     hwaccess.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date		    Author	    Summary of changes
+ *     ----		    ------	    ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _HWACCESS_H
+#define _HWACCESS_H
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/sound.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <emu_wrapper.h>
+
+typedef int (*CALLBACKFN)(unsigned long,unsigned long ,unsigned long);
+
+enum GlobalErrorCode
+{
+	CTSTATUS_SUCCESS = 0x0000,
+	CTSTATUS_ERROR,
+	CTSTATUS_INVALIDPARAM,
+	CTSTATUS_NOTSUPPORTED,
+	CTSTATUS_NOMEMORY,
+	CTSTATUS_INVALIDIO,
+	CTSTATUS_INVALIDIRQ,
+	CTSTATUS_INVALIDDMA,
+	CTSTATUS_INVALIDID,
+	CTSTATUS_INVALIDVALUE,
+	CTSTATUS_BADFORMAT_BITS,
+	CTSTATUS_BADFORMAT_RATE,
+	CTSTATUS_BADFORMAT_CHANNELS,
+	CTSTATUS_BADFORMAT_STEREO,
+	CTSTATUS_INUSE,
+	CTSTATUS_STILLPLAYING,
+	CTSTATUS_ALLOCATED,
+	CTSTATUS_INVALID_FORMAT,
+	CTSTATUS_OUT_OF_RESOURCE,
+	CTSTATUS_CHIP_INUSE,
+	CTSTATUS_NOCHIPRESOURCE,
+	CTSTATUS_PORTS_INUSE
+};
+
+enum LocalErrorCode
+{
+	CTSTATUS_NOTENABLED = 0x7000,
+	CTSTATUS_READY,
+	CTSTATUS_BUSY,
+	CTSTATUS_DATAAVAIL,
+	CTSTATUS_NODATA,
+	CTSTATUS_NEXT_BYTE
+};
+
+#define FLAGS_ENABLED       0x0001
+#define FLAGS_AVAILABLE     0x0002
+#define FLAGS_READY         0x0004
+#define FLAGS_CLOSEPENDING  0x0008
+
+/* FIXME: Make this stuff go away please */
+#ifndef TRUE
+#define TRUE    1
+#endif
+
+#ifndef FALSE
+#define FALSE   0
+#endif
+
+#ifndef NULL
+#define NULL    0
+#endif
+
+#define _stdcall
+#define __cdecl
+
+#define min(x,y) ((x) < (y)) ? (x) : (y)
+
+#define MM_CREATIVE         2
+#define MAXPNAMELEN         32      /* max product name length (including NULL) */
+#define MAX_CARD_DESC       80
+
+#define MM_CREATIVE_DRIVER_NAME     "SoundBlaster"
+#define MM_CREATIVE_DRIVER_VERSION  0x400
+#define MM_CREATIVE_MIXER_PID       409
+#define MM_CREATIVE_WAVEOUT_PID     104
+#define MM_CREATIVE_WAVEIN_PID      4
+#define MM_CREATIVE_MIDIOUT_PID     302
+#define MM_CREATIVE_MIDIIN_PID      202
+
+struct memhandle
+{
+	unsigned long physaddx;
+	void *virtaddx;
+	u32 order;
+};
+
+struct sblive_list
+{
+	struct sblive_list  *next;
+};
+
+int osAllocMemPhysical(u32, struct memhandle **);
+int osFreeMemPhysical(struct memhandle **);
+int osListAttach(struct sblive_list **head, struct sblive_list *new);
+int osListRemove(struct sblive_list **head, struct sblive_list *pDead);
+struct sblive_list *osListGetNext(struct sblive_list *head, struct sblive_list *curr);
+
+#define MAX_MEMREGISTER     1
+#define MAX_IOPORT          4
+#define MAX_IRQ             2
+#define MAX_DMA             2
+
+struct sblive_config
+{
+	u32 vendorid;			/* Vendor ID			*/
+	u32 serialno;			/* Serial number		*/
+	u32 logdevid;			/* Logical device ID		*/
+	u32 chiprev;			/* Chip revision		*/
+	u16 nummemwindows;			/* Number of memory windows	*/
+	u32 membase[MAX_MEMREGISTER];	/* Memory window base		*/
+	u32 memlength[MAX_MEMREGISTER];	/* Memory window length		*/
+	u16 memattrib[MAX_MEMREGISTER];	/* Memory window attributes	*/
+	u16 numioports;			/* Number of I/O ports		*/
+	u16 ioportbase[MAX_IOPORT];		/* I/O port base		*/
+	u16 ioportlenh[MAX_IOPORT];		/* I/O port length		*/
+	u16 numirq;				/* Number of IRQs		*/
+	u8  IRQregs[MAX_IRQ];		/* IRQ list			*/
+	u8  irqattr[MAX_IRQ];		/* IRQ attributes list		*/
+	u16 numdma;				/* Number of DMA channels	*/
+	u8  dmalst[MAX_DMA];		/* DMA list			*/
+	u16 dmaattr[MAX_DMA];		/* DMA attributes list		*/
+};
+
+#define DEBUG_LEVEL 3
+
+#ifdef EMU10K1_DEBUG
+# define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0);
+# define DPF(level,x)   do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0);
+#else
+# define DPD(level,x,y...) /* not debugging: nothing */
+# define DPF(level,x)
+#endif /* EMU10K1_DEBUG */
+
+
+#include "8010.h"
+
+struct sblive_hw;
+
+#include "voicemgr.h"
+
+struct emuaddr_allocdesc
+{
+	struct sblive_hw *sb_hw;
+	u32     ownertype;
+	CALLBACKFN  callback;
+	unsigned long     callback_data;
+	u32     size;     /* Size in bytes requested */
+	u32     flags;    /* stereo/mono  8/16 */
+};
+
+struct emu_page
+{
+	u16  flags;
+	struct sblive_hw *sb_hw;
+	u32 emustartaddr;
+};
+
+struct emu_addrmgr
+{
+	struct emu_page emupagetable[MAXPAGES];
+};
+
+int emu10kaddxmgrInit(struct sblive_hw *);
+int emu10kaddxmgrExit(struct sblive_hw *);
+int emu10kaddxmgrAlloc(struct emuaddr_allocdesc *,struct emu_page *  *);
+int emu10kaddxmgrFree(struct emu_page *);
+
+#include "timer.h"
+#include "irqmgr.h"
+#include "efxmgr.h"
+
+/* DATA STRUCTURES */
+
+struct sblive_hw
+{
+	struct sblive_hw *next, *prev;
+
+	unsigned long		mixeraddx;
+	unsigned long		hwconfigaddx;
+
+	struct memhandle	*virtualpagetable;
+
+	struct memhandle	*tankmem;
+	u32 tmemsize;
+	struct memhandle	*silentpage;
+
+	spinlock_t		emu_lock;
+
+	struct voice_mgr	voice_manager;
+	struct emu_addrmgr	emu_addrmgr;
+
+	struct emu_timer	*timer;
+	unsigned		timer_delay;
+	spinlock_t		timer_lock;
+
+	struct sblive_irq	hw_irq;
+
+	unsigned long		hwaddr;
+
+	unsigned        numvoices;
+	unsigned        awecount;
+	u32		intrstate;
+
+	unsigned long	joybase;
+	struct pci_dev	*pcidev_joy;
+	unsigned long	audio_num;
+	unsigned long	mixer_num;
+	unsigned long	midi_num;
+	unsigned long	stat_num;
+	struct sblive_waveout	*card_waveout;
+	struct sblive_wavein	*card_wavein;
+	struct sblive_mpuout	*card_mpuout;
+	struct sblive_mpuin	*card_mpuin;
+	u16			arrwVol[25]; /* Size is hardcoded.  Bad! */
+	unsigned int		modcnt;
+	struct semaphore	open_sem;
+	mode_t			open_mode;
+	wait_queue_head_t	open_wait;
+
+	u8	    paneffectsbus;
+	u8	    auxeffectsbus;
+	u8	    choruseffectsbus;
+	u8	    reverbeffectsbus;
+
+	u32	    powerstate; 	  // Current Power State
+	u32	    mpuacqcount;	  // Mpu acquire count
+	struct sblive_config	dsCardCfg;
+	u32	    has_toslink;	       // TOSLink detection
+};
+
+#define ENABLE 			0xffffffff
+#define DISABLE 		0x00000000
+
+#define ENV_ON			0x80
+#define ENV_OFF			0x00
+
+/* EMU Irq Types */
+#define IRQTYPE_PCIBUSERROR	    IPR_PCIERROR
+#define IRQTYPE_MIXERBUTTON	    (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
+#define IRQTYPE_VOICE		    (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
+#define IRQTYPE_RECORD		    (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
+#define IRQTYPE_MPUOUT		    IPR_MIDITRANSBUFEMPTY
+#define IRQTYPE_MPUIN		    IPR_MIDIRECVBUFEMPTY
+#define IRQTYPE_TIMER		    IPR_INTERVALTIMER
+#define IRQTYPE_SPDIF		    (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
+#define IRQTYPE_DSP		    IPR_FXDSP
+
+#define TIMEOUT 		    16384
+
+u32 srToPitch(u32);
+u8 sumVolumeToAttenuation(u32);
+
+int halInit(struct sblive_hw *, struct sblive_config *, u32 *);
+int halExit(struct sblive_hw *);
+
+extern u8 gabMsgLenChannel[];
+extern u8 gabMsgLenSystem[];
+extern spinlock_t sblive_spinlock;
+
+/* Hardware Abstraction Layer access functions */
+
+#define WRITE_FN0(a,b,c) sblive_wrtmskfn0((a),(u8)(b), ((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f), (c) << (((b) >> 16) & 0x1f))
+
+#define READ_FN0(a,b) sblive_rdmskfn0((a),(u8)(b),((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f)) >> (((b) >> 16) & 0x1f)
+
+#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c))
+
+void sblive_writefn0(struct sblive_hw *, u8 , u32 );
+void sblive_wrtmskfn0(struct sblive_hw *, u8 , u32 , u32 );
+
+u32 sblive_readfn0(struct sblive_hw *, u8 );
+u32 sblive_rdmskfn0(struct sblive_hw *, u8, u32 );
+
+void sblive_writeptr(struct sblive_hw *, u32 , u32 , u32 );
+u32 sblive_readptr(struct sblive_hw *, u32 , u32 );
+
+void halSetStopOnLoop(struct sblive_hw *, u32);
+void halClearStopOnLoop(struct sblive_hw *, u32);
+void halWC_WAIT(struct sblive_hw *, u32);
+
+/* AC97 Mixer access function */
+int sblive_readac97(struct sblive_hw *, u8, u16 *);
+int sblive_writeac97(struct sblive_hw *, u8, u16);
+int sblive_rmwac97(struct sblive_hw *, u8, u16, u16);
+
+/* MPU access function*/
+int hwmpuWriteData(struct sblive_hw *, u8);
+int hwmpuReadData(struct sblive_hw *, u8 *);
+int hwmpuReset(struct sblive_hw *);
+int hwmpuAcquire(struct sblive_hw *);
+int hwmpuRelease(struct sblive_hw *);
+
+#endif  /* _HWACCESS_H */
Index: oldkernel/linux/drivers/sound/emu10k1/icardmid.h
diff -u /dev/null linux/drivers/sound/emu10k1/icardmid.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/icardmid.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,199 @@
+/*
+ **********************************************************************
+ *     isblive_mid.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _ICARDMIDI_H
+#define _ICARDMIDI_H
+
+/* MIDI defines */
+#define MIDI_DATA_FIRST                 0x00
+#define MIDI_DATA_LAST                  0x7F
+#define MIDI_STATUS_FIRST               0x80
+#define MIDI_STATUS_LAST                0xFF
+
+/* Channel status bytes */
+#define MIDI_STATUS_CHANNEL_FIRST       0x80
+#define MIDI_STATUS_CHANNEL_LAST        0xE0
+#define MIDI_STATUS_CHANNEL_MASK        0xF0
+
+/* Channel voice messages */
+#define MIDI_VOICE_NOTE_OFF             0x80
+#define MIDI_VOICE_NOTE_ON              0x90
+#define MIDI_VOICE_POLY_PRESSURE        0xA0
+#define MIDI_VOICE_CONTROL_CHANGE       0xB0
+#define MIDI_VOICE_PROGRAM_CHANGE       0xC0
+#define MIDI_VOICE_CHANNEL_PRESSURE     0xD0
+#define MIDI_VOICE_PITCH_BEND           0xE0
+
+/* Channel mode messages */
+#define MIDI_MODE_CHANNEL               MIDI_VOICE_CONTROL_CHANGE
+
+/* System status bytes */
+#define MIDI_STATUS_SYSTEM_FIRST        0xF0
+#define MIDI_STATUS_SYSTEM_LAST         0xFF
+
+/* System exclusive messages */
+#define MIDI_SYSEX_BEGIN                0xF0
+#define MIDI_SYSEX_EOX                  0xF7
+
+/* System common messages */
+#define MIDI_COMMON_TCQF                0xF1	/* Time code quarter frame  */
+#define MIDI_COMMON_SONG_POSITION       0xF2
+#define MIDI_COMMON_SONG_SELECT         0xF3
+#define MIDI_COMMON_UNDEFINED_F4        0xF4
+#define MIDI_COMMON_UNDEFINED_F5        0xF5
+#define MIDI_COMMON_TUNE_REQUEST        0xF6
+
+/* System real-time messages */
+#define MIDI_RTIME_TIMING_CLOCK         0xF8
+#define MIDI_RTIME_UNDEFINED_F9         0xF9
+#define MIDI_RTIME_START                0xFA
+#define MIDI_RTIME_CONTINUE             0xFB
+#define MIDI_RTIME_STOP                 0xFC
+#define MIDI_RTIME_UNDEFINED_FD         0xFD
+#define MIDI_RTIME_ACTIVE_SENSING       0xFE
+#define MIDI_RTIME_SYSTEM_RESET         0xFF
+
+/* Flags for flags parm of midiOutCachePatches(), midiOutCacheDrumPatches() */
+#define MIDI_CACHE_ALL                  1
+#define MIDI_CACHE_BESTFIT              2
+#define MIDI_CACHE_QUERY                3
+#define MIDI_UNCACHE                    4
+
+/* Event declarations for MPU IRQ Callbacks */
+#define ICARDMIDI_INLONGDATA            0x00000001 /* MIM_LONGDATA */
+#define ICARDMIDI_INLONGERROR           0x00000002 /* MIM_LONGERROR */
+#define ICARDMIDI_OUTLONGDATA           0x00000004 /* MOM_DONE for MPU OUT buffer */
+#define ICARDMIDI_INDATA                0x00000010 /* MIM_DATA */
+#define ICARDMIDI_INDATAERROR           0x00000020 /* MIM_ERROR */
+
+/* Declaration for flags in CARDMIDIBUFFERHDR */
+/* Make it the same as MHDR_DONE, MHDR_INQUEUE in mmsystem.h */
+#define MIDIBUF_DONE                    0x00000001
+#define MIDIBUF_INQUEUE                 0x00000004
+
+/* Declaration for msg parameter in midiCallbackFn */
+#define ICARDMIDI_OUTBUFFEROK           0x00000001
+#define ICARDMIDI_INMIDIOK              0x00000002
+
+#define MIDICAPS_INPUT                  0x00001000
+#define MIDICAPS_OUTPUT                 0x00002000
+#define MIDICAPS_SOUNDFONT              0x00004000
+
+/* Declaration for technology in struct midi_caps */
+#define MT_MIDIPORT                     0x00000001	/* In original MIDIOUTCAPS structure */
+#define MT_FMSYNTH                      0x00000004	/* In original MIDIOUTCAPS structure */
+#define MT_AWESYNTH                     0x00001000
+#define MT_PCISYNTH                     0x00002000
+#define MT_PCISYNTH64                   0x00004000
+#define CARDMIDI_AWEMASK                0x0000F000
+
+/* Flags for wTechnology field of MIDIOUTCAPS structure */
+#define MOD_MIDIPORT                    1	/* Output port */
+#define MOD_SYNTH                       2	/* Generic internal synth */
+#define MOD_SQSYNTH                     3	/* Square wave internal synth */
+#define MOD_FMSYNTH                     4	/* FM internal synth */
+#define MOD_MAPPER                      5	/* MIDI mapper */
+
+/* Bit definitions for caps for struct midi_caps */
+#define CARDMIDI_OUT                    0x00000001
+#define CARDMIDI_IN                     0x00000002
+
+/* Definitions for product in struct midi_caps */
+#define MM_CREATIVE_MIDIOUT             201
+#define MM_CREATIVE_MIDIIN              202
+#define MM_CREATIVE_FMSYNTH_STEREO      302
+#define MM_CREATIVE_MIDI_AWE32          303
+#define MM_CREATIVE_MIDI_EMU8008        305
+#define MM_CREATIVE_MIDI_EMU10K1        306
+
+/* MIDI data block header */
+struct midi_hdr
+{
+	u8 *reserved;		/* Pointer to original locked data block */
+	u32 bufferlength;	/* Length of data in data block */
+	u32 bytesrecorded;	/* Used for input only */
+	u32 user;		/* For client's use */
+	u32 flags;		/* Assorted flags (see defines) */
+	struct midi_hdr  *next;	/* Reserved for driver */
+	u8 *lpData;		/* Second copy of first pointer */
+};
+
+struct midi_caps
+{
+	u32 cbsize;
+	u32 support;
+	u32 technology;
+	u32 product;
+	u32 manufacturer;
+	u32 voices;
+	u32 notes;
+	u32 channelmask;
+	u8 MIDIname[MAXPNAMELEN];
+	u32 caps;
+};
+
+struct midi_cache
+{
+	u32 cbsize;
+	u32 action;
+	u32 bank;
+	u16 array[128];
+};
+
+/* Enumeration for SetControl */
+enum
+{
+	MIDIOBJVOLUME = 0x1,
+	MIDIQUERYACTIVEINST
+};
+
+
+struct midi_queue
+{
+	struct midi_queue  *next;
+	u32 qtype;            /* 0 = short message, 1 = long data */
+	u32 length;
+	u32 sizeLeft;
+	u8 *midibyte;
+	unsigned long refdata;
+};
+
+struct midi_openinfo
+{
+	u32     cbsize;
+	u32     flags;
+	unsigned long  refdata;
+	u32     streamid;
+};
+
+int midiCallbackFn(unsigned long , unsigned long, unsigned long *);
+
+#endif /* _ICARDMIDI_H */
Index: oldkernel/linux/drivers/sound/emu10k1/icardwav.h
diff -u /dev/null linux/drivers/sound/emu10k1/icardwav.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/icardwav.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,96 @@
+/*     
+ **********************************************************************
+ *     icardwav.h
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#ifndef _ICARDWAV_H
+#define _ICARDWAV_H
+
+#define MAX_CARDWAVE_DESC   80
+
+struct wave_caps 
+{
+	u32 product_id;
+	u32 caps;
+	u32 controls;
+	u32 maxchannels;
+	u32 minrate, maxrate;
+	char wavedesc[MAX_CARDWAVE_DESC];
+};
+
+#define CARDWAVE_OUT                0x0001
+#define CARDWAVE_IN                 0x0002
+#define CARDWAVE_ALLOW_DIRECTXFER   0x0004
+#define CARDWAVE_CONTINUOUS_RATE    0x0008
+#define CARDWAVE_ALLOW_3D           0x0010
+
+#define CARDWAVE_CONTROL_VOLUME     0x0001
+#define CARDWAVE_CONTROL_MUTE       0x0002
+#define CARDWAVE_CONTROL_PAN        0x0004
+#define CARDWAVE_CONTROL_RATE       0x0008
+#define CARDWAVE_CONTROL_XFERPOS    0x1000
+#define CARDWAVE_CONTROL_LOOPING    0x2000
+
+#define CARDWAVE_PLAY_LOOPING       0x00000001
+
+struct wave_format 
+{
+	u32 samplingrate;
+	u32 bitspersample;
+	u32 channels;		/* 1 = Mono, 2 = Stereo */
+	int isinput;
+	u32 flags;
+};
+
+#define CARDWAVE_FORMAT_NORMAL              0x0000
+#define CARDWAVE_FORMAT_NOCONVERT_RATE      0x0001
+#define CARDWAVE_FORMAT_NOCONVERT_BITS      0x0002
+#define CARDWAVE_FORMAT_NOCONVERT_CHANNEL   0x0004
+#define CARDWAVE_FORMAT_NOCONVERT_ALL       (CARDWAVE_FORMAT_NOCONVERT_RATE | CARDWAVE_FORMAT_NOCONVERT_BITS | CARDWAVE_FORMAT_CHANNEL )
+#define CARDWAVE_FORMAT_DIRECTSOUND         0x2000
+#define CARDWAVE_FORMAT_DUP_BUFFER          0x4000
+#define CARDWAVE_FORMAT_DO_DIRECTXFER       0x8000
+#define CARDWAVE_FORMAT_3D_BUFFER           0x0100
+#define CARDWAVE_FORMAT_SOFTSYNTH           0x0200
+#define CARDWAVE_FORMAT_PRIMARY_BUFFER      0x0400
+
+/* Flags for QueryFormat */
+#define CARDWAVE_QF_RATE        0x00000001
+#define CARDWAVE_QF_BITS        0x00000002
+#define CARDWAVE_QF_CHANNEL     0x00000004
+#define CARDWAVE_QF_STEREO	0x00000008
+#define CARDWAVE_QF_ALL         (CARDWAVE_QF_RATE | CARDWAVE_QF_BITS | CARDWAVE_QF_CHANNEL | CARDWAVE_QF_STEREO)
+#define CARDWAVE_QF_DIRECTXFER  0x40000000
+#define CARDWAVE_QF_PHYSICAL    0x80000000
+
+/* Buffer type */
+#define CARDWAVE_DMA_BUFFER     0x0001
+#define CARDWAVE_LINEAR_BUFFER  0x0002
+
+#endif /* _ICARDWAV_H */
Index: oldkernel/linux/drivers/sound/emu10k1/irqmgr.c
diff -u /dev/null linux/drivers/sound/emu10k1/irqmgr.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/irqmgr.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,238 @@
+/*
+ **********************************************************************
+ *     irqmgr.c - IRQ manager for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "cardmi.h"
+#include "cardmo.h"
+#include "irqmgr.h"
+
+/* Interrupt handler */
+static void emu10k1_interrupt(int nIRQ, void *pvDevID, struct pt_regs *pRegs)
+{
+	struct sblive_irq *irq_ptr = (struct sblive_irq *) pvDevID;
+	struct sblive_hw *sb_hw = irq_ptr->sb_hw;
+	u32 irqstatus, ptr, tmp;
+
+	if (sb_hw->hw_irq.ID != EMU10K1_INTERRUPT_ID)
+		return;
+
+	DPD(4, "emu10k1_interrupt called, nIRQ =  %u\n", nIRQ);
+
+	/* Preserve PTR register */
+	ptr = sblive_readfn0(sb_hw, PTR);
+
+	/*
+	 ** NOTE :
+	 ** We do a 'while loop' here cos on certain machines, with both
+	 ** playback and recording going on at the same time, IRQs will
+	 ** stop coming in after a while. Checking IPND indeed shows that
+	 ** there are interrupts pending but the PIC says no IRQs pending.
+	 ** I suspect that some boards need edge-triggered IRQs but are not
+	 ** getting that condition if we don't completely clear the IPND
+	 ** (make sure no more interrupts are pending).
+	 ** - Eric
+	 */
+
+	irqstatus = sblive_readfn0(sb_hw, IPR);
+
+	do
+	{
+		DPD(4, "irq status %x\n", irqstatus);
+
+		tmp = irqstatus;
+
+		if (irqstatus & IRQTYPE_TIMER)
+		{
+			sblive_timerIrqCallback(sb_hw);
+			irqstatus &= ~IRQTYPE_TIMER;
+		}
+
+		if (irqstatus & IRQTYPE_RECORD)
+		{
+			sblive_waveinIrqCallback(sb_hw);
+			irqstatus &= ~IRQTYPE_RECORD;
+		}
+
+		if (irqstatus & IRQTYPE_MPUIN)
+		{
+			sblive_mpuinIrqCallback(sb_hw);
+			irqstatus &= ~IRQTYPE_MPUIN;
+		}
+
+		if (irqstatus & IRQTYPE_MPUOUT)
+		{
+			sblive_mpuoutIrqCallback(sb_hw);
+			irqstatus &= ~IRQTYPE_MPUOUT;
+		}
+
+		if(irqstatus)
+			sblive_irqmgrDisableIrq(sb_hw, irqstatus);
+
+		sblive_writefn0(sb_hw, IPR, tmp);
+
+	} while ((irqstatus = sblive_readfn0(sb_hw, IPR)));
+
+	sblive_writefn0(sb_hw, PTR, ptr);
+
+	return;
+}
+
+/************************************************************************
+ *
+ *   int    sblive_irqmgrInit(struct sblive_hw * sb_hw)
+ *
+ *   ENTRY
+ *       sb_hw -   Card object
+ *
+ *   RETURNS
+ *       SUCCESS -   CTSTATUS_SUCCESS
+ *       FAILURE -   CTSTATUS_ERROR
+ *
+ *   ABOUT
+ *       Initialization
+ *
+ ************************************************************************/
+int sblive_irqmgrInit(struct sblive_irq *irq_ptr)
+{
+	unsigned long flags;
+
+	irq_ptr->status = 0;
+	irq_ptr->ID = EMU10K1_INTERRUPT_ID;
+
+	flags = SA_SHIRQ;
+
+	/* Reserve IRQ Line */
+	if (request_irq(irq_ptr->irq, emu10k1_interrupt, flags, "emu10k1", irq_ptr))
+	{
+		DPD(2, "emu10k1: irq %u in use\n", (unsigned int) irq_ptr->irq);
+		irq_ptr->status &= ~FLAGS_ENABLED;
+		DPF(2, "Error initializing IRQ\n");
+		return CTSTATUS_ERROR;
+	}
+
+	irq_ptr->status |= (FLAGS_ENABLED | FLAGS_AVAILABLE);
+
+	if (irq_ptr->status & (FLAGS_ENABLED | FLAGS_AVAILABLE))
+		irq_ptr->status &= (~FLAGS_AVAILABLE);
+	else
+	{
+		DPF(2, "IRQ acquire failure\n");
+		return CTSTATUS_INUSE;
+	}
+
+	DPD(2, "IRQ : Acquired channel %u\n", irq_ptr->irq);
+	return CTSTATUS_SUCCESS;
+}
+
+
+/************************************************************************
+ *
+ *   int    sblive_irqmgrExit(struct sblive_irq *irq_ptr)
+ *
+ *   ENTRY
+ *       irq_ptr -   Card irq object
+ *
+ *   RETURNS
+ *       Always returns CTSTATUS_SUCCESS
+ *
+ *   ABOUT
+ *       Shutdown code
+ *
+ ************************************************************************/
+int sblive_irqmgrExit(struct sblive_irq *irq_ptr)
+{
+	irq_ptr->status |= FLAGS_AVAILABLE;
+	free_irq(irq_ptr->irq, irq_ptr);
+	irq_ptr->status &= ~FLAGS_ENABLED;
+
+	return CTSTATUS_SUCCESS;
+}
+
+/************************************************************************
+ *
+ *   int    sblive_irqmgrEnableIrq(struct sblive_hw * sb_hw, u16 wIrqType)
+ *
+ *   ENTRY
+ *       sb_hw -   Card object
+ *       wIrqType-   type of service to enable interrupt for
+ *
+ *   RETURNS
+ *       Always returns CTSTATUS_SUCCESS
+ *
+ *   ABOUT
+ *       Enables the specified irq service
+ *
+ ************************************************************************/
+int sblive_irqmgrEnableIrq(struct sblive_hw *sb_hw, u32 irqtype)
+{
+	/*
+	 * TODO :
+	 * put protection here so that we don't accidentally
+	 * screw-up another cardxxx objects irqs
+	 */
+
+	DPD(4, "sblive_irqmgrEnableIrq %x\n", irqtype);
+	sblive_wrtmskfn0(sb_hw, INTE, irqtype, ENABLE);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/************************************************************************
+ *
+ *   int    sblive_irqmgrDisableIrq(struct sblive_hw * sb_hw, u16 wIrqType)
+ *
+ *   ENTRY
+ *       sb_hw -   Card object
+ *       wIrqType-   type of service to disable interrupt for
+ *
+ *   RETURNS
+ *       Always returns CTSTATUS_SUCCESS
+ *
+ *   ABOUT
+ *       Disables the specified irq service
+ *
+ ************************************************************************/
+
+int sblive_irqmgrDisableIrq(struct sblive_hw *sb_hw, u32 irqtype)
+{
+	/*
+	 * TODO :
+	 * put protection here so that we don't accidentally
+	 * screw-up another cardxxx objects irqs
+	 */
+
+	DPD(4, "sblive_irqmgrDisableIrq %x\n", irqtype);
+	sblive_wrtmskfn0(sb_hw, INTE, irqtype, DISABLE);
+
+	return CTSTATUS_SUCCESS;
+}
+
Index: oldkernel/linux/drivers/sound/emu10k1/irqmgr.h
diff -u /dev/null linux/drivers/sound/emu10k1/irqmgr.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/irqmgr.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,61 @@
+/*
+ **********************************************************************
+ *     irq.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _IRQ_H
+#define _IRQ_H
+
+struct sblive_irq
+{
+	u32     	ID;
+	u32		status;
+	u32 		irq;
+	struct sblive_hw *sb_hw;
+};
+
+struct sblive_wavedevice
+{
+        struct sblive_hw *sb_hw;
+        struct wiinst *wiinst;
+        struct woinst *woinst;
+        u16 enablebits;
+};
+
+int sblive_timerIrqCallback(struct sblive_hw *);
+int sblive_waveinIrqCallback(struct sblive_hw *);
+
+int sblive_irqmgrInit(struct sblive_irq *);
+int sblive_irqmgrExit(struct sblive_irq *);
+int sblive_irqmgrEnableIrq(struct sblive_hw *, u32);
+int sblive_irqmgrDisableIrq(struct sblive_hw *, u32);
+
+#define EMU10K1_INTERRUPT_ID 0xfeebbeef
+
+#endif /* _IRQ_H */
Index: oldkernel/linux/drivers/sound/emu10k1/main.c
diff -u /dev/null linux/drivers/sound/emu10k1/main.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/main.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,369 @@
+/*
+ **********************************************************************
+ *     main.c - Creative EMU10K1 audio driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox        cleaned up stuff
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ *
+ *      Supported devices:
+ *      /dev/dsp:     Standard /dev/dsp device, OSS-compatible
+ *      /dev/mixer:   Standard /dev/mixer device, OSS-compatible
+ *      /dev/sndstat: Standard /dev/sndstat device, mostly OSS-compatible
+ *      /dev/midi:    Raw MIDI UART device, mostly OSS-compatible
+ *
+ *      Revision history:
+ *      0.1 beta Initial release
+ *      0.2 Lowered initial mixer vol. Improved on stuttering wave playback. Added MIDI UART support.
+ *      0.3 Fixed mixer routing bug, added APS, joystick support.
+ *      0.4 Added rear-channel, SPDIF support.
+ *
+ **********************************************************************
+ */
+
+
+/* These are only included once per module */
+#ifdef MODULE
+#include <linux/module.h>
+#else
+
+#endif
+
+#include "hwaccess.h"
+#include "mycommon.h"
+#include "cardwo.h"
+#include "audio.h"
+#include "midi.h"
+#include "sndstat.h"
+
+#ifndef PCI_VENDOR_ID_CREATIVE
+#define PCI_VENDOR_ID_CREATIVE 0x1102
+#endif
+
+#ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1
+#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
+#endif
+
+#define EMU10K1_EXTENT	0x20	/* 32 byte I/O space */
+#define JOY_EXTENT	0x8	/* 8 byte I/O space */
+#define MAX_EMU10K1	5
+
+/* Global var instantiation */
+
+struct sblive_hw *sblive_devs = NULL;
+static unsigned long joystick[MAX_EMU10K1 + 1] =
+{0,};
+
+/* Function prototypes */
+extern int sblive_mixer_init(struct sblive_hw *sb_hw);
+
+/* Driver initialization routine */
+#ifdef MODULE
+int init_module(void)
+#else
+	int __init init_emu10k1(void)
+#endif
+{
+	struct sblive_hw *hw_obj;
+	u32 hwflags = 0;
+	unsigned int index = 0, serial = 0;
+	unsigned long ioaddr;
+	unsigned char bus, devfn, ucRevID = 0;
+	struct sblive_config dsConfig;
+	struct sblive_config *config = &dsConfig;
+	struct pci_dev *pcidev=NULL, *pcidev_joy=NULL;
+	unsigned long irq;
+	unsigned long ioaddr1 = 0;
+
+	DPF(2, "init_module() called\n");
+
+	/* Do not export symbols */
+#ifdef MODULE
+	EXPORT_NO_SYMBOLS;
+#endif /* MODULE */
+
+	if (!pci_present())
+		return -ENODEV;
+
+	/* PCI BIOS detected */
+	for (index = 0; index < MAX_EMU10K1 &&
+	     (pcidev = pci_find_device(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1, pcidev));
+	     index++)
+	{
+		bus = pcidev->bus->number;
+		devfn = pcidev->devfn;
+		DPD(2, "Function 0: devfn %x\n", devfn);
+		/* Joystick is on the same bus and dev, but is function #1 */
+		if ((pcidev_joy=pci_find_slot(bus, devfn + 1))) {
+			DPD(2, "Function 1 exists: devfn %x\n", devfn + 1);
+		}
+		/* Device found - Query PCI BIOS info */
+		DPD(1, "Emu10k1 device %d found!\n", index);
+
+		ioaddr = RSRCADDRESS(pcidev, 0);
+		if (pcidev_joy)
+			ioaddr1 = RSRCADDRESS(pcidev_joy, 0);
+
+		if (!RSRCISIOREGION(pcidev, 0) || !RSRCISIOREGION(pcidev_joy, 0))
+			continue;
+
+		ioaddr = ioaddr & PCI_BASE_ADDRESS_IO_MASK;
+		DPD(1, "Function 0 IO Base Address = %#lx\n", ioaddr);
+
+		if (pcidev_joy)
+		{
+			ioaddr1 = ioaddr1 & PCI_BASE_ADDRESS_IO_MASK;
+			DPD(1, "Function 1 IO Base Address = %#lx\n", ioaddr1);
+		}
+
+		irq = pcidev->irq;
+
+		/*
+		 *	Some BIOSes screw this stuff up. Its worth reporting
+		 *	to the user
+		 */
+
+		if (irq == 0)
+		{
+			printk(KERN_ERR "sblive: No IRQ has been assigned to this device. Check your BIOS settings.\n");
+			continue;
+		}
+
+		DPD(1, "IRQ Line = %lu\n", irq);
+
+		pci_read_config_byte(pcidev, PCI_REVISION_ID, &ucRevID);
+		DPD(1, "Revision ID = %u\n", ucRevID);
+
+		pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &serial);
+		DPD(1, "Serial No = %08x\n", serial);
+
+		/* Initialize device struct */
+		hw_obj = kmalloc(sizeof(*hw_obj), GFP_KERNEL);
+		if (!hw_obj)
+		{
+			printk(KERN_WARNING "emu10k1: out of memory\n");
+			continue;
+		}
+		DPD(3, "kmalloc: [%p]\n", hw_obj);
+		memset(hw_obj, 0, sizeof(*hw_obj)); /* FIXME: use bzero()? */
+
+		hw_obj->pcidev_joy = pcidev_joy;
+		hw_obj->joybase = ioaddr1;
+		printk(KERN_INFO "Creative SBLive! at %#lx on irq %lu\n", ioaddr, irq);
+
+		DPD(3, "kmalloc: [%p]\n", config);
+		memset(config, 0, sizeof(*config)); /* FIXME: use bzero()? */
+
+		config->vendorid = PCI_VENDOR_ID_CREATIVE;
+		config->serialno = serial;
+		config->logdevid = PCI_DEVICE_ID_CREATIVE_EMU10K1;
+		config->chiprev = ucRevID;
+
+		config->nummemwindows = 0;
+
+		config->numioports = 1;
+		config->ioportbase[0] = ioaddr;
+		config->ioportlenh[0] = EMU10K1_EXTENT;
+
+		config->numirq = 1;
+		config->IRQregs[0] = irq;
+		config->irqattr[0] = 0;	/* Doesn't matter */
+
+		config->numdma = 0;
+
+		/* Reserve I/O region */
+		if (check_region(ioaddr, EMU10K1_EXTENT))
+		{
+			printk(KERN_ERR "emu10k1: io ports %#lx-%#lx in use\n",
+			       ioaddr, ioaddr + EMU10K1_EXTENT - 1);
+			goto err_region1;
+		}
+		request_region(ioaddr, EMU10K1_EXTENT, "emu10k1");
+
+		if (check_region(ioaddr1, JOY_EXTENT))
+		{
+			printk(KERN_ERR "emu10k1: io ports %#x-%#x in use\n",
+			       (unsigned int) ioaddr1, (unsigned int) ioaddr1 + JOY_EXTENT - 1);
+			goto err_region2;
+		}
+		request_region(ioaddr1, JOY_EXTENT, "emu10k1 joystick");
+
+		/* Register devices */
+		hw_obj->audio_num = register_sound_dsp(&emu10k1_audio_fops, -1);
+		if (hw_obj->audio_num < 0)
+		{
+			printk(KERN_ERR "emu10k1: cannot register audio device!\n");
+			goto err_dev1;
+		}
+
+		hw_obj->mixer_num = register_sound_mixer(&emu10k1_mixer_fops, -1);
+		if (hw_obj->mixer_num < 0)
+		{
+			printk(KERN_ERR "emu10k1: cannot register mixer device!\n");
+			goto err_dev2;
+		}
+
+		hw_obj->midi_num = register_sound_midi(&emu10k1_midi_fops, -1);
+		if (hw_obj->midi_num < 0)
+		{
+			printk(KERN_ERR "emu10k1: cannot register MIDI device!\n");
+			goto err_dev4;
+		}
+
+		if (pcidev_joy)
+		{
+			if ((joystick[index] & ~0x18) == 0x200)
+			{
+				if (check_region(joystick[index], JOY_EXTENT))
+					printk(KERN_ERR "emu10k1: joystick io ports %lx-%lx in use\n",
+					       joystick[index], joystick[index] + JOY_EXTENT - 1);
+				else {
+					/* Write joystick base address to PCI configuration space */
+					pci_write_config_dword(pcidev_joy, PCI_BASE_ADDRESS_0, joystick[index]);
+#ifdef EMU10K1_DEBUG
+					{
+						u32 base;
+						pci_read_config_dword(pcidev_joy, PCI_BASE_ADDRESS_0, &base);
+						DPD(2, " read back joystick base address is %x\n", base);
+					}
+#endif
+				}
+			}
+		}
+
+		/* Register-level initialization goes here.... */
+		DPF(2, "Initializing hardware....\n");
+		/* IRQ reservation happens in halInit */
+		if (halInit(hw_obj, config, &hwflags) != CTSTATUS_SUCCESS) {
+			printk(KERN_ERR "emu10k1: cannot initialize device!\n");
+			goto err_hal_init;
+		}
+		init_MUTEX(&hw_obj->open_sem);
+		hw_obj->open_mode = 0;
+		init_waitqueue_head(&hw_obj->open_wait);
+
+		DPD(2, "Hardware initialized. TRAM allocated: %u bytes\n", (unsigned int) hw_obj->tmemsize);
+
+
+		audio_init(hw_obj, "SBLive!");
+		sblive_mixer_init(hw_obj);
+
+		midi_init(hw_obj);
+
+		/* AOK, update global device list */
+		hw_obj->next = sblive_devs;
+		sblive_devs = hw_obj;
+
+		hw_obj->prev = NULL;
+		if (hw_obj->next)
+			hw_obj->next->prev = hw_obj;
+		continue;
+
+		/* Error handlers */
+		/* FIXME: These must reflect the device init order... */
+	err_hal_init:
+		halExit(hw_obj);	/* Should this be called? */
+
+		unregister_sound_midi(hw_obj->midi_num);
+	err_dev4:
+		unregister_sound_mixer(hw_obj->mixer_num);
+	err_dev2:
+		unregister_sound_dsp(hw_obj->audio_num);
+	err_dev1:
+		/* free_irq(hw_obj->irq, hw_obj); */
+		/*  err_irq: */
+		release_region(ioaddr1, JOY_EXTENT);
+	err_region2:
+		release_region(ioaddr, EMU10K1_EXTENT);
+	err_region1:
+		kfree(hw_obj);
+		DPD(3, "kfree: [%p]\n", hw_obj);
+	}
+
+	if (!sblive_devs)
+		return -ENODEV;
+
+	sblive_devs->stat_num = register_sound_special(&emu10k1_sndstat_fops, 6);
+	if (sblive_devs->stat_num < 0)
+		printk(KERN_ERR "emu10k1: cannot register sndstat device!\n");
+	else
+		sndstat_init();
+
+	DPF(2, "Module successfully initialized!\n");
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_PARM(joystick, "1-" __MODULE_STRING(MAX_EMU10K1) "i");
+MODULE_PARM_DESC(joystick, "sets address and enables joystick interface (still need separate driver)");
+MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: linux_bug@soundblaster.com)");
+MODULE_DESCRIPTION("Creative EMU10K1 Driver v0.4\nCopyright (C) 1999 Creative Technology Ltd.");
+
+/* Driver exit routine */
+void cleanup_module(void)
+{
+	struct sblive_hw *hw_obj;
+
+	DPF(2, "cleanup_module() called\n");
+
+	if (sblive_devs && sblive_devs->stat_num >= 0)
+		unregister_sound_special(6);
+
+	while ((hw_obj = sblive_devs))
+	{
+		sblive_devs = sblive_devs->next;
+
+		/* write original joystick base address to PCI configuration space */
+		pci_write_config_dword(hw_obj->pcidev_joy, PCI_BASE_ADDRESS_0, hw_obj->joybase);
+#ifdef EMU10K1_DEBUG
+		{
+			u32 base;
+			pci_read_config_dword(hw_obj->pcidev_joy, PCI_BASE_ADDRESS_0, &base);
+			DPD(2, "cleanup_module: read back joystick base address is %x\n", base);
+		}
+#endif
+
+		audio_exit(hw_obj);
+		midi_exit(hw_obj);
+
+		/* IRQ is freed in halExit */
+		halExit(hw_obj);
+		DPF(2, "halExit completed\n");
+
+		release_region(hw_obj->hwaddr, EMU10K1_EXTENT);
+		release_region(hw_obj->joybase, JOY_EXTENT);
+		unregister_sound_dsp(hw_obj->audio_num);
+		unregister_sound_mixer(hw_obj->mixer_num);
+		unregister_sound_midi(hw_obj->midi_num);
+		kfree(hw_obj);
+		DPD(3, "kfree: [%p]\n", hw_obj);
+	}
+
+	DPF(2, "Module unloaded\n");
+}
+
+#endif				// MODULE
Index: oldkernel/linux/drivers/sound/emu10k1/midi.c
diff -u /dev/null linux/drivers/sound/emu10k1/midi.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/midi.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,589 @@
+/*
+ **********************************************************************
+ *     midi.c - /dev/midi interface for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifdef MODULE
+#define __NO_VERSION__
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include "hwaccess.h"
+#include "mycommon.h"
+#include "cardmo.h"
+#include "cardmi.h"
+#include "midi.h"
+
+
+static spinlock_t midi_spinlock = SPIN_LOCK_UNLOCKED;
+
+static int emu10k1_midi_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct sblive_hw *sb_hw = sblive_devs;
+	struct sblive_mididevice *midi_dev;
+
+	DPF(2, "emu10k1_midi_open() called\n");
+
+	/* Check for correct device to open */
+	while (sb_hw && sb_hw->midi_num != minor)
+	  sb_hw = sb_hw->next;
+	if (!sb_hw)
+	  return -ENODEV;
+
+	/* Wait for device to become free */
+	down(&sb_hw->open_sem);
+	while (sb_hw->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) 
+	{
+		if (file->f_flags & O_NONBLOCK) 
+		{
+			up(&sb_hw->open_sem);
+			return -EBUSY;
+		}
+		
+		up(&sb_hw->open_sem);
+		interruptible_sleep_on(&sb_hw->open_wait);
+		
+		if (signal_pending(current))
+		  return -ERESTARTSYS;
+		
+		down(&sb_hw->open_sem);
+	}
+
+	midi_dev = (struct sblive_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL);
+	if (midi_dev == NULL) 
+	{
+		DPF(2, " MIDIDEVICEOBJ alloc fail.");
+		return -EINVAL;
+	}
+	
+	DPD(3, "kmalloc: [%p]\n", midi_dev);
+	
+	midi_dev->sb_hw = sb_hw;
+	midi_dev->mistate = MIDIIN_STATE_STOPPED;
+	init_waitqueue_head(&midi_dev->oWait);
+	init_waitqueue_head(&midi_dev->iWait);
+	midi_dev->ird = 0;
+	midi_dev->iwr = 0;
+	midi_dev->icnt = 0;
+	midi_dev->pmiHdrList = NULL;
+
+	if (file->f_mode & FMODE_READ) 
+	{
+		struct midi_openinfo dsCardMidiOpenInfo;
+		struct midi_hdr *midihdr1;
+		struct midi_hdr *midihdr2;
+
+		dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
+
+		if (sblive_mpuinOpen(sb_hw, &dsCardMidiOpenInfo) 
+		    != CTSTATUS_SUCCESS) 
+		{
+			DPF(2, "sblive_mpuinOpen failed.\n");
+
+			kfree(midi_dev);
+			DPD(3, "kfree: [%p]\n", midi_dev);			
+
+			return -ENODEV;
+		}
+
+		/* Add two buffers to receive sysex buffer */
+		if (midiInAddBuffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) 
+		{
+			kfree(midi_dev);
+			DPD(3, "kfree: [%p]\n", midi_dev);
+
+			return -ENODEV;
+		}
+
+		if (midiInAddBuffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) 
+		{
+			osListRemove((struct sblive_list **) &midi_dev->pmiHdrList, (struct sblive_list *) midihdr1);
+
+			kfree(midihdr1->lpData);
+			DPD(3, "kfree: [%p]\n", midihdr1->lpData);
+
+			kfree(midihdr1);
+			kfree(midi_dev);
+
+			DPD(3, "kfree: [%p]\n", midihdr1);
+			DPD(3, "kfree: [%p]\n", midi_dev);
+
+			return -ENODEV;
+		}
+	}
+
+	if (file->f_mode & FMODE_WRITE) 
+	{
+		struct midi_openinfo dsCardMidiOpenInfo;
+
+		dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
+
+		if (sblive_mpuoutOpen(sb_hw, &dsCardMidiOpenInfo)
+		    != CTSTATUS_SUCCESS) 
+		{
+			DPF(2, "sblive_mpuoutOpen failed.\n");
+
+			kfree(midi_dev);
+			DPD(3, "kfree: [%p]\n", midi_dev);
+
+			return -ENODEV;
+		}
+	}
+
+	file->private_data = (void *) midi_dev;
+
+	sb_hw->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
+
+	up(&sb_hw->open_sem);
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int emu10k1_midi_release(struct inode *inode, struct file *file)
+{
+	struct sblive_mididevice *midi_dev = (struct sblive_mididevice *) file->private_data;
+	struct sblive_hw *sb_hw = midi_dev->sb_hw;
+
+	DPF(2, "emu10k1_midi_release() called\n");
+	
+	if (file->f_mode & FMODE_WRITE) 
+	{
+		if(!(file->f_flags & O_NONBLOCK)){
+
+			while (!signal_pending(current) && (sb_hw->card_mpuout->firstmidiq !=NULL)){
+				DPF(2, "Cannot close - buffers not empty\n");
+
+				interruptible_sleep_on(&midi_dev->oWait);		
+
+			}
+		}
+
+		sblive_mpuoutClose(sb_hw);
+	}
+	
+	if (file->f_mode & FMODE_READ) 
+	{
+		struct midi_hdr *midihdr;
+
+		if (midi_dev->mistate == MIDIIN_STATE_STARTED) 
+		{
+			sblive_mpuinStop(sb_hw);
+			midi_dev->mistate = MIDIIN_STATE_STOPPED;
+			DPF(2, "MIDI in stopped\n");
+		}
+		
+		sblive_mpuinReset(sb_hw);
+		sblive_mpuinClose(sb_hw);
+		
+		DPF(2, "MIDI in closed\n");
+		
+		while ((midihdr = (struct midi_hdr *) osListGetNext((struct sblive_list *) midi_dev->pmiHdrList, NULL))) 
+		{
+			osListRemove((struct sblive_list **) &midi_dev-> pmiHdrList, (struct sblive_list *) midihdr);
+
+			kfree(midihdr->lpData);
+			DPD(3, "kfree: [%p]\n", midihdr->lpData);
+
+			kfree(midihdr);
+			DPD(3, "kfree: [%p]\n", midihdr);
+		}
+	}
+	
+	kfree(midi_dev);
+
+	DPD(3, "kfree: [%p]\n", midi_dev);
+
+	down(&sb_hw->open_sem);
+	sb_hw->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE));
+	up(&sb_hw->open_sem);
+	wake_up(&sb_hw->open_wait);
+	
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+
+static ssize_t emu10k1_midi_read(struct file *file, char *buffer, size_t count, loff_t *pos)
+{
+	struct sblive_mididevice *midi_dev = (struct sblive_mididevice *) file->private_data;
+	ssize_t ret = 0;
+	u16 cnt;
+	unsigned long flags;
+
+	DPD(2, "emu10k1_midi_read() called, count %d\n", count);
+
+	if (pos != &file->f_pos)
+	  return -ESPIPE;
+
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+	  return -EFAULT;
+
+	if (midi_dev->mistate == MIDIIN_STATE_STOPPED) 
+	{
+		if (sblive_mpuinStart(midi_dev->sb_hw) 
+		    != CTSTATUS_SUCCESS) 
+		{
+			DPF(2, "sblive_mpuinStart failed.\n");
+			return -EINVAL;
+		}
+		
+		midi_dev->mistate = MIDIIN_STATE_STARTED;
+	}
+
+	while (count > 0) 
+	{
+		cnt = MIDIIN_BUFLEN - midi_dev->ird;
+	
+		spin_lock_irqsave(&midi_spinlock, flags);
+	
+		if (midi_dev->icnt < cnt)
+		  cnt = midi_dev->icnt;
+		
+		spin_unlock_irqrestore(&midi_spinlock, flags);
+		
+		if (cnt > count)
+		  cnt = count;
+		
+		if (cnt <= 0) 
+		{
+			if (file->f_flags & O_NONBLOCK)
+			  return ret ? ret : -EAGAIN;
+			DPF(2, " Go to sleep...\n");
+			
+			interruptible_sleep_on(&midi_dev->iWait);
+			
+			if (signal_pending(current))
+				return ret ? ret : -ERESTARTSYS;
+			
+			continue;
+		}
+		
+		if (copy_to_user(buffer, midi_dev->iBuf + midi_dev->ird, cnt)) {
+			DPF(2, " copy_to_user failed.");
+			return ret ? ret : -EFAULT;
+		}
+		
+		midi_dev->ird += cnt;
+		midi_dev->ird %= MIDIIN_BUFLEN;
+
+		spin_lock_irqsave(&midi_spinlock, flags);
+
+		midi_dev->icnt -= cnt;
+		
+		spin_unlock_irqrestore(&midi_spinlock, flags);
+		
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		if (midi_dev->icnt == 0)
+			break;
+
+	}
+	
+	return ret;
+}
+
+
+static ssize_t emu10k1_midi_write(struct file *file, const char *buffer, size_t count, loff_t *pos)
+{
+	struct sblive_mididevice *midi_dev = (struct sblive_mididevice *) file->private_data;
+	struct midi_hdr *midihdr;
+	ssize_t ret = 0;
+	unsigned long flags;
+
+	DPD(2, "emu10k1_midi_write() called, count=%d\n", count);
+
+	if (pos != &file->f_pos)
+	  return -ESPIPE;
+
+	if (!access_ok(VERIFY_READ, buffer, count))
+	  return -EFAULT;
+
+	midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL);
+	if (midihdr == NULL) 
+		return -EINVAL;
+
+	DPD(3, "kmalloc: [%p]\n", midihdr);
+	
+	midihdr->bufferlength = count;
+	midihdr->bytesrecorded = 0;
+	midihdr->flags = 0;
+	midihdr->next = NULL;
+	
+	midihdr->lpData = (u8 *) kmalloc(count, GFP_KERNEL);
+	if (midihdr->lpData == NULL) 
+	{
+		DPF(2, "midihdr->lpData alloc failed\n");
+
+		kfree(midihdr);
+		DPD(3, "kfree: [%p]\n", midihdr);
+	
+		return -EINVAL;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", midihdr->lpData);
+	
+	if (copy_from_user(midihdr->lpData, buffer, count)) 
+	{
+		kfree(midihdr->lpData);
+		DPD(3, "kfree: [%p]\n", midihdr->lpData);
+
+		kfree(midihdr);
+		DPD(3, "kfree: [%p]\n", midihdr);
+		
+		return ret ? ret : -EFAULT;
+	}
+
+	spin_lock_irqsave(&midi_spinlock, flags);
+
+	if (sblive_mpuoutAddBuffer(midi_dev->sb_hw, midihdr) != CTSTATUS_SUCCESS) 
+	{
+		DPF(2, "sblive_mpuoutAddBuffer failed.\n");
+
+		kfree(midihdr->lpData);
+		DPD(3, "kfree: [%p]\n", midihdr->lpData);
+
+		kfree(midihdr);
+		DPD(3, "kfree: [%p]\n", midihdr);
+	
+		spin_unlock_irqrestore(&midi_spinlock, flags);
+		return -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&midi_spinlock, flags);
+
+	return count;
+}
+
+
+static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait)
+{
+	DPF(2, "emu10k1_midi_poll() called\n");
+	return 0;
+}
+
+
+int midiCallbackFn(unsigned long msg, unsigned long refdata, unsigned long *pmsg)
+{
+	struct sblive_mididevice *midi_dev = (struct sblive_mididevice *) refdata;
+	struct midi_hdr *midihdr = NULL;
+	unsigned long flags;
+	int i;
+
+	DPF(2, "midiCallbackFn!\n");
+	
+	spin_lock_irqsave(&midi_spinlock, flags);
+
+	switch (msg) 
+	{
+	case ICARDMIDI_OUTLONGDATA:
+		midihdr = (struct midi_hdr *) pmsg[2];
+
+		kfree(midihdr->lpData);
+		DPD(3, "kfree: [%p]\n", midihdr->lpData);
+
+		kfree(midihdr);
+		DPD(3, "kfree: [%p]\n", midihdr);
+
+		wake_up(&midi_dev->oWait);
+
+		break;
+
+	case ICARDMIDI_INLONGDATA:
+		DPF(2, " ICARDMIDI_INLONGDATA\n");
+		midihdr = (struct midi_hdr *) pmsg[2];
+
+		for (i = 0; i < midihdr->bytesrecorded; i++) {
+			midi_dev->iBuf[midi_dev->iwr++] = midihdr->lpData[i];
+			midi_dev->iwr %= MIDIIN_BUFLEN;
+		}
+
+		midi_dev->icnt += midihdr->bytesrecorded;
+		
+		if (midi_dev->mistate == MIDIIN_STATE_STARTED) 
+		{
+			initMidiHdr(midihdr);
+			sblive_mpuinAddBuffer(midi_dev->sb_hw->card_mpuin, midihdr);
+			wake_up(&midi_dev->iWait);
+		}
+		break;
+
+	case ICARDMIDI_INDATA:
+		DPF(2, " ICARDMIDI_INDATA\n");
+		{
+			u8 *pBuf = (u8 *) & pmsg[1];
+			u16 bytesvalid = pmsg[2];
+
+			for (i = 0; i < bytesvalid; i++) {
+				midi_dev->iBuf[midi_dev->iwr++] = pBuf[i];
+				midi_dev->iwr %= MIDIIN_BUFLEN;
+			}
+
+			midi_dev->icnt += bytesvalid;
+		}
+		
+		wake_up(&midi_dev->iWait);
+		break;
+
+	default:		/* Unknown message */
+		DPF(2, "Unknown message\n");
+		return CTSTATUS_ERROR;
+	}
+
+	spin_unlock_irqrestore(&midi_spinlock, flags);
+	
+	return CTSTATUS_SUCCESS;
+}
+
+
+/* Local functions */
+int midiInAddBuffer(struct sblive_mididevice *midi_dev, struct midi_hdr **midihdrptr)
+{
+	struct midi_hdr *midihdr;
+
+	midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL);
+	if (midihdr == NULL)
+	  return -EINVAL;
+
+	DPD(3, "kmalloc: [%p]\n", midihdr);
+	
+	initMidiHdr(midihdr);
+	
+	midihdr->lpData = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL);	
+	if (midihdr->lpData == NULL) 
+	{
+		DPF(2, "midihdr->lpData alloc fail.\n");
+
+		kfree(midihdr);
+		DPD(3, "kfree: [%p]\n", midihdr);
+
+		return CTSTATUS_ERROR;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", midihdr->lpData);
+	
+	if (sblive_mpuinAddBuffer(midi_dev->sb_hw->card_mpuin, midihdr) != CTSTATUS_SUCCESS) 
+	{
+		DPF(2, "sblive_mpuinAddBuffer failed.\n");
+
+		kfree(midihdr->lpData);
+		DPD(3, "kfree: [%p]\n", midihdr->lpData);
+
+		kfree(midihdr);
+		DPD(3, "kfree: [%p]\n", midihdr);
+
+		return CTSTATUS_ERROR;
+	}
+	
+	*midihdrptr = midihdr;
+	osListAttach((struct sblive_list **) &midi_dev->pmiHdrList, (struct sblive_list *) midihdr);
+
+	return CTSTATUS_SUCCESS;
+}
+
+void initMidiHdr(struct midi_hdr * midihdr)
+{
+	midihdr->bufferlength = MIDIIN_BUFLEN;
+	midihdr->bytesrecorded = 0;
+	midihdr->flags = 0;
+	midihdr->next = NULL;
+}
+
+/* End of local functions */
+
+
+int midi_init(struct sblive_hw *sb_hw)
+{
+	/* Initialize CardMpuOut struct */
+	sb_hw->card_mpuout = kmalloc(sizeof(struct sblive_mpuout), GFP_KERNEL);
+	if (sb_hw->card_mpuout == NULL) 
+	{
+		printk(KERN_WARNING "alloc struct sblive_mpuout: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
+	
+	DPD(3, "kmalloc: [%p]\n", sb_hw->card_mpuout);
+	
+	sblive_mpuoutInit(sb_hw->card_mpuout, sb_hw);
+
+	/* Initialize CardMpuIn struct */
+	sb_hw->card_mpuin = kmalloc(sizeof(struct sblive_mpuin), GFP_KERNEL);
+	if (sb_hw->card_mpuin == NULL) 
+	{
+		printk(KERN_WARNING "alloc struct sblive_mpuin: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
+	
+	DPD(3, "kmalloc: [%p]\n", sb_hw->card_mpuin);
+	
+	sblive_mpuinInit(sb_hw->card_mpuin, sb_hw);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int midi_exit(struct sblive_hw *sb_hw)
+{
+	sblive_mpuoutExit(sb_hw);
+	sblive_mpuinExit(sb_hw);
+	kfree(sb_hw->card_mpuout);
+	kfree(sb_hw->card_mpuin);
+	
+	DPD(3, "kfree: [%p]\n", sb_hw->card_mpuout);
+	DPD(3, "kfree: [%p]\n", sb_hw->card_mpuin);
+	
+	sb_hw->card_mpuout = NULL;
+	sb_hw->card_mpuin = NULL;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/* MIDI file operations */
+struct file_operations emu10k1_midi_fops = 
+{
+	NULL,
+	&emu10k1_midi_read,
+	&emu10k1_midi_write,
+	NULL,			/* readdir */
+	&emu10k1_midi_poll,
+	NULL,			/* ioctl */
+	NULL,			/* mmap */
+	&emu10k1_midi_open,
+	NULL,			/* flush */
+	&emu10k1_midi_release,
+	NULL,			/* fsync */
+	NULL,			/* fasync */
+};
Index: oldkernel/linux/drivers/sound/emu10k1/midi.h
diff -u /dev/null linux/drivers/sound/emu10k1/midi.h:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/midi.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,60 @@
+/*     
+ **********************************************************************
+ *     midi.h
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */ 
+
+#ifndef _MIDI_H
+#define _MIDI_H
+
+#define FMODE_MIDI_SHIFT 3
+#define FMODE_MIDI_READ  (FMODE_READ << FMODE_MIDI_SHIFT)
+#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
+
+#define MIDIIN_STATE_STARTED 0x00000001
+#define MIDIIN_STATE_STOPPED 0x00000002
+
+#define MIDIIN_BUFLEN 1024
+
+struct sblive_mididevice
+{
+	struct sblive_hw *sb_hw;
+	u32 mistate;
+	wait_queue_head_t oWait;
+	wait_queue_head_t iWait;
+	s8 iBuf[MIDIIN_BUFLEN];
+	u16 ird, iwr, icnt;
+	struct midi_hdr *pmiHdrList;
+};
+
+int midi_init(struct sblive_hw *);
+int midi_exit(struct sblive_hw *);
+int midiInAddBuffer(struct sblive_mididevice *, struct midi_hdr **);
+void initMidiHdr(struct midi_hdr *);
+
+#endif /* _MIDI_H */
Index: oldkernel/linux/drivers/sound/emu10k1/mixer.c
diff -u /dev/null linux/drivers/sound/emu10k1/mixer.c:1.1
--- /dev/null	Mon Jul 31 21:13:55 2000
+++ linux/drivers/sound/emu10k1/mixer.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,663 @@
+/*
+ **********************************************************************
+ *     mixer.c - /dev/mixer interface for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ *     This program uses some code from es1317.c, Copyright 1998-1999
+ *     Thomas Sailer
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox        cleaned up stuff
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifdef MODULE
+#define __NO_VERSION__		/* Kernel version only defined once */
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include "hwaccess.h"
+#include "mycommon.h"
+
+#define AC97_PESSIMISTIC
+#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+
+#define vol_to_hw_5(swvol) (31 - (((swvol) * 31) / 100))
+#define vol_to_hw_4(swvol) (15 - (((swvol) * 15) / 100))
+
+#define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31)
+#define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15)
+
+/* --------------------------------------------------------------------- */
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#ifdef hweight32
+#undef hweight32
+#endif
+
+extern __inline__ unsigned int hweight32(unsigned int w)
+{
+	unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+	res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+	res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+	return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+
+/* Mapping arrays */
+static const unsigned int recsrc[] =
+{
+	SOUND_MASK_MIC,
+	SOUND_MASK_CD,
+	SOUND_MASK_VIDEO,
+	SOUND_MASK_LINE1,
+	SOUND_MASK_LINE,
+	SOUND_MASK_VOLUME,
+	SOUND_MASK_OGAIN,	/* Used to be PHONEOUT */
+	SOUND_MASK_PHONEIN,
+	SOUND_MASK_TREBLE,
+	SOUND_MASK_BASS
+};
+
+static const unsigned char volreg[SOUND_MIXER_NRDEVICES] =
+{
+	/* 5 bit stereo */
+	[SOUND_MIXER_LINE] = AC97_LINEINVOLUME,
+	[SOUND_MIXER_CD] = AC97_CDVOLUME,
+	[SOUND_MIXER_VIDEO] = AC97_VIDEOVOLUME,
+	[SOUND_MIXER_LINE1] = AC97_AUXVOLUME,
+	[SOUND_MIXER_PCM] = AC97_PCMOUTVOLUME,
+	/* 5 bit stereo, setting 6th bit equal to maximum attenuation */
+	[SOUND_MIXER_VOLUME] = AC97_MASTERVOLUME,
+	[SOUND_MIXER_PHONEOUT] = AC97_HEADPHONEVOLUME,
+	/* 5 bit mono, setting 6th bit equal to maximum attenuation */
+	[SOUND_MIXER_OGAIN] = AC97_MASTERVOLUMEMONO,
+	/* 5 bit mono */
+	[SOUND_MIXER_PHONEIN] = AC97_PHONEVOLUME,
+	/* 4 bit mono but shifted by 1 */
+	[SOUND_MIXER_SPEAKER] = AC97_PCBEEPVOLUME,
+	/* 5 bit mono, 7th bit = preamp */
+	[SOUND_MIXER_MIC] = AC97_MICVOLUME,
+	/* 4 bit stereo */
+	[SOUND_MIXER_RECLEV] = AC97_RECORDGAIN,
+	/* 4 bit mono */
+	[SOUND_MIXER_IGAIN] = AC97_RECORDGAINMIC,
+	/* test code */
+	[SOUND_MIXER_BASS] = AC97_GENERALPUPOSE,
+	[SOUND_MIXER_TREBLE] = AC97_MASTERTONE
+};
+
+/* FIXME: OSS_DOCUMENTED_MIXER_SEMANTICS is #undefed.
+ * This needs to be explored more and cleaned up [jtaylor] */
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+
+#define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00))
+
+/* FIXME: mixer_rdch() is broken. */
+
+static int mixer_rdch(struct sblive_hw * sb_hw, unsigned int ch, int *arg)
+{
+	u16 reg;
+	int j;
+	int nL, nR;
+
+	switch (ch) {
+	case SOUND_MIXER_LINE:
+	case SOUND_MIXER_CD:
+	case SOUND_MIXER_VIDEO:
+	case SOUND_MIXER_LINE1:
+	case SOUND_MIXER_PCM:
+	case SOUND_MIXER_VOLUME:
+		sblive_readac97(sb_hw, volreg[ch], &reg);
+		nL = ((~(reg >> 8) & 0x1f) * 100) / 32;
+		nR = (~(reg & 0x1f) * 100) / 32;
+		DPD(2, "mixer_rdch: l=%d, r=%d\n", nL, nR);
+		return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg);
+
+	case SOUND_MIXER_OGAIN:
+	case SOUND_MIXER_PHONEIN:
+		sblive_readac97(sb_hw, volreg[ch], &reg);
+		return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101, (int *) arg);
+
+	case SOUND_MIXER_SPEAKER:
+		sblive_readac97(sb_hw, volreg[ch], &reg);
+		return put_user(reg & 0x8000 ? 0 : ~((reg >> 1) & 0xf) * 0x64 / 0x10 * 0x101, (int *) arg);
+
+	case SOUND_MIXER_MIC:
+		sblive_readac97(sb_hw, volreg[ch], &reg);
+		return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101 + ((reg & 0x40) ? 0x1e1e : 0), (int *) arg);
+
+	case SOUND_MIXER_RECLEV:
+		sblive_readac97(sb_hw, volreg[ch], &reg);
+		nL = ((~(reg >> 8) & 0x1f) * 100) / 16;
+		nR = (~(reg & 0x1f) * 100) / 16;
+		return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg);
+
+	case SOUND_MIXER_TREBLE:
+	case SOUND_MIXER_BASS:
+		return put_user(0x0000, (int *) arg);
+	default:
+		return -EINVAL;
+	}
+}
+
+#endif				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
+
+static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
+{
+	/* 5 bit stereo */
+	[SOUND_MIXER_LINE] = 1,
+	[SOUND_MIXER_CD] = 2,
+	[SOUND_MIXER_VIDEO] = 3,
+	[SOUND_MIXER_LINE1] = 4,
+	[SOUND_MIXER_PCM] = 5,
+	/* 6 bit stereo */
+	[SOUND_MIXER_VOLUME] = 6,
+	[SOUND_MIXER_PHONEOUT] = 7,
+	/* 6 bit mono */
+	[SOUND_MIXER_OGAIN] = 8,
+	[SOUND_MIXER_PHONEIN] = 9,
+	/* 4 bit mono but shifted by 1 */
+	[SOUND_MIXER_SPEAKER] = 10,
+	/* 6 bit mono + preamp */
+	[SOUND_MIXER_MIC] = 11,
+	/* 4 bit stereo */
+	[SOUND_MIXER_RECLEV] = 12,
+	/* 4 bit mono */
+	[SOUND_MIXER_IGAIN] = 13,
+	[SOUND_MIXER_TREBLE] = 14,
+	[SOUND_MIXER_BASS] = 15,
+	[SOUND_MIXER_DIGITAL1] = 17,
+	[SOUND_MIXER_DIGITAL2] = 18,
+	[SOUND_MIXER_LINE2] = 19
+};
+
+static void update_rearfront(struct sblive_hw *sb_hw)
+{
+	int i, l1, l2, l3, r1, r2, r3;
+	u16 reg, wval;
+
+	reg = sb_hw->arrwVol[volidx[SOUND_MIXER_PCM] - 1];
+	l1 = (reg & 0xff);
+	r1 = (reg >> 8) & 0xff;
+
+	reg = sb_hw->arrwVol[volidx[SOUND_MIXER_LINE2] - 1];
+	l2 = (reg & 0xff);
+	r2 = (reg >> 8) & 0xff;
+
+	reg = sb_hw->arrwVol[volidx[SOUND_MIXER_VOLUME] - 1];
+	l3 = (reg & 0xff);
+	r3 = (reg >> 8) & 0xff;
+
+	i = (r1 * r2) / 50;
+	if (r2 > 50)
+		r2 = 2 * r1 - i;
+	else {
+		r2 = r1;
+		r1 = i;
+	}
+
+	i = (l1 * l2) / 50;
+	if (l2 > 50)
+		l2 = 2 * l1 - i;
+	else {
+		l2 = l1;
+		l1 = i;
+	}
+
+	sblive_writeptr(sb_hw, FXGPREGBASE + 0x10, 0, l2 * l3 * (0x7fffffff / 10000));
+	sblive_writeptr(sb_hw, FXGPREGBASE + 0x11, 0, r2 * r3 * (0x7fffffff / 10000));
+	wval = ((((100 - l1) * 32 + 50) / 100) << 8) | (((100 - r1) * 32 + 50) / 100);
+	if (wval == 0x2020)
+		wval = 0x8000;
+	else
+		wval -= ((wval & 0x2020) / 0x20);
+	sblive_writeac97(sb_hw, volreg[SOUND_MIXER_PCM], wval);
+}
+
+static int mixer_wrch(struct sblive_hw * sb_hw, unsigned int ch, int val)
+{
+	int i;
+	unsigned l1, r1;
+	u16 wval;
+
+	l1 = val & 0xff;
+	r1 = (val >> 8) & 0xff;
+	if (l1 > 100)
+		l1 = 100;
+	if (r1 > 100)
+		r1 = 100;
+
+	DPD(2, "mixer_wrch() called: ch=%u, l1=%u, r1=%u\n", ch, l1, r1);
+
+	if (!volidx[ch]) return -EINVAL;
+	sb_hw->arrwVol[volidx[ch] - 1] = (r1 << 8) | l1;
+
+	switch (ch)
+	{
+	case SOUND_MIXER_LINE2:
+		DPF(2, "SOUND_MIXER_LINE2:\n");
+		update_rearfront(sb_hw);
+		return 0;
+	case SOUND_MIXER_DIGITAL2:
+		DPF(2, "SOUND_MIXER_DIGITAL2:\n");
+		sblive_writeptr(sb_hw, FXGPREGBASE + 0x14, 0, l1 * (0x7fffffff / 100));
+		sblive_writeptr(sb_hw, FXGPREGBASE + 0x15, 0, r1 * (0x7fffffff / 100));
+		return 0;
+	case SOUND_MIXER_DIGITAL1:
+		DPF(2, "SOUND_MIXER_DIGITAL1:\n");
+		sblive_writeptr(sb_hw, FXGPREGBASE + 0x12, 0, l1 * (0x7fffffff / 100));
+		sblive_writeptr(sb_hw, FXGPREGBASE + 0x13, 0, r1 * (0x7fffffff / 100));
+		return 0;
+	case SOUND_MIXER_PCM:
+		DPF(2, "SOUND_MIXER_PCM:\n");
+		update_rearfront(sb_hw);
+		return 0;
+	case SOUND_MIXER_LINE1:
+		DPF(2, "SOUND_MIXER_LINE1:\n");
+	case SOUND_MIXER_LINE:
+		DPF(2, "SOUND_MIXER_LINE:\n");
+	case SOUND_MIXER_CD:
+		DPF(2, "SOUND_MIXER_CD:\n");
+	case SOUND_MIXER_VOLUME:
+		DPF(2, "SOUND_MIXER_VOLUME:\n");
+		wval = ((((100 - l1) * 32 + 50) / 100) << 8) | (((100 - r1) * 32 + 50) / 100);
+		if (wval == 0x2020)
+			wval = 0x8000;
+		else
+			wval -= ((wval & 0x2020) / 0x20);
+		sblive_writeac97(sb_hw, volreg[ch], wval);
+		if (ch == SOUND_MIXER_VOLUME) update_rearfront(sb_hw);
+		return 0;
+
+	case SOUND_MIXER_OGAIN:
+		DPF(2, "SOUND_MIXER_OGAIN:\n");
+	case SOUND_MIXER_PHONEIN:
+		DPF(2, "SOUND_MIXER_PHONEIN:\n");
+		sblive_writeac97(sb_hw, volreg[ch], (l1 < 2) ? 0x8000 : ((100 - l1) * 32 + 50) / 100);
+		return 0;
+
+	case SOUND_MIXER_SPEAKER:
+		DPF(2, "SOUND_MIXER_SPEAKER:\n");
+		sblive_writeac97(sb_hw, volreg[ch], (l1 < 4) ? 0x8000 : (((100 - l1) * 16 + 50) / 100) << 1);
+		return 0;
+
+	case SOUND_MIXER_MIC:
+		DPF(2, "SOUND_MIXER_MIC:\n");
+		i = 0;
+		if (l1 >= 30)
+			// 20dB / (34.5dB + 12dB + 20dB) * 100 = 30
+		{
+			l1 -= 30;
+			i = 0x40;
+		}
+		sblive_writeac97(sb_hw, volreg[ch], (l1 < 2) ? 0x8000 : ((((70 - l1) * 0x20 + 35) / 70) | i));
+		return 0;
+
+	case SOUND_MIXER_RECLEV:
+		DPF(2, "SOUND_MIXER_RECLEV:\n");
+		wval = (((l1 * 16 + 50) / 100) << 8) | ((r1 * 16 + 50) / 100);
+		if (wval == 0)
+			wval = 0x8000;
+		else {
+			if (wval & 0xff) wval--;
+			if (wval & 0xff00) wval -= 0x0100;
+		}
+		sblive_writeac97(sb_hw, volreg[ch], wval);
+		return 0;
+
+	case SOUND_MIXER_TREBLE:
+		DPF(2, "SOUND_MIXER_TREBLE:\n");
+
+		{
+			//u8 atnL = sumVolumeToAttenuation(100 - l1);
+			//u8 atnR = sumVolumeToAttenuation(100 - r1);
+			u8 atnL = (100 - l1) * 0xa0 / 100;
+			u8 atnR = (100 - r1) * 0xa0 / 100;
+			int i = 0;
+
+			DPD(2, "atnL = 0x%08x, atnR = 0x%08x\n", atnL, atnR);
+
+			while (i < 64)
+			{
+				sblive_writeptr(sb_hw, IFATN_ATTENUATION, i++, atnL);
+				sblive_writeptr(sb_hw, IFATN_ATTENUATION, i++, atnR);
+			}
+			return 0;
+		}
+
+	case SOUND_MIXER_BASS:
+		DPF(2, "SOUND_MIXER_BASS:\n");
+
+		{
+			static int idxB = 0;
+			u8 peL = (l1 * 255 / 100 - 128) & 0xff;
+			u8 peR = (r1 * 255 / 100 - 128) & 0xff;
+			int i = 0; /* Usually first channel */
+
+			idxB += 1;
+			idxB &= 0xf;
+			DPD(2, "using 0x%08x\n", idxB);
+
+			/* for (i = 9; i <= 9; i++) { */
+			/* sblive_writeptr(sb_hw, CVCF_CURRENTFILTER, i, idx); */
+			/* sblive_writeptr(sb_hw, CVCF_CURRENTVOL, i, idx); */
+
+			/* this is pure hack - its for 4 channels */
+			/* FIXME: This is very odd, most of this code will
+			 * never be executed. */
+			while (i < 64)
+			{
+				if (1)
+				{
+					sblive_writeptr(sb_hw, PEFE_FILTERAMOUNT, i++, peL);
+					sblive_writeptr(sb_hw, PEFE_FILTERAMOUNT, i++, peR);
+				} else if (0)
+				{
+					sblive_writeptr(sb_hw, PEFE_PITCHAMOUNT, i++, peL);
+					sblive_writeptr(sb_hw, PEFE_FILTERAMOUNT, i++, peR);
+				} else if (0)
+				{
+					sblive_writeptr(sb_hw, IFATN_FILTERCUTOFF, i++, peL);
+					sblive_writeptr(sb_hw, IFATN_FILTERCUTOFF, i++, peR);
+				} else if (0)
+				{
+					sblive_writeptr(sb_hw, IP,  i++, idxB << 12);
+					sblive_writeptr(sb_hw, IP, i++, idxB << 12);
+				}
+			}
+			return 0;
+		}
+	default:
+		DPF(2, "Got unknown SOUND_MIXER ioctl\n");
+		return -EINVAL;
+	}
+}
+
+
+static loff_t sblive_mixer_llseek(struct file *file, loff_t offset, int nOrigin)
+{
+	DPF(2, "sblive_mixer_llseek() called\n");
+	return -ESPIPE;
+}
+
+/* Mixer file operations */
+/* FIXME: Do we need spinlocks in here? */
+static int sblive_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	static const char id[] = "SBLive";
+	static const char name[] = "Creative SBLive";
+	int i, val;
+	struct sblive_hw * sb_hw = (struct sblive_hw *) file->private_data;
+	u16 reg;
+
+	if (cmd == SOUND_MIXER_INFO)
+	{
+		mixer_info info;
+		DPF(2, "SOUND_MIXER_INFO\n");
+
+		strncpy(info.id, id, sizeof(info.id));
+		strncpy(info.name, name, sizeof(info.name));
+
+		info.modify_counter = sb_hw->modcnt;
+		if (copy_to_user((void *) arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	if (cmd == SOUND_OLD_MIXER_INFO)
+	{
+		_old_mixer_info info;
+		DPF(2, "SOUND_OLD_MIXER_INFO\n");
+
+		strncpy(info.id, id, sizeof(info.id));
+		strncpy(info.name, name, sizeof(info.name));
+
+		if (copy_to_user((void *) arg, &info, sizeof(info)))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	if (cmd == OSS_GETVERSION)
+	{
+		DPF(2, "OSS_GETVERSION\n");
+		return put_user(SOUND_VERSION, (int *) arg);
+	}
+
+	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+		return -EINVAL;
+
+	if (_IOC_DIR(cmd) == _IOC_READ)
+	{
+		switch (_IOC_NR(cmd))
+		{
+		case SOUND_MIXER_RECSRC:	/* Arg contains a bit for each recording source */
+			DPF(2, "SOUND_MIXER_READ_RECSRC\n");
+			sblive_readac97(sb_hw, AC97_RECORDSELECT, &reg);
+			return put_user(recsrc[reg & 7], (int *) arg);
+
+		case SOUND_MIXER_DEVMASK:	/* Arg contains a bit for each supported device */
+			DPF(4, "SOUND_MIXER_READ_DEVMASK\n");
+			return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+					SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
+					SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+					SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
+					/* SOUND_MASK_BASS | SOUND_MASK_TREBLE | */ /* Why not enable these? [jtaylor] */
+					SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
+					SOUND_MASK_LINE2 | SOUND_MASK_DIGITAL1 |
+					SOUND_MASK_DIGITAL2,
+					(int *) arg);
+		case SOUND_MIXER_RECMASK:	/* Arg contains a bit for each supported recording source */
+			DPF(2, "SOUND_MIXER_READ_RECMASK\n");
+			return put_user(SOUND_MASK_MIC | SOUND_MASK_CD |
+					SOUND_MASK_LINE1 | SOUND_MASK_LINE |
+					SOUND_MASK_VOLUME | SOUND_MASK_OGAIN |
+					SOUND_MASK_PHONEIN, (int *) arg);
+
+		case SOUND_MIXER_STEREODEVS:	/* Mixer channels supporting stereo */
+			DPF(2, "SOUND_MIXER_READ_STEREODEVS\n");
+			return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+					SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
+					SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+					/*SOUND_MASK_BASS | SOUND_MASK_TREBLE |*/ /* ...especially since they are enabled here */
+					SOUND_MASK_RECLEV | SOUND_MASK_LINE2 |
+					SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2,
+					(int *) arg);
+
+		case SOUND_MIXER_CAPS:
+			DPF(2, "SOUND_MIXER_READ_CAPS\n");
+			return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
+
+		default:
+			i = _IOC_NR(cmd);
+			DPD(4, "SOUND_MIXER_READ(%d)\n", i);
+			if (i >= SOUND_MIXER_NRDEVICES)
+				return -EINVAL;
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+			return mixer_rdch(sb_hw, i, (int *) arg);
+#else				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
+			if (!volidx[i])
+				return -EINVAL;
+			return put_user(sb_hw->arrwVol[volidx[i] - 1], (int *) arg);
+
+#endif				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
+		}
+	}			/* End of _IOC_READ */
+
+	if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE))
+		return -EINVAL;
+
+	/* _IOC_WRITE */
+	sb_hw->modcnt++;
+
+	switch (_IOC_NR(cmd))
+	{
+	case SOUND_MIXER_RECSRC:	/* Arg contains a bit for each recording source */
+		DPF(2, "SOUND_MIXER_WRITE_RECSRC\n");
+
+		get_user_ret(val, (int *) arg, -EFAULT);
+		i = hweight32(val);
+		if (i == 0)
+			return 0;	/*val = mixer_recmask(s); */
+		else if (i > 1)
+		{
+			sblive_readac97(sb_hw, AC97_RECORDSELECT, &reg);
+			val &= ~recsrc[reg & 7];
+		}
+
+		for (i = 0; i < 8; i++)
+		{
+			if (val & recsrc[i])
+			{
+				DPD(2, "Selecting record source to be 0x%04x\n", 0x0101 * i);
+				sblive_writeac97(sb_hw, AC97_RECORDSELECT, 0x0101 * i);
+				return 0;
+			}
+		}
+		return 0;
+
+	default:
+		i = _IOC_NR(cmd);
+		DPD(2, "SOUND_MIXER_WRITE(%d)\n", i);
+
+		if (i >= SOUND_MIXER_NRDEVICES)
+			return -EINVAL;
+		get_user_ret(val, (int *) arg, -EFAULT);
+		if (mixer_wrch(sb_hw, i, val))
+			return -EINVAL;
+
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+		return mixer_rdch(sb_hw, i, (int *) arg);
+#else				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
+		return put_user(sb_hw->arrwVol[volidx[i] - 1], (int *) arg);
+#endif				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
+
+	}
+}
+
+static int sblive_mixer_open(struct inode *inode, struct file *file)
+{
+	int nMinor = MINOR(inode->i_rdev);
+	struct sblive_hw * currobj = sblive_devs;
+
+	DPF(4, "sblive_mixer_open() called!\n");
+
+	while (currobj && currobj->mixer_num != nMinor)
+		currobj = currobj->next;
+	if (!currobj)
+		return -ENODEV;
+
+	file->private_data = currobj;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int sblive_mixer_close(struct inode *inode, struct file *file)
+{
+	DPF(4, "sblive_mixer_close() called!\n");
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+struct file_operations emu10k1_mixer_fops =
+{
+	&sblive_mixer_llseek,
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* select/poll */
+	&sblive_mixer_ioctl,
+	NULL,			/* mmap */
+	&sblive_mixer_open,
+	NULL,			/* flush */
+	&sblive_mixer_close,
+	NULL,			/* fsync */
+	NULL,			/* fasync */
+};
+
+static const struct initvol
+{
+	int mixch;
+	int vol;
+} initvol[] __initdata =
+{
+	{ SOUND_MIXER_VOLUME, 0x5050 },
+	{ SOUND_MIXER_OGAIN, 0x5050 },
+	{ SOUND_MIXER_SPEAKER, 0x5050 },
+	{ SOUND_MIXER_PHONEIN, 0x5050 },
+	{ SOUND_MIXER_MIC, 0x5050 },
+	{ SOUND_MIXER_LINE, 0x5050 },
+	{ SOUND_MIXER_CD, 0x5050 },
+	{ SOUND_MIXER_LINE1, 0x5050 },
+	{ SOUND_MIXER_LINE2, 0x3232 },
+	{ SOUND_MIXER_DIGITAL1, 0x5050 },
+	{ SOUND_MIXER_DIGITAL2, 0x0000 },
+	{ SOUND_MIXER_PCM, 0x5050 },
+	{ SOUND_MIXER_RECLEV, 0x5050 } /*,
+	{ SOUND_MIXER_TREBLE, 0x5050 },
+	{ SOUND_MIXER_BASS, 0x5050 } */
+};
+
+/* FIXME: Do we need spinlocks in here? */
+int sblive_mixer_init(struct sblive_hw * sb_hw)
+{
+	int count;
+
+	/* Reset */
+	sblive_writeac97(sb_hw, AC97_RESET, 0);
+
+#if 0
+	/* Check status word */
+	{
+		u16 reg;
+		sblive_readac97(sb_hw, AC97_RESET, &reg);
+		DPD(2, "RESET 0x%x\n", reg);
+		sblive_readac97(sb_hw, AC97_MASTERTONE, &reg);
+		DPD(2, "MASTER_TONE 0x%x\n", reg);
+	}
+#endif
+
+	/* Set default recording source to mic in */
+	sblive_writeac97(sb_hw, AC97_RECORDSELECT, 0);
+
+	/* Set default volumes for all mixer channels */
+	for (count = 0; count < sizeof(initvol) / sizeof(initvol[0]); count++)
+	{
+		mixer_wrch(sb_hw, initvol[count].mixch, initvol[count].vol);
+	}
+
+	sb_hw->modcnt = 0;	// Should this be here or in open() ?
+
+	return CTSTATUS_SUCCESS;
+}
Index: oldkernel/linux/drivers/sound/emu10k1/mmwave.h
diff -u /dev/null linux/drivers/sound/emu10k1/mmwave.h:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/mmwave.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,76 @@
+/*
+ **********************************************************************
+ *     mmwave.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _MMWAVE_H
+#define _MMWAVE_H
+
+/* Enumeration for SetControl */
+enum
+{
+	WAVESTARTLOOP = 0x10,
+	WAVEENDLOOP,
+	WAVECURPOS,
+	WAVESTOPPOSITION,
+	WAVEWRITEPOINTER,
+	WAVESETSTOPONLOOP,
+
+	WAVEOBJVOLUME = 0x20,
+	WAVEINSTANCEVOLUME,
+	WAVEOBJREVERB,
+	WAVEINSTANCEREVERB,
+	WAVEOBJCHORUS,
+	WAVEINSTANCECHORUS,
+	WAVEOBJMUTE,
+	WAVEVOLFACTOR,
+	WAVEREVERBFACTOR,
+	WAVECHORUSFACTOR,
+	WAVEINSTANCEPITCHOFFSET,
+	WAVEINSTANCESEND,
+
+	WAVESYNCHSETUP = 0x30,
+	WAVESYNCHSTART,
+	WAVESETFREQUENCY,
+	WAVESETSTARTFLAG,
+	WAVEQUERYACTIVEINST,
+	WAVEINSTANCEFILTERQ,
+	WAVEINSTANCEFILTERCUTOFF,
+	WAVEINSTANCEFORMAT,
+
+	WAVEPROPERTYSETGET = 0x200,
+	WAVEPROPERTYSETSET,
+	WAVEPROPERTYSETQUERYSUPPORT,
+
+	WAVEGET3DBUFFERPROPERTYSETIFACE = 0x250,
+	WAVEGET3DLISTENERPROPERTYSETIFACE,
+	WAVENUMFREE3DBUFFERS
+};
+
+#endif /* _MMWAVE_H */
Index: oldkernel/linux/drivers/sound/emu10k1/mycommon.h
diff -u /dev/null linux/drivers/sound/emu10k1/mycommon.h:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/mycommon.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,48 @@
+/*
+ **********************************************************************
+ *     common.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _MYCOMMON_H
+#define _MYCOMMON_H
+
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+
+/* extern global variables */
+extern struct sblive_hw * sblive_devs;
+extern struct file_operations emu10k1_audio_fops;
+extern struct file_operations emu10k1_dac_fops;
+extern struct file_operations emu10k1_mixer_fops;
+extern struct file_operations emu10k1_midi_fops;
+extern struct file_operations emu10k1_sndstat_fops;
+
+#endif /* _MYCOMMON_H */
Index: oldkernel/linux/drivers/sound/emu10k1/osutils.c
diff -u /dev/null linux/drivers/sound/emu10k1/osutils.c:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/osutils.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,174 @@
+/*
+ **********************************************************************
+ *     osutils.c - OS Services layer for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *     November 2, 1999     Alan Cox        cleaned up
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+/* FIXME! This file should not exist!
+ * We do not need the crossplatform support anymore
+ * This is a Linux-only driver
+ */
+
+#include "hwaccess.h"
+#include "mycommon.h"
+
+
+int osAllocMemPhysical(u32 size, struct memhandle **handle)
+{
+	u32 reqpage, order;
+
+	*handle = (struct memhandle *) kmalloc(sizeof(struct memhandle), GFP_KERNEL);
+	if (*handle == NULL)
+		return CTSTATUS_NOMEMORY;
+
+	DPD(3, "kmalloc: [%p]\n", *handle);
+
+	order = 0;
+	reqpage = size / PAGE_SIZE;
+
+	if (size % PAGE_SIZE)
+		reqpage++;
+
+	if (reqpage != 0)
+	{
+		reqpage--;
+		while (reqpage > 0)
+		{
+			reqpage >>= 1;
+			order++;
+		}
+	}
+
+	if (((*handle)->virtaddx = (void *)__get_free_pages(GFP_KERNEL, order)) == 0)
+	{
+		kfree((void *) *handle);
+
+		DPD(3, "kfree: [%p]\n", *handle);
+		*handle = NULL;
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "__get_free_pages: [%p]\n", (*handle)->virtaddx);
+
+	/* in linux, we can directly access physical address, don't need to do
+	 * phys_to_virt.
+	 * In linux kernel 2.0.36, virt_to_bus does nothing, get_free_pages
+	 * returns physical address. But in kernel 2.2.1 upwards,
+	 * get_free_pages returns virtual address, we need to convert it
+	 * to physical address. Then this physical address can be used to
+	 * program hardware registers. */
+	(*handle)->physaddx = virt_to_bus((*handle)->virtaddx);
+	(*handle)->order    = order;
+
+	return CTSTATUS_SUCCESS;
+}
+
+int osFreeMemPhysical(struct memhandle **handle)
+{
+	if (*handle == NULL)
+		return CTSTATUS_ERROR;
+
+	free_pages((unsigned long) (*handle)->virtaddx, (*handle)->order);
+	kfree((void*) *handle);
+
+	DPD(3, "free_pages: [%p]\n", (*handle)->virtaddx);
+	DPD(3, "kfree: [%p]\n", *handle);
+
+	*handle = NULL;
+	return CTSTATUS_SUCCESS;
+}
+
+
+int osListAttach(struct sblive_list **head, struct sblive_list *n)
+{
+	unsigned long flags;
+
+	if (head == NULL)
+		return CTSTATUS_ERROR;
+
+	spin_lock_irqsave(&sblive_spinlock, flags);
+
+	n->next = NULL;
+
+	if (*head != NULL)
+	{
+		struct sblive_list *t = *head;
+
+		while (t->next != NULL)
+			t = t->next;
+		t->next = n;
+	} else
+		*head = n;
+
+	spin_unlock_irqrestore(&sblive_spinlock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+int osListRemove(struct sblive_list **head, struct sblive_list *dead)
+{
+	u32 status = CTSTATUS_SUCCESS;
+	unsigned long flags;
+
+	if (head == NULL)
+		return CTSTATUS_ERROR;
+
+	spin_lock_irqsave(&sblive_spinlock, flags);
+
+	if (*head != dead)
+	{
+		struct sblive_list *t = *head;
+
+		while (t != NULL && t->next != dead)
+			t = t->next;
+
+		if (t != NULL)
+		{
+			t->next = dead->next;
+			dead->next = NULL;
+		} else
+			status = CTSTATUS_ERROR;
+	} else
+		*head = dead->next;
+
+	spin_unlock_irqrestore(&sblive_spinlock, flags);
+
+	return status;
+}
+
+
+struct sblive_list *osListGetNext(struct sblive_list *head, struct sblive_list *curr)
+{
+	if (curr == NULL)
+		return head;
+
+	return curr->next;
+}
+
Index: oldkernel/linux/drivers/sound/emu10k1/recmgr.c
diff -u /dev/null linux/drivers/sound/emu10k1/recmgr.c:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/recmgr.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,185 @@
+/*
+ **********************************************************************
+ *     recmgr.c -- Recording manager for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+#include "recmgr.h"
+
+/****************************************************************************/
+/**  Function: recmgrInit                                                  **/
+/**                                                                        **/
+/**  Input   : rec_ptr - pointer recording object                          **/
+/**                                                                        **/
+/**  About   : stop recording when init                                    **/
+/****************************************************************************/
+int recmgrInit(struct record *rec_ptr)
+{
+	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;
+
+	/* Disable record transfer */
+	sblive_writeptr(hw_ptr, ADCBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(hw_ptr, ADCCR, 0, 0);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/**  Function: recmgrStartRecord                                           **/
+/**                                                                        **/
+/**  Input   : rec_ptr - pointer recording object                          **/
+/**                                                                        **/
+/**  About   : start recording                                             **/
+/****************************************************************************/
+int recmgrStartRecord(struct record *rec_ptr)
+{
+	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;
+	u32 adcsr;
+
+
+#ifdef RECTEST
+	DPD(2, " data in 0x120 -> %x\n", sblive_readptr(hw_ptr, FXGPREGBASE + 0x20, 0));
+	DPD(2, " data in 0x121 -> %x\n", sblive_readptr(hw_ptr, FXGPREGBASE + 0x21, 0));
+#endif
+
+	DPD(2, "recmgrStartRecord: base addx: %x\n", rec_ptr->physaddx >> 12);
+	sblive_writeptr(hw_ptr, ADCBA, 0, rec_ptr->physaddx);
+
+	switch (rec_ptr->samplingrate) 
+	{
+	case 0xBB80: adcsr = ADCCR_SAMPLERATE_48; break;
+	case 0xAC44: adcsr = ADCCR_SAMPLERATE_44; break;
+	case 0x7D00: adcsr = ADCCR_SAMPLERATE_32; break;
+	case 0x5DC0: adcsr = ADCCR_SAMPLERATE_24; break;
+	case 0x5622: adcsr = ADCCR_SAMPLERATE_22; break;
+	case 0x3E80: adcsr = ADCCR_SAMPLERATE_16; break;
+	case 0x2B11: adcsr = ADCCR_SAMPLERATE_11; break;
+	case 0x1F40: adcsr = ADCCR_SAMPLERATE_8; break;
+	default:
+		DPF(2, "Unknown sampling rate!\n");
+		return CTSTATUS_ERROR;
+	}
+
+	adcsr |= ADCCR_LCHANENABLE;
+
+	if (rec_ptr->is_stereo)
+	  adcsr |= ADCCR_RCHANENABLE;
+
+	sblive_writeptr(hw_ptr, ADCCR, 0, adcsr);
+	sblive_writeptr(hw_ptr, ADCBS, 0, rec_ptr->bufsizereg);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/**  Function: recmgrStopRecord                                            **/
+/**                                                                        **/
+/**  Input   : rec_ptr - pointer recording object                          **/
+/**                                                                        **/
+/**  About   : stop recording                                              **/
+/****************************************************************************/
+int recmgrStopRecord(struct record *rec_ptr)
+{
+	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;
+
+	/* Disable record transfer */
+	sblive_writeptr(hw_ptr, ADCBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(hw_ptr, ADCCR, 0, 0);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/**  Function: recmgrSetControl                                            **/
+/**                                                                        **/
+/**  Input   : rec_ptr - pointer recording object                          **/
+/**            controlid - control ID                                      **/
+/**            value - value to set for a specified control                **/
+/**                                                                        **/
+/**  About   : set recording resource                                      **/
+/**                                                                        **/
+/**  Note    :                                                             **/
+/**                                                                        **/
+/**  XD, DMA, WR and RIGHT bits in CCCA register controls the way to       **/
+/**  record for 8005.                                                      **/
+/**                                                                        **/
+/**  XD   DMA    WR    RIGHT                                               **/
+/**  1     1     0      0      --- record from external(AC97, SPDIF, MIC)  **/
+/**  1     1     1      0      --- record from the output of Emu8000       **/
+/**                                effects engine.                         **/
+/**                                                                        **/
+/****************************************************************************/
+int recmgrSetControl(struct record *rec_ptr, u32 controlid, u32 value)
+{
+	/* FIXME: Implement me! */
+	return CTSTATUS_SUCCESS;
+}
+
+
+/****************************************************************************/
+/**  Function: recmgrGetPos                                                **/
+/**                                                                        **/
+/**  Input   : rec_ptr - pointer recording object                          **/
+/**            pos -  pointer to position returned                         **/
+/**                                                                        **/
+/**  About   : get recording position(no. of bytes per channel)            **/
+/**                                                                        **/
+/**  Formula : (WC*SamplingRate/48kHz)%(record buffer size)                **/
+/****************************************************************************/
+int recmgrGetPos(struct record *rec_ptr, u32 *pos)
+{
+	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;
+
+	u32 curidx;
+
+	curidx = recmgrGetRecIdx(hw_ptr);
+	if (curidx >= rec_ptr->prevadcidx)
+	  *pos = curidx - rec_ptr->prevadcidx;
+	else
+	  *pos = 0xfffff - (rec_ptr->prevadcidx - curidx);
+
+	*pos = (*pos) * ((u16) rec_ptr->samplingrate) / 48000
+	  * 2 * (rec_ptr->is_stereo + 1);
+
+	DPD(2, " Recmgr: *pos: %x\n", *pos);
+	
+	if (rec_ptr->pong) 
+	  *pos += rec_ptr->recbufsize / 2;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+u32 recmgrGetRecIdx(struct sblive_hw *sb_hw)
+{
+	return READ_FN0(sb_hw, WC_SAMPLECOUNTER);
+}
Index: oldkernel/linux/drivers/sound/emu10k1/recmgr.h
diff -u /dev/null linux/drivers/sound/emu10k1/recmgr.h:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/recmgr.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,65 @@
+/*     
+ **********************************************************************
+ *     recmgr.h
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */
+
+#ifndef _RECORDMGR_H
+#define _RECORDMGR_H
+
+struct record 
+{
+	void *reserved;
+	struct sblive_hw *sb_hw;
+	u32 recpos;
+	u32 recbufsize;
+	u32 bufsizereg;
+	u8 *recbuffer;
+	u32 physaddx;
+	u32 samplingrate;
+	int is_stereo;
+	int is16bit;
+	int fSetRecSrc;
+	u32 recsrc;
+	u32 prevadcidx;
+	int pong;
+};
+
+/* Recording resources */
+#define WAVERECORD_AC97        0x00000001
+#define WAVERECORD_E8K         0x00000002
+
+int recmgrInit(struct record *);
+int recmgrStartRecord(struct record *);
+int recmgrStopRecord(struct record *);
+int recmgrSetControl(struct record *, u32, u32);
+int recmgrGetPos(struct record *, u32 *);
+u32 recmgrGetRecIdx(struct sblive_hw *);
+
+
+#endif /* _RECORDMGR_H */
Index: oldkernel/linux/drivers/sound/emu10k1/sndstat.c
diff -u /dev/null linux/drivers/sound/emu10k1/sndstat.c:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/sndstat.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,300 @@
+/*     
+ **********************************************************************
+ * 
+ *     sndstat.c - /dev/sndstat interface for emu10k1 driver 
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ *
+ *     This file uses some code from soundcard.c, Copyright 1993-1997
+ *     Hannu Savolainen
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */ 
+
+#ifdef MODULE
+#define __NO_VERSION__
+#include <linux/module.h>
+#endif
+
+#include <linux/utsname.h>
+
+#include "hwaccess.h"
+#include "mycommon.h"
+#include "sndstat.h"
+
+static int in_use = 0;
+static int is_unloading = 0;
+static int sound_started = 0;
+static int soundcard_configured = 0;
+
+/* unneeded ??? - will be removed shortly
+int num_sound_cards = 0;
+struct card_info snd_installed_cards[20] = {{0}};
+
+int num_sound_drivers = 0;
+struct driver_info sound_drivers[20] = {{0}};
+
+struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; 
+int num_audiodevs = 0;
+
+struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; 
+int num_mixers = 0;
+
+*/
+
+static int sound_proc_get_info(char *buffer, char **start, off_t offset, int length, int inout)
+{
+	int len, count;
+	off_t begin = 0;
+	struct sblive_hw *lastdev, *dev;
+
+#ifdef MODULE
+#define MODULEPROCSTRING "Driver loaded as a module"
+#else
+#define MODULEPROCSTRING "Driver compiled into kernel"
+#endif
+
+	for (lastdev = sblive_devs; lastdev->next; lastdev = lastdev->next);
+	
+	len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n"
+		      "Load type: " MODULEPROCSTRING "\n"
+		      "Kernel: %s %s %s %s %s\n"
+		      "Config options: %x\n\nInstalled drivers: \n", 
+		      system_utsname.sysname, system_utsname.nodename, system_utsname.release, 
+		      system_utsname.version, system_utsname.machine, SELECTED_SOUND_OPTIONS);
+
+	len += sprintf(buffer + len, "Type 0: %s\n", "Creative EMU10K1 (0.4)");
+
+	len += sprintf(buffer + len, "\nCard config: \n");
+	dev = lastdev;
+	while (dev)
+	{
+		len += sprintf(buffer + len, "(");
+		len += sprintf(buffer + len, "%s", "Sound Blaster Live!");
+		len += sprintf(buffer + len, " at 0x%lx", dev->hwaddr);
+		len += sprintf(buffer + len, " irq %d", dev->hw_irq.irq);
+		len += sprintf(buffer + len, ")");
+		len += sprintf(buffer + len, "\n");
+		dev = dev->prev;
+	}
+
+	len += sprintf(buffer + len, "\nAudio devices:\n");
+	dev = lastdev;
+	count = 0;
+	while (dev) 
+	{
+		len += sprintf(buffer + len, "%d: %s%s\n", count++, "Sound Blaster Live!", " (DUPLEX)");
+		dev = dev->prev;
+	}
+
+	len += sprintf(buffer + len, "\nSynth devices: \nNot supported by current driver\n");
+
+	len += sprintf(buffer + len, "\nMidi devices: \n");
+	dev = lastdev;
+	count = 0;
+
+	while (dev) 
+	{
+		len += sprintf(buffer + len, "%d: %s\n", count++, "Sound Blaster Live!");
+		dev = dev->prev;
+	}
+
+	len += sprintf(buffer + len, "\nTimers:\n");
+	len += sprintf(buffer + len, "0: %s\n", "System Clock");
+
+	len += sprintf(buffer + len, "\nMixers:\n");
+	dev = lastdev;
+	count = 0;
+
+	while (dev) 
+	{
+		len += sprintf(buffer + len, "%d: %s\n", count++, "Sound Blaster Live!");
+		dev = dev->prev;
+	}
+
+	*start = buffer + (offset - begin);
+	len -= (offset - begin);
+	if (len > length) 
+	  len = length;
+	return len;
+}
+
+/* 4K page size but our output routines use some slack for overruns */
+#define PROC_BLOCK_SIZE (3*1024)
+
+/*
+ * basically copied from fs/proc/generic.c:proc_file_read 
+ * should be removed sometime in the future together with /dev/sndstat
+ * (a symlink /dev/sndstat -> /proc/sound will do as well)
+ */
+static int sndstat_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
+{
+	char  *page;
+	int   retval=0;
+	int   eof=0;
+	int   n, count;
+	char  *start;
+
+	if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+	  return -ENOMEM;
+
+	while ((nbytes > 0) && !eof) 
+	{
+		count = min(PROC_BLOCK_SIZE, nbytes);
+
+		start = NULL;
+		n = sound_proc_get_info(page, &start, *ppos, count, 0);
+		if (n < count)
+		  eof = 1;
+                        
+		if (!start) 
+		{
+			/* For proc files that are less than 4k */
+			start = page + *ppos;
+			n -= *ppos;
+			if (n <= 0)
+			  break;
+			if (n > count)
+			  n = count;
+		}
+		
+		if (n == 0)
+		  break;  /* End of file */
+		
+		if (n < 0) 
+		{
+			if (retval == 0)
+			  retval = n;
+			break;
+		}
+                
+		n -= copy_to_user(buf, start, n);       /* BUG ??? */
+		if (n == 0) 
+		{
+			if (retval == 0)
+			  retval = -EFAULT;
+			break;
+		}
+                
+		*ppos += n;     /* Move down the file */
+		nbytes -= n;
+		buf += n;
+		retval += n;
+	}
+	
+	free_page((unsigned long) page);
+	return retval;
+}
+
+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);
+
+	DPD(2, "sound_read(dev=%d, count=%d)\n", dev, count);
+
+	switch (dev & 0x0f) 
+	{
+		case SND_DEV_STATUS:
+		return sndstat_file_read(file, buf, count, &file->f_pos);
+
+		default: 
+		break;
+	}
+	return -EINVAL;
+}
+
+static int sound_open(struct inode *inode, struct file *file)
+{
+	int dev;
+
+	if (is_unloading) 
+	{
+		DPF(2, "Sound: Driver partially removed. Can't open device\n");
+		return -EBUSY;
+	}
+	dev = MINOR(inode->i_rdev);
+	if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) 
+	{
+		DPF(2, "SoundCard Error: The sound system has not been configured\n");
+		return -ENXIO;
+	}
+	DPD(2, "sound_open(dev=%d)\n", dev);
+	if ((dev >= SND_NDEVS) || (dev < 0)) 
+	{
+		DPD(2, "Invalid minor device %d\n", dev);
+		return -ENXIO;
+	}
+
+	switch (dev & 0x0f) 
+	{
+	case SND_DEV_STATUS:
+		break;
+	default:
+		DPD(2, "Invalid minor device %d\n", dev);
+		return -ENXIO;
+	}
+	in_use++;
+	return 0;
+}
+
+static int sound_release(struct inode *inode, struct file *file)
+{
+	int dev = MINOR(inode->i_rdev);
+
+	DPD(2, "sound_release(dev=%d)\n", dev);
+	switch (dev & 0x0f) 
+	{
+	case SND_DEV_STATUS:
+		break;
+	default:
+		DPD(2, "Sound error: Releasing unknown device 0x%02x\n", dev);
+	}
+	in_use--;
+
+	return 0;
+}
+
+
+void sndstat_init(void)
+{
+	soundcard_configured = 1;
+	sound_started = 1;
+}
+
+struct file_operations emu10k1_sndstat_fops = 
+{
+	NULL,
+	sound_read,
+	NULL,
+	NULL,          /* sound_readdir */
+	NULL,
+	NULL,
+	NULL,
+	sound_open,
+	NULL,
+	sound_release,
+	NULL,
+	NULL,
+};
Index: oldkernel/linux/drivers/sound/emu10k1/sndstat.h
diff -u /dev/null linux/drivers/sound/emu10k1/sndstat.h:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/sndstat.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,106 @@
+/*     
+ **********************************************************************
+ * 
+ *     sndstat.h
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ * 
+ *     This file uses some code from sound_config.h, Copyright 1993-
+ *     1997, Hannu Savolainen
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */ 
+
+#ifndef _SNDSTAT_H
+#define _SNDSTAT_H
+
+/* Minor numbers for the sound driver */
+
+#define SND_NDEVS	256	/* Number of supported devices */
+#define SND_DEV_CTL	0	/* Control port /dev/mixer */
+#define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM
+				   synthesizer and MIDI output) */
+#define SND_DEV_MIDIN	2	/* Raw MIDI access */
+#define SND_DEV_DSP	3	/* Digitized voice /dev/dsp */
+#define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
+#define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
+#define SND_DEV_STATUS	6	/* /dev/sndstat */
+#define SND_DEV_AWFM	7	/* Reserved */
+#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
+#define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
+#define SND_DEV_PSS	SND_DEV_SNDPROC
+
+#define SOUND_VERSION_STRING "3.8s2++-971130"
+
+#define SELECTED_SOUND_OPTIONS		0x0
+
+#ifndef ONECARD
+
+#define MAX_AUDIO_DEV   5
+#define MAX_MIXER_DEV   5
+#define DMA_DUPLEX      0x04
+
+struct address_info
+{
+	int io_base;
+	int irq;
+	int dma;
+	int dma2;
+	int always_detect;	/* 1=Trust me, it's there */
+	char *name;
+	int driver_use_1;	/* Driver defined field 1 */
+	int driver_use_2;	/* Driver defined field 2 */
+	int *osp;	/* OS specific info */
+	int card_subtype;	/* Driver specific. Usually 0 */
+	void *memptr;           /* Module memory chainer */
+	int slots[6];           /* To remember driver slot ids */
+};
+
+struct driver_info 
+{
+	char *driver_id;
+	int card_subtype;	/* Driver specific. Usually 0 */
+	int card_type;		/*	From soundcard.h	*/
+	char *name;
+	void (*attach) (struct address_info *hw_config);
+	int (*probe) (struct address_info *hw_config);
+	void (*unload) (struct address_info *hw_config);
+};
+
+struct card_info 
+{
+	int card_type;	/* Link (search key) to the driver list */
+	struct address_info config;
+	int enabled;
+	void *for_driver_use;
+};
+
+#define CONFIG_AUDIO
+
+#endif /* ONECARD */
+
+void sndstat_init(void);
+
+#endif /* _SNDSTAT_H */
Index: oldkernel/linux/drivers/sound/emu10k1/timer.c
diff -u /dev/null linux/drivers/sound/emu10k1/timer.c:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/timer.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,165 @@
+/*
+ **********************************************************************
+ *     timer.c
+ *     Copyright (C) 1999, 2000 Creative Labs, inc.
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#include "hwaccess.h"
+
+int sblive_timerIrqCallback(struct sblive_hw *sb_hw)
+{
+	struct emu_timer *timer;
+
+	spin_lock(&sb_hw->timer_lock);
+
+	timer = sb_hw->timer;
+	while (timer != NULL)
+	{
+		queue_task(timer->task, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		timer = timer->next;
+	}
+
+	spin_unlock(&sb_hw->timer_lock);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int sblive_timerinstall(struct sblive_hw *sb_hw, struct emu_timer **timer, struct tq_struct *task, unsigned delay)
+{
+	struct emu_timer *t;
+	unsigned long flags;
+
+	t = (struct emu_timer *) kmalloc(sizeof(struct emu_timer), GFP_KERNEL);
+	if (t == NULL)
+	{
+		DPF(2, "timer alloc failed\n");
+		return CTSTATUS_NOMEMORY;
+	}
+
+	DPD(3, "kmalloc: [%p]\n", t);
+
+	if(delay < 1 )
+		delay = 1;
+	else if (delay >= 1024)
+		delay = 1023;
+
+	t->delay = delay;
+	t->task = task;
+
+	*timer = t;
+
+	spin_lock_irqsave(&sb_hw->timer_lock, flags);
+
+	if(sb_hw->timer == NULL)
+	{
+		sb_hw->timer = *timer;
+		sb_hw->timer->next = NULL;
+		sb_hw->timer_delay = delay;
+		WRITE_FN0(sb_hw, TIMR_RATE, delay);
+		sblive_irqmgrEnableIrq(sb_hw, INTE_INTERVALTIMERENB);
+	}
+	else
+	{
+		t = sb_hw->timer;
+		sb_hw->timer = *timer;
+		sb_hw->timer->next = t;
+		if (delay < sb_hw->timer_delay)
+		{
+			sb_hw->timer_delay = delay;
+			WRITE_FN0(sb_hw, TIMR_RATE, delay);
+		}
+	}
+
+	spin_unlock_irqrestore(&sb_hw->timer_lock, flags);
+
+	DPD(2, "timer rate --> %d\n", sb_hw->timer_delay);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int sblive_timeruninstall(struct sblive_hw *sb_hw, struct emu_timer *timer)
+{
+	struct emu_timer *t;
+	unsigned delay;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sb_hw->timer_lock, flags);
+
+	t = sb_hw->timer;
+
+	if( t == NULL){
+		spin_unlock_irqrestore(&sb_hw->timer_lock, flags);
+		return CTSTATUS_SUCCESS;
+	}
+
+	delay = timer->delay;
+
+	if(sb_hw->timer == timer)
+	{
+		sb_hw->timer = timer->next;
+	}
+	else
+	{
+		while(t->next != timer)
+			t = t->next;
+
+		t->next = timer->next;
+	}
+
+	kfree(timer);
+
+	DPD(3, "kfree: [%p]\n", timer);
+
+	if(sb_hw->timer == NULL)
+	{
+		sblive_irqmgrDisableIrq(sb_hw, INTE_INTERVALTIMERENB);
+	}
+	else if (delay == sb_hw->timer_delay)
+	{
+		t = sb_hw->timer;
+		sb_hw->timer_delay = 1024;
+
+		while(t != NULL){
+
+			if(t->delay < sb_hw->timer_delay)
+				sb_hw->timer_delay = t->delay;
+			t = t->next;
+		}
+
+		WRITE_FN0(sb_hw, TIMR_RATE, sb_hw->timer_delay);
+
+		DPD(2, "timer rate --> %d\n", sb_hw->timer_delay);
+	}
+
+	spin_unlock_irqrestore(&sb_hw->timer_lock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+int sblive_timerinit(struct sblive_hw *sb_hw)
+{
+	sb_hw->timer = NULL;
+	sb_hw->timer_lock = SPIN_LOCK_UNLOCKED;
+
+	return CTSTATUS_SUCCESS;
+}
Index: oldkernel/linux/drivers/sound/emu10k1/timer.h
diff -u /dev/null linux/drivers/sound/emu10k1/timer.h:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/timer.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,41 @@
+/*
+ **********************************************************************
+ *     timer.h
+ *     Copyright (C) 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+
+#ifndef _TIMER_H
+#define _TIMER_H
+
+struct emu_timer 
+{
+	struct emu_timer *next;
+	struct tq_struct *task;
+	unsigned delay;
+};
+
+int sblive_timerinstall(struct sblive_hw *, struct emu_timer **, struct tq_struct *, unsigned);
+int sblive_timeruninstall(struct sblive_hw *, struct emu_timer *);
+int sblive_timerinit(struct sblive_hw *);
+
+#endif /* _TIMER_H */
Index: oldkernel/linux/drivers/sound/emu10k1/voicemgr.c
diff -u /dev/null linux/drivers/sound/emu10k1/voicemgr.c:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/voicemgr.c	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,993 @@
+/*
+ **********************************************************************
+ *     sblive_voice.c - Voice manager for emu10k1 driver
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+
+#include "hwaccess.h"
+
+/************************************************************************
+ *
+ *   static struct emu_voice * sblive_emuVoiceAlloc(struct sblive_hw *sb_hw, u32 flags)
+ *
+ *   ENTRY
+ *       sb_hw -    Pointer to the HWOBJ to allocate voice from
+ *       flags -    flags from struct voice_allocdesc from the ICardxxx
+ *                  object that called sblive_voiceAlloc
+ *
+ *   RETURNS
+ *       SUCCESS -   Pointer to a struct emu_voice
+ *       FAILURE -   NULL
+ *
+ *   ABOUT
+ *       This is a static funciton that searches for free emuvoices
+ *       and tries to return the type needed according to flags
+ *
+ ************************************************************************/
+static struct emu_voice *sblive_emuVoiceAlloc(struct voice_mgr *voice, u32 flags)
+{
+	unsigned int voicenum;
+	struct sblive_hw *sb_hw = voice->sb_hw;
+	struct emu_voice *foundvoice = NULL;
+	struct emu_voice *slavevoice = NULL;
+	struct emu_voice *testvoice, *testslave;
+	u32 curvol, lowestvol, mastervol, slavevol, CA, dcysusv;
+
+	DPF(2, "Entered sblive_emuVoiceAlloc\n");
+
+	if (flags & VOICEMGR_FLAGS_MONO)
+	{
+		DPF(2, "sblive_emuVoiceAlloc MONO PLAYBACK voicei\n");
+
+		/* Check for free voices first */
+		if (voice->free_voices)
+		{
+			voice->free_voices->voicestate = VOICEMGR_STATE_TRANSITION;
+			foundvoice = voice->free_voices;
+			foundvoice->flags = 0;
+			DPD(2, "  Voice found %d\n", foundvoice->voicenum);
+			return foundvoice;
+		}
+
+		/* We couldn't find any free voices so we need to free up
+		 * some voices. We only rip off MIDI voices at the moment. */
+		testvoice = dlFirstNode(&voice->midi_voices);
+
+		lowestvol = 0xffffffff;
+
+		while (testvoice)
+		{
+			/* Voice stealing algorithm goes here */
+			voicenum = testvoice->voicenum;
+
+			if (!(testvoice->voicestate & VOICEMGR_STATE_TRANSITION))
+			{
+				/* Check if voice is looping silence */
+				CA = sblive_readptr(sb_hw, CCCA_CURRADDR, voicenum);
+				if (CA > testvoice->voice_params.end)
+				{
+					testvoice->voicestate |= VOICEMGR_STATE_TRANSITION;
+					if (foundvoice)
+						foundvoice->voicestate &= ~VOICEMGR_STATE_TRANSITION;
+					lowestvol = 0;
+					foundvoice = testvoice;
+					break;
+				}
+
+				curvol = sblive_readptr(sb_hw, CVCF_CURRENTVOL, voicenum);
+				dcysusv = sblive_readptr(sb_hw, DCYSUSV, voicenum);
+				dcysusv = (dcysusv & DCYSUSV_PHASE1_MASK) ? 0 : 0x1000; /* 0x1000 means what? */
+
+				if ((curvol < 0x200) && !dcysusv && (testvoice->voicestate & VOICEMGR_STATE_RELEASE))
+				{
+					/* The volume is less than the threshold and
+					 the volume envelope is in the decaying state.
+					 Stop the pitch to stop the busmaster activities.
+					 */
+					sblive_writeptr(sb_hw, IP, voicenum, 0);
+					sblive_writeptr(sb_hw, VTFT, voicenum, VTFT_FILTERTARGET_MASK);
+					sblive_writeptr(sb_hw, PTRX_PITCHTARGET, voicenum, 0);
+				} else
+				{
+					if (testvoice->voicestate & VOICEMGR_STATE_SUSTAIN)
+						curvol += 0x500 + dcysusv;
+					else if (testvoice->voicestate & VOICEMGR_STATE_ATTACK)
+						curvol += 0x200 + dcysusv;
+				}
+
+				if (curvol < lowestvol)
+				{
+					testvoice->voicestate |= VOICEMGR_STATE_TRANSITION;
+
+					if (foundvoice)
+						foundvoice->voicestate &= ~VOICEMGR_STATE_TRANSITION;
+					foundvoice = testvoice;
+					lowestvol = curvol;
+				}
+			}
+			testvoice = dlNextNode(testvoice);
+		}
+
+		if (foundvoice)
+		{
+			if (foundvoice->callback)
+			{
+				/* Note that this function can change the voice suggested to another voice */
+				if (foundvoice->callback(VOICECALLBACK_EVENT_FREEVOICE, foundvoice->callback_data, (u32)&foundvoice)
+				    != CTSTATUS_SUCCESS)
+				{
+					DPF(2, "Found voide callback failed\n");
+					foundvoice = NULL;
+				}
+			}
+
+			foundvoice->flags = 0;
+			foundvoice->master_voice = NULL;
+			foundvoice->linked_voice = NULL;
+		} else
+		{
+			DPF(2, "Voice not found!\n");
+		}
+
+		return foundvoice;
+	} else
+	{
+		DPF(2, "sblive_emuVoiceAlloc STEREO PLAYBACK voice\n");
+
+		voicenum = 8;
+		lowestvol = 0xffffffff;
+
+		do
+		{
+			/* Since stereo voices must be side-by-side,
+			 we have to check 2 voices at once. */
+			if (((voice->voices[voicenum].usage == VOICEMGR_USAGE_FREE)
+			     || (voice->voices[voicenum].usage == VOICEMGR_USAGE_MIDI))
+			    && ((voice->voices[voicenum + 1].usage == VOICEMGR_USAGE_FREE)
+				|| (voice->voices[voicenum + 1].usage == VOICEMGR_USAGE_MIDI)))
+			{
+				mastervol = 0xffffffff;
+				slavevol = 0xffffffff;
+				testvoice = &voice->voices[voicenum];
+				testslave = &voice->voices[voicenum + 1];
+
+				if ((!(testvoice->voicestate & VOICEMGR_STATE_TRANSITION))
+				    && (!(testslave->voicestate & VOICEMGR_STATE_TRANSITION)))
+				{
+					/* Voice stealing algorithm goes here */
+
+					/* Check master voice */
+					if (testvoice->usage == VOICEMGR_USAGE_FREE)
+						mastervol = 0;
+					else
+					{
+						/* Check if voice is looping silence */
+						CA = sblive_readptr(sb_hw, CCCA_CURRADDR, voicenum);
+
+						if (CA > testvoice->voice_params.end)
+							mastervol = 0;
+						else
+						{
+							mastervol = sblive_readptr(sb_hw, CVCF_CURRENTVOL, voicenum);
+							if (!(testvoice->voicestate & VOICEMGR_STATE_RELEASE))
+								mastervol += 0x1300; /* Why??? */
+						}
+					}
+
+					/* Check slave voice */
+					if (testslave->usage == VOICEMGR_USAGE_FREE)
+						slavevol = 0;
+					else
+					{
+						/* Check if voice is looping silence */
+						CA = sblive_readptr(sb_hw, CCCA_CURRADDR, voicenum + 1);
+
+						if (CA > testslave->voice_params.end)
+							slavevol = 0;
+						else
+						{
+							slavevol = sblive_readptr(sb_hw, CVCF_CURRENTVOL, (voicenum + 1));
+							if (!(testslave->voicestate & VOICEMGR_STATE_RELEASE))
+								slavevol += 0x1300; /* Why??? */
+						}
+					}
+
+					if ((mastervol + slavevol) < lowestvol)
+					{
+						testvoice->voicestate |= VOICEMGR_STATE_TRANSITION;
+						testslave->voicestate |= VOICEMGR_STATE_TRANSITION;
+
+						if (foundvoice)
+						{
+							foundvoice->voicestate &= ~VOICEMGR_STATE_TRANSITION;
+							slavevoice->voicestate &= ~VOICEMGR_STATE_TRANSITION;
+						}
+
+						foundvoice = testvoice;
+						slavevoice = testslave;
+						lowestvol = mastervol + slavevol;
+					}
+				}
+			}
+
+			voicenum = (voicenum + 2) % NUM_G;
+
+		} while (voicenum != 8);
+
+		if (foundvoice)
+		{
+			if (foundvoice->callback)
+			{
+				/* Note that this function can change the voice suggested to another voice */
+				if (foundvoice->callback(VOICECALLBACK_EVENT_FREEVOICE, foundvoice->callback_data, (u32)&foundvoice)
+				    != CTSTATUS_SUCCESS)
+				{
+					DPF(2, "Voice callback failed\n");
+				}
+			}
+
+			if (slavevoice->callback)
+			{
+				/* Note that this function can change the voice suggested to another voice */
+				testvoice = slavevoice;
+				if (testvoice->callback(VOICECALLBACK_EVENT_FREEVOICE, testvoice->callback_data, (u32)&testvoice)
+				    != CTSTATUS_SUCCESS)
+				{
+					DPF(2, "Voice callback failed\n");
+				}
+
+				if (testvoice != slavevoice)
+				{
+					DPF(2, "testvoice != slavevoice\n");
+					return NULL;
+				}
+			}
+
+			DPD(2, "Voice found %x\n", (u32)voicenum);
+
+			/* Link next voice in stereo pair */
+			foundvoice->master_voice = NULL;
+			foundvoice->linked_voice = slavevoice;
+			slavevoice->master_voice = foundvoice;
+			slavevoice->linked_voice = NULL;
+
+			/* Mark second voice as stereo slave */
+			foundvoice->flags = VOICEMGR_FLAGS_VOICEMASTER;
+			slavevoice->flags = VOICEMGR_FLAGS_STEREOSLAVE;
+
+			return foundvoice;
+		}
+	}
+
+	return foundvoice;
+}
+
+/************************************************************************
+ *
+ *   int sblive_voiceInit(struct sblive_hw *sb_hw)
+ *
+ *   ENTRY
+ *       card  -    Pointer to the card obj to init voice manager
+ *
+ *   RETURNS
+ *       Always returns CTSTATUS_SUCCESS
+ *
+ *   ABOUT
+ *       Inits data
+ *
+ ************************************************************************/
+int sblive_voiceInit(struct sblive_hw *sb_hw)
+{
+	struct voice_mgr *voice;
+	struct emu_voice *emu_voice;
+	int i;
+
+	voice = &sb_hw->voice_manager;
+	voice->free_voices = NULL;
+
+	emu_voice = voice->voices;
+	for (i = 0; i < NUM_G; i++)
+	{
+		unsigned long flags;
+
+		emu_voice->sb_hw = sb_hw;
+		emu_voice->usage = VOICEMGR_USAGE_FREE;
+		emu_voice->voicestate = VOICEMGR_STATE_IDLE;
+		emu_voice->voicenum = i;
+		emu_voice->linked_voice = NULL;
+
+		spin_lock_irqsave(&sblive_spinlock, flags);
+
+		dlAddNode(&voice->free_voices, emu_voice);
+
+		spin_unlock_irqrestore(&sblive_spinlock, flags);
+
+		++emu_voice;
+	}
+
+	voice->sb_hw = sb_hw;
+	voice->playback_voices = NULL;
+	voice->record_voices = NULL;
+	voice->midi_voices = NULL;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/************************************************************************
+ *
+ *   int sblive_voiceExit(struct sblive_hw *sb_hw)
+ *
+ *   ENTRY
+ *       sb_hw  -    Pointer to the HWOBJ to init voice manager
+ *
+ *   RETURNS
+ *       Always returns CTSTATUS_SUCCESS
+ *
+ *   ABOUT
+ *       Exits
+ *
+ ************************************************************************/
+int sblive_voiceExit(struct sblive_hw *sb_hw)
+{
+	int i;
+	struct emu_voice *emu_voice;
+
+	emu_voice = sb_hw->voice_manager.voices;
+	for (i = 0; i < NUM_G; i++)
+	{
+		/* TODO: CALL ALL RELEASE CALLBACKS FOR BUSY VOICES */
+
+		emu_voice->usage = VOICEMGR_USAGE_FREE;
+		emu_voice->voicestate = VOICEMGR_STATE_IDLE;
+		emu_voice->voicenum = i;
+		emu_voice->linked_voice = NULL;
+		++emu_voice;
+	}
+
+	sb_hw->voice_manager.sb_hw = NULL;
+	sb_hw->voice_manager.free_voices = NULL;
+	sb_hw->voice_manager.playback_voices = NULL;
+	sb_hw->voice_manager.record_voices = NULL;
+	sb_hw->voice_manager.midi_voices = NULL;
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/************************************************************************
+ *
+ *   int sblive_voiceAlloc(struct voice_allocdesc *voiceallocdesc,
+ *                         struct emu_voice * *voices)
+ *
+ *   ENTRY
+ *       voiceallocdesc   -
+ *           Pointer to a struct voice_allocdesc that describes the
+ *           voices needed.
+ *
+ *       voices        -
+ *           Address to return allocated struct emu_voices
+ *
+ *   RETURNS
+ *       SUCCESS -   CTSTATUS_SUCCESS
+ *       FAILURE -   CTSTATUS_INUSE (not enough available voices)
+ *                   CTSTATUS_ERROR
+ *
+ *   ABOUT
+ *       Allocates voices according to the types requested.
+ *
+ ************************************************************************/
+int sblive_voiceAlloc(struct voice_allocdesc *voiceallocdesc, struct emu_voice **voices)
+{
+	struct emu_voice **ppOwnerList = NULL;	/* Linux: added initialization */
+	struct emu_voice *allocvoicelist;
+	struct emu_voice *lastvoice = NULL;	/* Linux: added initialization */
+	struct emu_voice *linkvoice;
+	int status = CTSTATUS_SUCCESS;
+	struct sblive_hw *sb_hw = voiceallocdesc->sb_hw;
+	unsigned long flags;
+	int i;
+
+	if (!voiceallocdesc->numvoicereqs)
+	{
+		/* No voices requested??? */
+		DPF(2, "No voices requested!\n");
+		return CTSTATUS_INVALIDPARAM;
+	}
+
+	/* Determine 'busy' list to attach voices to */
+	if (voiceallocdesc->ownertype == VOICEMGR_USAGE_PLAYBACK)
+		ppOwnerList = &sb_hw->voice_manager.playback_voices;
+	else if (voiceallocdesc->ownertype == VOICEMGR_USAGE_MIDI)
+		ppOwnerList = &sb_hw->voice_manager.midi_voices;
+
+	allocvoicelist = NULL;
+
+	/* Satisfy voice requests one by one */
+	for (i = 0; i < voiceallocdesc->numvoicereqs; i++)
+	{
+		/* Allocate voices */
+
+		linkvoice = sblive_emuVoiceAlloc(&sb_hw->voice_manager, voiceallocdesc->flags[i]);
+
+		if (linkvoice)
+		{
+			/* Suitable free voice found */
+			if (allocvoicelist == NULL)
+			{
+				allocvoicelist = linkvoice;
+				linkvoice->master_voice = NULL;
+			} else
+			{
+				lastvoice->linked_voice = linkvoice;
+				linkvoice->master_voice = lastvoice;
+			}
+
+			linkvoice->flags = VOICEMGR_FLAGS_VOICEMASTER;
+
+			/* Repeat for all linked voices */
+			while (linkvoice)
+			{
+				/* Shut off the voice */
+				sblive_writeptr(sb_hw, IFATN, linkvoice->voicenum, 0xffff);
+				sblive_writeptr(sb_hw, DCYSUSV , linkvoice->voicenum, ENV_OFF);
+				sblive_writeptr(sb_hw, VTFT, linkvoice->voicenum, 0xffff);
+				sblive_writeptr(sb_hw, PTRX, linkvoice->voicenum, 0);
+
+				spin_lock_irqsave(&sblive_spinlock, flags);
+
+				dlDelNode(&sb_hw->voice_manager.free_voices, linkvoice); /* Remove voice from free list */
+
+				linkvoice->sb_hw = sb_hw;
+				linkvoice->ownertype = voiceallocdesc->ownertype;
+				linkvoice->callback = voiceallocdesc->callback;
+				linkvoice->callback_data = voiceallocdesc->callback_data;
+
+				/* We need a transition state to make a voice
+				 as belonging to a owner but not yet assigned
+				 to that owner yet */
+				linkvoice->voicestate |= VOICEMGR_STATE_TRANSITION;
+				linkvoice->usage = voiceallocdesc->ownertype;
+				linkvoice->flags |= voiceallocdesc->flags[i];
+
+				dlAddNode(ppOwnerList, linkvoice); /* Attach voice to busy list */
+
+				spin_unlock_irqrestore(&sblive_spinlock, flags);
+
+				lastvoice = linkvoice; /* Remember last of linked voices */
+
+				linkvoice = linkvoice->linked_voice;
+			}
+		} else
+		{
+			/* No free suitable voices found - steal from busy voices */
+			status = CTSTATUS_INUSE;
+
+			/* TODO : IMPLEMENT VOICE STEALING ALGORITHM */
+
+			DPF(2, "Steal a voice: not yet implemented\n");
+
+			spin_lock_irqsave(&sblive_spinlock, flags);
+
+			while (allocvoicelist)
+			{
+				linkvoice = allocvoicelist;
+				allocvoicelist = allocvoicelist->linked_voice;
+				dlDelNode(ppOwnerList, linkvoice);
+
+				linkvoice->linked_voice = NULL;
+				linkvoice->master_voice = NULL;
+				linkvoice->flags = 0;
+				linkvoice->callback = 0;
+				linkvoice->callback_data = 0;
+				linkvoice->voicestate = VOICEMGR_STATE_IDLE;
+				linkvoice->usage = VOICEMGR_USAGE_FREE;
+
+				dlAddNode(&sb_hw->voice_manager.free_voices, linkvoice);
+			}
+
+			spin_unlock_irqrestore(&sblive_spinlock, flags);
+
+			break;
+		}
+	}
+
+	if (voiceallocdesc->ownertype != VOICEMGR_USAGE_MIDI)
+	{
+		linkvoice = allocvoicelist;
+
+		while (linkvoice)
+		{
+			linkvoice->voicestate &= ~VOICEMGR_STATE_TRANSITION;
+			linkvoice = linkvoice->linked_voice;
+		}
+	}
+
+	*voices = allocvoicelist;
+
+	return status;
+}
+
+
+/************************************************************************
+ *
+ *   int sblive_voiceFree(struct emu_voice * voices)
+ *
+ *   ENTRY
+ *       voices -
+ *           pointer to a struct emu_voice returned
+ *           by a call to sblive_voiceAlloc()
+ *
+ *   RETURNS
+ *       SUCCESS -   CTSTATUS_SUCCESS
+ *       FAILURE -   CTSTATUS_ERROR
+ *
+ *   ABOUT
+ *       Frees a previously allocated voice. Multiple voices can
+ *       be allocated at once but must be freed individually.
+ *
+ ************************************************************************/
+int sblive_voiceFree(struct emu_voice *voices)
+{
+	struct emu_voice *voicetemp;
+	struct emu_voice **ppOwnerList;
+	struct sblive_hw *sb_hw;
+	unsigned long flags;
+
+	if (voices == NULL)
+		return CTSTATUS_INVALIDPARAM;
+
+	sb_hw = voices->sb_hw;
+
+	if (voices->usage == VOICEMGR_USAGE_PLAYBACK)
+		ppOwnerList = &sb_hw->voice_manager.playback_voices;
+	else if (voices->usage == VOICEMGR_USAGE_MIDI)
+		ppOwnerList = &sb_hw->voice_manager.midi_voices;
+	else
+	{
+		DPF(2, "Unknown VOICEMGR_USAGE\n");
+		return CTSTATUS_ERROR;
+	}
+
+	if (!(voices->flags & VOICEMGR_FLAGS_VOICEMASTER))
+	{
+		/* Not first voice in list */
+		DPF(2, "Not first voice in list!\n");
+		return CTSTATUS_ERROR;
+	}
+
+	while (voices)
+	{
+		unsigned dcysusv, voicenum;
+
+		voicenum = voices->voicenum;
+
+		sblive_writeptr(sb_hw, IFATN, voicenum, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK);
+		sblive_writeptr(sb_hw, IP, voicenum, 0);
+
+		dcysusv = sblive_readptr(sb_hw, DCYSUSV, voicenum) & (DCYSUSV_PHASE1_MASK | DCYSUSV_SUSTAINLEVEL_MASK | DCYSUSV_DECAYTIME_MASK);
+		sblive_writeptr(sb_hw, DCYSUSV, voicenum, dcysusv | ENV_OFF);
+
+		sblive_writeptr(sb_hw, VTFT, voicenum, VTFT_FILTERTARGET_MASK);
+		sblive_writeptr(sb_hw, PTRX_PITCHTARGET, voicenum, 0);
+		sblive_writeptr(sb_hw, CVCF,  voicenum, CVCF_CURRENTFILTER_MASK);
+		sblive_writeptr(sb_hw, CPF, voicenum, 0);
+
+		{
+			u32 cra;
+			u32 sample;
+			int i;
+
+			sample = (voices->flags & VOICEMGR_FLAGS_16BIT) ? 0 : 0x80808080;
+			cra = sblive_readptr(sb_hw, CCR, voicenum) & CCR_READADDRESS_MASK;
+			sblive_writeptr(sb_hw, CCR, voicenum, cra);
+			cra = (cra >> 18) & 0xf;
+			sblive_writeptr(sb_hw, CD0 + cra, voicenum, sample);
+			cra = (cra + 0x1) & 0xf;
+			sblive_writeptr(sb_hw, CD0 + cra, voicenum, sample);
+
+			for (i = 0; i < NUM_FXSENDS; i++)
+				if (voices->sendhandle[i])
+					voices->sendhandle[i] = 0;
+		}
+
+		spin_lock_irqsave(&sblive_spinlock, flags);
+
+		/* Reattach to free list */
+		voicetemp = voices;
+		voices = voices->linked_voice;
+
+		dlDelNode(ppOwnerList, voicetemp);	/* Detach first */
+		voicetemp->linked_voice = NULL;
+		voicetemp->master_voice = NULL;
+		voicetemp->flags = 0;
+		voicetemp->callback = 0;
+		voicetemp->callback_data = 0;
+		voicetemp->voicestate = VOICEMGR_STATE_IDLE;
+		voicetemp->usage = VOICEMGR_USAGE_FREE;
+		dlAddNode(&sb_hw->voice_manager.free_voices, voicetemp);
+
+		spin_unlock_irqrestore(&sblive_spinlock, flags);
+
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/************************************************************************
+ *
+ *   int sblive_voicePlaybackSetup(struct emu_voice * voices)
+ *
+ *   ENTRY
+ *       voices -
+ *           pointer to a struct emu_voice returned
+ *           by a call to sblive_voiceAlloc()
+ *       pVoiceSetting -
+ *           pointer to an array of setting params
+ *
+ *   RETURNS
+ *       SUCCESS -   CTSTATUS_SUCCESS
+ *       FAILURE -   CTSTATUS_ERROR
+ *
+ *   ABOUT
+ *       Sets up a voices for Wave Playback
+ *
+ ************************************************************************/
+int sblive_voicePlaybackSetup(struct emu_voice *voices)
+{
+	int voicenum;
+	struct sblive_hw *sb_hw;
+	u32 cra = 0;
+	u32 start = 0;
+	struct voice_param *pvoice_params;
+	struct emu_voice *currvoice;
+
+	currvoice = voices;
+	while (currvoice)
+	{
+		/* Or here? (voices can be on different cards) */
+		sb_hw = currvoice->sb_hw;
+		voicenum = currvoice->voicenum;
+		pvoice_params = &currvoice->voice_params;
+
+		sblive_writeptr(sb_hw, DCYSUSV, voicenum, ENV_OFF);
+		sblive_writeptr(sb_hw, VTFT, voicenum, VTFT_FILTERTARGET_MASK);
+		sblive_writeptr(sb_hw, CVCF, voicenum, CVCF_CURRENTFILTER_MASK);
+
+		/* Stop CA */
+		/* Assumption that PT is already 0 so no harm overwriting */
+		sblive_writeptr(sb_hw, PTRX, voicenum,
+				(pvoice_params->unSends.tSends.reverb_send << 8) | pvoice_params->unSends.tSends.aux_send);
+
+		if (currvoice->flags & VOICEMGR_FLAGS_VOICEMASTER)
+		{
+			u32 sample;
+
+			if (currvoice->linked_voice != NULL)
+			{
+				/* Set stereo bit */
+				cra = 64;
+				sblive_writeptr(sb_hw, CPF, voicenum, CPF_STEREO_MASK);
+				sblive_writeptr(sb_hw, CPF, voicenum + 1, CPF_STEREO_MASK);
+			} else
+			{
+				cra = 32;
+				sblive_writeptr(sb_hw, CPF, voicenum, 0);
+			}
+
+			if (currvoice->flags & VOICEMGR_FLAGS_16BIT)
+				sample = 0;
+			else
+			{
+				cra = cra * 2;
+				sample = 0x80808080;
+			}
+			cra -= 4;
+
+			if (currvoice->linked_voice != NULL)
+			{
+				sblive_writeptr(sb_hw, CCR, voicenum, 0x3c << 16);
+				sblive_writeptr(sb_hw, CCR, voicenum + 1, cra << 16);
+				sblive_writeptr(sb_hw, CDE, voicenum + 1, sample);
+				sblive_writeptr(sb_hw, CDF, voicenum + 1, sample);
+				start = pvoice_params->start + cra / 2;
+			} else
+			{
+				sblive_writeptr(sb_hw, CCR, voicenum, 0x1c << 16); /* FIXME: Is 0x1c correct? */
+				sblive_writeptr(sb_hw, CDE, voicenum, sample);
+				sblive_writeptr(sb_hw, CDF, voicenum, sample);
+				start = pvoice_params->start + cra;
+			}
+
+			if (start > pvoice_params->endloop)
+			{
+				start -= pvoice_params->endloop;
+
+				if (currvoice->linked_voice != NULL)
+					cra = (cra << 25) | 0x1bc0000 | ((cra - start) << 9);
+				else
+					cra = (cra << 25) | 0x11c0000 | ((cra - start) << 9);
+
+				start += pvoice_params->startloop;
+
+				if (start >= pvoice_params->endloop)
+					start = pvoice_params->endloop - 1;
+			} else
+				if (currvoice->linked_voice != NULL)
+					cra = (cra << 25) | (0x3c << 16);
+				else
+					cra = (cra << 25) | (0x1c << 16);
+
+			start |= CCCA_INTERPROM_0;
+		}
+
+		/* CSL, ST, CA */
+		sblive_writeptr(sb_hw, DSL, voicenum,
+				pvoice_params->endloop | ((u32) pvoice_params->unSends.tSends.chorus_send << 24));
+
+		sblive_writeptr(sb_hw, PSST, voicenum,
+				pvoice_params->startloop | ((u32) pvoice_params->unSends.tSends.pan_send << 24));
+
+		if (currvoice->flags & VOICEMGR_FLAGS_16BIT)
+			sblive_writeptr(sb_hw, CCCA, voicenum, start);
+		else
+			sblive_writeptr(sb_hw, CCCA, voicenum, start | CCCA_8BITSELECT);
+
+		/* Clear filter delay memory */
+		sblive_writeptr(sb_hw, Z1, voicenum, 0);
+		sblive_writeptr(sb_hw, Z2, voicenum, 0);
+
+		/* Invalidate maps */
+		sblive_writeptr(sb_hw, MAPA, voicenum, MAP_PTI_MASK | (sb_hw->silentpage->physaddx * 2));
+		sblive_writeptr(sb_hw, MAPB, voicenum, MAP_PTI_MASK | (sb_hw->silentpage->physaddx * 2));
+
+		/* Fill cache */
+		if (currvoice->flags & VOICEMGR_FLAGS_VOICEMASTER)
+			sblive_writeptr(sb_hw, CCR, voicenum, cra);
+
+		sblive_writeptr(sb_hw, ATKHLDV, voicenum, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK);
+		sblive_writeptr(sb_hw, LFOVAL1, voicenum, 0x8000);
+		sblive_writeptr(sb_hw, ATKHLDM, voicenum, 0);
+		sblive_writeptr(sb_hw, DCYSUSM, voicenum, DCYSUSM_DECAYTIME_MASK);
+		sblive_writeptr(sb_hw, LFOVAL2, voicenum, 0x8000);
+		sblive_writeptr(sb_hw, IP,  voicenum, pvoice_params->initial_pitch);
+		sblive_writeptr(sb_hw, PEFE, voicenum, 0x7f);
+		sblive_writeptr(sb_hw, FMMOD, voicenum, 0);
+		sblive_writeptr(sb_hw, TREMFRQ, voicenum, 0);
+		sblive_writeptr(sb_hw, FM2FRQ2, voicenum, 0);
+		sblive_writeptr(sb_hw, ENVVAL, voicenum, 0xbfff);
+		sblive_writeptr(sb_hw, ENVVOL, voicenum, 0xbfff);
+		sblive_writeptr(sb_hw, IFATN, voicenum, IFATN_FILTERCUTOFF_MASK | pvoice_params->initial_attn);
+
+		pvoice_params->FC_target = 0xffff;
+		pvoice_params->pitch_target = (u16)(IP_TO_CP(pvoice_params->initial_pitch) >> 16);
+
+		currvoice = currvoice->linked_voice;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+/************************************************************************
+ *
+ *   int sblive_voiceStart(struct emu_voice * voices)
+ *
+ *   ENTRY
+ *       voices -
+ *           pointer to a struct emu_voice returned
+ *           by a call to sblive_voiceAlloc()
+ *
+ *   RETURNS
+ *       SUCCESS -   CTSTATUS_SUCCESS
+ *       FAILURE -   CTSTATUS_ERROR
+ *
+ *   ABOUT
+ *       Starts voices
+ *
+ ************************************************************************/
+int sblive_voiceStart(struct emu_voice *voices)
+{
+	struct sblive_hw *sb_hw;
+	struct emu_voice *tempvoice;
+
+	tempvoice = voices;
+	sb_hw = tempvoice->sb_hw;
+
+	/* Actual start */
+	while (tempvoice != NULL)
+	{
+		int voicenum = 0;	/* Linux: Added initialization */
+
+		if (tempvoice->flags & VOICEMGR_FLAGS_PLAYBACK)
+		{
+			struct voice_param *pvoice_params = &tempvoice->voice_params;
+			voicenum = tempvoice->voicenum;
+
+			/* Playback */
+			sblive_writeptr(sb_hw, PTRX_PITCHTARGET, voicenum, pvoice_params->pitch_target);
+
+			if (!(tempvoice->flags & VOICEMGR_FLAGS_STEREOSLAVE))
+				sblive_writeptr(sb_hw, CPF_CURRENTPITCH, voicenum, pvoice_params->pitch_target);
+
+			sblive_writeptr(sb_hw, VTFT, voicenum,
+					((u32) pvoice_params->volume_target << 16)
+					| pvoice_params->FC_target);
+			sblive_writeptr(sb_hw, CVCF, voicenum,
+					((u32) pvoice_params->volume_target << 16)
+					| pvoice_params->FC_target);
+			sblive_writeptr(sb_hw, DCYSUSV , voicenum,
+					(pvoice_params->byampl_env_sustain << 8)
+					| ENV_ON | pvoice_params->byampl_env_decay);
+
+			/* Using StopOnLoop for MIDI stops the playback
+			 too early, which may cause a DC level to be played
+			 until the note is released. */
+
+			if (tempvoice->usage == VOICEMGR_USAGE_MIDI)
+				halClearStopOnLoop(sb_hw, voicenum);
+			else
+			{
+				if (pvoice_params->startloop > pvoice_params->end)
+					halSetStopOnLoop(sb_hw, voicenum);
+				else
+					halClearStopOnLoop(sb_hw, voicenum);
+			}
+		} else
+			/* Recording */
+			sblive_writeptr(sb_hw, DCYSUSV, voicenum, DCYSUSV_SUSTAINLEVEL_MASK |  DCYSUSV_DECAYTIME_MASK | ENV_ON);
+
+		tempvoice->voicestate |= VOICEMGR_STATE_ATTACK;
+		tempvoice = tempvoice->linked_voice;
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/************************************************************************
+ *
+ *   int sblive_voiceStop(struct emu_voice * voices)
+ *
+ *   ENTRY
+ *       voices -
+ *           pointer to a struct emu_voice returned
+ *           by a call to sblive_voiceAlloc()
+ *
+ *   RETURNS
+ *       SUCCESS -   CTSTATUS_SUCCESS
+ *       FAILURE -   CTSTATUS_ERROR
+ *
+ *   ABOUT
+ *       Stops voices
+ *
+ ************************************************************************/
+int sblive_voiceStop(struct emu_voice *voices)
+{
+	struct sblive_hw *sb_hw = voices->sb_hw;
+	struct emu_voice *tempvoice = voices;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sblive_spinlock, flags);
+
+	while (tempvoice != NULL)
+	{
+
+		if (voices->flags & VOICEMGR_FLAGS_PLAYBACK)
+		{
+			int voicenum = tempvoice->voicenum;
+
+			sblive_writeptr(sb_hw, IFATN, voicenum, 0xffff);
+			sblive_writeptr(sb_hw, IP, voicenum, 0);
+			sblive_writeptr(sb_hw, VTFT, voicenum, 0xffff);
+			sblive_writeptr(sb_hw, PTRX_PITCHTARGET, voicenum, 0);
+		}
+
+		tempvoice->voicestate = VOICEMGR_STATE_IDLE;
+		tempvoice = tempvoice->linked_voice;
+	}
+
+	tempvoice = voices;
+
+	spin_unlock_irqrestore(&sblive_spinlock, flags);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/************************************************************************
+ *
+ *   int sblive_voiceSetControl(struct emu_voice *voices,
+ *                              struct voice_cntlset *pSetting,
+ *                              u32 numparam)
+ *
+ *   ENTRY
+ *       voices -
+ *           pointer to a struct emu_voice returned
+ *           by a call to sblive_voiceAlloc()
+ *
+ *       pSetting    -
+ *           An array of CNTLSET structures
+ *
+ *       numparam  -
+ *           Number of struct voice_cntlset structures in pSetting
+ *
+ *   RETURNS
+ *       SUCCESS -   CTSTATUS_SUCCESS
+ *       FAILURE -   CTSTATUS_ERROR
+ *
+ *   ABOUT
+ *       Sets a voice control
+ *
+ ************************************************************************/
+int sblive_voiceSetControl(struct emu_voice *voices, struct voice_cntlset *setting, u32 numparam)
+{
+	struct sblive_hw *sb_hw = voices->sb_hw;
+	struct emu_voice *currvoice = voices;
+	int count;
+
+	for (count = 0; count < numparam; count++)
+		sblive_writeptr(sb_hw, setting[count].paramID, currvoice->voicenum, setting[count].value);
+
+	return CTSTATUS_SUCCESS;
+}
+
+
+/************************************************************************
+ *
+ *   int sblive_voiceGetControl(struct emu_voice * voices,
+ *                              u32 controlid, u32 *value)
+ *
+ *   ENTRY
+ *       voices -
+ *           pointer to a struct emu_voice returned
+ *           by a call to sblive_voiceAlloc()
+ *
+ *       controlid -
+ *           control to get
+ *
+ *       pvalue    -
+ *           address to return control value
+ *
+ *   RETURNS
+ *       SUCCESS -   CTSTATUS_SUCCESS
+ *       FAILURE -   CTSTATUS_ERROR
+ *
+ *   ABOUT
+ *       Gets a voice control
+ *
+ ************************************************************************/
+int sblive_voiceGetControl(struct emu_voice *voices, u32 controlid, u32 *value)
+{
+	struct sblive_hw *sb_hw = voices->sb_hw;
+
+	*value = sblive_readptr(sb_hw, controlid, voices->voicenum);
+
+	return CTSTATUS_SUCCESS;
+}
Index: oldkernel/linux/drivers/sound/emu10k1/voicemgr.h
diff -u /dev/null linux/drivers/sound/emu10k1/voicemgr.h:1.1
--- /dev/null	Mon Jul 31 21:13:56 2000
+++ linux/drivers/sound/emu10k1/voicemgr.h	Thu Jun  1 16:52:15 2000
@@ -0,0 +1,242 @@
+/*
+ **********************************************************************
+ *     sblive_voice.h -- EMU Voice Resource Manager header file
+ *     Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ *     Date                 Author          Summary of changes
+ *     ----                 ------          ------------------
+ *     October 20, 1999     Bertrand Lee    base code release
+ *
+ **********************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _VOICEMGR_H
+#define _VOICEMGR_H
+
+
+#define SAMPLETYPE_ROMMASK              0x8000
+#define SAMPLETYPE_MONOSAMPLE           1
+#define SAMPLETYPE_RIGHTSAMPLE          2
+#define SAMPLETYPE_LEFTSAMPLE           4
+
+#define SAMPLEMODE_MASK                 3
+#define SAMPLEMODE_RELEASEINLOOP        1
+#define SAMPLEMODE_RELEASEOUTLOOP       3
+
+#define WAVE_RAMP_TIME_TO_TARGET        100
+#define MIDI_RAMP_TIME_TO_TARGET        200
+
+#define RAMP_REVERB_SEND_NUM            0
+#define RAMP_AUX_SEND_NUM               1
+#define RAMP_PAN_SEND_NUM               2
+#define RAMP_CHORUS_SEND_NUM            3
+
+/* struct emu_voice.usage flags */
+#define VOICEMGR_USAGE_FREE         0x00000000
+#define VOICEMGR_USAGE_MIDI         0x00000001
+#define VOICEMGR_USAGE_PLAYBACK     0x00000002
+#define VOICEMGR_USAGE_RECORDING    0x00000004
+
+/* struct emu_voice.voicestate flags */
+#define VOICEMGR_STATE_IDLE         0x00000000
+#define VOICEMGR_STATE_ATTACK       0x00000001
+#define VOICEMGR_STATE_RELEASE      0x00000002
+#define VOICEMGR_STATE_IRQON        0x00000004
+#define VOICEMGR_STATE_TRANSITION   0x00000008
+#define VOICEMGR_STATE_SUSTAIN      0x00000010
+
+/* struct emu_voice.flags flags */
+#define VOICEMGR_FLAGS_PLAYBACK     0x00000001
+#define VOICEMGR_FLAGS_MONO         0x00000002
+#define VOICEMGR_FLAGS_16BIT        0x00000004
+#define VOICEMGR_FLAGS_STEREOSLAVE  0x00000008
+#define VOICEMGR_FLAGS_VOICEMASTER  0x80000000
+#define VOICEMGR_FLAGS_FASTCALLBACK 0x40000000
+
+#define VOICECALLBACK_EVENT_CALLBACKSIZEREACHED  0
+#define VOICECALLBACK_EVENT_FREEVOICE            1
+#define VOICECALLBACK_EVENT_TIMER		 2
+
+#if !defined(DLIST)
+#define DLIST(x)    struct {x  *next,  *pPrev;} DList
+
+#define dlAddNode(list,node) \
+	{ \
+	(node)->DList.next = *(list); \
+	(node)->DList.pPrev = NULL; \
+	if (*list) (*(list))->DList.pPrev = (node); *(list) = (node); \
+	}
+
+#define dlDelNode(list, node) \
+	{ \
+	if ((node)->DList.pPrev == NULL) \
+	*(list) = (node)->DList.next; \
+	else \
+	((node)->DList.pPrev)->DList.next = (node)->DList.next; \
+	if ((node)->DList.next != NULL) \
+	((node)->DList.next)->DList.pPrev = (node)->DList.pPrev; \
+	(node)->DList.next = (node)->DList.pPrev = NULL; \
+	}
+
+
+#define dlFirstNode(list)       (*(list))
+#define dlNextNode(curnode)     ((curnode)->DList.next)
+#define dlPrevNode(curnode)     ((curnode)->DList.pPrev)
+#endif
+
+
+struct voice_param
+{
+	/* Sound engine */
+	u32 start;
+	u32 startloop;
+	u32 endloop;
+	u32 end;
+	u16 current_pitch;
+	u16 pitch_target;
+	u16 current_volume;
+	u16 volume_target;
+	u16 current_FC;
+	u16 FC_target;
+	u8 pan_target;
+	u8 aux_target;
+	u8 coef;
+	u8 sample_mode;
+	u8 sample_type;
+
+	union
+	{
+		struct
+		{
+			/* MUST be in the following order */
+			u8 reverb_send;
+			u8 aux_send;
+			u8 pan_send;
+			u8 chorus_send;
+		} tSends;
+	} unSends;
+
+	/* Envelope engine */
+	u16 ampl_env_delay;
+	u8 byampl_env_attack;
+	u8 byampl_env_hold;
+	u8 byampl_env_decay;
+	u8 byampl_env_sustain;
+	u8 byampl_env_release;
+
+	u16 aux_env_delay;
+	u8 byaux_env_attack;
+	u8 byaux_env_hold;
+	u8 byaux_env_decay;
+	u8 byaux_env_sustain;
+	u8 byaux_env_release;
+
+	u16 mod_LFO_delay;	/* LFO1 */
+	u16 vib_LFO_delay;	/* LFO2 */
+	u8 mod_LFO_freq;	/* LFO1 */
+	u8 vib_LFO_freq;	/* LFO2 */
+
+	s8 aux_env_to_pitch;
+	s8 aux_env_to_FC;
+	s8 mod_LFO_to_pitch;
+	s8 vib_LFO_to_pitch;
+	s8 mod_LFO_to_FC;
+	s8 mod_LFO_to_volume;
+
+	u16 sample_pitch;
+	u16 initial_pitch;
+	u8 initial_attn;
+	u8 initial_FC;
+
+	u8 velocity;		/* BUGBUG: to be moved to aweobj */
+
+	u32 bank;
+	u8 program;
+	u16 key_exclusive;
+};
+
+struct voice_allocdesc
+{
+	struct sblive_hw *sb_hw;
+	u32 ownertype;
+	CALLBACKFN callback;
+	u32 callback_data;
+	u32 numvoicereqs;		/* Number of voice requests */
+					/* Stereo voices count as 1 */
+					/* request                  */
+	u32 flags[MAXREQVOICES];	/* stereo/mono rec/playback 8/16 */
+};
+
+
+struct emu_voice
+{
+	DLIST(struct emu_voice);	/* Doubly-linked list */
+
+	struct sblive_hw *sb_hw;
+	u32 ownertype;
+	CALLBACKFN callback;
+	u32 callback_data;
+	u32 usage;		/* Free, MIDI, playback, recording, etc */
+	u32 voicestate;		/* Release, attack, idle, etc */
+	u32 voicenum;		/* Voice ID */
+	u32 flags;		/* Stereo/mono, rec/playback, 8/16 bit */
+
+	struct voice_param voice_params;
+	struct emu_voice *master_voice;	/* Index to previous linked voiceobj */
+	struct emu_voice *linked_voice;	/* Index to linked voiceobj, else set to NULL */
+
+	u32 sendhandle[NUM_FXSENDS];
+};
+
+
+struct voice_mgr
+{
+	struct sblive_hw *sb_hw;
+	struct emu_voice *free_voices;
+	struct emu_voice *playback_voices;
+	struct emu_voice *record_voices;
+	struct emu_voice *midi_voices;
+
+	struct emu_voice voices[NUM_G];
+
+	/* Shouldn't use this directly.  Just move pointers around from */
+	/* free_voices to the other lists and vice versa. */
+	u32 ramp_eng_handle;
+};
+
+struct voice_cntlset
+{
+	u32 paramID;
+	u32 value;
+};
+
+int sblive_voiceInit(struct sblive_hw *);
+int sblive_voiceExit(struct sblive_hw *);
+int sblive_voiceAlloc(struct voice_allocdesc *, struct emu_voice **);
+int sblive_voiceFree(struct emu_voice *);
+int sblive_voicePlaybackSetup(struct emu_voice *);
+int sblive_voiceStart(struct emu_voice *);
+int sblive_voiceStop(struct emu_voice *);
+int sblive_voiceSetControl(struct emu_voice *, struct voice_cntlset *, u32);
+int sblive_voiceGetControl(struct emu_voice *, u32, u32 *);
+
+#endif /* _VOICEMGR_H */
