25-akpm/Documentation/sound/alsa/ALSA-Configuration.txt              |   39 
 25-akpm/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl |   46 
 25-akpm/include/sound/ac97_codec.h                                   |   15 
 25-akpm/include/sound/ad1848.h                                       |   10 
 25-akpm/include/sound/asequencer.h                                   |   11 
 25-akpm/include/sound/asound.h                                       |    3 
 25-akpm/include/sound/core.h                                         |    3 
 25-akpm/include/sound/cs8427.h                                       |    2 
 25-akpm/include/sound/emu10k1.h                                      |    5 
 25-akpm/include/sound/hdsp.h                                         |    1 
 25-akpm/include/sound/info.h                                         |    9 
 25-akpm/include/sound/pcm_oss.h                                      |    4 
 25-akpm/include/sound/seq_midi_event.h                               |   16 
 25-akpm/include/sound/soundfont.h                                    |    1 
 25-akpm/include/sound/version.h                                      |    4 
 25-akpm/include/sound/ymfpci.h                                       |    8 
 25-akpm/scripts/MAKEDEV.snd                                          |  161 +
 25-akpm/sound/core/control.c                                         |    4 
 25-akpm/sound/core/info.c                                            |   10 
 25-akpm/sound/core/ioctl32/ioctl32.c                                 |    6 
 25-akpm/sound/core/memalloc.c                                        |   81 
 25-akpm/sound/core/oss/pcm_oss.c                                     |  203 ++
 25-akpm/sound/core/oss/pcm_plugin.c                                  |   23 
 25-akpm/sound/core/oss/pcm_plugin.h                                  |    1 
 25-akpm/sound/core/oss/plugin_ops.h                                  |    2 
 25-akpm/sound/core/oss/rate.c                                        |   22 
 25-akpm/sound/core/oss/route.c                                       |    4 
 25-akpm/sound/core/pcm_lib.c                                         |    9 
 25-akpm/sound/core/pcm_memory.c                                      |   16 
 25-akpm/sound/core/pcm_native.c                                      |   12 
 25-akpm/sound/core/rawmidi.c                                         |   26 
 25-akpm/sound/core/rtctimer.c                                        |   14 
 25-akpm/sound/core/seq/seq_clientmgr.c                               |   56 
 25-akpm/sound/core/seq/seq_midi_event.c                              |   55 
 25-akpm/sound/core/seq/seq_ports.c                                   |   14 
 25-akpm/sound/core/seq/seq_ports.h                                   |    3 
 25-akpm/sound/core/sound.c                                           |   18 
 25-akpm/sound/core/sound_oss.c                                       |    2 
 25-akpm/sound/core/timer.c                                           |   20 
 25-akpm/sound/drivers/dummy.c                                        |   26 
 25-akpm/sound/drivers/opl3/opl3_lib.c                                |    2 
 25-akpm/sound/drivers/opl4/opl4_lib.c                                |    5 
 25-akpm/sound/drivers/opl4/opl4_local.h                              |    2 
 25-akpm/sound/drivers/opl4/opl4_synth.c                              |   22 
 25-akpm/sound/drivers/vx/vx_core.c                                   |    6 
 25-akpm/sound/i2c/cs8427.c                                           |    6 
 25-akpm/sound/i2c/other/ak4xxx-adda.c                                |    2 
 25-akpm/sound/isa/ad1848/ad1848.c                                    |   19 
 25-akpm/sound/isa/ad1848/ad1848_lib.c                                |  108 +
 25-akpm/sound/isa/cmi8330.c                                          |    2 
 25-akpm/sound/isa/cs423x/cs4231_lib.c                                |    4 
 25-akpm/sound/isa/es18xx.c                                           |    2 
 25-akpm/sound/isa/gus/gus_main.c                                     |    4 
 25-akpm/sound/isa/opl3sa2.c                                          |    3 
 25-akpm/sound/isa/sb/emu8000.c                                       |    2 
 25-akpm/sound/isa/sb/sb16.c                                          |   18 
 25-akpm/sound/isa/sscape.c                                           |    2 
 25-akpm/sound/pci/ac97/Makefile                                      |    2 
 25-akpm/sound/pci/ac97/ac97_codec.c                                  |  823 ----------
 25-akpm/sound/pci/ac97/ac97_local.h                                  |   42 
 25-akpm/sound/pci/ac97/ac97_patch.c                                  |  618 +++++++
 25-akpm/sound/pci/ac97/ac97_patch.h                                  |    3 
 25-akpm/sound/pci/ac97/ac97_proc.c                                   |  295 +++
 25-akpm/sound/pci/ali5451/ali5451.c                                  |   52 
 25-akpm/sound/pci/cmipci.c                                           |    4 
 25-akpm/sound/pci/cs4281.c                                           |   74 
 25-akpm/sound/pci/cs46xx/cs46xx.c                                    |   13 
 25-akpm/sound/pci/cs46xx/cs46xx_lib.c                                |   29 
 25-akpm/sound/pci/emu10k1/emu10k1.c                                  |   10 
 25-akpm/sound/pci/emu10k1/emu10k1_main.c                             |    8 
 25-akpm/sound/pci/emu10k1/emufx.c                                    |   59 
 25-akpm/sound/pci/emu10k1/emumixer.c                                 |   82 
 25-akpm/sound/pci/emu10k1/irq.c                                      |   45 
 25-akpm/sound/pci/ens1370.c                                          |   10 
 25-akpm/sound/pci/es1938.c                                           |    6 
 25-akpm/sound/pci/es1968.c                                           |   48 
 25-akpm/sound/pci/ice1712/ak4xxx.c                                   |   14 
 25-akpm/sound/pci/ice1712/aureon.c                                   |    2 
 25-akpm/sound/pci/ice1712/ews.c                                      |   16 
 25-akpm/sound/pci/ice1712/ice1712.h                                  |    8 
 25-akpm/sound/pci/ice1712/ice1724.c                                  |    4 
 25-akpm/sound/pci/intel8x0.c                                         |  356 ++--
 25-akpm/sound/pci/maestro3.c                                         |  100 -
 25-akpm/sound/pci/nm256/nm256.c                                      |   13 
 25-akpm/sound/pci/rme96.c                                            |   18 
 25-akpm/sound/pci/rme9652/Makefile                                   |    5 
 25-akpm/sound/pci/rme9652/hammerfall_mem.c                           |  251 ---
 25-akpm/sound/pci/rme9652/hdsp.c                                     |  417 +++--
 25-akpm/sound/pci/rme9652/rme9652.c                                  |   79 
 25-akpm/sound/pci/sonicvibes.c                                       |    6 
 25-akpm/sound/pci/trident/trident.c                                  |   15 
 25-akpm/sound/pci/trident/trident_main.c                             |   17 
 25-akpm/sound/pci/via82xx.c                                          |    6 
 25-akpm/sound/pci/ymfpci/ymfpci.c                                    |   15 
 25-akpm/sound/pci/ymfpci/ymfpci_main.c                               |  131 +
 25-akpm/sound/pcmcia/vx/vxpocket.c                                   |    1 
 25-akpm/sound/ppc/awacs.c                                            |   29 
 25-akpm/sound/ppc/burgundy.c                                         |   25 
 25-akpm/sound/ppc/pmac.c                                             |    2 
 25-akpm/sound/ppc/pmac.h                                             |    5 
 25-akpm/sound/ppc/tumbler.c                                          |   28 
 25-akpm/sound/synth/emux/soundfont.c                                 |   18 
 25-akpm/sound/usb/usbaudio.c                                         |  230 +-
 25-akpm/sound/usb/usbaudio.h                                         |    8 
 25-akpm/sound/usb/usbmidi.c                                          |    3 
 25-akpm/sound/usb/usbmixer.c                                         |    2 
 25-akpm/sound/usb/usbmixer_maps.c                                    |   23 
 25-akpm/sound/usb/usbquirks.h                                        |   36 
 108 files changed, 3160 insertions(+), 2120 deletions(-)

diff -puN Documentation/sound/alsa/ALSA-Configuration.txt~alsa-bk-2003-07-28 Documentation/sound/alsa/ALSA-Configuration.txt
--- 25/Documentation/sound/alsa/ALSA-Configuration.txt~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/Documentation/sound/alsa/ALSA-Configuration.txt	Tue Jul 29 12:11:32 2003
@@ -27,6 +27,13 @@ the card supports).  You don't need to c
 isapnptools.
 
 
+Creating ALSA devices
+=====================
+
+Use the MAKEDEV.snd script located in the directory named scripts
+in the linux kernel tree.
+
+
 Module parameters
 =================
 
@@ -92,7 +99,7 @@ Module parameters
     amidi_map	- MIDI device number maps assigned to the 2st OSS device.
 		  (default: 1)
 
-  Global parameters for top soundcard modules
+  Common parameters for top soundcard modules
   -------------------------------------------
 
     Each of top-level soundcard module takes some general options,
@@ -518,6 +525,15 @@ Module parameters
 
     Module supports up to 8 cards.
 
+    Note: you need to load the firmware via hdsploader utility included
+          in alsa-tools package.
+
+    Note: snd-page-alloc module does the job which snd-hammerfall-mem
+          module did formerly.  It will allocate the buffers in advance
+          when any HDSP cards are found.  To make the buffer
+          allocation sure, load snd-page-alloc module in the early
+          stage of boot sequence.
+
   Module snd-ice1712
   ------------------
 
@@ -549,6 +565,7 @@ Module parameters
     Module for Envy24HT (VT/ICE1724) based PCI soundcards.
 			* MidiMan M Audio Revolution 7.1
 			* AMP Ltd AUDIO2000
+			* TerraTec Aureon Sky-5.1, Space-7.1
 
     Module supports up to 8 cards and autoprobe.
 
@@ -790,6 +807,12 @@ Module parameters
 
     Module supports up to 8 cards.
 
+    Note: snd-page-alloc module does the job which snd-hammerfall-mem
+          module did formerly.  It will allocate the buffers in advance
+          when any RME9652 cards are found.  To make the buffer
+          allocation sure, load snd-page-alloc module in the early
+          stage of boot sequence.
+
   Module snd-sa11xx-uda1341 (on arm only)
   ---------------------------------------
 
@@ -983,12 +1006,15 @@ Module parameters
     
     Note: VIA8233/5 (not VIA8233A) can support DXS (direct sound)
 	  channels as the first PCM.  With this device, up to 4
-	  streams can be played at the same time.  If the playback on
-	  this PCM is noisy, try to specify dxs_channels option to 2
-	  or 3.
+	  streams can be played at the same time.  On some motherboards,
+	  these channels don't work properly due to the bug of BIOS.
+	  If you experience that the playback on this PCM is noisy,
+	  try to specify dxs_support option to 2 or 3.  In most cases
+	  dxs_support=3 would suffice, so you can keep the multi-play
+	  capability.
 
     Note: for the MPU401 on VIA823x, use snd-mpu401 driver
-	  additonally.
+	  additonally.  The mpu_port option is for VIA686 chips only.
 
   Module snd-virmidi
   ------------------
@@ -1284,6 +1310,9 @@ Proc interfaces (/proc/asound)
 	  - direct    don't use plugins
 	  - block     force block mode (rvplayer)
 	  - non-block force non-block mode
+	  - whole-frag  write only whole fragments (optimization affecting
+			playback only)
+	  - no-silence  do not fill silence ahead to avoid clicks
 
   Example: echo "x11amp 128 16384" > /proc/asound/card0/pcm0p/oss
            echo "squake 0 0 disable" > /proc/asound/card0/pcm0c/oss
diff -puN Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl~alsa-bk-2003-07-28 Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
--- 25/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	Tue Jul 29 12:11:31 2003
@@ -239,8 +239,10 @@
     <section id="file-tree-drivers-directory">
       <title>drivers directory</title>
       <para>
-        This directory contains the non-architecture-specific
-      codes. For example, the dummy pcm driver and the serial MIDI
+        This directory contains the codes shared among different drivers
+      on the different architectures.  They are hence supposed not to be
+      architecture-specific.
+      For example, the dummy pcm driver and the serial MIDI
       driver are found in this directory. In the sub-directories,
       there are the codes for components which are independent from
       bus and cpu architectures. 
@@ -254,9 +256,9 @@
       </section>
 
       <section id="file-tree-drivers-directory-opl3">
-        <title>drivers/opl3</title>
+        <title>drivers/opl3 and opl4</title>
         <para>
-          The OPL3 FM-synth stuff is found here.
+          The OPL3 and OPL4 FM-synth stuff is found here.
         </para>
       </section>
     </section>
@@ -268,9 +270,9 @@
       </para>
 
       <para>
-        Although there is a standard i2c layer on Linux, ALSA uses its
+        Although there is a standard i2c layer on Linux, ALSA has its
       own i2c codes for some cards, because the soundcard needs only a
-      simple operation and the standard API is too complicated for
+      simple operation and the standard i2c API is too complicated for
       such a purpose. 
       </para>
 
@@ -298,7 +300,7 @@
       <title>pci directory</title>
       <para>
         This and its sub-directories hold the top-level card modules
-      for PCI soundcards. 
+      for PCI soundcards and the codes specific to the PCI BUS.
       </para>
 
       <para>
@@ -320,7 +322,7 @@
       <title>arm, ppc, and sparc directories</title>
       <para>
         These are for the top-level card modules which are
-      architecture specific. 
+      specific to each given architecture. 
       </para>
     </section>
 
@@ -3283,13 +3285,6 @@ struct _snd_pcm_runtime {
       <function>udelay()</function> or <function>mdelay()</function>.
       </para>
 
-      <para>
-      This atomicity problem appears also in the initialization of the
-      hardware when the power-management is supported.  The functions
-      for suspending and resuming the chip must be atomic, i.e. no
-      mutex nor sleep can be used in them.
-      </para>
-
     </section>
     <section id="pcm-interface-constraints">
       <title>Constraints</title>
@@ -4079,8 +4074,7 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-      These callbacks are non-atomic like the callbacks of control API
-      unless they are called during suspend/resume phase.
+      These callbacks are non-atomic like the callbacks of control API.
       </para>
 
       <para>
@@ -4094,8 +4088,6 @@ struct _snd_pcm_runtime {
         The <structfield>reset</structfield> callback is used to reset
       the codec. If the chip requires a special way of reset, you can
       define this callback. 
-      This callback must be atomic when it's called in the suspend
-      mode.
       </para>
 
       <para>
@@ -5212,6 +5204,13 @@ struct _snd_pcm_runtime {
     </para>
 
     <para>
+      For keeping the readability of 2.5 source code, it's recommended to
+      separate the above ifdef condition as the patch file in alsa-driver
+      directory.
+      See <filename>alsa-driver/pci/ali5451.c</filename> for example.
+   </para>
+
+    <para>
       The scheme of the real suspend job is as following.
 
       <orderedlist>
@@ -5383,15 +5382,6 @@ struct _snd_pcm_runtime {
       </informalexample>
     </para>
 
-    <para>
-      Last but not least: Please keep in mind that you cannot call
-    <function>schedule()</function> during the suspend and the resume
-    callbacks. If any delay is necessary, you have to use
-    <function>mdelay()</function> or <function>udelay()</function>
-    instead of <function>schedule_timeout()</function>! 
-    Of course, semaphores cannot be used, too, which will invoke sleep
-    inside.
-    </para>
   </chapter>
 
 
diff -puN include/sound/ac97_codec.h~alsa-bk-2003-07-28 include/sound/ac97_codec.h
--- 25/include/sound/ac97_codec.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/ac97_codec.h	Tue Jul 29 12:11:31 2003
@@ -229,6 +229,13 @@
 #define AC97_CM9739_SPDIF_IN_STATUS	0x68 /* 32bit */
 #define AC97_CM9739_SPDIF_CTRL	0x6c
 
+/* specific - wolfson */
+#define AC97_WM97XX_FMIXER_VOL  0x72
+#define AC97_WM9704_RMIXER_VOL  0x74
+#define AC97_WM9704_TEST        0x5a
+#define AC97_WM9704_RPCM_VOL    0x70
+#define AC97_WM9711_OUT3VOL     0x16
+
 
 /* ac97->scaps */
 #define AC97_SCAP_AUDIO		(1<<0)	/* audio AC'97 codec */
@@ -256,12 +263,20 @@
 
 typedef struct _snd_ac97 ac97_t;
 
+struct snd_ac97_build_ops {
+	int (*build_3d) (ac97_t *ac97);
+	int (*build_specific) (ac97_t *ac97);
+	int (*build_spdif) (ac97_t *ac97);
+	int (*build_post_spdif) (ac97_t *ac97);
+};
+
 struct _snd_ac97 {
 	void (*reset) (ac97_t *ac97);
 	void (*write) (ac97_t *ac97, unsigned short reg, unsigned short val);
 	unsigned short (*read) (ac97_t *ac97, unsigned short reg);
 	void (*wait) (ac97_t *ac97);
 	void (*init) (ac97_t *ac97);
+	struct snd_ac97_build_ops * build_ops;
 	void *private_data;
 	void (*private_free) (ac97_t *ac97);
 	/* --- */
diff -puN include/sound/ad1848.h~alsa-bk-2003-07-28 include/sound/ad1848.h
--- 25/include/sound/ad1848.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/ad1848.h	Tue Jul 29 12:11:31 2003
@@ -120,6 +120,12 @@
 #define AD1848_HW_AD1848	0x0002	/* AD1848 chip */
 #define AD1848_HW_CS4248	0x0003	/* CS4248 chip */
 #define AD1848_HW_CMI8330	0x0004	/* CMI8330 chip */
+#define AD1848_HW_THINKPAD	0x0005	/* Thinkpad 360/750/755 */
+
+/* IBM Thinkpad specific stuff */
+#define AD1848_THINKPAD_CTL_PORT1		0x15e8
+#define AD1848_THINKPAD_CTL_PORT2		0x15e9
+#define AD1848_THINKPAD_CS4248_ENABLE_BIT	0x02
 
 struct _snd_ad1848 {
 	unsigned long port;		/* i/o port */
@@ -140,6 +146,10 @@ struct _snd_ad1848 {
 	int mce_bit;
 	int calibrate_mute;
 	int dma_size;
+	int thinkpad_flag;		/* Thinkpad CS4248 needs some extra help */
+#ifdef CONFIG_PM
+	struct pm_dev *thinkpad_pmstate;
+#endif
 
 	spinlock_t reg_lock;
 	struct semaphore open_mutex;
diff -puN include/sound/asequencer.h~alsa-bk-2003-07-28 include/sound/asequencer.h
--- 25/include/sound/asequencer.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/asequencer.h	Tue Jul 29 12:11:31 2003
@@ -29,7 +29,7 @@
 #include <sound/asound.h>
 
 /** version of the sequencer */
-#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 0)
+#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 1)
 
 /**
  * definition of sequencer event types
@@ -57,8 +57,8 @@
 #define SNDRV_SEQ_EVENT_CHANPRESS	12
 #define SNDRV_SEQ_EVENT_PITCHBEND	13	/**< from -8192 to 8191 */
 #define SNDRV_SEQ_EVENT_CONTROL14	14	/**< 14 bit controller value */
-#define SNDRV_SEQ_EVENT_NONREGPARAM	15	/**< 14 bit NRPN */
-#define SNDRV_SEQ_EVENT_REGPARAM	16	/**< 14 bit RPN */
+#define SNDRV_SEQ_EVENT_NONREGPARAM	15	/**< 14 bit NRPN address + 14 bit unsigned value */
+#define SNDRV_SEQ_EVENT_REGPARAM	16	/**< 14 bit RPN address + 14 bit unsigned value */
 
 /** synchronisation messages
  * event data type = #sndrv_seq_ev_ctrl
@@ -604,6 +604,8 @@ struct sndrv_seq_remove_events {
 
 /* misc. conditioning flags */
 #define SNDRV_SEQ_PORT_FLG_GIVEN_PORT	(1<<0)
+#define SNDRV_SEQ_PORT_FLG_TIMESTAMP	(1<<1)
+#define SNDRV_SEQ_PORT_FLG_TIME_REAL	(1<<1)
 
 struct sndrv_seq_port_info {
 	struct sndrv_seq_addr addr;	/* client/port numbers */
@@ -620,7 +622,8 @@ struct sndrv_seq_port_info {
 
 	void *kernel;			/* reserved for kernel use (must be NULL) */
 	unsigned int flags;		/* misc. conditioning */
-	char reserved[60];		/* for future use */
+	unsigned char time_queue;	/* queue # for timestamping */
+	char reserved[59];		/* for future use */
 };
 
 
diff -puN include/sound/asound.h~alsa-bk-2003-07-28 include/sound/asound.h
--- 25/include/sound/asound.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/asound.h	Tue Jul 29 12:11:31 2003
@@ -105,9 +105,10 @@ enum sndrv_hwdep_iface {
 	SNDRV_HWDEP_IFACE_ICS2115,	/* Wavetable synth */
 	SNDRV_HWDEP_IFACE_SSCAPE,	/* Ensoniq SoundScape ISA card (MC68EC000) */
 	SNDRV_HWDEP_IFACE_VX,		/* Digigram VX cards */
+	SNDRV_HWDEP_IFACE_MIXART,	/* Digigram miXart cards */
 
 	/* Don't forget to change the following: */
-	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_VX,
+	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_MIXART,
 };
 
 struct sndrv_hwdep_info {
diff -puN include/sound/core.h~alsa-bk-2003-07-28 include/sound/core.h
--- 25/include/sound/core.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/core.h	Tue Jul 29 12:11:31 2003
@@ -222,9 +222,6 @@ typedef struct _snd_minor snd_minor_t;
 /* sound.c */
 
 extern int snd_ecards_limit;
-extern int device_mode;
-extern int device_gid;
-extern int device_uid;
 
 void snd_request_card(int card);
 
diff -puN include/sound/cs8427.h~alsa-bk-2003-07-28 include/sound/cs8427.h
--- 25/include/sound/cs8427.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/cs8427.h	Tue Jul 29 12:11:31 2003
@@ -189,6 +189,8 @@
 int snd_cs8427_detect(snd_i2c_bus_t *bus, unsigned char addr);
 int snd_cs8427_create(snd_i2c_bus_t *bus, unsigned char addr, snd_i2c_device_t **r_cs8427);
 void snd_cs8427_reset(snd_i2c_device_t *cs8427);
+int snd_cs8427_reg_write(snd_i2c_device_t *device, unsigned char reg, unsigned char val);
+int snd_cs8427_reg_read(snd_i2c_device_t *device, unsigned char reg);
 int snd_cs8427_iec958_build(snd_i2c_device_t *cs8427, snd_pcm_substream_t *playback_substream, snd_pcm_substream_t *capture_substream);
 int snd_cs8427_iec958_active(snd_i2c_device_t *cs8427, int active);
 int snd_cs8427_iec958_pcm(snd_i2c_device_t *cs8427, unsigned int rate);
diff -puN include/sound/emu10k1.h~alsa-bk-2003-07-28 include/sound/emu10k1.h
--- 25/include/sound/emu10k1.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/emu10k1.h	Tue Jul 29 12:11:31 2003
@@ -931,6 +931,7 @@ struct _snd_emu10k1 {
 	unsigned long port;			/* I/O port number */
 	struct resource *res_port;
 	int APS: 1,				/* APS flag */
+	    no_ac97: 1,				/* no AC'97 */
 	    tos_link: 1;			/* tos link detected */
 	unsigned int audigy;			/* is Audigy? */
 	unsigned int revision;			/* chip revision */
@@ -1346,10 +1347,10 @@ typedef struct {
 
 #define SNDRV_EMU10K1_IOCTL_INFO	_IOR ('H', 0x10, emu10k1_fx8010_info_t)
 #define SNDRV_EMU10K1_IOCTL_CODE_POKE	_IOW ('H', 0x11, emu10k1_fx8010_code_t)
-#define SNDRV_EMU10K1_IOCTL_CODE_PEEK	_IOW ('H', 0x12, emu10k1_fx8010_code_t)
+#define SNDRV_EMU10K1_IOCTL_CODE_PEEK	_IOWR('H', 0x12, emu10k1_fx8010_code_t)
 #define SNDRV_EMU10K1_IOCTL_TRAM_SETUP	_IOW ('H', 0x20, int)
 #define SNDRV_EMU10K1_IOCTL_TRAM_POKE	_IOW ('H', 0x21, emu10k1_fx8010_tram_t)
-#define SNDRV_EMU10K1_IOCTL_TRAM_PEEK	_IOR ('H', 0x22, emu10k1_fx8010_tram_t)
+#define SNDRV_EMU10K1_IOCTL_TRAM_PEEK	_IOWR('H', 0x22, emu10k1_fx8010_tram_t)
 #define SNDRV_EMU10K1_IOCTL_PCM_POKE	_IOW ('H', 0x30, emu10k1_fx8010_pcm_t)
 #define SNDRV_EMU10K1_IOCTL_PCM_PEEK	_IOWR('H', 0x31, emu10k1_fx8010_pcm_t)
 #define SNDRV_EMU10K1_IOCTL_STOP	_IO  ('H', 0x80)
diff -puN include/sound/hdsp.h~alsa-bk-2003-07-28 include/sound/hdsp.h
--- 25/include/sound/hdsp.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/hdsp.h	Tue Jul 29 12:11:31 2003
@@ -24,6 +24,7 @@
 typedef enum {
 	Digiface,
 	Multiface,
+	H9652,
 	Undefined,
 } HDSP_IO_Type;
 
diff -puN include/sound/info.h~alsa-bk-2003-07-28 include/sound/info.h
--- 25/include/sound/info.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/info.h	Tue Jul 29 12:11:31 2003
@@ -38,7 +38,6 @@ typedef struct snd_info_buffer snd_info_
 
 #define SNDRV_INFO_CONTENT_TEXT		0
 #define SNDRV_INFO_CONTENT_DATA		1
-#define SNDRV_INFO_CONTENT_DEVICE		2
 
 struct snd_info_entry;
 
@@ -118,10 +117,6 @@ snd_info_entry_t *snd_info_create_card_e
 					     const char *name,
 					     snd_info_entry_t * parent);
 void snd_info_free_entry(snd_info_entry_t * entry);
-snd_info_entry_t *snd_info_create_device(const char *name,
-					 unsigned int number,
-					 unsigned int mode);
-void snd_info_free_device(snd_info_entry_t * entry);
 int snd_info_store_text(snd_info_entry_t * entry);
 int snd_info_restore_text(snd_info_entry_t * entry);
 
@@ -163,10 +158,6 @@ static inline char *snd_info_get_str(cha
 static inline snd_info_entry_t *snd_info_create_module_entry(struct module * module, const char *name, snd_info_entry_t * parent) { return NULL; }
 static inline snd_info_entry_t *snd_info_create_card_entry(snd_card_t * card, const char *name, snd_info_entry_t * parent) { return NULL; }
 static inline void snd_info_free_entry(snd_info_entry_t * entry) { ; }
-static inline snd_info_entry_t *snd_info_create_device(const char *name,
-						       unsigned int number,
-						       unsigned int mode) { return NULL; }
-static inline void snd_info_free_device(snd_info_entry_t * entry) { ; }
 
 static inline int snd_info_card_create(snd_card_t * card) { return 0; }
 static inline int snd_info_card_register(snd_card_t * card) { return 0; }
diff -puN include/sound/pcm_oss.h~alsa-bk-2003-07-28 include/sound/pcm_oss.h
--- 25/include/sound/pcm_oss.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/pcm_oss.h	Tue Jul 29 12:11:31 2003
@@ -30,7 +30,9 @@ struct _snd_pcm_oss_setup {
 	unsigned int disable:1,
 		     direct:1,
 		     block:1,
-		     nonblock:1;
+		     nonblock:1,
+		     wholefrag:1,
+		     nosilence:1;
 	unsigned int periods;
 	unsigned int period_size;
 	snd_pcm_oss_setup_t *next;
diff -puN include/sound/seq_midi_event.h~alsa-bk-2003-07-28 include/sound/seq_midi_event.h
--- 25/include/sound/seq_midi_event.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/seq_midi_event.h	Tue Jul 29 12:11:31 2003
@@ -30,18 +30,16 @@ typedef struct snd_midi_event_t snd_midi
 
 /* midi status */
 struct snd_midi_event_t {
-	int qlen;	/* queue length */
-	int read;	/* chars read */
-	int type;	/* current event type */
-	unsigned char lastcmd;
-	unsigned char nostat;
-	int bufsize;
-	unsigned char *buf; /* input buffer */
+	int qlen;		/* queue length */
+	int read;		/* chars read */
+	int type;		/* current event type */
+	unsigned char lastcmd;	/* last command (for MIDI state handling) */
+	unsigned char nostat;	/* no state flag */
+	int bufsize;		/* allocated buffer size */
+	unsigned char *buf;	/* input buffer */
 	spinlock_t lock;
 };
 
-#define SND_MIDI_EVENT_NOSTATUS		(1<<0)	/* don't encode MIDI status */
-
 int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev);
 int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize);
 void snd_midi_event_free(snd_midi_event_t *dev);
diff -puN include/sound/soundfont.h~alsa-bk-2003-07-28 include/sound/soundfont.h
--- 25/include/sound/soundfont.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/soundfont.h	Tue Jul 29 12:11:31 2003
@@ -95,7 +95,6 @@ typedef struct snd_sf_list {
 	int zone_locked;	/* locked time for zone */
 	int sample_locked;	/* locked time for sample */
 	snd_sf_callback_t callback;	/* callback functions */
-	char sf_locked;		/* font lock flag */
 	struct semaphore presets_mutex;
 	spinlock_t lock;
 	snd_util_memhdr_t *memhdr;
diff -puN include/sound/version.h~alsa-bk-2003-07-28 include/sound/version.h
--- 25/include/sound/version.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/version.h	Tue Jul 29 12:11:31 2003
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "0.9.4"
-#define CONFIG_SND_DATE " (Mon Jun 09 12:01:18 2003 UTC)"
+#define CONFIG_SND_VERSION "0.9.6"
+#define CONFIG_SND_DATE " (Mon Jul 28 11:08:42 2003 UTC)"
diff -puN include/sound/ymfpci.h~alsa-bk-2003-07-28 include/sound/ymfpci.h
--- 25/include/sound/ymfpci.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/include/sound/ymfpci.h	Tue Jul 29 12:11:31 2003
@@ -25,6 +25,7 @@
 #include "pcm.h"
 #include "rawmidi.h"
 #include "ac97_codec.h"
+#include <linux/gameport.h>
 
 #ifndef PCI_VENDOR_ID_YAMAHA
 #define PCI_VENDOR_ID_YAMAHA            0x1073
@@ -309,7 +310,12 @@ struct _snd_ymfpci {
 	struct resource *mpu_res;
 
 	unsigned short old_legacy_ctrl;
+#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
 	unsigned int joystick_port;
+	struct semaphore joystick_mutex;
+	struct resource *joystick_res;
+	struct gameport gameport;
+#endif
 
 	void *work_ptr;
 	dma_addr_t work_ptr_addr;
@@ -383,7 +389,9 @@ int snd_ymfpci_pcm2(ymfpci_t *chip, int 
 int snd_ymfpci_pcm_spdif(ymfpci_t *chip, int device, snd_pcm_t **rpcm);
 int snd_ymfpci_pcm_4ch(ymfpci_t *chip, int device, snd_pcm_t **rpcm);
 int snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch);
+#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
 int snd_ymfpci_joystick(ymfpci_t *chip);
+#endif
 
 int snd_ymfpci_voice_alloc(ymfpci_t *chip, ymfpci_voice_type_t type, int pair, ymfpci_voice_t **rvoice);
 int snd_ymfpci_voice_free(ymfpci_t *chip, ymfpci_voice_t *pvoice);
diff -puN /dev/null scripts/MAKEDEV.snd
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/scripts/MAKEDEV.snd	Tue Jul 29 12:11:32 2003
@@ -0,0 +1,161 @@
+#!/bin/bash
+#
+# This script creates the proper /dev/ entries for ALSA devices.
+# See ../Documentation/sound/alsa/ALSA-Configuration.txt for more
+# information.
+
+MAJOR=116
+OSSMAJOR=14
+MAX_CARDS=4
+PERM=666
+OWNER=root.root
+
+if [ "`grep -w -E "^audio" /etc/group`x" != x ]; then
+  PERM=660
+  OWNER=root.audio
+fi
+
+function create_odevice () {
+  rm -f $1
+  echo -n "Creating $1..."
+  mknod -m $PERM $1 c $OSSMAJOR $2
+  chown $OWNER $1
+  echo " done"
+}
+
+function create_odevices () {
+  tmp=0
+  tmp1=0
+  rm -f $1 $1?
+  echo -n "Creating $1?..."
+  while [ $tmp1 -lt $MAX_CARDS ]; do
+    minor=$[ $2 + $tmp ]
+    mknod -m $PERM $1$tmp1 c $OSSMAJOR $minor
+    chown $OWNER $1$tmp1
+    tmp=$[ $tmp + 16 ]
+    tmp1=$[ $tmp1 + 1 ]
+  done
+  echo " done"
+}
+
+function create_device1 () {
+  rm -f $1
+  minor=$2
+  echo -n "Creating $1..."
+  mknod -m $PERM $1 c $MAJOR $minor
+  chown $OWNER $1
+  echo " done"
+}
+
+function create_devices () {
+  tmp=0
+  rm -f $1 $1?
+  echo -n "Creating $1?..."
+  while [ $tmp -lt $MAX_CARDS ]; do
+    minor=$[ $tmp * 32 ]
+    minor=$[ $2 + $minor ]
+    mknod -m $PERM "${1}C${tmp}" c $MAJOR $minor
+    chown $OWNER "${1}C${tmp}"
+    tmp=$[ $tmp + 1 ]
+  done
+  echo " done"
+}
+
+function create_devices2 () {
+  tmp=0
+  rm -f $1 $1?
+  echo -n "Creating $1??..."
+  while [ $tmp -lt $MAX_CARDS ]; do
+    tmp1=0
+    while [ $tmp1 -lt $3 ]; do
+      minor=$[ $tmp * 32 ]
+      minor=$[ $2 + $minor + $tmp1 ]
+      mknod -m $PERM "${1}C${tmp}D${tmp1}" c $MAJOR $minor
+      chown $OWNER "${1}C${tmp}D${tmp1}"
+      tmp1=$[ $tmp1 + 1 ]
+    done
+    tmp=$[ $tmp + 1 ]
+  done
+  echo " done"
+}
+
+function create_devices3 () {
+  tmp=0
+  rm -f $1 $1?
+  echo -n "Creating $1??$4..."
+  while [ $tmp -lt $MAX_CARDS ]; do
+    tmp1=0
+    while [ $tmp1 -lt $3 ]; do
+      minor=$[ $tmp * 32 ]
+      minor=$[ $2 + $minor + $tmp1 ]
+      mknod -m $PERM "${1}C${tmp}D${tmp1}${4}" c $MAJOR $minor
+      chown $OWNER "${1}C${tmp}D${tmp1}${4}"
+      tmp1=$[ $tmp1 + 1 ]
+    done
+    tmp=$[ $tmp + 1 ]
+  done
+  echo " done"
+}
+
+if test "$1" = "-?" || test "$1" = "-h" || test "$1" = "--help"; then
+  echo "Usage: snddevices [max]"
+  exit
+fi
+
+if test "$1" = "max"; then
+  DSP_MINOR=19
+fi
+
+# OSS (Lite) compatible devices...
+
+if test $OSSMAJOR -eq 14; then
+  create_odevices /dev/mixer		0
+  create_odevice /dev/sequencer		1
+  create_odevices /dev/midi		2
+  create_odevices /dev/dsp		3
+  create_odevices /dev/audio		4
+  create_odevice /dev/sndstat		6
+  create_odevice /dev/music		8
+  create_odevices /dev/dmmidi		9
+  create_odevices /dev/dmfm		10
+  create_odevices /dev/amixer		11	# alternate mixer
+  create_odevices /dev/adsp		12	# alternate dsp
+  create_odevices /dev/amidi		13	# alternate midi
+  create_odevices /dev/admmidi		14	# alternate direct midi
+  # create symlinks
+  ln -svf /dev/mixer0 /dev/mixer
+  ln -svf /dev/midi0 /dev/midi
+  ln -svf /dev/dsp0 /dev/dsp
+  ln -svf /dev/audio0 /dev/audio
+  ln -svf /dev/music /dev/sequencer2
+  ln -svf /dev/adsp0 /dev/adsp
+  ln -svf /dev/amidi0 /dev/amidi
+fi
+
+# Remove old devices
+
+mv -f /dev/sndstat /dev/1sndstat
+rm -f /dev/snd*
+mv -f /dev/1sndstat /dev/sndstat
+if [ -d /dev/snd ]; then
+  rm -f /dev/snd/*
+  rmdir /dev/snd
+fi
+
+# Create new ones
+
+mkdir -p /dev/snd
+create_devices  /dev/snd/control	0
+create_device1  /dev/snd/seq		1
+create_device1  /dev/snd/timer		33
+create_devices2 /dev/snd/hw		4	4
+create_devices2 /dev/snd/midi		8	8
+create_devices3 /dev/snd/pcm		16	8	p
+create_devices3 /dev/snd/pcm		24	8	c
+
+# Loader devices
+
+echo "ALSA loader devices"
+rm -f /dev/aload*
+create_devices  /dev/aload		0
+create_device1  /dev/aloadSEQ		1
diff -puN sound/core/control.c~alsa-bk-2003-07-28 sound/core/control.c
--- 25/sound/core/control.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/control.c	Tue Jul 29 12:11:31 2003
@@ -504,8 +504,10 @@ static int snd_ctl_elem_list(snd_card_t 
 			offset = 0;
 		}
 		up_read(&card->controls_rwsem);
-		if (list.used > 0 && copy_to_user(list.pids, dst, list.used * sizeof(snd_ctl_elem_id_t)))
+		if (list.used > 0 && copy_to_user(list.pids, dst, list.used * sizeof(snd_ctl_elem_id_t))) {
+			vfree(dst);
 			return -EFAULT;
+		}
 		vfree(dst);
 	} else {
 		down_read(&card->controls_rwsem);
diff -puN sound/core/info.c~alsa-bk-2003-07-28 sound/core/info.c
--- 25/sound/core/info.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/info.c	Tue Jul 29 12:11:31 2003
@@ -115,7 +115,7 @@ int snd_iprintf(snd_info_buffer_t * buff
 
  */
 
-struct proc_dir_entry *snd_proc_root = NULL;
+static struct proc_dir_entry *snd_proc_root = NULL;
 snd_info_entry_t *snd_seq_root = NULL;
 #ifdef CONFIG_SND_OSSEMUL
 snd_info_entry_t *snd_oss_root = NULL;
@@ -278,18 +278,16 @@ static int snd_info_entry_open(struct in
 		if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
 		     !entry->c.text.read_size) ||
 		    (entry->content == SNDRV_INFO_CONTENT_DATA &&
-		     entry->c.ops->read == NULL) ||
-		    entry->content == SNDRV_INFO_CONTENT_DEVICE) {
+		     entry->c.ops->read == NULL)) {
 		    	err = -ENODEV;
 		    	goto __error;
 		}
 	}
 	if (mode == O_WRONLY || mode == O_RDWR) {
 		if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
-					!entry->c.text.write_size) ||
+		     !entry->c.text.write_size) ||
 		    (entry->content == SNDRV_INFO_CONTENT_DATA &&
-		    			entry->c.ops->write == NULL) ||
-		    entry->content == SNDRV_INFO_CONTENT_DEVICE) {
+		     entry->c.ops->write == NULL)) {
 		    	err = -ENODEV;
 		    	goto __error;
 		}
diff -puN sound/core/ioctl32/ioctl32.c~alsa-bk-2003-07-28 sound/core/ioctl32/ioctl32.c
--- 25/sound/core/ioctl32/ioctl32.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/ioctl32/ioctl32.c	Tue Jul 29 12:11:31 2003
@@ -419,13 +419,13 @@ extern struct ioctl32_mapper pcm_mappers
 extern struct ioctl32_mapper rawmidi_mappers[];
 extern struct ioctl32_mapper timer_mappers[];
 extern struct ioctl32_mapper hwdep_mappers[];
-#ifdef CONFIG_SND_SEQUENCER
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 extern struct ioctl32_mapper seq_mappers[];
 #endif
 
 static void snd_ioctl32_done(void)
 {
-#ifdef CONFIG_SND_SEQUENCER
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	snd_ioctl32_unregister(seq_mappers);
 #endif
 	snd_ioctl32_unregister(hwdep_mappers);
@@ -442,7 +442,7 @@ static int __init snd_ioctl32_init(void)
 	snd_ioctl32_register(rawmidi_mappers);
 	snd_ioctl32_register(timer_mappers);
 	snd_ioctl32_register(hwdep_mappers);
-#ifdef CONFIG_SND_SEQUENCER
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	snd_ioctl32_register(seq_mappers);
 #endif
 	return 0;
diff -puN sound/core/memalloc.c~alsa-bk-2003-07-28 sound/core/memalloc.c
--- 25/sound/core/memalloc.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/memalloc.c	Tue Jul 29 12:11:31 2003
@@ -37,18 +37,12 @@ MODULE_DESCRIPTION("Memory allocator for
 MODULE_LICENSE("GPL");
 
 
-/* so far, pre-defined allocation is only for hammerfall cards... */
-/* #define ENABLE_PREALLOC */
-
-
-#ifdef ENABLE_PREALLOC
 #ifndef SNDRV_CARDS
 #define SNDRV_CARDS	8
 #endif
 static int enable[8] = {[0 ... (SNDRV_CARDS-1)] = 1};
 MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(enable, "Enable cards to allocate buffers.");
-#endif
 
 
 /*
@@ -154,6 +148,7 @@ static int compare_device(const struct s
 		return a->dev.flags == b->dev.flags;
 #ifdef CONFIG_PCI
 	case SNDRV_DMA_TYPE_PCI:
+	case SNDRV_DMA_TYPE_PCI_SG:
 		return a->dev.pci == b->dev.pci;
 #endif
 #ifdef CONFIG_SBUS
@@ -336,7 +331,7 @@ int snd_dma_free_reserved(const struct s
  * and replaced with the new one.
  *
  * When NULL buffer pointer or zero buffer size is given, the existing
- * release buffer is released and the entry is removed.
+ * buffer is released and the entry is removed.
  * 
  * Returns zero if successful, or a negative code at error.
  */
@@ -785,7 +780,6 @@ void snd_free_sbus_pages(struct sbus_dev
 #endif /* CONFIG_SBUS */
 
 
-#ifdef ENABLE_PREALLOC
 /*
  * allocation of buffers for pre-defined devices
  */
@@ -861,7 +855,6 @@ static void __init preallocate_cards(voi
 		}
 	}
 }
-#endif
 
 
 #ifdef CONFIG_PROC_FS
@@ -873,9 +866,56 @@ static int snd_mem_proc_read(char *page,
 {
 	int len = 0;
 	long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
+	struct list_head *p;
+	struct snd_mem_list *mem;
+	int devno;
 
+	down(&list_mutex);
 	len += sprintf(page + len, "pages  : %li bytes (%li pages per %likB)\n",
 		       pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
+	devno = 0;
+	list_for_each(p, &mem_list_head) {
+		mem = list_entry(p, struct snd_mem_list, list);
+		devno++;
+		len += sprintf(page + len, "buffer %d : ", devno);
+		if (mem->dev.id == SNDRV_DMA_DEVICE_UNUSED)
+			len += sprintf(page + len, "UNUSED");
+		else
+			len += sprintf(page + len, "ID %08x", mem->dev.id);
+		len += sprintf(page + len, " : type ");
+		switch (mem->dev.type) {
+		case SNDRV_DMA_TYPE_CONTINUOUS:
+			len += sprintf(page + len, "CONT [%x]", mem->dev.dev.flags);
+			break;
+#ifdef CONFIG_PCI
+		case SNDRV_DMA_TYPE_PCI:
+		case SNDRV_DMA_TYPE_PCI_SG:
+			if (mem->dev.dev.pci) {
+				len += sprintf(page + len, "PCI [%04x:%04x]",
+					       mem->dev.dev.pci->vendor,
+					       mem->dev.dev.pci->device);
+			}
+			break;
+#endif
+#ifdef CONFIG_ISA
+		case SNDRV_DMA_TYPE_ISA:
+			len += sprintf(page + len, "ISA [%x]", mem->dev.dev.flags);
+			break;
+#endif
+#ifdef CONFIG_SBUS
+		case SNDRV_DMA_TYPE_SBUS:
+			len += sprintf(page + len, "SBUS [%x]", mem->dev.dev.sbus->slot);
+			break;
+#endif
+		default:
+			len += sprintf(page + len, "UNKNOWN");
+			break;
+		}
+		len += sprintf(page + len, "\n  addr = 0x%lx, size = %d bytes, used = %s\n",
+			       (unsigned long)mem->buffer.addr, (int)mem->buffer.bytes,
+			       mem->used ? "yes" : "no");
+	}
+	up(&list_mutex);
 	return len;
 }
 #endif /* CONFIG_PROC_FS */
@@ -886,10 +926,10 @@ static int snd_mem_proc_read(char *page,
 
 static int __init snd_mem_init(void)
 {
+#ifdef CONFIG_PROC_FS
 	create_proc_read_entry("driver/snd-page-alloc", 0, 0, snd_mem_proc_read, NULL);
-#ifdef ENABLE_PREALLOC
-	preallocate_cards();
 #endif
+	preallocate_cards();
 	return 0;
 }
 
@@ -906,6 +946,25 @@ module_init(snd_mem_init)
 module_exit(snd_mem_exit)
 
 
+#ifndef MODULE
+
+/* format is: snd-page-alloc=enable */
+
+static int __init snd_mem_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&enable[nr_dev]) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-page-alloc=", snd_mem_setup);
+
+#endif
+
 /*
  * exports
  */
diff -puN sound/core/oss/pcm_oss.c~alsa-bk-2003-07-28 sound/core/oss/pcm_oss.c
--- 25/sound/core/oss/pcm_oss.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/oss/pcm_oss.c	Tue Jul 29 12:11:31 2003
@@ -22,6 +22,9 @@
 #if 0
 #define PLUGIN_DEBUG
 #endif
+#if 0
+#define OSS_DEBUG
+#endif
 
 #include <sound/driver.h>
 #include <linux/version.h>
@@ -442,7 +445,7 @@ static int snd_pcm_oss_change_params(snd
 	} else {
 		sw_params->start_threshold = runtime->boundary;
 	}
-	if (atomic_read(&runtime->mmap_count))
+	if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		sw_params->stop_threshold = runtime->boundary;
 	else
 		sw_params->stop_threshold = runtime->buffer_size;
@@ -451,8 +454,18 @@ static int snd_pcm_oss_change_params(snd
 	sw_params->sleep_min = 0;
 	sw_params->avail_min = runtime->period_size;
 	sw_params->xfer_align = 1;
-	sw_params->silence_threshold = 0;
-	sw_params->silence_size = 0;
+	if (atomic_read(&runtime->mmap_count) ||
+	    (substream->oss.setup && substream->oss.setup->nosilence)) {
+		sw_params->silence_threshold = 0;
+		sw_params->silence_size = 0;
+	} else {
+		snd_pcm_uframes_t frames;
+		frames = runtime->period_size + 16;
+		if (frames > runtime->buffer_size)
+			frames = runtime->buffer_size;
+		sw_params->silence_threshold = frames;
+		sw_params->silence_size = frames;
+	}
 
 	if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
 		snd_printd("SW_PARAMS failed: %i\n", err);
@@ -567,6 +580,31 @@ static int snd_pcm_oss_make_ready(snd_pc
 	return 0;
 }
 
+static int snd_pcm_oss_capture_position_fixup(snd_pcm_substream_t *substream, snd_pcm_sframes_t *delay)
+{
+	snd_pcm_runtime_t *runtime;
+	snd_pcm_uframes_t frames;
+	int err = 0;
+
+	while (1) {
+		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, delay);
+		if (err < 0)
+			break;
+		runtime = substream->runtime;
+		if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size)
+			break;
+		/* in case of overrun, skip whole periods like OSS/Linux driver does */
+		/* until avail(delay) <= buffer_size */
+		frames = (*delay - runtime->buffer_size) + runtime->period_size - 1;
+		frames /= runtime->period_size;
+		frames *= runtime->period_size;
+		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_FORWARD, &frames);
+		if (err < 0)
+			break;
+	}
+	return err;
+}
+
 snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
@@ -574,6 +612,12 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd
 	while (1) {
 		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
 		    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+#ifdef OSS_DEBUG
+			if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
+				printk("pcm_oss: write: recovering from XRUN\n");
+			else
+				printk("pcm_oss: write: recovering from SUSPEND\n");
+#endif
 			ret = snd_pcm_oss_prepare(substream);
 			if (ret < 0)
 				break;
@@ -599,10 +643,17 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd
 snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_pcm_sframes_t delay;
 	int ret;
 	while (1) {
 		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
 		    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+#ifdef OSS_DEBUG
+			if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
+				printk("pcm_oss: read: recovering from XRUN\n");
+			else
+				printk("pcm_oss: read: recovering from SUSPEND\n");
+#endif
 			ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, 0);
 			if (ret < 0)
 				break;
@@ -611,6 +662,9 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_
 			if (ret < 0)
 				break;
 		}
+		ret = snd_pcm_oss_capture_position_fixup(substream, &delay);
+		if (ret < 0)
+			break;
 		if (in_kernel) {
 			mm_segment_t fs;
 			fs = snd_enter_user();
@@ -640,6 +694,12 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(sn
 	while (1) {
 		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
 		    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+#ifdef OSS_DEBUG
+			if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
+				printk("pcm_oss: writev: recovering from XRUN\n");
+			else
+				printk("pcm_oss: writev: recovering from SUSPEND\n");
+#endif
 			ret = snd_pcm_oss_prepare(substream);
 			if (ret < 0)
 				break;
@@ -670,6 +730,12 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(snd
 	while (1) {
 		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
 		    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+#ifdef OSS_DEBUG
+			if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
+				printk("pcm_oss: readv: recovering from XRUN\n");
+			else
+				printk("pcm_oss: readv: recovering from SUSPEND\n");
+#endif
 			ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, 0);
 			if (ret < 0)
 				break;
@@ -746,8 +812,9 @@ static ssize_t snd_pcm_oss_write1(snd_pc
 			buf += tmp;
 			bytes -= tmp;
 			xfer += tmp;
-			if (runtime->oss.buffer_used == runtime->oss.period_bytes) {
-				tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
+			if (substream->oss.setup == NULL || !substream->oss.setup->wholefrag ||
+			    runtime->oss.buffer_used == runtime->oss.period_bytes) {
+				tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.buffer_used, 1);
 				if (tmp <= 0)
 					return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
 				runtime->oss.bytes += tmp;
@@ -855,6 +922,22 @@ static int snd_pcm_oss_reset(snd_pcm_oss
 	return 0;
 }
 
+static int snd_pcm_oss_post(snd_pcm_oss_file_t *pcm_oss_file)
+{
+	snd_pcm_substream_t *substream;
+	int err;
+
+	substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
+	if (substream != NULL) {
+		if ((err = snd_pcm_oss_make_ready(substream)) < 0)
+			return err;
+		snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_START, 0);
+	}
+	/* note: all errors from the start action are ignored */
+	/* OSS apps do not know, how to handle them */
+	return 0;
+}
+
 static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file)
 {
 	int err = 0;
@@ -1188,6 +1271,10 @@ static int snd_pcm_oss_set_trigger(snd_p
 	snd_pcm_runtime_t *runtime;
 	snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL;
 	int err, cmd;
+
+#ifdef OSS_DEBUG
+	printk("pcm_oss: trigger = 0x%x\n", trigger);
+#endif
 	
 	psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
 	csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
@@ -1288,7 +1375,7 @@ static int snd_pcm_oss_get_ptr(snd_pcm_o
 {	
 	snd_pcm_substream_t *substream;
 	snd_pcm_runtime_t *runtime;
-	snd_pcm_status_t status;
+	snd_pcm_sframes_t delay;
 	struct count_info info;
 	int err;
 
@@ -1306,14 +1393,17 @@ static int snd_pcm_oss_get_ptr(snd_pcm_o
 			return -EFAULT;
 		return 0;
 	}
-	memset(&status, 0, sizeof(status));
-	err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_STATUS, &status);
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
+	} else {
+		err = snd_pcm_oss_capture_position_fixup(substream, &delay);
+	}
 	if (err < 0)
 		return err;
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		info.bytes = runtime->oss.bytes - snd_pcm_oss_bytes(substream, runtime->buffer_size - status.avail);
+		info.bytes = runtime->oss.bytes - snd_pcm_oss_bytes(substream, delay);
 	} else {
-		info.bytes = runtime->oss.bytes + snd_pcm_oss_bytes(substream, status.avail);
+		info.bytes = runtime->oss.bytes + snd_pcm_oss_bytes(substream, delay);
 	}
 	info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
 	if (atomic_read(&runtime->mmap_count)) {
@@ -1326,10 +1416,7 @@ static int snd_pcm_oss_get_ptr(snd_pcm_o
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			snd_pcm_oss_simulate_fill(substream);
 	} else {
-		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-			info.blocks = (runtime->buffer_size - status.avail) / runtime->period_size;
-		else
-			info.blocks = status.avail / runtime->period_size;
+		info.blocks = delay / runtime->period_size;
 	}
 	if (copy_to_user(_info, &info, sizeof(info)))
 		return -EFAULT;
@@ -1340,7 +1427,7 @@ static int snd_pcm_oss_get_space(snd_pcm
 {
 	snd_pcm_substream_t *substream;
 	snd_pcm_runtime_t *runtime;
-	snd_pcm_status_t status;
+	snd_pcm_sframes_t avail;
 	struct audio_buf_info info;
 	int err;
 
@@ -1357,7 +1444,6 @@ static int snd_pcm_oss_get_space(snd_pcm
 
 	info.fragsize = runtime->oss.period_bytes;
 	info.fragstotal = runtime->periods;
-	memset(&status, 0, sizeof(status));
 	if (runtime->oss.prepare) {
 		if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
 			info.bytes = runtime->oss.period_bytes * runtime->periods;
@@ -1367,21 +1453,21 @@ static int snd_pcm_oss_get_space(snd_pcm
 			info.fragments = 0;
 		}
 	} else {
-		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_STATUS, &status);
+		if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &avail);
+			avail = runtime->buffer_size - avail;
+		} else {
+			err = snd_pcm_oss_capture_position_fixup(substream, &avail);
+		}
 		if (err < 0)
 			return err;
-		info.bytes = snd_pcm_oss_bytes(substream, status.avail);
-		info.fragments = status.avail / runtime->period_size;
+		info.bytes = snd_pcm_oss_bytes(substream, avail);
+		info.fragments = avail / runtime->period_size;
 	}
 
-#if 0
-	/* very experimental stuff to get Quake2 working */
-	runtime->oss.period = (info.periods - 1) << 16;
-	for (tmp = info.fragsize; tmp > 1; tmp >>= 1)
-		runtime->oss.period++;
-	runtime->oss.subdivision = 1;	/* disable SUBDIVIDE */
+#ifdef OSS_DEBUG
+	printk("pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.fragments, info.fragstotal, info.fragsize);
 #endif
-	// printk("space: bytes = %i, periods = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.periods, info.fragstotal, info.fragsize);
 	if (copy_to_user(_info, &info, sizeof(info)))
 		return -EFAULT;
 	return 0;
@@ -1727,6 +1813,9 @@ static int snd_pcm_oss_ioctl(struct inod
 #endif
 	if (((cmd >> 8) & 0xff) != 'P')
 		return -EINVAL;
+#ifdef OSS_DEBUG
+	printk("pcm_oss: ioctl = 0x%x\n", cmd);
+#endif
 	switch (cmd) {
 	case SNDCTL_DSP_RESET:
 		return snd_pcm_oss_reset(pcm_oss_file);
@@ -1782,8 +1871,8 @@ static int snd_pcm_oss_ioctl(struct inod
 	case SOUND_PCM_WRITE_FILTER:
 	case SOUND_PCM_READ_FILTER:
 		return -EIO;
-	case SNDCTL_DSP_POST:	/* to do */
-		return 0;
+	case SNDCTL_DSP_POST:
+		return snd_pcm_oss_post(pcm_oss_file);
 	case SNDCTL_DSP_SUBDIVIDE:
 		if (get_user(res, (int *)arg))
 			return -EFAULT;
@@ -1866,7 +1955,15 @@ static ssize_t snd_pcm_oss_read(struct f
 	substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
 	if (substream == NULL)
 		return -ENXIO;
+#ifndef OSS_DEBUG
 	return snd_pcm_oss_read1(substream, buf, count);
+#else
+	{
+		ssize_t res = snd_pcm_oss_read1(substream, buf, count);
+		printk("pcm_oss: read %li bytes (returned %li bytes)\n", (long)count, (long)res);
+		return res;
+	}
+#endif
 }
 
 static ssize_t snd_pcm_oss_write(struct file *file, const char *buf, size_t count, loff_t *offset)
@@ -1882,6 +1979,9 @@ static ssize_t snd_pcm_oss_write(struct 
 	up(&file->f_dentry->d_inode->i_sem);
 	result = snd_pcm_oss_write1(substream, buf, count);
 	down(&file->f_dentry->d_inode->i_sem);
+#ifdef OSS_DEBUG
+	printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
+#endif
 	return result;
 }
 
@@ -1927,12 +2027,20 @@ static unsigned int snd_pcm_oss_poll(str
 	}
 	if (csubstream != NULL) {
 		snd_pcm_runtime_t *runtime = csubstream->runtime;
+		enum sndrv_pcm_state ostate;
 		poll_wait(file, &runtime->sleep, wait);
 		snd_pcm_stream_lock_irq(csubstream);
-		if (runtime->status->state != SNDRV_PCM_STATE_RUNNING ||
+		if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING ||
 		    snd_pcm_oss_capture_ready(csubstream))
 			mask |= POLLIN | POLLRDNORM;
 		snd_pcm_stream_unlock_irq(csubstream);
+		if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
+			snd_pcm_oss_file_t ofile;
+			memset(&ofile, 0, sizeof(ofile));
+			ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
+			runtime->oss.trigger = 0;
+			snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT);
+		}
 	}
 
 	return mask;
@@ -1945,6 +2053,9 @@ static int snd_pcm_oss_mmap(struct file 
 	snd_pcm_runtime_t *runtime;
 	int err;
 
+#ifdef OSS_DEBUG
+	printk("pcm_oss: mmap begin\n");
+#endif
 	pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO);
 	switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
 	case VM_READ | VM_WRITE:
@@ -1988,6 +2099,9 @@ static int snd_pcm_oss_mmap(struct file 
 	if (err < 0)
 		return err;
 	runtime->oss.mmap_bytes = area->vm_end - area->vm_start;
+#ifdef OSS_DEBUG
+	printk("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes);
+#endif
 	/* In mmap mode we never stop */
 	runtime->stop_threshold = runtime->boundary;
 
@@ -2005,14 +2119,16 @@ static void snd_pcm_oss_proc_read(snd_in
 	snd_pcm_oss_setup_t *setup = pstr->oss.setup_list;
 	down(&pstr->oss.setup_mutex);
 	while (setup) {
-		snd_iprintf(buffer, "%s %u %u%s%s%s%s\n",
+		snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
 			    setup->task_name,
 			    setup->periods,
 			    setup->period_size,
 			    setup->disable ? " disable" : "",
 			    setup->direct ? " direct" : "",
 			    setup->block ? " block" : "",
-			    setup->nonblock ? " non-block" : "");
+			    setup->nonblock ? " non-block" : "",
+			    setup->wholefrag ? " whole-frag" : "",
+			    setup->nosilence ? " no-silence" : "");
 		setup = setup->next;
 	}
 	up(&pstr->oss.setup_mutex);
@@ -2078,6 +2194,10 @@ static void snd_pcm_oss_proc_write(snd_i
 				template.block = 1;
 			} else if (!strcmp(str, "non-block")) {
 				template.nonblock = 1;
+			} else if (!strcmp(str, "whole-frag")) {
+				template.wholefrag = 1;
+			} else if (!strcmp(str, "no-silence")) {
+				template.nosilence = 1;
 			}
 		} while (*str);
 		if (setup == NULL) {
@@ -2269,3 +2389,24 @@ static void __exit alsa_pcm_oss_exit(voi
 
 module_init(alsa_pcm_oss_init)
 module_exit(alsa_pcm_oss_exit)
+
+#ifndef MODULE
+
+/* format is: snd-pcm-oss=dsp_map,adsp_map[,nonblock_open] */
+
+static int __init alsa_pcm_oss_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&dsp_map[nr_dev]) == 2 &&
+	       get_option(&str,&adsp_map[nr_dev]) == 2);
+	(void)(get_option(&str,&nonblock_open) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-pcm-oss=", alsa_pcm_oss_setup);
+
+#endif /* !MODULE */
diff -puN sound/core/oss/pcm_plugin.c~alsa-bk-2003-07-28 sound/core/oss/pcm_plugin.c
--- 25/sound/core/oss/pcm_plugin.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/oss/pcm_plugin.c	Tue Jul 29 12:11:31 2003
@@ -56,6 +56,17 @@ static int snd_pcm_plugin_dst_channels_m
 	return 0;
 }
 
+/*
+ *  because some cards might have rates "very close", we ignore
+ *  all "resampling" requests within +-5%
+ */
+static int rate_match(unsigned int src_rate, unsigned int dst_rate)
+{
+	unsigned int low = (src_rate * 95) / 100;
+	unsigned int high = (src_rate * 105) / 100;
+	return dst_rate >= low && dst_rate <= high;
+}
+
 static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames)
 {
 	snd_pcm_plugin_format_t *format;
@@ -80,11 +91,14 @@ static int snd_pcm_plugin_alloc(snd_pcm_
 		plugin->buf = vmalloc(size);
 		plugin->buf_frames = frames;
 	}
-	if (!plugin->buf)
+	if (!plugin->buf) {
+		plugin->buf_frames = 0;
 		return -ENOMEM;
+	}
 	c = plugin->buf_channels;
 	if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
 		for (channel = 0; channel < format->channels; channel++, c++) {
+			c->frames = frames;
 			c->enabled = 1;
 			c->wanted = 0;
 			c->area.addr = plugin->buf;
@@ -95,6 +109,7 @@ static int snd_pcm_plugin_alloc(snd_pcm_
 		snd_assert((size % format->channels) == 0,);
 		size /= format->channels;
 		for (channel = 0; channel < format->channels; channel++, c++) {
+			c->frames = frames;
 			c->enabled = 1;
 			c->wanted = 0;
 			c->area.addr = plugin->buf + (channel * size);
@@ -420,7 +435,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_
 
 	/* Format change (linearization) */
 	if ((srcformat.format != dstformat.format ||
-	     srcformat.rate != dstformat.rate ||
+	     !rate_match(srcformat.rate, dstformat.rate) ||
 	     srcformat.channels != dstformat.channels) &&
 	    !snd_pcm_format_linear(srcformat.format)) {
 		if (snd_pcm_format_linear(dstformat.format))
@@ -468,7 +483,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_
 				ttable[v * sv + v] = FULL;
 		}
 		tmpformat.channels = dstformat.channels;
-		if (srcformat.rate == dstformat.rate &&
+		if (rate_match(srcformat.rate, dstformat.rate) &&
 		    snd_pcm_format_linear(dstformat.format))
 			tmpformat.format = dstformat.format;
 		err = snd_pcm_plugin_build_route(plug,
@@ -490,7 +505,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_
 	}
 
 	/* rate resampling */
-	if (srcformat.rate != dstformat.rate) {
+	if (!rate_match(srcformat.rate, dstformat.rate)) {
 		tmpformat.rate = dstformat.rate;
 		if (srcformat.channels == dstformat.channels &&
 		    snd_pcm_format_linear(dstformat.format))
diff -puN sound/core/oss/pcm_plugin.h~alsa-bk-2003-07-28 sound/core/oss/pcm_plugin.h
--- 25/sound/core/oss/pcm_plugin.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/oss/pcm_plugin.h	Tue Jul 29 12:11:31 2003
@@ -106,6 +106,7 @@ typedef struct _snd_pcm_channel_area {
 typedef struct _snd_pcm_plugin_channel {
 	void *aptr;			/* pointer to the allocated area */
 	snd_pcm_channel_area_t area;
+	snd_pcm_uframes_t frames;	/* allocated frames */
 	unsigned int enabled:1;		/* channel need to be processed */
 	unsigned int wanted:1;		/* channel is wanted */
 } snd_pcm_plugin_channel_t;
diff -puN sound/core/oss/plugin_ops.h~alsa-bk-2003-07-28 sound/core/oss/plugin_ops.h
--- 25/sound/core/oss/plugin_ops.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/oss/plugin_ops.h	Tue Jul 29 12:11:31 2003
@@ -323,7 +323,7 @@ get_s16_1234_xxC3: sample = swab16(as_u3
 
 #ifdef PUT_S16_LABELS
 /* dst_wid dst_endswap unsigned */
-static void *put_s16_labels[4 * 2 * 2 * 4 * 2] = {
+static void *put_s16_labels[4 * 2 * 2] = {
 	&&put_s16_xx12_xxx1,	 /* 16h ->  8h */
 	&&put_s16_xx12_xxx9,	 /* 16h ^>  8h */
 	&&put_s16_xx12_xxx1,	 /* 16h ->  8s */
diff -puN sound/core/oss/rate.c~alsa-bk-2003-07-28 sound/core/oss/rate.c
--- 25/sound/core/oss/rate.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/oss/rate.c	Tue Jul 29 12:11:31 2003
@@ -85,11 +85,7 @@ static void resample_expand(snd_pcm_plug
 #undef PUT_S16_LABELS
 	void *get = get_s16_labels[data->get];
 	void *put = put_s16_labels[data->put];
-	void *get_s16_end = 0;
 	signed short sample = 0;
-#define GET_S16_END *get_s16_end
-#include "plugin_ops.h"
-#undef GET_S16_END
 	
 	for (channel = 0; channel < plugin->src_format.channels; channel++) {
 		pos = data->pos;
@@ -108,24 +104,16 @@ static void resample_expand(snd_pcm_plug
 		dst_step = dst_channels[channel].area.step / 8;
 		src_frames1 = src_frames;
 		dst_frames1 = dst_frames;
-		if (pos & ~R_MASK) {
-			get_s16_end = &&after_get1;
-			goto *get;
-		after_get1:
-			pos &= R_MASK;
-			S1 = S2;
-			S2 = sample;
-			src += src_step;
-			src_frames1--;
-		}
 		while (dst_frames1-- > 0) {
 			if (pos & ~R_MASK) {
 				pos &= R_MASK;
 				S1 = S2;
 				if (src_frames1-- > 0) {
-					get_s16_end = &&after_get2;
 					goto *get;
-				after_get2:
+#define GET_S16_END after_get
+#include "plugin_ops.h"
+#undef GET_S16_END
+				after_get:
 					S2 = sample;
 					src += src_step;
 				}
@@ -318,6 +306,8 @@ static snd_pcm_sframes_t rate_transfer(s
 #endif
 
 	dst_frames = rate_dst_frames(plugin, frames);
+	if (dst_frames > dst_channels[0].frames)
+		dst_frames = dst_channels[0].frames;
 	data = (rate_t *)plugin->extra_data;
 	data->func(plugin, src_channels, dst_channels, frames, dst_frames);
 	return dst_frames;
diff -puN sound/core/oss/route.c~alsa-bk-2003-07-28 sound/core/oss/route.c
--- 25/sound/core/oss/route.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/oss/route.c	Tue Jul 29 12:11:31 2003
@@ -518,6 +518,10 @@ int getput_index(int format)
 	int sign, width, endian;
 	sign = !snd_pcm_format_signed(format);
 	width = snd_pcm_format_width(format) / 8 - 1;
+	if (width < 0 || width > 3) {
+		snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format);
+		width = 0;
+	}
 #ifdef SNDRV_LITTLE_ENDIAN
 	endian = snd_pcm_format_big_endian(format);
 #else
diff -puN sound/core/pcm_lib.c~alsa-bk-2003-07-28 sound/core/pcm_lib.c
--- 25/sound/core/pcm_lib.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/pcm_lib.c	Tue Jul 29 12:11:31 2003
@@ -60,7 +60,7 @@ void snd_pcm_playback_silence(snd_pcm_su
 			return;
 		snd_assert(runtime->silence_filled <= runtime->buffer_size, return);
 		noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
-		if (noise_dist > (snd_pcm_sframes_t) runtime->silence_threshold)
+		if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
 			return;
 		frames = runtime->silence_threshold - noise_dist;
 		if (frames > runtime->silence_size)
@@ -84,10 +84,9 @@ void snd_pcm_playback_silence(snd_pcm_su
 			if ((snd_pcm_sframes_t)runtime->silence_start < 0)
 				runtime->silence_start += runtime->boundary;
 		}
-		frames = runtime->buffer_size;
+		frames = runtime->buffer_size - runtime->silence_filled;
 	}
-	snd_assert(frames >= runtime->silence_filled, return);
-	frames -= runtime->silence_filled;
+	snd_assert(frames <= runtime->buffer_size, return);
 	if (frames == 0)
 		return;
 	ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size;
@@ -1932,7 +1931,7 @@ void snd_pcm_tick_prepare(snd_pcm_substr
 		if (runtime->silence_size >= runtime->boundary) {
 			frames = 1;
 		} else if (runtime->silence_size > 0 &&
-		    runtime->silence_filled < runtime->buffer_size) {
+			   runtime->silence_filled < runtime->buffer_size) {
 			snd_pcm_sframes_t noise_dist;
 			noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
 			snd_assert(noise_dist <= (snd_pcm_sframes_t)runtime->silence_threshold, );
diff -puN sound/core/pcm_memory.c~alsa-bk-2003-07-28 sound/core/pcm_memory.c
--- 25/sound/core/pcm_memory.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/pcm_memory.c	Tue Jul 29 12:11:31 2003
@@ -22,6 +22,7 @@
 #include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/time.h>
+#include <linux/init.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/info.h>
@@ -568,3 +569,18 @@ struct page *snd_pcm_sgbuf_ops_page(snd_
 }
 
 #endif /* CONFIG_PCI */
+
+#ifndef MODULE
+
+/* format is: snd-pcm=preallocate_dma,maximum_substreams */
+
+static int __init alsa_pcm_setup(char *str)
+{
+	(void)(get_option(&str,&preallocate_dma) == 2 &&
+	       get_option(&str,&maximum_substreams) == 2);
+	return 1;
+}
+
+__setup("snd-pcm=", alsa_pcm_setup);
+
+#endif /* ifndef MODULE */
diff -puN sound/core/pcm_native.c~alsa-bk-2003-07-28 sound/core/pcm_native.c
--- 25/sound/core/pcm_native.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/pcm_native.c	Tue Jul 29 12:11:31 2003
@@ -461,9 +461,15 @@ static int snd_pcm_sw_params(snd_pcm_sub
 	if (params->xfer_align == 0 ||
 	    params->xfer_align % runtime->min_align != 0)
 		return -EINVAL;
-	if ((params->silence_threshold != 0 || params->silence_size < runtime->boundary) &&
-	    (params->silence_threshold + params->silence_size > runtime->buffer_size))
-		return -EINVAL;
+	if (params->silence_size >= runtime->boundary) {
+		if (params->silence_threshold != 0)
+			return -EINVAL;
+	} else {
+		if (params->silence_size > params->silence_threshold)
+			return -EINVAL;
+		if (params->silence_threshold > runtime->buffer_size)
+			return -EINVAL;
+	}
 	snd_pcm_stream_lock_irq(substream);
 	runtime->tstamp_mode = params->tstamp_mode;
 	runtime->sleep_min = params->sleep_min;
diff -puN sound/core/rawmidi.c~alsa-bk-2003-07-28 sound/core/rawmidi.c
--- 25/sound/core/rawmidi.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/rawmidi.c	Tue Jul 29 12:11:31 2003
@@ -1437,7 +1437,7 @@ static int snd_rawmidi_dev_free(snd_devi
 	return snd_rawmidi_free(rmidi);
 }
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 static void snd_rawmidi_dev_seq_free(snd_seq_device_t *device)
 {
 	snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->private_data, return);
@@ -1513,7 +1513,7 @@ static int snd_rawmidi_dev_register(snd_
 		}
 	}
 	rmidi->proc_entry = entry;
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */
 		if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) {
 			rmidi->seq_dev->private_data = rmidi;
@@ -1568,7 +1568,7 @@ static int snd_rawmidi_dev_unregister(sn
 		rmidi->ops->dev_unregister(rmidi);
 	snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
 	up(&register_mutex);
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if (rmidi->seq_dev) {
 		snd_device_free(rmidi->card, rmidi->seq_dev);
 		rmidi->seq_dev = NULL;
@@ -1630,6 +1630,26 @@ static void __exit alsa_rawmidi_exit(voi
 module_init(alsa_rawmidi_init)
 module_exit(alsa_rawmidi_exit)
 
+#ifndef MODULE
+#ifdef CONFIG_SND_OSSEMUL
+/* format is: snd-rawmidi=midi_map,amidi_map */
+
+static int __init alsa_rawmidi_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&midi_map[nr_dev]) == 2 &&
+	       get_option(&str,&amidi_map[nr_dev]) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-rawmidi=", alsa_rawmidi_setup);
+#endif /* CONFIG_SND_OSSEMUL */
+#endif /* ifndef MODULE */
+
 EXPORT_SYMBOL(snd_rawmidi_output_params);
 EXPORT_SYMBOL(snd_rawmidi_input_params);
 EXPORT_SYMBOL(snd_rawmidi_drop_output);
diff -puN sound/core/rtctimer.c~alsa-bk-2003-07-28 sound/core/rtctimer.c
--- 25/sound/core/rtctimer.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/rtctimer.c	Tue Jul 29 12:11:31 2003
@@ -57,7 +57,7 @@ static struct _snd_timer_hardware rtc_hw
 	.stop =		rtctimer_stop,
 };
 
-int rtctimer_freq = RTC_FREQ;		/* frequency */
+static int rtctimer_freq = RTC_FREQ;		/* frequency */
 static snd_timer_t *rtctimer;
 static atomic_t rtc_inc = ATOMIC_INIT(0);
 static rtc_task_t rtc_task;
@@ -182,4 +182,16 @@ MODULE_PARM_DESC(rtctimer_freq, "timer f
 
 MODULE_LICENSE("GPL");
 
+#ifndef MODULE
+/* format is: snd-rtctimer=freq */
+
+static int __init rtctimer_setup(char *str)
+{
+	(void)(get_option(&str,&rtctimer_freq) == 2);
+	return 1;
+}
+
+__setup("snd-rtctimer=", rtctimer_setup);
+#endif /* ifndef MODULE */
+
 #endif /* CONFIG_RTC || CONFIG_RTC_MODULE */
diff -puN sound/core/seq/seq_clientmgr.c~alsa-bk-2003-07-28 sound/core/seq/seq_clientmgr.c
--- 25/sound/core/seq/seq_clientmgr.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/seq/seq_clientmgr.c	Tue Jul 29 12:11:31 2003
@@ -521,6 +521,32 @@ static int bounce_error_event(client_t *
 
 
 /*
+ * rewrite the time-stamp of the event record with the curren time
+ * of the given queue.
+ * return non-zero if updated.
+ */
+static int update_timestamp_of_queue(snd_seq_event_t *event, int queue, int real_time)
+{
+	queue_t *q;
+
+	q = queueptr(queue);
+	if (! q)
+		return 0;
+	event->queue = queue;
+	event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK;
+	if (real_time) {
+		event->time.time = snd_seq_timer_get_cur_time(q->timer);
+		event->flags |= SNDRV_SEQ_TIME_STAMP_REAL;
+	} else {
+		event->time.tick = snd_seq_timer_get_cur_tick(q->timer);
+		event->flags |= SNDRV_SEQ_TIME_STAMP_TICK;
+	}
+	queuefree(q);
+	return 1;
+}
+
+
+/*
  * deliver an event to the specified destination.
  * if filter is non-zero, client filter bitmap is tested.
  *
@@ -551,6 +577,10 @@ static int snd_seq_deliver_single_event(
 		goto __skip;
 	}
 		
+	if (dest_port->timestamping)
+		update_timestamp_of_queue(event, dest_port->time_queue,
+					  dest_port->time_real);
+
 	/* expand the quoted event */
 	if (event->type == SNDRV_SEQ_EVENT_KERNEL_QUOTE) {
 		quoted = 1;
@@ -597,27 +627,6 @@ static int snd_seq_deliver_single_event(
 }
 
 
-static void snd_seq_subs_update_event_header(subscribers_t *subs, snd_seq_event_t *event)
-{
-	if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) {
-		/* convert time according to flag with subscription */
-		queue_t *q;
-		q = queueptr(subs->info.queue);
-		if (q) {
-			event->queue = subs->info.queue;
-			event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK;
-			if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL) {
-				event->time.time = snd_seq_timer_get_cur_time(q->timer);
-				event->flags |= SNDRV_SEQ_TIME_STAMP_REAL;
-			} else {
-				event->time.tick = snd_seq_timer_get_cur_tick(q->timer);
-				event->flags |= SNDRV_SEQ_TIME_STAMP_TICK;
-			}
-			queuefree(q);
-		}
-	}
-}
-
 /*
  * send the event to all subscribers:
  */
@@ -647,7 +656,10 @@ static int deliver_to_subscribers(client
 	list_for_each(p, &grp->list_head) {
 		subs = list_entry(p, subscribers_t, src_list);
 		event->dest = subs->info.dest;
-		snd_seq_subs_update_event_header(subs, event);
+		if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
+			/* convert time according to flag with subscription */
+			update_timestamp_of_queue(event, subs->info.queue,
+						  subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL);
 		err = snd_seq_deliver_single_event(client, event,
 						   0, atomic, hop);
 		if (err < 0)
diff -puN sound/core/seq/seq_midi_event.c~alsa-bk-2003-07-28 sound/core/seq/seq_midi_event.c
--- 25/sound/core/seq/seq_midi_event.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/seq/seq_midi_event.c	Tue Jul 29 12:11:31 2003
@@ -98,14 +98,15 @@ static struct status_event_list_t {
 };
 
 static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev);
+static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, snd_seq_event_t *ev);
 
 static struct extra_event_list_t {
 	int event;
 	int (*decode)(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev);
 } extra_event[] = {
 	{SNDRV_SEQ_EVENT_CONTROL14, extra_decode_ctrl14},
-	/*{SNDRV_SEQ_EVENT_NONREGPARAM, extra_decode_nrpn},*/
-	/*{SNDRV_SEQ_EVENT_REGPARAM, extra_decode_rpn},*/
+	{SNDRV_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn},
+	{SNDRV_SEQ_EVENT_REGPARAM, extra_decode_xrpn},
 };
 
 /*
@@ -441,12 +442,12 @@ static int extra_decode_ctrl14(snd_midi_
 	unsigned char cmd;
 	int idx = 0;
 
-	if (ev->data.control.param < 32) {
+	cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
+	if (ev->data.control.param < 0x20) {
 		if (count < 4)
 			return -ENOMEM;
 		if (dev->nostat && count < 6)
 			return -ENOMEM;
-		cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
 		if (cmd != dev->lastcmd || dev->nostat) {
 			if (count < 5)
 				return -ENOMEM;
@@ -456,13 +457,11 @@ static int extra_decode_ctrl14(snd_midi_
 		buf[idx++] = (ev->data.control.value >> 7) & 0x7f;
 		if (dev->nostat)
 			buf[idx++] = cmd;
-		buf[idx++] = ev->data.control.param + 32;
+		buf[idx++] = ev->data.control.param + 0x20;
 		buf[idx++] = ev->data.control.value & 0x7f;
-		return idx;
 	} else {
 		if (count < 2)
 			return -ENOMEM;
-		cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
 		if (cmd != dev->lastcmd || dev->nostat) {
 			if (count < 3)
 				return -ENOMEM;
@@ -470,8 +469,48 @@ static int extra_decode_ctrl14(snd_midi_
 		}
 		buf[idx++] = ev->data.control.param & 0x7f;
 		buf[idx++] = ev->data.control.value & 0x7f;
-		return idx;
 	}
+	return idx;
+}
+
+/* decode reg/nonreg param */
+static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, snd_seq_event_t *ev)
+{
+	unsigned char cmd;
+	char *cbytes;
+	static char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB,
+				       MIDI_CTL_NONREG_PARM_NUM_LSB,
+				       MIDI_CTL_MSB_DATA_ENTRY,
+				       MIDI_CTL_LSB_DATA_ENTRY };
+	static char cbytes_rpn[4] =  { MIDI_CTL_REGIST_PARM_NUM_MSB,
+				       MIDI_CTL_REGIST_PARM_NUM_LSB,
+				       MIDI_CTL_MSB_DATA_ENTRY,
+				       MIDI_CTL_LSB_DATA_ENTRY };
+	unsigned char bytes[4];
+	int idx = 0, i;
+
+	if (count < 8)
+		return -ENOMEM;
+	if (dev->nostat && count < 12)
+		return -ENOMEM;
+	cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
+	bytes[0] = ev->data.control.param & 0x007f;
+	bytes[1] = (ev->data.control.param & 0x3f80) >> 7;
+	bytes[2] = ev->data.control.value & 0x007f;
+	bytes[3] = (ev->data.control.value & 0x3f80) >> 7;
+	if (cmd != dev->lastcmd && !dev->nostat) {
+		if (count < 9)
+			return -ENOMEM;
+		buf[idx++] = dev->lastcmd = cmd;
+	}
+	cbytes = ev->type == SNDRV_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn;
+	for (i = 0; i < 4; i++) {
+		if (dev->nostat)
+			buf[idx++] = dev->lastcmd = cmd;
+		buf[idx++] = cbytes[i];
+		buf[idx++] = bytes[i];
+	}
+	return idx;
 }
 
 /*
diff -puN sound/core/seq/seq_ports.c~alsa-bk-2003-07-28 sound/core/seq/seq_ports.c
--- 25/sound/core/seq/seq_ports.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/seq/seq_ports.c	Tue Jul 29 12:11:31 2003
@@ -352,6 +352,11 @@ int snd_seq_set_port_info(client_port_t 
 	port->midi_voices = info->midi_voices;
 	port->synth_voices = info->synth_voices;
 
+	/* timestamping */
+	port->timestamping = (info->flags & SNDRV_SEQ_PORT_FLG_TIMESTAMP) ? 1 : 0;
+	port->time_real = (info->flags & SNDRV_SEQ_PORT_FLG_TIME_REAL) ? 1 : 0;
+	port->time_queue = info->time_queue;
+
 	return 0;
 }
 
@@ -378,6 +383,15 @@ int snd_seq_get_port_info(client_port_t 
 	info->read_use = port->c_src.count;
 	info->write_use = port->c_dest.count;
 	
+	/* timestamping */
+	info->flags = 0;
+	if (port->timestamping) {
+		info->flags |= SNDRV_SEQ_PORT_FLG_TIMESTAMP;
+		if (port->time_real)
+			info->flags |= SNDRV_SEQ_PORT_FLG_TIME_REAL;
+		info->time_queue = port->time_queue;
+	}
+
 	return 0;
 }
 
diff -puN sound/core/seq/seq_ports.h~alsa-bk-2003-07-28 sound/core/seq/seq_ports.h
--- 25/sound/core/seq/seq_ports.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/seq/seq_ports.h	Tue Jul 29 12:11:31 2003
@@ -74,6 +74,9 @@ typedef struct client_port_t {
 	void *private_data;
 	unsigned int callback_all : 1;
 	unsigned int closing : 1;
+	unsigned int timestamping: 1;
+	unsigned int time_real: 1;
+	int time_queue;
 	
 	/* capability, inport, output, sync */
 	unsigned int capability;	/* port capability bits */
diff -puN sound/core/sound.c~alsa-bk-2003-07-28 sound/core/sound.c
--- 25/sound/core/sound.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/sound.c	Tue Jul 29 12:11:31 2003
@@ -389,6 +389,24 @@ static void __exit alsa_sound_exit(void)
 module_init(alsa_sound_init)
 module_exit(alsa_sound_exit)
 
+#ifndef MODULE
+
+/* format is: snd=major,cards_limit[,device_mode] */
+
+static int __init alsa_sound_setup(char *str)
+{
+	(void)(get_option(&str,&major) == 2 &&
+	       get_option(&str,&cards_limit) == 2);
+#ifdef CONFIG_DEVFS_FS
+	(void)(get_option(&str,&device_mode) == 2);
+#endif
+	return 1;
+}
+
+__setup("snd=", alsa_sound_setup);
+
+#endif /* ifndef MODULE */
+
   /* sound.c */
 EXPORT_SYMBOL(snd_major);
 EXPORT_SYMBOL(snd_ecards_limit);
diff -puN sound/core/sound_oss.c~alsa-bk-2003-07-28 sound/core/sound_oss.c
--- 25/sound/core/sound_oss.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/sound_oss.c	Tue Jul 29 12:11:31 2003
@@ -23,7 +23,7 @@
 
 #ifdef CONFIG_SND_OSSEMUL
 
-#if !defined(CONFIG_SOUND) && !defined(CONFIG_SOUND_MODULE)
+#if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE))
 #error "Enable the OSS soundcore multiplexer (CONFIG_SOUND) in the kernel."
 #endif
 
diff -puN sound/core/timer.c~alsa-bk-2003-07-28 sound/core/timer.c
--- 25/sound/core/timer.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/core/timer.c	Tue Jul 29 12:11:31 2003
@@ -41,7 +41,7 @@
 #define DEFAULT_TIMER_LIMIT 2
 #endif
 
-int timer_limit = DEFAULT_TIMER_LIMIT;
+static int timer_limit = DEFAULT_TIMER_LIMIT;
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ALSA timer interface");
 MODULE_LICENSE("GPL");
@@ -458,12 +458,14 @@ static int _snd_timer_stop(snd_timer_ins
 		return -EINVAL;
 	spin_lock_irqsave(&timer->lock, flags);
 	list_del_init(&timeri->ack_list);
+#if 0   /* FIXME: this causes dead lock with the sequencer timer */
 	/* wait until the callback is finished */
 	while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
 		spin_unlock_irqrestore(&timer->lock, flags);
 		udelay(10);
 		spin_lock_irqsave(&timer->lock, flags);
 	}
+#endif
 	list_del_init(&timeri->active_list);
 	if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) &&
 	    !(timeri->flags & SNDRV_TIMER_IFLG_SLAVE) &&
@@ -1688,10 +1690,11 @@ static ssize_t snd_timer_user_read(struc
 				break;
 			}
 		}
-		spin_unlock_irq(&tu->qlock);
 		if (err < 0)
 			break;
 
+		spin_unlock_irq(&tu->qlock);
+
 		if (tu->tread) {
 			if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], sizeof(snd_timer_tread_t))) {
 				err = -EFAULT;
@@ -1712,6 +1715,7 @@ static ssize_t snd_timer_user_read(struc
 		spin_lock_irq(&tu->qlock);
 		tu->qused--;
 	}
+	spin_unlock_irq(&tu->qlock);
 	return result > 0 ? result : err;
 }
 
@@ -1802,6 +1806,18 @@ static void __exit alsa_timer_exit(void)
 module_init(alsa_timer_init)
 module_exit(alsa_timer_exit)
 
+#ifndef MODULE
+/* format is: snd-timer=timer_limit */
+
+static int __init alsa_timer_setup(char *str)
+{
+	(void)(get_option(&str,&timer_limit) == 2);
+	return 1;
+}
+
+__setup("snd-timer=", alsa_timer_setup);
+#endif /* ifndef MODULE */
+
 EXPORT_SYMBOL(snd_timer_open);
 EXPORT_SYMBOL(snd_timer_close);
 EXPORT_SYMBOL(snd_timer_resolution);
diff -puN sound/drivers/dummy.c~alsa-bk-2003-07-28 sound/drivers/dummy.c
--- 25/sound/drivers/dummy.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/drivers/dummy.c	Tue Jul 29 12:11:31 2003
@@ -69,6 +69,15 @@ MODULE_DEVICES("{{ALSA,Dummy soundcard}}
 #define USE_PERIODS_MAX		255
 #endif
 
+#if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */
+#define USE_FORMATS		SNDRV_PCM_FMTBIT_S16_LE
+#define USE_CHANNELS_MIN	2
+#define USE_CHANNELS_MAX	2
+#define USE_RATE		SNDRV_PCM_RATE_48000
+#define USE_RATE_MIN		48000
+#define USE_RATE_MAX		48000
+#endif
+
 
 /* defaults */
 #ifndef MAX_BUFFER_SIZE
@@ -77,6 +86,11 @@ MODULE_DEVICES("{{ALSA,Dummy soundcard}}
 #ifndef USE_FORMATS
 #define USE_FORMATS 		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
 #endif
+#ifndef USE_RATE
+#define USE_RATE		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000
+#define USE_RATE_MIN		5500
+#define USE_RATE_MAX		48000
+#endif
 #ifndef USE_CHANNELS_MIN
 #define USE_CHANNELS_MIN 	1
 #endif
@@ -271,9 +285,9 @@ static snd_pcm_hardware_t snd_card_dummy
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_MMAP_VALID),
 	.formats =		USE_FORMATS,
-	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-	.rate_min =		5500,
-	.rate_max =		48000,
+	.rates =		USE_RATE,
+	.rate_min =		USE_RATE_MIN,
+	.rate_max =		USE_RATE_MAX,
 	.channels_min =		USE_CHANNELS_MIN,
 	.channels_max =		USE_CHANNELS_MAX,
 	.buffer_bytes_max =	MAX_BUFFER_SIZE,
@@ -289,9 +303,9 @@ static snd_pcm_hardware_t snd_card_dummy
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_MMAP_VALID),
 	.formats =		USE_FORMATS,
-	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-	.rate_min =		5500,
-	.rate_max =		48000,
+	.rates =		USE_RATE,
+	.rate_min =		USE_RATE_MIN,
+	.rate_max =		USE_RATE_MAX,
 	.channels_min =		USE_CHANNELS_MIN,
 	.channels_max =		USE_CHANNELS_MAX,
 	.buffer_bytes_max =	MAX_BUFFER_SIZE,
diff -puN sound/drivers/opl3/opl3_lib.c~alsa-bk-2003-07-28 sound/drivers/opl3/opl3_lib.c
--- 25/sound/drivers/opl3/opl3_lib.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/drivers/opl3/opl3_lib.c	Tue Jul 29 12:11:31 2003
@@ -538,7 +538,7 @@ int snd_opl3_hwdep_new(opl3_t * opl3,
 	hw->ops.release = snd_opl3_release;
 
 	opl3->seq_dev_num = seq_device;
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3,
 			       sizeof(opl3_t*), &opl3->seq_dev) >= 0) {
 		strcpy(opl3->seq_dev->name, hw->name);
diff -puN sound/drivers/opl4/opl4_lib.c~alsa-bk-2003-07-28 sound/drivers/opl4/opl4_lib.c
--- 25/sound/drivers/opl4/opl4_lib.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/drivers/opl4/opl4_lib.c	Tue Jul 29 12:11:31 2003
@@ -20,6 +20,7 @@
 #include "opl4_local.h"
 #include <sound/initval.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 #include <asm/io.h>
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
@@ -137,7 +138,7 @@ static int snd_opl4_detect(opl4_t *opl4)
 	return 0;
 }
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 static void snd_opl4_seq_dev_free(snd_seq_device_t *seq_dev)
 {
 	opl4_t *opl4 = snd_magic_cast(opl4_t, seq_dev->private_data, return);
@@ -243,7 +244,7 @@ int snd_opl4_create(snd_card_t *card,
 	snd_opl4_create_proc(opl4);
 #endif
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	opl4->seq_client = -1;
 	if (opl4->hardware < OPL3_HW_OPL4_ML)
 		snd_opl4_create_seq_dev(opl4, seq_device);
diff -puN sound/drivers/opl4/opl4_local.h~alsa-bk-2003-07-28 sound/drivers/opl4/opl4_local.h
--- 25/sound/drivers/opl4/opl4_local.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/drivers/opl4/opl4_local.h	Tue Jul 29 12:11:31 2003
@@ -163,8 +163,10 @@ typedef struct opl4_voice {
 	int note;
 	int velocity;
 	const opl4_sound_t *sound;
+	u8 level_direct;
 	u8 reg_f_number;
 	u8 reg_misc;
+	u8 reg_lfo_vibrato;
 } opl4_voice_t;
 
 struct opl4 {
diff -puN sound/drivers/opl4/opl4_synth.c~alsa-bk-2003-07-28 sound/drivers/opl4/opl4_synth.c
--- 25/sound/drivers/opl4/opl4_synth.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/drivers/opl4/opl4_synth.c	Tue Jul 29 12:11:31 2003
@@ -267,11 +267,6 @@ static unsigned char snd_opl4_volume_tab
 	  2,  2,  2,  1,  1,  0,  0,  0
 };
 
-static void snd_opl4_write_mask(opl4_t *opl4, u8 reg, u8 mask, u8 value)
-{
-	snd_opl4_write(opl4, reg, ((snd_opl4_read(opl4, reg)) & ~mask) | (value & mask));
-}
-
 /*
  * Initializes all voices.
  */
@@ -302,7 +297,8 @@ void snd_opl4_synth_shutdown(opl4_t *opl
 	int i;
 
 	for (i = 0; i < OPL4_MAX_VOICES; i++)
-		snd_opl4_write_mask(opl4, OPL4_REG_MISC + i, OPL4_KEY_ON_BIT, 0);
+		snd_opl4_write(opl4, OPL4_REG_MISC + i,
+			       opl4->voices[i].reg_misc & ~OPL4_KEY_ON_BIT);
 }
 
 /*
@@ -378,7 +374,9 @@ static void snd_opl4_update_volume(opl4_
 		att = 0;
 	else if (att > 0x7e)
 		att = 0x7e;
-	snd_opl4_write(opl4, OPL4_REG_LEVEL + voice->number, att << 1);
+	snd_opl4_write(opl4, OPL4_REG_LEVEL + voice->number,
+		       (att << 1) | voice->level_direct);
+	voice->level_direct = 0;
 }
 
 static void snd_opl4_update_pan(opl4_t *opl4, opl4_voice_t *voice)
@@ -405,8 +403,10 @@ static void snd_opl4_update_vibrato_dept
 	depth = (7 - voice->sound->vibrato)
 		* (voice->chan->control[MIDI_CTL_VIBRATO_DEPTH] & 0x7f);
 	depth = (depth >> 7) + voice->sound->vibrato;
-	snd_opl4_write_mask(opl4, OPL4_REG_LFO_VIBRATO + voice->number,
-			    OPL4_VIBRATO_DEPTH_MASK, depth);
+	voice->reg_lfo_vibrato &= ~OPL4_VIBRATO_DEPTH_MASK;
+	voice->reg_lfo_vibrato |= depth & OPL4_VIBRATO_DEPTH_MASK;
+	snd_opl4_write(opl4, OPL4_REG_LFO_VIBRATO + voice->number,
+		       voice->reg_lfo_vibrato);
 }
 
 static void snd_opl4_update_pitch(opl4_t *opl4, opl4_voice_t *voice)
@@ -441,8 +441,6 @@ static void snd_opl4_update_pitch(opl4_t
 
 static void snd_opl4_update_tone_parameters(opl4_t *opl4, opl4_voice_t *voice)
 {
-	snd_opl4_write(opl4, OPL4_REG_LFO_VIBRATO + voice->number,
-		       voice->sound->reg_lfo_vibrato);
 	snd_opl4_write(opl4, OPL4_REG_ATTACK_DECAY1 + voice->number,
 		       voice->sound->reg_attack_decay1);
 	snd_opl4_write(opl4, OPL4_REG_LEVEL_DECAY2 + voice->number,
@@ -521,6 +519,7 @@ void snd_opl4_note_on(void *private_data
 		voice[i]->reg_misc = OPL4_LFO_RESET_BIT;
 		snd_opl4_update_pan(opl4, voice[i]);
 		snd_opl4_update_pitch(opl4, voice[i]);
+		voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT;
 		snd_opl4_update_volume(opl4, voice[i]);
 	}
 
@@ -530,6 +529,7 @@ void snd_opl4_note_on(void *private_data
 	/* set remaining parameters */
 	for (i = 0; i < voices; i++) {
 		snd_opl4_update_tone_parameters(opl4, voice[i]);
+		voice[i]->reg_lfo_vibrato = voice[i]->sound->reg_lfo_vibrato;
 		snd_opl4_update_vibrato_depth(opl4, voice[i]);
 	}
 
diff -puN sound/drivers/vx/vx_core.c~alsa-bk-2003-07-28 sound/drivers/vx/vx_core.c
--- 25/sound/drivers/vx/vx_core.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/drivers/vx/vx_core.c	Tue Jul 29 12:11:31 2003
@@ -44,8 +44,7 @@ MODULE_LICENSE("GPL");
  */
 void snd_vx_delay(vx_core_t *chip, int xmsec)
 {
-	if (! (chip->chip_status & VX_STAT_IN_SUSPEND) && ! in_interrupt() &&
-	    xmsec >= 1000 / HZ) {
+	if (! in_interrupt() && xmsec >= 1000 / HZ) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((xmsec * HZ + 999) / 1000);
 	} else {
@@ -632,6 +631,9 @@ static void vx_proc_read(snd_info_entry_
 	snd_iprintf(buffer, "Frequency: %d\n", chip->freq);
 	snd_iprintf(buffer, "Detected Frequency: %d\n", chip->freq_detected);
 	snd_iprintf(buffer, "Detected UER type: %s\n", uer_type[chip->uer_detected]);
+	snd_iprintf(buffer, "Min/Max/Cur IBL: %d/%d/%d (granularity=%d)\n",
+		    chip->ibl.min_size, chip->ibl.max_size, chip->ibl.size,
+		    chip->ibl.granularity);
 }
 
 static void vx_proc_init(vx_core_t *chip)
diff -puN sound/i2c/cs8427.c~alsa-bk-2003-07-28 sound/i2c/cs8427.c
--- 25/sound/i2c/cs8427.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/i2c/cs8427.c	Tue Jul 29 12:11:31 2003
@@ -75,7 +75,7 @@ int snd_cs8427_detect(snd_i2c_bus_t *bus
 	return res;
 }
 
-static int snd_cs8427_reg_write(snd_i2c_device_t *device, unsigned char reg, unsigned char val)
+int snd_cs8427_reg_write(snd_i2c_device_t *device, unsigned char reg, unsigned char val)
 {
 	int err;
 	unsigned char buf[2];
@@ -89,7 +89,7 @@ static int snd_cs8427_reg_write(snd_i2c_
 	return 0;
 }
 
-static int snd_cs8427_reg_read(snd_i2c_device_t *device, unsigned char reg)
+int snd_cs8427_reg_read(snd_i2c_device_t *device, unsigned char reg)
 {
 	int err;
 	unsigned char buf;
@@ -561,6 +561,8 @@ int snd_cs8427_iec958_pcm(snd_i2c_device
 EXPORT_SYMBOL(snd_cs8427_detect);
 EXPORT_SYMBOL(snd_cs8427_create);
 EXPORT_SYMBOL(snd_cs8427_reset);
+EXPORT_SYMBOL(snd_cs8427_reg_write);
+EXPORT_SYMBOL(snd_cs8427_reg_read);
 EXPORT_SYMBOL(snd_cs8427_iec958_build);
 EXPORT_SYMBOL(snd_cs8427_iec958_active);
 EXPORT_SYMBOL(snd_cs8427_iec958_pcm);
diff -puN sound/i2c/other/ak4xxx-adda.c~alsa-bk-2003-07-28 sound/i2c/other/ak4xxx-adda.c
--- 25/sound/i2c/other/ak4xxx-adda.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/i2c/other/ak4xxx-adda.c	Tue Jul 29 12:11:31 2003
@@ -41,7 +41,7 @@ void snd_akm4xxx_write(akm4xxx_t *ak, in
 
 	/* save the data */
 	if (ak->type == SND_AK4524 || ak->type == SND_AK4528) {
-		if ((reg != 0x04 && reg != 0x05) || (reg & 0x80) == 0)
+		if ((reg != 0x04 && reg != 0x05) || (val & 0x80) == 0)
 			snd_akm4xxx_set(ak, chip, reg, val);
 		else
 			snd_akm4xxx_set_ipga(ak, chip, reg, val);
diff -puN sound/isa/ad1848/ad1848.c~alsa-bk-2003-07-28 sound/isa/ad1848/ad1848.c
--- 25/sound/isa/ad1848/ad1848.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/isa/ad1848/ad1848.c	Tue Jul 29 12:11:31 2003
@@ -46,6 +46,7 @@ static int enable[SNDRV_CARDS] = SNDRV_D
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,11,12,15 */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3,5,6,7 */
+static int thinkpad[SNDRV_CARDS];			/* Thinkpad special case */
 
 MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(index, "Index value for AD1848 soundcard.");
@@ -65,6 +66,9 @@ MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
 MODULE_PARM(dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(dma1, "DMA1 # for AD1848 driver.");
 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
+MODULE_PARM(thinkpad, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(thinkpad, "Enable only for the onboard CS4248 of IBM Thinkpad 360/750/755 series.");
+MODULE_PARM_SYNTAX(thinkpad,  SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 
 static snd_card_t *snd_ad1848_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
 
@@ -77,15 +81,15 @@ static int __init snd_card_ad1848_probe(
 	int err;
 
 	if (port[dev] == SNDRV_AUTO_PORT) {
-		snd_printk("specify port\n");
+		snd_printk(KERN_ERR "ad1848: specify port\n");
 		return -EINVAL;
 	}
 	if (irq[dev] == SNDRV_AUTO_IRQ) {
-		snd_printk("specify irq\n");
+		snd_printk(KERN_ERR "ad1848: specify irq\n");
 		return -EINVAL;
 	}
 	if (dma1[dev] == SNDRV_AUTO_DMA) {
-		snd_printk("specify dma1\n");
+		snd_printk(KERN_ERR "ad1848: specify dma1\n");
 		return -EINVAL;
 	}
 
@@ -96,7 +100,7 @@ static int __init snd_card_ad1848_probe(
 	if ((err = snd_ad1848_create(card, port[dev],
 				     irq[dev],
 				     dma1[dev],
-				     AD1848_HW_DETECT,
+				     thinkpad[dev] ? AD1848_HW_THINKPAD : AD1848_HW_DETECT,
 				     &chip)) < 0) {
 		snd_card_free(card);
 		return err;
@@ -116,6 +120,10 @@ static int __init snd_card_ad1848_probe(
 	sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
 		pcm->name, chip->port, irq[dev], dma1[dev]);
 
+	if (thinkpad[dev]) {
+		strcat(card->longname, " [Thinkpad]");
+	}
+
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
 		return err;
@@ -168,7 +176,8 @@ static int __init alsa_card_ad1848_setup
 	       get_id(&str,&id[nr_dev]) == 2 &&
 	       get_option(&str,(int *)&port[nr_dev]) == 2 &&
 	       get_option(&str,&irq[nr_dev]) == 2 &&
-	       get_option(&str,&dma1[nr_dev]) == 2);
+	       get_option(&str,&dma1[nr_dev]) == 2 &&
+	       get_option(&str,&thinkpad[nr_dev]) == 2);
 	nr_dev++;
 	return 1;
 }
diff -puN sound/isa/ad1848/ad1848_lib.c~alsa-bk-2003-07-28 sound/isa/ad1848/ad1848_lib.c
--- 25/sound/isa/ad1848/ad1848_lib.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/isa/ad1848/ad1848_lib.c	Tue Jul 29 12:11:31 2003
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <sound/core.h>
@@ -625,6 +626,95 @@ static snd_pcm_uframes_t snd_ad1848_capt
 
  */
 
+static void snd_ad1848_thinkpad_twiddle(ad1848_t *chip, int on) {
+
+	int tmp;
+
+	if (!chip->thinkpad_flag) return;
+
+	outb(0x1c, AD1848_THINKPAD_CTL_PORT1);
+	tmp = inb(AD1848_THINKPAD_CTL_PORT2);
+
+	if (on)
+		/* turn it on */
+		tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT;
+	else
+		/* turn it off */
+		tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT;
+	
+	outb(tmp, AD1848_THINKPAD_CTL_PORT2);
+
+}
+
+#ifdef CONFIG_PM
+static void snd_ad1848_suspend(ad1848_t *chip) {
+
+	snd_card_t *card = chip->card;
+
+	if (card->power_state == SNDRV_CTL_POWER_D3hot)
+		return;
+
+	snd_pcm_suspend_all(chip->pcm);
+	/* FIXME: save registers? */
+
+	if (chip->thinkpad_flag)
+		snd_ad1848_thinkpad_twiddle(chip, 0);
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+}
+
+static void snd_ad1848_resume(ad1848_t *chip) {
+
+	snd_card_t *card = chip->card;
+
+	if (card->power_state == SNDRV_CTL_POWER_D0)
+		return;
+
+	if (chip->thinkpad_flag)
+		snd_ad1848_thinkpad_twiddle(chip, 1);
+
+	/* FIXME: restore registers? */
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+}
+
+/* callback for control API */
+static int snd_ad1848_set_power_state(snd_card_t *card, unsigned int power_state)
+{
+	ad1848_t *chip = (ad1848_t *) card->power_state_private_data;
+	switch (power_state) {
+	case SNDRV_CTL_POWER_D0:
+	case SNDRV_CTL_POWER_D1:
+	case SNDRV_CTL_POWER_D2:
+		snd_ad1848_resume(chip);
+		break;
+	case SNDRV_CTL_POWER_D3hot:
+	case SNDRV_CTL_POWER_D3cold:
+		snd_ad1848_suspend(chip);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int snd_ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	ad1848_t *chip = snd_magic_cast(ad1848_t, dev->data, return 0);
+
+	switch (rqst) {
+	case PM_SUSPEND:
+		snd_ad1848_suspend(chip);
+		break;
+	case PM_RESUME:
+		snd_ad1848_resume(chip);
+		break;
+	}
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
 static int snd_ad1848_probe(ad1848_t * chip)
 {
 	unsigned long flags;
@@ -799,6 +889,10 @@ static int snd_ad1848_capture_close(snd_
 
 static int snd_ad1848_free(ad1848_t *chip)
 {
+#ifdef CONFIG_PM
+        if (chip->thinkpad_pmstate)
+                pm_unregister(chip->thinkpad_pmstate);
+#endif
 	if (chip->res_port) {
 		release_resource(chip->res_port);
 		kfree_nocheck(chip->res_port);
@@ -870,6 +964,20 @@ int snd_ad1848_create(snd_card_t * card,
 	}
 	chip->dma = dma;
 
+	if (hardware == AD1848_HW_THINKPAD) {
+		chip->thinkpad_flag = 1;
+		chip->hardware = AD1848_HW_DETECT; /* reset */
+		snd_ad1848_thinkpad_twiddle(chip, 1);
+#ifdef CONFIG_PM
+		chip->thinkpad_pmstate = pm_register(PM_ISA_DEV, 0, snd_ad1848_pm_callback);
+		if (chip->thinkpad_pmstate) {
+			chip->thinkpad_pmstate->data = chip;
+			card->set_power_state = snd_ad1848_set_power_state; /* callback */
+			card->power_state_private_data = chip;
+		}
+#endif
+	}
+
 	if (snd_ad1848_probe(chip) < 0) {
 		snd_ad1848_free(chip);
 		return -ENODEV;
diff -puN sound/isa/cmi8330.c~alsa-bk-2003-07-28 sound/isa/cmi8330.c
--- 25/sound/isa/cmi8330.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/isa/cmi8330.c	Tue Jul 29 12:11:31 2003
@@ -293,7 +293,7 @@ static int __devinit snd_cmi8330_pnp(int
 				     const struct pnp_card_device_id *id)
 {
 	struct pnp_dev *pdev;
-	struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_ATOMIC);
+	struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
 	int err;
 
 	acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL);
diff -puN sound/isa/cs423x/cs4231_lib.c~alsa-bk-2003-07-28 sound/isa/cs423x/cs4231_lib.c
--- 25/sound/isa/cs423x/cs4231_lib.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/isa/cs423x/cs4231_lib.c	Tue Jul 29 12:11:31 2003
@@ -1401,8 +1401,10 @@ static int snd_cs4231_pm_callback(struct
 
 	switch (rqst) {
 	case PM_SUSPEND:
-		if (chip->suspend)
+		if (chip->suspend) {
+			snd_pcm_suspend_all(chip->pcm);
 			(*chip->suspend)(chip);
+		}
 		break;
 	case PM_RESUME:
 		if (chip->resume)
diff -puN sound/isa/es18xx.c~alsa-bk-2003-07-28 sound/isa/es18xx.c
--- 25/sound/isa/es18xx.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/isa/es18xx.c	Tue Jul 29 12:11:31 2003
@@ -1966,7 +1966,7 @@ static int __devinit snd_audiodrive_pnp(
 					const struct pnp_card_device_id *id)
 {
 	struct pnp_dev *pdev;
-	struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_ATOMIC);
+	struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
 	int err;
 
 	if (!cfg)
diff -puN sound/isa/gus/gus_main.c~alsa-bk-2003-07-28 sound/isa/gus/gus_main.c
--- 25/sound/isa/gus/gus_main.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/isa/gus/gus_main.c	Tue Jul 29 12:11:31 2003
@@ -106,7 +106,7 @@ static int snd_gus_free(snd_gus_card_t *
 {
 	if (gus->gf1.res_port2 == NULL)
 		goto __hw_end;
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if (gus->seq_dev) {
 		snd_device_free(gus->card, gus->seq_dev);
 		gus->seq_dev = NULL;
@@ -434,7 +434,7 @@ int snd_gus_initialize(snd_gus_card_t *g
 	}
 	if ((err = snd_gus_init_dma_irq(gus, 1)) < 0)
 		return err;
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if (snd_seq_device_new(gus->card, 1, SNDRV_SEQ_DEV_ID_GUS,
 			       sizeof(snd_gus_card_t*), &gus->seq_dev) >= 0) {
 		strcpy(gus->seq_dev->name, "GUS");
diff -puN sound/isa/opl3sa2.c~alsa-bk-2003-07-28 sound/isa/opl3sa2.c
--- 25/sound/isa/opl3sa2.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/isa/opl3sa2.c	Tue Jul 29 12:11:31 2003
@@ -552,9 +552,8 @@ static void snd_opl3sa2_suspend(opl3sa2_
 	if (card->power_state == SNDRV_CTL_POWER_D3hot)
 		return;
 
-	/* FIXME: is this order ok? */
+	snd_pcm_suspend_all(chip->cs4231->pcm); /* stop before saving regs */
 	chip->cs4231_suspend(chip->cs4231);
-	snd_pcm_suspend_all(chip->cs4231->pcm);
 
 	/* power down */
 	snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3);
diff -puN sound/isa/sb/emu8000.c~alsa-bk-2003-07-28 sound/isa/sb/emu8000.c
--- 25/sound/isa/sb/emu8000.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/isa/sb/emu8000.c	Tue Jul 29 12:11:31 2003
@@ -1138,7 +1138,7 @@ snd_emu8000_new(snd_card_t *card, int in
 		snd_emu8000_free(hw);
 		return err;
 	}
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
 			       sizeof(emu8000_t*), &awe) >= 0) {
 		strcpy(awe->name, "EMU-8000");
diff -puN sound/isa/sb/sb16.c~alsa-bk-2003-07-28 sound/isa/sb/sb16.c
--- 25/sound/isa/sb/sb16.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/isa/sb/sb16.c	Tue Jul 29 12:11:31 2003
@@ -66,7 +66,7 @@ MODULE_DEVICES("{{Creative Labs,SB AWE 3
 #define SNDRV_DEBUG_IRQ
 #endif
 
-#if defined(SNDRV_SBAWE) && (defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE))
+#if defined(SNDRV_SBAWE) && (defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)))
 #define SNDRV_SBAWE_EMU8000
 #endif
 
@@ -350,6 +350,18 @@ __wt_error:
 
 #endif /* CONFIG_PNP */
 
+static void snd_sb16_free(snd_card_t *card)
+{
+	struct snd_card_sb16 *acard = (struct snd_card_sb16 *)card->private_data;
+        
+	if (acard == NULL)
+		return;
+	if (acard->fm_res) {
+		release_resource(acard->fm_res);
+		kfree_nocheck(acard->fm_res);
+	}
+}
+
 static int __init snd_sb16_probe(int dev,
 				 struct pnp_card_link *pcard,
 				 const struct pnp_card_device_id *pid)
@@ -374,6 +386,7 @@ static int __init snd_sb16_probe(int dev
 	if (card == NULL)
 		return -ENOMEM;
 	acard = (struct snd_card_sb16 *) card->private_data;
+	card->private_free = snd_sb16_free;
 #ifdef CONFIG_PNP
 	if (isapnp[dev]) {
 		if ((err = snd_card_sb16_pnp(dev, acard, pcard, pid))) {
@@ -464,7 +477,8 @@ static int __init snd_sb16_probe(int dev
 
 	if (fm_port[dev] > 0) {
 		if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
-				    OPL3_HW_OPL3, fm_port[dev] == port[dev],
+				    OPL3_HW_OPL3,
+				    fm_port[dev] == port[dev] || fm_port[dev] == 0x388,
 				    &opl3) < 0) {
 			snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
 				   fm_port[dev], fm_port[dev] + 2);
diff -puN sound/isa/sscape.c~alsa-bk-2003-07-28 sound/isa/sscape.c
--- 25/sound/isa/sscape.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/isa/sscape.c	Tue Jul 29 12:11:31 2003
@@ -809,7 +809,7 @@ static snd_kcontrol_new_t midi_mixer_ctl
  */
 static unsigned __devinit get_irq_config(int irq)
 {
-	static const int valid_irq[] __devinitdata = { 9, 5, 7, 10 };
+	static const int valid_irq[] = { 9, 5, 7, 10 };
 	unsigned cfg;
 
 	for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) {
diff -puN sound/pci/ac97/ac97_codec.c~alsa-bk-2003-07-28 sound/pci/ac97/ac97_codec.c
--- 25/sound/pci/ac97/ac97_codec.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ac97/ac97_codec.c	Tue Jul 29 12:11:31 2003
@@ -32,6 +32,7 @@
 #include <sound/ac97_codec.h>
 #include <sound/asoundef.h>
 #include <sound/initval.h>
+#include "ac97_local.h"
 #include "ac97_id.h"
 #include "ac97_patch.h"
 
@@ -51,8 +52,6 @@ MODULE_PARM_SYNTAX(enable_loopback, SNDR
 
  */
 
-static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix);
-
 typedef struct {
 	unsigned int id;
 	unsigned int mask;
@@ -114,7 +113,7 @@ static const ac97_codec_id_t snd_ac97_co
 { 0x414c4740, 0xfffffff0, "ALC202",		NULL,		NULL },
 { 0x414c4750, 0xfffffff0, "ALC250",		NULL,		NULL },
 { 0x414c4770, 0xfffffff0, "ALC203",		NULL,		NULL },
-{ 0x434d4941, 0xffffffff, "CMI9738",		NULL,		NULL },
+{ 0x434d4941, 0xffffffff, "CMI9738",		patch_cm9738,	NULL },
 { 0x434d4961, 0xffffffff, "CMI9739",		patch_cm9739,	NULL },
 { 0x43525900, 0xfffffff8, "CS4297",		NULL,		NULL },
 { 0x43525910, 0xfffffff8, "CS4297A",		patch_cirrus_spdif,	NULL },
@@ -134,8 +133,8 @@ static const ac97_codec_id_t snd_ac97_co
 { 0x49434501, 0xffffffff, "ICE1230",		NULL,		NULL },
 { 0x49434511, 0xffffffff, "ICE1232",		NULL,		NULL }, // alias VIA VT1611A?
 { 0x49434514, 0xffffffff, "ICE1232A",		NULL,		NULL },
-{ 0x49434551, 0xffffffff, "VT1616", 		NULL,		NULL }, 
-{ 0x49434552, 0xffffffff, "VT1616i",		NULL,		NULL }, // VT1616 compatible (chipset integrated)
+{ 0x49434551, 0xffffffff, "VT1616", 		patch_vt1616,	NULL }, 
+{ 0x49434552, 0xffffffff, "VT1616i",		patch_vt1616,	NULL }, // VT1616 compatible (chipset integrated)
 { 0x49544520, 0xffffffff, "IT2226E",		NULL,		NULL },
 { 0x4e534300, 0xffffffff, "LM4540/43/45/46/48",	NULL,		NULL }, // only guess --jk
 { 0x4e534331, 0xffffffff, "LM4549",		NULL,		NULL },
@@ -158,7 +157,7 @@ static const ac97_codec_id_t snd_ac97_co
 { 0x594d4800, 0xffffffff, "YMF743",		NULL,		NULL },
 { 0x594d4802, 0xffffffff, "YMF752",		NULL,		NULL },
 { 0x594d4803, 0xffffffff, "YMF753",		patch_yamaha_ymf753,	NULL },
-{ 0x83847600, 0xffffffff, "STAC9700/83/84",	NULL,		NULL },
+{ 0x83847600, 0xffffffff, "STAC9700/83/84",	patch_sigmatel_stac9700,	NULL },
 { 0x83847604, 0xffffffff, "STAC9701/3/4/5",	NULL,		NULL },
 { 0x83847605, 0xffffffff, "STAC9704",		NULL,		NULL },
 { 0x83847608, 0xffffffff, "STAC9708/11",	patch_sigmatel_stac9708,	NULL },
@@ -171,7 +170,7 @@ static const ac97_codec_id_t snd_ac97_co
 { 0, 	      0,	  NULL,			NULL,		NULL }
 };
 
-static const char *snd_ac97_stereo_enhancements[] =
+const char *snd_ac97_stereo_enhancements[] =
 {
   /*   0 */ "No 3D Stereo Enhancement",
   /*   1 */ "Analog Devices Phat Stereo",
@@ -310,21 +309,6 @@ void snd_ac97_write_cache(ac97_t *ac97, 
 	set_bit(reg, ac97->reg_accessed);
 }
 
-static void snd_ac97_write_cache_test(ac97_t *ac97, unsigned short reg, unsigned short value)
-{
-#if 0
-	if (!snd_ac97_valid_reg(ac97, reg))
-		return;
-	//spin_lock(&ac97->reg_lock);
-	ac97->write(ac97, reg, value);
-	ac97->regs[reg] = ac97->read(ac97, reg);
-	if (value != ac97->regs[reg])
-		snd_printk("AC97 reg=%02x val=%04x real=%04x\n", reg, value, ac97->regs[reg]);
-	//spin_unlock(&ac97->reg_lock);
-#endif
-	snd_ac97_write_cache(ac97, reg, value);
-}
-
 /**
  * snd_ac97_update - update the value on the given register
  * @ac97: the ac97 instance
@@ -518,12 +502,7 @@ static int snd_ac97_put_enum_double(snd_
 	return snd_ac97_update_bits(ac97, reg, 1 << shift, val << shift);
 }
 
-#define AC97_SINGLE(xname, reg, shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \
-  .get = snd_ac97_get_single, .put = snd_ac97_put_single, \
-  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
-
-static int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	int mask = (kcontrol->private_value >> 16) & 0xff;
 
@@ -534,7 +513,7 @@ static int snd_ac97_info_single(snd_kcon
 	return 0;
 }
 
-static int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	int reg = kcontrol->private_value & 0xff;
@@ -548,7 +527,7 @@ static int snd_ac97_get_single(snd_kcont
 	return 0;
 }
 
-static int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	int reg = kcontrol->private_value & 0xff;
@@ -718,7 +697,7 @@ AC97_ENUM_DOUBLE("Mic Select", AC97_GENE
 AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0)
 };
 
-static const snd_kcontrol_new_t snd_ac97_controls_3d[2] = {
+const snd_kcontrol_new_t snd_ac97_controls_3d[2] = {
 AC97_SINGLE("3D Control - Center", AC97_3D_CONTROL, 8, 15, 0),
 AC97_SINGLE("3D Control - Depth", AC97_3D_CONTROL, 0, 15, 0)
 };
@@ -743,21 +722,9 @@ AC97_SINGLE("Sigmatel Surround Playback 
 AC97_DOUBLE("Sigmatel Surround Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1)
 };
 
-static const snd_kcontrol_new_t snd_ac97_sigmatel_controls[] = {
-AC97_SINGLE("Sigmatel DAC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 1, 1, 0),
-AC97_SINGLE("Sigmatel ADC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 0, 1, 0)
-};
-
 static const snd_kcontrol_new_t snd_ac97_control_eapd =
 AC97_SINGLE("External Amplifier Power Down", AC97_POWERDOWN, 15, 1, 0);
 
-static const snd_kcontrol_new_t snd_ac97_controls_vt1616[] = {
-AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0),
-AC97_SINGLE("Alternate Level to Surround Out", 0x5a, 15, 1, 0),
-AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0),
-AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0),
-};
-
 static int snd_ac97_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
@@ -892,7 +859,7 @@ static int snd_ac97_put_spsa(snd_kcontro
 	return 0;
 }
 
-static const snd_kcontrol_new_t snd_ac97_controls_spdif[5] = {
+const snd_kcontrol_new_t snd_ac97_controls_spdif[5] = {
 	{
 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -916,7 +883,6 @@ static const snd_kcontrol_new_t snd_ac97
 	},
 
 	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),AC97_EXTENDED_STATUS, 2, 1, 0),
-	// AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA",AC97_EXTENDED_STATUS, 4, 3, 0)
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA",
@@ -927,15 +893,6 @@ static const snd_kcontrol_new_t snd_ac97
 	},
 };
 
-static const snd_kcontrol_new_t snd_ac97_cirrus_controls_spdif[2] = {
-    AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CSR_SPDIF, 15, 1, 0),
-    AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", AC97_CSR_ACMODE, 0, 3, 0)
-};
-
-static const snd_kcontrol_new_t snd_ac97_conexant_controls_spdif[2] = {
-    AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CXR_AUDIO_MISC, 3, 1, 0),
-};
-
 #define AD18XX_PCM_BITS(xname, codec, shift, mask) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_ad18xx_pcm_info_bits, \
   .get = snd_ac97_ad18xx_pcm_get_bits, .put = snd_ac97_ad18xx_pcm_put_bits, \
@@ -1031,325 +988,6 @@ static const snd_kcontrol_new_t snd_ac97
 AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 31)
 };
 
-static int snd_ac97_ad1980_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	static char *texts[2] = { "AC-Link", "A/D Converter" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-	if (uinfo->value.enumerated.item > 1)
-		uinfo->value.enumerated.item = 1;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int snd_ac97_ad1980_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-
-	val = ac97->regs[AC97_AD_SERIAL_CFG];
-	ucontrol->value.enumerated.item[0] = (val >> 2) & 1;
-	return 0;
-}
-
-static int snd_ac97_ad1980_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-
-	if (ucontrol->value.enumerated.item[0] > 1)
-		return -EINVAL;
-	val = ucontrol->value.enumerated.item[0] << 2;
-	return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val);
-}
-
-static const snd_kcontrol_new_t snd_ac97_ad1980_spdif_source = {
-	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-	.info	= snd_ac97_ad1980_spdif_source_info,
-	.get	= snd_ac97_ad1980_spdif_source_get,
-	.put	= snd_ac97_ad1980_spdif_source_put,
-};
-
-/*
- * ALC650
- */
-static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
-	AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
-	AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0),
-	AC97_SINGLE("Center/LFE Down Mix", AC97_ALC650_MULTICH, 2, 1, 0),
-	AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0),
-	/* 4: Analog Input To Surround */
-	/* 5: Analog Input To Center/LFE */
-	/* 6: Independent Master Volume Right */
-	/* 7: Independent Master Volume Left */
-	/* 8: reserved */
-	AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
-	AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0),
-#if 0 /* always set in patch_alc650 */
-	AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0),
-	AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0),
-	AC97_SINGLE("Surround DAC Switch", AC97_ALC650_SURR_DAC_VOL, 15, 1, 1),
-	AC97_DOUBLE("Surround DAC Volume", AC97_ALC650_SURR_DAC_VOL, 8, 0, 31, 1),
-	AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1),
-	AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1),
-#endif
-};
-
-static const snd_kcontrol_new_t snd_ac97_control_alc650_mic =
-AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0);
-
-
-static int snd_ac97_alc650_mic_gpio_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
-	return 0;
-}
-
-static int snd_ac97_alc650_mic_gpio_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	int change;
-	change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
-				      ucontrol->value.integer.value[0] ? (1 << 10) : 0);
-	if (change) {
-		/* GPIO0 write for mic */
-		snd_ac97_update_bits(ac97, 0x76, 0x01,
-				     ucontrol->value.integer.value[0] ? 0 : 0x01);
-		/* GPIO0 high for mic */
-		snd_ac97_update_bits(ac97, 0x78, 0x100,
-				     ucontrol->value.integer.value[0] ? 0 : 0x100);
-	}
-	return change;
-}
-
-static const snd_kcontrol_new_t snd_ac97_control_alc650_mic_gpio = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "Mic As Center/LFE",
-	.info = snd_ac97_info_single,
-	.get = snd_ac97_alc650_mic_gpio_get,
-	.put = snd_ac97_alc650_mic_gpio_put,
-	.private_value = (1 << 16), /* for info */
-};
-
-static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = {
-	AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
-	AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0),
-	AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0),
-};
-
-/* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */
-
-/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */
-static int snd_ac97_ymf753_info_speaker(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	static char *texts[3] = {
-		"Standard", "Small", "Smaller"
-	};
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 3;
-	if (uinfo->value.enumerated.item > 2)
-		uinfo->value.enumerated.item = 2;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int snd_ac97_ymf753_get_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-
-	val = ac97->regs[AC97_YMF753_3D_MODE_SEL];
-	val = (val >> 10) & 3;
-	if (val > 0)	/* 0 = invalid */
-		val--;
-	ucontrol->value.enumerated.item[0] = val;
-	return 0;
-}
-
-static int snd_ac97_ymf753_put_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-
-	if (ucontrol->value.enumerated.item[0] > 2)
-		return -EINVAL;
-	val = (ucontrol->value.enumerated.item[0] + 1) << 10;
-	return snd_ac97_update(ac97, AC97_YMF753_3D_MODE_SEL, val);
-}
-
-static const snd_kcontrol_new_t snd_ac97_ymf753_controls_speaker =
-{
-	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name	= "3D Control - Speaker",
-	.info	= snd_ac97_ymf753_info_speaker,
-	.get	= snd_ac97_ymf753_get_speaker,
-	.put	= snd_ac97_ymf753_put_speaker,
-};
-
-/* It is possible to indicate to the Yamaha YMF753 the source to direct to the S/PDIF output. */
-static int snd_ac97_ymf753_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	static char *texts[2] = { "AC-Link", "A/D Converter" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-	if (uinfo->value.enumerated.item > 1)
-		uinfo->value.enumerated.item = 1;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int snd_ac97_ymf753_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-
-	val = ac97->regs[AC97_YMF753_DIT_CTRL2];
-	ucontrol->value.enumerated.item[0] = (val >> 1) & 1;
-	return 0;
-}
-
-static int snd_ac97_ymf753_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-
-	if (ucontrol->value.enumerated.item[0] > 1)
-		return -EINVAL;
-	val = ucontrol->value.enumerated.item[0] << 1;
-	return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0002, val);
-}
-
-/* The AC'97 spec states that the S/PDIF signal is to be output at pin 48.
-   The YMF753 will output the S/PDIF signal to pin 43, 47 (EAPD), or 48.
-   By default, no output pin is selected, and the S/PDIF signal is not output.
-   There is also a bit to mute S/PDIF output in a vendor-specific register. */
-static int snd_ac97_ymf753_spdif_output_pin_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	static char *texts[3] = { "Disabled", "Pin 43", "Pin 48" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 3;
-	if (uinfo->value.enumerated.item > 2)
-		uinfo->value.enumerated.item = 2;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int snd_ac97_ymf753_spdif_output_pin_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-
-	val = ac97->regs[AC97_YMF753_DIT_CTRL2];
-	ucontrol->value.enumerated.item[0] = (val & 0x0008) ? 2 : (val & 0x0020) ? 1 : 0;
-	return 0;
-}
-
-static int snd_ac97_ymf753_spdif_output_pin_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-
-	if (ucontrol->value.enumerated.item[0] > 2)
-		return -EINVAL;
-	val = (ucontrol->value.enumerated.item[0] == 2) ? 0x0008 :
-	      (ucontrol->value.enumerated.item[0] == 1) ? 0x0020 : 0;
-	return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0028, val);
-	/* The following can be used to direct S/PDIF output to pin 47 (EAPD).
-	   snd_ac97_write_cache(ac97, 0x62, snd_ac97_read(ac97, 0x62) | 0x0008); */
-}
-
-static const snd_kcontrol_new_t snd_ac97_ymf753_controls_spdif[3] = {
-	{
-		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-		.info	= snd_ac97_ymf753_spdif_source_info,
-		.get	= snd_ac97_ymf753_spdif_source_get,
-		.put	= snd_ac97_ymf753_spdif_source_put,
-	},
-	{
-		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Output Pin",
-		.info	= snd_ac97_ymf753_spdif_output_pin_info,
-		.get	= snd_ac97_ymf753_spdif_output_pin_get,
-		.put	= snd_ac97_ymf753_spdif_output_pin_put,
-	},
-	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",NONE,NONE) "Mute", AC97_YMF753_DIT_CTRL2, 2, 1, 1)
-};
-
-
-/*
- * C-Media codecs
- */
-
-static int snd_ac97_cmedia_spdif_playback_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	static char *texts[] = { "Analog", "Digital" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-	if (uinfo->value.enumerated.item > 1)
-		uinfo->value.enumerated.item = 1;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int snd_ac97_cmedia_spdif_playback_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	unsigned short val;
-
-	val = ac97->regs[AC97_CM9739_SPDIF_CTRL];
-	ucontrol->value.enumerated.item[0] = (val >> 1) & 0x01;
-	return 0;
-}
-
-static int snd_ac97_cmedia_spdif_playback_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-
-	return snd_ac97_update_bits(ac97, AC97_CM9739_SPDIF_CTRL,
-				    0x01 << 1, 
-				    (ucontrol->value.enumerated.item[0] & 0x01) << 1);
-}
-
-static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = {
-	/* BIT 0: SPDI_EN - always true */
-	{ /* BIT 1: SPDIFS */
-		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-		.info	= snd_ac97_cmedia_spdif_playback_source_info,
-		.get	= snd_ac97_cmedia_spdif_playback_source_get,
-		.put	= snd_ac97_cmedia_spdif_playback_source_put,
-	},
-	/* BIT 2: IG_SPIV */
-	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9739_SPDIF_CTRL, 2, 1, 0),
-	/* BIT 3: SPI2F */
-	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9739_SPDIF_CTRL, 3, 1, 0), 
-	/* BIT 4: SPI2SDI */
-	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9739_SPDIF_CTRL, 4, 1, 0),
-	/* BIT 8: SPD32 - 32bit SPDIF - not supported yet */
-};
-
-static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = {
-	AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0),
-};
-
-static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = {
-	AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0),
-	AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0),
-};
-
 /*
  *
  */
@@ -1414,7 +1052,7 @@ static int snd_ac97_try_volume_mix(ac97_
 	if (!(val & mask)) {
 		/* nothing seems to be here - mute flag is not set */
 		/* try another test */
-		snd_ac97_write_cache_test(ac97, reg, val | mask);
+		snd_ac97_write_cache(ac97, reg, val | mask);
 		val = snd_ac97_read(ac97, reg);
 		if (!(val & mask))
 			return 0;	/* nothing here */
@@ -1422,7 +1060,7 @@ static int snd_ac97_try_volume_mix(ac97_
 	return 1;		/* success, useable */
 }
 
-static int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit)
+int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit)
 {
 	unsigned short mask, val, orig, res;
 
@@ -1491,7 +1129,7 @@ static inline int printable(unsigned int
 	return x;
 }
 
-static snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97)
+snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97)
 {
 	snd_kcontrol_new_t template;
 	memcpy(&template, _template, sizeof(template));
@@ -1500,8 +1138,9 @@ static snd_kcontrol_t *snd_ac97_cnew(con
 	return snd_ctl_new1(&template, ac97);
 }
 
-static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97)
+static int snd_ac97_mixer_build(ac97_t * ac97)
 {
+	snd_card_t *card = ac97->card;
 	snd_kcontrol_t *kctl;
 	const snd_kcontrol_new_t *knew;
 	int err;
@@ -1751,39 +1390,9 @@ static int snd_ac97_mixer_build(snd_card
 	snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x0000);
 
 	/* build 3D controls */
-	switch (ac97->id) {
-	case AC97_ID_STAC9708:
-		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
-			return err;
-		strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
-		kctl->private_value = AC97_3D_CONTROL | (3 << 16);
-		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
-			return err;
-		strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth");
-		kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16);
-		snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
-		break;
-	case AC97_ID_STAC9700:
-	case AC97_ID_STAC9721:
-	case AC97_ID_STAC9744:
-	case AC97_ID_STAC9756:
-		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
-			return err;
-		strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
-		kctl->private_value = AC97_3D_CONTROL | (3 << 16);
-		snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
-		break;
-	case AC97_ID_YMF753:
-		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
-			return err;
-		strcpy(kctl->id.name, "3D Control - Wide");
-		kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16);
-		snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
-		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0)
-			return err;
-		snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00);
-		break;
-	default:
+	if (ac97->build_ops && ac97->build_ops->build_3d) {
+		ac97->build_ops->build_3d(ac97);
+	} else {
 		if (snd_ac97_try_volume_mix(ac97, AC97_3D_CONTROL)) {
 			unsigned short val;
 			val = 0x0707;
@@ -1801,115 +1410,31 @@ static int snd_ac97_mixer_build(snd_card
 			snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
 		}
 	}
-	
+
 	/* build S/PDIF controls */
 	if (ac97->ext_id & AC97_EI_SPDIF) {
-		if (ac97->flags & AC97_CS_SPDIF) {
-			for (idx = 0; idx < 3; idx++)
-				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)
-					return err;
-			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cirrus_controls_spdif[0], ac97))) < 0)
+		if (ac97->build_ops && ac97->build_ops->build_spdif) {
+			if ((err = ac97->build_ops->build_spdif(ac97)) < 0)
 				return err;
-			switch (ac97->id & AC97_ID_CS_MASK) {
-			case AC97_ID_CS4205:
-				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cirrus_controls_spdif[1], ac97))) < 0)
-					return err;
-				break;
-			}
-			/* set default PCM S/PDIF params */
-			/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
-			snd_ac97_write_cache(ac97, AC97_CSR_SPDIF, 0x0a20);
-		} else if (ac97->flags & AC97_CX_SPDIF) {
-			for (idx = 0; idx < 3; idx++)
-				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)
-					return err;
-			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_conexant_controls_spdif[0], ac97))) < 0)
-				return err;
-			/* set default PCM S/PDIF params */
-			/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
-			snd_ac97_write_cache(ac97, AC97_CXR_AUDIO_MISC,
-					     snd_ac97_read(ac97, AC97_CXR_AUDIO_MISC) & ~(AC97_CXR_SPDIFEN|AC97_CXR_COPYRGT|AC97_CXR_SPDIF_MASK));
-			
 		} else {
 			for (idx = 0; idx < 5; idx++)
 				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)
 					return err;
-			switch (ac97->id) {
-			case AC97_ID_YMF753:
-				for (idx = 0; idx < 3; idx++)
-					if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_spdif[idx], ac97))) < 0)
-						return err;
-				break;
-			case AC97_ID_AD1980:
-				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ad1980_spdif_source, ac97))) < 0)
+			if (ac97->build_ops && ac97->build_ops->build_post_spdif) {
+				if ((err = ac97->build_ops->build_post_spdif(ac97)) < 0)
 					return err;
-				break;
-			case AC97_ID_CM9739:
-				for (idx = 0; idx < ARRAY_SIZE(snd_ac97_cm9739_controls_spdif); idx++)
-					if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9739_controls_spdif[idx], ac97))) < 0)
-						return err;
-				break;
 			}
 			/* set default PCM S/PDIF params */
 			/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
 			snd_ac97_write_cache(ac97, AC97_SPDIF, 0x2a20);
 		}
-
 		ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
 	}
 	
 	/* build chip specific controls */
-	switch (ac97->id) {
-	case AC97_ID_STAC9700:
-	case AC97_ID_STAC9708:
-	case AC97_ID_STAC9721:
-	case AC97_ID_STAC9744:
-	case AC97_ID_STAC9756:
-		snd_ac97_write_cache_test(ac97, AC97_SIGMATEL_ANALOG, snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) & ~0x0003);
-		if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 1))
-			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[0], ac97))) < 0)
-				return err;
-		if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0))
-			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[1], ac97))) < 0)
-				return err;
-		break;
-	case AC97_ID_ALC650:
-		/* detect ALC650 rev.E of later */
-		for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_alc650); idx++)
-			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_alc650[idx], ac97))) < 0)
-				return err;
-		if ((err = snd_ctl_add(card, snd_ac97_cnew(ac97->spec.dev_flags ?
-							   &snd_ac97_control_alc650_mic :
-							   &snd_ac97_control_alc650_mic_gpio, ac97))) < 0)
-			return err;
-		if (ac97->ext_id & AC97_EI_SPDIF) {
-			for (idx = 0; idx < ARRAY_SIZE(snd_ac97_spdif_controls_alc650); idx++)
-				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_spdif_controls_alc650[idx], ac97))) < 0)
-					return err;
-		}
-		break;
-	case AC97_ID_VT1616:
-		if (snd_ac97_try_bit(ac97, 0x5a, 9))
-			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_vt1616[0], ac97))) < 0)
-				return err;
-		for (idx = 1; idx < ARRAY_SIZE(snd_ac97_controls_vt1616); idx++)
-			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_vt1616[idx], ac97))) < 0)
-				return err;
-		break;
-	case AC97_ID_CM9739:
-		for (idx = 1; idx < ARRAY_SIZE(snd_ac97_cm9739_controls); idx++)
-			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9739_controls[idx], ac97))) < 0)
-				return err;
-		break;
-	case AC97_ID_CM9738:
-		for (idx = 1; idx < ARRAY_SIZE(snd_ac97_cm9738_controls); idx++)
-			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9738_controls[idx], ac97))) < 0)
-				return err;
-		break;
-	default:
-		/* nothing */
-		break;
-	}
+	if (ac97->build_ops && ac97->build_ops->build_specific)
+		if ((err = ac97->build_ops->build_specific(ac97)) < 0)
+			return err;
 
 	if (snd_ac97_try_bit(ac97, AC97_POWERDOWN, 15)) {
 		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_eapd, ac97))) < 0)
@@ -1931,7 +1456,7 @@ static int snd_ac97_test_rate(ac97_t *ac
 	unsigned int tmp;
 
 	tmp = ((unsigned int)rate * ac97->clock) / 48000;
-	snd_ac97_write_cache_test(ac97, reg, tmp & 0xffff);
+	snd_ac97_write_cache(ac97, reg, tmp & 0xffff);
 	val = snd_ac97_read(ac97, reg);
 	return val == (tmp & 0xffff);
 }
@@ -1961,7 +1486,7 @@ static void snd_ac97_determine_rates(ac9
 	*r_result = result;
 }
 
-static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem)
+void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem)
 {
 	const ac97_codec_id_t *pid;
 
@@ -2138,12 +1663,12 @@ int snd_ac97_mixer(snd_card_t * card, ac
 	/* FIXME: add powerdown control */
 	if (ac97_is_audio(ac97)) {
 		/* nothing should be in powerdown mode */
-		snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
-		snd_ac97_write_cache_test(ac97, AC97_RESET, 0);		/* reset to defaults */
+		snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0);
+		snd_ac97_write_cache(ac97, AC97_RESET, 0);		/* reset to defaults */
 		udelay(100);
 		/* nothing should be in powerdown mode */
-		snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
-		snd_ac97_write_cache_test(ac97, AC97_GENERAL_PURPOSE, 0);
+		snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0);
+		snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0);
 		end_time = jiffies + (HZ / 10);
 		do {
 			if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f)
@@ -2212,10 +1737,10 @@ int snd_ac97_mixer(snd_card_t * card, ac
 			snd_ac97_free(ac97);
 			return err;
 		}
-	}
-	if (ac97_is_audio(ac97) && snd_ac97_mixer_build(card, ac97) < 0) {
-		snd_ac97_free(ac97);
-		return -ENOMEM;
+		if (snd_ac97_mixer_build(ac97) < 0) {
+			snd_ac97_free(ac97);
+			return -ENOMEM;
+		}
 	}
 	snd_ac97_proc_init(card, ac97, "ac97");
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) {
@@ -2357,21 +1882,21 @@ int snd_ac97_modem(snd_card_t * card, ac
 		/* note: it's important to set the rate at first */
 		tmp = AC97_MEA_GPIO;
 		if (ac97->ext_mid & AC97_MEI_LINE1) {
-			snd_ac97_write_cache_test(ac97, AC97_LINE1_RATE, 12000);
+			snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000);
 			tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1;
 		}
 		if (ac97->ext_mid & AC97_MEI_LINE2) {
-			snd_ac97_write_cache_test(ac97, AC97_LINE2_RATE, 12000);
+			snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000);
 			tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2;
 		}
 		if (ac97->ext_mid & AC97_MEI_HANDSET) {
-			snd_ac97_write_cache_test(ac97, AC97_HANDSET_RATE, 12000);
+			snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000);
 			tmp |= AC97_MEA_HADC | AC97_MEA_HDAC;
 		}
-		snd_ac97_write_cache_test(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8));
+		snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8));
 		udelay(100);
 		/* nothing should be in powerdown mode */
-		snd_ac97_write_cache_test(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8));
+		snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8));
 		end_time = jiffies + (HZ / 10);
 		do {
 			if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp)
@@ -2422,270 +1947,6 @@ int snd_ac97_modem(snd_card_t * card, ac
 }
 
 /*
- * proc interface
- */
-
-static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx)
-{
-	char name[64];
-	unsigned int id;
-	unsigned short val, tmp, ext, mext;
-	static const char *spdif_slots[4] = { " SPDIF=3/4", " SPDIF=7/8", " SPDIF=6/9", " SPDIF=res" };
-	static const char *spdif_rates[4] = { " Rate=44.1kHz", " Rate=res", " Rate=48kHz", " Rate=32kHz" };
-	static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", " Rate=res", " Rate=res" };
-
-	id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;
-	id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
-	snd_ac97_get_name(NULL, id, name, 0);
-	snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name);
-	if ((ac97->scaps & AC97_SCAP_AUDIO) == 0)
-		goto __modem;
-
-	// val = snd_ac97_read(ac97, AC97_RESET);
-	val = ac97->caps;
-	snd_iprintf(buffer, "Capabilities     :%s%s%s%s%s%s\n",
-	    	    val & AC97_BC_DEDICATED_MIC ? " -dedicated MIC PCM IN channel-" : "",
-		    val & AC97_BC_RESERVED1 ? " -reserved1-" : "",
-		    val & AC97_BC_BASS_TREBLE ? " -bass & treble-" : "",
-		    val & AC97_BC_SIM_STEREO ? " -simulated stereo-" : "",
-		    val & AC97_BC_HEADPHONE ? " -headphone out-" : "",
-		    val & AC97_BC_LOUDNESS ? " -loudness-" : "");
-	tmp = ac97->caps & AC97_BC_DAC_MASK;
-	snd_iprintf(buffer, "DAC resolution   : %s%s%s%s\n",
-		    tmp == AC97_BC_16BIT_DAC ? "16-bit" : "",
-		    tmp == AC97_BC_18BIT_DAC ? "18-bit" : "",
-		    tmp == AC97_BC_20BIT_DAC ? "20-bit" : "",
-		    tmp == AC97_BC_DAC_MASK ? "???" : "");
-	tmp = ac97->caps & AC97_BC_ADC_MASK;
-	snd_iprintf(buffer, "ADC resolution   : %s%s%s%s\n",
-		    tmp == AC97_BC_16BIT_ADC ? "16-bit" : "",
-		    tmp == AC97_BC_18BIT_ADC ? "18-bit" : "",
-		    tmp == AC97_BC_20BIT_ADC ? "20-bit" : "",
-		    tmp == AC97_BC_ADC_MASK ? "???" : "");
-	snd_iprintf(buffer, "3D enhancement   : %s\n",
-		snd_ac97_stereo_enhancements[(val >> 10) & 0x1f]);
-	snd_iprintf(buffer, "\nCurrent setup\n");
-	val = snd_ac97_read(ac97, AC97_MIC);
-	snd_iprintf(buffer, "Mic gain         : %s [%s]\n", val & 0x0040 ? "+20dB" : "+0dB", ac97->regs[AC97_MIC] & 0x0040 ? "+20dB" : "+0dB");
-	val = snd_ac97_read(ac97, AC97_GENERAL_PURPOSE);
-	snd_iprintf(buffer, "POP path         : %s 3D\n"
-		    "Sim. stereo      : %s\n"
-		    "3D enhancement   : %s\n"
-		    "Loudness         : %s\n"
-		    "Mono output      : %s\n"
-		    "Mic select       : %s\n"
-		    "ADC/DAC loopback : %s\n",
-		    val & 0x8000 ? "post" : "pre",
-		    val & 0x4000 ? "on" : "off",
-		    val & 0x2000 ? "on" : "off",
-		    val & 0x1000 ? "on" : "off",
-		    val & 0x0200 ? "Mic" : "MIX",
-		    val & 0x0100 ? "Mic2" : "Mic1",
-		    val & 0x0080 ? "on" : "off");
-
-	ext = snd_ac97_read(ac97, AC97_EXTENDED_ID);
-	if (ext == 0)
-		goto __modem;
-		
-	snd_iprintf(buffer, "Extended ID      : codec=%i rev=%i%s%s%s%s DSA=%i%s%s%s%s\n",
-			(ext & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT,
-			(ext & AC97_EI_REV_MASK) >> AC97_EI_REV_SHIFT,
-			ext & AC97_EI_AMAP ? " AMAP" : "",
-			ext & AC97_EI_LDAC ? " LDAC" : "",
-			ext & AC97_EI_SDAC ? " SDAC" : "",
-			ext & AC97_EI_CDAC ? " CDAC" : "",
-			(ext & AC97_EI_DACS_SLOT_MASK) >> AC97_EI_DACS_SLOT_SHIFT,
-			ext & AC97_EI_VRM ? " VRM" : "",
-			ext & AC97_EI_SPDIF ? " SPDIF" : "",
-			ext & AC97_EI_DRA ? " DRA" : "",
-			ext & AC97_EI_VRA ? " VRA" : "");
-	val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);
-	snd_iprintf(buffer, "Extended status  :%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
-			val & AC97_EA_PRL ? " PRL" : "",
-			val & AC97_EA_PRK ? " PRK" : "",
-			val & AC97_EA_PRJ ? " PRJ" : "",
-			val & AC97_EA_PRI ? " PRI" : "",
-			val & AC97_EA_SPCV ? " SPCV" : "",
-			val & AC97_EA_MDAC ? " MADC" : "",
-			val & AC97_EA_LDAC ? " LDAC" : "",
-			val & AC97_EA_SDAC ? " SDAC" : "",
-			val & AC97_EA_CDAC ? " CDAC" : "",
-			ext & AC97_EI_SPDIF ? spdif_slots[(val & AC97_EA_SPSA_SLOT_MASK) >> AC97_EA_SPSA_SLOT_SHIFT] : "",
-			val & AC97_EA_VRM ? " VRM" : "",
-			val & AC97_EA_SPDIF ? " SPDIF" : "",
-			val & AC97_EA_DRA ? " DRA" : "",
-			val & AC97_EA_VRA ? " VRA" : "");
-	if (ext & AC97_EI_VRA) {	/* VRA */
-		val = snd_ac97_read(ac97, AC97_PCM_FRONT_DAC_RATE);
-		snd_iprintf(buffer, "PCM front DAC    : %iHz\n", val);
-		if (ext & AC97_EI_SDAC) {
-			val = snd_ac97_read(ac97, AC97_PCM_SURR_DAC_RATE);
-			snd_iprintf(buffer, "PCM Surr DAC     : %iHz\n", val);
-		}
-		if (ext & AC97_EI_LDAC) {
-			val = snd_ac97_read(ac97, AC97_PCM_LFE_DAC_RATE);
-			snd_iprintf(buffer, "PCM LFE DAC      : %iHz\n", val);
-		}
-		val = snd_ac97_read(ac97, AC97_PCM_LR_ADC_RATE);
-		snd_iprintf(buffer, "PCM ADC          : %iHz\n", val);
-	}
-	if (ext & AC97_EI_VRM) {
-		val = snd_ac97_read(ac97, AC97_PCM_MIC_ADC_RATE);
-		snd_iprintf(buffer, "PCM MIC ADC      : %iHz\n", val);
-	}
-	if ((ext & AC97_EI_SPDIF) || (ac97->flags & AC97_CS_SPDIF)) {
-	        if (ac97->flags & AC97_CS_SPDIF)
-			val = snd_ac97_read(ac97, AC97_CSR_SPDIF);
-		else
-			val = snd_ac97_read(ac97, AC97_SPDIF);
-
-		snd_iprintf(buffer, "SPDIF Control    :%s%s%s%s Category=0x%x Generation=%i%s%s%s\n",
-			val & AC97_SC_PRO ? " PRO" : " Consumer",
-			val & AC97_SC_NAUDIO ? " Non-audio" : " PCM",
-			val & AC97_SC_COPY ? " Copyright" : "",
-			val & AC97_SC_PRE ? " Preemph50/15" : "",
-			(val & AC97_SC_CC_MASK) >> AC97_SC_CC_SHIFT,
-			(val & AC97_SC_L) >> 11,
-			(ac97->flags & AC97_CS_SPDIF) ?
-			    spdif_rates_cs4205[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT] :
-			    spdif_rates[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT],
-			(ac97->flags & AC97_CS_SPDIF) ?
-			    (val & AC97_SC_DRS ? " Validity" : "") :
-			    (val & AC97_SC_DRS ? " DRS" : ""),
-			(ac97->flags & AC97_CS_SPDIF) ?
-			    (val & AC97_SC_V ? " Enabled" : "") :
-			    (val & AC97_SC_V ? " Validity" : ""));
-	}
-
-      __modem:
-	mext = snd_ac97_read(ac97, AC97_EXTENDED_MID);
-	if (mext == 0)
-		return;
-	
-	snd_iprintf(buffer, "Extended modem ID: codec=%i%s%s%s%s%s\n",
-			(mext & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT,
-			mext & AC97_MEI_CID2 ? " CID2" : "",
-			mext & AC97_MEI_CID1 ? " CID1" : "",
-			mext & AC97_MEI_HANDSET ? " HSET" : "",
-			mext & AC97_MEI_LINE2 ? " LIN2" : "",
-			mext & AC97_MEI_LINE1 ? " LIN1" : "");
-	val = snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS);
-	snd_iprintf(buffer, "Modem status     :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
-			val & AC97_MEA_GPIO ? " GPIO" : "",
-			val & AC97_MEA_MREF ? " MREF" : "",
-			val & AC97_MEA_ADC1 ? " ADC1" : "",
-			val & AC97_MEA_DAC1 ? " DAC1" : "",
-			val & AC97_MEA_ADC2 ? " ADC2" : "",
-			val & AC97_MEA_DAC2 ? " DAC2" : "",
-			val & AC97_MEA_HADC ? " HADC" : "",
-			val & AC97_MEA_HDAC ? " HDAC" : "",
-			val & AC97_MEA_PRA ? " PRA(GPIO)" : "",
-			val & AC97_MEA_PRB ? " PRB(res)" : "",
-			val & AC97_MEA_PRC ? " PRC(ADC1)" : "",
-			val & AC97_MEA_PRD ? " PRD(DAC1)" : "",
-			val & AC97_MEA_PRE ? " PRE(ADC2)" : "",
-			val & AC97_MEA_PRF ? " PRF(DAC2)" : "",
-			val & AC97_MEA_PRG ? " PRG(HADC)" : "",
-			val & AC97_MEA_PRH ? " PRH(HDAC)" : "");
-	if (mext & AC97_MEI_LINE1) {
-		val = snd_ac97_read(ac97, AC97_LINE1_RATE);
-		snd_iprintf(buffer, "Line1 rate       : %iHz\n", val);
-	}
-	if (mext & AC97_MEI_LINE2) {
-		val = snd_ac97_read(ac97, AC97_LINE2_RATE);
-		snd_iprintf(buffer, "Line2 rate       : %iHz\n", val);
-	}
-	if (mext & AC97_MEI_HANDSET) {
-		val = snd_ac97_read(ac97, AC97_HANDSET_RATE);
-		snd_iprintf(buffer, "Headset rate     : %iHz\n", val);
-	}
-}
-
-static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
-{
-	ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
-	
-	if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) {	// Analog Devices AD1881/85/86
-		int idx;
-		down(&ac97->spec.ad18xx.mutex);
-		for (idx = 0; idx < 3; idx++)
-			if (ac97->spec.ad18xx.id[idx]) {
-				/* select single codec */
-				snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
-				snd_ac97_proc_read_main(ac97, buffer, idx);
-				snd_iprintf(buffer, "\n\n");
-			}
-		/* select all codecs */
-		snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
-		up(&ac97->spec.ad18xx.mutex);
-		
-		snd_iprintf(buffer, "\nAD18XX configuration\n");
-		snd_iprintf(buffer, "Unchained        : 0x%04x,0x%04x,0x%04x\n",
-			ac97->spec.ad18xx.unchained[0],
-			ac97->spec.ad18xx.unchained[1],
-			ac97->spec.ad18xx.unchained[2]);
-		snd_iprintf(buffer, "Chained          : 0x%04x,0x%04x,0x%04x\n",
-			ac97->spec.ad18xx.chained[0],
-			ac97->spec.ad18xx.chained[1],
-			ac97->spec.ad18xx.chained[2]);
-	} else {
-		snd_ac97_proc_read_main(ac97, buffer, 0);
-	}
-}
-
-static void snd_ac97_proc_regs_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx)
-{
-	int reg, val;
-
-	for (reg = 0; reg < 0x80; reg += 2) {
-		val = snd_ac97_read(ac97, reg);
-		snd_iprintf(buffer, "%i:%02x = %04x\n", subidx, reg, val);
-	}
-}
-
-static void snd_ac97_proc_regs_read(snd_info_entry_t *entry, 
-				    snd_info_buffer_t * buffer)
-{
-	ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
-
-	if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) {	// Analog Devices AD1881/85/86
-
-		int idx;
-		down(&ac97->spec.ad18xx.mutex);
-		for (idx = 0; idx < 3; idx++)
-			if (ac97->spec.ad18xx.id[idx]) {
-				/* select single codec */
-				snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
-				snd_ac97_proc_regs_read_main(ac97, buffer, idx);
-			}
-		/* select all codecs */
-		snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
-		up(&ac97->spec.ad18xx.mutex);
-	} else {
-		snd_ac97_proc_regs_read_main(ac97, buffer, 0);
-	}	
-}
-
-static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix)
-{
-	snd_info_entry_t *entry;
-	char name[32];
-
-	if (ac97->num)
-		sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num);
-	else
-		sprintf(name, "%s#%d", prefix, ac97->addr);
-	if (! snd_card_proc_new(card, name, &entry))
-		snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read);
-	if (ac97->num)
-		sprintf(name, "%s#%d-%dregs", prefix, ac97->addr, ac97->num);
-	else
-		sprintf(name, "%s#%dregs", prefix, ac97->addr);
-	if (! snd_card_proc_new(card, name, &entry))
-		snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read);
-}
-
-/*
  *  PCM support
  */
 
diff -puN /dev/null sound/pci/ac97/ac97_local.h
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/sound/pci/ac97/ac97_local.h	Tue Jul 29 12:11:31 2003
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Universal interface for Audio Codec '97
+ *
+ *  For more details look to AC '97 component specification revision 2.2
+ *  by Intel Corporation (http://developer.intel.com).
+ *
+ *
+ *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#define AC97_SINGLE(xname, reg, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \
+  .get = snd_ac97_get_single, .put = snd_ac97_put_single, \
+  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
+
+/* ac97_codec.c */
+extern const char *snd_ac97_stereo_enhancements[];
+extern const snd_kcontrol_new_t snd_ac97_controls_3d[];
+extern const snd_kcontrol_new_t snd_ac97_controls_spdif[];
+snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97);
+void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem);
+int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
+int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit);
+
+/* ac97_proc.c */
+void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix);
diff -puN sound/pci/ac97/ac97_patch.c~alsa-bk-2003-07-28 sound/pci/ac97/ac97_patch.c
--- 25/sound/pci/ac97/ac97_patch.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ac97/ac97_patch.c	Tue Jul 29 12:11:31 2003
@@ -3,7 +3,8 @@
  *  Universal interface for Audio Codec '97
  *
  *  For more details look to AC '97 component specification revision 2.2
- *  by Intel Corporation (http://developer.intel.com).
+ *  by Intel Corporation (http://developer.intel.com) and to datasheets
+ *  for specific codecs.
  *
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -28,15 +29,203 @@
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <sound/control.h>
 #include <sound/ac97_codec.h>
-#include <sound/asoundef.h>
-#include <sound/initval.h>
 #include "ac97_patch.h"
+#include "ac97_id.h"
+#include "ac97_local.h"
+
+#define chip_t ac97_t
 
 /*
  *  Chip specific initialization
  */
 
+static int patch_build_controls(ac97_t * ac97, const snd_kcontrol_new_t *controls, int count)
+{
+	int idx, err;
+
+	for (idx = 0; idx < count; idx++)
+		if ((err = snd_ctl_add(ac97->card, snd_ac97_cnew(&controls[idx], ac97))) < 0)
+			return err;
+	return 0;
+}
+
+/* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */
+
+/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */
+static int snd_ac97_ymf753_info_speaker(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[3] = {
+		"Standard", "Small", "Smaller"
+	};
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+	if (uinfo->value.enumerated.item > 2)
+		uinfo->value.enumerated.item = 2;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ac97_ymf753_get_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	val = ac97->regs[AC97_YMF753_3D_MODE_SEL];
+	val = (val >> 10) & 3;
+	if (val > 0)    /* 0 = invalid */
+		val--;
+	ucontrol->value.enumerated.item[0] = val;
+	return 0;
+}
+
+static int snd_ac97_ymf753_put_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	if (ucontrol->value.enumerated.item[0] > 2)
+		return -EINVAL;
+	val = (ucontrol->value.enumerated.item[0] + 1) << 10;
+	return snd_ac97_update(ac97, AC97_YMF753_3D_MODE_SEL, val);
+}
+
+static const snd_kcontrol_new_t snd_ac97_ymf753_controls_speaker =
+{
+	.iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name   = "3D Control - Speaker",
+	.info   = snd_ac97_ymf753_info_speaker,
+	.get    = snd_ac97_ymf753_get_speaker,
+	.put    = snd_ac97_ymf753_put_speaker,
+};
+
+/* It is possible to indicate to the Yamaha YMF753 the source to direct to the S/PDIF output. */
+static int snd_ac97_ymf753_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[2] = { "AC-Link", "A/D Converter" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ac97_ymf753_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	val = ac97->regs[AC97_YMF753_DIT_CTRL2];
+	ucontrol->value.enumerated.item[0] = (val >> 1) & 1;
+	return 0;
+}
+
+static int snd_ac97_ymf753_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	if (ucontrol->value.enumerated.item[0] > 1)
+		return -EINVAL;
+	val = ucontrol->value.enumerated.item[0] << 1;
+	return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0002, val);
+}
+
+/* The AC'97 spec states that the S/PDIF signal is to be output at pin 48.
+   The YMF753 will output the S/PDIF signal to pin 43, 47 (EAPD), or 48.
+   By default, no output pin is selected, and the S/PDIF signal is not output.
+   There is also a bit to mute S/PDIF output in a vendor-specific register. */
+static int snd_ac97_ymf753_spdif_output_pin_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[3] = { "Disabled", "Pin 43", "Pin 48" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+	if (uinfo->value.enumerated.item > 2)
+		uinfo->value.enumerated.item = 2;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ac97_ymf753_spdif_output_pin_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	val = ac97->regs[AC97_YMF753_DIT_CTRL2];
+	ucontrol->value.enumerated.item[0] = (val & 0x0008) ? 2 : (val & 0x0020) ? 1 : 0;
+	return 0;
+}
+
+static int snd_ac97_ymf753_spdif_output_pin_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	if (ucontrol->value.enumerated.item[0] > 2)
+		return -EINVAL;
+	val = (ucontrol->value.enumerated.item[0] == 2) ? 0x0008 :
+	      (ucontrol->value.enumerated.item[0] == 1) ? 0x0020 : 0;
+	return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0028, val);
+	/* The following can be used to direct S/PDIF output to pin 47 (EAPD).
+	   snd_ac97_write_cache(ac97, 0x62, snd_ac97_read(ac97, 0x62) | 0x0008); */
+}
+
+static const snd_kcontrol_new_t snd_ac97_ymf753_controls_spdif[3] = {
+	{
+		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+		.info	= snd_ac97_ymf753_spdif_source_info,
+		.get	= snd_ac97_ymf753_spdif_source_get,
+		.put	= snd_ac97_ymf753_spdif_source_put,
+	},
+	{
+		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Output Pin",
+		.info	= snd_ac97_ymf753_spdif_output_pin_info,
+		.get	= snd_ac97_ymf753_spdif_output_pin_get,
+		.put	= snd_ac97_ymf753_spdif_output_pin_put,
+	},
+	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",NONE,NONE) "Mute", AC97_YMF753_DIT_CTRL2, 2, 1, 1)
+};
+
+static int patch_yamaha_ymf753_3d(ac97_t * ac97)
+{
+	snd_kcontrol_t *kctl;
+	int err;
+
+	if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
+		return err;
+	strcpy(kctl->id.name, "3D Control - Wide");
+	kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16);
+	snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
+	if ((err = snd_ctl_add(ac97->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0)
+		return err;
+	snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00);
+	return 0;
+}
+
+static int patch_yamaha_ymf753_post_spdif(ac97_t * ac97)
+{
+	int err;
+
+	if ((err = patch_build_controls(ac97, snd_ac97_ymf753_controls_spdif, ARRAY_SIZE(snd_ac97_ymf753_controls_spdif))) < 0)
+		return err;
+	return 0;
+}
+
+static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = {
+	.build_3d	= patch_yamaha_ymf753_3d,
+	.build_post_spdif = patch_yamaha_ymf753_post_spdif
+};
+
 int patch_yamaha_ymf753(ac97_t * ac97)
 {
 	/* Patch for Yamaha YMF753, Copyright (c) by David Shust, dshust@shustring.com.
@@ -46,6 +235,7 @@ int patch_yamaha_ymf753(ac97_t * ac97)
 	   By default, no output pin is selected, and the S/PDIF signal is not output.
 	   There is also a bit to mute S/PDIF output in a vendor-specific register.
 	*/
+	ac97->build_ops = &patch_yamaha_ymf753_ops;
 	ac97->caps |= AC97_BC_BASS_TREBLE;
 	ac97->caps |= 0x04 << 10; /* Yamaha 3D enhancement */
 	return 0;
@@ -57,12 +247,6 @@ int patch_yamaha_ymf753(ac97_t * ac97)
  *  added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
  */
 
-#define AC97_WM97XX_FMIXER_VOL	0x72
-#define AC97_WM9704_RMIXER_VOL	0x74
-#define AC97_WM9704_TEST	0x5a
-#define AC97_WM9704_RPCM_VOL	0x70
-#define AC97_WM9711_OUT3VOL	0x16
- 
 int patch_wolfson03(ac97_t * ac97)
 {
 	/* This is known to work for the ViewSonic ViewPad 1000
@@ -117,10 +301,89 @@ int patch_tritech_tr28028(ac97_t * ac97)
 	return 0;
 }
 
+static int patch_sigmatel_stac9700_3d(ac97_t * ac97)
+{
+	snd_kcontrol_t *kctl;
+	int err;
+
+	if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
+		return err;
+	strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
+	kctl->private_value = AC97_3D_CONTROL | (3 << 16);
+	snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
+	return 0;
+}
+
+static int patch_sigmatel_stac9708_3d(ac97_t * ac97)
+{
+	snd_kcontrol_t *kctl;
+	int err;
+
+	if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
+		return err;
+	strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
+	kctl->private_value = AC97_3D_CONTROL | (3 << 16);
+	if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
+		return err;
+	strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth");
+	kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16);
+	snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
+	return 0;
+}
+
+static const snd_kcontrol_new_t snd_ac97_sigmatel_4speaker =
+AC97_SINGLE("Sigmatel 4-Speaker Stereo Playback Switch", AC97_SIGMATEL_DAC2INVERT, 2, 1, 0);
+
+static const snd_kcontrol_new_t snd_ac97_sigmatel_phaseinvert =
+AC97_SINGLE("Sigmatel Surround Phase Inversion Playback Switch", AC97_SIGMATEL_DAC2INVERT, 3, 1, 0);
+
+static const snd_kcontrol_new_t snd_ac97_sigmatel_controls[] = {
+AC97_SINGLE("Sigmatel DAC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 1, 1, 0),
+AC97_SINGLE("Sigmatel ADC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 0, 1, 0)
+};
+
+static int patch_sigmatel_stac97xx_specific(ac97_t * ac97)
+{
+	int err;
+
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_ANALOG, snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) & ~0x0003);
+	if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 1))
+		if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_controls[0], 1)) < 0)
+			return err;
+	if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0))
+		if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_controls[1], 1)) < 0)
+			return err;
+	if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 2))
+		if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_4speaker, 1)) < 0)
+			return err;
+	if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 3))
+		if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_phaseinvert, 1)) < 0)
+			return err;
+	return 0;
+}
+
+static struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = {
+	.build_3d	= patch_sigmatel_stac9700_3d,
+	.build_specific	= patch_sigmatel_stac97xx_specific
+};
+
+static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = {
+	.build_3d	= patch_sigmatel_stac9708_3d,
+	.build_specific	= patch_sigmatel_stac97xx_specific
+};
+
+int patch_sigmatel_stac9700(ac97_t * ac97)
+{
+	ac97->build_ops = &patch_sigmatel_stac9700_ops;
+	return 0;
+}
+
 int patch_sigmatel_stac9708(ac97_t * ac97)
 {
 	unsigned int codec72, codec6c;
 
+	ac97->build_ops = &patch_sigmatel_stac9708_ops;
+
 	codec72 = snd_ac97_read(ac97, AC97_SIGMATEL_BIAS2) & 0x8000;
 	codec6c = snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG);
 
@@ -142,6 +405,7 @@ int patch_sigmatel_stac9708(ac97_t * ac9
 
 int patch_sigmatel_stac9721(ac97_t * ac97)
 {
+	ac97->build_ops = &patch_sigmatel_stac9700_ops;
 	if (snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) == 0) {
 		// patch for SigmaTel
 		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
@@ -156,6 +420,7 @@ int patch_sigmatel_stac9721(ac97_t * ac9
 int patch_sigmatel_stac9744(ac97_t * ac97)
 {
 	// patch for SigmaTel
+	ac97->build_ops = &patch_sigmatel_stac9700_ops;
 	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
 	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000);	/* is this correct? --jk */
 	snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
@@ -167,6 +432,7 @@ int patch_sigmatel_stac9744(ac97_t * ac9
 int patch_sigmatel_stac9756(ac97_t * ac97)
 {
 	// patch for SigmaTel
+	ac97->build_ops = &patch_sigmatel_stac9700_ops;
 	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
 	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000);	/* is this correct? --jk */
 	snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
@@ -175,6 +441,35 @@ int patch_sigmatel_stac9756(ac97_t * ac9
 	return 0;
 }
 
+static const snd_kcontrol_new_t snd_ac97_cirrus_controls_spdif[2] = {
+	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CSR_SPDIF, 15, 1, 0),
+	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", AC97_CSR_ACMODE, 0, 3, 0)
+};
+
+static int patch_cirrus_build_spdif(ac97_t * ac97)
+{
+	int err;
+
+	if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0)
+		return err;
+	if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[0], 1)) < 0)
+		return err;
+	switch (ac97->id & AC97_ID_CS_MASK) {
+	case AC97_ID_CS4205:
+		if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[1], 1)) < 0)
+			return err;
+		break;
+	}
+	/* set default PCM S/PDIF params */
+	/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
+	snd_ac97_write_cache(ac97, AC97_CSR_SPDIF, 0x0a20);
+	return 0;
+}
+
+static struct snd_ac97_build_ops patch_cirrus_ops = {
+	.build_spdif = patch_cirrus_build_spdif
+};
+
 int patch_cirrus_spdif(ac97_t * ac97)
 {
 	/* Basically, the cs4201/cs4205/cs4297a has non-standard sp/dif registers.
@@ -188,6 +483,7 @@ int patch_cirrus_spdif(ac97_t * ac97)
 	   - sp/dif ssource select is in 0x5e bits 0,1.
 	*/
 
+	ac97->build_ops = &patch_cirrus_ops;
 	ac97->flags |= AC97_CS_SPDIF; 
 	ac97->rates[AC97_RATES_SPDIF] &= ~SNDRV_PCM_RATE_32000;
         ac97->ext_id |= AC97_EI_SPDIF;	/* force the detection of spdif */
@@ -203,8 +499,32 @@ int patch_cirrus_cs4299(ac97_t * ac97)
 	return patch_cirrus_spdif(ac97);
 }
 
+static const snd_kcontrol_new_t snd_ac97_conexant_controls_spdif[1] = {
+	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CXR_AUDIO_MISC, 3, 1, 0),
+};
+
+static int patch_conexant_build_spdif(ac97_t * ac97)
+{
+	int err;
+
+	if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0)
+		return err;
+	if ((err = patch_build_controls(ac97, &snd_ac97_conexant_controls_spdif[0], 1)) < 0)
+		return err;
+	/* set default PCM S/PDIF params */
+	/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
+	snd_ac97_write_cache(ac97, AC97_CXR_AUDIO_MISC,
+			     snd_ac97_read(ac97, AC97_CXR_AUDIO_MISC) & ~(AC97_CXR_SPDIFEN|AC97_CXR_COPYRGT|AC97_CXR_SPDIF_MASK));
+	return 0;
+}
+
+static struct snd_ac97_build_ops patch_conexant_ops = {
+	.build_spdif = patch_conexant_build_spdif
+};
+
 int patch_conexant(ac97_t * ac97)
 {
+	ac97->build_ops = &patch_conexant_ops;
 	ac97->flags |= AC97_CX_SPDIF;
         ac97->ext_id |= AC97_EI_SPDIF;	/* force the detection of spdif */
 	return 0;
@@ -330,6 +650,26 @@ int patch_ad1881(ac97_t * ac97)
 	return 0;
 }
 
+static const snd_kcontrol_new_t snd_ac97_controls_ad1885[] = {
+	AC97_SINGLE("Digital Mono Direct", AC97_AD_MISC, 11, 1, 0),
+	AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0),
+	AC97_SINGLE("Low Power Mixer", AC97_AD_MISC, 14, 1, 0),
+	AC97_SINGLE("Zero Fill DAC", AC97_AD_MISC, 15, 1, 0),
+};
+
+static int patch_ad1885_specific(ac97_t * ac97)
+{
+	int err;
+
+	if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0)
+		return err;
+	return 0;
+}
+
+static struct snd_ac97_build_ops patch_ad1885_build_ops = {
+	.build_specific = &patch_ad1885_specific
+};
+
 int patch_ad1885(ac97_t * ac97)
 {
 	unsigned short jack;
@@ -341,6 +681,8 @@ int patch_ad1885(ac97_t * ac97)
 	/* turn off jack sense bits D8 & D9 */
 	jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF);
 	snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300);
+
+	ac97->build_ops = &patch_ad1885_build_ops;
 	return 0;
 }
 
@@ -353,11 +695,63 @@ int patch_ad1886(ac97_t * ac97)
 	return 0;
 }
 
+static int snd_ac97_ad1980_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[2] = { "AC-Link", "A/D Converter" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ac97_ad1980_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	val = ac97->regs[AC97_AD_SERIAL_CFG];
+	ucontrol->value.enumerated.item[0] = (val >> 2) & 1;
+	return 0;
+}
+
+static int snd_ac97_ad1980_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	if (ucontrol->value.enumerated.item[0] > 1)
+		return -EINVAL;
+	val = ucontrol->value.enumerated.item[0] << 2;
+	return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val);
+}
+
+static const snd_kcontrol_new_t snd_ac97_ad1980_spdif_source = {
+	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+	.info	= snd_ac97_ad1980_spdif_source_info,
+	.get	= snd_ac97_ad1980_spdif_source_get,
+	.put	= snd_ac97_ad1980_spdif_source_put,
+};
+
+static int patch_ad1980_post_spdif(ac97_t * ac97)
+{
+ 	return patch_build_controls(ac97, &snd_ac97_ad1980_spdif_source, 1);
+}
+
+static struct snd_ac97_build_ops patch_ad1980_build_ops = {
+	.build_post_spdif = &patch_ad1980_post_spdif
+};
+
 int patch_ad1980(ac97_t * ac97)
 {
 	unsigned short misc;
 	
 	patch_ad1881(ac97);
+	ac97->build_ops = &patch_ad1980_build_ops;
 	/* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */
 	/* it seems that most vendors connect line-out connector to headphone out of AC'97 */
 	misc = snd_ac97_read(ac97, AC97_AD_MISC);
@@ -365,6 +759,92 @@ int patch_ad1980(ac97_t * ac97)
 	return 0;
 }
 
+static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
+	AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
+	AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0),
+	AC97_SINGLE("Center/LFE Down Mix", AC97_ALC650_MULTICH, 2, 1, 0),
+	AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0),
+	/* 4: Analog Input To Surround */
+	/* 5: Analog Input To Center/LFE */
+	/* 6: Independent Master Volume Right */
+	/* 7: Independent Master Volume Left */
+	/* 8: reserved */
+	AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
+	AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0),
+#if 0 /* always set in patch_alc650 */
+	AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0),
+	AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0),
+	AC97_SINGLE("Surround DAC Switch", AC97_ALC650_SURR_DAC_VOL, 15, 1, 1),
+	AC97_DOUBLE("Surround DAC Volume", AC97_ALC650_SURR_DAC_VOL, 8, 0, 31, 1),
+	AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1),
+	AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1),
+#endif
+};
+
+static const snd_kcontrol_new_t snd_ac97_control_alc650_mic =
+AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0);
+
+static int snd_ac97_alc650_mic_gpio_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+        ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
+        return 0;
+}
+
+static int snd_ac97_alc650_mic_gpio_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+        int change;
+        change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
+                                      ucontrol->value.integer.value[0] ? (1 << 10) : 0);
+        if (change) {
+                /* GPIO0 write for mic */
+                snd_ac97_update_bits(ac97, 0x76, 0x01,
+                                     ucontrol->value.integer.value[0] ? 0 : 0x01);
+                /* GPIO0 high for mic */
+                snd_ac97_update_bits(ac97, 0x78, 0x100,
+                                     ucontrol->value.integer.value[0] ? 0 : 0x100);
+        }
+        return change;
+}
+
+static const snd_kcontrol_new_t snd_ac97_control_alc650_mic_gpio = {
+        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name = "Mic As Center/LFE",
+        .info = snd_ac97_info_single,
+        .get = snd_ac97_alc650_mic_gpio_get,
+        .put = snd_ac97_alc650_mic_gpio_put,
+        .private_value = (1 << 16), /* for info */
+};
+
+static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = {
+        AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
+        AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0),
+        AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0),
+};
+
+static int patch_alc650_specific(ac97_t * ac97)
+{
+	int err;
+
+	if ((err = patch_build_controls(ac97, snd_ac97_controls_alc650, ARRAY_SIZE(snd_ac97_controls_alc650))) < 0)
+		return err;
+	if ((err = patch_build_controls(ac97,
+					ac97->spec.dev_flags ?
+						&snd_ac97_control_alc650_mic :
+						&snd_ac97_control_alc650_mic_gpio, 1)) < 0)
+		return err;
+	if (ac97->ext_id & AC97_EI_SPDIF) {
+		if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0)
+			return err;
+	}
+	return 0;
+}
+
+static struct snd_ac97_build_ops patch_alc650_ops = {
+	.build_specific	= patch_alc650_specific
+};
+
 int patch_alc650(ac97_t * ac97)
 {
 	unsigned short val;
@@ -374,6 +854,7 @@ int patch_alc650(ac97_t * ac97)
 	 *        this is used for switching mic and center/lfe, which needs
 	 *        resetting GPIO0 level on the older revision.
 	 */
+	ac97->build_ops = &patch_alc650_ops;
 	ac97->spec.dev_flags = 0;
 
 	/* check spdif (should be only on rev.E) */
@@ -417,10 +898,101 @@ int patch_alc650(ac97_t * ac97)
 	return 0;
 }
 
+static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = {
+	AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0),
+	AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0),
+};
+
+static int patch_cm9738_specific(ac97_t * ac97)
+{
+	return patch_build_controls(ac97, snd_ac97_cm9738_controls, ARRAY_SIZE(snd_ac97_cm9738_controls));
+}
+
+static struct snd_ac97_build_ops patch_cm9738_ops = {
+	.build_specific	= patch_cm9738_specific
+};
+
+int patch_cm9738(ac97_t * ac97)
+{
+	ac97->build_ops = &patch_cm9738_ops;
+	return 0;
+}
+
+static int snd_ac97_cmedia_spdif_playback_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[] = { "Analog", "Digital" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ac97_cmedia_spdif_playback_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	unsigned short val;
+
+	val = ac97->regs[AC97_CM9739_SPDIF_CTRL];
+	ucontrol->value.enumerated.item[0] = (val >> 1) & 0x01;
+	return 0;
+}
+
+static int snd_ac97_cmedia_spdif_playback_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+	return snd_ac97_update_bits(ac97, AC97_CM9739_SPDIF_CTRL,
+				    0x01 << 1, 
+				    (ucontrol->value.enumerated.item[0] & 0x01) << 1);
+}
+
+static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = {
+	/* BIT 0: SPDI_EN - always true */
+	{ /* BIT 1: SPDIFS */
+		.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name	= SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+		.info	= snd_ac97_cmedia_spdif_playback_source_info,
+		.get	= snd_ac97_cmedia_spdif_playback_source_get,
+		.put	= snd_ac97_cmedia_spdif_playback_source_put,
+	},
+	/* BIT 2: IG_SPIV */
+	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9739_SPDIF_CTRL, 2, 1, 0),
+	/* BIT 3: SPI2F */
+	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9739_SPDIF_CTRL, 3, 1, 0), 
+	/* BIT 4: SPI2SDI */
+	AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9739_SPDIF_CTRL, 4, 1, 0),
+	/* BIT 8: SPD32 - 32bit SPDIF - not supported yet */
+};
+
+static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = {
+	AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0),
+};
+
+static int patch_cm9739_specific(ac97_t * ac97)
+{
+	return patch_build_controls(ac97, snd_ac97_cm9739_controls, ARRAY_SIZE(snd_ac97_cm9739_controls));
+}
+
+static int patch_cm9739_post_spdif(ac97_t * ac97)
+{
+	return patch_build_controls(ac97, snd_ac97_cm9739_controls_spdif, ARRAY_SIZE(snd_ac97_cm9739_controls_spdif));
+}
+
+static struct snd_ac97_build_ops patch_cm9739_ops = {
+	.build_specific	= patch_cm9739_specific,
+	.build_post_spdif = patch_cm9739_post_spdif
+};
+
 int patch_cm9739(ac97_t * ac97)
 {
 	unsigned short val;
 
+	ac97->build_ops = &patch_cm9739_ops;
+
 	/* check spdif */
 	val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);
 	if (val & AC97_EA_SPCV) {
@@ -444,3 +1016,31 @@ int patch_cm9739(ac97_t * ac97)
 	return 0;
 }
 
+static const snd_kcontrol_new_t snd_ac97_controls_vt1616[] = {
+AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0),
+AC97_SINGLE("Alternate Level to Surround Out", 0x5a, 15, 1, 0),
+AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0),
+AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0),
+};
+
+static int patch_vt1616_specific(ac97_t * ac97)
+{
+	int err;
+
+	if (snd_ac97_try_bit(ac97, 0x5a, 9))
+		if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[0], 1)) < 0)
+			return err;
+	if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0)
+		return err;
+	return 0;
+}
+
+static struct snd_ac97_build_ops patch_vt1616_ops = {
+	.build_specific	= patch_vt1616_specific
+};
+
+int patch_vt1616(ac97_t * ac97)
+{
+	ac97->build_ops = &patch_vt1616_ops;
+	return 0;
+}
diff -puN sound/pci/ac97/ac97_patch.h~alsa-bk-2003-07-28 sound/pci/ac97/ac97_patch.h
--- 25/sound/pci/ac97/ac97_patch.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ac97/ac97_patch.h	Tue Jul 29 12:11:31 2003
@@ -29,6 +29,7 @@ int patch_wolfson04(ac97_t * ac97);
 int patch_wolfson05(ac97_t * ac97);
 int patch_wolfson11(ac97_t * ac97);
 int patch_tritech_tr28028(ac97_t * ac97);
+int patch_sigmatel_stac9700(ac97_t * ac97);
 int patch_sigmatel_stac9708(ac97_t * ac97);
 int patch_sigmatel_stac9721(ac97_t * ac97);
 int patch_sigmatel_stac9744(ac97_t * ac97);
@@ -42,4 +43,6 @@ int patch_ad1885(ac97_t * ac97);
 int patch_ad1886(ac97_t * ac97);
 int patch_ad1980(ac97_t * ac97);
 int patch_alc650(ac97_t * ac97);
+int patch_cm9738(ac97_t * ac97);
 int patch_cm9739(ac97_t * ac97);
+int patch_vt1616(ac97_t * ac97);
diff -puN /dev/null sound/pci/ac97/ac97_proc.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/sound/pci/ac97/ac97_proc.c	Tue Jul 29 12:11:31 2003
@@ -0,0 +1,295 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Universal interface for Audio Codec '97
+ *
+ *  For more details look to AC '97 component specification revision 2.2
+ *  by Intel Corporation (http://developer.intel.com).
+ *
+ *
+ *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+#include <sound/asoundef.h>
+#include "ac97_local.h"
+#include "ac97_id.h"
+
+/*
+ * proc interface
+ */
+
+static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx)
+{
+	char name[64];
+	unsigned int id;
+	unsigned short val, tmp, ext, mext;
+	static const char *spdif_slots[4] = { " SPDIF=3/4", " SPDIF=7/8", " SPDIF=6/9", " SPDIF=res" };
+	static const char *spdif_rates[4] = { " Rate=44.1kHz", " Rate=res", " Rate=48kHz", " Rate=32kHz" };
+	static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", " Rate=res", " Rate=res" };
+
+	id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;
+	id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
+	snd_ac97_get_name(NULL, id, name, 0);
+	snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name);
+	if ((ac97->scaps & AC97_SCAP_AUDIO) == 0)
+		goto __modem;
+
+	// val = snd_ac97_read(ac97, AC97_RESET);
+	val = ac97->caps;
+	snd_iprintf(buffer, "Capabilities     :%s%s%s%s%s%s\n",
+	    	    val & AC97_BC_DEDICATED_MIC ? " -dedicated MIC PCM IN channel-" : "",
+		    val & AC97_BC_RESERVED1 ? " -reserved1-" : "",
+		    val & AC97_BC_BASS_TREBLE ? " -bass & treble-" : "",
+		    val & AC97_BC_SIM_STEREO ? " -simulated stereo-" : "",
+		    val & AC97_BC_HEADPHONE ? " -headphone out-" : "",
+		    val & AC97_BC_LOUDNESS ? " -loudness-" : "");
+	tmp = ac97->caps & AC97_BC_DAC_MASK;
+	snd_iprintf(buffer, "DAC resolution   : %s%s%s%s\n",
+		    tmp == AC97_BC_16BIT_DAC ? "16-bit" : "",
+		    tmp == AC97_BC_18BIT_DAC ? "18-bit" : "",
+		    tmp == AC97_BC_20BIT_DAC ? "20-bit" : "",
+		    tmp == AC97_BC_DAC_MASK ? "???" : "");
+	tmp = ac97->caps & AC97_BC_ADC_MASK;
+	snd_iprintf(buffer, "ADC resolution   : %s%s%s%s\n",
+		    tmp == AC97_BC_16BIT_ADC ? "16-bit" : "",
+		    tmp == AC97_BC_18BIT_ADC ? "18-bit" : "",
+		    tmp == AC97_BC_20BIT_ADC ? "20-bit" : "",
+		    tmp == AC97_BC_ADC_MASK ? "???" : "");
+	snd_iprintf(buffer, "3D enhancement   : %s\n",
+		snd_ac97_stereo_enhancements[(val >> 10) & 0x1f]);
+	snd_iprintf(buffer, "\nCurrent setup\n");
+	val = snd_ac97_read(ac97, AC97_MIC);
+	snd_iprintf(buffer, "Mic gain         : %s [%s]\n", val & 0x0040 ? "+20dB" : "+0dB", ac97->regs[AC97_MIC] & 0x0040 ? "+20dB" : "+0dB");
+	val = snd_ac97_read(ac97, AC97_GENERAL_PURPOSE);
+	snd_iprintf(buffer, "POP path         : %s 3D\n"
+		    "Sim. stereo      : %s\n"
+		    "3D enhancement   : %s\n"
+		    "Loudness         : %s\n"
+		    "Mono output      : %s\n"
+		    "Mic select       : %s\n"
+		    "ADC/DAC loopback : %s\n",
+		    val & 0x8000 ? "post" : "pre",
+		    val & 0x4000 ? "on" : "off",
+		    val & 0x2000 ? "on" : "off",
+		    val & 0x1000 ? "on" : "off",
+		    val & 0x0200 ? "Mic" : "MIX",
+		    val & 0x0100 ? "Mic2" : "Mic1",
+		    val & 0x0080 ? "on" : "off");
+
+	ext = snd_ac97_read(ac97, AC97_EXTENDED_ID);
+	if (ext == 0)
+		goto __modem;
+		
+	snd_iprintf(buffer, "Extended ID      : codec=%i rev=%i%s%s%s%s DSA=%i%s%s%s%s\n",
+			(ext & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT,
+			(ext & AC97_EI_REV_MASK) >> AC97_EI_REV_SHIFT,
+			ext & AC97_EI_AMAP ? " AMAP" : "",
+			ext & AC97_EI_LDAC ? " LDAC" : "",
+			ext & AC97_EI_SDAC ? " SDAC" : "",
+			ext & AC97_EI_CDAC ? " CDAC" : "",
+			(ext & AC97_EI_DACS_SLOT_MASK) >> AC97_EI_DACS_SLOT_SHIFT,
+			ext & AC97_EI_VRM ? " VRM" : "",
+			ext & AC97_EI_SPDIF ? " SPDIF" : "",
+			ext & AC97_EI_DRA ? " DRA" : "",
+			ext & AC97_EI_VRA ? " VRA" : "");
+	val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);
+	snd_iprintf(buffer, "Extended status  :%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+			val & AC97_EA_PRL ? " PRL" : "",
+			val & AC97_EA_PRK ? " PRK" : "",
+			val & AC97_EA_PRJ ? " PRJ" : "",
+			val & AC97_EA_PRI ? " PRI" : "",
+			val & AC97_EA_SPCV ? " SPCV" : "",
+			val & AC97_EA_MDAC ? " MADC" : "",
+			val & AC97_EA_LDAC ? " LDAC" : "",
+			val & AC97_EA_SDAC ? " SDAC" : "",
+			val & AC97_EA_CDAC ? " CDAC" : "",
+			ext & AC97_EI_SPDIF ? spdif_slots[(val & AC97_EA_SPSA_SLOT_MASK) >> AC97_EA_SPSA_SLOT_SHIFT] : "",
+			val & AC97_EA_VRM ? " VRM" : "",
+			val & AC97_EA_SPDIF ? " SPDIF" : "",
+			val & AC97_EA_DRA ? " DRA" : "",
+			val & AC97_EA_VRA ? " VRA" : "");
+	if (ext & AC97_EI_VRA) {	/* VRA */
+		val = snd_ac97_read(ac97, AC97_PCM_FRONT_DAC_RATE);
+		snd_iprintf(buffer, "PCM front DAC    : %iHz\n", val);
+		if (ext & AC97_EI_SDAC) {
+			val = snd_ac97_read(ac97, AC97_PCM_SURR_DAC_RATE);
+			snd_iprintf(buffer, "PCM Surr DAC     : %iHz\n", val);
+		}
+		if (ext & AC97_EI_LDAC) {
+			val = snd_ac97_read(ac97, AC97_PCM_LFE_DAC_RATE);
+			snd_iprintf(buffer, "PCM LFE DAC      : %iHz\n", val);
+		}
+		val = snd_ac97_read(ac97, AC97_PCM_LR_ADC_RATE);
+		snd_iprintf(buffer, "PCM ADC          : %iHz\n", val);
+	}
+	if (ext & AC97_EI_VRM) {
+		val = snd_ac97_read(ac97, AC97_PCM_MIC_ADC_RATE);
+		snd_iprintf(buffer, "PCM MIC ADC      : %iHz\n", val);
+	}
+	if ((ext & AC97_EI_SPDIF) || (ac97->flags & AC97_CS_SPDIF)) {
+	        if (ac97->flags & AC97_CS_SPDIF)
+			val = snd_ac97_read(ac97, AC97_CSR_SPDIF);
+		else
+			val = snd_ac97_read(ac97, AC97_SPDIF);
+
+		snd_iprintf(buffer, "SPDIF Control    :%s%s%s%s Category=0x%x Generation=%i%s%s%s\n",
+			val & AC97_SC_PRO ? " PRO" : " Consumer",
+			val & AC97_SC_NAUDIO ? " Non-audio" : " PCM",
+			val & AC97_SC_COPY ? " Copyright" : "",
+			val & AC97_SC_PRE ? " Preemph50/15" : "",
+			(val & AC97_SC_CC_MASK) >> AC97_SC_CC_SHIFT,
+			(val & AC97_SC_L) >> 11,
+			(ac97->flags & AC97_CS_SPDIF) ?
+			    spdif_rates_cs4205[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT] :
+			    spdif_rates[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT],
+			(ac97->flags & AC97_CS_SPDIF) ?
+			    (val & AC97_SC_DRS ? " Validity" : "") :
+			    (val & AC97_SC_DRS ? " DRS" : ""),
+			(ac97->flags & AC97_CS_SPDIF) ?
+			    (val & AC97_SC_V ? " Enabled" : "") :
+			    (val & AC97_SC_V ? " Validity" : ""));
+	}
+
+      __modem:
+	mext = snd_ac97_read(ac97, AC97_EXTENDED_MID);
+	if (mext == 0)
+		return;
+	
+	snd_iprintf(buffer, "Extended modem ID: codec=%i%s%s%s%s%s\n",
+			(mext & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT,
+			mext & AC97_MEI_CID2 ? " CID2" : "",
+			mext & AC97_MEI_CID1 ? " CID1" : "",
+			mext & AC97_MEI_HANDSET ? " HSET" : "",
+			mext & AC97_MEI_LINE2 ? " LIN2" : "",
+			mext & AC97_MEI_LINE1 ? " LIN1" : "");
+	val = snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS);
+	snd_iprintf(buffer, "Modem status     :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+			val & AC97_MEA_GPIO ? " GPIO" : "",
+			val & AC97_MEA_MREF ? " MREF" : "",
+			val & AC97_MEA_ADC1 ? " ADC1" : "",
+			val & AC97_MEA_DAC1 ? " DAC1" : "",
+			val & AC97_MEA_ADC2 ? " ADC2" : "",
+			val & AC97_MEA_DAC2 ? " DAC2" : "",
+			val & AC97_MEA_HADC ? " HADC" : "",
+			val & AC97_MEA_HDAC ? " HDAC" : "",
+			val & AC97_MEA_PRA ? " PRA(GPIO)" : "",
+			val & AC97_MEA_PRB ? " PRB(res)" : "",
+			val & AC97_MEA_PRC ? " PRC(ADC1)" : "",
+			val & AC97_MEA_PRD ? " PRD(DAC1)" : "",
+			val & AC97_MEA_PRE ? " PRE(ADC2)" : "",
+			val & AC97_MEA_PRF ? " PRF(DAC2)" : "",
+			val & AC97_MEA_PRG ? " PRG(HADC)" : "",
+			val & AC97_MEA_PRH ? " PRH(HDAC)" : "");
+	if (mext & AC97_MEI_LINE1) {
+		val = snd_ac97_read(ac97, AC97_LINE1_RATE);
+		snd_iprintf(buffer, "Line1 rate       : %iHz\n", val);
+	}
+	if (mext & AC97_MEI_LINE2) {
+		val = snd_ac97_read(ac97, AC97_LINE2_RATE);
+		snd_iprintf(buffer, "Line2 rate       : %iHz\n", val);
+	}
+	if (mext & AC97_MEI_HANDSET) {
+		val = snd_ac97_read(ac97, AC97_HANDSET_RATE);
+		snd_iprintf(buffer, "Headset rate     : %iHz\n", val);
+	}
+}
+
+static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+{
+	ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
+	
+	if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) {	// Analog Devices AD1881/85/86
+		int idx;
+		down(&ac97->spec.ad18xx.mutex);
+		for (idx = 0; idx < 3; idx++)
+			if (ac97->spec.ad18xx.id[idx]) {
+				/* select single codec */
+				snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
+				snd_ac97_proc_read_main(ac97, buffer, idx);
+				snd_iprintf(buffer, "\n\n");
+			}
+		/* select all codecs */
+		snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+		up(&ac97->spec.ad18xx.mutex);
+		
+		snd_iprintf(buffer, "\nAD18XX configuration\n");
+		snd_iprintf(buffer, "Unchained        : 0x%04x,0x%04x,0x%04x\n",
+			ac97->spec.ad18xx.unchained[0],
+			ac97->spec.ad18xx.unchained[1],
+			ac97->spec.ad18xx.unchained[2]);
+		snd_iprintf(buffer, "Chained          : 0x%04x,0x%04x,0x%04x\n",
+			ac97->spec.ad18xx.chained[0],
+			ac97->spec.ad18xx.chained[1],
+			ac97->spec.ad18xx.chained[2]);
+	} else {
+		snd_ac97_proc_read_main(ac97, buffer, 0);
+	}
+}
+
+static void snd_ac97_proc_regs_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx)
+{
+	int reg, val;
+
+	for (reg = 0; reg < 0x80; reg += 2) {
+		val = snd_ac97_read(ac97, reg);
+		snd_iprintf(buffer, "%i:%02x = %04x\n", subidx, reg, val);
+	}
+}
+
+static void snd_ac97_proc_regs_read(snd_info_entry_t *entry, 
+				    snd_info_buffer_t * buffer)
+{
+	ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
+
+	if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) {	// Analog Devices AD1881/85/86
+
+		int idx;
+		down(&ac97->spec.ad18xx.mutex);
+		for (idx = 0; idx < 3; idx++)
+			if (ac97->spec.ad18xx.id[idx]) {
+				/* select single codec */
+				snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
+				snd_ac97_proc_regs_read_main(ac97, buffer, idx);
+			}
+		/* select all codecs */
+		snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+		up(&ac97->spec.ad18xx.mutex);
+	} else {
+		snd_ac97_proc_regs_read_main(ac97, buffer, 0);
+	}	
+}
+
+void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix)
+{
+	snd_info_entry_t *entry;
+	char name[32];
+
+	if (ac97->num)
+		sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num);
+	else
+		sprintf(name, "%s#%d", prefix, ac97->addr);
+	if (! snd_card_proc_new(card, name, &entry))
+		snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read);
+	if (ac97->num)
+		sprintf(name, "%s#%d-%dregs", prefix, ac97->addr, ac97->num);
+	else
+		sprintf(name, "%s#%dregs", prefix, ac97->addr);
+	if (! snd_card_proc_new(card, name, &entry))
+		snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read);
+}
diff -puN sound/pci/ac97/Makefile~alsa-bk-2003-07-28 sound/pci/ac97/Makefile
--- 25/sound/pci/ac97/Makefile~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ac97/Makefile	Tue Jul 29 12:11:31 2003
@@ -3,7 +3,7 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-snd-ac97-codec-objs := ac97_codec.o ac97_patch.o
+snd-ac97-codec-objs := ac97_codec.o ac97_proc.o ac97_patch.o
 snd-ak4531-codec-objs := ak4531_codec.o
 
 # Toplevel Module Dependency
diff -puN sound/pci/ali5451/ali5451.c~alsa-bk-2003-07-28 sound/pci/ali5451/ali5451.c
--- 25/sound/pci/ali5451/ali5451.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ali5451/ali5451.c	Tue Jul 29 12:11:31 2003
@@ -1891,27 +1891,14 @@ static int __devinit snd_ali_mixer(ali_t
 }
 
 #ifdef CONFIG_PM
-#ifndef PCI_OLD_SUSPEND
-static int snd_ali_suspend(struct pci_dev *dev, u32 state)
-#else
-static void snd_ali_suspend(struct pci_dev *dev)
-#endif
+static void ali_suspend(ali_t *chip)
 {
-#ifndef PCI_OLD_SUSPEND
-	ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return -ENXIO);
-#else
-	ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return);
-#endif
 	ali_image_t *im;
 	int i, j;
 
 	im = chip->image;
 	if (! im)
-#ifndef PCI_OLD_SUSPEND
-		return -ENXIO;
-#else
 		return;
-#endif
 
 	spin_lock_irq(&chip->reg_lock);
 	
@@ -1938,32 +1925,16 @@ static void snd_ali_suspend(struct pci_d
 	outl(0xffffffff, ALI_REG(chip, ALI_STOP));
 
 	spin_unlock_irq(&chip->reg_lock);
-#ifndef PCI_OLD_SUSPEND
-	return 0;
-#endif
 }
 
-#ifndef PCI_OLD_SUSPEND
-static int snd_ali_resume(struct pci_dev *dev)
-#else
-static void snd_ali_resume(struct pci_dev *dev)
-#endif
+static void ali_resume(ali_t *chip)
 {
-#ifndef PCI_OLD_SUSPEND
-	ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return -ENXIO);
-#else
-	ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return);
-#endif
 	ali_image_t *im;
 	int i, j;
 
 	im = chip->image;
 	if (! im)
-#ifndef PCI_OLD_SUSPEND
-		return -ENXIO;
-#else
 		return;
-#endif
 
 	pci_enable_device(chip->pci);
 
@@ -1989,11 +1960,22 @@ static void snd_ali_resume(struct pci_de
 	outl(im->regs[ALI_MISCINT >> 2], ALI_REG(chip, ALI_MISCINT));
 	
 	spin_unlock_irq(&chip->reg_lock);
-#ifndef PCI_OLD_SUSPEND
+	return;
+}
+
+static int snd_ali_suspend(struct pci_dev *dev, u32 state)
+{
+	ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return -ENXIO);
+	ali_suspend(chip);
 	return 0;
-#endif
 }
-#endif
+static int snd_ali_resume(struct pci_dev *dev)
+{
+	ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return -ENXIO);
+	ali_resume(chip);
+	return 0;
+}
+#endif /* CONFIG_PM */
 
 static int snd_ali_free(ali_t * codec)
 {
@@ -2181,7 +2163,7 @@ static int __devinit snd_ali_create(snd_
 	/* M7101: power management */
        	pci_dev = pci_find_device(0x10b9, 0x7101, NULL);
 	codec->pci_m7101 = pci_dev;
-	if (! codec->pci_m7101) {
+	if (! codec->pci_m7101 && codec->revision == ALI_5451_V02) {
 		snd_printk(KERN_ERR "ali5451: cannot find ALi 7101 chip.\n");
 		snd_ali_free(codec);
 		return -ENODEV;
diff -puN sound/pci/cmipci.c~alsa-bk-2003-07-28 sound/pci/cmipci.c
--- 25/sound/pci/cmipci.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/cmipci.c	Tue Jul 29 12:11:31 2003
@@ -1186,7 +1186,7 @@ static int snd_cmipci_ac3_copy(snd_pcm_s
 #ifndef USE_AES_IEC958
 	u16 *srcp = src, val;
 #else
-	char buf[1920];         /* bits can be divided by 20, 24, 16 */
+	char buf[480];         /* bits can be divided by 20, 24, 16 */
 	size_t bytes = frames_to_bytes(runtime, count);
 #endif
 
@@ -1245,7 +1245,7 @@ static int snd_cmipci_ac3_silence(snd_pc
 	snd_pcm_uframes_t offset;
 	snd_pcm_runtime_t *runtime = subs->runtime;
 # ifdef USE_AES_IEC958
-	char buf[1920];		/* bits can be divided by 20, 24, 16 */
+	char buf[480];		/* bits can be divided by 20, 24, 16 */
 	size_t bytes = frames_to_bytes(runtime, count);
 # endif
 	if (! cm->channel[CM_CH_PLAY].ac3_shift)
diff -puN sound/pci/cs4281.c~alsa-bk-2003-07-28 sound/pci/cs4281.c
--- 25/sound/pci/cs4281.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/cs4281.c	Tue Jul 29 12:11:31 2003
@@ -530,36 +530,27 @@ MODULE_DEVICE_TABLE(pci, snd_cs4281_ids)
  *  common I/O routines
  */
 
-static void snd_cs4281_delay(unsigned int delay, int can_schedule)
+static void snd_cs4281_delay(unsigned int delay)
 {
 	if (delay > 999) {
-		if (can_schedule) {
-			unsigned long end_time;
-			delay = (delay * HZ) / 1000000;
-			if (delay < 1)
-				delay = 1;
-			end_time = jiffies + delay;
-			do {
-				set_current_state(TASK_UNINTERRUPTIBLE);
-				schedule_timeout(1);
-			} while (time_after_eq(end_time, jiffies));
-		} else {
-			delay += 999;
-			delay /= 1000;
-			mdelay(delay > 0 ? delay : 1);
-		}
+		unsigned long end_time;
+		delay = (delay * HZ) / 1000000;
+		if (delay < 1)
+			delay = 1;
+		end_time = jiffies + delay;
+		do {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+		} while (time_after_eq(end_time, jiffies));
 	} else {
 		udelay(delay);
 	}
 }
 
-inline static void snd_cs4281_delay_long(int can_schedule)
+inline static void snd_cs4281_delay_long(void)
 {
-	if (can_schedule) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
-	} else
-		mdelay(10);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(1);
 }
 
 static inline void snd_cs4281_pokeBA0(cs4281_t *chip, unsigned long offset, unsigned int val)
@@ -1267,7 +1258,7 @@ static void __devinit snd_cs4281_proc_in
  * joystick support
  */
 
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 
 typedef struct snd_cs4281_gameport {
 	struct gameport info;
@@ -1359,7 +1350,7 @@ static void __devinit snd_cs4281_gamepor
 
 #else
 #define snd_cs4281_gameport(chip) /*NOP*/
-#endif /* CONFIG_GAMEPORT || CONFIG_GAMEPORT_MODULE */
+#endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */
 
 
 /*
@@ -1368,7 +1359,7 @@ static void __devinit snd_cs4281_gamepor
 
 static int snd_cs4281_free(cs4281_t *chip)
 {
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	if (chip->gameport) {
 		gameport_unregister_port(&chip->gameport->info);
 		kfree(chip->gameport);
@@ -1411,7 +1402,7 @@ static int snd_cs4281_dev_free(snd_devic
 	return snd_cs4281_free(chip);
 }
 
-static int snd_cs4281_chip_init(cs4281_t *chip, int can_schedule); /* defined below */
+static int snd_cs4281_chip_init(cs4281_t *chip); /* defined below */
 #ifdef CONFIG_PM
 static int snd_cs4281_set_power_state(snd_card_t *card, unsigned int power_state);
 #endif
@@ -1471,7 +1462,7 @@ static int __devinit snd_cs4281_create(s
 		return -ENOMEM;
 	}
 	
-	tmp = snd_cs4281_chip_init(chip, 1);
+	tmp = snd_cs4281_chip_init(chip);
 	if (tmp) {
 		snd_cs4281_free(chip);
 		return tmp;
@@ -1493,7 +1484,7 @@ static int __devinit snd_cs4281_create(s
 	return 0;
 }
 
-static int snd_cs4281_chip_init(cs4281_t *chip, int can_schedule)
+static int snd_cs4281_chip_init(cs4281_t *chip)
 {
 	unsigned int tmp;
 	int timeout;
@@ -1547,7 +1538,7 @@ static int snd_cs4281_chip_init(cs4281_t
 	snd_cs4281_pokeBA0(chip, BA0_SPMC, 0);
 	udelay(50);
 	snd_cs4281_pokeBA0(chip, BA0_SPMC, BA0_SPMC_RSTN);
-	snd_cs4281_delay(50000, can_schedule);
+	snd_cs4281_delay(50000);
 
 	if (chip->dual_codec)
 		snd_cs4281_pokeBA0(chip, BA0_SPMC, BA0_SPMC_RSTN | BA0_SPMC_ASDI2E);
@@ -1563,7 +1554,7 @@ static int snd_cs4281_chip_init(cs4281_t
 	 *  Start the DLL Clock logic.
 	 */
 	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, BA0_CLKCR1_DLLP);
-	snd_cs4281_delay(50000, can_schedule);
+	snd_cs4281_delay(50000);
 	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, BA0_CLKCR1_SWCE | BA0_CLKCR1_DLLP);
 
 	/*
@@ -1577,7 +1568,7 @@ static int snd_cs4281_chip_init(cs4281_t
 		 */
 		if (snd_cs4281_peekBA0(chip, BA0_CLKCR1) & BA0_CLKCR1_DLLRDY)
 			goto __ok0;
-		snd_cs4281_delay_long(can_schedule);
+		snd_cs4281_delay_long();
 	} while (timeout-- > 0);
 
 	snd_printk(KERN_ERR "DLLRDY not seen\n");
@@ -1603,7 +1594,7 @@ static int snd_cs4281_chip_init(cs4281_t
 		 */
 		if (snd_cs4281_peekBA0(chip, BA0_ACSTS) & BA0_ACSTS_CRDY)
 			goto __ok1;
-		snd_cs4281_delay_long(can_schedule);
+		snd_cs4281_delay_long();
 	} while (timeout-- > 0);
 
 	snd_printk(KERN_ERR "never read codec ready from AC'97 (0x%x)\n", snd_cs4281_peekBA0(chip, BA0_ACSTS));
@@ -1615,7 +1606,7 @@ static int snd_cs4281_chip_init(cs4281_t
 		do {
 			if (snd_cs4281_peekBA0(chip, BA0_ACSTS2) & BA0_ACSTS_CRDY)
 				goto __codec2_ok;
-			snd_cs4281_delay_long(can_schedule);
+			snd_cs4281_delay_long();
 		} while (timeout-- > 0);
 		snd_printk(KERN_INFO "secondary codec doesn't respond. disable it...\n");
 		chip->dual_codec = 0;
@@ -1642,7 +1633,7 @@ static int snd_cs4281_chip_init(cs4281_t
 		 */
                 if ((snd_cs4281_peekBA0(chip, BA0_ACISV) & (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4))) == (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4)))
                         goto __ok2;
-		snd_cs4281_delay_long(can_schedule);
+		snd_cs4281_delay_long();
 	} while (timeout-- > 0);
 
 	snd_printk(KERN_ERR "never read ISV3 and ISV4 from AC'97\n");
@@ -2109,7 +2100,7 @@ static void cs4281_resume(cs4281_t *chip
 	ulCLK |= CLKCR1_CKRA;
 	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
 
-	snd_cs4281_chip_init(chip, 0);
+	snd_cs4281_chip_init(chip);
 
 	/* restore the status registers */
 	for (i = 0; i < number_of(saved_regs); i++)
@@ -2128,7 +2119,6 @@ static void cs4281_resume(cs4281_t *chip
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 }
 
-#ifndef PCI_OLD_SUSPEND
 static int snd_cs4281_suspend(struct pci_dev *dev, u32 state)
 {
 	cs4281_t *chip = snd_magic_cast(cs4281_t, pci_get_drvdata(dev), return -ENXIO);
@@ -2141,18 +2131,6 @@ static int snd_cs4281_resume(struct pci_
 	cs4281_resume(chip);
 	return 0;
 }
-#else
-static void snd_cs4281_suspend(struct pci_dev *dev)
-{
-	cs4281_t *chip = snd_magic_cast(cs4281_t, pci_get_drvdata(dev), return);
-	cs4281_suspend(chip);
-}
-static void snd_cs4281_resume(struct pci_dev *dev)
-{
-	cs4281_t *chip = snd_magic_cast(cs4281_t, pci_get_drvdata(dev), return);
-	cs4281_resume(chip);
-}
-#endif
 
 /* callback */
 static int snd_cs4281_set_power_state(snd_card_t *card, unsigned int power_state)
diff -puN sound/pci/cs46xx/cs46xx.c~alsa-bk-2003-07-28 sound/pci/cs46xx/cs46xx.c
--- 25/sound/pci/cs46xx/cs46xx.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/cs46xx/cs46xx.c	Tue Jul 29 12:11:31 2003
@@ -163,7 +163,6 @@ static int __devinit snd_card_cs46xx_pro
 }
 
 #ifdef CONFIG_PM
-#ifndef PCI_OLD_SUSPEND
 static int snd_card_cs46xx_suspend(struct pci_dev *pci, u32 state)
 {
 	cs46xx_t *chip = snd_magic_cast(cs46xx_t, pci_get_drvdata(pci), return -ENXIO);
@@ -176,18 +175,6 @@ static int snd_card_cs46xx_resume(struct
 	snd_cs46xx_resume(chip);
 	return 0;
 }
-#else
-static void snd_card_cs46xx_suspend(struct pci_dev *pci)
-{
-	cs46xx_t *chip = snd_magic_cast(cs46xx_t, pci_get_drvdata(pci), return);
-	snd_cs46xx_suspend(chip);
-}
-static void snd_card_cs46xx_resume(struct pci_dev *pci)
-{
-	cs46xx_t *chip = snd_magic_cast(cs46xx_t, pci_get_drvdata(pci), return);
-	snd_cs46xx_resume(chip);
-}
-#endif
 #endif
 
 static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci)
diff -puN sound/pci/cs46xx/cs46xx_lib.c~alsa-bk-2003-07-28 sound/pci/cs46xx/cs46xx_lib.c
--- 25/sound/pci/cs46xx/cs46xx_lib.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/cs46xx/cs46xx_lib.c	Tue Jul 29 12:11:31 2003
@@ -2743,7 +2743,7 @@ int __devinit snd_cs46xx_midi(cs46xx_t *
  * gameport interface
  */
 
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 
 typedef struct snd_cs46xx_gameport {
 	struct gameport info;
@@ -2960,7 +2960,7 @@ static int snd_cs46xx_free(cs46xx_t *chi
 	if (chip->active_ctrl)
 		chip->active_ctrl(chip, 1);
 
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	if (chip->gameport) {
 		gameport_unregister_port(&chip->gameport->info);
 		kfree(chip->gameport);
@@ -3010,7 +3010,7 @@ static int snd_cs46xx_dev_free(snd_devic
 /*
  *  initialize chip
  */
-static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait)
+static int snd_cs46xx_chip_init(cs46xx_t *chip)
 {
 	int timeout;
 
@@ -3090,7 +3090,8 @@ static int snd_cs46xx_chip_init(cs46xx_t
 	/*
          *  Wait until the PLL has stabilized.
 	 */
-	mdelay(100); /* FIXME: schedule? */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10); /* 100ms */
 
 	/*
 	 *  Turn on clocking of the core so that we can setup the serial ports.
@@ -3143,12 +3144,8 @@ static int snd_cs46xx_chip_init(cs46xx_t
 		 */
 		if (snd_cs46xx_peekBA0(chip, BA0_ACSTS) & ACSTS_CRDY)
 			goto ok1;
-		if (busywait)
-			mdelay(10);
-		else {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout((HZ+99)/100);
-		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((HZ+99)/100);
 	}
 
 
@@ -3197,12 +3194,8 @@ static int snd_cs46xx_chip_init(cs46xx_t
 		 */
 		if ((snd_cs46xx_peekBA0(chip, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
 			goto ok2;
-		if (busywait)
-			mdelay(10);
-		else {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout((HZ+99)/100);
-		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((HZ+99)/100);
 	}
 
 #ifndef CONFIG_SND_CS46XX_NEW_DSP
@@ -3811,7 +3804,7 @@ void snd_cs46xx_resume(cs46xx_t *chip)
 	chip->amplifier = 0;
 	chip->active_ctrl(chip, 1); /* force to on */
 
-	snd_cs46xx_chip_init(chip, 1);
+	snd_cs46xx_chip_init(chip);
 
 #if 0
 	snd_cs46xx_codec_write(chip, BA0_AC97_GENERAL_PURPOSE, 
@@ -3992,7 +3985,7 @@ int __devinit snd_cs46xx_create(snd_card
 	}
 #endif
 
-	err = snd_cs46xx_chip_init(chip, 0);
+	err = snd_cs46xx_chip_init(chip);
 	if (err < 0) {
 		snd_cs46xx_free(chip);
 		return err;
diff -puN sound/pci/emu10k1/emu10k1.c~alsa-bk-2003-07-28 sound/pci/emu10k1/emu10k1.c
--- 25/sound/pci/emu10k1/emu10k1.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/emu10k1/emu10k1.c	Tue Jul 29 12:11:31 2003
@@ -35,7 +35,7 @@ MODULE_CLASSES("{sound}");
 MODULE_DEVICES("{{Creative Labs,SB Live!/PCI512/E-mu APS},"
 	       "{Creative Labs,SB Audigy}}");
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 #define ENABLE_SYNTH
 #include <sound/emu10k1_synth.h>
 #endif
@@ -135,11 +135,9 @@ static int __devinit snd_card_emu10k1_pr
 		snd_card_free(card);
 		return err;
 	}		
-	if (!emu->APS) {	/* APS board has not an AC97 mixer */
-		if ((err = snd_emu10k1_mixer(emu)) < 0) {
-			snd_card_free(card);
-			return err;
-		}		
+	if ((err = snd_emu10k1_mixer(emu)) < 0) {
+		snd_card_free(card);
+		return err;
 	}
 	if (emu->audigy) {
 		if ((err = snd_emu10k1_audigy_midi(emu)) < 0) {
diff -puN sound/pci/emu10k1/emu10k1_main.c~alsa-bk-2003-07-28 sound/pci/emu10k1/emu10k1_main.c
--- 25/sound/pci/emu10k1/emu10k1_main.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/emu10k1/emu10k1_main.c	Tue Jul 29 12:11:31 2003
@@ -674,6 +674,14 @@ int __devinit snd_emu10k1_create(snd_car
 	if (emu->serial == 0x40011102) {
 		emu->card_type = EMU10K1_CARD_EMUAPS;
 		emu->APS = 1;
+		emu->no_ac97 = 1; /* APS has no AC97 chip */
+	}
+	else if (emu->revision == 4 && emu->serial == 0x10051102) {
+		/* Audigy 2 EX has apparently no effective AC97 controls
+		 * (for both input and output), so we skip the AC97 detections
+		 */
+		snd_printdd(KERN_INFO "Audigy2 EX is detected. skpping ac97.\n");
+		emu->no_ac97 = 1;
 	}
 	
 	emu->fx8010.fxbus_mask = 0x303f;
diff -puN sound/pci/emu10k1/emufx.c~alsa-bk-2003-07-28 sound/pci/emu10k1/emufx.c
--- 25/sound/pci/emu10k1/emufx.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/emu10k1/emufx.c	Tue Jul 29 12:11:31 2003
@@ -945,12 +945,15 @@ static void snd_emu10k1_add_controls(emu
 	snd_emu10k1_fx8010_ctl_t *ctl, nctl;
 	snd_kcontrol_new_t knew;
 	snd_kcontrol_t *kctl;
-	snd_ctl_elem_value_t val;
+	snd_ctl_elem_value_t *val;
 
+	val = (snd_ctl_elem_value_t *)kmalloc(sizeof(*val), GFP_KERNEL);
+	if (!val)
+		return;
 	for (i = 0, _gctl = icode->gpr_add_controls;
 	     i < icode->gpr_add_control_count; i++, _gctl++) {
 		if (copy_from_user(&gctl, _gctl, sizeof(gctl)))
-			return;
+			break;
 		snd_runtime_check(gctl.id.iface == SNDRV_CTL_ELEM_IFACE_MIXER ||
 		                  gctl.id.iface == SNDRV_CTL_ELEM_IFACE_PCM, continue);
 		snd_runtime_check(gctl.id.name[0] != '\0', continue);
@@ -970,7 +973,7 @@ static void snd_emu10k1_add_controls(emu
 		for (j = 0; j < 32; j++) {
 			nctl.gpr[j] = gctl.gpr[j];
 			nctl.value[j] = ~gctl.value[j];	/* inverted, we want to write new value in gpr_ctl_put() */
-			val.value.integer.value[j] = gctl.value[j];
+			val->value.integer.value[j] = gctl.value[j];
 		}
 		nctl.min = gctl.min;
 		nctl.max = gctl.max;
@@ -996,8 +999,9 @@ static void snd_emu10k1_add_controls(emu
 			snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
 			                          SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
 		}
-		snd_emu10k1_gpr_ctl_put(ctl->kcontrol, &val);
+		snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
 	}
+	kfree(val);
 }
 
 static void snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
@@ -1234,7 +1238,10 @@ static void __devinit snd_emu10k1_init_s
 
 static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu)
 {
-	int err, i, z, gpr, tmp, playback, capture, nctl;
+	int err, i, z, gpr, nctl;
+	const int playback = 10;
+	const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
+	const int tmp = 0x88;
 	u32 ptr;
 	emu10k1_fx8010_code_t *icode;
 	emu10k1_fx8010_control_gpr_t *controls, *ctl;
@@ -1257,19 +1264,15 @@ static int __devinit _snd_emu10k1_audigy
 	strcpy(icode->name, "Audigy DSP code for ALSA");
 	ptr = 0;
 	nctl = 0;
-	playback = 10;
-	capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
 	gpr = capture + 10;
-	tmp = 0x88;
 
 	/* stop FX processor */
 	snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
 
-	/* Wave Playback */
+	/* Wave Playback Volume */
 	A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
 	A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
-	snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr,
-					emu->revision == 4 ? 50 : 100);
+	snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
 	gpr += 2;
 
 	/* Wave Surround Playback */
@@ -1493,6 +1496,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G
 	snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
 	gpr += 2;
 
+	/* Master volume for audigy2 */
+	if (emu->revision == 4) {
+		A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS));
+		A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS));
+		snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
+		gpr += 2;
+	}
+
 	/* digital outputs */
 	A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
 	A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
@@ -1500,7 +1511,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G
 	A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
 
 	/* analog speakers */
-	if (emu->audigy && emu->revision == 4) { /* audigy2 */
+	if (emu->revision == 4) { /* audigy2 */
 		A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
 	} else {
 		A_PUT_STEREO_OUTPUT(A_EXTOUT_AC97_L, A_EXTOUT_AC97_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
@@ -2227,7 +2238,7 @@ static int snd_emu10k1_fx8010_info(emu10
 static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	emu10k1_t *emu = snd_magic_cast(emu10k1_t, hw->private_data, return -ENXIO);
-	emu10k1_fx8010_info_t info;
+	emu10k1_fx8010_info_t *info;
 	emu10k1_fx8010_code_t *icode;
 	emu10k1_fx8010_pcm_t *ipcm;
 	unsigned int addr;
@@ -2235,10 +2246,18 @@ static int snd_emu10k1_fx8010_ioctl(snd_
 	
 	switch (cmd) {
 	case SNDRV_EMU10K1_IOCTL_INFO:
-		if ((res = snd_emu10k1_fx8010_info(emu, &info)) < 0)
+		info = (emu10k1_fx8010_info_t *)kmalloc(sizeof(*info), GFP_KERNEL);
+		if (!info)
+			return -ENOMEM;
+		if ((res = snd_emu10k1_fx8010_info(emu, info)) < 0) {
+			kfree(info);
 			return res;
-		if (copy_to_user((void *)arg, &info, sizeof(info)))
+		}
+		if (copy_to_user((void *)arg, info, sizeof(*info))) {
+			kfree(info);
 			return -EFAULT;
+		}
+		kfree(info);
 		return 0;
 	case SNDRV_EMU10K1_IOCTL_CODE_POKE:
 		if (!capable(CAP_SYS_ADMIN))
@@ -2271,9 +2290,13 @@ static int snd_emu10k1_fx8010_ioctl(snd_
 	case SNDRV_EMU10K1_IOCTL_PCM_POKE:
 		if (emu->audigy)
 			return -EINVAL;
-		ipcm = (emu10k1_fx8010_pcm_t *)snd_kcalloc(sizeof(*ipcm), GFP_KERNEL);
+		ipcm = (emu10k1_fx8010_pcm_t *)kmalloc(sizeof(*ipcm), GFP_KERNEL);
 		if (ipcm == NULL)
 			return -ENOMEM;
+		if (copy_from_user(ipcm, (void *)arg, sizeof(*ipcm))) {
+			kfree(ipcm);
+			return -EFAULT;
+		}
 		res = snd_emu10k1_ipcm_poke(emu, ipcm);
 		kfree(ipcm);
 		return res;
@@ -2283,6 +2306,10 @@ static int snd_emu10k1_fx8010_ioctl(snd_
 		ipcm = (emu10k1_fx8010_pcm_t *)snd_kcalloc(sizeof(*ipcm), GFP_KERNEL);
 		if (ipcm == NULL)
 			return -ENOMEM;
+		if (copy_from_user(ipcm, (void *)arg, sizeof(*ipcm))) {
+			kfree(ipcm);
+			return -EFAULT;
+		}
 		res = snd_emu10k1_ipcm_peek(emu, ipcm);
 		if (res == 0 && copy_to_user((void *)arg, ipcm, sizeof(*ipcm))) {
 			kfree(ipcm);
diff -puN sound/pci/emu10k1/emumixer.c~alsa-bk-2003-07-28 sound/pci/emu10k1/emumixer.c
--- 25/sound/pci/emu10k1/emumixer.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/emu10k1/emumixer.c	Tue Jul 29 12:11:31 2003
@@ -423,6 +423,36 @@ static void snd_emu10k1_mixer_free_ac97(
 	emu->ac97 = NULL;
 }
 
+/*
+ */
+static int remove_ctl(snd_card_t *card, const char *name)
+{
+	snd_ctl_elem_id_t id;
+	memset(&id, 0, sizeof(id));
+	strcpy(id.name, name);
+	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	return snd_ctl_remove_id(card, &id);
+}
+
+static snd_kcontrol_t *ctl_find(snd_card_t *card, const char *name)
+{
+	snd_ctl_elem_id_t sid;
+	memset(&sid, 0, sizeof(sid));
+	strcpy(sid.name, name);
+	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	return snd_ctl_find_id(card, &sid);
+}
+
+static int rename_ctl(snd_card_t *card, const char *src, const char *dst)
+{
+	snd_kcontrol_t *kctl = ctl_find(card, src);
+	if (kctl) {
+		strcpy(kctl->id.name, dst);
+		return 0;
+	}
+	return -ENOENT;
+}
+
 int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
 {
 	ac97_t ac97;
@@ -430,7 +460,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_
 	snd_kcontrol_t *kctl;
 	snd_card_t *card = emu->card;
 
-	if (!emu->APS) {
+	if (!emu->no_ac97) {
 		memset(&ac97, 0, sizeof(ac97));
 		ac97.write = snd_emu10k1_ac97_write;
 		ac97.read = snd_emu10k1_ac97_read;
@@ -438,8 +468,33 @@ int __devinit snd_emu10k1_mixer(emu10k1_
 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
 		if ((err = snd_ac97_mixer(emu->card, &ac97, &emu->ac97)) < 0)
 			return err;
+		if (emu->audigy && emu->revision == 4) {
+			/* Master/PCM controls on ac97 of Audigy2 has no effect */
+			/* FIXME: keep master volume/switch to be sure.
+			 * once after we check that they play really no roles,
+			 * they shall be removed.
+			 */
+			rename_ctl(card, "Master Playback Switch", "AC97 Master Playback Switch");
+			rename_ctl(card, "Master Playback Volume", "AC97 Master Playback Volume");
+			/* pcm controls are removed */
+			remove_ctl(card, "PCM Playback Switch");
+			remove_ctl(card, "PCM Playback Volume");
+		}
 	} else {
-		strcpy(emu->card->mixername, "EMU APS");
+		if (emu->APS)
+			strcpy(emu->card->mixername, "EMU APS");
+		else if (emu->audigy)
+			strcpy(emu->card->mixername, "SB Audigy");
+		else
+			strcpy(emu->card->mixername, "Emu10k1");
+	}
+
+	if (emu->audigy && emu->revision == 4) {
+		/* Audigy2 and Audigy2 EX */
+		/* use the conventional names */
+		rename_ctl(card, "Wave Playback Volume", "PCM Playback Volume");
+		rename_ctl(card, "Wave Playback Volume", "PCM Capture Volume");
+		rename_ctl(card, "Wave Master Playback Volume", "Master Playback Volume");
 	}
 
 	if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
@@ -455,6 +510,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_
 	if ((err = snd_ctl_add(card, kctl)))
 		return err;
 
+	/* intiailize the routing and volume table for each pcm playback stream */
 	for (pcm = 0; pcm < 32; pcm++) {
 		emu10k1_pcm_mixer_t *mix;
 		int v;
@@ -474,21 +530,25 @@ int __devinit snd_emu10k1_mixer(emu10k1_
 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
 	}
 	
-	if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
-		return -ENOMEM;
-	if ((err = snd_ctl_add(card, kctl)))
-		return err;
-	if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
-		return -ENOMEM;
-	if ((err = snd_ctl_add(card, kctl)))
-		return err;
+	if (! emu->APS) { /* FIXME: APS has these controls? */
+		/* sb live! and audigy */
+		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
+			return -ENOMEM;
+		if ((err = snd_ctl_add(card, kctl)))
+			return err;
+		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
+			return -ENOMEM;
+		if ((err = snd_ctl_add(card, kctl)))
+			return err;
+	}
 
 	if (emu->audigy) {
 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
 			return -ENOMEM;
 		if ((err = snd_ctl_add(card, kctl)))
 			return err;
-	} else {
+	} else if (! emu->APS) {
+		/* sb live! */
 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
 			return -ENOMEM;
 		if ((err = snd_ctl_add(card, kctl)))
diff -puN sound/pci/emu10k1/irq.c~alsa-bk-2003-07-28 sound/pci/emu10k1/irq.c
--- 25/sound/pci/emu10k1/irq.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/emu10k1/irq.c	Tue Jul 29 12:11:31 2003
@@ -55,15 +55,13 @@ irqreturn_t snd_emu10k1_interrupt(int ir
 		if (status & IPR_CHANNELLOOP) {
 			int voice;
 			int voice_max = status & IPR_CHANNELNUMBERMASK;
-			int voice_max_l;
 			u32 val;
 			emu10k1_voice_t *pvoice = emu->voices;
 
 			val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
-			voice_max_l = voice_max;
-			if (voice_max_l >= 0x20)
-				voice_max_l = 0x1f;
-			for (voice = 0; voice <= voice_max_l; voice++) {
+			for (voice = 0; voice <= voice_max; voice++) {
+				if (voice == 0x20)
+					val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
 				if (val & 1) {
 					if (pvoice->use && pvoice->interrupt != NULL) {
 						pvoice->interrupt(emu, pvoice);
@@ -75,21 +73,6 @@ irqreturn_t snd_emu10k1_interrupt(int ir
 				val >>= 1;
 				pvoice++;
 			}
-			if (voice_max > 0x1f) {
-				val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
-				for (; voice <= voice_max; voice++) {
-					if(val & 1) {
-						if (pvoice->use && pvoice->interrupt != NULL) {
-							pvoice->interrupt(emu, pvoice);
-							snd_emu10k1_voice_intr_ack(emu, voice);
-						} else {
-							snd_emu10k1_voice_intr_disable(emu, voice);
-						}
-					}
-					val >>= 1;
-					pvoice++;
-				}
-			}
 			status &= ~IPR_CHANNELLOOP;
 		}
 		status &= ~IPR_CHANNELNUMBERMASK;
@@ -150,9 +133,27 @@ irqreturn_t snd_emu10k1_interrupt(int ir
 			status &= ~IPR_FXDSP;
 		}
 		if (status) {
-			snd_printd(KERN_WARNING "emu10k1: unhandled interrupt: 0x%08x\n", status);
+			unsigned int bits;
+			snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
+			//make sure any interrupts we don't handle are disabled:
+			bits = INTE_FXDSPENABLE |
+				INTE_PCIERRORENABLE |
+				INTE_VOLINCRENABLE |
+				INTE_VOLDECRENABLE |
+				INTE_MUTEENABLE |
+				INTE_MICBUFENABLE |
+				INTE_ADCBUFENABLE |
+				INTE_EFXBUFENABLE |
+				INTE_GPSPDIFENABLE |
+				INTE_CDSPDIFENABLE |
+				INTE_INTERVALTIMERENB |
+				INTE_MIDITXENABLE |
+				INTE_MIDIRXENABLE;
+			if (emu->audigy)
+				bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2;
+			snd_emu10k1_intr_disable(emu, bits);
 		}
-		outl(orig_status, emu->port + IPR); /* ack */
+		outl(orig_status, emu->port + IPR); /* ack all */
 	}
 	return IRQ_RETVAL(handled);
 }
diff -puN sound/pci/ens1370.c~alsa-bk-2003-07-28 sound/pci/ens1370.c
--- 25/sound/pci/ens1370.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ens1370.c	Tue Jul 29 12:11:31 2003
@@ -409,7 +409,7 @@ struct _snd_ensoniq {
 	dma_addr_t bugbuf_addr;
 #endif
 
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	struct gameport gameport;
 	struct semaphore joy_sem;	// gameport configuration semaphore
 #endif
@@ -1559,7 +1559,7 @@ static int snd_ensoniq_1371_mixer(ensoni
 #endif /* CHIP1371 */
 
 /* generic control callbacks for ens1370 and for joystick */
-#if defined(CHIP1370) || defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CHIP1370) || defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 #define ENSONIQ_CONTROL(xname, mask) \
 { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, .info = snd_ensoniq_control_info, \
   .get = snd_ensoniq_control_get, .put = snd_ensoniq_control_put, \
@@ -1657,7 +1657,7 @@ static int __devinit snd_ensoniq_1370_mi
  *  General Switches...
  */
 
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 /* MQ: gameport driver connectivity */
 #define ENSONIQ_JOY_CONTROL(xname, mask) \
 { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, .info = snd_ensoniq_control_info, \
@@ -1814,7 +1814,7 @@ static void __devinit snd_ensoniq_proc_i
 
 static int snd_ensoniq_free(ensoniq_t *ensoniq)
 {
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	if (ensoniq->ctrl & ES_JYSTK_EN)
 		snd_ensoniq_joy_disable(ensoniq);
 #endif
@@ -2012,7 +2012,7 @@ static int __devinit snd_ensoniq_create(
 	outb(ensoniq->uartc = 0x00, ES_REG(ensoniq, UART_CONTROL));
 	outb(0x00, ES_REG(ensoniq, UART_RES));
 	outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	init_MUTEX(&ensoniq->joy_sem);
 #ifdef CHIP1371
 	snd_ctl_add(card, snd_ctl_new1(&snd_es1371_joystick_addr, ensoniq));
diff -puN sound/pci/es1938.c~alsa-bk-2003-07-28 sound/pci/es1938.c
--- 25/sound/pci/es1938.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/es1938.c	Tue Jul 29 12:11:31 2003
@@ -244,7 +244,7 @@ struct _snd_es1938 {
 	spinlock_t mixer_lock;
         snd_info_entry_t *proc_entry;
 
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	struct gameport gameport;
 #endif
 };
@@ -1346,7 +1346,7 @@ static int snd_es1938_free(es1938_t *chi
 {
 	/*if (chip->rmidi)
 	  snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0);*/
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	if (chip->gameport.io)
 		gameport_unregister_port(&chip->gameport);
 #endif
@@ -1663,7 +1663,7 @@ static int __devinit snd_es1938_probe(st
 	} /*else
 	    snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0x40);*/
 
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	chip->gameport.io = chip->game_port;
 	gameport_register_port(&chip->gameport);
 #endif
diff -puN sound/pci/es1968.c~alsa-bk-2003-07-28 sound/pci/es1968.c
--- 25/sound/pci/es1968.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/es1968.c	Tue Jul 29 12:11:31 2003
@@ -654,6 +654,11 @@ inline static u16 maestro_read(es1968_t 
 	return result;
 }
 
+#define big_mdelay(msec) do {\
+	set_current_state(TASK_UNINTERRUPTIBLE);\
+	schedule_timeout(((msec) * HZ + 999) / 1000);\
+} while (0)
+	
 /* Wait for the codec bus to be free */
 static int snd_es1968_ac97_wait(es1968_t *chip)
 {
@@ -2109,7 +2114,7 @@ static void snd_es1968_ac97_reset(es1968
 	outw(0x0000, ioaddr + 0x60);	/* write 0 to gpio 0 */
 	udelay(20);
 	outw(0x0001, ioaddr + 0x60);	/* write 1 to gpio 1 */
-	mdelay(20);
+	big_mdelay(20);
 
 	outw(save_68 | 0x1, ioaddr + 0x68);	/* now restore .. */
 	outw((inw(ioaddr + 0x38) & 0xfffc) | 0x1, ioaddr + 0x38);
@@ -2125,7 +2130,7 @@ static void snd_es1968_ac97_reset(es1968
 	outw(0x0001, ioaddr + 0x60);	/* write 1 to gpio */
 	udelay(20);
 	outw(0x0009, ioaddr + 0x60);	/* write 9 to gpio */
-	mdelay(500);		/* .. ouch.. */
+	big_mdelay(500);
 	//outw(inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
 	outw(inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
 	outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
@@ -2151,7 +2156,7 @@ static void snd_es1968_ac97_reset(es1968
 
 		if (w > 10000) {
 			outb(inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37);	/* do a software reset */
-			mdelay(500);	/* oh my.. */
+			big_mdelay(500);	/* oh my.. */
 			outb(inb(ioaddr + 0x37) & ~0x08,
 				ioaddr + 0x37);
 			udelay(1);
@@ -2340,11 +2345,6 @@ static void snd_es1968_chip_init(es1968_
 	outb(3, iobase + ASSP_CONTROL_A);	/* M: Reserved bits... */
 	outb(0, iobase + ASSP_CONTROL_C);	/* M: Disable ASSP, ASSP IRQ's and FM Port */
 
-	/* Enable IRQ's */
-	w = ESM_HIRQ_DSIE | ESM_HIRQ_MPU401 | ESM_HIRQ_HW_VOLUME;
-	outw(w, iobase + ESM_PORT_HOST_IRQ);
-
-
 	/*
 	 * set up wavecache
 	 */
@@ -2414,6 +2414,14 @@ static void snd_es1968_chip_init(es1968_
 	}
 }
 
+/* Enable IRQ's */
+static void snd_es1968_start_irq(es1968_t *chip)
+{
+	unsigned short w;
+	w = ESM_HIRQ_DSIE | ESM_HIRQ_MPU401 | ESM_HIRQ_HW_VOLUME;
+	outw(w, chip->io_port + ESM_PORT_HOST_IRQ);
+}
+
 #ifdef CONFIG_PM
 /*
  * PM support
@@ -2453,16 +2461,18 @@ static void es1968_resume(es1968_t *chip
 		wave_set_register(chip, 0x01FC, chip->dma.addr >> 12);
 	}
 
+	snd_es1968_start_irq(chip);
+
 	/* restore ac97 state */
 	snd_ac97_resume(chip->ac97);
 
 	/* start timer again */
 	if (atomic_read(&chip->bobclient))
 		snd_es1968_bob_start(chip);
+
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 }
 
-#ifndef PCI_OLD_SUSPEND
 static int snd_es1968_suspend(struct pci_dev *dev, u32 state)
 {
 	es1968_t *chip = snd_magic_cast(es1968_t, pci_get_drvdata(dev), return -ENXIO);
@@ -2475,18 +2485,6 @@ static int snd_es1968_resume(struct pci_
 	es1968_resume(chip);
 	return 0;
 }
-#else
-static void snd_es1968_suspend(struct pci_dev *dev)
-{
-	es1968_t *chip = snd_magic_cast(es1968_t, pci_get_drvdata(dev), return);
-	es1968_suspend(chip);
-}
-static void snd_es1968_resume(struct pci_dev *dev)
-{
-	es1968_t *chip = snd_magic_cast(es1968_t, pci_get_drvdata(dev), return);
-	es1968_resume(chip);
-}
-#endif
 
 /* callback */
 static int snd_es1968_set_power_state(snd_card_t *card, unsigned int power_state)
@@ -2612,9 +2610,9 @@ static int __devinit snd_es1968_create(s
 		/* disable power-management if not maestro2e or
 		 * if not on the whitelist
 		 */
-		unsigned int vend;
-		pci_read_config_dword(chip->pci, PCI_SUBSYSTEM_VENDOR_ID, &vend);
-		if (chip->type != TYPE_MAESTRO2E || (vend & 0xffff) != 0x1028) {
+		unsigned short vend;
+		pci_read_config_word(chip->pci, PCI_SUBSYSTEM_VENDOR_ID, &vend);
+		if (chip->type != TYPE_MAESTRO2E || (vend != 0x1028 && vend != 0x1179)) {
 			printk(KERN_INFO "es1968: not attempting power management.\n");
 			do_pm = 0;
 		}
@@ -2769,6 +2767,8 @@ static int __devinit snd_es1968_probe(st
 		}
 	}
 
+	snd_es1968_start_irq(chip);
+
 	chip->clock = clock[dev];
 	if (! chip->clock)
 		es1968_measure_clock(chip);
diff -puN sound/pci/ice1712/ak4xxx.c~alsa-bk-2003-07-28 sound/pci/ice1712/ak4xxx.c
--- 25/sound/pci/ice1712/ak4xxx.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ice1712/ak4xxx.c	Tue Jul 29 12:11:31 2003
@@ -27,8 +27,14 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <sound/core.h>
+#include <sound/initval.h>
 #include "ice1712.h"
 
+MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("ICEnsemble ICE17xx <-> AK4xxx AD/DA chip interface");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+
 static void snd_ice1712_akm4xxx_lock(akm4xxx_t *ak, int chip)
 {
 	ice1712_t *ice = ak->private_data[0];
@@ -116,8 +122,8 @@ static void snd_ice1712_akm4xxx_write(ak
 /*
  * initialize the akm4xxx_t record with the template
  */
-int __devinit snd_ice1712_akm4xxx_init(akm4xxx_t *ak, const akm4xxx_t *temp,
-				       const struct snd_ak4xxx_private *_priv, ice1712_t *ice)
+int snd_ice1712_akm4xxx_init(akm4xxx_t *ak, const akm4xxx_t *temp,
+			     const struct snd_ak4xxx_private *_priv, ice1712_t *ice)
 {
 	struct snd_ak4xxx_private *priv;
 
@@ -139,7 +145,7 @@ int __devinit snd_ice1712_akm4xxx_init(a
 	return 0;
 }
 
-void __devexit snd_ice1712_akm4xxx_free(ice1712_t *ice)
+void snd_ice1712_akm4xxx_free(ice1712_t *ice)
 {
 	unsigned int akidx;
 	if (ice->akm == NULL)
@@ -155,7 +161,7 @@ void __devexit snd_ice1712_akm4xxx_free(
 /*
  * build AK4xxx controls
  */
-int __devinit snd_ice1712_akm4xxx_build_controls(ice1712_t *ice)
+int snd_ice1712_akm4xxx_build_controls(ice1712_t *ice)
 {
 	unsigned int akidx;
 	int err;
diff -puN sound/pci/ice1712/aureon.c~alsa-bk-2003-07-28 sound/pci/ice1712/aureon.c
--- 25/sound/pci/ice1712/aureon.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ice1712/aureon.c	Tue Jul 29 12:11:31 2003
@@ -449,7 +449,7 @@ static int __devinit aureon_init(ice1712
 
 
 /*
- * Aureon board don't provide the EEPROM data except for the vendor IDs.
+ * Aureon boards don't provide the EEPROM data except for the vendor IDs.
  * hence the driver needs to sets up it properly.
  */
 
diff -puN sound/pci/ice1712/ews.c~alsa-bk-2003-07-28 sound/pci/ice1712/ews.c
--- 25/sound/pci/ice1712/ews.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ice1712/ews.c	Tue Jul 29 12:11:31 2003
@@ -389,6 +389,14 @@ static struct snd_ak4xxx_private akm_6fi
  * initialize the chip
  */
 
+/* 6fire specific */
+#define PCF9554_REG_INPUT      0
+#define PCF9554_REG_OUTPUT     1
+#define PCF9554_REG_POLARITY   2
+#define PCF9554_REG_CONFIG     3
+
+static int snd_ice1712_6fire_write_pca(ice1712_t *ice, unsigned char reg, unsigned char data);
+
 static int __devinit snd_ice1712_ews_init(ice1712_t *ice)
 {
 	int err;
@@ -425,6 +433,7 @@ static int __devinit snd_ice1712_ews_ini
 			snd_printk("PCF9554 initialization failed\n");
 			return err;
 		}
+		snd_ice1712_6fire_write_pca(ice, PCF9554_REG_CONFIG, 0x80);
 		break;
 	case ICE1712_SUBDEVICE_EWS88MT:
 	case ICE1712_SUBDEVICE_EWS88MT_NEW:
@@ -449,10 +458,12 @@ static int __devinit snd_ice1712_ews_ini
 	case ICE1712_SUBDEVICE_EWX2496:
 		if ((err = snd_ice1712_init_cs8427(ice, CS8427_BASE_ADDR)) < 0)
 			return err;
+		snd_cs8427_reg_write(ice->cs8427, CS8427_REG_RECVERRMASK, CS8427_UNLOCK | CS8427_CONF | CS8427_BIP | CS8427_PAR);
 		break;
 	case ICE1712_SUBDEVICE_DMX6FIRE:
 		if ((err = snd_ice1712_init_cs8427(ice, ICE1712_6FIRE_CS8427_ADDR)) < 0)
 			return err;
+		snd_cs8427_reg_write(ice->cs8427, CS8427_REG_RECVERRMASK, CS8427_UNLOCK | CS8427_CONF | CS8427_BIP | CS8427_PAR);
 		break;
 	case ICE1712_SUBDEVICE_EWS88MT:
 	case ICE1712_SUBDEVICE_EWS88MT_NEW:
@@ -750,11 +761,6 @@ static snd_kcontrol_new_t snd_ice1712_ew
  * DMX 6Fire specific controls
  */
 
-#define PCF9554_REG_INPUT	0
-#define PCF9554_REG_OUTPUT	1
-#define PCF9554_REG_POLARITY	2
-#define PCF9554_REG_CONFIG	3
-
 static int snd_ice1712_6fire_read_pca(ice1712_t *ice, unsigned char reg)
 {
 	unsigned char byte;
diff -puN sound/pci/ice1712/ice1712.h~alsa-bk-2003-07-28 sound/pci/ice1712/ice1712.h
--- 25/sound/pci/ice1712/ice1712.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ice1712/ice1712.h	Tue Jul 29 12:11:31 2003
@@ -86,8 +86,8 @@
  *  Indirect registers
  */
 
-#define ICE1712_IREG_PBK_COUNT_HI	0x00
-#define ICE1712_IREG_PBK_COUNT_LO	0x01
+#define ICE1712_IREG_PBK_COUNT_LO	0x00
+#define ICE1712_IREG_PBK_COUNT_HI	0x01
 #define ICE1712_IREG_PBK_CTRL		0x02
 #define ICE1712_IREG_PBK_LEFT		0x03	/* left volume */
 #define ICE1712_IREG_PBK_RIGHT		0x04	/* right volume */
@@ -95,8 +95,8 @@
 #define ICE1712_IREG_PBK_RATE_LO	0x06
 #define ICE1712_IREG_PBK_RATE_MID	0x07
 #define ICE1712_IREG_PBK_RATE_HI	0x08
-#define ICE1712_IREG_CAP_COUNT_HI	0x10
-#define ICE1712_IREG_CAP_COUNT_LO	0x11
+#define ICE1712_IREG_CAP_COUNT_LO	0x10
+#define ICE1712_IREG_CAP_COUNT_HI	0x11
 #define ICE1712_IREG_CAP_CTRL		0x12
 #define ICE1712_IREG_GPIO_DATA		0x20
 #define ICE1712_IREG_GPIO_WRITE_MASK	0x21
diff -puN sound/pci/ice1712/ice1724.c~alsa-bk-2003-07-28 sound/pci/ice1712/ice1724.c
--- 25/sound/pci/ice1712/ice1724.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ice1712/ice1724.c	Tue Jul 29 12:11:31 2003
@@ -1583,8 +1583,8 @@ static int __devinit snd_vt1724_read_eep
 	struct snd_ice1712_card_info **tbl, *c;
 
 	if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) == 0) {
-		snd_printk("ICE1724 has not detected EEPROM\n");
-		return -EIO;
+		snd_printk(KERN_WARNING "ICE1724 has not detected EEPROM\n");
+		// return -EIO;
 	}
 	ice->eeprom.subvendor = (snd_vt1724_read_i2c(ice, dev, 0x00) << 0) |
 				(snd_vt1724_read_i2c(ice, dev, 0x01) << 8) | 
diff -puN sound/pci/intel8x0.c~alsa-bk-2003-07-28 sound/pci/intel8x0.c
--- 25/sound/pci/intel8x0.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/intel8x0.c	Tue Jul 29 12:11:31 2003
@@ -254,8 +254,13 @@ DEFINE_REGSET(AL_PI, 0x40);	/* ALi PCM i
 DEFINE_REGSET(AL_PO, 0x50);	/* Ali PCM out */
 DEFINE_REGSET(AL_MC, 0x60);	/* Ali Mic in */
 DEFINE_REGSET(AL_CDC_SPO, 0x70);	/* Ali Codec SPDIF out */
+DEFINE_REGSET(AL_CENTER, 0x80);		/* Ali center out */
+DEFINE_REGSET(AL_LFE, 0x90);		/* Ali center out */
 DEFINE_REGSET(AL_CLR_SPI, 0xa0);	/* Ali Controller SPDIF in */
 DEFINE_REGSET(AL_CLR_SPO, 0xb0);	/* Ali Controller SPDIF out */
+DEFINE_REGSET(AL_I2S, 0xc0);	/* Ali I2S in */
+DEFINE_REGSET(AL_PI2, 0xd0);	/* Ali PCM2 in */
+DEFINE_REGSET(AL_MC2, 0xe0);	/* Ali Mic2 in */
 
 enum {
 	ICH_REG_ALI_SCR = 0x00,		/* System Control Register */
@@ -275,32 +280,61 @@ enum {
 	ICH_REG_ALI_RTSR = 0x34,	/* Receive Tag Slot  Register */
 	ICH_REG_ALI_CSPSR = 0x38,	/* Command/Status Port Status Register */
 	ICH_REG_ALI_CAS = 0x3c,		/* Codec Write Semaphore Register */
+	ICH_REG_ALI_HWVOL = 0xf0,	/* hardware volume control/status */
+	ICH_REG_ALI_I2SCR = 0xf4,	/* I2S control/status */
 	ICH_REG_ALI_SPDIFCSR = 0xf8,	/* spdif channel status register  */
-	ICH_REG_ALI_SPDIFICS = 0xfc	/* spdif interface control/status  */
+	ICH_REG_ALI_SPDIFICS = 0xfc,	/* spdif interface control/status  */
 };
 
 #define ALI_CAS_SEM_BUSY	0x80000000
-#define ALI_CSPSR_CODEC_READY	0x08
+#define ALI_CPR_ADDR_SECONDARY	0x100
 #define ALI_CPR_ADDR_READ	0x80
+#define ALI_CSPSR_CODEC_READY	0x08
 #define ALI_CSPSR_READ_OK	0x02
 #define ALI_CSPSR_WRITE_OK	0x01
 
 /* interrupts for the whole chip by interrupt status register finish */
  
+#define ALI_INT_MICIN2		(1<<26)
+#define ALI_INT_PCMIN2		(1<<25)
+#define ALI_INT_I2SIN		(1<<24)
 #define ALI_INT_SPDIFOUT	(1<<23)	/* controller spdif out INTERRUPT */
 #define ALI_INT_SPDIFIN		(1<<22)
+#define ALI_INT_LFEOUT		(1<<21)
+#define ALI_INT_CENTEROUT	(1<<20)
 #define ALI_INT_CODECSPDIFOUT	(1<<19)
 #define ALI_INT_MICIN		(1<<18)
 #define ALI_INT_PCMOUT		(1<<17)
 #define ALI_INT_PCMIN		(1<<16)
-#define ALI_INT_CPRAIS		(1<<7)
-#define ALI_INT_SPRAIS		(1<<5)
+#define ALI_INT_CPRAIS		(1<<7)	/* command port available */
+#define ALI_INT_SPRAIS		(1<<5)	/* status port available */
 #define ALI_INT_GPIO		(1<<1)
 #define ALI_INT_MASK		(ALI_INT_SPDIFOUT|ALI_INT_CODECSPDIFOUT|ALI_INT_MICIN|ALI_INT_PCMOUT|ALI_INT_PCMIN)
 
-#define ALI_PCM_CH4		0x100
-#define ALI_PCM_CH6		0x200
-#define ALI_PCM_MASK		(ALI_PCM_CH4 | ALI_PCM_CH6)
+#define ICH_ALI_SC_RESET	(1<<31)	/* master reset */
+#define ICH_ALI_SC_AC97_DBL	(1<<30)
+#define ICH_ALI_SC_CODEC_SPDF	(3<<20)	/* 1=7/8, 2=6/9, 3=10/11 */
+#define ICH_ALI_SC_IN_BITS	(3<<18)
+#define ICH_ALI_SC_OUT_BITS	(3<<16)
+#define ICH_ALI_SC_6CH_CFG	(3<<14)
+#define ICH_ALI_SC_PCM_4	(1<<8)
+#define ICH_ALI_SC_PCM_6	(2<<8)
+#define ICH_ALI_SC_PCM_246_MASK	(3<<8)
+
+#define ICH_ALI_SS_SEC_ID	(3<<5)
+#define ICH_ALI_SS_PRI_ID	(3<<3)
+
+#define ICH_ALI_IF_AC97SP	(1<<21)
+#define ICH_ALI_IF_MC		(1<<20)
+#define ICH_ALI_IF_PI		(1<<19)
+#define ICH_ALI_IF_MC2		(1<<18)
+#define ICH_ALI_IF_PI2		(1<<17)
+#define ICH_ALI_IF_LINE_SRC	(1<<15)	/* 0/1 = slot 3/6 */
+#define ICH_ALI_IF_MIC_SRC	(1<<14)	/* 0/1 = slot 3/6 */
+#define ICH_ALI_IF_SPDF_SRC	(3<<12)	/* 00 = PCM, 01 = AC97-in, 10 = spdif-in, 11 = i2s */
+#define ICH_ALI_IF_AC97_OUT	(3<<8)	/* 00 = PCM, 10 = spdif-in, 11 = i2s */
+#define ICH_ALI_IF_PO_SPDF	(1<<3)
+#define ICH_ALI_IF_PO		(1<<1)
 
 /*
  *  
@@ -336,11 +370,6 @@ typedef struct {
 	ac97_t *ac97;
 	unsigned short ac97_rate_regs[3];
 	int ac97_rates_idx;
-#ifdef CONFIG_PM
-	unsigned char civ_saved;
-	unsigned char piv_saved;
-	unsigned short picb_saved;
-#endif
 } ichdev_t;
 
 typedef struct _snd_intel8x0 intel8x0_t;
@@ -603,31 +632,29 @@ static int snd_intel8x0_ali_codec_semaph
 	int time = 100;
 	while (time-- && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY))
 		udelay(1);
+	if (! time)
+		snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n");
 	return snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_CODEC_READY);
 }
 
 static unsigned short snd_intel8x0_ali_codec_read(ac97_t *ac97, unsigned short reg)
 {
 	intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return ~0);
-	unsigned short data, reg2;
+	unsigned short data = 0xffff;
 
 	spin_lock(&chip->ac97_lock);
 	if (snd_intel8x0_ali_codec_semaphore(chip))
 		goto __err;
-	iputword(chip, ICHREG(ALI_CPR_ADDR), reg | ALI_CPR_ADDR_READ);
+	reg |= ALI_CPR_ADDR_READ;
+	if (ac97->num)
+		reg |= ALI_CPR_ADDR_SECONDARY;
+	iputword(chip, ICHREG(ALI_CPR_ADDR), reg);
 	if (snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_READ_OK))
 		goto __err;
 	data = igetword(chip, ICHREG(ALI_SPR));
-	reg2 = igetword(chip, ICHREG(ALI_SPR_ADDR));
-	if (reg != reg2) {
-		snd_printd(KERN_WARNING "intel8x0: AC97 read not completed? 0x%x != 0x%x\n", reg, reg2);
-		// goto __err;
-	}
-	spin_unlock(&chip->ac97_lock);
-	return data;
  __err:
 	spin_unlock(&chip->ac97_lock);
-	return 0xffff;
+	return data;
 }
 
 static void snd_intel8x0_ali_codec_write(ac97_t *ac97, unsigned short reg, unsigned short val)
@@ -640,7 +667,9 @@ static void snd_intel8x0_ali_codec_write
 		return;
 	}
 	iputword(chip, ICHREG(ALI_CPR), val);
-	iputbyte(chip, ICHREG(ALI_CPR_ADDR), reg);
+	if (ac97->num)
+		reg |= ALI_CPR_ADDR_SECONDARY;
+	iputword(chip, ICHREG(ALI_CPR_ADDR), reg);
 	snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_WRITE_OK);
 	spin_unlock(&chip->ac97_lock);
 }
@@ -680,6 +709,7 @@ static void snd_intel8x0_setup_periods(i
 		ichdev->frags = ichdev->size / ichdev->fragsize;
 	}
 	iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi = ICH_REG_LVI_MASK);
+	iputbyte(chip, port + ICH_REG_OFF_CIV, 0);
 	ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;
 	ichdev->position = 0;
 #if 0
@@ -728,6 +758,8 @@ static irqreturn_t snd_intel8x0_interrup
 	spin_lock(&chip->reg_lock);
 	status = igetdword(chip, chip->int_sta_reg);
 	if ((status & chip->int_sta_mask) == 0) {
+		if (status)
+			iputdword(chip, chip->int_sta_reg, status);
 		spin_unlock(&chip->reg_lock);
 		return IRQ_NONE;
 	}
@@ -776,8 +808,9 @@ static int snd_intel8x0_pcm_trigger(snd_
 	}
 	iputbyte(chip, port + ICH_REG_OFF_CR, val);
 	if (cmd == SNDRV_PCM_TRIGGER_STOP) {
-		/* reset whole DMA things */
+		/* wait until DMA stopped */
 		while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) ;
+		/* reset whole DMA things */
 		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
 	}
 	return 0;
@@ -788,31 +821,40 @@ static int snd_intel8x0_ali_trigger(snd_
 	intel8x0_t *chip = snd_pcm_substream_chip(substream);
 	ichdev_t *ichdev = get_ichdev(substream);
 	unsigned long port = ichdev->reg_offset;
+	static int fiforeg[] = { ICHREG(ALI_FIFOCR1), ICHREG(ALI_FIFOCR2), ICHREG(ALI_FIFOCR3) };
+	unsigned int val, fifo;
 
+	val = igetdword(chip, ICHREG(ALI_DMACR));
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 	case SNDRV_PCM_TRIGGER_RESUME:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			/* clear FIFO for synchronization of channels */
+			fifo = igetdword(chip, fiforeg[ichdev->ali_slot / 4]);
+			fifo &= ~(0xff << (ichdev->ali_slot % 4));  
+			fifo |= 0x83 << (ichdev->ali_slot % 4); 
+			iputdword(chip, fiforeg[ichdev->ali_slot / 4], fifo);
+		}
 		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
-		iputbyte(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
+		val &= ~(1 << (ichdev->ali_slot + 16)); /* clear PAUSE flag */
+		iputdword(chip, ICHREG(ALI_DMACR), val | (1 << ichdev->ali_slot)); /* start DMA */
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
-		iputbyte(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 8));
+		iputdword(chip, ICHREG(ALI_DMACR), val | (1 << (ichdev->ali_slot + 16))); /* pause */
 		iputbyte(chip, port + ICH_REG_OFF_CR, 0);
-		/* reset whole DMA things */
-		while (!(igetbyte(chip, port + ICH_REG_OFF_CR)))
+		while (igetbyte(chip, port + ICH_REG_OFF_CR))
 			;
+		if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
+			break;
+		/* reset whole DMA things */
 		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
 		/* clear interrupts */
 		iputbyte(chip, port + ICH_REG_OFF_SR, igetbyte(chip, port + ICH_REG_OFF_SR) | 0x1e);
 		iputdword(chip, ICHREG(ALI_INTERRUPTSR),
-			  igetdword(chip, ICHREG(ALI_INTERRUPTSR)) & (1 << (ichdev->ali_slot + 8)));
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		iputbyte(chip, port + ICH_REG_OFF_CR, 0);
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		iputbyte(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
+			  igetdword(chip, ICHREG(ALI_INTERRUPTSR)) & ichdev->int_sta_mask);
 		break;
 	default:
 		return -EINVAL;
@@ -833,21 +875,36 @@ static int snd_intel8x0_hw_free(snd_pcm_
 
 static void snd_intel8x0_setup_multi_channels(intel8x0_t *chip, int channels)
 {
-	unsigned int cnt = igetdword(chip, ICHREG(GLOB_CNT));
-	if (chip->device_type == DEVICE_SIS) {
+	unsigned int cnt;
+	switch (chip->device_type) {
+	case DEVICE_ALI:
+		cnt = igetdword(chip, ICHREG(ALI_SCR));
+		cnt &= ~ICH_ALI_SC_PCM_246_MASK;
+		if (chip->multi4 && channels == 4)
+			cnt |= ICH_ALI_SC_PCM_4;
+		else if (chip->multi6 && channels == 6)
+			cnt |= ICH_ALI_SC_PCM_6;
+		iputdword(chip, ICHREG(ALI_SCR), cnt);
+		break;
+	case DEVICE_SIS:
+		cnt = igetdword(chip, ICHREG(GLOB_CNT));
 		cnt &= ~ICH_SIS_PCM_246_MASK;
 		if (chip->multi4 && channels == 4)
 			cnt |= ICH_SIS_PCM_4;
 		else if (chip->multi6 && channels == 6)
 			cnt |= ICH_SIS_PCM_6;
-	} else {
+		iputdword(chip, ICHREG(GLOB_CNT), cnt);
+		break;
+	default:
+		cnt = igetdword(chip, ICHREG(GLOB_CNT));
 		cnt &= ~ICH_PCM_246_MASK;
 		if (chip->multi4 && channels == 4)
 			cnt |= ICH_PCM_4;
 		else if (chip->multi6 && channels == 6)
 			cnt |= ICH_PCM_6;
+		iputdword(chip, ICHREG(GLOB_CNT), cnt);
+		break;
 	}
-	iputdword(chip, ICHREG(GLOB_CNT), cnt);
 }
 
 static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
@@ -860,7 +917,7 @@ static int snd_intel8x0_pcm_prepare(snd_
 	ichdev->physbuf = runtime->dma_addr;
 	ichdev->size = snd_pcm_lib_buffer_bytes(substream);
 	ichdev->fragsize = snd_pcm_lib_period_bytes(substream);
-	if (ichdev->ichd == ICHD_PCMOUT && chip->device_type != DEVICE_ALI) {
+	if (ichdev->ichd == ICHD_PCMOUT) {
 		spin_lock(&chip->reg_lock);
 		snd_intel8x0_setup_multi_channels(chip, runtime->channels);
 		spin_unlock(&chip->reg_lock);
@@ -869,6 +926,9 @@ static int snd_intel8x0_pcm_prepare(snd_
 		for (i = 0; i < 3; i++)
 			if (ichdev->ac97_rate_regs[i])
 				snd_ac97_set_rate(ichdev->ac97, ichdev->ac97_rate_regs[i], runtime->rate);
+		/* FIXME: hack to enable spdif support */
+		if (ichdev->ichd == ICHD_PCMOUT && chip->device_type == DEVICE_SIS)
+			snd_ac97_set_rate(ichdev->ac97, AC97_SPDIF, runtime->rate);
 	}
 	snd_intel8x0_setup_periods(chip, ichdev);
 	return 0;
@@ -878,11 +938,16 @@ static snd_pcm_uframes_t snd_intel8x0_pc
 {
 	intel8x0_t *chip = snd_pcm_substream_chip(substream);
 	ichdev_t *ichdev = get_ichdev(substream);
-	size_t ptr;
+	size_t ptr1, ptr;
 
-	ptr = ichdev->fragsize1;
-	ptr -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift;
+	ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift;
+	if (ptr1 != 0)
+		ptr = ichdev->fragsize1 - ptr1;
+	else
+		ptr = 0;
 	ptr += ichdev->position;
+	if (ptr >= ichdev->size)
+		return 0;
 	return bytes_to_frames(substream->runtime, ptr);
 }
 
@@ -895,7 +960,7 @@ static snd_pcm_hardware_t snd_intel8x0_s
 				 SNDRV_PCM_INFO_RESUME),
 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
 	.rates =		SNDRV_PCM_RATE_48000,
-	.rate_min =		8000,
+	.rate_min =		48000,
 	.rate_max =		48000,
 	.channels_min =		2,
 	.channels_max =		2,
@@ -935,14 +1000,23 @@ static int snd_intel8x0_pcm_open(snd_pcm
 {
 	intel8x0_t *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
+	static unsigned int i, rates[] = {
+		/* ATTENTION: these values depend on the definition in pcm.h! */
+		5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000
+	};
 	int err;
 
 	ichdev->substream = substream;
 	runtime->hw = snd_intel8x0_stream;
-	if (ichdev->ac97 && ichdev->ac97_rates_idx >= 0)
+	if (ichdev->ac97 && ichdev->ac97_rates_idx >= 0) {
 		runtime->hw.rates = ichdev->ac97->rates[ichdev->ac97_rates_idx];
-	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
-		runtime->hw.rate_min = 48000;
+		for (i = 0; i < ARRAY_SIZE(rates); i++) {
+			if (runtime->hw.rates & (1 << i)) {
+				runtime->hw.rate_min = rates[i];
+				break;
+			}
+		}
+	}
 	if (chip->device_type == DEVICE_SIS) {
 		runtime->hw.buffer_bytes_max = 64*1024;
 		runtime->hw.period_bytes_max = 64*1024;
@@ -1058,6 +1132,14 @@ static int snd_intel8x0_spdif_close(snd_
 static int snd_intel8x0_ali_ac97spdifout_open(snd_pcm_substream_t * substream)
 {
 	intel8x0_t *chip = snd_pcm_substream_chip(substream);
+	unsigned long flags;
+	unsigned int val;
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	val = igetdword(chip, ICHREG(ALI_INTERFACECR));
+	val |= ICH_ALI_IF_AC97SP;
+	/* also needs to set ALI_SC_CODEC_SPDF correctly */
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_AC97SPDIFOUT]);
 }
@@ -1065,8 +1147,15 @@ static int snd_intel8x0_ali_ac97spdifout
 static int snd_intel8x0_ali_ac97spdifout_close(snd_pcm_substream_t * substream)
 {
 	intel8x0_t *chip = snd_pcm_substream_chip(substream);
+	unsigned long flags;
+	unsigned int val;
 
 	chip->ichd[ALID_AC97SPDIFOUT].substream = NULL;
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	val = igetdword(chip, ICHREG(ALI_INTERFACECR));
+	val &= ~ICH_ALI_IF_AC97SP;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
 	return 0;
 }
 
@@ -1085,6 +1174,7 @@ static int snd_intel8x0_ali_spdifin_clos
 	return 0;
 }
 
+#if 0 // NYI
 static int snd_intel8x0_ali_spdifout_open(snd_pcm_substream_t * substream)
 {
 	intel8x0_t *chip = snd_pcm_substream_chip(substream);
@@ -1099,6 +1189,7 @@ static int snd_intel8x0_ali_spdifout_clo
 	chip->ichd[ALID_SPDIFOUT].substream = NULL;
 	return 0;
 }
+#endif
 
 static snd_pcm_ops_t snd_intel8x0_playback_ops = {
 	.open =		snd_intel8x0_playback_open,
@@ -1221,6 +1312,7 @@ static snd_pcm_ops_t snd_intel8x0_ali_sp
 	.pointer =	snd_intel8x0_pcm_pointer,
 };
 
+#if 0 // NYI
 static snd_pcm_ops_t snd_intel8x0_ali_spdifout_ops = {
 	.open =		snd_intel8x0_ali_spdifout_open,
 	.close =	snd_intel8x0_ali_spdifout_close,
@@ -1231,6 +1323,7 @@ static snd_pcm_ops_t snd_intel8x0_ali_sp
 	.trigger =	snd_intel8x0_pcm_trigger,
 	.pointer =	snd_intel8x0_pcm_pointer,
 };
+#endif // NYI
 
 struct ich_pcm_table {
 	char *suffix;
@@ -1352,18 +1445,20 @@ static struct ich_pcm_table ali_pcms[] _
 	},
 	{
 		.suffix = "IEC958",
-		.playback_ops = &snd_intel8x0_ali_spdifout_ops,
+		.playback_ops = &snd_intel8x0_ali_ac97spdifout_ops,
 		.capture_ops = &snd_intel8x0_ali_spdifin_ops,
 		.prealloc_size = 64 * 1024,
 		.prealloc_max_size = 128 * 1024,
+		.ac97_idx = ALID_AC97SPDIFOUT,
 	},
+#if 0 // NYI
 	{
-		.suffix = "AC97 IEC958",
-		.playback_ops = &snd_intel8x0_ali_ac97spdifout_ops,
+		.suffix = "HW IEC958",
+		.playback_ops = &snd_intel8x0_ali_spdifout_ops,
 		.prealloc_size = 64 * 1024,
 		.prealloc_max_size = 128 * 1024,
-		.ac97_idx = ALID_AC97SPDIFOUT,
 	},
+#endif
 };
 
 static int __devinit snd_intel8x0_pcm(intel8x0_t *chip)
@@ -1442,20 +1537,30 @@ static struct _ac97_rate_regs nforce_ac9
 };
 
 static struct _ac97_rate_regs ali_ac97_rate_regs[] __devinitdata = {
+#if 0 /* FIXME: my test board doens't work well with VRA... */
 	{ ALID_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC },
 	{ ALID_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC },
 	{ ALID_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC },
 	{ ALID_AC97SPDIFOUT, { AC97_SPDIF, 0, 0 }, AC97_RATES_SPDIF },
 	{ ALID_SPDIFOUT, { 0, 0, 0 }, -1 },
 	{ ALID_SPDIFIN, { 0, 0, 0 }, -1 },
+#else
+	{ ALID_PCMOUT, { AC97_PCM_FRONT_DAC_RATE }, -1 },
+	{ ALID_PCMIN, { AC97_PCM_LR_ADC_RATE }, -1 },
+	{ ALID_MIC, { AC97_PCM_MIC_ADC_RATE }, -1 },
+	{ ALID_AC97SPDIFOUT, { AC97_SPDIF }, -1 },
+	{ ALID_SPDIFOUT, { }, -1 },
+	{ ALID_SPDIFIN, { }, -1 },
+#endif
 };
 
 static struct ac97_quirk ac97_quirks[] __devinitdata = {
 	{ 0x1028, 0x0126, "Dell Optiplex GX260", AC97_TUNE_HP_ONLY },
 	{ 0x1734, 0x0088, "Fujitsu-Siemens D1522", AC97_TUNE_HP_ONLY },
 	{ 0x10f1, 0x2665, "Fujitsu-Siemens Celcius", AC97_TUNE_HP_ONLY },
+	{ 0x110a, 0x0056, "Fujitsu-Siemens Scenic", AC97_TUNE_HP_ONLY },
 	{ 0x8086, 0x4d44, "Intel D850EMV2", AC97_TUNE_HP_ONLY },
-	{ 0x4144, 0x5360, "AMD64 Motherboard", AC97_TUNE_HP_ONLY },
+	/* { 0x4144, 0x5360, "AMD64 Motherboard", AC97_TUNE_HP_ONLY }, */ /* FIXME: this seems invalid */
 	{ 0x1043, 0x80b0, "ASUS P4PE Mobo", AC97_TUNE_SWAP_SURROUND },
 	{ } /* terminator */
 };
@@ -1465,19 +1570,24 @@ static int __devinit snd_intel8x0_mixer(
 	ac97_t ac97, *x97;
 	ichdev_t *ichdev;
 	int err;
-	unsigned int i, num, channels = 2, codecs, _codecs;
+	unsigned int i, num, codecs, _codecs;
 	unsigned int glob_sta = 0;
 	struct _ac97_rate_regs *tbl;
+	int spdif_idx = -1; /* disabled */
 
 	switch (chip->device_type) {
 	case DEVICE_NFORCE:
 		tbl = nforce_ac97_rate_regs;
+		spdif_idx = NVD_SPBAR;
 		break;
 	case DEVICE_ALI:
 		tbl = ali_ac97_rate_regs;
+		spdif_idx = ALID_AC97SPDIFOUT;
 		break;
 	default:
 		tbl = intel_ac97_rate_regs;
+		if (chip->device_type == DEVICE_INTEL_ICH4)
+			spdif_idx = ICHD_SPBAR;
 		break;
 	};
 	for (i = 0; i < chip->bdbars_count; i++) {
@@ -1501,10 +1611,6 @@ static int __devinit snd_intel8x0_mixer(
 		glob_sta = igetdword(chip, ICHREG(GLOB_STA));
 		ac97.write = snd_intel8x0_codec_write;
 		ac97.read = snd_intel8x0_codec_read;
-		if (glob_sta & ICH_PCM_6)
-			channels = 6;
-		else if (glob_sta & ICH_PCM_4)
-			channels = 4;
 		if (chip->device_type == DEVICE_INTEL_ICH4) {
 			codecs = 0;
 			if (glob_sta & ICH_PCR)
@@ -1527,7 +1633,6 @@ static int __devinit snd_intel8x0_mixer(
 	} else {
 		ac97.write = snd_intel8x0_ali_codec_write;
 		ac97.read = snd_intel8x0_ali_codec_read;
-		channels = 6;
 		codecs = 1;
 		/* detect the secondary codec */
 		for (i = 0; i < 100; i++) {
@@ -1551,19 +1656,8 @@ static int __devinit snd_intel8x0_mixer(
 	if (x97->ext_id & AC97_EI_VRM)
 		chip->ichd[ICHD_MIC].ac97 = x97;
 	/* spdif */
-	if (x97->ext_id & AC97_EI_SPDIF) {
-		switch (chip->device_type) {
-		case DEVICE_INTEL_ICH4:
-			chip->ichd[ICHD_SPBAR].ac97 = x97;
-			break;
-		case DEVICE_NFORCE:
-			chip->ichd[NVD_SPBAR].ac97 = x97;
-			break;
-		case DEVICE_ALI:
-			chip->ichd[ALID_AC97SPDIFOUT].ac97 = x97;
-			break;
-		}
-	}
+	if ((x97->ext_id & AC97_EI_SPDIF) && spdif_idx >= 0)
+		chip->ichd[spdif_idx].ac97 = x97;
 	/* make sure, that we have DACs at right slot for rev2.2 */
 	if (ac97_is_rev22(x97))
 		snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 0);
@@ -1594,23 +1688,18 @@ static int __devinit snd_intel8x0_mixer(
 					 chip->ichd[ICHD_PCM2IN].ac97 == x97)
 					chip->ichd[ICHD_MIC2].ac97 = x97;
 			}
-			if (x97->ext_id & AC97_EI_SPDIF) {
-				if (chip->ichd[ICHD_SPBAR].ac97 == NULL)
-					chip->ichd[ICHD_SPBAR].ac97 = x97;
-			}
 			break;
 		default:
 			if (x97->ext_id & AC97_EI_VRM) {
 				if (chip->ichd[ICHD_MIC].ac97 == NULL)
 					chip->ichd[ICHD_MIC].ac97 = x97;
 			}
-			if ((x97->ext_id & AC97_EI_SPDIF) &&
-			    chip->device_type == DEVICE_NFORCE) {
-				if (chip->ichd[NVD_SPBAR].ac97 == NULL)
-					chip->ichd[NVD_SPBAR].ac97 = x97;
-			}
 			break;
 		}
+		if ((x97->ext_id & AC97_EI_SPDIF) && spdif_idx >= 0) {
+			if (chip->ichd[spdif_idx].ac97 == NULL)
+				chip->ichd[spdif_idx].ac97 = x97;
+		}
 	}
 	
       __skip_secondary:
@@ -1640,22 +1729,24 @@ static int __devinit snd_intel8x0_mixer(
 		if (x97->scaps & AC97_SCAP_CENTER_LFE_DAC)
 			chip->multi6 = 1;
 	}
-	if (codecs > 1) {
+	if (chip->device_type == DEVICE_ALI && chip->ac97[1]) {
+		/* set secondary codec id */
+		iputdword(chip, ICHREG(ALI_SSR),
+			  (igetdword(chip, ICHREG(ALI_SSR)) & ~ICH_ALI_SS_SEC_ID) |
+			  (chip->ac97[1]->addr << 5));
+	}
+	if (codecs > 1 && !chip->multi6) {
 		/* assign right slots for rev2.2 codecs */
 		i = 1;
-		if (chip->multi4)
-			goto __6ch;
-		for ( ; i < codecs; i++) {
+		for ( ; i < codecs && !chip->multi4; i++) {
 			x97 = chip->ac97[i];
 			if (!ac97_is_audio(x97))
 				continue;
 			if (ac97_is_rev22(x97)) {
 				snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 1);
 				chip->multi4 = 1;
-				break;
 			}
 		}
-	      __6ch:
 		for ( ; i < codecs && chip->multi4; i++) {
 			x97 = chip->ac97[i];
 			if (!ac97_is_audio(x97))
@@ -1668,27 +1759,20 @@ static int __devinit snd_intel8x0_mixer(
 		}
 		/* ok, some older codecs might support only AMAP */
 		if (!chip->multi4) {
+			int cnums = 0;
 			for (i = 1; i < codecs; i++) {
 				x97 = chip->ac97[i];
 				if (!ac97_is_audio(x97))
 					continue;
 				if (ac97_can_amap(x97)) {
-					if (x97->addr == 1) {
-						chip->multi4 = 1;
-						break;
-					}
-				}
-			}
-			for ( ; i < codecs && chip->multi4; i++) {
-				if (!ac97_is_audio(x97))
-					continue;
-				if (ac97_can_amap(x97)) {
-					if (x97->addr == 2) {
-						chip->multi6 = 1;
-						break;
-					}
+					if (x97->addr > 0)
+						cnums++;
 				}
 			}
+			if (cnums >= 2)
+				chip->multi6 = 1;
+			if (cnums >= 1)
+				chip->multi4 = 1;
 		}
 	}
 	chip->in_ac97_init = 0;
@@ -1702,25 +1786,20 @@ static int __devinit snd_intel8x0_mixer(
 
 static void do_ali_reset(intel8x0_t *chip)
 {
-	iputdword(chip, ICHREG(ALI_SCR), 0x8000000);
+	iputdword(chip, ICHREG(ALI_SCR), ICH_ALI_SC_RESET);
 	iputdword(chip, ICHREG(ALI_FIFOCR1), 0x83838383);
 	iputdword(chip, ICHREG(ALI_FIFOCR2), 0x83838383);
-	iputdword(chip, ICHREG(ALI_INTERFACECR), 0x04080002); /* no spdif? */
+	iputdword(chip, ICHREG(ALI_FIFOCR3), 0x83838383);
+	iputdword(chip, ICHREG(ALI_INTERFACECR),
+		  ICH_ALI_IF_MC|ICH_ALI_IF_PI|ICH_ALI_IF_PO);
 	iputdword(chip, ICHREG(ALI_INTERRUPTCR), 0x00000000);
 	iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000);
 }
 
-static void do_delay(intel8x0_t *chip)
-{
-#ifdef CONFIG_PM
-	if (chip->in_suspend) {
-		mdelay((1000 + HZ - 1) / HZ);
-		return;
-	}
-#endif
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(1);
-}
+#define do_delay(chip) do {\
+	set_current_state(TASK_UNINTERRUPTIBLE);\
+	schedule_timeout(1);\
+} while (0)
 
 static int snd_intel8x0_ich_chip_init(intel8x0_t *chip)
 {
@@ -1847,14 +1926,14 @@ static int snd_intel8x0_chip_init(intel8
 	unsigned int i;
 	int err;
 	
-	if (chip->device_type != DEVICE_ALI)
-		err = snd_intel8x0_ich_chip_init(chip);
-	else
-		err = snd_intel8x0_ali_chip_init(chip);
-	if (err < 0)
-		return err;
-
-	iagetword(chip, 0);	/* clear semaphore flag */
+	if (chip->device_type != DEVICE_ALI) {
+		if ((err = snd_intel8x0_ich_chip_init(chip)) < 0)
+			return err;
+		iagetword(chip, 0);	/* clear semaphore flag */
+	} else {
+		if ((err = snd_intel8x0_ali_chip_init(chip)) < 0)
+			return err;
+	}
 
 	/* disable interrupts */
 	for (i = 0; i < chip->bdbars_count; i++)
@@ -1939,6 +2018,7 @@ static void intel8x0_resume(intel8x0_t *
 		return;
 
 	pci_enable_device(chip->pci);
+	pci_set_master(chip->pci);
 	snd_intel8x0_chip_init(chip);
 	for (i = 0; i < 3; i++)
 		if (chip->ac97[i])
@@ -1948,7 +2028,6 @@ static void intel8x0_resume(intel8x0_t *
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 }
 
-#ifndef PCI_OLD_SUSPEND
 static int snd_intel8x0_suspend(struct pci_dev *dev, u32 state)
 {
 	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return -ENXIO);
@@ -1961,18 +2040,6 @@ static int snd_intel8x0_resume(struct pc
 	intel8x0_resume(chip);
 	return 0;
 }
-#else
-static void snd_intel8x0_suspend(struct pci_dev *dev)
-{
-	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return);
-	intel8x0_suspend(chip);
-}
-static void snd_intel8x0_resume(struct pci_dev *dev)
-{
-	intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return);
-	intel8x0_resume(chip);
-}
-#endif
 
 /* callback */
 static int snd_intel8x0_set_power_state(snd_card_t *card, unsigned int power_state)
@@ -2033,7 +2100,7 @@ static void __devinit intel8x0_measure_a
 		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM);
 	else {
 		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
-		iputbyte(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
+		iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
 	}
 	do_gettimeofday(&start_time);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
@@ -2051,12 +2118,16 @@ static void __devinit intel8x0_measure_a
 	pos += ichdev->position;
 	do_gettimeofday(&stop_time);
 	/* stop */
-	if (chip->device_type == DEVICE_ALI)
-		iputbyte(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 8));
-	iputbyte(chip, port + ICH_REG_OFF_CR, 0);
-	/* reset whole DMA things */
-	while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH))
-		;
+	if (chip->device_type == DEVICE_ALI) {
+		iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 8));
+		iputbyte(chip, port + ICH_REG_OFF_CR, 0);
+		while (igetbyte(chip, port + ICH_REG_OFF_CR))
+			;
+	} else {
+		iputbyte(chip, port + ICH_REG_OFF_CR, 0);
+		while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH))
+			;
+	}
 	iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
@@ -2281,7 +2352,8 @@ static int __devinit snd_intel8x0_create
 			ichdev->roff_sr = ICH_REG_OFF_SR;
 			ichdev->roff_picb = ICH_REG_OFF_PICB;
 		}
-		ichdev->ali_slot = i + 1;	/* is this right for last three devices? --jk */
+		if (device_type == DEVICE_ALI)
+			ichdev->ali_slot = (ichdev->reg_offset - 0x40) / 0x10;
 	}
 	/* SIS7012 handles the pcm data in bytes, others are in words */
 	chip->pcm_pos_shift = (device_type == DEVICE_SIS) ? 0 : 1;
diff -puN sound/pci/maestro3.c~alsa-bk-2003-07-28 sound/pci/maestro3.c
--- 25/sound/pci/maestro3.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/maestro3.c	Tue Jul 29 12:11:32 2003
@@ -43,6 +43,7 @@
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
+#include <sound/mpu401.h>
 #include <sound/ac97_codec.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
@@ -851,6 +852,9 @@ struct snd_m3 {
 	int external_amp;
 	int amp_gpio;
 
+	/* midi */
+	snd_rawmidi_t *rmidi;
+
 	/* pcm streams */
 	int num_substreams;
 	m3_dma_t *substreams;
@@ -971,6 +975,11 @@ static struct m3_quirk m3_quirk_list[] =
  * lowlevel functions
  */
 
+#define big_mdelay(msec) do {\
+	set_current_state(TASK_UNINTERRUPTIBLE);\
+	schedule_timeout(((msec) * HZ) / 1000);\
+} while (0)
+	
 inline static void snd_m3_outw(m3_t *chip, u16 value, unsigned long reg)
 {
 	outw(value, chip->iobase + reg);
@@ -1012,7 +1021,7 @@ static void snd_m3_assp_write(m3_t *chip
 static void snd_m3_assp_halt(m3_t *chip)
 {
 	chip->reset_state = snd_m3_inb(chip, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
-	mdelay(10);
+	big_mdelay(10);
 	snd_m3_outb(chip, chip->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
 }
 
@@ -1526,9 +1535,14 @@ static snd_pcm_uframes_t
 snd_m3_pcm_pointer(snd_pcm_substream_t * subs)
 {
 	m3_t *chip = snd_pcm_substream_chip(subs);
+	unsigned int ptr;
 	m3_dma_t *s = (m3_dma_t*)subs->runtime->private_data;
 	snd_assert(s != NULL, return 0);
-	return bytes_to_frames(subs->runtime, snd_m3_get_pointer(chip, s, subs));
+
+	spin_lock(&chip->reg_lock);
+	ptr = snd_m3_get_pointer(chip, s, subs);
+	spin_unlock(&chip->reg_lock);
+	return bytes_to_frames(subs->runtime, ptr);
 }
 
 
@@ -1562,17 +1576,11 @@ snd_m3_interrupt(int irq, void *dev_id, 
 	u8 status;
 	int i;
 
-	status = inb(chip->iobase + 0x1A);
+	status = inb(chip->iobase + HOST_INT_STATUS);
 
 	if (status == 0xff)
 		return IRQ_NONE;
    
-	/* presumably acking the ints? */
-	outw(status, chip->iobase + 0x1A);
-
-	/*if (in_suspend)
-		return IRQ_NONE;*/
-
 	/*
 	 * ack an assp int if its running
 	 * and has an int pending
@@ -1595,9 +1603,13 @@ snd_m3_interrupt(int irq, void *dev_id, 
 		}
 	}
 
-	/* XXX is this needed? */
-	if (status & 0x40) 
-		outb(0x40, chip->iobase+0x1A);
+#if 0 /* TODO: not supported yet */
+	if ((status & MPU401_INT_PENDING) && chip->rmidi)
+		snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+#endif
+
+	/* ack ints */
+	snd_m3_outw(chip, HOST_INT_STATUS, status);
 
 	return IRQ_HANDLED;
 }
@@ -1898,7 +1910,7 @@ static int snd_m3_try_read_vendor(m3_t *
 	return (ret == 0) || (ret == 0xffff);
 }
 
-static void snd_m3_ac97_reset(m3_t *chip, int busywait)
+static void snd_m3_ac97_reset(m3_t *chip)
 {
 	u16 dir;
 	int delay1 = 0, delay2 = 0, i;
@@ -1933,12 +1945,8 @@ static void snd_m3_ac97_reset(m3_t *chip
 		outw(0, io + GPIO_DATA);
 		outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);
 
-		if (busywait)  {
-			mdelay(delay1);
-		} else {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout((delay1 * HZ) / 1000);
-		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((delay1 * HZ) / 1000);
 
 		outw(GPO_PRIMARY_AC97, io + GPIO_DATA);
 		udelay(5);
@@ -1946,12 +1954,9 @@ static void snd_m3_ac97_reset(m3_t *chip
 		outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A);
 		outw(~0, io + GPIO_MASK);
 
-		if (busywait) {
-			mdelay(delay2);
-		} else {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout((delay2 * HZ) / 1000);
-		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((delay2 * HZ) / 1000);
+
 		if (! snd_m3_try_read_vendor(chip))
 			break;
 
@@ -1968,9 +1973,9 @@ static void snd_m3_ac97_reset(m3_t *chip
 	 */
 	tmp = inw(io + RING_BUS_CTRL_A);
 	outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
-	mdelay(20);
+	big_mdelay(20);
 	outw(tmp, io + RING_BUS_CTRL_A);
-	mdelay(50);
+	big_mdelay(50);
 #endif
 }
 
@@ -2298,8 +2303,15 @@ snd_m3_chip_init(m3_t *chip)
 {
 	struct pci_dev *pcidev = chip->pci;
 	u32 n;
+	u16 w;
 	u8 t; /* makes as much sense as 'n', no? */
 
+	pci_read_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, &w);
+	w &= ~(SOUND_BLASTER_ENABLE|FM_SYNTHESIS_ENABLE|
+	       MPU401_IO_ENABLE|MPU401_IRQ_ENABLE|ALIAS_10BIT_IO|
+	       DISABLE_LEGACY);
+	pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
+
 	pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
 	n &= REDUCED_DEBOUNCE;
 	n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
@@ -2337,7 +2349,7 @@ snd_m3_enable_ints(m3_t *chip)
 {
 	unsigned long io = chip->iobase;
 
-	outw(ASSP_INT_ENABLE, io + HOST_INT_CTRL);
+	outw(ASSP_INT_ENABLE | MPU401_INT_ENABLE, io + HOST_INT_CTRL);
 	outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
 	     io + ASSP_CONTROL_C);
 }
@@ -2363,6 +2375,10 @@ static int snd_m3_free(m3_t *chip)
 		spin_unlock_irqrestore(&chip->reg_lock, flags);
 		kfree(chip->substreams);
 	}
+	if (chip->iobase_res) {
+		snd_m3_outw(chip, HOST_INT_CTRL, 0); /* disable ints */
+	}
+
 #ifdef CONFIG_PM
 	if (chip->suspend_mem)
 		vfree(chip->suspend_mem);
@@ -2400,7 +2416,7 @@ static void m3_suspend(m3_t *chip)
 
 	snd_pcm_suspend_all(chip->pcm);
 
-	mdelay(10); /* give the assp a chance to idle.. */
+	big_mdelay(10); /* give the assp a chance to idle.. */
 
 	snd_m3_assp_halt(chip);
 
@@ -2435,7 +2451,7 @@ static void m3_resume(m3_t *chip)
 
 	snd_m3_chip_init(chip);
 	snd_m3_assp_halt(chip);
-	snd_m3_ac97_reset(chip, 1);
+	snd_m3_ac97_reset(chip);
 
 	/* restore dsp image */
 	index = 0;
@@ -2460,7 +2476,6 @@ static void m3_resume(m3_t *chip)
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 }
 
-#ifndef PCI_OLD_SUSPEND
 static int snd_m3_suspend(struct pci_dev *pci, u32 state)
 {
 	m3_t *chip = snd_magic_cast(m3_t, pci_get_drvdata(pci), return -ENXIO);
@@ -2473,18 +2488,6 @@ static int snd_m3_resume(struct pci_dev 
 	m3_resume(chip);
 	return 0;
 }
-#else
-static void snd_m3_suspend(struct pci_dev *pci)
-{
-	m3_t *chip = snd_magic_cast(m3_t, pci_get_drvdata(pci), return);
-	m3_suspend(chip);
-}
-static void snd_m3_resume(struct pci_dev *pci)
-{
-	m3_t *chip = snd_magic_cast(m3_t, pci_get_drvdata(pci), return);
-	m3_resume(chip);
-}
-#endif
 
 /* callback */
 static int snd_m3_set_power_state(snd_card_t *card, unsigned int power_state)
@@ -2606,7 +2609,7 @@ snd_m3_create(snd_card_t *card, struct p
 	snd_m3_chip_init(chip);
 	snd_m3_assp_halt(chip);
 
-	snd_m3_ac97_reset(chip, 0);
+	snd_m3_ac97_reset(chip);
 
 	snd_m3_assp_init(chip);
 	snd_m3_amp_enable(chip, 1);
@@ -2717,6 +2720,15 @@ snd_m3_probe(struct pci_dev *pci, const 
 		return err;
 	}
 
+#if 0 /* TODO: not supported yet */
+	/* TODO enable midi irq and i/o */
+	err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401,
+				  chip->iobase + MPU401_DATA_PORT, 1,
+				  chip->irq, 0, &chip->rmidi);
+	if (err < 0)
+		printk(KERN_WARNING "maestro3: no midi support.\n");
+#endif
+
 	pci_set_drvdata(pci, chip);
 	dev++;
 	return 0;
diff -puN sound/pci/nm256/nm256.c~alsa-bk-2003-07-28 sound/pci/nm256/nm256.c
--- 25/sound/pci/nm256/nm256.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/nm256/nm256.c	Tue Jul 29 12:11:31 2003
@@ -1307,7 +1307,6 @@ static void nm256_resume(nm256_t *chip)
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 }
 
-#ifndef PCI_OLD_SUSPEND
 static int snd_nm256_suspend(struct pci_dev *dev, u32 state)
 {
 	nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(dev), return -ENXIO);
@@ -1320,18 +1319,6 @@ static int snd_nm256_resume(struct pci_d
 	nm256_resume(chip);
 	return 0;
 }
-#else
-static void snd_nm256_suspend(struct pci_dev *dev)
-{
-	nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(dev), return);
-	nm256_suspend(chip);
-}
-static void snd_nm256_resume(struct pci_dev *dev)
-{
-	nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(dev), return);
-	nm256_resume(chip);
-}
-#endif
 
 /* callback */
 static int snd_nm256_set_power_state(snd_card_t *card, unsigned int power_state)
diff -puN sound/pci/rme9652/hammerfall_mem.c~alsa-bk-2003-07-28 sound/pci/rme9652/hammerfall_mem.c
--- 25/sound/pci/rme9652/hammerfall_mem.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/rme9652/hammerfall_mem.c	Tue Jul 29 12:11:31 2003
@@ -1,251 +0,0 @@
-/* 
-    ALSA memory allocation module for the RME Digi9652
-  
- 	Copyright(c) 1999 IEM - Winfried Ritsch
-        Copyright (C) 1999 Paul Barton-Davis 
-
-    This module is only needed if you compiled the hammerfall driver with
-    the PREALLOCATE_MEMORY option. It allocates the memory need to
-    run the board and holds it until the module is unloaded. Because
-    we need 2 contiguous 1.6MB regions for the board, it can be
-    a problem getting them once the system memory has become fairly
-    fragmented. 
-
-    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-    $Id: hammerfall_mem.c,v 1.9 2003/05/31 11:33:57 perex Exp $
-
-
-    Tue Oct 17 2000  Jaroslav Kysela <perex@suse.cz>
-    	* space is allocated only for physical devices
-        * added support for 2.4 kernels (pci_alloc_consistent)
-    
-*/
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <sound/initval.h>
-
-#define HAMMERFALL_CARDS			8
-#define HAMMERFALL_CHANNEL_BUFFER_SAMPLES  (16*1024)
-#define HAMMERFALL_CHANNEL_BUFFER_BYTES    (4*HAMMERFALL_CHANNEL_BUFFER_SAMPLES)
-
-/* export */
-
-static int enable[8] = {1,1,1,1,1,1,1,1};
-MODULE_PARM(enable, "1-" __MODULE_STRING(HAMMERFALL_CARDS) "i");
-MODULE_PARM_DESC(enable, "Enable cards to allocate buffers for.");
-
-MODULE_AUTHOR("Winfried Ritsch, Paul Barton-Davis <pbd@op.net>");
-MODULE_DESCRIPTION("Memory allocator for RME Hammerfall");
-MODULE_CLASSES("{sound}");
-MODULE_LICENSE("GPL");
-
-/* Since we don't know at this point if we're allocating memory for a
-   Hammerfall or a Hammerfall/Light, assume the worst and allocate
-   space for the maximum number of channels.
-
-   The extra channel is allocated because we need a 64kB-aligned
-   buffer in the actual interface driver code (see rme9652.c or hdsp.c
-   for details)
-*/
-
-#define TOTAL_SIZE (26+1)*(HAMMERFALL_CHANNEL_BUFFER_BYTES)
-#define NBUFS   2*HAMMERFALL_CARDS
-
-#define HAMMERFALL_BUF_ALLOCATED 0x1
-#define HAMMERFALL_BUF_USED      0x2
-
-typedef struct hammerfall_buf_stru hammerfall_buf_t;
-
-struct hammerfall_buf_stru {
-	struct pci_dev *pci;
-	void *buf;
-	dma_addr_t addr;
-	char flags;
-};
-
-static hammerfall_buf_t hammerfall_buffers[NBUFS];
-
-/* These are here so that we have absolutely no dependencies
-   on any other modules. Dependencies can (1) cause us to
-   lose in the rush for 2x1.6MB chunks of contiguous memory
-   and (2) make driver debugging difficult because unloading
-   and reloading the snd module causes us to have to do the
-   same for this one. Since we can rarely if ever allocate
-   memory after starting things running, that would be very
-   undesirable.  
-*/
-
-static void *hammerfall_malloc_pages(struct pci_dev *pci,
-				  unsigned long size,
-				  dma_addr_t *dmaaddr)
-{
-	void *res;
-
-	res = (void *) pci_alloc_consistent(pci, size, dmaaddr);
-	if (res != NULL) {
-		struct page *page = virt_to_page(res);
-		struct page *last_page = page + (size + PAGE_SIZE - 1) / PAGE_SIZE;
-		while (page < last_page)
-			set_bit(PG_reserved, &(page++)->flags);
-	}
-	return res;
-}
-
-static void hammerfall_free_pages(struct pci_dev *pci, unsigned long size,
-			       void *ptr, dma_addr_t dmaaddr)
-{
-	struct page *page, *last_page;
-
-	if (ptr == NULL)
-		return;
-	page = virt_to_page(ptr);
-	last_page = virt_to_page(ptr) + (size + PAGE_SIZE - 1) / PAGE_SIZE;
-	while (page < last_page)
-		clear_bit(PG_reserved, &(page++)->flags);
-	pci_free_consistent(pci, size, ptr, dmaaddr);
-}
-
-void *snd_hammerfall_get_buffer (struct pci_dev *pcidev, dma_addr_t *dmaaddr)
-{
-	int i;
-	hammerfall_buf_t *rbuf;
-
-	for (i = 0; i < NBUFS; i++) {
-		rbuf = &hammerfall_buffers[i];
-		if (rbuf->flags == HAMMERFALL_BUF_ALLOCATED) {
-			rbuf->flags |= HAMMERFALL_BUF_USED;
-			rbuf->pci = pcidev;
-			*dmaaddr = rbuf->addr;
-			return rbuf->buf;
-		}
-	}
-
-	return NULL;
-}
-
-void snd_hammerfall_free_buffer (struct pci_dev *pcidev, void *addr)
-{
-	int i;
-	hammerfall_buf_t *rbuf;
-
-	for (i = 0; i < NBUFS; i++) {
-		rbuf = &hammerfall_buffers[i];
-		if (rbuf->buf == addr && rbuf->pci == pcidev) {
-			rbuf->flags &= ~HAMMERFALL_BUF_USED;
-			return;
-		}
-	}
-
-	printk ("Hammerfall memory allocator: unknown buffer address or PCI device ID");
-}
-
-static void hammerfall_free_buffers (void)
-
-{
-	int i;
-	hammerfall_buf_t *rbuf;
-
-	for (i = 0; i < NBUFS; i++) {
-
-		/* We rely on general module code to prevent
-		   us from being unloaded with buffers in use.
-
-		   However, not quite. Do not release memory
-		   if it is still marked as in use. This might
-		   be unnecessary.
-		*/
-
-		rbuf = &hammerfall_buffers[i];
-
-		if (rbuf->flags == HAMMERFALL_BUF_ALLOCATED) {
-			hammerfall_free_pages (rbuf->pci, TOTAL_SIZE, rbuf->buf, rbuf->addr);
-			rbuf->buf = NULL;
-			rbuf->flags = 0;
-		}
-	}
-}				 
-
-static int __init alsa_hammerfall_mem_init(void)
-{
-	int i;
-	struct pci_dev *pci = NULL;
-	hammerfall_buf_t *rbuf;
-
-	/* make sure our buffer records are clean */
-
-	for (i = 0; i < NBUFS; i++) {
-		rbuf = &hammerfall_buffers[i];
-		rbuf->pci = NULL;
-		rbuf->buf = NULL;
-		rbuf->flags = 0;
-	}
-
-	/* ensure sane values for the number of buffers */
-
-	/* Remember: 2 buffers per card, one for capture, one for
-	   playback.
-	*/
-	
-	i = 0;	/* card number */
-	rbuf = hammerfall_buffers;
-	while ((pci = pci_find_device(PCI_VENDOR_ID_XILINX, PCI_ANY_ID, pci)) != NULL) {
-		int k;
-		
-		/* check for Hammerfall and Hammerfall DSP cards */
-
-		if (pci->device != 0x3fc4 && pci->device != 0x3fc5)
-			continue;
-
-		if (!enable[i])
-			continue;
-
-		for (k = 0; k < 2; ++k) {
-			rbuf->buf = hammerfall_malloc_pages(pci, TOTAL_SIZE, &rbuf->addr);
-			if (rbuf->buf == NULL) {
-				hammerfall_free_buffers();
-				printk(KERN_ERR "Hammerfall memory allocator: no memory available for card %d buffer %d\n", i, k + 1);
-				return -ENOMEM;
-			}
-			rbuf->flags = HAMMERFALL_BUF_ALLOCATED;
-			rbuf++;
-		}
-		i++;
-	}
-
-	if (i == 0)
-		printk(KERN_ERR "Hammerfall memory allocator: "
-		       "no Hammerfall cards found...\n");
-	else
-		printk(KERN_ERR "Hammerfall memory allocator: "
-		       "buffers allocated for %d cards\n", i);
-
-	return 0;
-}
-
-static void __exit alsa_hammerfall_mem_exit(void)
-{
-	hammerfall_free_buffers();
-}
-
-module_init(alsa_hammerfall_mem_init)
-module_exit(alsa_hammerfall_mem_exit)
-
-EXPORT_SYMBOL(snd_hammerfall_get_buffer);
-EXPORT_SYMBOL(snd_hammerfall_free_buffer);
diff -puN sound/pci/rme9652/hdsp.c~alsa-bk-2003-07-28 sound/pci/rme9652/hdsp.c
--- 25/sound/pci/rme9652/hdsp.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/rme9652/hdsp.c	Tue Jul 29 12:11:31 2003
@@ -22,6 +22,7 @@
  */
 
 #include <sound/driver.h>
+#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
@@ -75,6 +76,8 @@ MODULE_DEVICES("{{RME Hammerfall-DSP},"
 #define DIGIFACE_DS_CHANNELS     14
 #define MULTIFACE_SS_CHANNELS    18
 #define MULTIFACE_DS_CHANNELS    14
+#define H9652_SS_CHANNELS        26
+#define H9652_DS_CHANNELS        14
 
 /* Write registers. These are defined as byte-offsets from the iobase value.
  */
@@ -84,7 +87,7 @@ MODULE_DEVICES("{{RME Hammerfall-DSP},"
 #define HDSP_controlRegister		64
 #define HDSP_interruptConfirmation	96
 #define HDSP_outputEnable	  	128
-#define HDSP_jtagReg  			256
+#define HDSP_control2Reg		256
 #define HDSP_midiDataOut0  		352
 #define HDSP_midiDataOut1  		356
 #define HDSP_fifoData  			368
@@ -120,7 +123,7 @@ MODULE_DEVICES("{{RME Hammerfall-DSP},"
 
 #define HDSP_IO_EXTENT     5192
 
-/* jtag register bits */
+/* control2 register bits */
 
 #define HDSP_TMS                0x01
 #define HDSP_TCK                0x02
@@ -133,6 +136,7 @@ MODULE_DEVICES("{{RME Hammerfall-DSP},"
 #define HDSP_VERSION_BIT	0x100
 #define HDSP_BIGENDIAN_MODE     0x200
 #define HDSP_RD_MULTIPLE        0x400
+#define HDSP_9652_ENABLE_MIXER  0x800
 
 #define HDSP_S_PROGRAM     	(HDSP_PROGRAM|HDSP_CONFIG_MODE_0)
 #define HDSP_S_LOAD		(HDSP_PROGRAM|HDSP_CONFIG_MODE_1)
@@ -358,15 +362,16 @@ struct _hdsp {
         hdsp_midi_t           midi[2];
 	struct tasklet_struct midi_tasklet;
 	int                   precise_ptr;
-	u32                   control_register;	         /* cached value */
+	u32                   control_register;	     /* cached value */
+	u32                   control2_register;     /* cached value */
 	u32                   creg_spdif;
 	u32                   creg_spdif_stream;
-	char                 *card_name;		    /* digiface/multiface */
+	char                 *card_name;	     /* digiface/multiface */
 	HDSP_IO_Type          io_type;               /* ditto, but for code use */
         unsigned short        firmware_rev;
 	unsigned short	      state;		     /* stores state bits */
 	u32		      firmware_cache[24413]; /* this helps recover from accidental iobox power failure */
-	size_t                period_bytes; 	    /* guess what this is */
+	size_t                period_bytes; 	     /* guess what this is */
 	unsigned char         ds_channels;
 	unsigned char         ss_channels;	    /* different for multiface/digiface */
 	void                 *capture_buffer_unaligned;	 /* original buffer addresses */
@@ -433,8 +438,39 @@ static char channel_map_ds[HDSP_MAX_CHAN
 #define HDSP_PREALLOCATE_MEMORY	/* via module snd-hdsp_mem */
 
 #ifdef HDSP_PREALLOCATE_MEMORY
-extern void *snd_hammerfall_get_buffer(struct pci_dev *, dma_addr_t *dmaaddr);
-extern void snd_hammerfall_free_buffer(struct pci_dev *, void *ptr);
+static void *snd_hammerfall_get_buffer(struct pci_dev *pci, size_t size, dma_addr_t *addrp, int capture)
+{
+	struct snd_dma_device pdev;
+	struct snd_dma_buffer dmbuf;
+
+	snd_dma_device_pci(&pdev, pci, capture);
+	dmbuf.bytes = 0;
+	if (! snd_dma_get_reserved(&pdev, &dmbuf)) {
+		if (snd_dma_alloc_pages(&pdev, size, &dmbuf) < 0)
+			return NULL;
+		snd_dma_set_reserved(&pdev, &dmbuf);
+	}
+	*addrp = dmbuf.addr;
+	return dmbuf.area;
+}
+
+static void snd_hammerfall_free_buffer(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t addr, int capture)
+{
+	struct snd_dma_device dev;
+	snd_dma_device_pci(&dev, pci, capture);
+	snd_dma_free_reserved(&dev);
+}
+
+#else
+static void *snd_hammerfall_get_buffer(struct pci_dev *pci, size_t size, dma_addr_t *addrp, int capture)
+{
+	return snd_malloc_pci_pages(pci, size, addrp);
+}
+
+static void snd_hammerfall_free_buffer(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t addr, int capture)
+{
+	snd_free_pci_pages(pci, size, ptr, addr);
+}
 #endif
 
 static struct pci_device_id snd_hdsp_ids[] __devinitdata = {
@@ -452,7 +488,7 @@ MODULE_DEVICE_TABLE(pci, snd_hdsp_ids);
 /* prototypes */
 static int __devinit snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp);
 static int __devinit snd_hdsp_create_pcm(snd_card_t *card, hdsp_t *hdsp);
-static inline int snd_hdsp_initialize_input_enable (hdsp_t *hdsp);
+static inline int snd_hdsp_enable_io (hdsp_t *hdsp);
 static inline void snd_hdsp_initialize_midi_flush (hdsp_t *hdsp);
 static inline void snd_hdsp_initialize_channels (hdsp_t *hdsp);
 static inline int hdsp_fifo_wait(hdsp_t *hdsp, int count, int timeout);
@@ -460,18 +496,6 @@ static int hdsp_update_simple_mixer_cont
 static int hdsp_autosync_ref(hdsp_t *hdsp);
 static int snd_hdsp_set_defaults(hdsp_t *hdsp);
 
-static inline int hdsp_is_9652 (hdsp_t *hdsp)
-{
-	switch (hdsp->firmware_rev) {
-	case 0x64:
-	case 0x65:
-	case 0x68:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
 static inline int hdsp_playback_to_output_key (hdsp_t *hdsp, int in, int out)
 {
 	switch (hdsp->firmware_rev) {
@@ -504,12 +528,15 @@ static inline unsigned int hdsp_read(hds
 
 static inline int hdsp_check_for_iobox (hdsp_t *hdsp)
 {
+
+	if (hdsp->io_type == H9652) return 0;
 	if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) {
 		snd_printk ("Hammerfall-DSP: no Digiface or Multiface connected!\n");
 		hdsp->state &= ~HDSP_FirmwareLoaded;
 		return -EIO;
 	}
 	return 0;
+
 }
 
 static int snd_hdsp_load_firmware_from_cache(hdsp_t *hdsp) {
@@ -521,7 +548,7 @@ static int snd_hdsp_load_firmware_from_c
 		
 		snd_printk ("loading firmware\n");
 
-		hdsp_write (hdsp, HDSP_jtagReg, HDSP_S_PROGRAM);
+		hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_PROGRAM);
 		hdsp_write (hdsp, HDSP_fifoData, 0);
 		
 		if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
@@ -529,7 +556,7 @@ static int snd_hdsp_load_firmware_from_c
 			return -EIO;
 		}
 		
-		hdsp_write (hdsp, HDSP_jtagReg, HDSP_S_LOAD);
+		hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
 		
 		for (i = 0; i < 24413; ++i) {
 			hdsp_write(hdsp, HDSP_fifoData, hdsp->firmware_cache[i]);
@@ -544,7 +571,12 @@ static int snd_hdsp_load_firmware_from_c
 		    	return -EIO;
 		}
 
-		hdsp_write (hdsp, HDSP_jtagReg, 0);
+#ifdef SNDRV_BIG_ENDIAN
+		hdsp->control2_register = HDSP_BIGENDIAN_MODE;
+#else
+		hdsp->control2_register = 0;
+#endif
+		hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
 		snd_printk ("finished firmware loading\n");
 		
 		if ((1000 / HZ) < 3000) {
@@ -574,25 +606,25 @@ static inline int hdsp_get_iobox_version
 		return -EIO;
 	}
 
-	if ((err = snd_hdsp_initialize_input_enable(hdsp)) < 0) {
+	if ((err = snd_hdsp_enable_io(hdsp)) < 0) {
 		return err;
 	}
 		
 	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
 	
-		hdsp_write (hdsp, HDSP_jtagReg, HDSP_PROGRAM);
+		hdsp_write (hdsp, HDSP_control2Reg, HDSP_PROGRAM);
 		hdsp_write (hdsp, HDSP_fifoData, 0);
 		if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT) < 0) {
 			return -EIO;
 		}
 
-		hdsp_write (hdsp, HDSP_jtagReg, HDSP_S_LOAD);
+		hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
 		hdsp_write (hdsp, HDSP_fifoData, 0);
 
 		if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT)) {
 			hdsp->io_type = Multiface;
-			hdsp_write (hdsp, HDSP_jtagReg, HDSP_VERSION_BIT);
-			hdsp_write (hdsp, HDSP_jtagReg, HDSP_S_LOAD);
+			hdsp_write (hdsp, HDSP_control2Reg, HDSP_VERSION_BIT);
+			hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
 			hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT);
 		} else {
 			hdsp->io_type = Digiface;
@@ -611,6 +643,7 @@ static inline int hdsp_get_iobox_version
 
 static inline int hdsp_check_for_firmware (hdsp_t *hdsp)
 {
+	if (hdsp->io_type == H9652) return 0;
 	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
 		snd_printk("firmware not present.\n");
 		hdsp->state &= ~HDSP_FirmwareLoaded;
@@ -657,36 +690,41 @@ static inline int hdsp_write_gain(hdsp_t
 {
 	unsigned int ad;
 
-	if (hdsp_is_9652 (hdsp)) {
+	if (addr >= HDSP_MATRIX_MIXER_SIZE)
+		return -1;
+		
+	if (hdsp->io_type == H9652) {
 
-		if ((ad = addr/2) < 676) {
+		/* from martin björnsen:
+		   
+		   "You can only write dwords to the
+		   mixer memory which contain two
+		   mixer values in the low and high
+		   word. So if you want to change
+		   value 0 you have to read value 1
+		   from the cache and write both to
+		   the first dword in the mixer
+		   memory."
+		*/
 
-			/* from martin björnsen:
+		hdsp->mixer_matrix[addr] = data;
 
-			   "You can only write dwords to the
-			   mixer memory which contain two
-			   mixer values in the low and high
-			   word. So if you want to change
-			   value 0 you have to read value 1
-			   from the cache and write both to
-			   the first dword in the mixer
-			   memory."
-			*/
-
-			hdsp->mixer_matrix[addr] = data;
-			hdsp_write (hdsp, 1024 + ad, 
-				    (hdsp->mixer_matrix[(addr&0x7fe)+1] << 16) + 
-				    hdsp->mixer_matrix[addr&0x7fe]);
-			return 0;
-		} else {
-			return -1;
-		}
+		/* `addr' addresses a 16-bit wide address, but
+		   the address space accessed via hdsp_write
+		   uses byte offsets. put another way, addr
+		   varies from 0 to 1351, but to access the
+		   corresponding memory location, we need
+		   to access 0 to 2703 ...
+		*/
+
+		hdsp_write (hdsp, 4096 + (addr*2), 
+			    (hdsp->mixer_matrix[(addr&0x7fe)+1] << 16) + 
+			    hdsp->mixer_matrix[addr&0x7fe]);
 		
+		return 0;
 
 	} else {
-		if (addr >= HDSP_MATRIX_MIXER_SIZE)
-			return -1;
-		
+
 		ad = (addr << 16) + data;
 		
 		if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT)) {
@@ -829,6 +867,11 @@ static int hdsp_set_rate(hdsp_t *hdsp, i
 	int current_rate;
 	int rate_bits;
 
+	/* ASSUMPTION: hdsp->lock is either help, or
+	   there is no need for it (e.g. during module
+	   initialization).
+	*/
+	
 	if (!(hdsp->control_register & HDSP_ClockModeMaster)) {	
 		if (called_internally) {
 			/* request from ctl or card initialization */
@@ -860,8 +903,6 @@ static int hdsp_set_rate(hdsp_t *hdsp, i
 	   exists for externally-driven rate changes. All we can do
 	   is to flag rate changes in the read/write routines.  */
 
-	spin_lock_irq(&hdsp->lock);
-
 	switch (rate) {
 	case 32000:
 		if (current_rate > 48000) {
@@ -900,7 +941,6 @@ static int hdsp_set_rate(hdsp_t *hdsp, i
 		rate_bits = HDSP_Frequency96KHz;
 		break;
 	default:
-		spin_unlock_irq(&hdsp->lock);
 		return -EINVAL;
 	}
 
@@ -908,7 +948,6 @@ static int hdsp_set_rate(hdsp_t *hdsp, i
 		snd_printk ("cannot change between single- and double-speed mode (capture PID = %d, playback PID = %d)\n",
 			    hdsp->capture_pid,
 			    hdsp->playback_pid);
-		spin_unlock_irq(&hdsp->lock);
 		return -EBUSY;
 	}
 
@@ -924,6 +963,7 @@ static int hdsp_set_rate(hdsp_t *hdsp, i
 			hdsp->channel_map = channel_map_mf_ss;
 			break;
 		case Digiface:
+		case H9652:
 			hdsp->channel_map = channel_map_df_ss;
 			break;
 		default:
@@ -938,7 +978,6 @@ static int hdsp_set_rate(hdsp_t *hdsp, i
 		hdsp_update_simple_mixer_controls (hdsp);
 	}
 
-	spin_unlock_irq(&hdsp->lock);
 	return 0;
 }
 
@@ -1131,21 +1170,19 @@ static void snd_hdsp_midi_input_trigger(
 	hdsp_t *hdsp;
 	hdsp_midi_t *hmidi;
 	unsigned long flags;
+	u32 ie;
 
 	hmidi = (hdsp_midi_t *) substream->rmidi->private_data;
 	hdsp = hmidi->hdsp;
+	ie = hmidi->id ? HDSP_Midi1InterruptEnable : HDSP_Midi0InterruptEnable;
 	spin_lock_irqsave (&hdsp->lock, flags);
 	if (up) {
-		snd_hdsp_flush_midi_input (hdsp, hmidi->id);
-		if (hmidi->id) 
-			hdsp->control_register |= HDSP_Midi1InterruptEnable;
-		else 
-			hdsp->control_register |= HDSP_Midi0InterruptEnable;
+		if (!(hdsp->control_register & ie)) {
+			snd_hdsp_flush_midi_input (hdsp, hmidi->id);
+			hdsp->control_register |= ie;
+		}
 	} else {
-		if (hmidi->id) 
-			hdsp->control_register &= ~HDSP_Midi1InterruptEnable;
-		else 
-			hdsp->control_register &= ~HDSP_Midi0InterruptEnable;
+		hdsp->control_register &= ~ie;
 	}
 
 	hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
@@ -2004,7 +2041,19 @@ static int snd_hdsp_info_pref_sync_ref(s
 	
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
-	uinfo->value.enumerated.items = (hdsp->io_type == Digiface) ? 6 : 4;
+
+	switch (hdsp->io_type) {
+	case Digiface:
+	case H9652:
+		uinfo->value.enumerated.items = 6;
+		break;
+	case Multiface:
+		uinfo->value.enumerated.items = 4;
+	default:
+		uinfo->value.enumerated.items = 0;
+		break;
+	}
+		
 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
@@ -2028,7 +2077,19 @@ static int snd_hdsp_put_pref_sync_ref(sn
 	
 	if (!snd_hdsp_use_is_exclusive(hdsp))
 		return -EBUSY;
-	max = (hdsp->io_type == Digiface) ? 6 : 4;
+
+	switch (hdsp->io_type) {
+	case Digiface:
+	case H9652:
+		max = 6;
+		break;
+	case Multiface:
+		max = 4;
+		break;
+	default:
+		return -EIO;
+	}
+
 	val = ucontrol->value.enumerated.item[0] % max;
 	spin_lock_irqsave(&hdsp->lock, flags);
 	change = (int)val != hdsp_pref_sync_ref(hdsp);
@@ -2496,7 +2557,22 @@ static int snd_hdsp_get_adat_sync_check(
 	hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol);
 
 	offset = ucontrol->id.index - 1;
-	snd_assert(offset >= 0 || offset < ((hdsp->io_type == Digiface) ? 3 : 1), return -EINVAL);
+	snd_assert(offset >= 0);
+
+	switch (hdsp->io_type) {
+	case Digiface:
+	case H9652:
+		if (offset >= 3)
+			return -EINVAL;
+		break;
+	case Multiface:
+		if (offset >= 1) 
+			return -EINVAL;
+		break;
+	default:
+		return -EIO;
+	}
+
 	ucontrol->value.enumerated.item[0] = hdsp_adat_sync_check(hdsp, offset);
 	return 0;
 }
@@ -2593,8 +2669,9 @@ int snd_hdsp_create_controls(snd_card_t 
 	snd_kcontrol_t *kctl;
 
 	for (idx = 0; idx < HDSP_CONTROLS; idx++) {
-		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0)
+		if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0) {
 			return err;
+		}
 		if (idx == 1)	/* IEC958 (S/PDIF) Stream */
 			hdsp->spdif_ctl = kctl;
 	}
@@ -2602,10 +2679,18 @@ int snd_hdsp_create_controls(snd_card_t 
 	snd_hdsp_playback_mixer.name = "Chn";
 	snd_hdsp_adat_sync_check.name = "ADAT Lock Status";
 
-	if (hdsp->io_type == Digiface) {
+	switch (hdsp->io_type) {
+	case Digiface:
 		limit = DIGIFACE_SS_CHANNELS;
-	} else {
+		break;
+	case H9652:
+		limit = H9652_SS_CHANNELS;
+		break;
+	case Multiface:
 		limit = MULTIFACE_SS_CHANNELS;
+		break;
+	default:
+		return -EIO;
 	}
 	
 	/* The index values are one greater than the channel ID so that alsamixer
@@ -2627,7 +2712,7 @@ int snd_hdsp_create_controls(snd_card_t 
 	if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp)))) {
 		return err;
 	}	
-	if (hdsp->io_type == Digiface) {
+	if (hdsp->io_type == Digiface || hdsp->io_type == H9652) {
 		for (idx = 1; idx < 3; ++idx) {
 			snd_hdsp_adat_sync_check.index = idx+1;
 			if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp)))) {
@@ -2681,6 +2766,7 @@ snd_hdsp_proc_read(snd_info_entry_t *ent
 	snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
 		    hdsp->irq, hdsp->port, hdsp->iobase);
 	snd_iprintf(buffer, "Control register: 0x%x\n", hdsp->control_register);
+	snd_iprintf(buffer, "Control2 register: 0x%x\n", hdsp->control2_register);
 	snd_iprintf(buffer, "Status register: 0x%x\n", status);
 	snd_iprintf(buffer, "Status2 register: 0x%x\n", status2);
 	snd_iprintf(buffer, "FIFO status: %d\n", hdsp_read(hdsp, HDSP_fifoStatus) & 0xff);
@@ -2854,6 +2940,7 @@ snd_hdsp_proc_read(snd_info_entry_t *ent
 
 	switch (hdsp->io_type) {
 	case Digiface:
+	case H9652:
 		x = status & HDSP_Sync1;
 		if (status & HDSP_Lock1) {
 			snd_iprintf(buffer, "ADAT2: %s\n", x ? "Sync" : "Lock");
@@ -2913,25 +3000,15 @@ static void __devinit snd_hdsp_proc_init
 static void snd_hdsp_free_buffers(hdsp_t *hdsp)
 {
 	if (hdsp->capture_buffer_unaligned) {
-#ifndef HDSP_PREALLOCATE_MEMORY
-		snd_free_pci_pages(hdsp->pci,
-				   HDSP_DMA_AREA_BYTES,
-				   hdsp->capture_buffer_unaligned,
-				   hdsp->capture_buffer_addr);
-#else
-		snd_hammerfall_free_buffer(hdsp->pci, hdsp->capture_buffer_unaligned);
-#endif
+		snd_hammerfall_free_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES,
+					   hdsp->capture_buffer_unaligned,
+					   hdsp->capture_buffer_addr, 1);
 	}
 
 	if (hdsp->playback_buffer_unaligned) {
-#ifndef HDSP_PREALLOCATE_MEMORY
-		snd_free_pci_pages(hdsp->pci,
-				   HDSP_DMA_AREA_BYTES,
-				   hdsp->playback_buffer_unaligned,
-				   hdsp->playback_buffer_addr);
-#else
-		snd_hammerfall_free_buffer(hdsp->pci, hdsp->playback_buffer_unaligned);
-#endif
+		snd_hammerfall_free_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES,
+					   hdsp->playback_buffer_unaligned,
+					   hdsp->playback_buffer_addr, 0);
 	}
 }
 
@@ -2941,28 +3018,15 @@ static int __devinit snd_hdsp_initialize
 	dma_addr_t pb_addr, cb_addr;
 	unsigned long pb_bus, cb_bus;
 
-#ifndef HDSP_PREALLOCATE_MEMORY
-	cb = snd_malloc_pci_pages(hdsp->pci, HDSP_DMA_AREA_BYTES, &cb_addr);
-	pb = snd_malloc_pci_pages(hdsp->pci, HDSP_DMA_AREA_BYTES, &pb_addr);
-#else
-	cb = snd_hammerfall_get_buffer(hdsp->pci, &cb_addr);
-	pb = snd_hammerfall_get_buffer(hdsp->pci, &pb_addr);
-#endif
+	cb = snd_hammerfall_get_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES, &cb_addr, 1);
+	pb = snd_hammerfall_get_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES, &pb_addr, 0);
 
 	if (cb == 0 || pb == 0) {
 		if (cb) {
-#ifdef HDSP_PREALLOCATE_MEMORY
-			snd_hammerfall_free_buffer(hdsp->pci, cb);
-#else
-			snd_free_pci_pages(hdsp->pci, HDSP_DMA_AREA_BYTES, cb, cb_addr);
-#endif
+			snd_hammerfall_free_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES, cb, cb_addr, 1);
 		}
 		if (pb) {
-#ifdef HDSP_PREALLOCATE_MEMORY
-			snd_hammerfall_free_buffer(hdsp->pci, pb);
-#else
-			snd_free_pci_pages(hdsp->pci, HDSP_DMA_AREA_BYTES, pb, pb_addr);
-#endif
+			snd_hammerfall_free_buffer(hdsp->pci, HDSP_DMA_AREA_BYTES, pb, pb_addr, 0);
 		}
 
 		printk(KERN_ERR "%s: no buffers available\n", hdsp->card_name);
@@ -3025,13 +3089,13 @@ static int snd_hdsp_set_defaults(hdsp_t 
 		hdsp->mixer_matrix[i] = MINUS_INFINITY_GAIN;
 	}
 
-	for (i = 0; i < (hdsp_is_9652(hdsp) ? 1352 : HDSP_MATRIX_MIXER_SIZE); i++) {
+	for (i = 0; i < (hdsp->io_type == H9652 ? 1352 : HDSP_MATRIX_MIXER_SIZE); i++) {
 		if (hdsp_write_gain (hdsp, i, MINUS_INFINITY_GAIN)) {
 			return -EIO;
 		}
 	}
 	
-	if (!hdsp_is_9652(hdsp) && line_outs_monitor[hdsp->dev]) {
+	if ((hdsp->io_type != H9652) && line_outs_monitor[hdsp->dev]) {
 		
 		snd_printk ("sending all inputs and playback streams to line outs.\n");
 
@@ -3291,9 +3355,13 @@ static int snd_hdsp_hw_params(snd_pcm_su
 	/* how to make sure that the rate matches an externally-set one ?
 	 */
 
+	spin_lock_irq(&hdsp->lock);
 	if ((err = hdsp_set_rate(hdsp, params_rate(params), 0)) < 0) {
+		spin_unlock_irq(&hdsp->lock);
 		_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
 		return err;
+	} else {
+		spin_unlock_irq(&hdsp->lock);
 	}
 
 	if ((err = hdsp_set_interrupt_interval(hdsp, params_period_size(params))) < 0) {
@@ -3731,6 +3799,10 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde
 	
 	switch (cmd) {
 	case SNDRV_HDSP_IOCTL_GET_PEAK_RMS:
+		if (hdsp->io_type == H9652) {
+		    snd_printk("hardware metering isn't supported yet for hdsp9652 cards\n");
+		    return -EINVAL;
+		}
 		if (!(hdsp->state & HDSP_FirmwareLoaded)) {
 			snd_printk("firmware needs to be uploaded to the card.\n");	
 			return -EINVAL;
@@ -3783,7 +3855,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde
 			return -EFAULT;
 		break;
 	case SNDRV_HDSP_IOCTL_GET_VERSION:
-		if (hdsp_is_9652(hdsp)) return -EINVAL;
+		if (hdsp->io_type == H9652) return -EINVAL;
 		if (hdsp->io_type == Undefined) {
 			if ((err = hdsp_get_iobox_version(hdsp)) < 0) {
 				return err;
@@ -3796,7 +3868,7 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde
 		}
 		break;
 	case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE:
-		if (hdsp_is_9652(hdsp)) return -EINVAL;
+		if (hdsp->io_type == H9652) return -EINVAL;
 		/* SNDRV_HDSP_IOCTL_GET_VERSION must have been called */
 		if (hdsp->io_type == Undefined) return -EINVAL;
 
@@ -3904,7 +3976,19 @@ static int __devinit snd_hdsp_create_pcm
 	return 0;
 }
 
-static inline int snd_hdsp_initialize_input_enable (hdsp_t *hdsp)
+static inline void snd_hdsp_9652_enable_mixer (hdsp_t *hdsp)
+{
+        hdsp->control2_register |= HDSP_9652_ENABLE_MIXER;
+	hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
+}
+
+static inline void snd_hdsp_9652_disable_mixer (hdsp_t *hdsp)
+{
+        hdsp->control2_register &= ~HDSP_9652_ENABLE_MIXER;
+	hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
+}
+
+static inline int snd_hdsp_enable_io (hdsp_t *hdsp)
 {
 	int i;
 	
@@ -3922,14 +4006,27 @@ static inline int snd_hdsp_initialize_in
 
 static inline void snd_hdsp_initialize_channels(hdsp_t *hdsp)
 {
-	if (hdsp->io_type == Digiface) {
+	switch (hdsp->io_type) {
+	case Digiface:
 		hdsp->card_name = "RME Hammerfall DSP + Digiface";
 		hdsp->ss_channels = DIGIFACE_SS_CHANNELS;
 		hdsp->ds_channels = DIGIFACE_DS_CHANNELS;
-	} else {
+		break;
+
+	case H9652:
+		hdsp->card_name = "RME Hammerfall HDSP 9652";
+		hdsp->ss_channels = H9652_SS_CHANNELS;
+		hdsp->ds_channels = H9652_DS_CHANNELS;
+		break;
+
+	case Multiface:
 		hdsp->card_name = "RME Hammerfall DSP + Multiface";
 		hdsp->ss_channels = MULTIFACE_SS_CHANNELS;
 		hdsp->ds_channels = MULTIFACE_DS_CHANNELS;
+
+	default:
+ 		/* should never get here */
+		break;
 	}
 }
 
@@ -3937,10 +4034,6 @@ static inline void snd_hdsp_initialize_m
 {
 	snd_hdsp_flush_midi_input (hdsp, 0);
 	snd_hdsp_flush_midi_input (hdsp, 1);
-
-#ifdef SNDRV_BIG_ENDIAN
-	hdsp_write(hdsp, HDSP_jtagReg, HDSP_BIGENDIAN_MODE);
-#endif
 }
 
 static int __devinit snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp)
@@ -4001,6 +4094,7 @@ static int __devinit snd_hdsp_create(snd
 	struct pci_dev *pci = hdsp->pci;
 	int err;
 	int i;
+	int is_9652 = 0;
 
 	hdsp->irq = -1;
 	hdsp->state = 0;
@@ -4027,23 +4121,27 @@ static int __devinit snd_hdsp_create(snd
 	pci_read_config_word(hdsp->pci, PCI_CLASS_REVISION, &hdsp->firmware_rev);
 	strcpy(card->driver, "H-DSP");
 	strcpy(card->mixername, "Xilinx FPGA");
-	
+
 	switch (hdsp->firmware_rev & 0xff) {
 	case 0xa:
 	case 0xb:
 		hdsp->card_name = "RME Hammerfall DSP";
 		break;
+
 	case 0x64:
 	case 0x65:
 	case 0x68:
 		hdsp->card_name = "RME HDSP 9652";
+		is_9652 = 1;
 		break;
+
 	default:
 		return -ENODEV;
 	}
 
-	if ((err = pci_enable_device(pci)) < 0)
+	if ((err = pci_enable_device(pci)) < 0) {
 		return err;
+	}
 
 	pci_set_master(hdsp->pci);
 
@@ -4071,70 +4169,53 @@ static int __devinit snd_hdsp_create(snd
 		return err;
 	}
 	
-	if (hdsp_is_9652(hdsp)) {
-		
-		if ((err = snd_hdsp_initialize_input_enable(hdsp)) != 0) {
+	if (!is_9652 && hdsp_check_for_iobox (hdsp)) {
+		/* no iobox connected, we defer initialization */
+		snd_printk("card initialization pending : waiting for firmware\n");
+		if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
 			return err;
 		}
-
-		hdsp->io_type = Digiface;		
-	
-		hdsp->ss_channels = DIGIFACE_SS_CHANNELS;
-		hdsp->ds_channels = DIGIFACE_DS_CHANNELS;
+		return 0;
+	}
 	
-		snd_hdsp_initialize_midi_flush(hdsp);
+	if ((err = snd_hdsp_enable_io(hdsp)) != 0) {
+		return err;
+	}
 	
+	if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
+		snd_printk("card initialization pending : waiting for firmware\n");
 		if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
 			return err;
 		}
-
-	} else {
+		return 0;
+	} 
 	
-		if (hdsp_check_for_iobox (hdsp)) {
-			/* no iobox connected, we defer initialization */
-			snd_printk("card initialization pending : waiting for firmware\n");
-			if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
-				return err;
-			}
-			return 0;
-		}
+	snd_printk("Firmware already loaded, initializing card.\n");
+	
+	if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) {
+		hdsp->io_type = Multiface;
+	} else {
+		hdsp->io_type = Digiface;
+	}
 
-		if ((err = snd_hdsp_initialize_input_enable(hdsp)) != 0) {
-			return err;
-		}
-		
-		if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
-			snd_printk("card initialization pending : waiting for firmware\n");
-			if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
-				return err;
-			}
-		return 0;
-		} 
-		
-		snd_printk("Firmware already loaded, initializing card.\n");
+	if (is_9652) {
+	        hdsp->io_type = H9652;
+	        snd_hdsp_9652_enable_mixer (hdsp);
+	}
 
-		if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) {
-			hdsp->io_type = Multiface;
-		} else {
-			hdsp->io_type = Digiface;
-		}
-		
-		if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
-			return err;
-		}
-		
-		snd_hdsp_initialize_channels(hdsp);
-		
-		snd_hdsp_initialize_midi_flush(hdsp);
-		
+	if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) {
+		return err;
 	}
 	
+	snd_hdsp_initialize_channels(hdsp);
+	snd_hdsp_initialize_midi_flush(hdsp);
+
 	hdsp->state |= HDSP_FirmwareLoaded;	
-	
+
 	if ((err = snd_hdsp_create_alsa_devices(card, hdsp)) < 0) {
 		return err;
 	}
-	
+
 	return 0;	
 }
 
@@ -4201,7 +4282,7 @@ static int __devinit snd_hdsp_probe(stru
 	strcpy(card->shortname, "Hammerfall DSP");
 	sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name, 
 		hdsp->port, hdsp->irq);
-	
+
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
 		return err;
diff -puN sound/pci/rme9652/Makefile~alsa-bk-2003-07-28 sound/pci/rme9652/Makefile
--- 25/sound/pci/rme9652/Makefile~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/rme9652/Makefile	Tue Jul 29 12:11:31 2003
@@ -3,10 +3,9 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-snd-hammerfall-mem-objs := hammerfall_mem.o
 snd-rme9652-objs := rme9652.o
 snd-hdsp-objs := hdsp.o
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_RME9652) += snd-rme9652.o snd-hammerfall-mem.o
-obj-$(CONFIG_SND_HDSP) += snd-hdsp.o snd-hammerfall-mem.o
+obj-$(CONFIG_SND_RME9652) += snd-rme9652.o
+obj-$(CONFIG_SND_HDSP) += snd-hdsp.o
diff -puN sound/pci/rme9652/rme9652.c~alsa-bk-2003-07-28 sound/pci/rme9652/rme9652.c
--- 25/sound/pci/rme9652/rme9652.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/rme9652/rme9652.c	Tue Jul 29 12:11:31 2003
@@ -309,10 +309,42 @@ static char channel_map_9636_ds[26] = {
 #define RME9652_PREALLOCATE_MEMORY	/* via module snd-hammerfall-mem */
 
 #ifdef RME9652_PREALLOCATE_MEMORY
-extern void *snd_hammerfall_get_buffer(struct pci_dev *, dma_addr_t *dmaaddr);
-extern void snd_hammerfall_free_buffer(struct pci_dev *, void *ptr);
+static void *snd_hammerfall_get_buffer(struct pci_dev *pci, size_t size, dma_addr_t *addrp, int capture)
+{
+	struct snd_dma_device pdev;
+	struct snd_dma_buffer dmbuf;
+
+	snd_dma_device_pci(&pdev, pci, capture);
+	dmbuf.bytes = 0;
+	if (! snd_dma_get_reserved(&pdev, &dmbuf)) {
+		if (snd_dma_alloc_pages(&pdev, size, &dmbuf) < 0)
+			return NULL;
+		snd_dma_set_reserved(&pdev, &dmbuf);
+	}
+	*addrp = dmbuf.addr;
+	return dmbuf.area;
+}
+
+static void snd_hammerfall_free_buffer(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t addr, int capture)
+{
+	struct snd_dma_device dev;
+	snd_dma_device_pci(&dev, pci, capture);
+	snd_dma_free_reserved(&dev);
+}
+
+#else
+static void *snd_hammerfall_get_buffer(struct pci_dev *pci, size_t size, dma_addr_t *addrp, int capture)
+{
+	return snd_malloc_pci_pages(pci, size, addrp);
+}
+
+static void snd_hammerfall_free_buffer(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t addr, int capture)
+{
+	snd_free_pci_pages(pci, size, ptr, addr);
+}
 #endif
 
+
 static struct pci_device_id snd_rme9652_ids[] __devinitdata = {
 	{
 		.vendor	   = 0x10ee,
@@ -1810,25 +1842,15 @@ static void __devinit snd_rme9652_proc_i
 static void snd_rme9652_free_buffers(rme9652_t *rme9652)
 {
 	if (rme9652->capture_buffer_unaligned) {
-#ifndef RME9652_PREALLOCATE_MEMORY
-		snd_free_pci_pages(rme9652->pci,
-				   RME9652_DMA_AREA_BYTES,
-				   rme9652->capture_buffer_unaligned,
-				   rme9652->capture_buffer_addr);
-#else
-		snd_hammerfall_free_buffer(rme9652->pci, rme9652->capture_buffer_unaligned);
-#endif
+		snd_hammerfall_free_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES,
+					   rme9652->capture_buffer_unaligned,
+					   rme9652->capture_buffer_addr, 1);
 	}
 
 	if (rme9652->playback_buffer_unaligned) {
-#ifndef RME9652_PREALLOCATE_MEMORY
-		snd_free_pci_pages(rme9652->pci,
-				   RME9652_DMA_AREA_BYTES,
-				   rme9652->playback_buffer_unaligned,
-				   rme9652->playback_buffer_addr);
-#else
-		snd_hammerfall_free_buffer(rme9652->pci, rme9652->playback_buffer_unaligned);
-#endif
+		snd_hammerfall_free_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES,
+					   rme9652->playback_buffer_unaligned,
+					   rme9652->playback_buffer_addr, 0);
 	}
 }
 
@@ -1855,28 +1877,15 @@ static int __devinit snd_rme9652_initial
 	dma_addr_t pb_addr, cb_addr;
 	unsigned long pb_bus, cb_bus;
 
-#ifndef RME9652_PREALLOCATE_MEMORY
-	cb = snd_malloc_pci_pages(rme9652->pci, RME9652_DMA_AREA_BYTES, &cb_addr);
-	pb = snd_malloc_pci_pages(rme9652->pci, RME9652_DMA_AREA_BYTES, &pb_addr);
-#else
-	cb = snd_hammerfall_get_buffer(rme9652->pci, &cb_addr);
-	pb = snd_hammerfall_get_buffer(rme9652->pci, &pb_addr);
-#endif
+	cb = snd_hammerfall_get_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES, &cb_addr, 1);
+	pb = snd_hammerfall_get_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES, &pb_addr, 0);
 
 	if (cb == 0 || pb == 0) {
 		if (cb) {
-#ifdef RME9652_PREALLOCATE_MEMORY
-			snd_hammerfall_free_buffer(rme9652->pci, cb);
-#else
-			snd_free_pci_pages(rme9652->pci, RME9652_DMA_AREA_BYTES, cb, cb_addr);
-#endif
+			snd_hammerfall_free_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES, cb, cb_addr, 1);
 		}
 		if (pb) {
-#ifdef RME9652_PREALLOCATE_MEMORY
-			snd_hammerfall_free_buffer(rme9652->pci, pb);
-#else
-			snd_free_pci_pages(rme9652->pci, RME9652_DMA_AREA_BYTES, pb, pb_addr);
-#endif
+			snd_hammerfall_free_buffer(rme9652->pci, RME9652_DMA_AREA_BYTES, pb, pb_addr, 0);
 		}
 
 		printk(KERN_ERR "%s: no buffers available\n", rme9652->card_name);
diff -puN sound/pci/rme96.c~alsa-bk-2003-07-28 sound/pci/rme96.c
--- 25/sound/pci/rme96.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/rme96.c	Tue Jul 29 12:11:31 2003
@@ -806,10 +806,12 @@ snd_rme96_setclockmode(rme96_t *rme96,
 {
 	switch (mode) {
 	case RME96_CLOCKMODE_SLAVE:
+	        /* AutoSync */ 
 		rme96->wcreg &= ~RME96_WCR_MASTER;
 		rme96->areg &= ~RME96_AR_WSEL;
 		break;
 	case RME96_CLOCKMODE_MASTER:
+	        /* Internal */
 		rme96->wcreg |= RME96_WCR_MASTER;
 		rme96->areg &= ~RME96_AR_WSEL;
 		break;
@@ -1318,7 +1320,7 @@ snd_rme96_capture_adat_open(snd_pcm_subs
 	snd_pcm_set_sync(substream);
 
 	runtime->hw = snd_rme96_capture_adat_info;
-        if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG) {
+        if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) {
                 /* makes no sense to use analog input. Note that analog
                    expension cards AEB4/8-I are RME96_INPUT_INTERNAL */
                 return -EIO;
@@ -1862,15 +1864,15 @@ snd_rme96_proc_read(snd_info_entry_t *en
 		snd_iprintf(buffer, "  sample format: 16 bit\n");
 	}
 	if (rme96->areg & RME96_AR_WSEL) {
-		snd_iprintf(buffer, "  clock mode: word clock\n");
+		snd_iprintf(buffer, "  sample clock source: word clock\n");
 	} else if (rme96->wcreg & RME96_WCR_MASTER) {
-		snd_iprintf(buffer, "  clock mode: master\n");
+		snd_iprintf(buffer, "  sample clock source: internal\n");
 	} else if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) {
-		snd_iprintf(buffer, "  clock mode: slave (master anyway due to analog input setting)\n");
+		snd_iprintf(buffer, "  sample clock source: autosync (internal anyway due to analog input setting)\n");
 	} else if (snd_rme96_capture_getrate(rme96, &n) < 0) {
-		snd_iprintf(buffer, "  clock mode: slave (master anyway due to no valid signal)\n");
+		snd_iprintf(buffer, "  sample clock source: autosync (internal anyway due to no valid signal)\n");
 	} else {
-		snd_iprintf(buffer, "  clock mode: slave\n");
+		snd_iprintf(buffer, "  sample clock source: autosync\n");
 	}
 	if (rme96->wcreg & RME96_WCR_PRO) {
 		snd_iprintf(buffer, "  format: AES/EBU (professional)\n");
@@ -2095,7 +2097,7 @@ snd_rme96_put_inputtype_control(snd_kcon
 static int
 snd_rme96_info_clockmode_control(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
-	static char *texts[3] = { "Slave", "Master", "Wordclock" };
+	static char *texts[3] = { "AutoSync", "Internal", "Word" };
 	
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
@@ -2418,7 +2420,7 @@ static snd_kcontrol_new_t snd_rme96_cont
 },
 {
         .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-	.name =         "Clock Mode",
+	.name =         "Sample Clock Source",
 	.info =         snd_rme96_info_clockmode_control, 
 	.get =          snd_rme96_get_clockmode_control,
 	.put =          snd_rme96_put_clockmode_control
diff -puN sound/pci/sonicvibes.c~alsa-bk-2003-07-28 sound/pci/sonicvibes.c
--- 25/sound/pci/sonicvibes.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/sonicvibes.c	Tue Jul 29 12:11:31 2003
@@ -254,7 +254,7 @@ struct _snd_sonicvibes {
 	snd_kcontrol_t *master_mute;
 	snd_kcontrol_t *master_volume;
 
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	struct gameport gameport;
 #endif
 };
@@ -1189,7 +1189,7 @@ SONICVIBES_SINGLE("Joystick Speed", 0, S
 
 static int snd_sonicvibes_free(sonicvibes_t *sonic)
 {
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	if (sonic->gameport.io)
 		gameport_unregister_port(&sonic->gameport);
 #endif
@@ -1493,7 +1493,7 @@ static int __devinit snd_sonic_probe(str
 		snd_card_free(card);
 		return err;
 	}
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	sonic->gameport.io = sonic->game_port;
 	gameport_register_port(&sonic->gameport);
 #endif
diff -puN sound/pci/trident/trident.c~alsa-bk-2003-07-28 sound/pci/trident/trident.c
--- 25/sound/pci/trident/trident.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/trident/trident.c	Tue Jul 29 12:11:31 2003
@@ -132,7 +132,7 @@ static int __devinit snd_trident_probe(s
 		return err;
 	}
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if ((err = snd_trident_attach_synthesizer(trident)) < 0) {
 		snd_card_free(card);
 		return err;
@@ -182,7 +182,6 @@ static void __devexit snd_trident_remove
 }
 
 #ifdef CONFIG_PM
-#ifndef PCI_OLD_SUSPEND
 static int snd_card_trident_suspend(struct pci_dev *pci, u32 state)
 {
 	trident_t *chip = snd_magic_cast(trident_t, pci_get_drvdata(pci), return -ENXIO);
@@ -195,18 +194,6 @@ static int snd_card_trident_resume(struc
 	snd_trident_resume(chip);
 	return 0;
 }
-#else
-static void snd_card_trident_suspend(struct pci_dev *pci)
-{
-	trident_t *chip = snd_magic_cast(trident_t, pci_get_drvdata(pci), return);
-	snd_trident_suspend(chip);
-}
-static void snd_card_trident_resume(struct pci_dev *pci)
-{
-	trident_t *chip = snd_magic_cast(trident_t, pci_get_drvdata(pci), return);
-	snd_trident_resume(chip);
-}
-#endif
 #endif
 
 static struct pci_driver driver = {
diff -puN sound/pci/trident/trident_main.c~alsa-bk-2003-07-28 sound/pci/trident/trident_main.c
--- 25/sound/pci/trident/trident_main.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/trident/trident_main.c	Tue Jul 29 12:11:31 2003
@@ -3077,7 +3077,8 @@ static int __devinit snd_trident_mixer(t
 /*
  * gameport interface
  */
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 
 typedef struct snd_trident_gameport {
 	struct gameport info;
@@ -3173,12 +3174,6 @@ void __devinit snd_trident_gameport(trid
  */
 inline static void do_delay(trident_t *chip)
 {
-#ifdef CONFIG_PM
-	if (chip->in_suspend) {
-		mdelay((1000 + HZ - 1) / HZ);
-		return;
-	}
-#endif
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(1);
 }
@@ -3273,7 +3268,7 @@ static void snd_trident_proc_read(snd_in
 			snd_iprintf(buffer, "Memory Free    : %d\n", snd_util_mem_avail(trident->tlb.memhdr));
 		}
 	}
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	snd_iprintf(buffer,"\nWavetable Synth\n");
 	snd_iprintf(buffer, "Memory Maximum : %d\n", trident->synth.max_size);
 	snd_iprintf(buffer, "Memory Used    : %d\n", trident->synth.current_size);
@@ -3636,7 +3631,7 @@ int __devinit snd_trident_create(snd_car
 
 int snd_trident_free(trident_t *trident)
 {
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	if (trident->gameport) {
 		gameport_unregister_port(&trident->gameport->info);
 		kfree(trident->gameport);
@@ -3796,7 +3791,7 @@ static irqreturn_t snd_trident_interrupt
   ---------------------------------------------------------------------------*/
 int snd_trident_attach_synthesizer(trident_t *trident)
 {	
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if (snd_seq_device_new(trident->card, 1, SNDRV_SEQ_DEV_ID_TRIDENT,
 			       sizeof(trident_t*), &trident->seq_dev) >= 0) {
 		strcpy(trident->seq_dev->name, "4DWave");
@@ -3808,7 +3803,7 @@ int snd_trident_attach_synthesizer(tride
 
 int snd_trident_detach_synthesizer(trident_t *trident)
 {
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if (trident->seq_dev) {
 		snd_device_free(trident->card, trident->seq_dev);
 		trident->seq_dev = NULL;
diff -puN sound/pci/via82xx.c~alsa-bk-2003-07-28 sound/pci/via82xx.c
--- 25/sound/pci/via82xx.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/via82xx.c	Tue Jul 29 12:11:32 2003
@@ -886,7 +886,7 @@ static int snd_via8233_playback_prepare(
 		snd_ac97_set_rate(chip->ac97, AC97_PCM_LFE_DAC_RATE, runtime->rate);
 		snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
 	}
-	if (chip->chip_type == TYPE_VIA8233A)
+	if (chip->revision == VIA_REV_8233A)
 		rbits = 0;
 	else
 		rbits = (0xfffff / 48000) * runtime->rate + ((0xfffff % 48000) * runtime->rate) / 48000;
@@ -928,7 +928,7 @@ static int snd_via8233_multi_prepare(snd
 	fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
 	fmt |= runtime->channels << 4;
 	outb(fmt, VIADEV_REG(viadev, OFS_MULTPLAY_FORMAT));
-	if (chip->chip_type == TYPE_VIA8233A)
+	if (chip->revision == VIA_REV_8233A)
 		slots = 0;
 	else {
 		/* set sample number to slot 3, 4, 7, 8, 6, 9 (for VIA8233/C,8235) */
@@ -1108,7 +1108,7 @@ static int snd_via8233_multi_open(snd_pc
 	if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0)
 		return err;
 	substream->runtime->hw.channels_max = 6;
-	if (chip->chip_type == TYPE_VIA8233A)
+	if (chip->revision == VIA_REV_8233A)
 		snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
 	return 0;
 }
diff -puN sound/pci/ymfpci/ymfpci.c~alsa-bk-2003-07-28 sound/pci/ymfpci/ymfpci.c
--- 25/sound/pci/ymfpci/ymfpci.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ymfpci/ymfpci.c	Tue Jul 29 12:11:31 2003
@@ -229,9 +229,11 @@ static int __devinit snd_card_ymfpci_pro
 			return err;
 		}
 	}
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 	if ((err = snd_ymfpci_joystick(chip)) < 0) {
 		printk(KERN_WARNING "ymfpci: cannot initialize joystick, skipping...\n");
 	}
+#endif
 	strcpy(card->driver, str);
 	sprintf(card->shortname, "Yamaha DS-XG PCI (%s)", str);
 	sprintf(card->longname, "%s at 0x%lx, irq %i",
@@ -249,7 +251,6 @@ static int __devinit snd_card_ymfpci_pro
 }
 
 #ifdef CONFIG_PM
-#ifndef PCI_OLD_SUSPEND
 static int snd_card_ymfpci_suspend(struct pci_dev *pci, u32 state)
 {
 	ymfpci_t *chip = snd_magic_cast(ymfpci_t, pci_get_drvdata(pci), return -ENXIO);
@@ -262,18 +263,6 @@ static int snd_card_ymfpci_resume(struct
 	snd_ymfpci_resume(chip);
 	return 0;
 }
-#else
-static void snd_card_ymfpci_suspend(struct pci_dev *pci)
-{
-	ymfpci_t *chip = snd_magic_cast(ymfpci_t, pci_get_drvdata(pci), return);
-	snd_ymfpci_suspend(chip);
-}
-static void snd_card_ymfpci_resume(struct pci_dev *pci)
-{
-	ymfpci_t *chip = snd_magic_cast(ymfpci_t, pci_get_drvdata(pci), return);
-	snd_ymfpci_resume(chip);
-}
-#endif
 #endif
 
 static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci)
diff -puN sound/pci/ymfpci/ymfpci_main.c~alsa-bk-2003-07-28 sound/pci/ymfpci/ymfpci_main.c
--- 25/sound/pci/ymfpci/ymfpci_main.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pci/ymfpci/ymfpci_main.c	Tue Jul 29 12:11:31 2003
@@ -84,7 +84,7 @@ static inline void snd_ymfpci_writel(ymf
 	writel(val, chip->reg_area_virt + offset);
 }
 
-static int snd_ymfpci_codec_ready(ymfpci_t *chip, int secondary, int sched)
+static int snd_ymfpci_codec_ready(ymfpci_t *chip, int secondary)
 {
 	signed long end_time;
 	u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
@@ -93,10 +93,8 @@ static int snd_ymfpci_codec_ready(ymfpci
 	do {
 		if ((snd_ymfpci_readw(chip, reg) & 0x8000) == 0)
 			return 0;
-		if (sched) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(1);
-		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
 	} while (end_time - (signed long)jiffies >= 0);
 	snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg));
 	return -EBUSY;
@@ -107,7 +105,7 @@ static void snd_ymfpci_codec_write(ac97_
 	ymfpci_t *chip = snd_magic_cast(ymfpci_t, ac97->private_data, return);
 	u32 cmd;
 	
-	snd_ymfpci_codec_ready(chip, 0, 0);
+	snd_ymfpci_codec_ready(chip, 0);
 	cmd = ((YDSXG_AC97WRITECMD | reg) << 16) | val;
 	snd_ymfpci_writel(chip, YDSXGR_AC97CMDDATA, cmd);
 }
@@ -116,10 +114,10 @@ static u16 snd_ymfpci_codec_read(ac97_t 
 {
 	ymfpci_t *chip = snd_magic_cast(ymfpci_t, ac97->private_data, return -ENXIO);
 
-	if (snd_ymfpci_codec_ready(chip, 0, 0))
+	if (snd_ymfpci_codec_ready(chip, 0))
 		return ~0;
 	snd_ymfpci_writew(chip, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
-	if (snd_ymfpci_codec_ready(chip, 0, 0))
+	if (snd_ymfpci_codec_ready(chip, 0))
 		return ~0;
 	if (chip->device_id == PCI_DEVICE_ID_YAMAHA_744 && chip->rev < 2) {
 		int i;
@@ -1708,24 +1706,65 @@ int __devinit snd_ymfpci_mixer(ymfpci_t 
  * joystick support
  */
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 static int ymfpci_joystick_ports[4] = {
 	0x201, 0x202, 0x204, 0x205
 };
 
+static int snd_ymfpci_get_joystick_port(ymfpci_t *chip, int index)
+{
+	if (index < 4)
+		return ymfpci_joystick_ports[index];
+	else
+		return pci_resource_start(chip->pci, 2);
+}
+
 static void setup_joystick_base(ymfpci_t *chip)
 {
-	if (chip->pci->device >= 0x0010) /* YMF 744/754 */
+	if (chip->device_id >= 0x0010) /* YMF 744/754 */
 		pci_write_config_word(chip->pci, PCIR_DSXG_JOYBASE,
-				      ymfpci_joystick_ports[chip->joystick_port]);
+				      snd_ymfpci_get_joystick_port(chip, chip->joystick_port));
 	else {
 		u16 legacy_ctrl2;
 		pci_read_config_word(chip->pci, PCIR_DSXG_ELEGACY, &legacy_ctrl2);
-		legacy_ctrl2 &= ~(3 << 6);
+		legacy_ctrl2 &= ~YMFPCI_LEGACY2_JSIO;
 		legacy_ctrl2 |= chip->joystick_port << 6;
 		pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, legacy_ctrl2);
 	}
 }
 
+static int snd_ymfpci_enable_joystick(ymfpci_t *chip)
+{
+	u16 val;
+
+	chip->gameport.io = snd_ymfpci_get_joystick_port(chip, chip->joystick_port);
+	chip->joystick_res = request_region(chip->gameport.io, 1, "YMFPCI gameport");
+	if (!chip->joystick_res) {
+		snd_printk(KERN_WARNING "gameport port %#x in use\n", chip->gameport.io);
+		return 0;
+	}
+	setup_joystick_base(chip);
+	pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, &val);
+	val |= YMFPCI_LEGACY_JPEN;
+	pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, val);
+	gameport_register_port(&chip->gameport);
+	return 1;
+}
+
+static int snd_ymfpci_disable_joystick(ymfpci_t *chip)
+{
+	u16 val;
+
+	gameport_unregister_port(&chip->gameport);
+	pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, &val);
+	val &= ~YMFPCI_LEGACY_JPEN;
+	pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, val);
+	release_resource(chip->joystick_res);
+	kfree_nocheck(chip->joystick_res);
+	chip->joystick_res = NULL;
+	return 1;
+}
+
 static int snd_ymfpci_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
@@ -1741,36 +1780,41 @@ static int snd_ymfpci_joystick_get(snd_k
 	u16 val;
 
 	pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, &val);
-	ucontrol->value.integer.value[0] = (val & 0x04) ? 1 : 0;
+	ucontrol->value.integer.value[0] = (val & YMFPCI_LEGACY_JPEN) ? 1 : 0;
 	return 0;
 }
 
 static int snd_ymfpci_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
-	u16 val, oval;
+	int enabled, change;
 
-	pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, &oval);
-	val = oval & ~0x04;
-	if (ucontrol->value.integer.value[0])
-		val |= 0x04;
-	if (val != oval) {
-		setup_joystick_base(chip);
-		pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, val);
-		return 1;
+	down(&chip->joystick_mutex);
+	enabled = chip->joystick_res != NULL;
+	change = enabled != !! ucontrol->value.integer.value[0];
+	if (change) {
+		if (!enabled)
+			change = snd_ymfpci_enable_joystick(chip);
+		else
+			change = snd_ymfpci_disable_joystick(chip);
 	}
-	return 0;
+	up(&chip->joystick_mutex);
+	return change;
 }
 
 static int snd_ymfpci_joystick_addr_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
-        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-        uinfo->count = 1;
-        uinfo->value.enumerated.items = 4;
-	if (uinfo->value.enumerated.item >= 4)
-		uinfo->value.enumerated.item = 3;
-	sprintf(uinfo->value.enumerated.name, "port 0x%x", ymfpci_joystick_ports[uinfo->value.enumerated.item]);
-        return 0;
+	ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
+	int ports = chip->device_id >= 0x0010 ? 5 : 4;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = ports;
+	if (uinfo->value.enumerated.item >= ports)
+		uinfo->value.enumerated.item = ports - 1;
+	sprintf(uinfo->value.enumerated.name, "port 0x%x",
+		snd_ymfpci_get_joystick_port(chip, uinfo->value.enumerated.item));
+	return 0;
 }
 
 static int snd_ymfpci_joystick_addr_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
@@ -1783,13 +1827,20 @@ static int snd_ymfpci_joystick_addr_get(
 static int snd_ymfpci_joystick_addr_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
-	if (ucontrol->value.enumerated.item[0] != chip->joystick_port) {
-		snd_assert(ucontrol->value.enumerated.item[0] >= 0 && ucontrol->value.enumerated.item[0] < 4, return -EINVAL);
+	int change, enabled;
+
+	down(&chip->joystick_mutex);
+	change = ucontrol->value.enumerated.item[0] != chip->joystick_port;
+	if (change) {
+		enabled = chip->joystick_res != NULL;
+		if (enabled)
+			snd_ymfpci_disable_joystick(chip);
 		chip->joystick_port = ucontrol->value.enumerated.item[0];
-		setup_joystick_base(chip);
-		return 1;
+		if (enabled)
+			snd_ymfpci_enable_joystick(chip);
 	}
-	return 0;
+	up(&chip->joystick_mutex);
+	return change;
 }
 
 static snd_kcontrol_new_t snd_ymfpci_control_joystick __devinitdata = {
@@ -1819,6 +1870,7 @@ int __devinit snd_ymfpci_joystick(ymfpci
 		return err;
 	return 0;
 }
+#endif /* CONFIG_GAMEPORT */
 
 
 /*
@@ -2067,6 +2119,10 @@ static int snd_ymfpci_free(ymfpci_t *chi
 		release_resource(chip->fm_res);
 		kfree_nocheck(chip->fm_res);
 	}
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+	if (chip->joystick_res)
+		snd_ymfpci_disable_joystick(chip);
+#endif
 	if (chip->reg_area_virt)
 		iounmap((void *)chip->reg_area_virt);
 	if (chip->work_ptr)
@@ -2151,7 +2207,7 @@ void snd_ymfpci_resume(ymfpci_t *chip)
 	pci_enable_device(chip->pci);
 	pci_set_master(chip->pci);
 	snd_ymfpci_aclink_reset(chip->pci);
-	snd_ymfpci_codec_ready(chip, 0, 0);
+	snd_ymfpci_codec_ready(chip, 0);
 	snd_ymfpci_download_image(chip);
 	udelay(100);
 
@@ -2216,6 +2272,9 @@ int __devinit snd_ymfpci_create(snd_card
 	spin_lock_init(&chip->voice_lock);
 	init_waitqueue_head(&chip->interrupt_sleep);
 	atomic_set(&chip->interrupt_sleep_count, 0);
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+	init_MUTEX(&chip->joystick_mutex);
+#endif
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
@@ -2238,7 +2297,7 @@ int __devinit snd_ymfpci_create(snd_card
 	chip->irq = pci->irq;
 
 	snd_ymfpci_aclink_reset(pci);
-	if (snd_ymfpci_codec_ready(chip, 0, 1) < 0) {
+	if (snd_ymfpci_codec_ready(chip, 0) < 0) {
 		snd_ymfpci_free(chip);
 		return -EIO;
 	}
diff -puN sound/pcmcia/vx/vxpocket.c~alsa-bk-2003-07-28 sound/pcmcia/vx/vxpocket.c
--- 25/sound/pcmcia/vx/vxpocket.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/pcmcia/vx/vxpocket.c	Tue Jul 29 12:11:31 2003
@@ -31,6 +31,7 @@
  */
 
 #include <sound/driver.h>
+#include <linux/init.h>
 #include <sound/core.h>
 #include <pcmcia/version.h>
 #include "vxpocket.h"
diff -puN sound/ppc/awacs.c~alsa-bk-2003-07-28 sound/ppc/awacs.c
--- 25/sound/ppc/awacs.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/ppc/awacs.c	Tue Jul 29 12:11:31 2003
@@ -92,18 +92,9 @@ snd_pmac_awacs_write_noreg(pmac_t *chip,
 	snd_pmac_awacs_write(chip, val | (reg << 12));
 }
 
-static void do_mdelay(int msec, int can_schedule)
-{
-	if (can_schedule) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((msec * HZ + 999) / 1000);
-	} else
-		mdelay(msec);
-}
-
 #ifdef CONFIG_PMAC_PBOOK
 /* Recalibrate chip */
-static void screamer_recalibrate(pmac_t *chip, int can_schedule)
+static void screamer_recalibrate(pmac_t *chip)
 {
 	if (chip->model != PMAC_SCREAMER)
 		return;
@@ -114,7 +105,7 @@ static void screamer_recalibrate(pmac_t 
 	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
 	if (chip->manufacturer == 0x1)
 		/* delay for broken crystal part */
-		do_mdelay(750, can_schedule);
+		big_mdelay(750);
 	snd_pmac_awacs_write_noreg(chip, 1,
 				   chip->awacs_reg[1] | MASK_RECALIBRATE | MASK_CMUTE | MASK_AMUTE);
 	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
@@ -122,7 +113,7 @@ static void screamer_recalibrate(pmac_t 
 }
 
 #else
-#define screamer_recalibrate(chip, can_schedule) /* NOP */
+#define screamer_recalibrate(chip) /* NOP */
 #endif
 
 
@@ -631,7 +622,7 @@ static int build_mixers(pmac_t *chip, in
 /*
  * restore all registers
  */
-static void awacs_restore_all_regs(pmac_t *chip, int can_schedule)
+static void awacs_restore_all_regs(pmac_t *chip)
 {
 	snd_pmac_awacs_write_noreg(chip, 0, chip->awacs_reg[0]);
 	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
@@ -655,19 +646,19 @@ static void snd_pmac_awacs_resume(pmac_t
 {
 	if (machine_is_compatible("PowerBook3,1")
 	    || machine_is_compatible("PowerBook3,2")) {
-		do_mdelay(100, 0);
+		big_mdelay(100);
 		snd_pmac_awacs_write_reg(chip, 1,
 			chip->awacs_reg[1] & ~MASK_PAROUT);
-		do_mdelay(300, 0);
+		big_mdelay(300);
 	}
 
-	awacs_restore_all_regs(chip, 0);
+	awacs_restore_all_regs(chip);
 	if (chip->model == PMAC_SCREAMER) {
 		/* reset power bits in reg 6 */
 		mdelay(5);
 		snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);
 	}
-	screamer_recalibrate(chip, 0);
+	screamer_recalibrate(chip);
 #ifdef PMAC_AMP_AVAIL
 	if (chip->mixer_data) {
 		awacs_amp_t *amp = chip->mixer_data;
@@ -775,9 +766,9 @@ snd_pmac_awacs_init(pmac_t *chip)
 		chip->awacs_reg[7] = 0;
 	}
 
-	awacs_restore_all_regs(chip, 1);
+	awacs_restore_all_regs(chip);
 	chip->manufacturer = (in_le32(&chip->awacs->codec_stat) >> 8) & 0xf;
-	screamer_recalibrate(chip, 1);
+	screamer_recalibrate(chip);
 
 	chip->revision = (in_le32(&chip->awacs->codec_stat) >> 12) & 0xf;
 #ifdef PMAC_AMP_AVAIL
diff -puN sound/ppc/burgundy.c~alsa-bk-2003-07-28 sound/ppc/burgundy.c
--- 25/sound/ppc/burgundy.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/ppc/burgundy.c	Tue Jul 29 12:11:31 2003
@@ -23,6 +23,7 @@
 #include <asm/io.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <sound/core.h>
 #include "pmac.h"
 #include "burgundy.h"
@@ -34,17 +35,27 @@
 inline static void
 snd_pmac_burgundy_busy_wait(pmac_t *chip)
 {
-	while (in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD)
-		;
+	int timeout = 50;
+	while ((in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) && timeout--)
+		udelay(1);
+	if (! timeout)
+		printk(KERN_DEBUG "burgundy_busy_wait: timeout\n");
 }
 
 inline static void
 snd_pmac_burgundy_extend_wait(pmac_t *chip)
 {
-	while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND))
-		;
-	while (in_le32(&chip->awacs->codec_stat) & MASK_EXTEND)
-		;
+	int timeout;
+	timeout = 50;
+	while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
+		udelay(1);
+	if (! timeout)
+		printk(KERN_DEBUG "burgundy_extend_wait: timeout #1\n");
+	timeout = 50;
+	while ((in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
+		udelay(1);
+	if (! timeout)
+		printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n");
 }
 
 static void
@@ -66,7 +77,6 @@ snd_pmac_burgundy_rcw(pmac_t *chip, unsi
 	unsigned val = 0;
 	unsigned long flags;
 
-	/* should have timeouts here */
 	spin_lock_irqsave(&chip->reg_lock, flags);
 
 	out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
@@ -107,7 +117,6 @@ snd_pmac_burgundy_rcb(pmac_t *chip, unsi
 	unsigned val = 0;
 	unsigned long flags;
 
-	/* should have timeouts here */
 	spin_lock_irqsave(&chip->reg_lock, flags);
 
 	out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
diff -puN sound/ppc/pmac.c~alsa-bk-2003-07-28 sound/ppc/pmac.c
--- 25/sound/ppc/pmac.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/ppc/pmac.c	Tue Jul 29 12:11:31 2003
@@ -736,7 +736,7 @@ static void snd_pmac_sound_feature(pmac_
 		pmu_suspend();
 		feature_clear(chip->node, FEATURE_Sound_power);
 		feature_clear(chip->node, FEATURE_Sound_CLK_enable);
-		mdelay(1000); /* XXX */
+		big_mdelay(1000); /* XXX */
 		pmu_resume();
 	}
 	if (chip->is_pbook_3400) {
diff -puN sound/ppc/pmac.h~alsa-bk-2003-07-28 sound/ppc/pmac.h
--- 25/sound/ppc/pmac.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/ppc/pmac.h	Tue Jul 29 12:11:31 2003
@@ -201,6 +201,11 @@ int snd_pmac_boolean_mono_info(snd_kcont
 
 int snd_pmac_add_automute(pmac_t *chip);
 
+#define big_mdelay(msec) do {\
+	set_current_state(TASK_UNINTERRUPTIBLE);\
+	schedule_timeout(((msec) * HZ + 999) / 1000);\
+} while (0)
+
 #ifndef PMAC_SUPPORT_PCM_BEEP
 #define snd_pmac_attach_beep(chip) 0
 #define snd_pmac_beep_stop(chip)  /**/
diff -puN sound/ppc/tumbler.c~alsa-bk-2003-07-28 sound/ppc/tumbler.c
--- 25/sound/ppc/tumbler.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/ppc/tumbler.c	Tue Jul 29 12:11:31 2003
@@ -27,7 +27,6 @@
 #include <linux/kmod.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/workqueue.h>
 #include <sound/core.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -93,9 +92,6 @@ typedef struct pmac_tumbler_t {
 	unsigned int mix_vol[VOL_IDX_LAST_MIX][2]; /* stereo volumes for tas3004 */
 	int drc_range;
 	int drc_enable;
-#ifdef CONFIG_PMAC_PBOOK
-	struct work_struct resume_workq;
-#endif
 } pmac_tumbler_t;
 
 
@@ -870,23 +866,21 @@ static void tumbler_reset_audio(pmac_t *
 	pmac_tumbler_t *mix = chip->mixer_data;
 
 	write_audio_gpio(&mix->audio_reset, 0);
-	mdelay(200);
+	big_mdelay(200);
 	write_audio_gpio(&mix->audio_reset, 1);
-	mdelay(100);
+	big_mdelay(100);
 	write_audio_gpio(&mix->audio_reset, 0);
-	mdelay(100);
+	big_mdelay(100);
 }
 
 #ifdef CONFIG_PMAC_PBOOK
 /* resume mixer */
-/* we call the i2c transfer in a workqueue because it may need either schedule()
- * or completion from timer interrupts.
- */
-static void tumbler_resume_work(void *arg)
+static void tumbler_resume(pmac_t *chip)
 {
-	pmac_t *chip = (pmac_t *)arg;
 	pmac_tumbler_t *mix = chip->mixer_data;
 
+	snd_assert(mix, return);
+
 	tumbler_reset_audio(chip);
 	if (mix->i2c.client) {
 		if (tumbler_init_client(&mix->i2c) < 0)
@@ -910,16 +904,6 @@ static void tumbler_resume_work(void *ar
 	if (chip->update_automute)
 		chip->update_automute(chip, 0);
 }
-
-static void tumbler_resume(pmac_t *chip)
-{
-	pmac_tumbler_t *mix = chip->mixer_data;
-	snd_assert(mix, return);
-	INIT_WORK(&mix->resume_workq, tumbler_resume_work, chip);
-	if (schedule_work(&mix->resume_workq))
-		return;
-	printk(KERN_ERR "ALSA tumbler: cannot schedule resume-workqueue.\n");
-}
 #endif
 
 /* initialize tumbler */
diff -puN sound/synth/emux/soundfont.c~alsa-bk-2003-07-28 sound/synth/emux/soundfont.c
--- 25/sound/synth/emux/soundfont.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/synth/emux/soundfont.c	Tue Jul 29 12:11:32 2003
@@ -66,15 +66,11 @@ static void snd_sf_clear(snd_sf_list_t *
 static int
 lock_preset(snd_sf_list_t *sflist, int nonblock)
 {
-	unsigned long flags;
-	spin_lock_irqsave(&sflist->lock, flags);
-	if (sflist->sf_locked && nonblock) {
-		spin_unlock_irqrestore(&sflist->lock, flags);
-		return -EBUSY;
-	}
-	spin_unlock_irqrestore(&sflist->lock, flags);
-	down(&sflist->presets_mutex);
-	sflist->sf_locked = 1;
+	if (nonblock) {
+		if (down_trylock(&sflist->presets_mutex))
+			return -EBUSY;
+	} else 
+		down(&sflist->presets_mutex);
 	return 0;
 }
 
@@ -86,7 +82,6 @@ static void
 unlock_preset(snd_sf_list_t *sflist)
 {
 	up(&sflist->presets_mutex);
-	sflist->sf_locked = 0;
 }
 
 
@@ -1356,7 +1351,6 @@ snd_sf_new(snd_sf_callback_t *callback, 
 
 	init_MUTEX(&sflist->presets_mutex);
 	spin_lock_init(&sflist->lock);
-	sflist->sf_locked = 0;
 	sflist->memhdr = hdr;
 
 	if (callback)
@@ -1403,7 +1397,7 @@ snd_soundfont_remove_samples(snd_sf_list
 
 /*
  * Remove unlocked samples.
- * The soundcard should be silet before calling this function.
+ * The soundcard should be silent before calling this function.
  */
 int
 snd_soundfont_remove_unlocked(snd_sf_list_t *sflist)
diff -puN sound/usb/usbaudio.c~alsa-bk-2003-07-28 sound/usb/usbaudio.c
--- 25/sound/usb/usbaudio.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/usb/usbaudio.c	Tue Jul 29 12:11:32 2003
@@ -153,6 +153,9 @@ struct snd_usb_substream {
 	int direction;	/* playback or capture */
 	int interface;	/* current interface */
 	int endpoint;	/* assigned endpoint */
+	struct audioformat *cur_audiofmt;	/* current audioformat pointer (for hw_params callback) */
+	unsigned int cur_rate;		/* current rate (for hw_params callback) */
+	unsigned int period_bytes;	/* current period bytes (for hw_params callback) */
 	unsigned int format;     /* USB data format */
 	unsigned int datapipe;   /* the data i/o pipe */
 	unsigned int syncpipe;   /* 1 - async out or adaptive in */
@@ -385,6 +388,7 @@ static int prepare_playback_sync_urb(snd
 		urb->iso_frame_desc[i].length = 3;
 		urb->iso_frame_desc[i].offset = offs;
 	}
+	urb->interval = 1;
 	return 0;
 }
 
@@ -509,6 +513,7 @@ static int prepare_playback_urb(snd_usb_
 	spin_unlock_irqrestore(&subs->lock, flags);
 	urb->transfer_buffer_length = offs * stride;
 	ctx->transfer = offs;
+	urb->interval = 1;
 
 	return 0;
 }
@@ -808,14 +813,15 @@ static void release_substream_urbs(snd_u
 /*
  * initialize a substream for plaback/capture
  */
-static int init_substream_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
+static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_bytes,
+			       unsigned int rate, unsigned int frame_bits)
 {
 	unsigned int maxsize, n, i;
 	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
 	unsigned int npacks[MAX_URBS], total_packs;
 
 	/* calculate the frequency in 10.14 format */
-	subs->freqn = subs->freqm = get_usb_rate(runtime->rate);
+	subs->freqn = subs->freqm = get_usb_rate(rate);
 	subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */
 	subs->phase = 0;
 
@@ -828,7 +834,7 @@ static int init_substream_urbs(snd_usb_s
 	subs->unlink_mask = 0;
 
 	/* calculate the max. size of packet */
-	maxsize = ((subs->freqmax + 0x3fff) * (runtime->frame_bits >> 3)) >> 14;
+	maxsize = ((subs->freqmax + 0x3fff) * (frame_bits >> 3)) >> 14;
 	if (subs->maxpacksize && maxsize > subs->maxpacksize) {
 		//snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n",
 		//	   maxsize, subs->maxpacksize);
@@ -839,7 +845,6 @@ static int init_substream_urbs(snd_usb_s
 		subs->curpacksize = subs->maxpacksize;
 	else
 		subs->curpacksize = maxsize;
-	subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
 
 	/* allocate a temporary buffer for playback */
 	if (is_playback) {
@@ -851,7 +856,7 @@ static int init_substream_urbs(snd_usb_s
 	}
 
 	/* decide how many packets to be used */
-	total_packs = (frames_to_bytes(runtime, runtime->period_size) + maxsize - 1) / maxsize;
+	total_packs = (period_bytes + maxsize - 1) / maxsize;
 	if (total_packs < 2 * MIN_PACKS_URB)
 		total_packs = 2 * MIN_PACKS_URB;
 	subs->nurbs = (total_packs + nrpacks - 1) / nrpacks;
@@ -945,7 +950,8 @@ static int init_substream_urbs(snd_usb_s
 /*
  * find a matching audio format
  */
-static struct audioformat *find_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
+static struct audioformat *find_format(snd_usb_substream_t *subs, unsigned int format,
+				       unsigned int rate, unsigned int channels)
 {
 	struct list_head *p;
 	struct audioformat *found = NULL;
@@ -953,23 +959,21 @@ static struct audioformat *find_format(s
 	list_for_each(p, &subs->fmt_list) {
 		struct audioformat *fp;
 		fp = list_entry(p, struct audioformat, list);
-		if (fp->format != runtime->format ||
-		    fp->channels != runtime->channels)
+		if (fp->format != format || fp->channels != channels)
 			continue;
-		if (runtime->rate < fp->rate_min || runtime->rate > fp->rate_max)
+		if (rate < fp->rate_min || rate > fp->rate_max)
 			continue;
-		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) {
-			if (! found || fp->maxpacksize > found->maxpacksize)
-				found = fp;
-		} else {
+		if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) {
 			unsigned int i;
 			for (i = 0; i < fp->nr_rates; i++)
-				if (fp->rate_table[i] == runtime->rate) {
-					if (! found || fp->maxpacksize > found->maxpacksize)
-						found = fp;
+				if (fp->rate_table[i] == rate)
 					break;
-				}
+			if (i >= fp->nr_rates)
+				continue;
 		}
+		/* find the format with the largest max. packet size */
+		if (! found || fp->maxpacksize > found->maxpacksize)
+			found = fp;
 	}
 	return found;
 }
@@ -1042,30 +1046,25 @@ static int init_usb_sample_rate(struct u
 /*
  * find a matching format and set up the interface
  */
-static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
+static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
 {
 	struct usb_device *dev = subs->dev;
 	struct usb_host_config *config = dev->actconfig;
 	struct usb_host_interface *alts;
 	struct usb_interface_descriptor *altsd;
 	struct usb_interface *iface;
-	struct audioformat *fmt;
 	unsigned int ep, attr;
 	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
 	int err;
 
-	fmt = find_format(subs, runtime);
-	if (! fmt) {
-		snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n",
-			   snd_pcm_format_name(runtime->format), runtime->rate, runtime->channels);
-		return -EINVAL;
-	}
-
 	iface = &config->interface[fmt->iface];
 	alts = &iface->altsetting[fmt->altset_idx];
 	altsd = get_iface_desc(alts);
 	snd_assert(altsd->bAlternateSetting == fmt->altsetting, return -EINVAL);
 
+	if (fmt == subs->cur_audiofmt)
+		return 0;
+
 	/* close the old interface */
 	if (subs->interface >= 0 && subs->interface != fmt->iface) {
 		usb_set_interface(subs->dev, subs->interface, 0);
@@ -1093,7 +1092,6 @@ static int set_format(snd_usb_substream_
 		subs->datapipe = usb_rcvisocpipe(dev, ep);
 	subs->syncpipe = subs->syncinterval = 0;
 	subs->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
-	subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
 	subs->fill_max = 0;
 
 	/* we need a sync pipe in async OUT or adaptive IN mode */
@@ -1123,18 +1121,18 @@ static int set_format(snd_usb_substream_
 		subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
 	}
 
-	if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0 ||
-	    (err = init_usb_sample_rate(dev, subs->interface, alts, fmt,
-					runtime->rate)) < 0)
-		return err;
-
 	/* always fill max packet size */
 	if (fmt->attributes & EP_CS_ATTR_FILL_MAX)
 		subs->fill_max = 1;
 
+	if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0)
+		return err;
+
+	subs->cur_audiofmt = fmt;
+
 #if 0
 	printk("setting done: format = %d, rate = %d, channels = %d\n",
-	       runtime->format, runtime->rate, runtime->channels);
+	       fmt->format, fmt->rate, fmt->channels);
 	printk("  datapipe = 0x%0x, syncpipe = 0x%0x\n",
 	       subs->datapipe, subs->syncpipe);
 #endif
@@ -1143,7 +1141,9 @@ static int set_format(snd_usb_substream_
 }
 
 /*
- * allocate a buffer.
+ * hw_params callback
+ *
+ * allocate a buffer and set the given audio format.
  *
  * so far we use a physically linear buffer although packetize transfer
  * doesn't need a continuous area.
@@ -1153,33 +1153,91 @@ static int set_format(snd_usb_substream_
 static int snd_usb_hw_params(snd_pcm_substream_t *substream,
 			     snd_pcm_hw_params_t *hw_params)
 {
-	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+	snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
+	struct audioformat *fmt;
+	unsigned int channels, rate, format;
+	int ret, changed;
+
+	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+	if (ret < 0)
+		return ret;
+	
+	format = params_format(hw_params);
+	rate = params_rate(hw_params);
+	channels = params_channels(hw_params);
+	fmt = find_format(subs, format, rate, channels);
+	if (! fmt) {
+		snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n",
+			   snd_pcm_format_name(format), rate, channels);
+		return -EINVAL;
+	}
+
+	changed = subs->cur_audiofmt != fmt ||
+		subs->period_bytes != params_period_bytes(hw_params) ||
+		subs->cur_rate != rate;
+	if ((ret = set_format(subs, fmt)) < 0)
+		return ret;
+
+	if (subs->cur_rate != rate) {
+		struct usb_host_config *config = subs->dev->actconfig;
+		struct usb_host_interface *alts;
+		struct usb_interface *iface;
+		iface = &config->interface[fmt->iface];
+		alts = &iface->altsetting[fmt->altset_idx];
+		ret = init_usb_sample_rate(subs->dev, subs->interface, alts, fmt, rate);
+		if (ret < 0)
+			return ret;
+		subs->cur_rate = rate;
+	}
+
+	if (changed) {
+		/* format changed */
+		release_substream_urbs(subs, 0);
+		/* influenced: period_bytes, channels, rate, format, */
+		ret = init_substream_urbs(subs, params_period_bytes(hw_params),
+					  params_rate(hw_params),
+					  snd_pcm_format_physical_width(params_format(hw_params)) * params_channels(hw_params));
+	}
+
+	return ret;
 }
 
 /*
- * free the buffer
+ * hw_free callback
+ *
+ * reset the audio format and release the buffer
  */
 static int snd_usb_hw_free(snd_pcm_substream_t *substream)
 {
+	snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
+
+	subs->cur_audiofmt = NULL;
+	subs->cur_rate = 0;
+	subs->period_bytes = 0;
+	release_substream_urbs(subs, 0);
 	return snd_pcm_lib_free_pages(substream);
 }
 
 /*
  * prepare callback
  *
- * set format and initialize urbs
+ * only a few subtle things...
  */
 static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	snd_usb_substream_t *subs = (snd_usb_substream_t *)runtime->private_data;
-	int err;
 
-	release_substream_urbs(subs, 0);
-	if ((err = set_format(subs, runtime)) < 0)
-		return err;
+	if (! subs->cur_audiofmt) {
+		snd_printk(KERN_ERR "usbaudio: no format is specified!\n");
+		return -ENXIO;
+	}
+
+	/* some unit conversions in runtime */
+	subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
+	subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
 
-	return init_substream_urbs(subs, runtime);
+	return 0;
 }
 
 static snd_pcm_hardware_t snd_usb_playback =
@@ -1536,9 +1594,10 @@ static int snd_usb_pcm_close(snd_pcm_sub
 	snd_usb_stream_t *as = snd_pcm_substream_chip(substream);
 	snd_usb_substream_t *subs = &as->substream[direction];
 
-	release_substream_urbs(subs, 0);
-	if (subs->interface >= 0)
+	if (subs->interface >= 0) {
 		usb_set_interface(subs->dev, subs->interface, 0);
+		subs->interface = -1;
+	}
 	subs->pcm_substream = NULL;
 	return 0;
 }
@@ -2163,8 +2222,10 @@ static int parse_audio_endpoints(snd_usb
 		/* skip invalid one */
 		if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
 		     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
-		    altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING ||
-		    altsd->bNumEndpoints < 1)
+		    (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING &&
+		     altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
+		    altsd->bNumEndpoints < 1 ||
+		    get_endpoint(alts, 0)->wMaxPacketSize == 0)
 			continue;
 		/* must be isochronous */
 		if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
@@ -2236,6 +2297,14 @@ static int parse_audio_endpoints(snd_usb
 			 */
 			fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE;
 		}
+
+		/* workaround for M-Audio Audiophile USB */
+		if (dev->descriptor.idVendor == 0x0763 &&
+		    dev->descriptor.idProduct == 0x2003) {
+			/* doesn't set the sample rate attribute, but supports it */
+			fp->attributes |= EP_CS_ATTR_SAMPLE_RATE;
+		}
+
 		/*
 		 * plantronics headset and Griffin iMic have set adaptive-in
 		 * although it's really not...
@@ -2278,6 +2347,32 @@ static int parse_audio_endpoints(snd_usb
 
 
 /*
+ * disconnect streams
+ * called from snd_usb_audio_disconnect()
+ */
+static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver *driver)
+{
+	int idx;
+	snd_usb_stream_t *as;
+	snd_usb_substream_t *subs;
+	struct list_head *p;
+
+	as = list_entry(head, snd_usb_stream_t, list);
+	for (idx = 0; idx < 2; idx++) {
+		subs = &as->substream[idx];
+		if (!subs->num_formats)
+			return;
+		release_substream_urbs(subs, 1);
+		subs->interface = -1;
+		/* release interfaces */
+		list_for_each(p, &subs->fmt_list) {
+			struct audioformat *fp = list_entry(p, struct audioformat, list);
+			usb_driver_release_interface(driver, usb_ifnum_to_if(subs->dev, fp->iface));
+		}
+	}
+}
+
+/*
  * parse audio control descriptor and create pcm/midi streams
  */
 static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif)
@@ -2381,7 +2476,8 @@ static int create_fixed_stream_quirk(snd
  * create a stream for an interface with proper descriptors
  */
 static int create_standard_interface_quirk(snd_usb_audio_t *chip,
-					   struct usb_interface *iface)
+					   struct usb_interface *iface,
+					   const snd_usb_audio_quirk_t *quirk)
 {
 	struct usb_host_interface *alts;
 	struct usb_interface_descriptor *altsd;
@@ -2389,19 +2485,18 @@ static int create_standard_interface_qui
 
 	alts = &iface->altsetting[0];
 	altsd = get_iface_desc(alts);
-	switch (altsd->bInterfaceSubClass) {
-	case USB_SUBCLASS_AUDIO_STREAMING:
+	switch (quirk->type) {
+	case QUIRK_AUDIO_STANDARD_INTERFACE:
 		err = parse_audio_endpoints(chip, altsd->bInterfaceNumber);
 		if (!err)
 			usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); /* reset the current interface */
 		break;
-	case USB_SUBCLASS_MIDI_STREAMING:
+	case QUIRK_MIDI_STANDARD_INTERFACE:
 		err = snd_usb_create_midi_interface(chip, iface, NULL);
 		break;
 	default:
-		snd_printk(KERN_ERR "if %d: non-supported subclass %d\n",
-			   altsd->bInterfaceNumber, altsd->bInterfaceSubClass);
-		return -ENODEV;
+		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
+		return -ENXIO;
 	}
 	if (err < 0) {
 		snd_printk(KERN_ERR "cannot setup if %d: error %d\n",
@@ -2495,8 +2590,9 @@ static int snd_usb_create_quirk(snd_usb_
 		return create_composite_quirk(chip, iface, quirk);
 	case QUIRK_AUDIO_FIXED_ENDPOINT:
 		return create_fixed_stream_quirk(chip, iface, quirk);
-	case QUIRK_STANDARD_INTERFACE:
-		return create_standard_interface_quirk(chip, iface);
+	case QUIRK_AUDIO_STANDARD_INTERFACE:
+	case QUIRK_MIDI_STANDARD_INTERFACE:
+		return create_standard_interface_quirk(chip, iface, quirk);
 	default:
 		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
 		return -ENXIO;
@@ -2635,11 +2731,6 @@ static void *snd_usb_audio_probe(struct 
 	if (quirk && quirk->ifnum != QUIRK_ANY_INTERFACE && ifnum != quirk->ifnum)
 		goto __err_val;
 
-	if (usb_set_configuration(dev, get_cfg_desc(config)->bConfigurationValue) < 0) {
-		snd_printk(KERN_ERR "cannot set configuration (value 0x%x)\n", get_cfg_desc(config)->bConfigurationValue);
-		goto __err_val;
-	}
-
 	/* SB Extigy needs special boot-up sequence */
 	/* if more models come, this will go to the quirk list. */
 	if (dev->descriptor.idVendor == 0x041e && dev->descriptor.idProduct == 0x3000) {
@@ -2669,6 +2760,11 @@ static void *snd_usb_audio_probe(struct 
 		/* it's a fresh one.
 		 * now look for an empty slot and create a new card instance
 		 */
+		/* first, set the current configuration for this device */
+		if (usb_set_configuration(dev, get_cfg_desc(config)->bConfigurationValue) < 0) {
+			snd_printk(KERN_ERR "cannot set configuration (value 0x%x)\n", get_cfg_desc(config)->bConfigurationValue);
+			goto __error;
+		}
 		for (i = 0; i < SNDRV_CARDS; i++)
 			if (enable[i] && ! usb_chip[i] &&
 			    (vid[i] == -1 || vid[i] == dev->descriptor.idVendor) &&
@@ -2746,21 +2842,11 @@ static void snd_usb_audio_disconnect(str
 		snd_card_disconnect(card);
 		/* release the pcm resources */
 		list_for_each(p, &chip->pcm_list) {
-			snd_usb_stream_t *as;
-			int idx;
-			as = list_entry(p, snd_usb_stream_t, list);
-			for (idx = 0; idx < 2; idx++) {
-				snd_usb_substream_t *subs;
-				subs = &as->substream[idx];
-				if (!subs->num_formats)
-					continue;
-				release_substream_urbs(subs, 1);
-				subs->interface = -1;
-			}
+			snd_usb_stream_disconnect(p, &usb_audio_driver);
 		}
 		/* release the midi resources */
 		list_for_each(p, &chip->midi_list) {
-			snd_usbmidi_disconnect(p);
+			snd_usbmidi_disconnect(p, &usb_audio_driver);
 		}
 		up(&register_mutex);
 		snd_card_free_in_thread(card);
diff -puN sound/usb/usbaudio.h~alsa-bk-2003-07-28 sound/usb/usbaudio.h
--- 25/sound/usb/usbaudio.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/usb/usbaudio.h	Tue Jul 29 12:11:31 2003
@@ -28,6 +28,7 @@
 #define USB_SUBCLASS_AUDIO_CONTROL	0x01
 #define USB_SUBCLASS_AUDIO_STREAMING	0x02
 #define USB_SUBCLASS_MIDI_STREAMING	0x03
+#define USB_SUBCLASS_VENDOR_SPEC	0xff
 
 #define USB_DT_CS_DEVICE                0x21
 #define USB_DT_CS_CONFIG                0x22
@@ -154,7 +155,8 @@ struct snd_usb_audio {
 #define QUIRK_MIDI_MIDIMAN		2
 #define QUIRK_COMPOSITE			3
 #define QUIRK_AUDIO_FIXED_ENDPOINT	4
-#define QUIRK_STANDARD_INTERFACE	5
+#define QUIRK_AUDIO_STANDARD_INTERFACE	5
+#define QUIRK_MIDI_STANDARD_INTERFACE	6
 
 typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
 typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
@@ -184,7 +186,7 @@ struct snd_usb_midi_endpoint_info {
 
 /* for QUIRK_AUDIO_FIXED_ENDPOINT, data points to an audioformat structure */
 
-/* for QUIRK_STANDARD_INTERFACE, data is NULL */
+/* for QUIRK_AUDIO/MIDI_STANDARD_INTERFACE, data is NULL */
 
 /*
  */
@@ -201,7 +203,7 @@ void *snd_usb_find_csint_desc(void *desc
 int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif);
 
 int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk);
-void snd_usbmidi_disconnect(struct list_head *p);
+void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver);
 
 /*
  * retrieve usb_interface descriptor from the host interface
diff -puN sound/usb/usbmidi.c~alsa-bk-2003-07-28 sound/usb/usbmidi.c
--- 25/sound/usb/usbmidi.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/usb/usbmidi.c	Tue Jul 29 12:11:31 2003
@@ -693,12 +693,13 @@ static void snd_usbmidi_free(snd_usb_mid
 /*
  * Unlinks all URBs (must be done before the usb_device is deleted).
  */
-void snd_usbmidi_disconnect(struct list_head* p)
+void snd_usbmidi_disconnect(struct list_head* p, struct usb_driver *driver)
 {
 	snd_usb_midi_t* umidi;
 	int i;
 
 	umidi = list_entry(p, snd_usb_midi_t, list);
+	usb_driver_release_interface(driver, umidi->iface);
 	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
 		snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
 		if (ep->out && ep->out->urb)
diff -puN sound/usb/usbmixer.c~alsa-bk-2003-07-28 sound/usb/usbmixer.c
--- 25/sound/usb/usbmixer.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/usb/usbmixer.c	Tue Jul 29 12:11:31 2003
@@ -96,7 +96,7 @@ enum {
 	USB_FEATURE_AGC,
 	USB_FEATURE_DELAY,
 	USB_FEATURE_BASSBOOST,
-	FSB_FEATURE_LOUDNESS
+	USB_FEATURE_LOUDNESS
 };
 
 enum {
diff -puN sound/usb/usbmixer_maps.c~alsa-bk-2003-07-28 sound/usb/usbmixer_maps.c
--- 25/sound/usb/usbmixer_maps.c~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/usb/usbmixer_maps.c	Tue Jul 29 12:11:31 2003
@@ -89,6 +89,28 @@ static struct usbmix_name_map extigy_map
 	{ 0 } /* terminator */
 };
 
+/* Section "justlink_map" below added by James Courtier-Dutton <James@superbug.demon.co.uk>
+ * sourced from Maplin Electronics (http://www.maplin.co.uk), part number A56AK
+ * Part has 2 connectors that act as a single output. (TOSLINK Optical for digital out, and 3.5mm Jack for Analogue out.)
+ * The USB Mixer publishes a Microphone and extra Volume controls for it, but none exist on the device,
+ * so this map removes all unwanted sliders from alsamixer
+ */
+
+static struct usbmix_name_map justlink_map[] = {
+	/* 1: IT pcm playback */
+	/* 2: Not present */
+	{ 3, NULL}, /* IT mic (No mic input on device) */
+	/* 4: Not present */
+	/* 5: OT speacker */
+	/* 6: OT pcm capture */
+	{ 7, "Master Playback" }, /* Mute/volume for speaker */
+	{ 8, NULL }, /* Capture Switch (No capture inputs on device) */
+	{ 9, NULL }, /* Capture Mute/volume (No capture inputs on device */
+	/* 0xa: Not present */
+	/* 0xb: MU (w/o controls) */
+	{ 0xc, NULL }, /* Mic feedback Mute/volume (No capture inputs on device) */
+	{ 0 } /* terminator */
+};
 
 /*
  * Control map entries
@@ -96,6 +118,7 @@ static struct usbmix_name_map extigy_map
 
 static struct usbmix_ctl_map usbmix_ctl_maps[] = {
 	{ 0x41e, 0x3000, extigy_map },
+	{ 0xc45, 0x1158, justlink_map },
 	{ 0 } /* terminator */
 };
 
diff -puN sound/usb/usbquirks.h~alsa-bk-2003-07-28 sound/usb/usbquirks.h
--- 25/sound/usb/usbquirks.h~alsa-bk-2003-07-28	Tue Jul 29 12:11:31 2003
+++ 25-akpm/sound/usb/usbquirks.h	Tue Jul 29 12:11:31 2003
@@ -453,6 +453,36 @@
 		}
 	}
 },
+{	/*
+	 * This quirk is for the "Advanced Driver" mode of the Edirol UA-5.
+	 * If the advanced mode switch at the back of the unit is off, the
+	 * UA-5 has ID 0x0582/0x0011 and is standard compliant (no quirks),
+	 * but offers only 16-bit PCM.
+	 * In advanced mode, the UA-5 will output S24_3LE samples (two
+	 * channels) at the rate indicated on the front switch, including
+	 * the 96kHz sample rate.
+	 */
+	USB_DEVICE(0x0582, 0x0010),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "UA-5",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = & (const snd_usb_audio_quirk_t[]) {
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
 {
 	USB_DEVICE(0x0582, 0x0012),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
@@ -520,15 +550,15 @@
 		.data = & (const snd_usb_audio_quirk_t[]) {
 			{
 				.ifnum = 1,
-				.type = QUIRK_STANDARD_INTERFACE
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
 			},
 			{
 				.ifnum = 2,
-				.type = QUIRK_STANDARD_INTERFACE
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
 			},
 			{
 				.ifnum = 3,
-				.type = QUIRK_STANDARD_INTERFACE
+				.type = QUIRK_MIDI_STANDARD_INTERFACE
 			},
 			{
 				.ifnum = -1

_