http://linux-sound.bkbits.net/linux-sound
perex@suse.cz|ChangeSet|20050127072045|45912 perex

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/02/02 20:54:30-08:00 akpm@bix.(none) 
#   ss
# 
# sound/pci/rme9652/hdsp.c
#   2005/02/02 20:54:23-08:00 akpm@bix.(none) +0 -1
#   ss
# 
# ChangeSet
#   2005/01/27 08:20:45+01:00 perex@suse.cz 
#   [ALSA] Removed file added by mistake
#   
#   Removed include/sound/version.h~
# 
# BitKeeper/deleted/.del-version.h~~37c78b8aa77b0731
#   2005/01/27 08:15:16+01:00 perex@suse.cz +0 -0
#   Delete: include/sound/version.h~
# 
# ChangeSet
#   2005/01/25 20:52:17+01:00 perex@suse.cz 
#   [ALSA] replace schedule_timeout() with msleep()
#   
#   EMU8000 driver
#   Use msleep() instead of schedule_timeout() to guarantee the task
#   delays as expected.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/isa/sb/emu8000.c
#   2005/01/24 08:00:18+01:00 perex@suse.cz +2 -2
#   [ALSA] replace schedule_timeout() with msleep()
#   
#   D:2005/01/24 15:00:18
#   C:EMU8000 driver
#   F:isa/sb/emu8000.c:1.24->1.25 
#   L:Use msleep() instead of schedule_timeout() to guarantee the task
#   L:delays as expected.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/25 20:50:28+01:00 perex@suse.cz 
#   [ALSA] insert set_current_state() before schedule_timeout()
#   
#   Wavefront drivers
#   Insert set_current_state() before schedule_timeout(). Without the
#   insertion, schedule_timeout() returns immediately, resulting in an
#   effective busy-wait.
#   
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/isa/wavefront/wavefront_synth.c
#   2005/01/24 07:59:27+01:00 perex@suse.cz +1 -0
#   [ALSA] insert set_current_state() before schedule_timeout()
#   
#   D:2005/01/24 14:59:27
#   C:Wavefront drivers
#   F:isa/wavefront/wavefront_synth.c:1.23->1.24 
#   L:Insert set_current_state() before schedule_timeout(). Without the
#   L:insertion, schedule_timeout() returns immediately, resulting in an
#   L:effective busy-wait.
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/25 20:48:58+01:00 perex@suse.cz 
#   [ALSA] replace schedule_timeout() with msleep_interruptible()
#   
#   GUS Library
#   Use msleep_interruptible() instead of custom wait code involving
#   schedule_timeout() to guarantee the task delays as expected. This also
#   removes a dependence on the value of HZ.
#   
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/isa/gus/gus_reset.c
#   2005/01/24 07:58:37+01:00 perex@suse.cz +1 -6
#   [ALSA] replace schedule_timeout() with msleep_interruptible()
#   
#   D:2005/01/24 14:58:37
#   C:GUS Library
#   F:isa/gus/gus_reset.c:1.7->1.8 
#   L:Use msleep_interruptible() instead of custom wait code involving
#   L:schedule_timeout() to guarantee the task delays as expected. This also
#   L:removes a dependence on the value of HZ.
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/25 20:47:19+01:00 perex@suse.cz 
#   [ALSA] insert set_current_state() before schedule_timeout()
#   
#   GUS Library
#   Insert set_current_state() before schedule_timeout(). Without the
#   insertion, schedule_timeout() returns immediately.
#   
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/isa/gus/gus_pcm.c
#   2005/01/24 07:57:51+01:00 perex@suse.cz +1 -0
#   [ALSA] insert set_current_state() before schedule_timeout()
#   
#   D:2005/01/24 14:57:51
#   C:GUS Library
#   F:isa/gus/gus_pcm.c:1.23->1.24 
#   L:Insert set_current_state() before schedule_timeout(). Without the
#   L:insertion, schedule_timeout() returns immediately.
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/25 20:41:00+01:00 perex@suse.cz 
#   [ALSA] replace schedule_timeout() with msleep()
#   
#   Digigram VX core
#   Use msleep() instead of schedule_timeout() to guarantee the task
#   delays as expected.
#   
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/drivers/vx/vx_core.c
#   2005/01/24 07:56:51+01:00 perex@suse.cz +3 -5
#   [ALSA] replace schedule_timeout() with msleep()
#   
#   D:2005/01/24 14:56:51
#   C:Digigram VX core
#   F:drivers/vx/vx_core.c:1.13->1.14 
#   L:Use msleep() instead of schedule_timeout() to guarantee the task
#   L:delays as expected.
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/25 20:39:04+01:00 perex@suse.cz 
#   [ALSA] replace schedule_timeout() with msleep()
#   
#   RawMidi Midlevel
#   Use msleep instead of schedule_timeout() to guarantee the task delays
#   as expected. This also removes a dependence on the value of HZ.
#   
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/rawmidi.c
#   2005/01/24 07:55:43+01:00 perex@suse.cz +3 -4
#   [ALSA] replace schedule_timeout() with msleep()
#   
#   D:2005/01/24 14:55:43
#   C:RawMidi Midlevel
#   F:core/rawmidi.c:1.52->1.53 
#   L:Use msleep instead of schedule_timeout() to guarantee the task delays
#   L:as expected. This also removes a dependence on the value of HZ.
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/25 20:37:18+01:00 perex@suse.cz 
#   [ALSA] Special AC97 patch for ASUS W1000/CMI9739 laptop
#   
#   AC97 Codec
#   This patch fixes sound output on the ASUS W1000 laptop with the CMI9739
#   chip. It wrongly reports that it has a SPDIF in, when in fact we wish to
#   use the EAPD pin.
#   
#   Signed-off-by: James Courtier-Dutton <James@superbug.co.uk>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/ac97/ac97_patch.c
#   2005/01/24 05:11:00+01:00 perex@suse.cz +9 -0
#   [ALSA] Special AC97 patch for ASUS W1000/CMI9739 laptop
#   
#   D:2005/01/24 12:11:00
#   C:AC97 Codec
#   F:pci/ac97/ac97_patch.c:1.70->1.71 
#   L:This patch fixes sound output on the ASUS W1000 laptop with the CMI9739
#   L:chip. It wrongly reports that it has a SPDIF in, when in fact we wish to
#   L:use the EAPD pin.
#   Signed-off-by: James Courtier-Dutton <James@superbug.co.uk>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/25 20:35:33+01:00 perex@suse.cz 
#   [ALSA] Warning doc about VIA82xx recording
#   
#   Documentation
#   Add warning about the consequences of adjusting the 'Input Source Select'
#   of VIA82xx.
#   
#   Signed-off-by: Ross Kendall Axe <ross.axe@blueyonder.co.uk>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# Documentation/sound/alsa/VIA82xx-mixer.txt
#   2005/01/25 14:32:28+01:00 perex@suse.cz +8 -0
#   [ALSA] Warning doc about VIA82xx recording
#   
#   D:2005/01/21 19:33:11
#   C:Documentation
#   F:Documentation/VIA82xx-mixer.txt:INITIAL->1.1 
#   L:Add warning about the consequences of adjusting the 'Input Source Select'
#   L:of VIA82xx.
#   Signed-off-by: Ross Kendall Axe <ross.axe@blueyonder.co.uk>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# Documentation/sound/alsa/VIA82xx-mixer.txt
#   2005/01/25 14:32:28+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/Documentation/sound/alsa/VIA82xx-mixer.txt
# 
# ChangeSet
#   2005/01/25 20:33:42+01:00 perex@suse.cz 
#   [ALSA] fix usage of preprocessor directive inside macro
#   
#   HDA Intel driver
#   gcc-2 complains about preprocessor directives inside a macro argument list
#   
#   Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
# 
# sound/pci/hda/hda_intel.c
#   2005/01/21 10:46:00+01:00 perex@suse.cz +3 -3
#   [ALSA] fix usage of preprocessor directive inside macro
#   
#   D:2005/01/21 17:46:00
#   C:HDA Intel driver
#   F:pci/hda/hda_intel.c:1.1->1.2 
#   L:gcc-2 complains about preprocessor directives inside a macro argument list
#   Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
# 
# ChangeSet
#   2005/01/25 20:32:04+01:00 perex@suse.cz 
#   [ALSA] add more Yamaha USB MIDI quirks
#   
#   USB generic driver
#   add support for Yamaha UC-MX, UC-KX, CLP-175, SPX2000
#   
#   Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
# 
# sound/usb/usbquirks.h
#   2005/01/21 01:32:12+01:00 perex@suse.cz +6 -0
#   [ALSA] add more Yamaha USB MIDI quirks
#   
#   D:2005/01/21 08:32:12
#   C:USB generic driver
#   F:usb/usbquirks.h:1.39->1.40 
#   L:add support for Yamaha UC-MX, UC-KX, CLP-175, SPX2000
#   Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
# 
# ChangeSet
#   2005/01/20 22:29:20+01:00 perex@suse.cz 
#   [ALSA] remove obsolete sound/core/ioctl32 directory
#   
#   The compatibility layer is integrated to ALSA midlevel code now.
# 
# include/sound/version.h~
#   2005/01/20 22:26:24+01:00 perex@suse.cz +3 -0
# 
# include/sound/version.h~
#   2005/01/20 22:26:24+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/include/sound/version.h~
# 
# BitKeeper/deleted/.del-hwdep32.c~2628af71433fb282
#   2005/01/20 22:14:14+01:00 perex@suse.cz +0 -0
#   Delete: sound/core/ioctl32/hwdep32.c
# 
# BitKeeper/deleted/.del-ioctl32.h~6fa31b659e702cbd
#   2005/01/20 22:14:12+01:00 perex@suse.cz +0 -0
#   Delete: sound/core/ioctl32/ioctl32.h
# 
# BitKeeper/deleted/.del-ioctl32.c~e6621ca58003986f
#   2005/01/20 22:14:11+01:00 perex@suse.cz +0 -0
#   Delete: sound/core/ioctl32/ioctl32.c
# 
# BitKeeper/deleted/.del-Makefile~767d5bad6308fa6d
#   2005/01/20 22:14:08+01:00 perex@suse.cz +0 -0
#   Delete: sound/core/ioctl32/Makefile
# 
# BitKeeper/deleted/.del-pcm32.c~79101ddd8c8dbba8
#   2005/01/20 22:14:05+01:00 perex@suse.cz +0 -0
#   Delete: sound/core/ioctl32/pcm32.c
# 
# BitKeeper/deleted/.del-rawmidi32.c~b24d28b2a36477f1
#   2005/01/20 22:14:03+01:00 perex@suse.cz +0 -0
#   Delete: sound/core/ioctl32/rawmidi32.c
# 
# BitKeeper/deleted/.del-seq32.c~c96c6dffe1307ca0
#   2005/01/20 22:14:00+01:00 perex@suse.cz +0 -0
#   Delete: sound/core/ioctl32/seq32.c
# 
# BitKeeper/deleted/.del-timer32.c~e0c2522dbc4e6d68
#   2005/01/20 22:13:55+01:00 perex@suse.cz +0 -0
#   Delete: sound/core/ioctl32/timer32.c
# 
# ChangeSet
#   2005/01/20 21:47:16+01:00 perex@suse.cz 
#   Merge suse.cz:/home/perex/bk/linux-sound/linux-sound
#   into suse.cz:/home/perex/bk/linux-sound/work
# 
# sound/pci/Kconfig
#   2005/01/20 21:46:53+01:00 perex@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/01/20 20:33:37+01:00 perex@suse.cz 
#   [ALSA] Use DEFINE_SPINLOCK(), DEFINE_RWLOCK() macros
#   
#   ALSA Core,PCM Midlevel,Timer Midlevel,ALSA sequencer
#   ALSA<-OSS sequencer
#   Replace spin/rwlock definitions with DEFINE_SPINLOCK() and DEFINE_RWLOCK()
#   macros.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/timer.c
#   2005/01/20 10:42:36+01:00 perex@suse.cz +1 -1
#   [ALSA] Use DEFINE_SPINLOCK(), DEFINE_RWLOCK() macros
#   
#   D:2005/01/20 17:42:36
#   C:ALSA Core,PCM Midlevel,Timer Midlevel,ALSA sequencer
#   C:ALSA<-OSS sequencer
#   F:core/init.c:1.54->1.55 
#   F:core/memory.c:1.36->1.37 
#   F:core/pcm_native.c:1.112->1.113 
#   F:core/timer.c:1.64->1.65 
#   F:core/seq/seq_clientmgr.c:1.41->1.42 
#   F:core/seq/seq_queue.c:1.15->1.16 
#   F:core/seq/oss/seq_oss_midi.c:1.16->1.17 
#   F:core/seq/oss/seq_oss_synth.c:1.16->1.17 
#   L:Replace spin/rwlock definitions with DEFINE_SPINLOCK() and DEFINE_RWLOCK()
#   L:macros.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/seq/seq_queue.c
#   2005/01/20 10:42:37+01:00 perex@suse.cz +1 -1
#   [ALSA] Use DEFINE_SPINLOCK(), DEFINE_RWLOCK() macros
#   
#   D:2005/01/20 17:42:36
#   C:ALSA Core,PCM Midlevel,Timer Midlevel,ALSA sequencer
#   C:ALSA<-OSS sequencer
#   F:core/init.c:1.54->1.55 
#   F:core/memory.c:1.36->1.37 
#   F:core/pcm_native.c:1.112->1.113 
#   F:core/timer.c:1.64->1.65 
#   F:core/seq/seq_clientmgr.c:1.41->1.42 
#   F:core/seq/seq_queue.c:1.15->1.16 
#   F:core/seq/oss/seq_oss_midi.c:1.16->1.17 
#   F:core/seq/oss/seq_oss_synth.c:1.16->1.17 
#   L:Replace spin/rwlock definitions with DEFINE_SPINLOCK() and DEFINE_RWLOCK()
#   L:macros.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/seq/seq_clientmgr.c
#   2005/01/20 10:42:37+01:00 perex@suse.cz +1 -1
#   [ALSA] Use DEFINE_SPINLOCK(), DEFINE_RWLOCK() macros
#   
#   D:2005/01/20 17:42:36
#   C:ALSA Core,PCM Midlevel,Timer Midlevel,ALSA sequencer
#   C:ALSA<-OSS sequencer
#   F:core/init.c:1.54->1.55 
#   F:core/memory.c:1.36->1.37 
#   F:core/pcm_native.c:1.112->1.113 
#   F:core/timer.c:1.64->1.65 
#   F:core/seq/seq_clientmgr.c:1.41->1.42 
#   F:core/seq/seq_queue.c:1.15->1.16 
#   F:core/seq/oss/seq_oss_midi.c:1.16->1.17 
#   F:core/seq/oss/seq_oss_synth.c:1.16->1.17 
#   L:Replace spin/rwlock definitions with DEFINE_SPINLOCK() and DEFINE_RWLOCK()
#   L:macros.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/seq/oss/seq_oss_synth.c
#   2005/01/20 10:42:37+01:00 perex@suse.cz +1 -1
#   [ALSA] Use DEFINE_SPINLOCK(), DEFINE_RWLOCK() macros
#   
#   D:2005/01/20 17:42:36
#   C:ALSA Core,PCM Midlevel,Timer Midlevel,ALSA sequencer
#   C:ALSA<-OSS sequencer
#   F:core/init.c:1.54->1.55 
#   F:core/memory.c:1.36->1.37 
#   F:core/pcm_native.c:1.112->1.113 
#   F:core/timer.c:1.64->1.65 
#   F:core/seq/seq_clientmgr.c:1.41->1.42 
#   F:core/seq/seq_queue.c:1.15->1.16 
#   F:core/seq/oss/seq_oss_midi.c:1.16->1.17 
#   F:core/seq/oss/seq_oss_synth.c:1.16->1.17 
#   L:Replace spin/rwlock definitions with DEFINE_SPINLOCK() and DEFINE_RWLOCK()
#   L:macros.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/seq/oss/seq_oss_midi.c
#   2005/01/20 10:42:37+01:00 perex@suse.cz +1 -1
#   [ALSA] Use DEFINE_SPINLOCK(), DEFINE_RWLOCK() macros
#   
#   D:2005/01/20 17:42:36
#   C:ALSA Core,PCM Midlevel,Timer Midlevel,ALSA sequencer
#   C:ALSA<-OSS sequencer
#   F:core/init.c:1.54->1.55 
#   F:core/memory.c:1.36->1.37 
#   F:core/pcm_native.c:1.112->1.113 
#   F:core/timer.c:1.64->1.65 
#   F:core/seq/seq_clientmgr.c:1.41->1.42 
#   F:core/seq/seq_queue.c:1.15->1.16 
#   F:core/seq/oss/seq_oss_midi.c:1.16->1.17 
#   F:core/seq/oss/seq_oss_synth.c:1.16->1.17 
#   L:Replace spin/rwlock definitions with DEFINE_SPINLOCK() and DEFINE_RWLOCK()
#   L:macros.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/pcm_native.c
#   2005/01/20 10:42:36+01:00 perex@suse.cz +1 -1
#   [ALSA] Use DEFINE_SPINLOCK(), DEFINE_RWLOCK() macros
#   
#   D:2005/01/20 17:42:36
#   C:ALSA Core,PCM Midlevel,Timer Midlevel,ALSA sequencer
#   C:ALSA<-OSS sequencer
#   F:core/init.c:1.54->1.55 
#   F:core/memory.c:1.36->1.37 
#   F:core/pcm_native.c:1.112->1.113 
#   F:core/timer.c:1.64->1.65 
#   F:core/seq/seq_clientmgr.c:1.41->1.42 
#   F:core/seq/seq_queue.c:1.15->1.16 
#   F:core/seq/oss/seq_oss_midi.c:1.16->1.17 
#   F:core/seq/oss/seq_oss_synth.c:1.16->1.17 
#   L:Replace spin/rwlock definitions with DEFINE_SPINLOCK() and DEFINE_RWLOCK()
#   L:macros.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/memory.c
#   2005/01/20 10:42:36+01:00 perex@suse.cz +2 -2
#   [ALSA] Use DEFINE_SPINLOCK(), DEFINE_RWLOCK() macros
#   
#   D:2005/01/20 17:42:36
#   C:ALSA Core,PCM Midlevel,Timer Midlevel,ALSA sequencer
#   C:ALSA<-OSS sequencer
#   F:core/init.c:1.54->1.55 
#   F:core/memory.c:1.36->1.37 
#   F:core/pcm_native.c:1.112->1.113 
#   F:core/timer.c:1.64->1.65 
#   F:core/seq/seq_clientmgr.c:1.41->1.42 
#   F:core/seq/seq_queue.c:1.15->1.16 
#   F:core/seq/oss/seq_oss_midi.c:1.16->1.17 
#   F:core/seq/oss/seq_oss_synth.c:1.16->1.17 
#   L:Replace spin/rwlock definitions with DEFINE_SPINLOCK() and DEFINE_RWLOCK()
#   L:macros.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/init.c
#   2005/01/20 10:42:36+01:00 perex@suse.cz +1 -1
#   [ALSA] Use DEFINE_SPINLOCK(), DEFINE_RWLOCK() macros
#   
#   D:2005/01/20 17:42:36
#   C:ALSA Core,PCM Midlevel,Timer Midlevel,ALSA sequencer
#   C:ALSA<-OSS sequencer
#   F:core/init.c:1.54->1.55 
#   F:core/memory.c:1.36->1.37 
#   F:core/pcm_native.c:1.112->1.113 
#   F:core/timer.c:1.64->1.65 
#   F:core/seq/seq_clientmgr.c:1.41->1.42 
#   F:core/seq/seq_queue.c:1.15->1.16 
#   F:core/seq/oss/seq_oss_midi.c:1.16->1.17 
#   F:core/seq/oss/seq_oss_synth.c:1.16->1.17 
#   L:Replace spin/rwlock definitions with DEFINE_SPINLOCK() and DEFINE_RWLOCK()
#   L:macros.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:32:02+01:00 perex@suse.cz 
#   [ALSA] Remove snd-ioctl32 entry
#   
#   ALSA Core
#   Remove the entry for snd-ioctl32.  The 32bit wrapper is built in the core
#   module.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/Makefile
#   2005/01/20 10:16:39+01:00 perex@suse.cz +0 -1
#   [ALSA] Remove snd-ioctl32 entry
#   
#   D:2005/01/20 17:16:35
#   C:ALSA Core
#   F:core/Kconfig:1.7->1.8 
#   F:core/Makefile:1.54->1.55 
#   L:Remove the entry for snd-ioctl32.  The 32bit wrapper is built in the core
#   L:module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/Kconfig
#   2005/01/20 10:16:35+01:00 perex@suse.cz +0 -14
#   [ALSA] Remove snd-ioctl32 entry
#   
#   D:2005/01/20 17:16:35
#   C:ALSA Core
#   F:core/Kconfig:1.7->1.8 
#   F:core/Makefile:1.54->1.55 
#   L:Remove the entry for snd-ioctl32.  The 32bit wrapper is built in the core
#   L:module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:30:46+01:00 perex@suse.cz 
#   [ALSA] Export new register/unregister functions
#   
#   ALSA Core
#   Export new register/unregister functions for compat control-ioctls.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/sound.c
#   2005/01/20 10:15:37+01:00 perex@suse.cz +4 -0
#   [ALSA] Export new register/unregister functions
#   
#   D:2005/01/20 17:15:37
#   C:ALSA Core
#   F:core/sound.c:1.71->1.72 
#   L:Export new register/unregister functions for compat control-ioctls.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:29:26+01:00 perex@suse.cz 
#   [ALSA] unlocked/compat_ioctl rewrite for OSS compatible drivers
#   
#   ALSA<-OSS emulation,ALSA<-OSS sequencer
#   The ioctl handlers for OSS compatible drivers are rewritten using
#   unlocked/compat_ioctl.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/seq/oss/seq_oss.c
#   2005/01/20 10:14:45+01:00 perex@suse.cz +11 -10
#   [ALSA] unlocked/compat_ioctl rewrite for OSS compatible drivers
#   
#   D:2005/01/20 17:14:44
#   C:ALSA<-OSS emulation,ALSA<-OSS sequencer
#   F:core/oss/mixer_oss.c:1.37->1.38 
#   F:core/oss/pcm_oss.c:1.83->1.84 
#   F:core/seq/oss/seq_oss.c:1.17->1.18 
#   L:The ioctl handlers for OSS compatible drivers are rewritten using
#   L:unlocked/compat_ioctl.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/oss/pcm_oss.c
#   2005/01/20 10:14:45+01:00 perex@suse.cz +9 -13
#   [ALSA] unlocked/compat_ioctl rewrite for OSS compatible drivers
#   
#   D:2005/01/20 17:14:44
#   C:ALSA<-OSS emulation,ALSA<-OSS sequencer
#   F:core/oss/mixer_oss.c:1.37->1.38 
#   F:core/oss/pcm_oss.c:1.83->1.84 
#   F:core/seq/oss/seq_oss.c:1.17->1.18 
#   L:The ioctl handlers for OSS compatible drivers are rewritten using
#   L:unlocked/compat_ioctl.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/oss/mixer_oss.c
#   2005/01/20 10:14:44+01:00 perex@suse.cz +11 -10
#   [ALSA] unlocked/compat_ioctl rewrite for OSS compatible drivers
#   
#   D:2005/01/20 17:14:44
#   C:ALSA<-OSS emulation,ALSA<-OSS sequencer
#   F:core/oss/mixer_oss.c:1.37->1.38 
#   F:core/oss/pcm_oss.c:1.83->1.84 
#   F:core/seq/oss/seq_oss.c:1.17->1.18 
#   L:The ioctl handlers for OSS compatible drivers are rewritten using
#   L:unlocked/compat_ioctl.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:28:06+01:00 perex@suse.cz 
#   [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API
#   
#   HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
#   The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
#   using unlocked/compat_ioctl.
#   The 32bit wrapper is merged to the core module.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/timer_compat.c
#   2005/01/20 19:16:31+01:00 perex@suse.cz +119 -0
#   [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API
#   
#   D:2005/01/20 17:13:40
#   C:HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
#   F:core/hwdep.c:1.28->1.29 
#   F:core/hwdep_compat.c:INITIAL->1.1 
#   F:core/rawmidi.c:1.51->1.52 
#   F:core/rawmidi_compat.c:INITIAL->1.1 
#   F:core/timer.c:1.63->1.64 
#   F:core/timer_compat.c:INITIAL->1.1 
#   F:core/seq/seq_clientmgr.c:1.40->1.41 
#   F:core/seq/seq_compat.c:INITIAL->1.1 
#   F:include/hwdep.h:1.6->1.7 
#   L:The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
#   L:using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/seq/seq_compat.c
#   2005/01/20 19:17:01+01:00 perex@suse.cz +137 -0
#   [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API
#   
#   D:2005/01/20 17:13:40
#   C:HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
#   F:core/hwdep.c:1.28->1.29 
#   F:core/hwdep_compat.c:INITIAL->1.1 
#   F:core/rawmidi.c:1.51->1.52 
#   F:core/rawmidi_compat.c:INITIAL->1.1 
#   F:core/timer.c:1.63->1.64 
#   F:core/timer_compat.c:INITIAL->1.1 
#   F:core/seq/seq_clientmgr.c:1.40->1.41 
#   F:core/seq/seq_compat.c:INITIAL->1.1 
#   F:include/hwdep.h:1.6->1.7 
#   L:The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
#   L:using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/rawmidi_compat.c
#   2005/01/20 19:16:21+01:00 perex@suse.cz +120 -0
#   [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API
#   
#   D:2005/01/20 17:13:40
#   C:HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
#   F:core/hwdep.c:1.28->1.29 
#   F:core/hwdep_compat.c:INITIAL->1.1 
#   F:core/rawmidi.c:1.51->1.52 
#   F:core/rawmidi_compat.c:INITIAL->1.1 
#   F:core/timer.c:1.63->1.64 
#   F:core/timer_compat.c:INITIAL->1.1 
#   F:core/seq/seq_clientmgr.c:1.40->1.41 
#   F:core/seq/seq_compat.c:INITIAL->1.1 
#   F:include/hwdep.h:1.6->1.7 
#   L:The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
#   L:using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/timer_compat.c
#   2005/01/20 19:16:31+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/core/timer_compat.c
# 
# sound/core/timer.c
#   2005/01/20 10:13:40+01:00 perex@suse.cz +9 -14
#   [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API
#   
#   D:2005/01/20 17:13:40
#   C:HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
#   F:core/hwdep.c:1.28->1.29 
#   F:core/hwdep_compat.c:INITIAL->1.1 
#   F:core/rawmidi.c:1.51->1.52 
#   F:core/rawmidi_compat.c:INITIAL->1.1 
#   F:core/timer.c:1.63->1.64 
#   F:core/timer_compat.c:INITIAL->1.1 
#   F:core/seq/seq_clientmgr.c:1.40->1.41 
#   F:core/seq/seq_compat.c:INITIAL->1.1 
#   F:include/hwdep.h:1.6->1.7 
#   L:The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
#   L:using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/seq/seq_compat.c
#   2005/01/20 19:17:01+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/core/seq/seq_compat.c
# 
# sound/core/seq/seq_clientmgr.c
#   2005/01/20 10:13:41+01:00 perex@suse.cz +9 -9
#   [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API
#   
#   D:2005/01/20 17:13:40
#   C:HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
#   F:core/hwdep.c:1.28->1.29 
#   F:core/hwdep_compat.c:INITIAL->1.1 
#   F:core/rawmidi.c:1.51->1.52 
#   F:core/rawmidi_compat.c:INITIAL->1.1 
#   F:core/timer.c:1.63->1.64 
#   F:core/timer_compat.c:INITIAL->1.1 
#   F:core/seq/seq_clientmgr.c:1.40->1.41 
#   F:core/seq/seq_compat.c:INITIAL->1.1 
#   F:include/hwdep.h:1.6->1.7 
#   L:The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
#   L:using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/rawmidi_compat.c
#   2005/01/20 19:16:21+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/core/rawmidi_compat.c
# 
# sound/core/rawmidi.c
#   2005/01/20 10:13:40+01:00 perex@suse.cz +13 -14
#   [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API
#   
#   D:2005/01/20 17:13:40
#   C:HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
#   F:core/hwdep.c:1.28->1.29 
#   F:core/hwdep_compat.c:INITIAL->1.1 
#   F:core/rawmidi.c:1.51->1.52 
#   F:core/rawmidi_compat.c:INITIAL->1.1 
#   F:core/timer.c:1.63->1.64 
#   F:core/timer_compat.c:INITIAL->1.1 
#   F:core/seq/seq_clientmgr.c:1.40->1.41 
#   F:core/seq/seq_compat.c:INITIAL->1.1 
#   F:include/hwdep.h:1.6->1.7 
#   L:The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
#   L:using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/hwdep.c
#   2005/01/20 10:13:40+01:00 perex@suse.cz +11 -14
#   [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API
#   
#   D:2005/01/20 17:13:40
#   C:HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
#   F:core/hwdep.c:1.28->1.29 
#   F:core/hwdep_compat.c:INITIAL->1.1 
#   F:core/rawmidi.c:1.51->1.52 
#   F:core/rawmidi_compat.c:INITIAL->1.1 
#   F:core/timer.c:1.63->1.64 
#   F:core/timer_compat.c:INITIAL->1.1 
#   F:core/seq/seq_clientmgr.c:1.40->1.41 
#   F:core/seq/seq_compat.c:INITIAL->1.1 
#   F:include/hwdep.h:1.6->1.7 
#   L:The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
#   L:using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# include/sound/hwdep.h
#   2005/01/20 10:13:41+01:00 perex@suse.cz +1 -0
#   [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API
#   
#   D:2005/01/20 17:13:40
#   C:HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
#   F:core/hwdep.c:1.28->1.29 
#   F:core/hwdep_compat.c:INITIAL->1.1 
#   F:core/rawmidi.c:1.51->1.52 
#   F:core/rawmidi_compat.c:INITIAL->1.1 
#   F:core/timer.c:1.63->1.64 
#   F:core/timer_compat.c:INITIAL->1.1 
#   F:core/seq/seq_clientmgr.c:1.40->1.41 
#   F:core/seq/seq_compat.c:INITIAL->1.1 
#   F:include/hwdep.h:1.6->1.7 
#   L:The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
#   L:using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/hwdep_compat.c
#   2005/01/20 19:16:12+01:00 perex@suse.cz +77 -0
#   [ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API
#   
#   D:2005/01/20 17:13:40
#   C:HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
#   F:core/hwdep.c:1.28->1.29 
#   F:core/hwdep_compat.c:INITIAL->1.1 
#   F:core/rawmidi.c:1.51->1.52 
#   F:core/rawmidi_compat.c:INITIAL->1.1 
#   F:core/timer.c:1.63->1.64 
#   F:core/timer_compat.c:INITIAL->1.1 
#   F:core/seq/seq_clientmgr.c:1.40->1.41 
#   F:core/seq/seq_compat.c:INITIAL->1.1 
#   F:include/hwdep.h:1.6->1.7 
#   L:The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
#   L:using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/hwdep_compat.c
#   2005/01/20 19:16:12+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/core/hwdep_compat.c
# 
# ChangeSet
#   2005/01/20 20:26:43+01:00 perex@suse.cz 
#   [ALSA] unlocked/compat_ioctl rewrite for PCM API
#   
#   PCM Midlevel
#   The ioctl handler for PCM API is rewritten using unlocked/compat_ioctl.
#   The 32bit wrapper is merged to the core module.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/pcm_native.c
#   2005/01/20 10:11:46+01:00 perex@suse.cz +17 -18
#   [ALSA] unlocked/compat_ioctl rewrite for PCM API
#   
#   D:2005/01/20 17:11:46
#   C:PCM Midlevel
#   F:core/pcm.c:1.49->1.50 
#   F:core/pcm_compat.c:INITIAL->1.1 
#   F:core/pcm_native.c:1.111->1.112 
#   L:The ioctl handler for PCM API is rewritten using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/pcm.c
#   2005/01/20 10:11:46+01:00 perex@suse.cz +2 -0
#   [ALSA] unlocked/compat_ioctl rewrite for PCM API
#   
#   D:2005/01/20 17:11:46
#   C:PCM Midlevel
#   F:core/pcm.c:1.49->1.50 
#   F:core/pcm_compat.c:INITIAL->1.1 
#   F:core/pcm_native.c:1.111->1.112 
#   L:The ioctl handler for PCM API is rewritten using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/pcm_compat.c
#   2005/01/20 19:15:57+01:00 perex@suse.cz +513 -0
#   [ALSA] unlocked/compat_ioctl rewrite for PCM API
#   
#   D:2005/01/20 17:11:46
#   C:PCM Midlevel
#   F:core/pcm.c:1.49->1.50 
#   F:core/pcm_compat.c:INITIAL->1.1 
#   F:core/pcm_native.c:1.111->1.112 
#   L:The ioctl handler for PCM API is rewritten using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/pcm_compat.c
#   2005/01/20 19:15:57+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/core/pcm_compat.c
# 
# ChangeSet
#   2005/01/20 20:25:19+01:00 perex@suse.cz 
#   [ALSA] unlocked/compat_ioctl rewrite for control API
#   
#   Control Midlevel
#   ioctl handler for control API is rewritten using unlocked/compat_ioctl.
#   The 32bit wrapper is merged to the core module.
#   
#   Added a new register/unregister function for compat control ioctls.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/control.c
#   2005/01/20 10:10:23+01:00 perex@suse.cz +95 -81
#   [ALSA] unlocked/compat_ioctl rewrite for control API
#   
#   D:2005/01/20 17:10:23
#   C:Control Midlevel
#   F:core/control.c:1.55->1.56 
#   F:core/control_compat.c:INITIAL->1.1 
#   F:include/control.h:1.11->1.12 
#   L:ioctl handler for control API is rewritten using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   L:
#   L:Added a new register/unregister function for compat control ioctls.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# include/sound/control.h
#   2005/01/20 10:10:24+01:00 perex@suse.cz +7 -0
#   [ALSA] unlocked/compat_ioctl rewrite for control API
#   
#   D:2005/01/20 17:10:23
#   C:Control Midlevel
#   F:core/control.c:1.55->1.56 
#   F:core/control_compat.c:INITIAL->1.1 
#   F:include/control.h:1.11->1.12 
#   L:ioctl handler for control API is rewritten using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   L:
#   L:Added a new register/unregister function for compat control ioctls.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/control_compat.c
#   2005/01/20 19:15:43+01:00 perex@suse.cz +412 -0
#   [ALSA] unlocked/compat_ioctl rewrite for control API
#   
#   D:2005/01/20 17:10:23
#   C:Control Midlevel
#   F:core/control.c:1.55->1.56 
#   F:core/control_compat.c:INITIAL->1.1 
#   F:include/control.h:1.11->1.12 
#   L:ioctl handler for control API is rewritten using unlocked/compat_ioctl.
#   L:The 32bit wrapper is merged to the core module.
#   L:
#   L:Added a new register/unregister function for compat control ioctls.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/control_compat.c
#   2005/01/20 19:15:43+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/core/control_compat.c
# 
# ChangeSet
#   2005/01/20 20:23:54+01:00 perex@suse.cz 
#   [ALSA] Add Intel HDA driver
#   
#   Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   HDA Intel driver
#   Added a new Intel High-Definition audio driver.
#   The driver consists of two separate modules: the generic support
#   module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   snd-azx in the ALSA 1.0.8 rlease.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/patch_realtek.c
#   2005/01/20 19:15:31+01:00 perex@suse.cz +1174 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/patch_cmedia.c
#   2005/01/20 19:15:26+01:00 perex@suse.cz +614 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/hda_proc.c
#   2005/01/20 19:15:21+01:00 perex@suse.cz +298 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/hda_patch.h
#   2005/01/20 19:15:17+01:00 perex@suse.cz +14 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/hda_local.h
#   2005/01/20 19:15:12+01:00 perex@suse.cz +159 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/hda_intel.c
#   2005/01/20 19:15:07+01:00 perex@suse.cz +1449 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/hda_generic.c
#   2005/01/20 19:15:01+01:00 perex@suse.cz +898 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/hda_codec.h
#   2005/01/20 19:14:56+01:00 perex@suse.cz +602 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/hda_codec.c
#   2005/01/20 19:14:51+01:00 perex@suse.cz +1731 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/Makefile
#   2005/01/20 19:14:46+01:00 perex@suse.cz +7 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/hda/patch_realtek.c
#   2005/01/20 19:15:31+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/pci/hda/patch_realtek.c
# 
# sound/pci/hda/patch_cmedia.c
#   2005/01/20 19:15:26+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/pci/hda/patch_cmedia.c
# 
# sound/pci/hda/hda_proc.c
#   2005/01/20 19:15:21+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/pci/hda/hda_proc.c
# 
# sound/pci/hda/hda_patch.h
#   2005/01/20 19:15:17+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/pci/hda/hda_patch.h
# 
# sound/pci/hda/hda_local.h
#   2005/01/20 19:15:12+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/pci/hda/hda_local.h
# 
# sound/pci/hda/hda_intel.c
#   2005/01/20 19:15:07+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/pci/hda/hda_intel.c
# 
# sound/pci/hda/hda_generic.c
#   2005/01/20 19:15:01+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/pci/hda/hda_generic.c
# 
# sound/pci/hda/hda_codec.h
#   2005/01/20 19:14:56+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/pci/hda/hda_codec.h
# 
# sound/pci/hda/hda_codec.c
#   2005/01/20 19:14:51+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/pci/hda/hda_codec.c
# 
# sound/pci/hda/Makefile
#   2005/01/20 19:14:46+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/sound/pci/hda/Makefile
# 
# sound/pci/Makefile
#   2005/01/20 08:02:28+01:00 perex@suse.cz +1 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/Kconfig
#   2005/01/20 08:02:28+01:00 perex@suse.cz +11 -1
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# Documentation/sound/alsa/ALSA-Configuration.txt
#   2005/01/20 08:02:27+01:00 perex@suse.cz +31 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# Documentation/sound/alsa/hda_codec.txt
#   2005/01/20 19:14:31+01:00 perex@suse.cz +299 -0
#   [ALSA] Add Intel HDA driver
#   
#   D:2005/01/20 15:02:27
#   C:Documentation,PCI drivers,HDA generic driver,HDA Codec driver
#   C:HDA Intel driver
#   F:Documentation/ALSA-Configuration.txt:1.63->1.64 
#   F:Documentation/hda_codec.txt:INITIAL->1.1 
#   F:pci/Kconfig:1.39->1.40 
#   F:pci/Makefile:1.19->1.20 
#   F:pci/hda/Makefile:INITIAL->1.1 
#   F:pci/hda/hda_codec.c:INITIAL->1.1 
#   F:pci/hda/hda_codec.h:INITIAL->1.1 
#   F:pci/hda/hda_generic.c:INITIAL->1.1 
#   F:pci/hda/hda_intel.c:INITIAL->1.1 
#   F:pci/hda/hda_local.h:INITIAL->1.1 
#   F:pci/hda/hda_patch.h:INITIAL->1.1 
#   F:pci/hda/hda_proc.c:INITIAL->1.1 
#   F:pci/hda/patch_cmedia.c:INITIAL->1.1 
#   F:pci/hda/patch_realtek.c:INITIAL->1.1 
#   L:Added a new Intel High-Definition audio driver.
#   L:The driver consists of two separate modules: the generic support
#   L:module for HD codecs (snd-hda-codec), and the driver for Intel ICH6/7
#   L:chipset (snd-hda-intel).  The snd-hda-intel was called formerly
#   L:snd-azx in the ALSA 1.0.8 rlease.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# Documentation/sound/alsa/hda_codec.txt
#   2005/01/20 19:14:31+01:00 perex@suse.cz +0 -0
#   BitKeeper file /home/perex/bk/linux-sound/work/Documentation/sound/alsa/hda_codec.txt
# 
# ChangeSet
#   2005/01/20 20:22:29+01:00 perex@suse.cz 
#   [ALSA] Enable HP jack sense for FSC Scenic-W
#   
#   AC97 Codec
#   Enable 'Headphone Jack Sense' control on FSC Scenic-W as default, too.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/ac97/ac97_patch.c
#   2005/01/20 04:43:19+01:00 perex@suse.cz +1 -0
#   [ALSA] Enable HP jack sense for FSC Scenic-W
#   
#   D:2005/01/20 11:43:19
#   C:AC97 Codec
#   F:pci/ac97/ac97_patch.c:1.69->1.70 
#   L:Enable 'Headphone Jack Sense' control on FSC Scenic-W as default, too.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:21:09+01:00 perex@suse.cz 
#   [ALSA] Add quirk for HP nc8000
#   
#   Intel8x0 driver
#   Added ac97 quirk for HP nc8000.
#   The list is sorted again.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/intel8x0.c
#   2005/01/20 04:41:50+01:00 perex@suse.cz +10 -4
#   [ALSA] Add quirk for HP nc8000
#   
#   D:2005/01/20 11:41:50
#   C:Intel8x0 driver
#   F:pci/intel8x0.c:1.189->1.190 
#   L:Added ac97 quirk for HP nc8000.
#   L:The list is sorted again.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:19:48+01:00 perex@suse.cz 
#   [ALSA] Add quirk for HP pavilion ZV5030US
#   
#   ATIIXP driver
#   Added ac97 quirk for HP Pavilion ZV5030US to bind the control with
#   mute-LED.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/atiixp.c
#   2005/01/19 09:43:06+01:00 perex@suse.cz +6 -0
#   [ALSA] Add quirk for HP pavilion ZV5030US
#   
#   D:2005/01/19 16:43:06
#   C:ATIIXP driver
#   F:pci/atiixp.c:1.30->1.31 
#   L:Added ac97 quirk for HP Pavilion ZV5030US to bind the control with
#   L:mute-LED.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:18:30+01:00 perex@suse.cz 
#   [ALSA] Simplify the general ac97 volume/switch callback
#   
#   AC97 Codec
#   Simplified the control callbacks of general AC97 volumes/switches.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/ac97/ac97_local.h
#   2005/01/19 05:03:51+01:00 perex@suse.cz +2 -4
#   [ALSA] Simplify the general ac97 volume/switch callback
#   
#   D:2005/01/19 12:03:49
#   C:AC97 Codec
#   F:pci/ac97/ac97_codec.c:1.168->1.169 
#   F:pci/ac97/ac97_local.h:1.11->1.12 
#   L:Simplified the control callbacks of general AC97 volumes/switches.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/ac97/ac97_codec.c
#   2005/01/19 05:03:49+01:00 perex@suse.cz +36 -37
#   [ALSA] Simplify the general ac97 volume/switch callback
#   
#   D:2005/01/19 12:03:49
#   C:AC97 Codec
#   F:pci/ac97/ac97_codec.c:1.168->1.169 
#   F:pci/ac97/ac97_local.h:1.11->1.12 
#   L:Simplified the control callbacks of general AC97 volumes/switches.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:17:15+01:00 perex@suse.cz 
#   [ALSA] Add missing inclusion of linux/device.h
#   
#   Digigram VX core,Digigram VX222 driver,Digigram VX Pocket driver
#   Added the missing inclusion of <linux/device.h>
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pcmcia/vx/vxp_ops.c
#   2005/01/19 04:36:30+01:00 perex@suse.cz +1 -0
#   [ALSA] Add missing inclusion of linux/device.h
#   
#   D:2005/01/19 11:36:29
#   C:Digigram VX core,Digigram VX222 driver,Digigram VX Pocket driver
#   F:drivers/vx/vx_core.c:1.12->1.13 
#   F:drivers/vx/vx_hwdep.c:1.4->1.5 
#   F:pci/vx222/vx222_ops.c:1.8->1.9 
#   F:pcmcia/vx/vxp_ops.c:1.5->1.6 
#   L:Added the missing inclusion of <linux/device.h>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/vx222/vx222_ops.c
#   2005/01/19 04:36:30+01:00 perex@suse.cz +1 -0
#   [ALSA] Add missing inclusion of linux/device.h
#   
#   D:2005/01/19 11:36:29
#   C:Digigram VX core,Digigram VX222 driver,Digigram VX Pocket driver
#   F:drivers/vx/vx_core.c:1.12->1.13 
#   F:drivers/vx/vx_hwdep.c:1.4->1.5 
#   F:pci/vx222/vx222_ops.c:1.8->1.9 
#   F:pcmcia/vx/vxp_ops.c:1.5->1.6 
#   L:Added the missing inclusion of <linux/device.h>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/drivers/vx/vx_hwdep.c
#   2005/01/19 04:36:29+01:00 perex@suse.cz +1 -0
#   [ALSA] Add missing inclusion of linux/device.h
#   
#   D:2005/01/19 11:36:29
#   C:Digigram VX core,Digigram VX222 driver,Digigram VX Pocket driver
#   F:drivers/vx/vx_core.c:1.12->1.13 
#   F:drivers/vx/vx_hwdep.c:1.4->1.5 
#   F:pci/vx222/vx222_ops.c:1.8->1.9 
#   F:pcmcia/vx/vxp_ops.c:1.5->1.6 
#   L:Added the missing inclusion of <linux/device.h>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/drivers/vx/vx_core.c
#   2005/01/19 04:36:29+01:00 perex@suse.cz +1 -0
#   [ALSA] Add missing inclusion of linux/device.h
#   
#   D:2005/01/19 11:36:29
#   C:Digigram VX core,Digigram VX222 driver,Digigram VX Pocket driver
#   F:drivers/vx/vx_core.c:1.12->1.13 
#   F:drivers/vx/vx_hwdep.c:1.4->1.5 
#   F:pci/vx222/vx222_ops.c:1.8->1.9 
#   F:pcmcia/vx/vxp_ops.c:1.5->1.6 
#   L:Added the missing inclusion of <linux/device.h>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:15:52+01:00 perex@suse.cz 
#   [ALSA] Add workaround for buggy ATI IXP hardwares
#   
#   ATIIXP-modem driver
#   Added a workaround for buggy ATI IXP hardwares which returns
#   bogus DMA pointer register value.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/atiixp_modem.c
#   2005/01/19 04:35:04+01:00 perex@suse.cz +11 -12
#   [ALSA] Add workaround for buggy ATI IXP hardwares
#   
#   D:2005/01/19 11:35:04
#   C:ATIIXP-modem driver
#   F:pci/atiixp_modem.c:1.12->1.13 
#   L:Added a workaround for buggy ATI IXP hardwares which returns
#   L:bogus DMA pointer register value.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:14:34+01:00 perex@suse.cz 
#   [ALSA] Add support for Chaintech 9CJS
#   
#   ICE1712 driver
#   Added the support for Chaintech 9CJS by Delmaire Maxime.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/ice1712/vt1720_mobo.h
#   2005/01/19 04:32:46+01:00 perex@suse.cz +3 -1
#   [ALSA] Add support for Chaintech 9CJS
#   
#   D:2005/01/19 11:32:46
#   C:ICE1712 driver
#   F:pci/ice1712/vt1720_mobo.c:1.2->1.3 
#   F:pci/ice1712/vt1720_mobo.h:1.2->1.3 
#   L:Added the support for Chaintech 9CJS by Delmaire Maxime.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/ice1712/vt1720_mobo.c
#   2005/01/19 04:32:46+01:00 perex@suse.cz +9 -0
#   [ALSA] Add support for Chaintech 9CJS
#   
#   D:2005/01/19 11:32:46
#   C:ICE1712 driver
#   F:pci/ice1712/vt1720_mobo.c:1.2->1.3 
#   F:pci/ice1712/vt1720_mobo.h:1.2->1.3 
#   L:Added the support for Chaintech 9CJS by Delmaire Maxime.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:13:15+01:00 perex@suse.cz 
#   [ALSA] AK4117 code - fixed cosmetic typos
#   
#   AK4117 receiver
#   
#   
#   Signed-off-by: Jaroslav Kysela <perex@suse.cz>
# 
# include/sound/ak4117.h
#   2005/01/18 08:41:15+01:00 perex@suse.cz +3 -3
#   [ALSA] AK4117 code - fixed cosmetic typos
#   
#   D:2005/01/18 15:41:15
#   C:AK4117 receiver
#   F:include/ak4117.h:1.1->1.2 
#   L:
#   Signed-off-by: Jaroslav Kysela <perex@suse.cz>
# 
# ChangeSet
#   2005/01/20 20:11:59+01:00 perex@suse.cz 
#   [ALSA] don't use broken legacy interfaces on M-Audio Quattro/Omnistudio
#   
#   USB generic driver
#   Interfaces 0-2 of M-Audio Quattro/Omnistudio devices duplicate functionality
#   of interfaces 3-5 and cause errors when used with those.  Add a quirk to
#   tell the driver not to use them.
#   
#   Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
# 
# sound/usb/usbquirks.h
#   2005/01/17 10:41:38+01:00 perex@suse.cz +70 -5
#   [ALSA] don't use broken legacy interfaces on M-Audio Quattro/Omnistudio
#   
#   D:2005/01/17 17:41:34
#   C:USB generic driver
#   F:usb/usbaudio.c:1.113->1.114 
#   F:usb/usbaudio.h:1.35->1.36 
#   F:usb/usbquirks.h:1.38->1.39 
#   L:Interfaces 0-2 of M-Audio Quattro/Omnistudio devices duplicate functionality
#   L:of interfaces 3-5 and cause errors when used with those.  Add a quirk to
#   L:tell the driver not to use them.
#   Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
# 
# sound/usb/usbaudio.h
#   2005/01/17 10:41:38+01:00 perex@suse.cz +3 -0
#   [ALSA] don't use broken legacy interfaces on M-Audio Quattro/Omnistudio
#   
#   D:2005/01/17 17:41:34
#   C:USB generic driver
#   F:usb/usbaudio.c:1.113->1.114 
#   F:usb/usbaudio.h:1.35->1.36 
#   F:usb/usbquirks.h:1.38->1.39 
#   L:Interfaces 0-2 of M-Audio Quattro/Omnistudio devices duplicate functionality
#   L:of interfaces 3-5 and cause errors when used with those.  Add a quirk to
#   L:tell the driver not to use them.
#   Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
# 
# sound/usb/usbaudio.c
#   2005/01/17 10:41:34+01:00 perex@suse.cz +2 -0
#   [ALSA] don't use broken legacy interfaces on M-Audio Quattro/Omnistudio
#   
#   D:2005/01/17 17:41:34
#   C:USB generic driver
#   F:usb/usbaudio.c:1.113->1.114 
#   F:usb/usbaudio.h:1.35->1.36 
#   F:usb/usbquirks.h:1.38->1.39 
#   L:Interfaces 0-2 of M-Audio Quattro/Omnistudio devices duplicate functionality
#   L:of interfaces 3-5 and cause errors when used with those.  Add a quirk to
#   L:tell the driver not to use them.
#   Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
# 
# ChangeSet
#   2005/01/20 20:10:41+01:00 perex@suse.cz 
#   [ALSA] Fix silent output on some machines with AD1981x codecs
#   
#   AC97 Codec
#   Fixed the default state of 'Headphone Jack Sense' switch on AD1981x
#   codecs.  Setting this on affects the output of some machines (e.g.
#   Thindpads).
#   
#   The default value is set on only hardwares which are known to work.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/ac97/ac97_patch.c
#   2005/01/17 06:47:20+01:00 perex@suse.cz +14 -2
#   [ALSA] Fix silent output on some machines with AD1981x codecs
#   
#   D:2005/01/17 13:47:20
#   C:AC97 Codec
#   F:pci/ac97/ac97_patch.c:1.68->1.69 
#   L:Fixed the default state of 'Headphone Jack Sense' switch on AD1981x
#   L:codecs.  Setting this on affects the output of some machines (e.g.
#   L:Thindpads).
#   L:
#   L:The default value is set on only hardwares which are known to work.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:09:28+01:00 perex@suse.cz 
#   [ALSA] AC'97 Audio support for Intel ICH7
#   
#   Intel8x0 driver
#   This patch adds the ICH7 AC'97 DID the the intel8x0.c AC'97 audio
#   driver. This patch was build against 2.6.11-rc1.
#   
#   Signed-off-by: Jason Gaston <Jason.d.gaston@intel.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/intel8x0.c
#   2005/01/17 04:29:18+01:00 perex@suse.cz +6 -0
#   [ALSA] AC'97 Audio support for Intel ICH7
#   
#   D:2005/01/17 11:29:18
#   C:Intel8x0 driver
#   F:pci/intel8x0.c:1.188->1.189 
#   L:This patch adds the ICH7 AC'97 DID the the intel8x0.c AC'97 audio
#   L:driver. This patch was build against 2.6.11-rc1.
#   Signed-off-by: Jason Gaston <Jason.d.gaston@intel.com>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:08:09+01:00 perex@suse.cz 
#   [ALSA] Fix compilation on big-endian arch
#   
#   RME HDSP driver
#   Fixed typo in the code for big-endian architectures.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/pci/rme9652/hdsp.c
#   2005/01/14 12:52:06+01:00 perex@suse.cz +1 -1
#   [ALSA] Fix compilation on big-endian arch
#   
#   D:2005/01/14 19:52:06
#   C:RME HDSP driver
#   F:pci/rme9652/hdsp.c:1.78->1.79 
#   L:Fixed typo in the code for big-endian architectures.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:07:01+01:00 perex@suse.cz 
#   [ALSA] Show firmware loading state in proc file
#   
#   Digigram VX core
#   Show the firmware loading state in proc file.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/drivers/vx/vx_core.c
#   2005/01/14 10:41:36+01:00 perex@suse.cz +4 -0
#   [ALSA] Show firmware loading state in proc file
#   
#   D:2005/01/14 17:41:36
#   C:Digigram VX core
#   F:drivers/vx/vx_core.c:1.11->1.12 
#   L:Show the firmware loading state in proc file.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:05:33+01:00 perex@suse.cz 
#   [ALSA] Fix struct size mismatch
#   
#   IOCTL32 emulation
#   Fixed the struct size mismatch - should work on SPARC64 now, too.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/ioctl32/ioctl32.c
#   2005/01/14 04:15:16+01:00 perex@suse.cz +1 -1
#   [ALSA] Fix struct size mismatch
#   
#   D:2005/01/14 11:15:16
#   C:IOCTL32 emulation
#   F:core/ioctl32/ioctl32.c:1.28->1.29 
#   L:Fixed the struct size mismatch - should work on SPARC64 now, too.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:04:23+01:00 perex@suse.cz 
#   [ALSA] Add missing FORWARD ioctl
#   
#   IOCTL32 emulation
#   Added the missing FORWARD ioctl.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/ioctl32/pcm32.c
#   2005/01/14 03:51:12+01:00 perex@suse.cz +3 -0
#   [ALSA] Add missing FORWARD ioctl
#   
#   D:2005/01/14 10:51:12
#   C:IOCTL32 emulation
#   F:core/ioctl32/pcm32.c:1.23->1.24 
#   L:Added the missing FORWARD ioctl.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:03:02+01:00 perex@suse.cz 
#   [ALSA] Fix struct alignment on PPC64
#   
#   IOCTL32 emulation
#   Fixed the struct size mismatch (due to alignment) of
#   snd_ctl_elem_value_t for PPC64.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/ioctl32/ioctl32.c
#   2005/01/14 03:50:29+01:00 perex@suse.cz +3 -0
#   [ALSA] Fix struct alignment on PPC64
#   
#   D:2005/01/14 10:50:29
#   C:IOCTL32 emulation
#   F:core/ioctl32/ioctl32.c:1.27->1.28 
#   L:Fixed the struct size mismatch (due to alignment) of
#   L:snd_ctl_elem_value_t for PPC64.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 20:01:42+01:00 perex@suse.cz 
#   [ALSA] fix typo
#   
#   Documentation
#   
#   
#   Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
# 
# Documentation/sound/alsa/ALSA-Configuration.txt
#   2005/01/14 03:15:32+01:00 perex@suse.cz +1 -1
#   [ALSA] fix typo
#   
#   D:2005/01/14 10:15:32
#   C:Documentation
#   F:Documentation/ALSA-Configuration.txt:1.62->1.63 
#   L:
#   Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
# 
# ChangeSet
#   2005/01/20 20:00:22+01:00 perex@suse.cz 
#   [ALSA] Fix typos in doc
#   
#   Documentation
#   Fixed typos in the document by Kirill Smelkov <kirr@mns.spb.ru>
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
#   2005/01/13 10:29:03+01:00 perex@suse.cz +16 -13
#   [ALSA] Fix typos in doc
#   
#   D:2005/01/13 17:29:03
#   C:Documentation
#   F:Documentation/DocBook/writing-an-alsa-driver.tmpl:1.46->1.47 
#   L:Fixed typos in the document by Kirill Smelkov <kirr@mns.spb.ru>
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# ChangeSet
#   2005/01/20 19:58:45+01:00 perex@suse.cz 
#   ALSA CVS update
#   PCM Midlevel
#   Sumary: Fix comment of snd_pcm_lib_malloc_pages()
#   
#   Fixed comment of snd_pcm_lib_malloc_pages() by
#   Kirill Smelkov <kirr@mns.spb.ru>.
#   
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
# sound/core/pcm_memory.c
#   2005/01/13 10:27:29+01:00 perex@suse.cz +1 -1
#   ALSA CVS update
#   D:2005/01/13 17:27:29
#   C:PCM Midlevel
#   F:core/pcm_memory.c:1.33->1.34 
#   L:Sumary: Fix comment of snd_pcm_lib_malloc_pages()
#   L:
#   L:Fixed comment of snd_pcm_lib_malloc_pages() by
#   L:Kirill Smelkov <kirr@mns.spb.ru>.
#   Signed-off-by: Takashi Iwai <tiwai@suse.de>
# 
diff -Nru a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
--- a/Documentation/sound/alsa/ALSA-Configuration.txt	2005-02-09 18:36:40 -08:00
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt	2005-02-09 18:36:40 -08:00
@@ -599,6 +599,37 @@
 
     Module supports up to 8 cards and autoprobe.
     
+  Module snd-hda-intel
+  --------------------
+
+    Module for Intel HD Audio (ICH6, ICH6M, ICH7)
+
+    model	- force the model name
+
+    Module supports up to 8 cards.
+
+    Each codec may have a model table for different configurations.
+    If your machine isn't listed there, the default (usually minimal)
+    configuration is set up.  You can pass "model=<name>" option to
+    specify a certain model in such a case.  There are different
+    models depending on the codec chip.
+
+	  Model name	Description
+	  ----------    -----------
+	ALC880
+	  3stack	3-jack in back and a headphone out
+	  3stack-digout	3-jack in back, a HP out and a SPDIF out
+	  5stack	5-jack in back, 2-jack in front
+	  5stack-digout	5-jack in back, 2-jack in front, a SPDIF out
+	  w810		3-jack
+
+	CMI9880
+	  minimal	3-jack in back
+	  min_fp	3-jack in back, 2-jack in front
+	  full		6-jack in back, 2-jack in front
+	  full_dig	6-jack in back, 2-jack in front, SPDIF I/O
+	  allout	5-jack in back, 2-jack in front, SPDIF out
+
   Module snd-hdsp
   ---------------
 
@@ -689,7 +720,7 @@
                       hp_only = use headphone control as master
                       swap_hp = swap headphone and master controls
                       swap_surround = swap master and surround controls
-                      ad_shring = for AD1985, turn on OMS bit and use headphone
+                      ad_sharing = for AD1985, turn on OMS bit and use headphone
                       alc_jack = for ALC65x, turn on the jack sense mode
                       inv_eapd = inverted EAPD implementation
                       mute_led = bind EAPD bit for turning on/off mute LED
diff -Nru a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	2005-02-09 18:36:41 -08:00
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	2005-02-09 18:36:41 -08:00
@@ -110,9 +110,9 @@
       </para>
 
       <para>
-        One is the the trees provided as a tarball or via cvs from the
+        One is the trees provided as a tarball or via cvs from the
       ALSA's ftp site, and another is the 2.6 (or later) Linux kernel
-      tree. To synchronize both, the ALSA driver tree is split to
+      tree. To synchronize both, the ALSA driver tree is split into
       two different trees: alsa-kernel and alsa-driver. The former
       contains purely the source codes for the Linux 2.6 (or later)
       tree. This tree is designed only for compilation on 2.6 or
@@ -766,7 +766,7 @@
       </para>
 
       <para>
-      The ALSA interfaces like PCM or control API are define in other
+      The ALSA interfaces like PCM or control API are defined in other
       header files as <filename>&lt;sound/xxx.h&gt;</filename>.
       They have to be included after
       <filename>&lt;sound/core.h&gt;</filename>.
@@ -1103,7 +1103,7 @@
           /* release the irq */
           if (chip->irq >= 0)
                   free_irq(chip->irq, (void *)chip);
-          /* release the i/o ports */
+          /* release the i/o ports & memory */
           pci_release_regions(chip->pci);
           /* disable the PCI entry */
           pci_disable_device(chip->pci);
@@ -1314,6 +1314,7 @@
       </para>
 
       <para>
+        <!-- obsolete -->
         It will reserve the i/o port region of 8 bytes of the given
       PCI device. The returned value, chip-&gt;res_port, is allocated
       via <function>kmalloc()</function> by
@@ -1936,6 +1937,7 @@
           snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
                           &snd_mychip_capture_ops);
           /* pre-allocation of buffers */
+          /* NOTE: this may fail */
           snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                                 snd_dma_pci_data(chip->pci),
                                                 64*1024, 64*1024);
@@ -1950,7 +1952,7 @@
     <section id="pcm-interface-constructor">
       <title>Constructor</title>
       <para>
-        A pcm instance is allocated <function>snd_pcm_new()</function>
+        A pcm instance is allocated by <function>snd_pcm_new()</function>
       function. It would be better to create a constructor for pcm,
       namely, 
 
@@ -2235,7 +2237,8 @@
 	unsigned char *dma_area;	/* DMA area */
 	dma_addr_t dma_addr;		/* physical bus address (not accessible from main CPU) */
 	size_t dma_bytes;		/* size of DMA area */
-	void *dma_private;		/* private DMA data for the memory allocator */
+
+	struct snd_dma_buffer *dma_buffer_p;	/* allocated buffer */
 
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
 	/* -- OSS things -- */
@@ -2250,7 +2253,7 @@
 	<para>
 	  For the operators (callbacks) of each sound driver, most of
 	these records are supposed to be read-only.  Only the PCM
-	middle-layer changes / updates these info.  The excpetions are
+	middle-layer changes / updates these info.  The exceptions are
 	the hardware description (hw), interrupt callbacks
 	(transfer_ack_xxx), DMA buffer information, and the private
 	data.  Besides, if you use the standard buffer allocation
@@ -3250,7 +3253,7 @@
 
       <para>
         There are many different constraints.
-        Look in <filename>sound/asound.h</filename> for a complete list.
+        Look in <filename>sound/pcm.h</filename> for a complete list.
         You can even define your own constraint rules.
         For example, let's suppose my_chip can manage a substream of 1 channel
         if and only if the format is S16_LE, otherwise it supports any format
@@ -4066,7 +4069,7 @@
         Both <function>snd_ac97_write()</function> and
         <function>snd_ac97_update()</function> functions are used to
         set a value to the given register
-        (<constant>AC97_XXX</constant>). The different between them is
+        (<constant>AC97_XXX</constant>). The difference between them is
         that <function>snd_ac97_update()</function> doesn't write a
         value if the given value has been already set, while
         <function>snd_ac97_write()</function> always rewrites the
@@ -4152,8 +4155,8 @@
       <title>Proc Files</title>
       <para>
         The ALSA AC97 interface will create a proc file such as
-      <filename>/proc/asound/card0/ac97#0</filename> and
-      <filename>ac97#0regs</filename>. You can refer to these files to
+      <filename>/proc/asound/card0/codec97#0/ac97#0-0</filename> and
+      <filename>ac97#0-0+regs</filename>. You can refer to these files to
       see the current status and registers of the codec. 
       </para>
     </section>
@@ -4633,7 +4636,7 @@
         where <parameter>size</parameter> is the byte size to be
       pre-allocated and the <parameter>max</parameter> is the maximal
       size to be changed via <filename>prealloc</filename> proc file.
-      The allocator will try to get as the large area as possible
+      The allocator will try to get as large area as possible
       within the given size. 
       </para>
 
@@ -4855,7 +4858,7 @@
         If your hardware supports the page table like emu10k1 or the
       buffer descriptors like via82xx, you can use the scatter-gather
       (SG) DMA. ALSA provides an interface for handling SG-buffers.
-      The API is provided in <filename>&lt;sound/pcm_sgbuf.h&gt;</filename>. 
+      The API is provided in <filename>&lt;sound/pcm.h&gt;</filename>. 
       </para>
 
       <para>
diff -Nru a/Documentation/sound/alsa/VIA82xx-mixer.txt b/Documentation/sound/alsa/VIA82xx-mixer.txt
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/sound/alsa/VIA82xx-mixer.txt	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,8 @@
+
+				VIA82xx mixer
+				=============
+
+On many VIA82xx boards, the 'Input Source Select' mixer control does not work.
+Setting it to 'Input2' on such boards will cause recording to hang, or fail
+with EIO (input/output error) via OSS emulation.  This control should be left
+at 'Input1' for such cards.
diff -Nru a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/sound/alsa/hda_codec.txt	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,299 @@
+Notes on Universal Interface for Intel High Definition Audio Codec
+------------------------------------------------------------------
+
+Takashi Iwai <tiwai@suse.de>
+
+
+[Still a draft version]
+
+
+General
+=======
+
+The snd-hda-codec module supports the generic access function for the
+High Definition (HD) audio codecs.  It's designed to be independent
+from the controller code like ac97 codec module.  The real accessors
+from/to the controller must be implemented in the lowlevel driver.
+
+The structure of this module is similar with ac97_codec module.
+Each codec chip belongs to a bus class which communicates with the
+controller.
+
+
+Initialization of Bus Instance
+==============================
+
+The card driver has to create struct hda_bus at first.  The template
+struct should be filled and passed to the constructor:
+
+struct hda_bus_template {
+	void *private_data;
+	struct pci_dev *pci;
+	const char *modelname;
+	struct hda_bus_ops ops;
+};
+
+The card driver can set and use the private_data field to retrieve its
+own data in callback functions.  The pci field is used when the patch
+needs to check the PCI subsystem IDs, so on.  For non-PCI system, it
+doesn't have to be set, of course.
+The modelname field specifies the board's specific configuration.  The
+string is passed to the codec parser, and it depends on the parser how
+the string is used.
+These fields, private_data, pci and modelname are all optional.
+
+The ops field contains the callback functions as the following:
+
+struct hda_bus_ops {
+	int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct,
+		       unsigned int verb, unsigned int parm);
+	unsigned int (*get_response)(struct hda_codec *codec);
+	void (*private_free)(struct hda_bus *);
+};
+
+The command callback is called when the codec module needs to send a
+VERB to the controller.  It's always a single command.
+The get_response callback is called when the codec requires the answer
+for the last command.  These two callbacks are mandatory and have to
+be given.
+The last, private_free callback, is optional.  It's called in the
+destructor to release any necessary data in the lowlevel driver.
+
+The bus instance is created via snd_hda_bus_new().  You need to pass
+the card instance, the template, and the pointer to store the
+resultant bus instance.
+
+int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp,
+		    struct hda_bus **busp);
+
+It returns zero if successful.  A negative return value means any
+error during creation.
+
+
+Creation of Codec Instance
+==========================
+
+Each codec chip on the board is then created on the BUS instance.
+To create a codec instance, call snd_hda_codec_new().
+
+int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+		      struct hda_codec **codecp);
+
+The first argument is the BUS instance, the second argument is the
+address of the codec, and the last one is the pointer to store the
+resultant codec instance (can be NULL if not needed).
+
+The codec is stored in a linked list of bus instance.  You can follow
+the codec list like:
+
+	struct list_head *p;
+	struct hda_codec *codec;
+	list_for_each(p, &bus->codec_list) {
+		codec = list_entry(p, struct hda_codec, list);
+		...
+	}
+
+The codec isn't initialized at this stage properly.  The
+initialization sequence is called when the controls are built later.
+
+
+Codec Access
+============
+
+To access codec, use snd_codec_read() and snd_codec_write().
+snd_hda_param_read() is for reading parameters.
+For writing a sequence of verbs, use snd_hda_sequence_write().
+
+To retrieve the number of sub nodes connected to the given node, use
+snd_hda_get_sub_nodes().  The connection list can be obtained via
+snd_hda_get_connections() call.
+
+When an unsolicited event happens, pass the event via
+snd_hda_queue_unsol_event() so that the codec routines will process it
+later.
+
+
+(Mixer) Controls
+================
+
+To create mixer controls of all codecs, call
+snd_hda_build_controls().  It then builds the mixers and does
+initialization stuff on each codec.
+
+
+PCM Stuff
+=========
+
+snd_hda_build_pcms() gives the necessary information to create PCM
+streams.  When it's called, each codec belonging to the bus stores 
+codec->num_pcms and codec->pcm_info fields.  The num_pcms indicates
+the number of elements in pcm_info array.  The card driver is supposed
+to traverse the codec linked list, read the pcm information in
+pcm_info array, and build pcm instances according to them. 
+
+The pcm_info array contains the following record:
+
+/* PCM information for each substream */
+struct hda_pcm_stream {
+	unsigned int substreams;	/* number of substreams, 0 = not exist */
+	unsigned int channels_min;	/* min. number of channels */
+	unsigned int channels_max;	/* max. number of channels */
+	hda_nid_t nid;	/* default NID to query rates/formats/bps, or set up */
+	u32 rates;	/* supported rates */
+	u64 formats;	/* supported formats (SNDRV_PCM_FMTBIT_) */
+	unsigned int maxbps;	/* supported max. bit per sample */
+	struct hda_pcm_ops ops;
+};
+
+/* for PCM creation */
+struct hda_pcm {
+	char *name;
+	struct hda_pcm_stream stream[2];
+};
+
+The name can be passed to snd_pcm_new().  The stream field contains
+the information  for playback (SNDRV_PCM_STREAM_PLAYBACK = 0) and
+capture (SNDRV_PCM_STREAM_CAPTURE = 1) directions.  The card driver
+should pass substreams to snd_pcm_new() for the number of substreams
+to create.
+
+The channels_min, channels_max, rates and formats should be copied to
+runtime->hw record.  They and maxbps fields are used also to compute
+the format value for the HDA codec and controller.  Call
+snd_hda_calc_stream_format() to get the format value.
+
+The ops field contains the following callback functions:
+
+struct hda_pcm_ops {
+	int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		    snd_pcm_substream_t *substream);
+	int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		     snd_pcm_substream_t *substream);
+	int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		       unsigned int stream_tag, unsigned int format,
+		       snd_pcm_substream_t *substream);
+	int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		       snd_pcm_substream_t *substream);
+};
+
+All are non-NULL, so you can call them safely without NULL check.
+
+The open callback should be called in PCM open after runtime->hw is
+set up.  It may override some setting and constraints additionally.
+Similarly, the close callback should be called in the PCM close.
+
+The prepare callback should be called in PCM prepare.  This will set
+up the codec chip properly for the operation.  The cleanup should be
+called in hw_free to clean up the configuration.
+
+The caller should check the return value, at least for open and
+prepare callbacks.  When a negative value is returned, some error
+occurred.
+
+
+Proc Files
+==========
+
+Each codec dumps the widget node information in
+/proc/asound/card*/codec#* file.  This information would be really
+helpful for debugging.  Please provide its contents together with the
+bug report.
+
+
+Power Management
+================
+
+It's simple:
+Call snd_hda_suspend() in the PM suspend callback.
+Call snd_hda_resume() in the PM resume callback.
+
+
+Codec Preset (Patch)
+====================
+
+To set up and handle the codec functionality fully, each codec may
+have a codec preset (patch).  It's defined in struct hda_codec_preset:
+
+	struct hda_codec_preset {
+		unsigned int id;
+		unsigned int mask;
+		unsigned int subs;
+		unsigned int subs_mask;
+		unsigned int rev;
+		const char *name;
+		int (*patch)(struct hda_codec *codec);
+	};
+
+When the codec id and codec subsystem id match with the given id and
+subs fields bitwise (with bitmask mask and subs_mask), the callback
+patch is called.  The patch callback should initialize the codec and
+set the codec->patch_ops field.  This is defined as below:
+
+	struct hda_codec_ops {
+		int (*build_controls)(struct hda_codec *codec);
+		int (*build_pcms)(struct hda_codec *codec);
+		int (*init)(struct hda_codec *codec);
+		void (*free)(struct hda_codec *codec);
+		void (*unsol_event)(struct hda_codec *codec, unsigned int res);
+	#ifdef CONFIG_PM
+		int (*suspend)(struct hda_codec *codec, unsigned int state);
+		int (*resume)(struct hda_codec *codec, unsigned int state);
+	#endif
+	};
+
+The build_controls callback is called from snd_hda_build_controls().
+Similarly, the build_pcms callback is called from
+snd_hda_build_pcms().  The init callback is called after
+build_controls to initialize the hardware.
+The free callback is called as a destructor.
+
+The unsol_event callback is called when an unsolicited event is
+received.
+
+The suspend and resume callbacks are for power management.
+
+Each entry can be NULL if not necessary to be called.
+
+
+Generic Parser
+==============
+
+When the device doesn't match with any given presets, the widgets are
+parsed via th generic parser (hda_generic.c).  Its support is
+limited: no multi-channel support, for example.
+
+
+Digital I/O
+===========
+
+Call snd_hda_create_spdif_out_ctls() from the patch to create controls
+related with SPDIF out.  In the patch resume callback, call
+snd_hda_resume_spdif().
+
+
+Helper Functions
+================
+
+snd_hda_get_codec_name() stores the codec name on the given string.
+
+snd_hda_check_board_config() can be used to obtain the configuration
+information matching with the device.  Define the table with struct
+hda_board_config entries (zero-terminated), and pass it to the
+function.  The function checks the modelname given as a module
+parameter, and PCI subsystem IDs.  If the matching entry is found, it
+returns the config field value.
+
+snd_hda_add_new_ctls() can be used to create and add control entries.
+Pass the zero-terminated array of snd_kcontrol_new_t.  The same array
+can be passed to snd_hda_resume_ctls() for resume.
+Note that this will call control->put callback of these entries.  So,
+put callback should check codec->in_resume and force to restore the
+given value if it's non-zero even if the value is identical with the
+cached value.
+
+Macros HDA_CODEC_VOLUME(), HDA_CODEC_MUTE() and their variables can be
+used for the entry of snd_kcontrol_new_t.
+
+The input MUX helper callbacks for such a control are provided, too:
+snd_hda_input_mux_info() and snd_hda_input_mux_put().  See
+patch_realtek.c for example.
diff -Nru a/include/sound/ak4117.h b/include/sound/ak4117.h
--- a/include/sound/ak4117.h	2005-02-09 18:36:41 -08:00
+++ b/include/sound/ak4117.h	2005-02-09 18:36:41 -08:00
@@ -106,7 +106,7 @@
 #define AK4117_DIF_24L		(AK4117_DIF2)			/* STDO: 24-bit, left justified */
 #define AK4117_DIF_24I2S	(AK4117_DIF2|AK4117_DIF0)	/* STDO: I2S */
 
-/* AK4117_REG_INT0_MASK & AK4117_INT1_MASK */
+/* AK4117_REG_INT0_MASK & AK4117_REG_INT1_MASK */
 #define AK4117_MULK		(1<<7)	/* mask enable for UNLOCK bit */
 #define AK4117_MPAR		(1<<6)	/* mask enable for PAR bit */
 #define AK4117_MAUTO		(1<<5)	/* mask enable for AUTO bit */
@@ -181,8 +181,8 @@
 
 int snd_ak4117_create(snd_card_t *card, ak4117_read_t *read, ak4117_write_t *write,
 		      unsigned char pgm[5], void *private_data, ak4117_t **r_ak4117);
-void snd_ak4117_reg_write(ak4117_t *chip, unsigned char reg, unsigned char mask, unsigned char val);
-void snd_ak4117_reinit(ak4117_t *chip);
+void snd_ak4117_reg_write(ak4117_t *ak4117, unsigned char reg, unsigned char mask, unsigned char val);
+void snd_ak4117_reinit(ak4117_t *ak4117);
 int snd_ak4117_build(ak4117_t *ak4117, snd_pcm_substream_t *capture_substream);
 int snd_ak4117_external_rate(ak4117_t *ak4117);
 int snd_ak4117_check_rate_and_errors(ak4117_t *ak4117, unsigned int flags);
diff -Nru a/include/sound/control.h b/include/sound/control.h
--- a/include/sound/control.h	2005-02-09 18:36:41 -08:00
+++ b/include/sound/control.h	2005-02-09 18:36:41 -08:00
@@ -119,6 +119,13 @@
 
 int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
 int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);
+#ifdef CONFIG_COMPAT
+int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn);
+int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
+#else
+#define snd_ctl_register_ioctl_compat(fcn)
+#define snd_ctl_unregister_ioctl_compat(fcn)
+#endif
 
 int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *control);
 int snd_ctl_elem_write(snd_card_t *card, snd_ctl_file_t *file, snd_ctl_elem_value_t *control);
diff -Nru a/include/sound/hwdep.h b/include/sound/hwdep.h
--- a/include/sound/hwdep.h	2005-02-09 18:36:41 -08:00
+++ b/include/sound/hwdep.h	2005-02-09 18:36:41 -08:00
@@ -38,6 +38,7 @@
 	int (*release) (snd_hwdep_t * hw, struct file * file);
 	unsigned int (*poll) (snd_hwdep_t * hw, struct file * file, poll_table * wait);
 	int (*ioctl) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg);
+	int (*ioctl_compat) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg);
 	int (*mmap) (snd_hwdep_t * hw, struct file * file, struct vm_area_struct * vma);
 	int (*dsp_status) (snd_hwdep_t * hw, snd_hwdep_dsp_status_t * status);
 	int (*dsp_load) (snd_hwdep_t * hw, snd_hwdep_dsp_image_t * image);
diff -Nru a/sound/core/Kconfig b/sound/core/Kconfig
--- a/sound/core/Kconfig	2005-02-09 18:36:41 -08:00
+++ b/sound/core/Kconfig	2005-02-09 18:36:41 -08:00
@@ -81,20 +81,6 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-seq-oss.
 
-config SND_BIT32_EMUL
-	tristate "Emulation for 32-bit applications"
-	depends on SND && COMPAT
-	select SND_PCM
-	select SND_RAWMIDI
-	select SND_TIMER
-	select SND_HWDEP
-	help
-	  Say Y here to enable the emulation for 32-bit ALSA-native
-	  applications.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-ioctl32.
-
 config SND_RTCTIMER
 	tristate "RTC Timer support"
 	depends on SND && RTC
diff -Nru a/sound/core/Makefile b/sound/core/Makefile
--- a/sound/core/Makefile	2005-02-09 18:36:41 -08:00
+++ b/sound/core/Makefile	2005-02-09 18:36:41 -08:00
@@ -31,4 +31,3 @@
 
 obj-$(CONFIG_SND_OSSEMUL)	+= oss/
 obj-$(CONFIG_SND_SEQUENCER)	+= seq/
-obj-$(CONFIG_SND_BIT32_EMUL) += ioctl32/
diff -Nru a/sound/core/control.c b/sound/core/control.c
--- a/sound/core/control.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/control.c	2005-02-09 18:36:41 -08:00
@@ -43,6 +43,9 @@
 
 static DECLARE_RWSEM(snd_ioctl_rwsem);
 static LIST_HEAD(snd_control_ioctls);
+#ifdef CONFIG_COMPAT
+static LIST_HEAD(snd_control_compat_ioctls);
+#endif
 
 static int snd_ctl_open(struct inode *inode, struct file *file)
 {
@@ -595,43 +598,51 @@
 	return 0;
 }
 
-static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info)
+static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *info)
 {
 	snd_card_t *card = ctl->card;
-	snd_ctl_elem_info_t info;
 	snd_kcontrol_t *kctl;
 	snd_kcontrol_volatile_t *vd;
 	unsigned int index_offset;
 	int result;
 	
-	if (copy_from_user(&info, _info, sizeof(info)))
-		return -EFAULT;
 	down_read(&card->controls_rwsem);
-	kctl = snd_ctl_find_id(card, &info.id);
+	kctl = snd_ctl_find_id(card, &info->id);
 	if (kctl == NULL) {
 		up_read(&card->controls_rwsem);
 		return -ENOENT;
 	}
 #ifdef CONFIG_SND_DEBUG
-	info.access = 0;
+	info->access = 0;
 #endif
-	result = kctl->info(kctl, &info);
+	result = kctl->info(kctl, info);
 	if (result >= 0) {
-		snd_assert(info.access == 0, );
-		index_offset = snd_ctl_get_ioff(kctl, &info.id);
+		snd_assert(info->access == 0, );
+		index_offset = snd_ctl_get_ioff(kctl, &info->id);
 		vd = &kctl->vd[index_offset];
-		snd_ctl_build_ioff(&info.id, kctl, index_offset);
-		info.access = vd->access;
+		snd_ctl_build_ioff(&info->id, kctl, index_offset);
+		info->access = vd->access;
 		if (vd->owner) {
-			info.access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
+			info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
 			if (vd->owner == ctl)
-				info.access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
-			info.owner = vd->owner_pid;
+				info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
+			info->owner = vd->owner_pid;
 		} else {
-			info.owner = -1;
+			info->owner = -1;
 		}
 	}
 	up_read(&card->controls_rwsem);
+	return result;
+}
+
+static int snd_ctl_elem_info_user(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info)
+{
+	snd_ctl_elem_info_t info;
+	int result;
+
+	if (copy_from_user(&info, _info, sizeof(info)))
+		return -EFAULT;
+	result = snd_ctl_elem_info(ctl, &info);
 	if (result >= 0)
 		if (copy_to_user(_info, &info, sizeof(info)))
 			return -EFAULT;
@@ -816,14 +827,6 @@
 	struct user_element *ue = kcontrol->private_data;
 
 	*uinfo = ue->info;
-	if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
-		uinfo->value.enumerated.items = ue->info.value.enumerated.items;
-		if (uinfo->value.enumerated.item >= ue->info.value.enumerated.items)
-			uinfo->value.enumerated.item = 0;
-		strlcpy(uinfo->value.enumerated.name,
-			(char *)ue->priv_data + uinfo->value.enumerated.item * 64,
-			64);
-	}
 	return 0;
 }
 
@@ -851,28 +854,25 @@
 	kfree(kcontrol->private_data);
 }
 
-static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace)
+static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *info, int replace)
 {
 	snd_card_t *card = file->card;
-	snd_ctl_elem_info_t info;
 	snd_kcontrol_t kctl, *_kctl;
 	unsigned int access;
-	long private_size, extra_size;
+	long private_size;
 	struct user_element *ue;
 	int idx, err;
 	
 	if (card->user_ctl_count >= MAX_USER_CONTROLS)
 		return -ENOMEM;
-	if (copy_from_user(&info, _info, sizeof(info)))
-		return -EFAULT;
-	if (info.count > 1024)
+	if (info->count > 1024)
 		return -EINVAL;
-	access = info.access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
-		(info.access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE));
-	info.id.numid = 0;
+	access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
+		(info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE));
+	info->id.numid = 0;
 	memset(&kctl, 0, sizeof(kctl));
 	down_write(&card->controls_rwsem);
-	_kctl = snd_ctl_find_id(card, &info.id);
+	_kctl = snd_ctl_find_id(card, &info->id);
 	err = 0;
 	if (_kctl) {
 		if (replace)
@@ -886,67 +886,50 @@
 	up_write(&card->controls_rwsem);
 	if (err < 0)
 		return err;
-	memcpy(&kctl.id, &info.id, sizeof(info.id));
-	kctl.count = info.owner ? info.owner : 1;
+	memcpy(&kctl.id, &info->id, sizeof(info->id));
+	kctl.count = info->owner ? info->owner : 1;
 	access |= SNDRV_CTL_ELEM_ACCESS_USER;
 	kctl.info = snd_ctl_elem_user_info;
 	if (access & SNDRV_CTL_ELEM_ACCESS_READ)
 		kctl.get = snd_ctl_elem_user_get;
 	if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
 		kctl.put = snd_ctl_elem_user_put;
-	extra_size = 0;
-	switch (info.type) {
+	switch (info->type) {
 	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
 		private_size = sizeof(char);
-		if (info.count > 128)
+		if (info->count > 128)
 			return -EINVAL;
 		break;
 	case SNDRV_CTL_ELEM_TYPE_INTEGER:
 		private_size = sizeof(long);
-		if (info.count > 128)
+		if (info->count > 128)
 			return -EINVAL;
 		break;
 	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
 		private_size = sizeof(long long);
-		if (info.count > 64)
+		if (info->count > 64)
 			return -EINVAL;
 		break;
-	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
-		private_size = sizeof(unsigned int);
-		if (info.count > 128)
-			return -EINVAL;
-		if (info.value.enumerated.items > 128)
-			return -EINVAL;
-		extra_size = info.value.enumerated.items * 64;
-		break;
 	case SNDRV_CTL_ELEM_TYPE_BYTES:
 		private_size = sizeof(unsigned char);
-		if (info.count > 512)
+		if (info->count > 512)
 			return -EINVAL;
 		break;
 	case SNDRV_CTL_ELEM_TYPE_IEC958:
 		private_size = sizeof(struct sndrv_aes_iec958);
-		if (info.count != 1)
+		if (info->count != 1)
 			return -EINVAL;
 		break;
 	default:
 		return -EINVAL;
 	}
-	private_size *= info.count;
-	ue = kcalloc(1, sizeof(struct user_element) + private_size + extra_size, GFP_KERNEL);
+	private_size *= info->count;
+	ue = kcalloc(1, sizeof(struct user_element) + private_size, GFP_KERNEL);
 	if (ue == NULL)
 		return -ENOMEM;
-	ue->info = info;
+	ue->info = *info;
 	ue->elem_data = (char *)ue + sizeof(ue);
 	ue->elem_data_size = private_size;
-	if (extra_size) {
-		ue->priv_data = (char *)ue + sizeof(ue) + private_size;
-		ue->priv_data_size = extra_size;
-		if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
-			if (copy_from_user(ue->priv_data, *(char __user **)info.value.enumerated.name, extra_size))
-				return -EFAULT;
-		}
-	}
 	kctl.private_free = snd_ctl_elem_user_free;
 	_kctl = snd_ctl_new(&kctl, access);
 	if (_kctl == NULL) {
@@ -969,6 +952,14 @@
 	return 0;
 }
 
+static int snd_ctl_elem_add_user(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace)
+{
+	snd_ctl_elem_info_t info;
+	if (copy_from_user(&info, _info, sizeof(info)))
+		return -EFAULT;
+	return snd_ctl_elem_add(file, &info, replace);
+}
+
 static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
 {
 	snd_ctl_elem_id_t id;
@@ -1039,8 +1030,7 @@
 }
 #endif
 
-static inline int _snd_ctl_ioctl(struct inode *inode, struct file *file,
-				 unsigned int cmd, unsigned long arg)
+static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_ctl_file_t *ctl;
 	snd_card_t *card;
@@ -1061,7 +1051,7 @@
 	case SNDRV_CTL_IOCTL_ELEM_LIST:
 		return snd_ctl_elem_list(ctl->card, argp);
 	case SNDRV_CTL_IOCTL_ELEM_INFO:
-		return snd_ctl_elem_info(ctl, argp);
+		return snd_ctl_elem_info_user(ctl, argp);
 	case SNDRV_CTL_IOCTL_ELEM_READ:
 		return snd_ctl_elem_read_user(ctl->card, argp);
 	case SNDRV_CTL_IOCTL_ELEM_WRITE:
@@ -1071,7 +1061,7 @@
 	case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
 		return snd_ctl_elem_unlock(ctl, argp);
 	case SNDRV_CTL_IOCTL_ELEM_ADD:
-		return snd_ctl_elem_add(ctl, argp, 0);
+		return snd_ctl_elem_add_user(ctl, argp, 0);
 	case SNDRV_CTL_IOCTL_ELEM_REPLACE:
 		return snd_ctl_elem_add(ctl, argp, 1);
 	case SNDRV_CTL_IOCTL_ELEM_REMOVE:
@@ -1113,17 +1103,6 @@
 	return -ENOTTY;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_ctl_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg)
-{
-	int err;
-	unlock_kernel();
-	err = _snd_ctl_ioctl(inode, file, cmd, arg);
-	lock_kernel();
-	return err;
-}
-
 static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset)
 {
 	snd_ctl_file_t *ctl;
@@ -1199,7 +1178,7 @@
  * register the device-specific control-ioctls.
  * called from each device manager like pcm.c, hwdep.c, etc.
  */
-int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
+static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
 {
 	snd_kctl_ioctl_t *pn;
 
@@ -1208,22 +1187,34 @@
 		return -ENOMEM;
 	pn->fioctl = fcn;
 	down_write(&snd_ioctl_rwsem);
-	list_add_tail(&pn->list, &snd_control_ioctls);
+	list_add_tail(&pn->list, lists);
 	up_write(&snd_ioctl_rwsem);
 	return 0;
 }
 
+int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
+}
+
+#ifdef CONFIG_COMPAT
+int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
+}
+#endif
+
 /*
  * de-register the device-specific control-ioctls.
  */
-int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
+static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
 {
 	struct list_head *list;
 	snd_kctl_ioctl_t *p;
 
 	snd_runtime_check(fcn != NULL, return -EINVAL);
 	down_write(&snd_ioctl_rwsem);
-	list_for_each(list, &snd_control_ioctls) {
+	list_for_each(list, lists) {
 		p = list_entry(list, snd_kctl_ioctl_t, list);
 		if (p->fioctl == fcn) {
 			list_del(&p->list);
@@ -1237,6 +1228,19 @@
 	return -EINVAL;
 }
 
+int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
+}
+
+#ifdef CONFIG_COMPAT
+int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
+}
+
+#endif
+
 static int snd_ctl_fasync(int fd, struct file * file, int on)
 {
 	snd_ctl_file_t *ctl;
@@ -1249,6 +1253,15 @@
 }
 
 /*
+ * ioctl32 compat
+ */
+#ifdef CONFIG_COMPAT
+#include "control_compat.c"
+#else
+#define snd_ctl_ioctl_compat	NULL
+#endif
+
+/*
  *  INIT PART
  */
 
@@ -1259,7 +1272,8 @@
 	.open =		snd_ctl_open,
 	.release =	snd_ctl_release,
 	.poll =		snd_ctl_poll,
-	.ioctl =	snd_ctl_ioctl,
+	.unlocked_ioctl =	snd_ctl_ioctl,
+	.compat_ioctl =	snd_ctl_ioctl_compat,
 	.fasync =	snd_ctl_fasync,
 };
 
diff -Nru a/sound/core/control_compat.c b/sound/core/control_compat.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/core/control_compat.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,412 @@
+/*
+ * compat ioctls for control API
+ *
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   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
+ */
+
+/* this file included from control.c */
+
+#include <linux/compat.h>
+
+struct sndrv_ctl_elem_list32 {
+	u32 offset;
+	u32 space;
+	u32 used;
+	u32 count;
+	u32 pids;
+	unsigned char reserved[50];
+} /* don't set packed attribute here */;
+
+static int snd_ctl_elem_list_compat(snd_card_t *card, struct sndrv_ctl_elem_list32 __user *data32)
+{
+	struct sndrv_ctl_elem_list __user *data;
+	compat_caddr_t ptr;
+	int err;
+
+	data = compat_alloc_user_space(sizeof(*data));
+
+	/* offset, space, used, count */
+	if (copy_in_user(data, data32, 4 * sizeof(u32)))
+		return -EFAULT;
+	/* pids */
+	if (get_user(ptr, &data32->pids) ||
+	    put_user(compat_ptr(ptr), &data->pids))
+		return -EFAULT;
+	err = snd_ctl_elem_list(card, data);
+	if (err < 0)
+		return err;
+	/* copy the result */
+	if (copy_in_user(data32, data, 4 * sizeof(u32)))
+		return -EFAULT;
+	return 0;
+}
+
+/*
+ * control element info
+ * it uses union, so the things are not easy..
+ */
+
+struct sndrv_ctl_elem_info32 {
+	struct sndrv_ctl_elem_id id; // the size of struct is same
+	s32 type;
+	u32 access;
+	u32 count;
+	s32 owner;
+	union {
+		struct {
+			s32 min;
+			s32 max;
+			s32 step;
+		} integer;
+		struct {
+			u64 min;
+			u64 max;
+			u64 step;
+		} integer64;
+		struct {
+			u32 items;
+			u32 item;
+			char name[64];
+		} enumerated;
+		unsigned char reserved[128];
+	} value;
+	unsigned char reserved[64];
+} __attribute__((packed));
+
+static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_info32 __user *data32)
+{
+	struct sndrv_ctl_elem_info *data;
+	int err;
+
+	data = kcalloc(1, sizeof(*data), GFP_KERNEL);
+	if (! data)
+		return -ENOMEM;
+
+	err = -EFAULT;
+	/* copy id */
+	if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
+		goto error;
+	/* we need to copy the item index.
+	 * hope this doesn't break anything..
+	 */
+	if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
+		goto error;
+	err = snd_ctl_elem_info(ctl, data);
+	if (err < 0)
+		goto error;
+	/* restore info to 32bit */
+	err = -EFAULT;
+	/* id, type, access, count */
+	if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
+	    copy_to_user(&data32->type, &data->type, 3 * sizeof(u32)))
+		goto error;
+	if (put_user(data->owner, &data32->owner))
+		goto error;
+	switch (data->type) {
+	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+	case SNDRV_CTL_ELEM_TYPE_INTEGER:
+		if (put_user(data->value.integer.min, &data32->value.integer.min) ||
+		    put_user(data->value.integer.max, &data32->value.integer.max) ||
+		    put_user(data->value.integer.step, &data32->value.integer.step))
+			goto error;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+		if (copy_to_user(&data32->value.integer64,
+				 &data->value.integer64,
+				 sizeof(data->value.integer64)))
+			goto error;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+		if (copy_to_user(&data32->value.enumerated,
+				 &data->value.enumerated,
+				 sizeof(data->value.enumerated)))
+			goto error;
+		break;
+	default:
+		break;
+	}
+	err = 0;
+ error:
+	kfree(data);
+	return err;
+}
+
+/* read / write */
+struct sndrv_ctl_elem_value32 {
+	struct sndrv_ctl_elem_id id;
+	unsigned int indirect;	/* bit-field causes misalignment */
+        union {
+		s32 integer[128];
+		unsigned char data[512];
+#ifndef CONFIG_X86_64
+		s64 integer64[64];
+#endif
+        } value;
+        unsigned char reserved[128];
+};
+
+
+/* get the value type and count of the control */
+static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id, int *countp)
+{
+	snd_kcontrol_t *kctl;
+	snd_ctl_elem_info_t info;
+	int err;
+
+	down_read(&card->controls_rwsem);
+	kctl = snd_ctl_find_id(card, id);
+	if (! kctl) {
+		up_read(&card->controls_rwsem);
+		return -ENXIO;
+	}
+	info.id = *id;
+	err = kctl->info(kctl, &info);
+	up_read(&card->controls_rwsem);
+	if (err >= 0) {
+		err = info.type;
+		*countp = info.count;
+	}
+	return err;
+}
+
+static int get_elem_size(int type, int count)
+{
+	switch (type) {
+	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+		return sizeof(s64) * count;
+	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+		return sizeof(int) * count;
+	case SNDRV_CTL_ELEM_TYPE_BYTES:
+		return 512;
+	case SNDRV_CTL_ELEM_TYPE_IEC958:
+		return sizeof(struct sndrv_aes_iec958);
+	default:
+		return -1;
+	}
+}
+
+static int copy_ctl_value_from_user(snd_card_t *card,
+				    struct sndrv_ctl_elem_value *data,
+				    struct sndrv_ctl_elem_value32 __user *data32,
+				    int *typep, int *countp)
+{
+	int i, type, count, size;
+	unsigned int indirect;
+
+	if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
+		return -EFAULT;
+	if (get_user(indirect, &data32->indirect))
+		return -EFAULT;
+	if (indirect)
+		return -EINVAL;
+	type = get_ctl_type(card, &data->id, &count);
+	if (type < 0)
+		return type;
+
+	if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+	    type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
+		for (i = 0; i < count; i++) {
+			int val;
+			if (get_user(val, &data32->value.integer[i]))
+				return -EFAULT;
+			data->value.integer.value[i] = val;
+		}
+	} else {
+		size = get_elem_size(type, count);
+		if (size < 0) {
+			printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
+			return -EINVAL;
+		}
+		if (copy_from_user(data->value.bytes.data,
+				   data32->value.data, size))
+			return -EFAULT;
+	}
+
+	*typep = type;
+	*countp = count;
+	return 0;
+}
+
+/* restore the value to 32bit */
+static int copy_ctl_value_to_user(struct sndrv_ctl_elem_value32 __user *data32,
+				  struct sndrv_ctl_elem_value *data,
+				  int type, int count)
+{
+	int i, size;
+
+	if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+	    type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
+		for (i = 0; i < count; i++) {
+			int val;
+			val = data->value.integer.value[i];
+			if (put_user(val, &data32->value.integer[i]))
+				return -EFAULT;
+		}
+	} else {
+		size = get_elem_size(type, count);
+		if (copy_to_user(data32->value.data,
+				 data->value.bytes.data, size))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static int snd_ctl_elem_read_user_compat(snd_card_t *card, 
+					 struct sndrv_ctl_elem_value32 __user *data32)
+{
+	struct sndrv_ctl_elem_value *data;
+	int err, type, count;
+
+	data = kcalloc(1, sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0)
+		goto error;
+	if ((err = snd_ctl_elem_read(card, data)) < 0)
+		goto error;
+	err = copy_ctl_value_to_user(data32, data, type, count);
+ error:
+	kfree(data);
+	return err;
+}
+
+static int snd_ctl_elem_write_user_compat(snd_ctl_file_t *file,
+					  struct sndrv_ctl_elem_value32 __user *data32)
+{
+	struct sndrv_ctl_elem_value *data;
+	int err, type, count;
+
+	data = kcalloc(1, sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	if ((err = copy_ctl_value_from_user(file->card, data, data32, &type, &count)) < 0)
+		goto error;
+	if ((err = snd_ctl_elem_write(file->card, file, data)) < 0)
+		goto error;
+	err = copy_ctl_value_to_user(data32, data, type, count);
+ error:
+	kfree(data);
+	return err;
+}
+
+/* add or replace a user control */
+static int snd_ctl_elem_add_compat(snd_ctl_file_t *file,
+				   struct sndrv_ctl_elem_info32 __user *data32,
+				   int replace)
+{
+	struct sndrv_ctl_elem_info *data;
+	int err;
+
+	data = kcalloc(1, sizeof(*data), GFP_KERNEL);
+	if (! data)
+		return -ENOMEM;
+
+	err = -EFAULT;
+	/* id, type, access, count */ \
+	if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
+	    copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
+		goto error;
+	if (get_user(data->owner, &data32->owner) ||
+	    get_user(data->type, &data32->type))
+		goto error;
+	switch (data->type) {
+	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+	case SNDRV_CTL_ELEM_TYPE_INTEGER:
+		if (get_user(data->value.integer.min, &data32->value.integer.min) ||
+		    get_user(data->value.integer.max, &data32->value.integer.max) ||
+		    get_user(data->value.integer.step, &data32->value.integer.step))
+			goto error;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+		if (copy_from_user(&data->value.integer64,
+				   &data32->value.integer64,
+				   sizeof(data->value.integer64)))
+			goto error;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+		if (copy_from_user(&data->value.enumerated,
+				   &data32->value.enumerated,
+				   sizeof(data->value.enumerated)))
+			goto error;
+		break;
+	default:
+		break;
+	}
+	err = snd_ctl_elem_add(file, data, replace);
+ error:
+	kfree(data);
+	return err;
+}  
+
+enum {
+	SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32),
+	SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32),
+	SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32),
+	SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32),
+	SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct sndrv_ctl_elem_info32),
+	SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct sndrv_ctl_elem_info32),
+};
+
+static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	snd_ctl_file_t *ctl;
+	struct list_head *list;
+	void __user *argp = compat_ptr(arg);
+	int err;
+
+	ctl = file->private_data;
+	snd_assert(ctl && ctl->card, return -ENXIO);
+
+	switch (cmd) {
+	case SNDRV_CTL_IOCTL_PVERSION:
+	case SNDRV_CTL_IOCTL_CARD_INFO:
+	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
+	case SNDRV_CTL_IOCTL_POWER:
+	case SNDRV_CTL_IOCTL_POWER_STATE:
+	case SNDRV_CTL_IOCTL_ELEM_LOCK:
+	case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
+		return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
+	case SNDRV_CTL_IOCTL_ELEM_LIST32:
+		return snd_ctl_elem_list_compat(ctl->card, argp);
+	case SNDRV_CTL_IOCTL_ELEM_INFO32:
+		return snd_ctl_elem_info_compat(ctl, argp);
+	case SNDRV_CTL_IOCTL_ELEM_READ32:
+		return snd_ctl_elem_read_user_compat(ctl->card, argp);
+	case SNDRV_CTL_IOCTL_ELEM_WRITE32:
+		return snd_ctl_elem_write_user_compat(ctl, argp);
+	case SNDRV_CTL_IOCTL_ELEM_ADD32:
+		return snd_ctl_elem_add_compat(ctl, argp, 0);
+	case SNDRV_CTL_IOCTL_ELEM_REPLACE32:
+		return snd_ctl_elem_add_compat(ctl, argp, 1);
+	}
+
+	down_read(&snd_ioctl_rwsem);
+	list_for_each(list, &snd_control_compat_ioctls) {
+		snd_kctl_ioctl_t *p = list_entry(list, snd_kctl_ioctl_t, list);
+		if (p->fioctl) {
+			err = p->fioctl(ctl->card, ctl, cmd, arg);
+			if (err != -ENOIOCTLCMD) {
+				up_read(&snd_ioctl_rwsem);
+				return err;
+			}
+		}
+	}
+	up_read(&snd_ioctl_rwsem);
+	return -ENOIOCTLCMD;
+}
diff -Nru a/sound/core/hwdep.c b/sound/core/hwdep.c
--- a/sound/core/hwdep.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/hwdep.c	2005-02-09 18:36:41 -08:00
@@ -232,8 +232,7 @@
 	return 0;
 }
 
-static inline int _snd_hwdep_ioctl(struct inode *inode, struct file * file,
-				   unsigned int cmd, unsigned long arg)
+static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
 {
 	snd_hwdep_t *hw = file->private_data;
 	void __user *argp = (void __user *)arg;
@@ -252,17 +251,6 @@
 	return -ENOTTY;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_hwdep_ioctl(struct inode *inode, struct file * file,
-			   unsigned int cmd, unsigned long arg)
-{
-	int err;
-	unlock_kernel();
-	err = _snd_hwdep_ioctl(inode, file, cmd, arg);
-	lock_kernel();
-	return err;
-}
-
 static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma)
 {
 	snd_hwdep_t *hw = file->private_data;
@@ -315,6 +303,12 @@
 	return -ENOIOCTLCMD;
 }
 
+#ifdef CONFIG_COMPAT
+#include "hwdep_compat.c"
+#else
+#define snd_hwdep_ioctl_compat	NULL
+#endif
+
 /*
 
  */
@@ -328,7 +322,8 @@
 	.open =		snd_hwdep_open,
 	.release =	snd_hwdep_release,
 	.poll =		snd_hwdep_poll,
-	.ioctl =	snd_hwdep_ioctl,
+	.unlocked_ioctl =	snd_hwdep_ioctl,
+	.compat_ioctl =	snd_hwdep_ioctl_compat,
 	.mmap =		snd_hwdep_mmap,
 };
 
@@ -509,12 +504,14 @@
 	}
 	snd_hwdep_proc_entry = entry;
 	snd_ctl_register_ioctl(snd_hwdep_control_ioctl);
+	snd_ctl_register_ioctl_compat(snd_hwdep_control_ioctl);
 	return 0;
 }
 
 static void __exit alsa_hwdep_exit(void)
 {
 	snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl);
+	snd_ctl_unregister_ioctl_compat(snd_hwdep_control_ioctl);
 	if (snd_hwdep_proc_entry) {
 		snd_info_unregister(snd_hwdep_proc_entry);
 		snd_hwdep_proc_entry = NULL;
diff -Nru a/sound/core/hwdep_compat.c b/sound/core/hwdep_compat.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/core/hwdep_compat.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,77 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for hwdep API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   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
+ *
+ */
+
+/* This file is included from hwdep.c */
+
+#include <linux/compat.h>
+
+struct sndrv_hwdep_dsp_image32 {
+	u32 index;
+	unsigned char name[64];
+	u32 image;	/* pointer */
+	u32 length;
+	u32 driver_data;
+} /* don't set packed attribute here */;
+
+static int snd_hwdep_dsp_load_compat(snd_hwdep_t *hw,
+				     struct sndrv_hwdep_dsp_image32 __user *src)
+{
+	struct sndrv_hwdep_dsp_image *dst;
+	compat_caddr_t ptr;
+	u32 val;
+
+	dst = compat_alloc_user_space(sizeof(*dst));
+
+	/* index and name */
+	if (copy_in_user(dst, src, 4 + 64))
+		return -EFAULT;
+	if (get_user(ptr, &src->image) ||
+	    put_user(compat_ptr(ptr), &dst->image))
+		return -EFAULT;
+	if (get_user(val, &src->length) ||
+	    put_user(val, &dst->length))
+		return -EFAULT;
+	if (get_user(val, &src->driver_data) ||
+	    put_user(val, &dst->driver_data))
+		return -EFAULT;
+
+	return snd_hwdep_dsp_load(hw, dst);
+}
+
+enum {
+	SNDRV_HWDEP_IOCTL_DSP_LOAD32   = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
+};
+
+static long snd_hwdep_ioctl_compat(struct file * file, unsigned int cmd, unsigned long arg)
+{
+	snd_hwdep_t *hw = file->private_data;
+	void __user *argp = compat_ptr(arg);
+	switch (cmd) {
+	case SNDRV_HWDEP_IOCTL_PVERSION:
+	case SNDRV_HWDEP_IOCTL_INFO:
+	case SNDRV_HWDEP_IOCTL_DSP_STATUS:
+		return snd_hwdep_ioctl(file, cmd, (unsigned long)argp);
+	case SNDRV_HWDEP_IOCTL_DSP_LOAD32:
+		return snd_hwdep_dsp_load_compat(hw, argp);
+	}
+	if (hw->ops.ioctl_compat)
+		return hw->ops.ioctl_compat(hw, file, cmd, arg);
+	return -ENOIOCTLCMD;
+}
diff -Nru a/sound/core/init.c b/sound/core/init.c
--- a/sound/core/init.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/init.c	2005-02-09 18:36:41 -08:00
@@ -39,7 +39,7 @@
 
 unsigned int snd_cards_lock = 0;	/* locked for registering/using */
 snd_card_t *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL};
-rwlock_t snd_card_rwlock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(snd_card_rwlock);
 
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
 int (*snd_mixer_oss_notify_callback)(snd_card_t *card, int free_flag);
diff -Nru a/sound/core/ioctl32/Makefile b/sound/core/ioctl32/Makefile
--- a/sound/core/ioctl32/Makefile	2005-02-09 18:36:41 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,11 +0,0 @@
-#
-# Makefile for ALSA
-# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
-#
-
-snd-ioctl32-objs := ioctl32.o pcm32.o rawmidi32.o timer32.o hwdep32.o
-ifneq ($(CONFIG_SND_SEQUENCER),n)
-  snd-ioctl32-objs += seq32.o
-endif
-
-obj-$(CONFIG_SND_BIT32_EMUL) += snd-ioctl32.o
diff -Nru a/sound/core/ioctl32/hwdep32.c b/sound/core/ioctl32/hwdep32.c
--- a/sound/core/ioctl32/hwdep32.c	2005-02-09 18:36:41 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,73 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for hwdep API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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/time.h>
-#include <linux/fs.h>
-#include <sound/core.h>
-#include <sound/hwdep.h>
-#include <asm/uaccess.h>
-#include "ioctl32.h"
-
-struct sndrv_hwdep_dsp_image32 {
-	u32 index;
-	unsigned char name[64];
-	u32 image;	/* pointer */
-	u32 length;
-	u32 driver_data;
-} /* don't set packed attribute here */;
-
-static inline int _snd_ioctl32_hwdep_dsp_image(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_hwdep_dsp_image __user *data, *dst;
-	struct sndrv_hwdep_dsp_image32 __user *data32, *src;
-	compat_caddr_t ptr;
-
-	data32 = compat_ptr(arg);
-	data = compat_alloc_user_space(sizeof(*data));
-
-	/* index and name */
-	if (copy_in_user(data, data32, 4 + 64))
-		return -EFAULT;
-	if (__get_user(ptr, &data32->image) ||
-	    __put_user(compat_ptr(ptr), &data->image))
-		return -EFAULT;
-	src = data32;
-	dst = data;
-	COPY_CVT(length);
-	COPY_CVT(driver_data);
-	return file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
-}
-
-DEFINE_ALSA_IOCTL_ENTRY(hwdep_dsp_image, hwdep_dsp_image, SNDRV_HWDEP_IOCTL_DSP_LOAD);
-
-#define AP(x) snd_ioctl32_##x
-
-enum {
-	SNDRV_HWDEP_IOCTL_DSP_LOAD32   = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
-};
-
-struct ioctl32_mapper hwdep_mappers[] = {
-	MAP_COMPAT(SNDRV_HWDEP_IOCTL_PVERSION),
-	MAP_COMPAT(SNDRV_HWDEP_IOCTL_INFO),
-	MAP_COMPAT(SNDRV_HWDEP_IOCTL_DSP_STATUS),
-	{ SNDRV_HWDEP_IOCTL_DSP_LOAD32, AP(hwdep_dsp_image) },
-	{ 0 },
-};
diff -Nru a/sound/core/ioctl32/ioctl32.c b/sound/core/ioctl32/ioctl32.c
--- a/sound/core/ioctl32/ioctl32.c	2005-02-09 18:36:40 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,430 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for control API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <sound/core.h>
-#include <sound/control.h>
-#include <sound/minors.h>
-#include <asm/uaccess.h>
-#include "ioctl32.h"
-
-
-/*
- * register/unregister mappers
- * exported for other modules
- */
-
-MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
-MODULE_DESCRIPTION("ioctl32 wrapper for ALSA");
-MODULE_LICENSE("GPL");
-
-int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
-int unregister_ioctl32_conversion(unsigned int cmd);
-
-
-int snd_ioctl32_register(struct ioctl32_mapper *mappers)
-{
-	int err;
-	struct ioctl32_mapper *m;
-
-	for (m = mappers; m->cmd; m++) {
-		err = register_ioctl32_conversion(m->cmd, m->handler);
-		if (err >= 0)
-			m->registered++;
-	}
-	return 0;
-}
-
-void snd_ioctl32_unregister(struct ioctl32_mapper *mappers)
-{
-	struct ioctl32_mapper *m;
-
-	for (m = mappers; m->cmd; m++) {
-		if (m->registered) {
-			unregister_ioctl32_conversion(m->cmd);
-			m->registered = 0;
-		}
-	}
-}
-
-
-/*
- * compatible wrapper
- */
-int snd_ioctl32_compat(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp)
-{
-	if (! filp->f_op || ! filp->f_op->ioctl)
-		return -ENOTTY;
-	return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
-}
-
-
-/*
- * Controls
- */
-
-struct sndrv_ctl_elem_list32 {
-	u32 offset;
-	u32 space;
-	u32 used;
-	u32 count;
-	u32 pids;
-	unsigned char reserved[50];
-} /* don't set packed attribute here */;
-
-static inline int _snd_ioctl32_ctl_elem_list(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_ctl_elem_list32 __user *data32;
-	struct sndrv_ctl_elem_list __user *data;
-	compat_caddr_t ptr;
-	int err;
-
-	data32 = compat_ptr(arg);
-	data = compat_alloc_user_space(sizeof(*data));
-
-	/* offset, space, used, count */
-	if (copy_in_user(data, data32, 4 * sizeof(u32)))
-		return -EFAULT;
-	/* pids */
-	if (__get_user(ptr, &data32->pids) ||
-	    __put_user(compat_ptr(ptr), &data->pids))
-		return -EFAULT;
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
-	if (err < 0)
-		return err;
-	/* copy the result */
-	if (copy_in_user(data32, data, 4 * sizeof(u32)))
-		return -EFAULT;
-	return 0;
-}
-
-DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST);
-
-/*
- * control element info
- * it uses union, so the things are not easy..
- */
-
-struct sndrv_ctl_elem_info32 {
-	struct sndrv_ctl_elem_id id; // the size of struct is same
-	s32 type;
-	u32 access;
-	u32 count;
-	s32 owner;
-	union {
-		struct {
-			s32 min;
-			s32 max;
-			s32 step;
-		} integer;
-		struct {
-			u64 min;
-			u64 max;
-			u64 step;
-		} integer64;
-		struct {
-			u32 items;
-			u32 item;
-			char name[64];
-		} enumerated;
-		unsigned char reserved[128];
-	} value;
-	unsigned char reserved[64];
-} __attribute__((packed));
-
-static inline int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_ctl_elem_info __user *data, *src;
-	struct sndrv_ctl_elem_info32 __user *data32, *dst;
-	unsigned int type;
-	int err;
-
-	data32 = compat_ptr(arg);
-	data = compat_alloc_user_space(sizeof(*data));
-
-	/* copy id */
-	if (copy_in_user(&data->id, &data32->id, sizeof(data->id)))
-		return -EFAULT;
-	/* we need to copy the item index.
-	 * hope this doesn't break anything..
-	 */
-	if (copy_in_user(&data->value.enumerated.item,
-			 &data32->value.enumerated.item,
-			 sizeof(data->value.enumerated.item)))
-		return -EFAULT;
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
-	if (err < 0)
-		return err;
-	/* restore info to 32bit */
-	/* for COPY_CVT macro */
-	src = data;
-	dst = data32;
-	/* id, type, access, count */
-	if (copy_in_user(&data32->id, &data->id, sizeof(data->id)) ||
-	    copy_in_user(&data32->type, &data->type, 3 * sizeof(u32)))
-		return -EFAULT;
-	COPY_CVT(owner);
-	__get_user(type, &data->type);
-	switch (type) {
-	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
-	case SNDRV_CTL_ELEM_TYPE_INTEGER:
-		COPY_CVT(value.integer.min);
-		COPY_CVT(value.integer.max);
-		COPY_CVT(value.integer.step);
-		break;
-	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
-		if (copy_in_user(&data32->value.integer64,
-				 &data->value.integer64,
-				 sizeof(data->value.integer64)))
-			return -EFAULT;
-		break;
-	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
-		if (copy_in_user(&data32->value.enumerated,
-				 &data->value.enumerated,
-				 sizeof(data->value.enumerated)))
-			return -EFAULT;
-		break;
-	default:
-		break;
-	}
-	return 0;
-}
-
-DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO);
-
-struct sndrv_ctl_elem_value32 {
-	struct sndrv_ctl_elem_id id;
-	unsigned int indirect;	/* bit-field causes misalignment */
-        union {
-		s32 integer[128];	/* integer and boolean need conversion */
-		unsigned char data[512];	/* others should be compatible */
-        } value;
-        unsigned char reserved[128];	/* not used */
-};
-
-
-/* hmm, it's so hard to retrieve the value type from the control id.. */
-static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id)
-{
-	snd_kcontrol_t *kctl;
-	snd_ctl_elem_info_t info;
-	int err;
-
-	down_read(&card->controls_rwsem);
-	kctl = snd_ctl_find_id(card, id);
-	if (! kctl) {
-		up_read(&card->controls_rwsem);
-		return -ENXIO;
-	}
-	info.id = *id;
-	err = kctl->info(kctl, &info);
-	up_read(&card->controls_rwsem);
-	if (err >= 0)
-		err = info.type;
-	return err;
-}
-
-extern int snd_major;
-
-static inline int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_ctl_elem_value *data;
-	struct sndrv_ctl_elem_value32 __user *data32;
-	snd_ctl_file_t *ctl;
-	int err, i, indirect;
-	int type;
-
-	/* sanity check */
-	if (imajor(file->f_dentry->d_inode) != snd_major ||
-	    SNDRV_MINOR_DEVICE(iminor(file->f_dentry->d_inode)) != SNDRV_MINOR_CONTROL)
-		return -ENOTTY;
-
-	if ((ctl = file->private_data) == NULL)
-		return -ENOTTY;
-
-	data32 = compat_ptr(arg);
-	data = kcalloc(1, sizeof(*data), GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) {
-		err = -EFAULT;
-		goto __end;
-	}
-	if (__get_user(indirect, &data32->indirect)) {
-		err = -EFAULT;
-		goto __end;
-	}
-	/* FIXME: indirect access is not supported */
-	if (indirect) {
-		err = -EINVAL;
-		goto __end;
-	}
-	type = get_ctl_type(ctl->card, &data->id);
-	if (type < 0) {
-		err = type;
-		goto __end;
-	}
-
-	switch (type) {
-	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
-	case SNDRV_CTL_ELEM_TYPE_INTEGER:
-		for (i = 0; i < 128; i++) {
-			int val;
-			if (__get_user(val, &data32->value.integer[i])) {
-				err = -EFAULT;
-				goto __end;
-			}
-			data->value.integer.value[i] = val;
-		}
-		break;
-	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
-	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
-	case SNDRV_CTL_ELEM_TYPE_BYTES:
-	case SNDRV_CTL_ELEM_TYPE_IEC958:
-		if (__copy_from_user(data->value.bytes.data,
-				     data32->value.data,
-				     sizeof(data32->value.data))) {
-			err = -EFAULT;
-			goto __end;
-		}
-		break;
-	default:
-		printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
-		err = -EINVAL;
-		goto __end;
-	}
-
-	if (native_ctl == SNDRV_CTL_IOCTL_ELEM_READ)
-		err = snd_ctl_elem_read(ctl->card, data);
-	else
-		err = snd_ctl_elem_write(ctl->card, ctl, data);
-	if (err < 0)
-		goto __end;
-	/* restore info to 32bit */
-	switch (type) {
-	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
-	case SNDRV_CTL_ELEM_TYPE_INTEGER:
-		for (i = 0; i < 128; i++) {
-			int val;
-			val = data->value.integer.value[i];
-			if (__put_user(val, &data32->value.integer[i])) {
-				err = -EFAULT;
-				goto __end;
-			}
-		}
-		break;
-	default:
-		if (__copy_to_user(data32->value.data,
-				   data->value.bytes.data,
-				   sizeof(data32->value.data))) {
-			err = -EFAULT;
-			goto __end;
-		}
-		break;
-		break;
-	}
-	err = 0;
-      __end:
-	kfree(data);
-	return err;
-}
-
-DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_read, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_READ);
-DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_write, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_WRITE);
-
-/*
- */
-
-#define AP(x) snd_ioctl32_##x
-
-enum {
-	SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32),
-	SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32),
-	SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32),
-	SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32),
-};
-
-static struct ioctl32_mapper control_mappers[] = {
-	/* controls (without rawmidi, hwdep, timer releated ones) */
-	MAP_COMPAT(SNDRV_CTL_IOCTL_PVERSION),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_CARD_INFO),
-	{ SNDRV_CTL_IOCTL_ELEM_LIST32, AP(ctl_elem_list) },
-	{ SNDRV_CTL_IOCTL_ELEM_INFO32, AP(ctl_elem_info) },
-	{ SNDRV_CTL_IOCTL_ELEM_READ32, AP(ctl_elem_read) },
-	{ SNDRV_CTL_IOCTL_ELEM_WRITE32, AP(ctl_elem_write) },
-	MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_LOCK),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_UNLOCK),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_INFO),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_INFO),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_POWER),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_POWER_STATE),
-	{ 0 }
-};
-
-
-/*
- */
-
-extern struct ioctl32_mapper pcm_mappers[];
-extern struct ioctl32_mapper rawmidi_mappers[];
-extern struct ioctl32_mapper timer_mappers[];
-extern struct ioctl32_mapper hwdep_mappers[];
-#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)
-{
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-	snd_ioctl32_unregister(seq_mappers);
-#endif
-	snd_ioctl32_unregister(hwdep_mappers);
-	snd_ioctl32_unregister(timer_mappers);
-	snd_ioctl32_unregister(rawmidi_mappers);
-	snd_ioctl32_unregister(pcm_mappers);
-	snd_ioctl32_unregister(control_mappers);
-}
-
-static int __init snd_ioctl32_init(void)
-{
-	snd_ioctl32_register(control_mappers);
-	snd_ioctl32_register(pcm_mappers);
-	snd_ioctl32_register(rawmidi_mappers);
-	snd_ioctl32_register(timer_mappers);
-	snd_ioctl32_register(hwdep_mappers);
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-	snd_ioctl32_register(seq_mappers);
-#endif
-	return 0;
-}
-
-module_init(snd_ioctl32_init)
-module_exit(snd_ioctl32_done)
diff -Nru a/sound/core/ioctl32/ioctl32.h b/sound/core/ioctl32/ioctl32.h
--- a/sound/core/ioctl32/ioctl32.h	2005-02-09 18:36:41 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,102 +0,0 @@
-/*
- *   32bit -> 64bit ioctl helpers
- *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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
- *
- *
- * This file registers the converters from 32-bit ioctls to 64-bit ones.
- * The converter assumes that a 32-bit user-pointer can be casted by compat_ptr(x)
- * macro to a valid 64-bit pointer which is accessible via copy_from/to_user.
- *
- */
-
-#ifndef __ALSA_IOCTL32_H
-#define __ALSA_IOCTL32_H
-
-#include <linux/compat.h>
-
-#define COPY(x) \
-	do { \
-		if (copy_in_user(&dst->x, &src->x, sizeof(dst->x))) \
-			return -EFAULT; \
-	} while (0)
-
-#define COPY_ARRAY(x) \
-	do { \
-		if (copy_in_user(dst->x, src->x, sizeof(dst->x))) \
-			return -EFAULT; \
-	} while (0)
-
-#define COPY_CVT(x) \
-	do { \
-		__typeof__(src->x) __val_tmp; \
-		if (get_user(__val_tmp, &src->x) || \
-		    put_user(__val_tmp, &dst->x))\
-			return -EFAULT; \
-	} while (0)
-
-#define convert_from_32(type, dstp, srcp)\
-{\
-	struct sndrv_##type __user *dst = dstp;\
-	struct sndrv_##type##32 __user *src = srcp;\
-	CVT_##sndrv_##type();\
-}
-
-#define convert_to_32(type, dstp, srcp)\
-{\
-	struct sndrv_##type __user *src = srcp;\
-	struct sndrv_##type##32 __user *dst = dstp;\
-	CVT_##sndrv_##type();\
-}
-
-
-#define DEFINE_ALSA_IOCTL(type) \
-static inline int _snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)\
-{\
-	struct sndrv_##type##32 __user *data32;\
-	struct sndrv_##type __user *data;\
-	int err;\
-	data32 = compat_ptr(arg);\
-	data = compat_alloc_user_space(sizeof(*data));\
-	convert_from_32(type, data, data32);\
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);\
-	if (err < 0) \
-		return err;\
-	if (native_ctl & (_IOC_READ << _IOC_DIRSHIFT)) {\
-		convert_to_32(type, data32, data);\
-	}\
-	return 0;\
-}
-
-#define DEFINE_ALSA_IOCTL_ENTRY(name,type,native_ctl) \
-static int snd_ioctl32_##name(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file) {\
-	return _snd_ioctl32_##type(fd, cmd, arg, file, native_ctl);\
-}
-
-#define MAP_COMPAT(ctl) { ctl, snd_ioctl32_compat }
-
-struct ioctl32_mapper {
-	unsigned int cmd;
-	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
-	int registered;
-};
-
-int snd_ioctl32_compat(unsigned int, unsigned int, unsigned long, struct file *);
-
-int snd_ioctl32_register(struct ioctl32_mapper *mappers);
-void snd_ioctl32_unregister(struct ioctl32_mapper *mappers);
-
-#endif /* __ALSA_IOCTL32_H */
diff -Nru a/sound/core/ioctl32/pcm32.c b/sound/core/ioctl32/pcm32.c
--- a/sound/core/ioctl32/pcm32.c	2005-02-09 18:36:41 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,461 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for PCM API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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/time.h>
-#include <linux/slab.h>
-#include <linux/compat.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/minors.h>
-#include "ioctl32.h"
-
-
-/* wrapper for sndrv_pcm_[us]frames */
-struct sndrv_pcm_sframes_str {
-	sndrv_pcm_sframes_t val;
-};
-struct sndrv_pcm_sframes_str32 {
-	s32 val;
-};
-struct sndrv_pcm_uframes_str {
-	sndrv_pcm_uframes_t val;
-};
-struct sndrv_pcm_uframes_str32 {
-	u32 val;
-};
-
-#define CVT_sndrv_pcm_sframes_str() { COPY_CVT(val); }
-#define CVT_sndrv_pcm_uframes_str() { COPY_CVT(val); }
-
-
-struct sndrv_pcm_hw_params32 {
-	u32 flags;
-	struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
-	struct sndrv_mask mres[5];	/* reserved masks */
-	struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
-	struct sndrv_interval ires[9];	/* reserved intervals */
-	u32 rmask;
-	u32 cmask;
-	u32 info;
-	u32 msbits;
-	u32 rate_num;
-	u32 rate_den;
-	u32 fifo_size;
-	unsigned char reserved[64];
-} __attribute__((packed));
-
-struct sndrv_pcm_sw_params32 {
-	s32 tstamp_mode;
-	u32 period_step;
-	u32 sleep_min;
-	u32 avail_min;
-	u32 xfer_align;
-	u32 start_threshold;
-	u32 stop_threshold;
-	u32 silence_threshold;
-	u32 silence_size;
-	u32 boundary;
-	unsigned char reserved[64];
-} __attribute__((packed));
-
-#define CVT_sndrv_pcm_sw_params()\
-{\
-	COPY(tstamp_mode);\
-	COPY(period_step);\
-	COPY(sleep_min);\
-	COPY_CVT(avail_min);\
-	COPY_CVT(xfer_align);\
-	COPY_CVT(start_threshold);\
-	COPY_CVT(stop_threshold);\
-	COPY_CVT(silence_threshold);\
-	COPY_CVT(silence_size);\
-	COPY_CVT(boundary);\
-}
-
-struct sndrv_pcm_channel_info32 {
-	u32 channel;
-	u32 offset;
-	u32 first;
-	u32 step;
-} __attribute__((packed));
-
-#define CVT_sndrv_pcm_channel_info()\
-{\
-	COPY(channel);\
-	COPY_CVT(offset);\
-	COPY(first);\
-	COPY(step);\
-}
-
-struct sndrv_pcm_status32 {
-	s32 state;
-	struct compat_timespec trigger_tstamp;
-	struct compat_timespec tstamp;
-	u32 appl_ptr;
-	u32 hw_ptr;
-	s32 delay;
-	u32 avail;
-	u32 avail_max;
-	u32 overrange;
-	s32 suspended_state;
-	unsigned char reserved[60];
-} __attribute__((packed));
-
-#define CVT_sndrv_pcm_status()\
-{\
-	COPY(state);\
-	COPY_CVT(trigger_tstamp.tv_sec);\
-	COPY_CVT(trigger_tstamp.tv_nsec);\
-	COPY_CVT(tstamp.tv_sec);\
-	COPY_CVT(tstamp.tv_nsec);\
-	COPY_CVT(appl_ptr);\
-	COPY_CVT(hw_ptr);\
-	COPY_CVT(delay);\
-	COPY_CVT(avail);\
-	COPY_CVT(avail_max);\
-	COPY_CVT(overrange);\
-	COPY(suspended_state);\
-}
-
-DEFINE_ALSA_IOCTL(pcm_uframes_str);
-DEFINE_ALSA_IOCTL(pcm_sframes_str);
-DEFINE_ALSA_IOCTL(pcm_sw_params);
-DEFINE_ALSA_IOCTL(pcm_channel_info);
-DEFINE_ALSA_IOCTL(pcm_status);
-
-/* sanity device check */
-extern int snd_major;
-static int sanity_check_pcm(struct file *file)
-{
-	unsigned short minor;
-	if (imajor(file->f_dentry->d_inode) != snd_major)
-		return -ENOTTY;
-	minor = iminor(file->f_dentry->d_inode);
-	if (minor >= 256 || 
-	    minor % SNDRV_MINOR_DEVICES < SNDRV_MINOR_PCM_PLAYBACK)
-		return -ENOTTY;
-	return 0;
-}
-
-/* recalcuate the boundary within 32bit */
-static void recalculate_boundary(snd_pcm_runtime_t *runtime)
-{
-	if (! runtime->buffer_size)
-		return;
-	runtime->boundary = runtime->buffer_size;
-	while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
-		runtime->boundary *= 2;
-}
-
-/* both for HW_PARAMS and HW_REFINE */
-static int _snd_ioctl32_pcm_hw_params(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_pcm_hw_params32 __user *data32;
-	struct sndrv_pcm_hw_params *data;
-	snd_pcm_file_t *pcm_file;
-	snd_pcm_substream_t *substream;
-	snd_pcm_runtime_t *runtime;
-	int err;
-
-	if (sanity_check_pcm(file))
-		return -ENOTTY;
-	if (! (pcm_file = file->private_data))
-		return -ENOTTY;
-	if (! (substream = pcm_file->substream))
-		return -ENOTTY;
-	if (! (runtime = substream->runtime))
-		return -ENOTTY;
-
-	data32 = compat_ptr(arg);
-	data = kmalloc(sizeof(*data), GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-	if (copy_from_user(data, data32, sizeof(*data32))) {
-		err = -EFAULT;
-		goto error;
-	}
-	if (native_ctl == SNDRV_PCM_IOCTL_HW_REFINE)
-		err = snd_pcm_hw_refine(substream, data);
-	else
-		err = snd_pcm_hw_params(substream, data);
-	if (err < 0)
-		goto error;
-	if (copy_to_user(data32, data, sizeof(*data32)) ||
-	    __put_user((u32)data->fifo_size, &data32->fifo_size)) {
-		err = -EFAULT;
-		goto error;
-	}
-
-	if (native_ctl == SNDRV_PCM_IOCTL_HW_PARAMS)
-		recalculate_boundary(runtime);
- error:
-	kfree(data);
-	return err;
-}
-
-
-/*
- */
-struct sndrv_xferi32 {
-	s32 result;
-	u32 buf;
-	u32 frames;
-} __attribute__((packed));
-
-static int _snd_ioctl32_xferi(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	struct sndrv_xferi32 data32;
-	struct sndrv_xferi __user *data;
-	snd_pcm_sframes_t result;
-	int err;
-
-	if (copy_from_user(&data32, (void __user *)arg, sizeof(data32)))
-		return -EFAULT;
-	data = compat_alloc_user_space(sizeof(*data));
-	if (put_user((snd_pcm_sframes_t)data32.result, &data->result) ||
-	    __put_user(compat_ptr(data32.buf), &data->buf) ||
-	    __put_user((snd_pcm_uframes_t)data32.frames, &data->frames))
-		return -EFAULT;
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
-	if (err < 0)
-		return err;
-	/* copy the result */
-	if (__get_user(result, &data->result))
-		return -EFAULT;
-	data32.result = result;
-	if (copy_to_user((void __user *)arg, &data32, sizeof(data32)))
-		return -EFAULT;
-	return 0;
-}
-
-
-/* snd_xfern needs remapping of bufs */
-struct sndrv_xfern32 {
-	s32 result;
-	u32 bufs;  /* this is void **; */
-	u32 frames;
-} __attribute__((packed));
-
-/*
- * xfern ioctl nees to copy (up to) 128 pointers on stack.
- * although we may pass the copied pointers through f_op->ioctl, but the ioctl
- * handler there expands again the same 128 pointers on stack, so it is better
- * to handle the function (calling pcm_readv/writev) directly in this handler.
- */
-static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
-{
-	snd_pcm_file_t *pcm_file;
-	snd_pcm_substream_t *substream;
-	struct sndrv_xfern32 __user *srcptr = compat_ptr(arg);
-	struct sndrv_xfern32 data32;
-	void __user **bufs;
-	int err = 0, ch, i;
-	u32 __user *bufptr;
-
-	if (sanity_check_pcm(file))
-		return -ENOTTY;
-	if (! (pcm_file = file->private_data))
-		return -ENOTTY;
-	if (! (substream = pcm_file->substream))
-		return -ENOTTY;
-	if (! substream->runtime)
-		return -ENOTTY;
-
-	/* check validty of the command */
-	switch (native_ctl) {
-	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
-		if (substream->stream  != SNDRV_PCM_STREAM_PLAYBACK)
-			return -EINVAL;
-		if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
-			return -EBADFD;
-		break;
-	case SNDRV_PCM_IOCTL_READN_FRAMES:
-		if (substream->stream  != SNDRV_PCM_STREAM_CAPTURE)
-			return -EINVAL;
-		break;
-	}
-	if ((ch = substream->runtime->channels) > 128)
-		return -EINVAL;
-	if (copy_from_user(&data32, (void __user *)arg, sizeof(data32)))
-		return -EFAULT;
-	bufptr = compat_ptr(data32.bufs);
-	bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL);
-	if (bufs == NULL)
-		return -ENOMEM;
-	for (i = 0; i < ch; i++) {
-		u32 ptr;
-		if (get_user(ptr, bufptr)) {
-			kfree(bufs);
-			return -EFAULT;
-		}
-		bufs[ch] = compat_ptr(ptr);
-		bufptr++;
-	}
-	switch (native_ctl) {
-	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
-		err = snd_pcm_lib_writev(substream, bufs, data32.frames);
-		break;
-	case SNDRV_PCM_IOCTL_READN_FRAMES:
-		err = snd_pcm_lib_readv(substream, bufs, data32.frames);
-		break;
-	}
-	if (err >= 0) {
-		if (put_user(err, &srcptr->result))
-			err = -EFAULT;
-	}
-	kfree(bufs);
-	return err;
-}
-
-
-struct sndrv_pcm_mmap_status32 {
-	s32 state;
-	s32 pad1;
-	u32 hw_ptr;
-	struct compat_timespec tstamp;
-	s32 suspended_state;
-} __attribute__((packed));
-
-struct sndrv_pcm_mmap_control32 {
-	u32 appl_ptr;
-	u32 avail_min;
-} __attribute__((packed));
-
-struct sndrv_pcm_sync_ptr32 {
-	u32 flags;
-	union {
-		struct sndrv_pcm_mmap_status32 status;
-		unsigned char reserved[64];
-	} s;
-	union {
-		struct sndrv_pcm_mmap_control32 control;
-		unsigned char reserved[64];
-	} c;
-} __attribute__((packed));
-
-#define CVT_sndrv_pcm_sync_ptr()\
-{\
-	COPY(flags);\
-	COPY(s.status.state);\
-	COPY(s.status.pad1);\
-	COPY_CVT(s.status.hw_ptr);\
-	COPY_CVT(s.status.tstamp.tv_sec);\
-	COPY_CVT(s.status.tstamp.tv_nsec);\
-	COPY(s.status.suspended_state);\
-	COPY_CVT(c.control.appl_ptr);\
-	COPY_CVT(c.control.avail_min);\
-}
-
-DEFINE_ALSA_IOCTL(pcm_sync_ptr);
-
-/*
- */
-
-DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_refine, pcm_hw_params, SNDRV_PCM_IOCTL_HW_REFINE);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_params, pcm_hw_params, SNDRV_PCM_IOCTL_HW_PARAMS);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_sw_params, pcm_sw_params, SNDRV_PCM_IOCTL_SW_PARAMS);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_status, pcm_status, SNDRV_PCM_IOCTL_STATUS);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_delay, pcm_sframes_str, SNDRV_PCM_IOCTL_DELAY);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_channel_info, pcm_channel_info, SNDRV_PCM_IOCTL_CHANNEL_INFO);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_rewind, pcm_uframes_str, SNDRV_PCM_IOCTL_REWIND);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_readi, xferi, SNDRV_PCM_IOCTL_READI_FRAMES);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_writei, xferi, SNDRV_PCM_IOCTL_WRITEI_FRAMES);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_readn, xfern, SNDRV_PCM_IOCTL_READN_FRAMES);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_writen, xfern, SNDRV_PCM_IOCTL_WRITEN_FRAMES);
-DEFINE_ALSA_IOCTL_ENTRY(pcm_sync_ptr, pcm_sync_ptr, SNDRV_PCM_IOCTL_SYNC_PTR);
-
-
-/*
- * When PCM is used on 32bit mode, we need to disable
- * mmap of PCM status/control records because of the size
- * incompatibility.
- * 
- * Since INFO ioctl is always called at first, we mark the
- * mmap-disabling in this ioctl wrapper.
- */
-static int snd_pcm_info_ioctl32(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp)
-{
-	snd_pcm_file_t *pcm_file;
-	snd_pcm_substream_t *substream;
-	if (! filp->f_op || ! filp->f_op->ioctl)
-		return -ENOTTY;
-	pcm_file = filp->private_data;
-	if (! pcm_file)
-		return -ENOTTY;
-	substream = pcm_file->substream;
-	if (! substream)
-		return -ENOTTY;
-	substream->no_mmap_ctrl = 1;
-	return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
-}
-
-/*
- */
-#define AP(x) snd_ioctl32_##x
-
-enum {
-	SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params32),
-	SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params32),
-	SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct sndrv_pcm_sw_params32),
-	SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct sndrv_pcm_status32),
-	SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
-	SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct sndrv_pcm_channel_info32),
-	SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
-	SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct sndrv_xferi32),
-	SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct sndrv_xferi32),
-	SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct sndrv_xfern32),
-	SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct sndrv_xfern32),
-	SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr32),
-
-};
-
-struct ioctl32_mapper pcm_mappers[] = {
-	MAP_COMPAT(SNDRV_PCM_IOCTL_PVERSION),
-	/* MAP_COMPAT(SNDRV_PCM_IOCTL_INFO), */
-	{ SNDRV_PCM_IOCTL_INFO, snd_pcm_info_ioctl32 },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_TSTAMP),
-	{ SNDRV_PCM_IOCTL_HW_REFINE32, AP(pcm_hw_refine) },
-	{ SNDRV_PCM_IOCTL_HW_PARAMS32, AP(pcm_hw_params) },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_HW_FREE),
-	{ SNDRV_PCM_IOCTL_SW_PARAMS32, AP(pcm_sw_params) },
-	{ SNDRV_PCM_IOCTL_STATUS32, AP(pcm_status) },
-	{ SNDRV_PCM_IOCTL_DELAY32, AP(pcm_delay) },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_HWSYNC),
-	{ SNDRV_PCM_IOCTL_SYNC_PTR32, AP(pcm_sync_ptr) },
-	{ SNDRV_PCM_IOCTL_CHANNEL_INFO32, AP(pcm_channel_info) },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_PREPARE),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_RESET),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_START),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_DROP),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_DRAIN),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_PAUSE),
-	{ SNDRV_PCM_IOCTL_REWIND32, AP(pcm_rewind) },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_RESUME),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_XRUN),
-	{ SNDRV_PCM_IOCTL_WRITEI_FRAMES32, AP(pcm_writei) },
-	{ SNDRV_PCM_IOCTL_READI_FRAMES32, AP(pcm_readi) },
-	{ SNDRV_PCM_IOCTL_WRITEN_FRAMES32, AP(pcm_writen) },
-	{ SNDRV_PCM_IOCTL_READN_FRAMES32, AP(pcm_readn) },
-	MAP_COMPAT(SNDRV_PCM_IOCTL_LINK),
-	MAP_COMPAT(SNDRV_PCM_IOCTL_UNLINK),
-
-	{ 0 },
-};
diff -Nru a/sound/core/ioctl32/rawmidi32.c b/sound/core/ioctl32/rawmidi32.c
--- a/sound/core/ioctl32/rawmidi32.c	2005-02-09 18:36:41 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,91 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for raw MIDI API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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/time.h>
-#include <linux/fs.h>
-#include <linux/compat.h>
-#include <sound/core.h>
-#include <sound/rawmidi.h>
-#include <asm/uaccess.h>
-#include "ioctl32.h"
-
-struct sndrv_rawmidi_params32 {
-	s32 stream;
-	u32 buffer_size;
-	u32 avail_min;
-	unsigned int no_active_sensing; /* avoid bit-field */
-	unsigned char reserved[16];
-} __attribute__((packed));
-
-#define CVT_sndrv_rawmidi_params()\
-{\
-	COPY(stream);\
-	COPY_CVT(buffer_size);\
-	COPY_CVT(avail_min);\
-	if (copy_in_user(((size_t __user *)&dst->avail_min + 1),\
-			 ((size_t __user *)&src->avail_min + 1), 4)) \
-		return -EFAULT;\
-}
-
-struct sndrv_rawmidi_status32 {
-	s32 stream;
-	struct compat_timespec tstamp;
-	u32 avail;
-	u32 xruns;
-	unsigned char reserved[16];
-} __attribute__((packed));
-
-#define CVT_sndrv_rawmidi_status()\
-{\
-	COPY(stream);\
-	COPY_CVT(tstamp.tv_sec);\
-	COPY_CVT(tstamp.tv_nsec);\
-	COPY_CVT(avail);\
-	COPY_CVT(xruns);\
-}
-
-DEFINE_ALSA_IOCTL(rawmidi_params);
-DEFINE_ALSA_IOCTL(rawmidi_status);
-
-DEFINE_ALSA_IOCTL_ENTRY(rawmidi_params, rawmidi_params, SNDRV_RAWMIDI_IOCTL_PARAMS);
-DEFINE_ALSA_IOCTL_ENTRY(rawmidi_status, rawmidi_status, SNDRV_RAWMIDI_IOCTL_STATUS);
-
-#define AP(x) snd_ioctl32_##x
-
-enum {
-	SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32),
-	SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32),
-};
-
-struct ioctl32_mapper rawmidi_mappers[] = {
-	MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_PVERSION),
-	MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_INFO),
-	{ SNDRV_RAWMIDI_IOCTL_PARAMS32, AP(rawmidi_params) },
-	{ SNDRV_RAWMIDI_IOCTL_STATUS32, AP(rawmidi_status) },
-	MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_DROP),
-	MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_DRAIN),
-
-	MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_INFO),
-	MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE),
-
-	{ 0 },
-};
diff -Nru a/sound/core/ioctl32/seq32.c b/sound/core/ioctl32/seq32.c
--- a/sound/core/ioctl32/seq32.c	2005-02-09 18:36:41 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,116 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for sequencer API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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/time.h>
-#include <linux/fs.h>
-#include <sound/core.h>
-#include <sound/timer.h>
-#include <asm/uaccess.h>
-#include <sound/asequencer.h>
-#include "ioctl32.h"
-
-struct sndrv_seq_port_info32 {
-	struct sndrv_seq_addr addr;	/* client/port numbers */
-	char name[64];			/* port name */
-
-	u32 capability;	/* port capability bits */
-	u32 type;		/* port type bits */
-	s32 midi_channels;		/* channels per MIDI port */
-	s32 midi_voices;		/* voices per MIDI port */
-	s32 synth_voices;		/* voices per SYNTH port */
-
-	s32 read_use;			/* R/O: subscribers for output (from this port) */
-	s32 write_use;			/* R/O: subscribers for input (to this port) */
-
-	u32 kernel;			/* reserved for kernel use (must be NULL) */
-	u32 flags;		/* misc. conditioning */
-	unsigned char time_queue;	/* queue # for timestamping */
-	char reserved[59];		/* for future use */
-};
-
-#define CVT_sndrv_seq_port_info()\
-{\
-	COPY(addr);\
-	COPY_ARRAY(name);\
-	COPY(capability);\
-	COPY(type);\
-	COPY(midi_channels);\
-	COPY(midi_voices);\
-	COPY(synth_voices);\
-	COPY(read_use);\
-	COPY(write_use);\
-	COPY(flags);\
-	COPY(time_queue);\
-}
-
-DEFINE_ALSA_IOCTL(seq_port_info);
-DEFINE_ALSA_IOCTL_ENTRY(create_port, seq_port_info, SNDRV_SEQ_IOCTL_CREATE_PORT);
-DEFINE_ALSA_IOCTL_ENTRY(delete_port, seq_port_info, SNDRV_SEQ_IOCTL_DELETE_PORT);
-DEFINE_ALSA_IOCTL_ENTRY(get_port_info, seq_port_info, SNDRV_SEQ_IOCTL_GET_PORT_INFO);
-DEFINE_ALSA_IOCTL_ENTRY(set_port_info, seq_port_info, SNDRV_SEQ_IOCTL_SET_PORT_INFO);
-DEFINE_ALSA_IOCTL_ENTRY(query_next_port, seq_port_info, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT);
-
-/*
- */
-#define AP(x) snd_ioctl32_##x
-
-enum {
-  SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
-  SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
-  SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
-  SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
-  SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
-};
-
-struct ioctl32_mapper seq_mappers[] = {
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_PVERSION),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_CLIENT_ID),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SYSTEM_INFO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_CLIENT_INFO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_CLIENT_INFO),
-	{ SNDRV_SEQ_IOCTL_CREATE_PORT32, AP(create_port) },
-	{ SNDRV_SEQ_IOCTL_DELETE_PORT32, AP(delete_port) },
-	{ SNDRV_SEQ_IOCTL_GET_PORT_INFO32, AP(get_port_info) },
-	{ SNDRV_SEQ_IOCTL_SET_PORT_INFO32, AP(set_port_info) },
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_CREATE_QUEUE),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_DELETE_QUEUE),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_INFO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_INFO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_CLIENT_POOL),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_CLIENT_POOL),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_REMOVE_EVENTS),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_QUERY_SUBS),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION),
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT),
-	{ SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32, AP(query_next_port) },
-	MAP_COMPAT(SNDRV_SEQ_IOCTL_RUNNING_MODE),
-	{ 0 },
-};
diff -Nru a/sound/core/ioctl32/timer32.c b/sound/core/ioctl32/timer32.c
--- a/sound/core/ioctl32/timer32.c	2005-02-09 18:36:41 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,105 +0,0 @@
-/*
- *   32bit -> 64bit ioctl wrapper for timer API
- *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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/time.h>
-#include <linux/fs.h>
-#include <linux/compat.h>
-#include <sound/core.h>
-#include <sound/timer.h>
-#include <asm/uaccess.h>
-#include "ioctl32.h"
-
-struct sndrv_timer_info32 {
-	u32 flags;
-	s32 card;
-	unsigned char id[64];
-	unsigned char name[80];
-	u32 reserved0;
-	u32 resolution;
-	unsigned char reserved[64];
-};
-
-#define CVT_sndrv_timer_info()\
-{\
-	COPY(flags);\
-	COPY(card);\
-	COPY_ARRAY(id);\
-	COPY_ARRAY(name);\
-	COPY_CVT(resolution);\
-}
-
-struct sndrv_timer_status32 {
-	struct compat_timespec tstamp;
-	u32 resolution;
-	u32 lost;
-	u32 overrun;
-	u32 queue;
-	unsigned char reserved[64];
-};
-
-#define CVT_sndrv_timer_status()\
-{\
-	COPY_CVT(tstamp.tv_sec);\
-	COPY_CVT(tstamp.tv_nsec);\
-	COPY(resolution);\
-	COPY(lost);\
-	COPY(overrun);\
-	COPY(queue);\
-}
-
-DEFINE_ALSA_IOCTL(timer_info);
-DEFINE_ALSA_IOCTL(timer_status);
-
-DEFINE_ALSA_IOCTL_ENTRY(timer_info, timer_info, SNDRV_TIMER_IOCTL_INFO);
-DEFINE_ALSA_IOCTL_ENTRY(timer_status, timer_status, SNDRV_TIMER_IOCTL_STATUS);
-
-/*
- */
-
-#define AP(x) snd_ioctl32_##x
-
-enum {
-	SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32),
-	SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32),
-};
-
-struct ioctl32_mapper timer_mappers[] = {
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_PVERSION),
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_NEXT_DEVICE),
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_SELECT),
-	{ SNDRV_TIMER_IOCTL_INFO32, AP(timer_info) },
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_PARAMS),
-	{ SNDRV_TIMER_IOCTL_STATUS32, AP(timer_status) },
-#if 0
-	/* ** FIXME **
-	 * The following four entries are disabled because they conflict
-	 * with the TCOC* definitions.
-	 * Unfortunately, the current ioctl32 wrapper uses a single
-	 * hash table for all devices.  Once when the wrapper is fixed
-	 * with the table based on devices, they'll be back again.
-	 */
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_START),
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_STOP),
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_CONTINUE),
-	MAP_COMPAT(SNDRV_TIMER_IOCTL_PAUSE),
-#endif
-	{ 0 },
-};
diff -Nru a/sound/core/memory.c b/sound/core/memory.c
--- a/sound/core/memory.c	2005-02-09 18:36:40 -08:00
+++ b/sound/core/memory.c	2005-02-09 18:36:40 -08:00
@@ -50,8 +50,8 @@
 static long snd_alloc_vmalloc;
 static LIST_HEAD(snd_alloc_kmalloc_list);
 static LIST_HEAD(snd_alloc_vmalloc_list);
-static spinlock_t snd_alloc_kmalloc_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t snd_alloc_vmalloc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(snd_alloc_kmalloc_lock);
+static DEFINE_SPINLOCK(snd_alloc_vmalloc_lock);
 #define KMALLOC_MAGIC 0x87654321
 #define VMALLOC_MAGIC 0x87654320
 static snd_info_entry_t *snd_memory_info_entry;
diff -Nru a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
--- a/sound/core/oss/mixer_oss.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/oss/mixer_oss.c	2005-02-09 18:36:41 -08:00
@@ -359,16 +359,9 @@
 	return -ENXIO;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_mixer_oss_ioctl(struct inode *inode, struct file *file,
-			       unsigned int cmd, unsigned long arg)
+static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-	int err;
-	/* FIXME: need to unlock BKL to allow preemption */
-	unlock_kernel();
-	err = snd_mixer_oss_ioctl1((snd_mixer_oss_file_t *) file->private_data, cmd, arg);
-	lock_kernel();
-	return err;
+	return snd_mixer_oss_ioctl1((snd_mixer_oss_file_t *) file->private_data, cmd, arg);
 }
 
 int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg)
@@ -384,6 +377,13 @@
 	return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
 }
 
+#ifdef CONFIG_COMPAT
+/* all compatible */
+#define snd_mixer_oss_ioctl_compat	snd_mixer_oss_ioctl
+#else
+#define snd_mixer_oss_ioctl_compat	NULL
+#endif
+
 /*
  *  REGISTRATION PART
  */
@@ -393,7 +393,8 @@
 	.owner =	THIS_MODULE,
 	.open =		snd_mixer_oss_open,
 	.release =	snd_mixer_oss_release,
-	.ioctl =	snd_mixer_oss_ioctl,
+	.unlocked_ioctl =	snd_mixer_oss_ioctl,
+	.compat_ioctl =	snd_mixer_oss_ioctl_compat,
 };
 
 static snd_minor_t snd_mixer_oss_reg =
diff -Nru a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
--- a/sound/core/oss/pcm_oss.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/oss/pcm_oss.c	2005-02-09 18:36:41 -08:00
@@ -1913,8 +1913,7 @@
 	return 0;
 }
 
-static inline int _snd_pcm_oss_ioctl(struct inode *inode, struct file *file,
-				     unsigned int cmd, unsigned long arg)
+static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_pcm_oss_file_t *pcm_oss_file;
 	int __user *p = (int __user *)arg;
@@ -2073,16 +2072,12 @@
 	return -EINVAL;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_pcm_oss_ioctl(struct inode *inode, struct file *file,
-			     unsigned int cmd, unsigned long arg)
-{
-	int err;
-	unlock_kernel();
-	err = _snd_pcm_oss_ioctl(inode, file, cmd, arg);
-	lock_kernel();
-	return err;
-}
+#ifdef CONFIG_COMPAT
+/* all compatible */
+#define snd_pcm_oss_ioctl_compat	snd_pcm_oss_ioctl
+#else
+#define snd_pcm_oss_ioctl_compat	NULL
+#endif
 
 static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
 {
@@ -2410,7 +2405,8 @@
 	.open =		snd_pcm_oss_open,
 	.release =	snd_pcm_oss_release,
 	.poll =		snd_pcm_oss_poll,
-	.ioctl =	snd_pcm_oss_ioctl,
+	.unlocked_ioctl =	snd_pcm_oss_ioctl,
+	.compat_ioctl =	snd_pcm_oss_ioctl_compat,
 	.mmap =		snd_pcm_oss_mmap,
 };
 
diff -Nru a/sound/core/pcm.c b/sound/core/pcm.c
--- a/sound/core/pcm.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/pcm.c	2005-02-09 18:36:41 -08:00
@@ -1004,6 +1004,7 @@
 	snd_info_entry_t *entry;
 
 	snd_ctl_register_ioctl(snd_pcm_control_ioctl);
+	snd_ctl_register_ioctl_compat(snd_pcm_control_ioctl);
 	if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {
 		snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128, snd_pcm_proc_read);
 		if (snd_info_register(entry) < 0) {
@@ -1018,6 +1019,7 @@
 static void __exit alsa_pcm_exit(void)
 {
 	snd_ctl_unregister_ioctl(snd_pcm_control_ioctl);
+	snd_ctl_unregister_ioctl_compat(snd_pcm_control_ioctl);
 	if (snd_pcm_proc_entry) {
 		snd_info_unregister(snd_pcm_proc_entry);
 		snd_pcm_proc_entry = NULL;
diff -Nru a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/core/pcm_compat.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,513 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for PCM API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   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
+ *
+ */
+
+/* This file included from pcm_native.c */
+
+#include <linux/compat.h>
+
+static int snd_pcm_ioctl_delay_compat(snd_pcm_substream_t *substream,
+				      s32 __user *src)
+{
+	snd_pcm_sframes_t delay;
+	mm_segment_t fs;
+	int err;
+
+	fs = snd_enter_user();
+	err = snd_pcm_delay(substream, &delay);
+	snd_leave_user(fs);
+	if (err < 0)
+		return err;
+	if (put_user(delay, src))
+		return -EFAULT;
+	return err;
+}
+
+static int snd_pcm_ioctl_rewind_compat(snd_pcm_substream_t *substream,
+				       u32 __user *src)
+{
+	snd_pcm_uframes_t frames;
+	int err;
+
+	if (get_user(frames, src))
+		return -EFAULT;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		err = snd_pcm_playback_rewind(substream, frames);
+	else
+		err = snd_pcm_capture_rewind(substream, frames);
+	if (put_user(err, src))
+		return -EFAULT;
+	return err < 0 ? err : 0;
+}
+
+static int snd_pcm_ioctl_forward_compat(snd_pcm_substream_t *substream,
+				       u32 __user *src)
+{
+	snd_pcm_uframes_t frames;
+	int err;
+
+	if (get_user(frames, src))
+		return -EFAULT;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		err = snd_pcm_playback_forward(substream, frames);
+	else
+		err = snd_pcm_capture_forward(substream, frames);
+	if (put_user(err, src))
+		return -EFAULT;
+	return err < 0 ? err : 0;
+}
+
+struct sndrv_pcm_hw_params32 {
+	u32 flags;
+	struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
+	struct sndrv_mask mres[5];	/* reserved masks */
+	struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+	struct sndrv_interval ires[9];	/* reserved intervals */
+	u32 rmask;
+	u32 cmask;
+	u32 info;
+	u32 msbits;
+	u32 rate_num;
+	u32 rate_den;
+	u32 fifo_size;
+	unsigned char reserved[64];
+};
+
+struct sndrv_pcm_sw_params32 {
+	s32 tstamp_mode;
+	u32 period_step;
+	u32 sleep_min;
+	u32 avail_min;
+	u32 xfer_align;
+	u32 start_threshold;
+	u32 stop_threshold;
+	u32 silence_threshold;
+	u32 silence_size;
+	u32 boundary;
+	unsigned char reserved[64];
+};
+
+static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
+					  struct sndrv_pcm_sw_params32 __user *src)
+{
+	snd_pcm_sw_params_t params;
+	int err;
+
+	memset(&params, 0, sizeof(params));
+	if (get_user(params.tstamp_mode, &src->tstamp_mode) ||
+	    get_user(params.period_step, &src->period_step) ||
+	    get_user(params.sleep_min, &src->sleep_min) ||
+	    get_user(params.avail_min, &src->avail_min) ||
+	    get_user(params.xfer_align, &src->xfer_align) ||
+	    get_user(params.start_threshold, &src->start_threshold) ||
+	    get_user(params.stop_threshold, &src->stop_threshold) ||
+	    get_user(params.silence_threshold, &src->silence_threshold) ||
+	    get_user(params.silence_size, &src->silence_size))
+		return -EFAULT;
+	err = snd_pcm_sw_params(substream, &params);
+	if (err < 0)
+		return err;
+	if (put_user(params.boundary, &src->boundary))
+		return -EFAULT;
+	return err;
+}
+
+struct sndrv_pcm_channel_info32 {
+	u32 channel;
+	u32 offset;
+	u32 first;
+	u32 step;
+};
+
+static int snd_pcm_ioctl_channel_info_compat(snd_pcm_substream_t *substream,
+					     struct sndrv_pcm_channel_info32 __user *src)
+{
+	snd_pcm_channel_info_t info;
+	int err;
+
+	if (get_user(info.channel, &src->channel) ||
+	    get_user(info.offset, &src->offset) ||
+	    get_user(info.first, &src->first) ||
+	    get_user(info.step, &src->step))
+		return -EFAULT;
+	err = snd_pcm_channel_info(substream, &info);
+	if (err < 0)
+		return err;
+	if (put_user(info.channel, &src->channel) ||
+	    put_user(info.offset, &src->offset) ||
+	    put_user(info.first, &src->first) ||
+	    put_user(info.step, &src->step))
+		return -EFAULT;
+	return err;
+}
+
+struct sndrv_pcm_status32 {
+	s32 state;
+	struct compat_timespec trigger_tstamp;
+	struct compat_timespec tstamp;
+	u32 appl_ptr;
+	u32 hw_ptr;
+	s32 delay;
+	u32 avail;
+	u32 avail_max;
+	u32 overrange;
+	s32 suspended_state;
+	unsigned char reserved[60];
+} __attribute__((packed));
+
+
+static int snd_pcm_status_user_compat(snd_pcm_substream_t *substream,
+				      struct sndrv_pcm_status32 __user *src)
+{
+	snd_pcm_status_t status;
+	int err;
+
+	err = snd_pcm_status(substream, &status);
+	if (err < 0)
+		return err;
+
+	if (put_user(status.state, &src->state) ||
+	    put_user(status.trigger_tstamp.tv_sec, &src->trigger_tstamp.tv_sec) ||
+	    put_user(status.trigger_tstamp.tv_nsec, &src->trigger_tstamp.tv_nsec) ||
+	    put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
+	    put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
+	    put_user(status.appl_ptr, &src->appl_ptr) ||
+	    put_user(status.hw_ptr, &src->hw_ptr) ||
+	    put_user(status.delay, &src->delay) ||
+	    put_user(status.avail, &src->avail) ||
+	    put_user(status.avail_max, &src->avail_max) ||
+	    put_user(status.overrange, &src->overrange) ||
+	    put_user(status.suspended_state, &src->suspended_state))
+		return -EFAULT;
+
+	return err;
+}
+
+/* recalcuate the boundary within 32bit */
+static void recalculate_boundary(snd_pcm_runtime_t *runtime)
+{
+	if (! runtime->buffer_size)
+		return;
+	runtime->boundary = runtime->buffer_size;
+	while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
+		runtime->boundary *= 2;
+}
+
+/* both for HW_PARAMS and HW_REFINE */
+static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
+					  int refine, 
+					  struct sndrv_pcm_hw_params32 __user *data32)
+{
+	struct sndrv_pcm_hw_params *data;
+	snd_pcm_runtime_t *runtime;
+	int err;
+
+	if (! (runtime = substream->runtime))
+		return -ENOTTY;
+
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+	/* only fifo_size is different, so just copy all */
+	if (copy_from_user(data, data32, sizeof(*data32))) {
+		err = -EFAULT;
+		goto error;
+	}
+	if (refine)
+		err = snd_pcm_hw_refine(substream, data);
+	else
+		err = snd_pcm_hw_params(substream, data);
+	if (err < 0)
+		goto error;
+	if (copy_to_user(data32, data, sizeof(*data32)) ||
+	    put_user(data->fifo_size, &data32->fifo_size)) {
+		err = -EFAULT;
+		goto error;
+	}
+
+	if (! refine)
+		recalculate_boundary(runtime);
+ error:
+	kfree(data);
+	return err;
+}
+
+
+/*
+ */
+struct sndrv_xferi32 {
+	s32 result;
+	u32 buf;
+	u32 frames;
+};
+
+static int snd_pcm_ioctl_xferi_compat(snd_pcm_substream_t *substream,
+				      int dir, struct sndrv_xferi32 __user *data32)
+{
+	compat_caddr_t buf;
+	u32 frames;
+	int err;
+
+	if (! substream->runtime)
+		return -ENOTTY;
+	if (substream->stream != dir)
+		return -EINVAL;
+	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
+		return -EBADFD;
+
+	if (get_user(buf, &data32->buf) ||
+	    get_user(frames, &data32->frames))
+		return -EFAULT;
+
+	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+		err = snd_pcm_lib_write(substream, compat_ptr(buf), frames);
+	else
+		err = snd_pcm_lib_read(substream, compat_ptr(buf), frames);
+	if (err < 0)
+		return err;
+	/* copy the result */
+	if (put_user(err, &data32->result))
+		return -EFAULT;
+	return 0;
+}
+
+
+/* snd_xfern needs remapping of bufs */
+struct sndrv_xfern32 {
+	s32 result;
+	u32 bufs;  /* this is void **; */
+	u32 frames;
+};
+
+/*
+ * xfern ioctl nees to copy (up to) 128 pointers on stack.
+ * although we may pass the copied pointers through f_op->ioctl, but the ioctl
+ * handler there expands again the same 128 pointers on stack, so it is better
+ * to handle the function (calling pcm_readv/writev) directly in this handler.
+ */
+static int snd_pcm_ioctl_xfern_compat(snd_pcm_substream_t *substream,
+				      int dir, struct sndrv_xfern32 __user *data32)
+{
+	compat_caddr_t buf;
+	compat_caddr_t __user *bufptr;
+	u32 frames;
+	void __user **bufs;
+	int err, ch, i;
+
+	if (! substream->runtime)
+		return -ENOTTY;
+	if (substream->stream != dir)
+		return -EINVAL;
+
+	if ((ch = substream->runtime->channels) > 128)
+		return -EINVAL;
+	if (get_user(buf, &data32->bufs) ||
+	    get_user(frames, &data32->frames))
+		return -EFAULT;
+	bufptr = compat_ptr(buf);
+	bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL);
+	if (bufs == NULL)
+		return -ENOMEM;
+	for (i = 0; i < ch; i++) {
+		u32 ptr;
+		if (get_user(ptr, bufptr)) {
+			kfree(bufs);
+			return -EFAULT;
+		}
+		bufs[ch] = compat_ptr(ptr);
+		bufptr++;
+	}
+	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+		err = snd_pcm_lib_writev(substream, bufs, frames);
+	else
+		err = snd_pcm_lib_readv(substream, bufs, frames);
+	if (err >= 0) {
+		if (put_user(err, &data32->result))
+			err = -EFAULT;
+	}
+	kfree(bufs);
+	return err;
+}
+
+
+struct sndrv_pcm_mmap_status32 {
+	s32 state;
+	s32 pad1;
+	u32 hw_ptr;
+	struct compat_timespec tstamp;
+	s32 suspended_state;
+} __attribute__((packed));
+
+struct sndrv_pcm_mmap_control32 {
+	u32 appl_ptr;
+	u32 avail_min;
+};
+
+struct sndrv_pcm_sync_ptr32 {
+	u32 flags;
+	union {
+		struct sndrv_pcm_mmap_status32 status;
+		unsigned char reserved[64];
+	} s;
+	union {
+		struct sndrv_pcm_mmap_control32 control;
+		unsigned char reserved[64];
+	} c;
+} __attribute__((packed));
+
+static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
+					 struct sndrv_pcm_sync_ptr32 __user *src)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	volatile struct sndrv_pcm_mmap_status *status;
+	volatile struct sndrv_pcm_mmap_control *control;
+	u32 sflags;
+	struct sndrv_pcm_mmap_control scontrol;
+	struct sndrv_pcm_mmap_status sstatus;
+	int err;
+
+	snd_assert(runtime, return -EINVAL);
+
+	if (get_user(sflags, &src->flags) ||
+	    get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
+	    get_user(scontrol.avail_min, &src->c.control.avail_min))
+		return -EFAULT;
+	if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
+		err = snd_pcm_hwsync(substream);
+		if (err < 0)
+			return err;
+	}
+	status = runtime->status;
+	control = runtime->control;
+	snd_pcm_stream_lock_irq(substream);
+	if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
+		control->appl_ptr = scontrol.appl_ptr;
+	else
+		scontrol.appl_ptr = control->appl_ptr;
+	if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+		control->avail_min = scontrol.avail_min;
+	else
+		scontrol.avail_min = control->avail_min;
+	sstatus.state = status->state;
+	sstatus.hw_ptr = status->hw_ptr;
+	sstatus.tstamp = status->tstamp;
+	sstatus.suspended_state = status->suspended_state;
+	snd_pcm_stream_unlock_irq(substream);
+	if (put_user(sstatus.state, &src->s.status.state) ||
+	    put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
+	    put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp.tv_sec) ||
+	    put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp.tv_nsec) ||
+	    put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
+	    put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
+	    put_user(scontrol.avail_min, &src->c.control.avail_min))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+/*
+ */
+enum {
+	SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params32),
+	SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params32),
+	SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct sndrv_pcm_sw_params32),
+	SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct sndrv_pcm_status32),
+	SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
+	SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct sndrv_pcm_channel_info32),
+	SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
+	SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32),
+	SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct sndrv_xferi32),
+	SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct sndrv_xferi32),
+	SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct sndrv_xfern32),
+	SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct sndrv_xfern32),
+	SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr32),
+
+};
+
+static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	snd_pcm_file_t *pcm_file;
+	snd_pcm_substream_t *substream;
+	void __user *argp = compat_ptr(arg);
+
+	pcm_file = file->private_data;
+	if (! pcm_file)
+		return -ENOTTY;
+	substream = pcm_file->substream;
+	if (! substream)
+		return -ENOTTY;
+
+	/*
+	 * When PCM is used on 32bit mode, we need to disable
+	 * mmap of PCM status/control records because of the size
+	 * incompatibility.
+	 */
+	substream->no_mmap_ctrl = 1;
+
+	switch (cmd) {
+	case SNDRV_PCM_IOCTL_PVERSION:
+	case SNDRV_PCM_IOCTL_INFO:
+	case SNDRV_PCM_IOCTL_TSTAMP:
+	case SNDRV_PCM_IOCTL_HWSYNC:
+	case SNDRV_PCM_IOCTL_PREPARE:
+	case SNDRV_PCM_IOCTL_RESET:
+	case SNDRV_PCM_IOCTL_START:
+	case SNDRV_PCM_IOCTL_DROP:
+	case SNDRV_PCM_IOCTL_DRAIN:
+	case SNDRV_PCM_IOCTL_PAUSE:
+	case SNDRV_PCM_IOCTL_HW_FREE:
+	case SNDRV_PCM_IOCTL_RESUME:
+	case SNDRV_PCM_IOCTL_XRUN:
+	case SNDRV_PCM_IOCTL_LINK:
+	case SNDRV_PCM_IOCTL_UNLINK:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			return snd_pcm_playback_ioctl1(substream, cmd, argp);
+		else
+			return snd_pcm_capture_ioctl1(substream, cmd, argp);
+	case SNDRV_PCM_IOCTL_HW_REFINE32:
+		return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
+	case SNDRV_PCM_IOCTL_HW_PARAMS32:
+		return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
+	case SNDRV_PCM_IOCTL_SW_PARAMS32:
+		return snd_pcm_ioctl_sw_params_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_STATUS32:
+		return snd_pcm_status_user_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_SYNC_PTR32:
+		return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
+		return snd_pcm_ioctl_channel_info_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_WRITEI_FRAMES32:
+		return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
+	case SNDRV_PCM_IOCTL_READI_FRAMES32:
+		return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
+	case SNDRV_PCM_IOCTL_WRITEN_FRAMES32:
+		return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
+	case SNDRV_PCM_IOCTL_READN_FRAMES32:
+		return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
+	case SNDRV_PCM_IOCTL_DELAY32:
+		return snd_pcm_ioctl_delay_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_REWIND32:
+		return snd_pcm_ioctl_rewind_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_FORWARD32:
+		return snd_pcm_ioctl_forward_compat(substream, argp);
+	}
+
+	return -ENOIOCTLCMD;
+}
diff -Nru a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
--- a/sound/core/pcm_memory.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/pcm_memory.c	2005-02-09 18:36:41 -08:00
@@ -291,7 +291,7 @@
  * @substream: the substream to allocate the DMA buffer to
  * @size: the requested buffer size in bytes
  *
- * Allocates the DMA buffer on the BUS type given by
+ * Allocates the DMA buffer on the BUS type given earlier to
  * snd_pcm_lib_preallocate_xxx_pages().
  *
  * Returns 1 if the buffer is changed, 0 if not changed, or a negative
diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c
--- a/sound/core/pcm_native.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/pcm_native.c	2005-02-09 18:36:41 -08:00
@@ -65,7 +65,7 @@
  *
  */
 
-rwlock_t snd_pcm_link_rwlock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(snd_pcm_link_rwlock);
 static DECLARE_RWSEM(snd_pcm_link_rwsem);
 
 
@@ -2640,40 +2640,28 @@
 	return snd_pcm_common_ioctl1(substream, cmd, arg);
 }
 
-static int snd_pcm_playback_ioctl(struct inode *inode, struct file *file,
-				  unsigned int cmd, unsigned long arg)
+static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_pcm_file_t *pcm_file;
-	int err;
 
 	pcm_file = file->private_data;
 
 	if (((cmd >> 8) & 0xff) != 'A')
 		return -ENOTTY;
 
-	/* FIXME: need to unlock BKL to allow preemption */
-	unlock_kernel();
-	err = snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
-	lock_kernel();
-	return err;
+	return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
 }
 
-static int snd_pcm_capture_ioctl(struct inode *inode, struct file *file,
-				 unsigned int cmd, unsigned long arg)
+static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_pcm_file_t *pcm_file;
-	int err;
 
 	pcm_file = file->private_data;
 
 	if (((cmd >> 8) & 0xff) != 'A')
 		return -ENOTTY;
 
-	/* FIXME: need to unlock BKL to allow preemption */
-	unlock_kernel();
-	err = snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
-	lock_kernel();
-	return err;
+	return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
 }
 
 int snd_pcm_kernel_playback_ioctl(snd_pcm_substream_t *substream,
@@ -3198,6 +3186,15 @@
 }
 
 /*
+ * ioctl32 compat
+ */
+#ifdef CONFIG_COMPAT
+#include "pcm_compat.c"
+#else
+#define snd_pcm_ioctl_compat	NULL
+#endif
+
+/*
  *  To be removed helpers to keep binary compatibility
  */
 
@@ -3318,7 +3315,8 @@
 	.open =		snd_pcm_open,
 	.release =	snd_pcm_release,
 	.poll =		snd_pcm_playback_poll,
-	.ioctl =	snd_pcm_playback_ioctl,
+	.unlocked_ioctl =	snd_pcm_playback_ioctl,
+	.compat_ioctl = snd_pcm_ioctl_compat,
 	.mmap =		snd_pcm_mmap,
 	.fasync =	snd_pcm_fasync,
 };
@@ -3330,7 +3328,8 @@
 	.open =		snd_pcm_open,
 	.release =	snd_pcm_release,
 	.poll =		snd_pcm_capture_poll,
-	.ioctl =	snd_pcm_capture_ioctl,
+	.unlocked_ioctl =	snd_pcm_capture_ioctl,
+	.compat_ioctl = snd_pcm_ioctl_compat,
 	.mmap =		snd_pcm_mmap,
 	.fasync =	snd_pcm_fasync,
 };
diff -Nru a/sound/core/rawmidi.c b/sound/core/rawmidi.c
--- a/sound/core/rawmidi.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/rawmidi.c	2005-02-09 18:36:41 -08:00
@@ -29,6 +29,7 @@
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
+#include <linux/delay.h>
 #include <sound/rawmidi.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -149,10 +150,8 @@
 		/* we need wait a while to make sure that Tx FIFOs are empty */
 		if (substream->ops->drain)
 			substream->ops->drain(substream);
-		else {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ / 20);
-		}
+		else
+			msleep(50);
 		snd_rawmidi_drop_output(substream);
 	}
 	return err;
@@ -673,8 +672,7 @@
 	return 0;
 }
 
-static inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file,
-				     unsigned int cmd, unsigned long arg)
+static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_rawmidi_file_t *rfile;
 	void __user *argp = (void __user *)arg;
@@ -784,17 +782,6 @@
 	return -ENOTTY;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
-			     unsigned int cmd, unsigned long arg)
-{
-	int err;
-	unlock_kernel();
-	err = _snd_rawmidi_ioctl(inode, file, cmd, arg);
-	lock_kernel();
-	return err;
-}
-
 static int snd_rawmidi_control_ioctl(snd_card_t * card,
 				     snd_ctl_file_t * control,
 				     unsigned int cmd,
@@ -1278,6 +1265,14 @@
 }
 
 /*
+ */
+#ifdef CONFIG_COMPAT
+#include "rawmidi_compat.c"
+#else
+#define snd_rawmidi_ioctl_compat	NULL
+#endif
+
+/*
 
  */
 
@@ -1347,7 +1342,8 @@
 	.open =		snd_rawmidi_open,
 	.release =	snd_rawmidi_release,
 	.poll =		snd_rawmidi_poll,
-	.ioctl =	snd_rawmidi_ioctl,
+	.unlocked_ioctl =	snd_rawmidi_ioctl,
+	.compat_ioctl =	snd_rawmidi_ioctl_compat,
 };
 
 static snd_minor_t snd_rawmidi_reg =
@@ -1628,6 +1624,7 @@
 {
 
 	snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
+	snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
 #ifdef CONFIG_SND_OSSEMUL
 	{ int i;
 	/* check device map table */
@@ -1649,6 +1646,7 @@
 static void __exit alsa_rawmidi_exit(void)
 {
 	snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl);
+	snd_ctl_unregister_ioctl_compat(snd_rawmidi_control_ioctl);
 }
 
 module_init(alsa_rawmidi_init)
diff -Nru a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/core/rawmidi_compat.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,120 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for raw MIDI API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   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
+ *
+ */
+
+/* This file included from rawmidi.c */
+
+#include <linux/compat.h>
+
+struct sndrv_rawmidi_params32 {
+	s32 stream;
+	u32 buffer_size;
+	u32 avail_min;
+	unsigned int no_active_sensing; /* avoid bit-field */
+	unsigned char reserved[16];
+} __attribute__((packed));
+
+static int snd_rawmidi_ioctl_params_compat(snd_rawmidi_file_t *rfile,
+					   struct sndrv_rawmidi_params32 __user *src)
+{
+	snd_rawmidi_params_t params;
+	unsigned int val;
+
+	if (rfile->output == NULL)
+		return -EINVAL;
+	if (get_user(params.stream, &src->stream) ||
+	    get_user(params.buffer_size, &src->buffer_size) ||
+	    get_user(params.avail_min, &src->avail_min) ||
+	    get_user(val, &src->no_active_sensing))
+		return -EFAULT;
+	params.no_active_sensing = val;
+	switch (params.stream) {
+	case SNDRV_RAWMIDI_STREAM_OUTPUT:
+		return snd_rawmidi_output_params(rfile->output, &params);
+	case SNDRV_RAWMIDI_STREAM_INPUT:
+		return snd_rawmidi_input_params(rfile->input, &params);
+	}
+	return -EINVAL;
+}
+
+struct sndrv_rawmidi_status32 {
+	s32 stream;
+	struct compat_timespec tstamp;
+	u32 avail;
+	u32 xruns;
+	unsigned char reserved[16];
+} __attribute__((packed));
+
+static int snd_rawmidi_ioctl_status_compat(snd_rawmidi_file_t *rfile,
+					   struct sndrv_rawmidi_status32 __user *src)
+{
+	int err;
+	snd_rawmidi_status_t status;
+
+	if (rfile->output == NULL)
+		return -EINVAL;
+	if (get_user(status.stream, &src->stream))
+		return -EFAULT;
+
+	switch (status.stream) {
+	case SNDRV_RAWMIDI_STREAM_OUTPUT:
+		err = snd_rawmidi_output_status(rfile->output, &status);
+		break;
+	case SNDRV_RAWMIDI_STREAM_INPUT:
+		err = snd_rawmidi_input_status(rfile->input, &status);
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (err < 0)
+		return err;
+
+	if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
+	    put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
+	    put_user(status.avail, &src->avail) ||
+	    put_user(status.xruns, &src->xruns))
+		return -EFAULT;
+
+	return 0;
+}
+
+enum {
+	SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32),
+	SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32),
+};
+
+static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	snd_rawmidi_file_t *rfile;
+	void __user *argp = compat_ptr(arg);
+
+	rfile = file->private_data;
+	switch (cmd) {
+	case SNDRV_RAWMIDI_IOCTL_PVERSION:
+	case SNDRV_RAWMIDI_IOCTL_INFO:
+	case SNDRV_RAWMIDI_IOCTL_DROP:
+	case SNDRV_RAWMIDI_IOCTL_DRAIN:
+		return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
+	case SNDRV_RAWMIDI_IOCTL_PARAMS32:
+		return snd_rawmidi_ioctl_params_compat(rfile, argp);
+	case SNDRV_RAWMIDI_IOCTL_STATUS32:
+		return snd_rawmidi_ioctl_status_compat(rfile, argp);
+	}
+	return -ENOIOCTLCMD;
+}
diff -Nru a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
--- a/sound/core/seq/oss/seq_oss.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/seq/oss/seq_oss.c	2005-02-09 18:36:41 -08:00
@@ -59,7 +59,7 @@
 static int odev_release(struct inode *inode, struct file *file);
 static ssize_t odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset);
 static ssize_t odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset);
-static int odev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static long odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 static unsigned int odev_poll(struct file *file, poll_table * wait);
 #ifdef CONFIG_PROC_FS
 static void info_read(snd_info_entry_t *entry, snd_info_buffer_t *buf);
@@ -177,20 +177,20 @@
 	return snd_seq_oss_write(dp, buf, count, file);
 }
 
-static int
-odev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long
+odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	seq_oss_devinfo_t *dp;
-	int err;
 	dp = file->private_data;
 	snd_assert(dp != NULL, return -EIO);
-	/* FIXME: need to unlock BKL to allow preemption */
-	unlock_kernel();
-	err = snd_seq_oss_ioctl(dp, cmd, arg);
-	lock_kernel();
-	return err;
+	return snd_seq_oss_ioctl(dp, cmd, arg);
 }
 
+#ifdef CONFIG_COMPAT
+#define odev_ioctl_compat	odev_ioctl
+#else
+#define odev_ioctl_compat	NULL
+#endif
 
 static unsigned int
 odev_poll(struct file *file, poll_table * wait)
@@ -213,7 +213,8 @@
 	.open =		odev_open,
 	.release =	odev_release,
 	.poll =		odev_poll,
-	.ioctl =	odev_ioctl,
+	.unlocked_ioctl =	odev_ioctl,
+	.compat_ioctl =	odev_ioctl_compat,
 };
 
 static snd_minor_t seq_oss_reg = {
diff -Nru a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
--- a/sound/core/seq/oss/seq_oss_midi.c	2005-02-09 18:36:40 -08:00
+++ b/sound/core/seq/oss/seq_oss_midi.c	2005-02-09 18:36:40 -08:00
@@ -56,7 +56,7 @@
 static int max_midi_devs;
 static seq_oss_midi_t *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS];
 
-static spinlock_t register_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(register_lock);
 
 /*
  * prototypes
diff -Nru a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
--- a/sound/core/seq/oss/seq_oss_synth.c	2005-02-09 18:36:40 -08:00
+++ b/sound/core/seq/oss/seq_oss_synth.c	2005-02-09 18:36:40 -08:00
@@ -75,7 +75,7 @@
 	"MIDI", /* name */
 };
 
-static spinlock_t register_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(register_lock);
 
 /*
  * prototypes
diff -Nru a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
--- a/sound/core/seq/seq_clientmgr.c	2005-02-09 18:36:40 -08:00
+++ b/sound/core/seq/seq_clientmgr.c	2005-02-09 18:36:40 -08:00
@@ -51,7 +51,7 @@
 #define SNDRV_SEQ_LFLG_OUTPUT	0x0002
 #define SNDRV_SEQ_LFLG_OPEN	(SNDRV_SEQ_LFLG_INPUT|SNDRV_SEQ_LFLG_OUTPUT)
 
-static spinlock_t clients_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(clients_lock);
 static DECLARE_MUTEX(register_mutex);
 
 /*
@@ -2131,21 +2131,20 @@
 }
 
 
-static int snd_seq_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg)
+static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	client_t *client = (client_t *) file->private_data;
-	int err;
 
 	snd_assert(client != NULL, return -ENXIO);
 		
-	/* FIXME: need to unlock BKL to allow preemption */
-	unlock_kernel();
-	err = snd_seq_do_ioctl(client, cmd, (void __user *) arg);
-	lock_kernel();
-	return err;
+	return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
 }
 
+#ifdef CONFIG_COMPAT
+#include "seq_compat.c"
+#else
+#define snd_seq_ioctl_compat	NULL
+#endif
 
 /* -------------------------------------------------------- */
 
@@ -2462,7 +2461,8 @@
 	.open =		snd_seq_open,
 	.release =	snd_seq_release,
 	.poll =		snd_seq_poll,
-	.ioctl =	snd_seq_ioctl,
+	.unlocked_ioctl =	snd_seq_ioctl,
+	.compat_ioctl =	snd_seq_ioctl_compat,
 };
 
 static snd_minor_t snd_seq_reg =
diff -Nru a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/core/seq/seq_compat.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,137 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for sequencer API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   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
+ *
+ */
+
+/* This file included from seq.c */
+
+#include <linux/compat.h>
+
+struct sndrv_seq_port_info32 {
+	struct sndrv_seq_addr addr;	/* client/port numbers */
+	char name[64];			/* port name */
+
+	u32 capability;	/* port capability bits */
+	u32 type;		/* port type bits */
+	s32 midi_channels;		/* channels per MIDI port */
+	s32 midi_voices;		/* voices per MIDI port */
+	s32 synth_voices;		/* voices per SYNTH port */
+
+	s32 read_use;			/* R/O: subscribers for output (from this port) */
+	s32 write_use;			/* R/O: subscribers for input (to this port) */
+
+	u32 kernel;			/* reserved for kernel use (must be NULL) */
+	u32 flags;		/* misc. conditioning */
+	unsigned char time_queue;	/* queue # for timestamping */
+	char reserved[59];		/* for future use */
+};
+
+static int snd_seq_call_port_info_ioctl(client_t *client, unsigned int cmd,
+					struct sndrv_seq_port_info32 __user *data32)
+{
+	int err = -EFAULT;
+	snd_seq_port_info_t *data;
+	mm_segment_t fs;
+
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (! data)
+		return -ENOMEM;
+
+	if (copy_from_user(data, data32, sizeof(*data32)) ||
+	    get_user(data->flags, &data32->flags) ||
+	    get_user(data->time_queue, &data32->time_queue))
+		goto error;
+	data->kernel = NULL;
+
+	fs = snd_enter_user();
+	err = snd_seq_do_ioctl(client, cmd, data);
+	snd_leave_user(fs);
+	if (err < 0)
+		goto error;
+
+	if (copy_to_user(data32, data, sizeof(*data32)) ||
+	    put_user(data->flags, &data32->flags) ||
+	    put_user(data->time_queue, &data32->time_queue))
+		err = -EFAULT;
+
+ error:
+	kfree(data);
+	return err;
+}
+
+
+
+/*
+ */
+
+enum {
+	SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
+	SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
+	SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
+	SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
+	SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
+};
+
+static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	client_t *client = (client_t *) file->private_data;
+	void __user *argp = compat_ptr(arg);
+
+	snd_assert(client != NULL, return -ENXIO);
+
+	switch (cmd) {
+	case SNDRV_SEQ_IOCTL_PVERSION:
+	case SNDRV_SEQ_IOCTL_CLIENT_ID:
+	case SNDRV_SEQ_IOCTL_SYSTEM_INFO:
+	case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO:
+	case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO:
+	case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT:
+	case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT:
+	case SNDRV_SEQ_IOCTL_CREATE_QUEUE:
+	case SNDRV_SEQ_IOCTL_DELETE_QUEUE:
+	case SNDRV_SEQ_IOCTL_GET_QUEUE_INFO:
+	case SNDRV_SEQ_IOCTL_SET_QUEUE_INFO:
+	case SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE:
+	case SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS:
+	case SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO:
+	case SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO:
+	case SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER:
+	case SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER:
+	case SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT:
+	case SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT:
+	case SNDRV_SEQ_IOCTL_GET_CLIENT_POOL:
+	case SNDRV_SEQ_IOCTL_SET_CLIENT_POOL:
+	case SNDRV_SEQ_IOCTL_REMOVE_EVENTS:
+	case SNDRV_SEQ_IOCTL_QUERY_SUBS:
+	case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION:
+	case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT:
+	case SNDRV_SEQ_IOCTL_RUNNING_MODE:
+		return snd_seq_do_ioctl(client, cmd, argp);
+	case SNDRV_SEQ_IOCTL_CREATE_PORT32:
+		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp);
+	case SNDRV_SEQ_IOCTL_DELETE_PORT32:
+		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_DELETE_PORT, argp);
+	case SNDRV_SEQ_IOCTL_GET_PORT_INFO32:
+		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_GET_PORT_INFO, argp);
+	case SNDRV_SEQ_IOCTL_SET_PORT_INFO32:
+		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_SET_PORT_INFO, argp);
+	case SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32:
+		return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, argp);
+	}
+	return -ENOIOCTLCMD;
+}
diff -Nru a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
--- a/sound/core/seq/seq_queue.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/seq/seq_queue.c	2005-02-09 18:36:41 -08:00
@@ -49,7 +49,7 @@
 
 /* list of allocated queues */
 static queue_t *queue_list[SNDRV_SEQ_MAX_QUEUES];
-static spinlock_t queue_list_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(queue_list_lock);
 /* number of queues allocated */
 static int num_queues;
 
diff -Nru a/sound/core/sound.c b/sound/core/sound.c
--- a/sound/core/sound.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/sound.c	2005-02-09 18:36:41 -08:00
@@ -467,6 +467,10 @@
 EXPORT_SYMBOL(snd_ctl_notify);
 EXPORT_SYMBOL(snd_ctl_register_ioctl);
 EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
+#ifdef CONFIG_COMPAT
+EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
+EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
+#endif
 EXPORT_SYMBOL(snd_ctl_elem_read);
 EXPORT_SYMBOL(snd_ctl_elem_write);
   /* misc.c */
diff -Nru a/sound/core/timer.c b/sound/core/timer.c
--- a/sound/core/timer.c	2005-02-09 18:36:41 -08:00
+++ b/sound/core/timer.c	2005-02-09 18:36:41 -08:00
@@ -76,7 +76,7 @@
 static LIST_HEAD(snd_timer_slave_list);
 
 /* lock for slave active lists */
-static spinlock_t slave_active_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(slave_active_lock);
 
 static DECLARE_MUTEX(register_mutex);
 
@@ -1653,8 +1653,7 @@
 	return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
 }
 
-static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file,
-					unsigned int cmd, unsigned long arg)
+static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	snd_timer_user_t *tu;
 	void __user *argp = (void __user *)arg;
@@ -1701,17 +1700,6 @@
 	return -ENOTTY;
 }
 
-/* FIXME: need to unlock BKL to allow preemption */
-static int snd_timer_user_ioctl(struct inode *inode, struct file * file,
-				unsigned int cmd, unsigned long arg)
-{
-	int err;
-	unlock_kernel();
-	err = _snd_timer_user_ioctl(inode, file, cmd, arg);
-	lock_kernel();
-	return err;
-}
-
 static int snd_timer_user_fasync(int fd, struct file * file, int on)
 {
 	snd_timer_user_t *tu;
@@ -1803,6 +1791,12 @@
 	return mask;
 }
 
+#ifdef CONFIG_COMPAT
+#include "timer_compat.c"
+#else
+#define snd_timer_user_ioctl_compat	NULL
+#endif
+
 static struct file_operations snd_timer_f_ops =
 {
 	.owner =	THIS_MODULE,
@@ -1810,7 +1804,8 @@
 	.open =		snd_timer_user_open,
 	.release =	snd_timer_user_release,
 	.poll =		snd_timer_user_poll,
-	.ioctl =	snd_timer_user_ioctl,
+	.unlocked_ioctl =	snd_timer_user_ioctl,
+	.compat_ioctl =	snd_timer_user_ioctl_compat,
 	.fasync = 	snd_timer_user_fasync,
 };
 
diff -Nru a/sound/core/timer_compat.c b/sound/core/timer_compat.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/core/timer_compat.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,119 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for timer API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   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
+ *
+ */
+
+/* This file included from timer.c */
+
+#include <linux/compat.h>
+
+struct sndrv_timer_info32 {
+	u32 flags;
+	s32 card;
+	unsigned char id[64];
+	unsigned char name[80];
+	u32 reserved0;
+	u32 resolution;
+	unsigned char reserved[64];
+};
+
+static int snd_timer_user_info_compat(struct file *file,
+				      struct sndrv_timer_info32 __user *_info)
+{
+	snd_timer_user_t *tu;
+	struct sndrv_timer_info32 info;
+	snd_timer_t *t;
+
+	tu = file->private_data;
+	snd_assert(tu->timeri != NULL, return -ENXIO);
+	t = tu->timeri->timer;
+	snd_assert(t != NULL, return -ENXIO);
+	memset(&info, 0, sizeof(info));
+	info.card = t->card ? t->card->number : -1;
+	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
+		info.flags |= SNDRV_TIMER_FLG_SLAVE;
+	strlcpy(info.id, t->id, sizeof(info.id));
+	strlcpy(info.name, t->name, sizeof(info.name));
+	info.resolution = t->hw.resolution;
+	if (copy_to_user(_info, &info, sizeof(*_info)))
+		return -EFAULT;
+	return 0;
+}
+
+struct sndrv_timer_status32 {
+	struct compat_timespec tstamp;
+	u32 resolution;
+	u32 lost;
+	u32 overrun;
+	u32 queue;
+	unsigned char reserved[64];
+};
+
+static int snd_timer_user_status_compat(struct file *file,
+					struct sndrv_timer_status32 __user *_status)
+{
+	snd_timer_user_t *tu;
+	snd_timer_status_t status;
+	
+	tu = file->private_data;
+	snd_assert(tu->timeri != NULL, return -ENXIO);
+	memset(&status, 0, sizeof(status));
+	status.tstamp = tu->tstamp;
+	status.resolution = snd_timer_resolution(tu->timeri);
+	status.lost = tu->timeri->lost;
+	status.overrun = tu->overrun;
+	spin_lock_irq(&tu->qlock);
+	status.queue = tu->qused;
+	spin_unlock_irq(&tu->qlock);
+	if (copy_to_user(_status, &status, sizeof(status)))
+		return -EFAULT;
+	return 0;
+}
+
+/*
+ */
+
+enum {
+	SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32),
+	SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32),
+};
+
+static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = compat_ptr(arg);
+
+	switch (cmd) {
+	case SNDRV_TIMER_IOCTL_PVERSION:
+	case SNDRV_TIMER_IOCTL_TREAD:
+	case SNDRV_TIMER_IOCTL_GINFO:
+	case SNDRV_TIMER_IOCTL_GPARAMS:
+	case SNDRV_TIMER_IOCTL_GSTATUS:
+	case SNDRV_TIMER_IOCTL_SELECT:
+	case SNDRV_TIMER_IOCTL_PARAMS:
+	case SNDRV_TIMER_IOCTL_START:
+	case SNDRV_TIMER_IOCTL_STOP:
+	case SNDRV_TIMER_IOCTL_CONTINUE:
+	case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
+		return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
+	case SNDRV_TIMER_IOCTL_INFO32:
+		return snd_timer_user_info_compat(file, argp);
+	case SNDRV_TIMER_IOCTL_STATUS32:
+		return snd_timer_user_status_compat(file, argp);
+	}
+	return -ENOIOCTLCMD;
+}
diff -Nru a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
--- a/sound/drivers/vx/vx_core.c	2005-02-09 18:36:41 -08:00
+++ b/sound/drivers/vx/vx_core.c	2005-02-09 18:36:41 -08:00
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/device.h>
 #include <linux/firmware.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -45,12 +46,10 @@
  */
 void snd_vx_delay(vx_core_t *chip, int xmsec)
 {
-	if (! in_interrupt() && xmsec >= 1000 / HZ) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((xmsec * HZ + 999) / 1000);
-	} else {
+	if (! in_interrupt() && xmsec >= 1000 / HZ)
+		msleep(xmsec);
+	else
 		mdelay(xmsec);
-	}
 }
 
 /*
@@ -610,6 +609,10 @@
 	static char *uer_type[] = { "Consumer", "Professional", "Not Present" };
 	
 	snd_iprintf(buffer, "%s\n", chip->card->longname);
+	snd_iprintf(buffer, "Xilinx Firmware: %s\n",
+		    chip->chip_status & VX_STAT_XILINX_LOADED ? "Loaded" : "No");
+	snd_iprintf(buffer, "Device Initialized: %s\n",
+		    chip->chip_status & VX_STAT_DEVICE_INIT ? "Yes" : "No");
 	snd_iprintf(buffer, "DSP audio info:");
 	if (chip->audio_info & VX_AUDIO_INFO_REAL_TIME)
 		snd_iprintf(buffer, " realtime");
diff -Nru a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c
--- a/sound/drivers/vx/vx_hwdep.c	2005-02-09 18:36:41 -08:00
+++ b/sound/drivers/vx/vx_hwdep.c	2005-02-09 18:36:41 -08:00
@@ -21,6 +21,7 @@
  */
 
 #include <sound/driver.h>
+#include <linux/device.h>
 #include <linux/firmware.h>
 #include <sound/core.h>
 #include <sound/hwdep.h>
diff -Nru a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
--- a/sound/isa/gus/gus_pcm.c	2005-02-09 18:36:41 -08:00
+++ b/sound/isa/gus/gus_pcm.c	2005-02-09 18:36:41 -08:00
@@ -333,6 +333,7 @@
 			}
 		}
 		if (count > 0 && !in_interrupt()) {
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(1);
 			if (signal_pending(current))
 				return -EAGAIN;
diff -Nru a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c
--- a/sound/isa/gus/gus_reset.c	2005-02-09 18:36:40 -08:00
+++ b/sound/isa/gus/gus_reset.c	2005-02-09 18:36:41 -08:00
@@ -207,7 +207,6 @@
 	unsigned long flags;
 	short i, ramp_ok;
 	unsigned short ramp_end;
-	long time;
 
 	if (!in_interrupt()) {	/* this can't be done in interrupt */
 		for (i = v_min, ramp_ok = 0; i <= v_max; i++) {
@@ -227,11 +226,7 @@
 			}
 			spin_unlock_irqrestore(&gus->reg_lock, flags);
 		}
-		time = HZ / 20;
-		while (time > 0 && !signal_pending(current)) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			time = schedule_timeout(time);
-		}
+		msleep_interruptible(50);
 	}
 	snd_gf1_clear_voices(gus, v_min, v_max);
 }
diff -Nru a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
--- a/sound/isa/sb/emu8000.c	2005-02-09 18:36:41 -08:00
+++ b/sound/isa/sb/emu8000.c	2005-02-09 18:36:41 -08:00
@@ -25,6 +25,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/delay.h>
 #include <sound/core.h>
 #include <sound/emu8000.h>
 #include <sound/emu8000_reg.h>
@@ -355,8 +356,7 @@
 {
 	send_array(emu, init1, ARRAY_SIZE(init1)/4);
 
-	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout((HZ * (44099 + 1024)) / 44100); /* wait for 1024 clocks */
+	msleep((1024 * 1000) / 44100); /* wait for 1024 clocks */
 	send_array(emu, init2, ARRAY_SIZE(init2)/4);
 	send_array(emu, init3, ARRAY_SIZE(init3)/4);
 
diff -Nru a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
--- a/sound/isa/wavefront/wavefront_synth.c	2005-02-09 18:36:41 -08:00
+++ b/sound/isa/wavefront/wavefront_synth.c	2005-02-09 18:36:41 -08:00
@@ -1751,6 +1751,7 @@
 	outb (val,port);
 	spin_unlock_irq(&dev->irq_lock);
 	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		if ((timeout = schedule_timeout(timeout)) == 0)
 			return;
 		if (dev->irq_ok)
diff -Nru a/sound/pci/Kconfig b/sound/pci/Kconfig
--- a/sound/pci/Kconfig	2005-02-09 18:36:41 -08:00
+++ b/sound/pci/Kconfig	2005-02-09 18:36:41 -08:00
@@ -514,5 +514,15 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-vx222.
 
-endmenu
+config SND_HDA_INTEL
+	tristate "Intel HD Audio"
+	depends on SND
+	select SND_PCM
+	help
+	  Say Y here to include support for Intel "High Definition
+	  Audio" (Azalia) motherboard devices.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-hda-intel.
 
+endmenu
diff -Nru a/sound/pci/Makefile b/sound/pci/Makefile
--- a/sound/pci/Makefile	2005-02-09 18:36:40 -08:00
+++ b/sound/pci/Makefile	2005-02-09 18:36:40 -08:00
@@ -53,6 +53,7 @@
 	ca0106/ \
 	cs46xx/ \
 	emu10k1/ \
+	hda/ \
 	ice1712/ \
 	korg1212/ \
 	mixart/ \
diff -Nru a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
--- a/sound/pci/ac97/ac97_codec.c	2005-02-09 18:36:41 -08:00
+++ b/sound/pci/ac97/ac97_codec.c	2005-02-09 18:36:41 -08:00
@@ -438,9 +438,10 @@
 }
 
 /*
- *
+ * Controls
  */
 
+/* input mux */
 static int snd_ac97_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	static char *texts[8] = {
@@ -481,6 +482,7 @@
 	return snd_ac97_update(ac97, AC97_REC_SEL, val);
 }
 
+/* standard stereo enums */
 #define AC97_ENUM_DOUBLE(xname, reg, shift, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_enum_double, \
   .get = snd_ac97_get_enum_double, .put = snd_ac97_put_enum_double, \
@@ -543,6 +545,30 @@
 	return snd_ac97_update_bits(ac97, reg, 1 << shift, val << shift);
 }
 
+/* save/restore ac97 v2.3 paging */
+static int snd_ac97_page_save(ac97_t *ac97, int reg, snd_kcontrol_t *kcontrol)
+{
+	int page_save = -1;
+	if ((kcontrol->private_value & (1<<25)) &&
+	    (ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 &&
+	    (reg >= 0x60 && reg < 0x70)) {
+		unsigned short page = (kcontrol->private_value >> 26) & 0x0f;
+		down(&ac97->page_mutex); /* lock paging */
+		page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
+		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
+	}
+	return page_save;
+}
+
+static void snd_ac97_page_restore(ac97_t *ac97, int page_save)
+{
+	if (page_save >= 0) {
+		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
+		up(&ac97->page_mutex); /* unlock paging */
+	}
+}
+
+/* volume and switch controls */
 int snd_ac97_info_volsw(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	int mask = (kcontrol->private_value >> 16) & 0xff;
@@ -564,7 +590,9 @@
 	int rshift = (kcontrol->private_value >> 12) & 0x0f;
 	int mask = (kcontrol->private_value >> 16) & 0xff;
 	int invert = (kcontrol->private_value >> 24) & 0x01;
-	
+	int page_save;
+
+	page_save = snd_ac97_page_save(ac97, reg, kcontrol);
 	ucontrol->value.integer.value[0] = (snd_ac97_read_cache(ac97, reg) >> shift) & mask;
 	if (shift != rshift)
 		ucontrol->value.integer.value[1] = (snd_ac97_read_cache(ac97, reg) >> rshift) & mask;
@@ -573,6 +601,7 @@
 		if (shift != rshift)
 			ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
 	}
+	snd_ac97_page_restore(ac97, page_save);
 	return 0;
 }
 
@@ -584,8 +613,10 @@
 	int rshift = (kcontrol->private_value >> 12) & 0x0f;
 	int mask = (kcontrol->private_value >> 16) & 0xff;
 	int invert = (kcontrol->private_value >> 24) & 0x01;
+	int err, page_save;
 	unsigned short val, val2, val_mask;
 	
+	page_save = snd_ac97_page_save(ac97, reg, kcontrol);
 	val = (ucontrol->value.integer.value[0] & mask);
 	if (invert)
 		val = mask - val;
@@ -598,47 +629,15 @@
 		val_mask |= mask << rshift;
 		val |= val2 << rshift;
 	}
-	return snd_ac97_update_bits(ac97, reg, val_mask, val);
+	err = snd_ac97_update_bits(ac97, reg, val_mask, val);
+	snd_ac97_page_restore(ac97, page_save);
+	return err;
 }
 
 #define AC97_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .info = snd_ac97_info_volsw, \
   .get = snd_ac97_get_volsw, .put = snd_ac97_put_volsw, \
   .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) }
-
-static int snd_ac97_getput_page(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol,
-			 int (*func)(snd_kcontrol_t *, snd_ctl_elem_value_t *))
-{
-	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	int reg = kcontrol->private_value & 0xff;
-	int err;
-
-	if ((ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 &&
-	    (reg >= 0x60 && reg < 0x70)) {
-		unsigned short page_save;
-		unsigned short page = (kcontrol->private_value >> 25) & 0x0f;
-		down(&ac97->page_mutex); /* lock paging */
-		page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
-		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
-		err = func(kcontrol, ucontrol);
-		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
-		up(&ac97->page_mutex); /* unlock paging */
-	} else
-		err = func(kcontrol, ucontrol);
-	return err;
-}
-
-/* for rev2.3 paging */
-int snd_ac97_page_get_volsw(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	return snd_ac97_getput_page(kcontrol, ucontrol, snd_ac97_get_volsw);
-}
-
-/* for rev2.3 paging */
-int snd_ac97_page_put_volsw(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	return snd_ac97_getput_page(kcontrol, ucontrol, snd_ac97_put_volsw);
-}
 
 static const snd_kcontrol_new_t snd_ac97_controls_master_mono[2] = {
 AC97_SINGLE("Master Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
diff -Nru a/sound/pci/ac97/ac97_local.h b/sound/pci/ac97/ac97_local.h
--- a/sound/pci/ac97/ac97_local.h	2005-02-09 18:36:41 -08:00
+++ b/sound/pci/ac97/ac97_local.h	2005-02-09 18:36:41 -08:00
@@ -23,14 +23,14 @@
  */
 
 #define AC97_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) | ((shift) << 12) | ((mask) << 16) | ((invert) << 24))
-#define AC97_PAGE_SINGLE_VALUE(reg,shift,mask,invert,page) (AC97_SINGLE_VALUE(reg,shift,mask,invert) | ((page) << 25))
+#define AC97_PAGE_SINGLE_VALUE(reg,shift,mask,invert,page) (AC97_SINGLE_VALUE(reg,shift,mask,invert) | (1<<25) | ((page) << 26))
 #define AC97_SINGLE(xname, reg, shift, mask, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_volsw, \
   .get = snd_ac97_get_volsw, .put = snd_ac97_put_volsw, \
   .private_value =  AC97_SINGLE_VALUE(reg, shift, mask, invert) }
 #define AC97_PAGE_SINGLE(xname, reg, shift, mask, invert, page)		\
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_volsw, \
-  .get = snd_ac97_page_get_volsw, .put = snd_ac97_page_put_volsw, \
+  .get = snd_ac97_get_volsw, .put = snd_ac97_put_volsw, \
   .private_value =  AC97_PAGE_SINGLE_VALUE(reg, shift, mask, invert, page) }
 
 /* ac97_codec.c */
@@ -42,8 +42,6 @@
 int snd_ac97_info_volsw(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
 int snd_ac97_get_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_ac97_put_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
-int snd_ac97_page_get_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
-int snd_ac97_page_put_volsw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit);
 int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix);
 int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix);
diff -Nru a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
--- a/sound/pci/ac97/ac97_patch.c	2005-02-09 18:36:41 -08:00
+++ b/sound/pci/ac97/ac97_patch.c	2005-02-09 18:36:41 -08:00
@@ -1107,13 +1107,26 @@
 #endif
 };
 
+static void check_ad1981_hp_jack_sense(ac97_t *ac97)
+{
+	u32 subid = ((u32)ac97->subsystem_vendor << 16) | ac97->subsystem_device;
+	switch (subid) {
+	case 0x103c0890: /* HP nc6000 */
+	case 0x103c006d: /* HP nx9105 */
+	case 0x17340088: /* FSC Scenic-W */
+		/* enable headphone jack sense */
+		snd_ac97_update_bits(ac97, AC97_AD_JACK_SPDIF, 1<<11, 1<<11);
+		break;
+	}
+}
+
 int patch_ad1981a(ac97_t *ac97)
 {
 	patch_ad1881(ac97);
 	ac97->build_ops = &patch_ad1981a_build_ops;
 	snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_MSPLT, AC97_AD198X_MSPLT);
 	ac97->flags |= AC97_STEREO_MUTES;
-	snd_ac97_update_bits(ac97, AC97_AD_JACK_SPDIF, 1<<11, 1<<11); /* HP jack sense */
+	check_ad1981_hp_jack_sense(ac97);
 	return 0;
 }
 
@@ -1144,7 +1157,7 @@
 	ac97->build_ops = &patch_ad1981b_build_ops;
 	snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_MSPLT, AC97_AD198X_MSPLT);
 	ac97->flags |= AC97_STEREO_MUTES;
-	snd_ac97_update_bits(ac97, AC97_AD_JACK_SPDIF, 1<<11, 1<<11); /* HP jack sense */
+	check_ad1981_hp_jack_sense(ac97);
 	return 0;
 }
 
@@ -1903,6 +1916,15 @@
 	/* FIXME: set up GPIO */
 	snd_ac97_write_cache(ac97, 0x70, 0x0100);
 	snd_ac97_write_cache(ac97, 0x72, 0x0020);
+	/* Special exception for ASUS W1000/CMI9739. It does not have an SPDIF in. */
+	if (ac97->pci &&
+	     ac97->subsystem_vendor == 0x1043 &&
+	     ac97->subsystem_device == 0x1843) {
+		snd_ac97_write_cache(ac97, AC97_CM9739_SPDIF_CTRL,
+			snd_ac97_read(ac97, AC97_CM9739_SPDIF_CTRL) & ~0x01);
+		snd_ac97_write_cache(ac97, AC97_CM9739_MULTI_CHAN,
+			snd_ac97_read(ac97, AC97_CM9739_MULTI_CHAN) | (1 << 14));
+	}
 
 	return 0;
 }
diff -Nru a/sound/pci/atiixp.c b/sound/pci/atiixp.c
--- a/sound/pci/atiixp.c	2005-02-09 18:36:41 -08:00
+++ b/sound/pci/atiixp.c	2005-02-09 18:36:41 -08:00
@@ -1332,6 +1332,12 @@
  */
 
 static struct ac97_quirk ac97_quirks[] __devinitdata = {
+	{
+		.vendor = 0x103c,
+		.device = 0x006b,
+		.name = "HP Pavilion ZV5030US",
+		.type = AC97_TUNE_MUTE_LED
+	},
 	{ } /* terminator */
 };
 
diff -Nru a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
--- a/sound/pci/atiixp_modem.c	2005-02-09 18:36:41 -08:00
+++ b/sound/pci/atiixp_modem.c	2005-02-09 18:36:41 -08:00
@@ -606,21 +606,20 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	atiixp_dma_t *dma = (atiixp_dma_t *)runtime->private_data;
 	unsigned int curptr;
+	int timeout = 1000;
 
-	spin_lock(&chip->reg_lock);
-	curptr = readl(chip->remap_addr + dma->ops->dt_cur);
-	if (curptr < dma->buf_addr) {
-		snd_printdd("curptr = %x, base = %x\n", curptr, dma->buf_addr);
-		curptr = 0;
-	} else {
+	while (timeout--) {
+		curptr = readl(chip->remap_addr + dma->ops->dt_cur);
+		if (curptr < dma->buf_addr)
+			continue;
 		curptr -= dma->buf_addr;
-		if (curptr >= dma->buf_bytes) {
-			snd_printdd("curptr = %x, size = %x\n", curptr, dma->buf_bytes);
-			curptr = 0;
-		}
+		if (curptr >= dma->buf_bytes)
+			continue;
+		return bytes_to_frames(runtime, curptr);
 	}
-	spin_unlock(&chip->reg_lock);
-	return bytes_to_frames(runtime, curptr);
+	snd_printd("atiixp-modem: invalid DMA pointer read 0x%x (buf=%x)\n",
+		   readl(chip->remap_addr + dma->ops->dt_cur), dma->buf_addr);
+	return 0;
 }
 
 /*
diff -Nru a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/pci/hda/Makefile	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,7 @@
+snd-hda-intel-objs := hda_intel.o
+snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o
+ifdef CONFIG_PROC_FS
+snd-hda-codec-objs += hda_proc.o
+endif
+
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o snd-hda-codec.o
diff -Nru a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/pci/hda/hda_codec.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,1731 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ *  This driver 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 driver 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/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include "hda_local.h"
+
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_DESCRIPTION("Universal interface for High Definition Audio Codec");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * vendor / preset table
+ */
+
+struct hda_vendor_id {
+	unsigned int id;
+	const char *name;
+};
+
+/* codec vendor labels */
+static struct hda_vendor_id hda_vendor_ids[] = {
+	{ 0x10ec, "Realtek" },
+	{ 0x434d, "C-Media" },
+	{} /* terminator */
+};
+
+/* codec presets */
+#include "hda_patch.h"
+
+
+/**
+ * snd_hda_codec_read - send a command and get the response
+ * @codec: the HDA codec
+ * @nid: NID to send the command
+ * @direct: direct flag
+ * @verb: the verb to send
+ * @parm: the parameter for the verb
+ *
+ * Send a single command and read the corresponding response.
+ *
+ * Returns the obtained response value, or -1 for an error.
+ */
+unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct,
+				unsigned int verb, unsigned int parm)
+{
+	unsigned int res;
+	down(&codec->bus->cmd_mutex);
+	if (! codec->bus->ops.command(codec, nid, direct, verb, parm))
+		res = codec->bus->ops.get_response(codec);
+	else
+		res = (unsigned int)-1;
+	up(&codec->bus->cmd_mutex);
+	return res;
+}
+
+/**
+ * snd_hda_codec_write - send a single command without waiting for response
+ * @codec: the HDA codec
+ * @nid: NID to send the command
+ * @direct: direct flag
+ * @verb: the verb to send
+ * @parm: the parameter for the verb
+ *
+ * Send a single command without waiting for response.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
+			 unsigned int verb, unsigned int parm)
+{
+	int err;
+	down(&codec->bus->cmd_mutex);
+	err = codec->bus->ops.command(codec, nid, direct, verb, parm);
+	up(&codec->bus->cmd_mutex);
+	return err;
+}
+
+/**
+ * snd_hda_sequence_write - sequence writes
+ * @codec: the HDA codec
+ * @seq: VERB array to send
+ *
+ * Send the commands sequentially from the given array.
+ * The array must be terminated with NID=0.
+ */
+void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq)
+{
+	for (; seq->nid; seq++)
+		snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param);
+}
+
+/**
+ * snd_hda_get_sub_nodes - get the range of sub nodes
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @start_id: the pointer to store the start NID
+ *
+ * Parse the NID and store the start NID of its sub-nodes.
+ * Returns the number of sub-nodes.
+ */
+int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id)
+{
+	unsigned int parm;
+
+	parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT);
+	*start_id = (parm >> 16) & 0x7fff;
+	return (int)(parm & 0x7fff);
+}
+
+/**
+ * snd_hda_get_connections - get connection list
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @conn_list: connection list array
+ * @max_conns: max. number of connections to store
+ *
+ * Parses the connection list of the given widget and stores the list
+ * of NIDs.
+ *
+ * Returns the number of connections, or a negative error code.
+ */
+int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
+			    hda_nid_t *conn_list, int max_conns)
+{
+	unsigned int parm;
+	int i, j, conn_len, num_tupples, conns;
+	unsigned int shift, num_elems, mask;
+
+	snd_assert(conn_list && max_conns > 0, return -EINVAL);
+
+	parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
+	if (parm & AC_CLIST_LONG) {
+		/* long form */
+		shift = 16;
+		num_elems = 2;
+	} else {
+		/* short form */
+		shift = 8;
+		num_elems = 4;
+	}
+	conn_len = parm & AC_CLIST_LENGTH;
+	num_tupples = num_elems / 2;
+	mask = (1 << (shift-1)) - 1;
+
+	if (! conn_len)
+		return 0; /* no connection */
+
+	if (conn_len == 1) {
+		/* single connection */
+		parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, 0);
+		conn_list[0] = parm & mask;
+		return 1;
+	}
+
+	/* multi connection */
+	conns = 0;
+	for (i = 0; i < conn_len; i += num_elems) {
+		parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, i);
+		for (j = 0; j < num_tupples; j++) {
+			int range_val;
+			hda_nid_t val1, val2, n;
+			range_val = parm & (1 << (shift-1)); /* ranges */
+			val1 = parm & mask;
+			parm >>= shift;
+			val2 = parm & mask;
+			parm >>= shift;
+			if (range_val) {
+				/* ranges between val1 and val2 */
+				if (val1 > val2) {
+					snd_printk(KERN_WARNING "hda_codec: invalid dep_range_val %x:%x\n", val1, val2);
+					continue;
+				}
+				for (n = val1; n <= val2; n++) {
+					if (conns >= max_conns)
+						return -EINVAL;
+					conn_list[conns++] = n;
+				}
+			} else {
+				if (! val1)
+					break;
+				if (conns >= max_conns)
+					return -EINVAL;
+				conn_list[conns++] = val1;
+				if (! val2)
+					break;
+				if (conns >= max_conns)
+					return -EINVAL;
+				conn_list[conns++] = val2;
+			}
+		}
+	}
+	return conns;
+}
+
+
+/**
+ * snd_hda_queue_unsol_event - add an unsolicited event to queue
+ * @bus: the BUS
+ * @res: unsolicited event (lower 32bit of RIRB entry)
+ * @res_ex: codec addr and flags (upper 32bit or RIRB entry)
+ *
+ * Adds the given event to the queue.  The events are processed in
+ * the workqueue asynchronously.  Call this function in the interrupt
+ * hanlder when RIRB receives an unsolicited event.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
+{
+	struct hda_bus_unsolicited *unsol;
+	unsigned int wp;
+
+	if ((unsol = bus->unsol) == NULL)
+		return 0;
+
+	wp = (unsol->wp + 1) % HDA_UNSOL_QUEUE_SIZE;
+	unsol->wp = wp;
+
+	wp <<= 1;
+	unsol->queue[wp] = res;
+	unsol->queue[wp + 1] = res_ex;
+
+	queue_work(unsol->workq, &unsol->work);
+
+	return 0;
+}
+
+/*
+ * process queueud unsolicited events
+ */
+static void process_unsol_events(void *data)
+{
+	struct hda_bus *bus = data;
+	struct hda_bus_unsolicited *unsol = bus->unsol;
+	struct hda_codec *codec;
+	unsigned int rp, caddr, res;
+
+	while (unsol->rp != unsol->wp) {
+		rp = (unsol->rp + 1) % HDA_UNSOL_QUEUE_SIZE;
+		unsol->rp = rp;
+		rp <<= 1;
+		res = unsol->queue[rp];
+		caddr = unsol->queue[rp + 1];
+		if (! (caddr & (1 << 4))) /* no unsolicited event? */
+			continue;
+		codec = bus->caddr_tbl[caddr & 0x0f];
+		if (codec && codec->patch_ops.unsol_event)
+			codec->patch_ops.unsol_event(codec, res);
+	}
+}
+
+/*
+ * initialize unsolicited queue
+ */
+static int init_unsol_queue(struct hda_bus *bus)
+{
+	struct hda_bus_unsolicited *unsol;
+
+	unsol = kcalloc(1, sizeof(*unsol), GFP_KERNEL);
+	if (! unsol) {
+		snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n");
+		return -ENOMEM;
+	}
+	unsol->workq = create_workqueue("hda_codec");
+	if (! unsol->workq) {
+		snd_printk(KERN_ERR "hda_codec: can't create workqueue\n");
+		kfree(unsol);
+		return -ENOMEM;
+	}
+	INIT_WORK(&unsol->work, process_unsol_events, bus);
+	bus->unsol = unsol;
+	return 0;
+}
+
+/*
+ * destructor
+ */
+static void snd_hda_codec_free(struct hda_codec *codec);
+
+static int snd_hda_bus_free(struct hda_bus *bus)
+{
+	struct list_head *p, *n;
+
+	if (! bus)
+		return 0;
+	if (bus->unsol) {
+		destroy_workqueue(bus->unsol->workq);
+		kfree(bus->unsol);
+	}
+	list_for_each_safe(p, n, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		snd_hda_codec_free(codec);
+	}
+	if (bus->ops.private_free)
+		bus->ops.private_free(bus);
+	kfree(bus);
+	return 0;
+}
+
+static int snd_hda_bus_dev_free(snd_device_t *device)
+{
+	struct hda_bus *bus = device->device_data;
+	return snd_hda_bus_free(bus);
+}
+
+/**
+ * snd_hda_bus_new - create a HDA bus
+ * @card: the card entry
+ * @temp: the template for hda_bus information
+ * @busp: the pointer to store the created bus instance
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp,
+		    struct hda_bus **busp)
+{
+	struct hda_bus *bus;
+	int err;
+	static snd_device_ops_t dev_ops = {
+		.dev_free = snd_hda_bus_dev_free,
+	};
+
+	snd_assert(temp, return -EINVAL);
+	snd_assert(temp->ops.command && temp->ops.get_response, return -EINVAL);
+
+	if (busp)
+		*busp = NULL;
+
+	bus = kcalloc(1, sizeof(*bus), GFP_KERNEL);
+	if (bus == NULL) {
+		snd_printk(KERN_ERR "can't allocate struct hda_bus\n");
+		return -ENOMEM;
+	}
+
+	bus->card = card;
+	bus->private_data = temp->private_data;
+	bus->pci = temp->pci;
+	bus->modelname = temp->modelname;
+	bus->ops = temp->ops;
+
+	init_MUTEX(&bus->cmd_mutex);
+	INIT_LIST_HEAD(&bus->codec_list);
+
+	init_unsol_queue(bus);
+
+	if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)) < 0) {
+		snd_hda_bus_free(bus);
+		return err;
+	}
+	if (busp)
+		*busp = bus;
+	return 0;
+}
+
+
+/*
+ * find a matching codec preset
+ */
+static const struct hda_codec_preset *find_codec_preset(struct hda_codec *codec)
+{
+	const struct hda_codec_preset **tbl, *preset;
+
+	for (tbl = hda_preset_tables; *tbl; tbl++) {
+		for (preset = *tbl; preset->id; preset++) {
+			u32 mask = preset->mask;
+			if (! mask)
+				mask = ~0;
+			if (preset->id == (codec->vendor_id & mask))
+				return preset;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * snd_hda_get_codec_name - store the codec name
+ */
+void snd_hda_get_codec_name(struct hda_codec *codec,
+			    char *name, int namelen)
+{
+	const struct hda_vendor_id *c;
+	const char *vendor = NULL;
+	u16 vendor_id = codec->vendor_id >> 16;
+	char tmp[16];
+
+	for (c = hda_vendor_ids; c->id; c++) {
+		if (c->id == vendor_id) {
+			vendor = c->name;
+			break;
+		}
+	}
+	if (! vendor) {
+		sprintf(tmp, "Generic %04x", vendor_id);
+		vendor = tmp;
+	}
+	if (codec->preset && codec->preset->name)
+		snprintf(name, namelen, "%s %s", vendor, codec->preset->name);
+	else
+		snprintf(name, namelen, "%s ID %x", vendor, codec->vendor_id & 0xffff);
+}
+
+/*
+ * look for an AFG node
+ *
+ * return 0 if not found
+ */
+static int look_for_afg_node(struct hda_codec *codec)
+{
+	int i, total_nodes;
+	hda_nid_t nid;
+
+	total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
+	for (i = 0; i < total_nodes; i++, nid++) {
+		if (snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) == AC_GRP_AUDIO_FUNCTION)
+			return nid;
+	}
+	return 0;
+}
+
+/*
+ * codec destructor
+ */
+static void snd_hda_codec_free(struct hda_codec *codec)
+{
+	if (! codec)
+		return;
+	list_del(&codec->list);
+	codec->bus->caddr_tbl[codec->addr] = NULL;
+	if (codec->patch_ops.free)
+		codec->patch_ops.free(codec);
+	kfree(codec);
+}
+
+static void init_amp_hash(struct hda_codec *codec);
+
+/**
+ * snd_hda_codec_new - create a HDA codec
+ * @bus: the bus to assign
+ * @codec_addr: the codec address
+ * @codecp: the pointer to store the generated codec
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+		      struct hda_codec **codecp)
+{
+	struct hda_codec *codec;
+	char component[13];
+	int err;
+
+	snd_assert(bus, return -EINVAL);
+	snd_assert(codec_addr <= HDA_MAX_CODEC_ADDRESS, return -EINVAL);
+
+	if (bus->caddr_tbl[codec_addr]) {
+		snd_printk(KERN_ERR "hda_codec: address 0x%x is already occupied\n", codec_addr);
+		return -EBUSY;
+	}
+
+	codec = kcalloc(1, sizeof(*codec), GFP_KERNEL);
+	if (codec == NULL) {
+		snd_printk(KERN_ERR "can't allocate struct hda_codec\n");
+		return -ENOMEM;
+	}
+
+	codec->bus = bus;
+	codec->addr = codec_addr;
+	init_MUTEX(&codec->spdif_mutex);
+	init_amp_hash(codec);
+
+	list_add_tail(&codec->list, &bus->codec_list);
+	bus->caddr_tbl[codec_addr] = codec;
+
+	codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_VENDOR_ID);
+	codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID);
+	codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID);
+
+	/* FIXME: support for multiple AFGs? */
+	codec->afg = look_for_afg_node(codec);
+	if (! codec->afg) {
+		snd_printk(KERN_ERR "hda_codec: no AFG node found\n");
+		snd_hda_codec_free(codec);
+		return -ENODEV;
+	}
+
+	codec->preset = find_codec_preset(codec);
+	if (! *bus->card->mixername)
+		snd_hda_get_codec_name(codec, bus->card->mixername,
+				       sizeof(bus->card->mixername));
+
+	if (codec->preset && codec->preset->patch)
+		err = codec->preset->patch(codec);
+	else
+		err = snd_hda_parse_generic_codec(codec);
+	if (err < 0) {
+		snd_hda_codec_free(codec);
+		return err;
+	}
+
+	snd_hda_codec_proc_new(codec);
+
+	sprintf(component, "HDA:%08x", codec->vendor_id);
+	snd_component_add(codec->bus->card, component);
+
+	if (codecp)
+		*codecp = codec;
+	return 0;
+}
+
+/**
+ * snd_hda_codec_setup_stream - set up the codec for streaming
+ * @codec: the CODEC to set up
+ * @nid: the NID to set up
+ * @stream_tag: stream tag to pass, it's between 0x1 and 0xf.
+ * @channel_id: channel id to pass, zero based.
+ * @format: stream format.
+ */
+void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag,
+				int channel_id, int format)
+{
+	snd_printdd("hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
+		    nid, stream_tag, channel_id, format);
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID,
+			    (stream_tag << 4) | channel_id);
+	msleep(1);
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format);
+}
+
+
+/*
+ * amp access functions
+ */
+
+#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + (idx) * 32 + (dir) * 64)
+#define INFO_AMP_CAPS	(1<<0)
+#define INFO_AMP_VOL	(1<<1)
+
+/* initialize the hash table */
+static void init_amp_hash(struct hda_codec *codec)
+{
+	memset(codec->amp_hash, 0xff, sizeof(codec->amp_hash));
+	codec->num_amp_entries = 0;
+}
+
+/* query the hash.  allocate an entry if not found. */
+static struct hda_amp_info *get_alloc_amp_hash(struct hda_codec *codec, u32 key)
+{
+	u16 idx = key % (u16)ARRAY_SIZE(codec->amp_hash);
+	u16 cur = codec->amp_hash[idx];
+	struct hda_amp_info *info;
+
+	while (cur != 0xffff) {
+		info = &codec->amp_info[cur];
+		if (info->key == key)
+			return info;
+		cur = info->next;
+	}
+
+	/* add a new hash entry */
+	if (codec->num_amp_entries >= ARRAY_SIZE(codec->amp_info)) {
+		snd_printk(KERN_ERR "hda_codec: Tooooo many amps!\n");
+		return NULL;
+	}
+	cur = codec->num_amp_entries++;
+	info = &codec->amp_info[cur];
+	info->key = key;
+	info->status = 0; /* not initialized yet */
+	info->next = codec->amp_hash[idx];
+	codec->amp_hash[idx] = cur;
+
+	return info;
+}
+
+/*
+ * query AMP capabilities for the given widget and direction
+ */
+static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
+{
+	struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0));
+
+	if (! info)
+		return 0;
+	if (! (info->status & INFO_AMP_CAPS)) {
+		info->amp_caps = snd_hda_param_read(codec, nid, direction == HDA_OUTPUT ?
+						    AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
+		info->status |= INFO_AMP_CAPS;
+	}
+	return info->amp_caps;
+}
+
+/*
+ * read the current volume to info
+ * if the cache exists, read from the cache.
+ */
+static void get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
+			 hda_nid_t nid, int ch, int direction, int index)
+{
+	u32 val, parm;
+
+	if (info->status & (INFO_AMP_VOL << ch))
+		return;
+
+	parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
+	parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
+	parm |= index;
+	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm);
+	info->vol[ch] = val & 0xff;
+	info->status |= INFO_AMP_VOL << ch;
+}
+
+/*
+ * write the current volume in info to the h/w
+ */
+static void put_vol_mute(struct hda_codec *codec,
+			 hda_nid_t nid, int ch, int direction, int index, int val)
+{
+	u32 parm;
+
+	parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT;
+	parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT;
+	parm |= index << AC_AMP_SET_INDEX_SHIFT;
+	parm |= val;
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
+}
+
+/*
+ * read/write AMP value.  The volume is between 0 to 0x7f, 0x80 = mute bit.
+ */
+int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index)
+{
+	struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
+	if (! info)
+		return 0;
+	get_vol_mute(codec, info, nid, ch, direction, index);
+	return info->vol[ch];
+}
+
+int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val)
+{
+	struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
+	if (! info)
+		return 0;
+	get_vol_mute(codec, info, nid, ch, direction, idx);
+	if (info->vol[ch] == val && ! codec->in_resume)
+		return 0;
+	put_vol_mute(codec, nid, ch, direction, idx, val);
+	info->vol[ch] = val;
+	return 1;
+}
+
+
+/*
+ * AMP control callbacks
+ */
+/* retrieve parameters from private_value */
+#define get_amp_nid(kc)		((kc)->private_value & 0xffff)
+#define get_amp_channels(kc)	(((kc)->private_value >> 16) & 0x3)
+#define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
+#define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
+
+/* volume */
+int snd_hda_mixer_amp_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	u16 nid = get_amp_nid(kcontrol);
+	u8 chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	u32 caps;
+
+	caps = query_amp_caps(codec, nid, dir);
+	caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; /* num steps */
+	if (! caps) {
+		printk(KERN_WARNING "hda_codec: num_steps = 0 for NID=0x%x\n", nid);
+		return -EINVAL;
+	}
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = chs == 3 ? 2 : 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = caps;
+	return 0;
+}
+
+int snd_hda_mixer_amp_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = get_amp_nid(kcontrol);
+	int chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	int idx = get_amp_index(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+
+	if (chs & 1)
+		*valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f;
+	if (chs & 2)
+		*valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f;
+	return 0;
+}
+
+int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = get_amp_nid(kcontrol);
+	int chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	int idx = get_amp_index(kcontrol);
+	int val;
+	long *valp = ucontrol->value.integer.value;
+	int change = 0;
+
+	if (chs & 1) {
+		val = *valp & 0x7f;
+		val |= snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80;
+		change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val);
+		valp++;
+	}
+	if (chs & 2) {
+		val = *valp & 0x7f;
+		val |= snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80;
+		change |= snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val);
+	}
+	return change;
+}
+
+/* switch */
+int snd_hda_mixer_amp_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	int chs = get_amp_channels(kcontrol);
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = chs == 3 ? 2 : 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+int snd_hda_mixer_amp_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = get_amp_nid(kcontrol);
+	int chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	int idx = get_amp_index(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+
+	if (chs & 1)
+		*valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80) ? 0 : 1;
+	if (chs & 2)
+		*valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80) ? 0 : 1;
+	return 0;
+}
+
+int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = get_amp_nid(kcontrol);
+	int chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	int idx = get_amp_index(kcontrol);
+	int val;
+	long *valp = ucontrol->value.integer.value;
+	int change = 0;
+
+	if (chs & 1) {
+		val = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f;
+		val |= *valp ? 0 : 0x80;
+		change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val);
+		valp++;
+	}
+	if (chs & 2) {
+		val = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f;
+		val |= *valp ? 0 : 0x80;
+		change = snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val);
+	}
+	return change;
+}
+
+/*
+ * SPDIF out controls
+ */
+
+static int snd_hda_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_hda_spdif_cmask_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |
+					   IEC958_AES0_NONAUDIO |
+					   IEC958_AES0_CON_EMPHASIS_5015 |
+					   IEC958_AES0_CON_NOT_COPYRIGHT;
+	ucontrol->value.iec958.status[1] = IEC958_AES1_CON_CATEGORY |
+					   IEC958_AES1_CON_ORIGINAL;
+	return 0;
+}
+
+static int snd_hda_spdif_pmask_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |
+					   IEC958_AES0_NONAUDIO |
+					   IEC958_AES0_PRO_EMPHASIS_5015;
+	return 0;
+}
+
+static int snd_hda_spdif_default_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff;
+	ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff;
+	ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff;
+	ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff;
+
+	return 0;
+}
+
+static int snd_hda_spdif_default_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value;
+	unsigned int sbits;
+	unsigned short val;
+	int change;
+
+	val = 0;
+	down(&codec->spdif_mutex);
+	sbits = codec->spdif_status & 1;
+	sbits |= ucontrol->value.iec958.status[0] & (IEC958_AES0_PROFESSIONAL|
+						     IEC958_AES0_NONAUDIO);
+	if (sbits & IEC958_AES0_PROFESSIONAL)
+		val = 1 << 6;
+	if (sbits & IEC958_AES0_NONAUDIO)
+		val |= 1 << 5;
+	if (sbits & IEC958_AES0_PROFESSIONAL) {
+		sbits |= ucontrol->value.iec958.status[0] & IEC958_AES0_PRO_EMPHASIS;
+		if ((sbits & IEC958_AES0_PRO_EMPHASIS) == IEC958_AES0_PRO_EMPHASIS_5015)
+			val |= 1 << 3;
+	} else {
+		sbits |= ucontrol->value.iec958.status[0] & (IEC958_AES0_CON_EMPHASIS|
+							     IEC958_AES0_CON_NOT_COPYRIGHT);
+		if ((sbits & IEC958_AES0_CON_EMPHASIS) == IEC958_AES0_CON_EMPHASIS_5015)
+			val |= 1 << 3;
+		if (! (sbits & IEC958_AES0_CON_NOT_COPYRIGHT))
+			val |= 1 << 4;
+		sbits |= ucontrol->value.iec958.status[1] << 8;
+		if (sbits & (IEC958_AES1_CON_ORIGINAL << 8))
+			val |= 1 << 7;
+		val |= sbits & (IEC958_AES1_CON_CATEGORY << 8);
+	}
+
+	change = codec->spdif_status != sbits;
+	codec->spdif_status = sbits;
+
+	if (change) {
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val & 0xff);
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, val >> 8);
+	}
+
+	up(&codec->spdif_mutex);
+	return change;
+}
+
+static int snd_hda_spdif_out_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_hda_spdif_out_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = codec->spdif_status & 1;
+	return 0;
+}
+
+static int snd_hda_spdif_out_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value;
+	unsigned int sbits;
+	int change;
+
+	down(&codec->spdif_mutex);
+	sbits = codec->spdif_status & ~1;
+	if (ucontrol->value.integer.value[0])
+		sbits |= 1;
+	change = codec->spdif_status != sbits;
+	if (change) {
+		codec->spdif_status = sbits;
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, sbits & 0xff);
+	}
+	up(&codec->spdif_mutex);
+	return change;
+}
+
+static snd_kcontrol_new_t dig_mixes[] = {
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+		.info = snd_hda_spdif_mask_info,
+		.get = snd_hda_spdif_cmask_get,
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+		.info = snd_hda_spdif_mask_info,
+		.get = snd_hda_spdif_pmask_get,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+		.info = snd_hda_spdif_mask_info,
+		.get = snd_hda_spdif_default_get,
+		.put = snd_hda_spdif_default_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
+		.info = snd_hda_spdif_out_switch_info,
+		.get = snd_hda_spdif_out_switch_get,
+		.put = snd_hda_spdif_out_switch_put,
+	},
+	{ } /* end */
+};
+
+/**
+ * snd_hda_create_spdif_out_ctls - create SPDIF-related controls
+ * @codec: the HDA codec
+ * @nid: audio out widget NID
+ *
+ * Creates controls related with the SPDIF output.
+ * Called from each patch supporting the SPDIF out.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
+{
+	int err;
+	snd_kcontrol_t *kctl;
+	snd_kcontrol_new_t *dig_mix;
+
+	for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
+		kctl = snd_ctl_new1(dig_mix, codec);
+		kctl->private_value = nid;
+		if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0)
+			return err;
+	}
+#if 0
+	/* not enabled, consumer, audio, no emphasis, original, PCM coder */
+	codec->spdif_status = (1 << 7) | (0x02 << 8);
+#else
+	codec->spdif_status = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0);
+#endif
+	return 0;
+}
+
+/**
+ * snd_hda_build_controls - build mixer controls
+ * @bus: the BUS
+ *
+ * Creates mixer controls for each codec included in the bus.
+ *
+ * Returns 0 if successful, otherwise a negative error code.
+ */
+int snd_hda_build_controls(struct hda_bus *bus)
+{
+	struct list_head *p;
+
+	/* build controls */
+	list_for_each(p, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		int err;
+		if (! codec->patch_ops.build_controls)
+			continue;
+		err = codec->patch_ops.build_controls(codec);
+		if (err < 0)
+			return err;
+	}
+
+	/* initialize */
+	list_for_each(p, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		int err;
+		if (! codec->patch_ops.init)
+			continue;
+		err = codec->patch_ops.init(codec);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+
+/*
+ * stream formats
+ */
+static unsigned int rate_bits[][3] = {
+	/* rate in Hz, ALSA rate bitmask, HDA format value */
+	{ 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */
+	{ 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */
+	{ 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */
+	{ 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */
+	{ 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */
+	{ 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */
+	{ 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */
+	{ 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */
+	{ 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */
+	{ 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */
+	{ 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */
+	{ 0 }
+};
+
+/**
+ * snd_hda_calc_stream_format - calculate format bitset
+ * @rate: the sample rate
+ * @channels: the number of channels
+ * @format: the PCM format (SNDRV_PCM_FORMAT_XXX)
+ * @maxbps: the max. bps
+ *
+ * Calculate the format bitset from the given rate, channels and th PCM format.
+ *
+ * Return zero if invalid.
+ */
+unsigned int snd_hda_calc_stream_format(unsigned int rate,
+					unsigned int channels,
+					unsigned int format,
+					unsigned int maxbps)
+{
+	int i;
+	unsigned int val = 0;
+
+	for (i = 0; rate_bits[i][0]; i++)
+		if (rate_bits[i][0] == rate) {
+			val = rate_bits[i][2];
+			break;
+		}
+	if (! rate_bits[i][0]) {
+		snd_printdd("invalid rate %d\n", rate);
+		return 0;
+	}
+
+	if (channels == 0 || channels > 8) {
+		snd_printdd("invalid channels %d\n", channels);
+		return 0;
+	}
+	val |= channels - 1;
+
+	switch (snd_pcm_format_width(format)) {
+	case 8:  val |= 0x00; break;
+	case 16: val |= 0x10; break;
+	case 20:
+	case 24:
+	case 32:
+		if (maxbps >= 32)
+			val |= 0x40;
+		else if (maxbps >= 24)
+			val |= 0x30;
+		else
+			val |= 0x20;
+		break;
+	default:
+		snd_printdd("invalid format width %d\n", snd_pcm_format_width(format));
+		return 0;
+	}
+
+	return val;
+}
+
+/**
+ * snd_hda_query_supported_pcm - query the supported PCM rates and formats
+ * @codec: the HDA codec
+ * @nid: NID to query
+ * @ratesp: the pointer to store the detected rate bitflags
+ * @formatsp: the pointer to store the detected formats
+ * @bpsp: the pointer to store the detected format widths
+ *
+ * Queries the supported PCM rates and formats.  The NULL @ratesp, @formatsp
+ * or @bsps argument is ignored.
+ *
+ * Returns 0 if successful, otherwise a negative error code.
+ */
+int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+				u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
+{
+	int i;
+	unsigned int val, streams;
+
+	val = 0;
+	if (nid != codec->afg &&
+	    snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) {
+		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+		if (val == -1)
+			return -EIO;
+	}
+	if (! val)
+		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+
+	if (ratesp) {
+		u32 rates = 0;
+		for (i = 0; rate_bits[i][0]; i++) {
+			if (val & (1 << i))
+				rates |= rate_bits[i][1];
+		}
+		*ratesp = rates;
+	}
+
+	if (formatsp || bpsp) {
+		u64 formats = 0;
+		unsigned int bps;
+		unsigned int wcaps;
+
+		wcaps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
+		streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+		if (streams == -1)
+			return -EIO;
+		if (! streams) {
+			streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
+			if (streams == -1)
+				return -EIO;
+		}
+
+		bps = 0;
+		if (streams & AC_SUPFMT_PCM) {
+			if (val & AC_SUPPCM_BITS_8) {
+				formats |= SNDRV_PCM_FMTBIT_U8;
+				bps = 8;
+			}
+			if (val & AC_SUPPCM_BITS_16) {
+				formats |= SNDRV_PCM_FMTBIT_S16_LE;
+				bps = 16;
+			}
+			if (wcaps & AC_WCAP_DIGITAL) {
+				if (val & AC_SUPPCM_BITS_32)
+					formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
+				if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24))
+					formats |= SNDRV_PCM_FMTBIT_S32_LE;
+				if (val & AC_SUPPCM_BITS_24)
+					bps = 24;
+				else if (val & AC_SUPPCM_BITS_20)
+					bps = 20;
+			} else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24|AC_SUPPCM_BITS_32)) {
+				formats |= SNDRV_PCM_FMTBIT_S32_LE;
+				if (val & AC_SUPPCM_BITS_32)
+					bps = 32;
+				else if (val & AC_SUPPCM_BITS_20)
+					bps = 20;
+				else if (val & AC_SUPPCM_BITS_24)
+					bps = 24;
+			}
+		}
+		else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */
+			formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
+			bps = 32;
+		} else if (streams == AC_SUPFMT_AC3) { /* should be exclusive */
+			/* temporary hack: we have still no proper support
+			 * for the direct AC3 stream...
+			 */
+			formats |= SNDRV_PCM_FMTBIT_U8;
+			bps = 8;
+		}
+		if (formatsp)
+			*formatsp = formats;
+		if (bpsp)
+			*bpsp = bps;
+	}
+
+	return 0;
+}
+
+/**
+ * snd_hda_is_supported_format - check whether the given node supports the format val
+ *
+ * Returns 1 if supported, 0 if not.
+ */
+int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
+				unsigned int format)
+{
+	int i;
+	unsigned int val = 0, rate;
+
+	if (nid != codec->afg &&
+	    snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) {
+		val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+		if (val == -1)
+			return 0;
+	}
+	if (! val) {
+		val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+		if (val == -1)
+			return 0;
+	}
+
+	rate = format & 0xffff;
+	for (i = 0; rate_bits[i][0]; i++)
+		if (rate_bits[i][2] == rate) {
+			if (val & (1 << i))
+				break;
+			return 0;
+		}
+	if (! rate_bits[i][0])
+		return 0;
+
+	val = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+	if (val == -1)
+		return 0;
+	if (! val && nid != codec->afg)
+		val = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
+	if (! val || val == -1)
+		return 0;
+
+	if (val & AC_SUPFMT_PCM) {
+		switch (format & 0xf0) {
+		case 0x00:
+			if (! (val & AC_SUPPCM_BITS_8))
+				return 0;
+			break;
+		case 0x10:
+			if (! (val & AC_SUPPCM_BITS_16))
+				return 0;
+			break;
+		case 0x20:
+			if (! (val & AC_SUPPCM_BITS_20))
+				return 0;
+			break;
+		case 0x30:
+			if (! (val & AC_SUPPCM_BITS_24))
+				return 0;
+			break;
+		case 0x40:
+			if (! (val & AC_SUPPCM_BITS_32))
+				return 0;
+			break;
+		default:
+			return 0;
+		}
+	} else {
+		/* FIXME: check for float32 and AC3? */
+	}
+
+	return 1;
+}
+
+/*
+ * PCM stuff
+ */
+static int hda_pcm_default_open_close(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      snd_pcm_substream_t *substream)
+{
+	return 0;
+}
+
+static int hda_pcm_default_prepare(struct hda_pcm_stream *hinfo,
+				   struct hda_codec *codec,
+				   unsigned int stream_tag,
+				   unsigned int format,
+				   snd_pcm_substream_t *substream)
+{
+	snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
+	return 0;
+}
+
+static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo,
+				   struct hda_codec *codec,
+				   snd_pcm_substream_t *substream)
+{
+	snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0);
+	return 0;
+}
+
+static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream *info)
+{
+	if (info->nid) {
+		/* query support PCM information from the given NID */
+		if (! info->rates || ! info->formats)
+			snd_hda_query_supported_pcm(codec, info->nid,
+						    info->rates ? NULL : &info->rates,
+						    info->formats ? NULL : &info->formats,
+						    info->maxbps ? NULL : &info->maxbps);
+	}
+	if (info->ops.open == NULL)
+		info->ops.open = hda_pcm_default_open_close;
+	if (info->ops.close == NULL)
+		info->ops.close = hda_pcm_default_open_close;
+	if (info->ops.prepare == NULL) {
+		snd_assert(info->nid, return -EINVAL);
+		info->ops.prepare = hda_pcm_default_prepare;
+	}
+	if (info->ops.prepare == NULL) {
+		snd_assert(info->nid, return -EINVAL);
+		info->ops.prepare = hda_pcm_default_prepare;
+	}
+	if (info->ops.cleanup == NULL) {
+		snd_assert(info->nid, return -EINVAL);
+		info->ops.cleanup = hda_pcm_default_cleanup;
+	}
+	return 0;
+}
+
+/**
+ * snd_hda_build_pcms - build PCM information
+ * @bus: the BUS
+ *
+ * Create PCM information for each codec included in the bus.
+ *
+ * The build_pcms codec patch is requested to set up codec->num_pcms and
+ * codec->pcm_info properly.  The array is referred by the top-level driver
+ * to create its PCM instances.
+ * The allocated codec->pcm_info should be released in codec->patch_ops.free
+ * callback.
+ *
+ * At least, substreams, channels_min and channels_max must be filled for
+ * each stream.  substreams = 0 indicates that the stream doesn't exist.
+ * When rates and/or formats are zero, the supported values are queried
+ * from the given nid.  The nid is used also by the default ops.prepare
+ * and ops.cleanup callbacks.
+ *
+ * The driver needs to call ops.open in its open callback.  Similarly,
+ * ops.close is supposed to be called in the close callback.
+ * ops.prepare should be called in the prepare or hw_params callback
+ * with the proper parameters for set up.
+ * ops.cleanup should be called in hw_free for clean up of streams.
+ *
+ * This function returns 0 if successfull, or a negative error code.
+ */
+int snd_hda_build_pcms(struct hda_bus *bus)
+{
+	struct list_head *p;
+
+	list_for_each(p, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		unsigned int pcm, s;
+		int err;
+		if (! codec->patch_ops.build_pcms)
+			continue;
+		err = codec->patch_ops.build_pcms(codec);
+		if (err < 0)
+			return err;
+		for (pcm = 0; pcm < codec->num_pcms; pcm++) {
+			for (s = 0; s < 2; s++) {
+				struct hda_pcm_stream *info;
+				info = &codec->pcm_info[pcm].stream[s];
+				if (! info->substreams)
+					continue;
+				err = set_pcm_default_values(codec, info);
+				if (err < 0)
+					return err;
+			}
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * snd_hda_check_board_config - compare the current codec with the config table
+ * @codec: the HDA codec
+ * @tbl: configuration table, terminated by null entries
+ *
+ * Compares the modelname or PCI subsystem id of the current codec with the
+ * given configuration table.  If a matching entry is found, returns its
+ * config value (supposed to be 0 or positive).
+ *
+ * If no entries are matching, the function returns a negative value.
+ */
+int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl)
+{
+	struct hda_board_config *c;
+
+	if (codec->bus->modelname) {
+		for (c = tbl; c->modelname || c->pci_vendor; c++) {
+			if (c->modelname &&
+			    ! strcmp(codec->bus->modelname, c->modelname)) {
+				snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname);
+				return c->config;
+			}
+		}
+	}
+
+	if (codec->bus->pci) {
+		u16 subsystem_vendor, subsystem_device;
+		pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
+		pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device);
+		for (c = tbl; c->modelname || c->pci_vendor; c++) {
+			if (c->pci_vendor == subsystem_vendor &&
+			    c->pci_device == subsystem_device)
+				return c->config;
+		}
+	}
+	return -1;
+}
+
+/**
+ * snd_hda_add_new_ctls - create controls from the array
+ * @codec: the HDA codec
+ * @knew: the array of snd_kcontrol_new_t
+ *
+ * This helper function creates and add new controls in the given array.
+ * The array must be terminated with an empty entry as terminator.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew)
+{
+	int err;
+
+	for (; knew->name; knew++) {
+		err = snd_ctl_add(codec->bus->card, snd_ctl_new1(knew, codec));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+
+/*
+ * input MUX helper
+ */
+int snd_hda_input_mux_info(const struct hda_input_mux *imux, snd_ctl_elem_info_t *uinfo)
+{
+	unsigned int index;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = imux->num_items;
+	index = uinfo->value.enumerated.item;
+	if (index >= imux->num_items)
+		index = imux->num_items - 1;
+	strcpy(uinfo->value.enumerated.name, imux->items[index].label);
+	return 0;
+}
+
+int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux,
+			  snd_ctl_elem_value_t *ucontrol, hda_nid_t nid,
+			  unsigned int *cur_val)
+{
+	unsigned int idx;
+
+	idx = ucontrol->value.enumerated.item[0];
+	if (idx >= imux->num_items)
+		idx = imux->num_items - 1;
+	if (*cur_val == idx && ! codec->in_resume)
+		return 0;
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
+			    imux->items[idx].index);
+	*cur_val = idx;
+	return 1;
+}
+
+
+/*
+ * Multi-channel / digital-out PCM helper functions
+ */
+
+/*
+ * open the digital out in the exclusive mode
+ */
+int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout)
+{
+	down(&codec->spdif_mutex);
+	if (mout->dig_out_used) {
+		up(&codec->spdif_mutex);
+		return -EBUSY; /* already being used */
+	}
+	mout->dig_out_used = HDA_DIG_EXCLUSIVE;
+	up(&codec->spdif_mutex);
+	return 0;
+}
+
+/*
+ * release the digital out
+ */
+int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout)
+{
+	down(&codec->spdif_mutex);
+	mout->dig_out_used = 0;
+	up(&codec->spdif_mutex);
+	return 0;
+}
+
+/*
+ * set up more restrictions for analog out
+ */
+int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout,
+				  snd_pcm_substream_t *substream)
+{
+	substream->runtime->hw.channels_max = mout->max_channels;
+	return snd_pcm_hw_constraint_step(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+}
+
+/*
+ * set up the i/o for analog out
+ * when the digital out is available, copy the front out to digital out, too.
+ */
+int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout,
+				     unsigned int stream_tag,
+				     unsigned int format,
+				     snd_pcm_substream_t *substream)
+{
+	hda_nid_t *nids = mout->dac_nids;
+	int chs = substream->runtime->channels;
+	int i;
+
+	down(&codec->spdif_mutex);
+	if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
+		if (chs == 2 &&
+		    snd_hda_is_supported_format(codec, mout->dig_out_nid, format)) {
+
+			mout->dig_out_used = HDA_DIG_ANALOG_DUP;
+			/* setup digital receiver */
+			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
+						   stream_tag, 0, format);
+
+			if (codec->spdif_status & AC_DIG1_NONAUDIO) {
+				/* non-audio SPDIF out, turning off all DACs */
+				for (i = 0; i < mout->num_dacs; i++)
+					snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
+				if (mout->hp_nid)
+					snd_hda_codec_setup_stream(codec, mout->hp_nid,0, 0, 0);
+				up(&codec->spdif_mutex);
+				return 0;
+			}
+		} else {
+			mout->dig_out_used = 0;
+			snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
+		}
+	}
+	up(&codec->spdif_mutex);
+
+	/* front */
+	snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format);
+	if (mout->hp_nid)
+		/* headphone out will just decode front left/right (stereo) */
+		snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
+	/* surrounds */
+	for (i = 0; i < mout->num_dacs; i++) {
+		if (i == HDA_REAR && chs == 2) /* copy front to rear */
+			snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, format);
+		else if (chs >= (i + 1) * 2) /* independent out */
+			snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2,
+						   format);
+	}
+	return 0;
+}
+
+/*
+ * clean up the setting for analog out
+ */
+int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout)
+{
+	hda_nid_t *nids = mout->dac_nids;
+	int i;
+
+	for (i = 0; i < mout->num_dacs; i++)
+		snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
+	if (mout->hp_nid)
+		snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0);
+	down(&codec->spdif_mutex);
+	if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
+		snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
+		mout->dig_out_used = 0;
+	}
+	up(&codec->spdif_mutex);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * power management
+ */
+
+/**
+ * snd_hda_suspend - suspend the codecs
+ * @bus: the HDA bus
+ * @state: suspsend state
+ *
+ * Returns 0 if successful.
+ */
+int snd_hda_suspend(struct hda_bus *bus, unsigned int state)
+{
+	struct list_head *p;
+
+	/* FIXME: should handle power widget capabilities */
+	list_for_each(p, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		if (codec->patch_ops.suspend)
+			codec->patch_ops.suspend(codec, state);
+	}
+	return 0;
+}
+
+/**
+ * snd_hda_resume - resume the codecs
+ * @bus: the HDA bus
+ * @state: resume state
+ *
+ * Returns 0 if successful.
+ */
+int snd_hda_resume(struct hda_bus *bus, unsigned int state)
+{
+	struct list_head *p;
+
+	list_for_each(p, &bus->codec_list) {
+		struct hda_codec *codec = list_entry(p, struct hda_codec, list);
+		if (codec->patch_ops.resume)
+			codec->patch_ops.resume(codec, state);
+	}
+	return 0;
+}
+
+/**
+ * snd_hda_resume_ctls - resume controls in the new control list
+ * @codec: the HDA codec
+ * @knew: the array of snd_kcontrol_new_t
+ *
+ * This function resumes the mixer controls in the snd_kcontrol_new_t array,
+ * originally for snd_hda_add_new_ctls().
+ * The array must be terminated with an empty entry as terminator.
+ */
+int snd_hda_resume_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew)
+{
+	snd_ctl_elem_value_t *val;
+
+	val = kmalloc(sizeof(*val), GFP_KERNEL);
+	if (! val)
+		return -ENOMEM;
+	codec->in_resume = 1;
+	for (; knew->name; knew++) {
+		int i, count;
+		count = knew->count ? knew->count : 1;
+		for (i = 0; i < count; i++) {
+			memset(val, 0, sizeof(*val));
+			val->id.iface = knew->iface;
+			val->id.device = knew->device;
+			val->id.subdevice = knew->subdevice;
+			strcpy(val->id.name, knew->name);
+			val->id.index = knew->index ? knew->index : i;
+			/* Assume that get callback reads only from cache,
+			 * not accessing to the real hardware
+			 */
+			if (snd_ctl_elem_read(codec->bus->card, val) < 0)
+				continue;
+			snd_ctl_elem_write(codec->bus->card, NULL, val);
+		}
+	}
+	codec->in_resume = 0;
+	kfree(val);
+	return 0;
+}
+
+/**
+ * snd_hda_resume_spdi_out - resume the digital I/O
+ * @codec: the HDA codec
+ */
+int snd_hda_resume_spdif_out(struct hda_codec *codec)
+{
+	return snd_hda_resume_ctls(codec, dig_mixes);
+}
+#endif
+
+/*
+ * symbols exported for controller modules
+ */
+EXPORT_SYMBOL(snd_hda_codec_read);
+EXPORT_SYMBOL(snd_hda_codec_write);
+EXPORT_SYMBOL(snd_hda_sequence_write);
+EXPORT_SYMBOL(snd_hda_get_sub_nodes);
+EXPORT_SYMBOL(snd_hda_queue_unsol_event);
+EXPORT_SYMBOL(snd_hda_bus_new);
+EXPORT_SYMBOL(snd_hda_codec_new);
+EXPORT_SYMBOL(snd_hda_codec_setup_stream);
+EXPORT_SYMBOL(snd_hda_calc_stream_format);
+EXPORT_SYMBOL(snd_hda_build_pcms);
+EXPORT_SYMBOL(snd_hda_build_controls);
+#ifdef CONFIG_PM
+EXPORT_SYMBOL(snd_hda_suspend);
+EXPORT_SYMBOL(snd_hda_resume);
+#endif
+
+/*
+ *  INIT part
+ */
+
+static int __init alsa_hda_init(void)
+{
+	return 0;
+}
+
+static void __exit alsa_hda_exit(void)
+{
+}
+
+module_init(alsa_hda_init)
+module_exit(alsa_hda_exit)
diff -Nru a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/pci/hda/hda_codec.h	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,602 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by 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.
+ */
+
+#ifndef __SOUND_HDA_CODEC_H
+#define __SOUND_HDA_CODEC_H
+
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+
+/*
+ * nodes
+ */
+#define	AC_NODE_ROOT		0x00
+
+/*
+ * function group types
+ */
+enum {
+	AC_GRP_AUDIO_FUNCTION = 0x01,
+	AC_GRP_MODEM_FUNCTION = 0x02,
+};
+	
+/*
+ * widget types
+ */
+enum {
+	AC_WID_AUD_OUT,		/* Audio Out */
+	AC_WID_AUD_IN,		/* Audio In */
+	AC_WID_AUD_MIX,		/* Audio Mixer */
+	AC_WID_AUD_SEL,		/* Audio Selector */
+	AC_WID_PIN,		/* Pin Complex */
+	AC_WID_POWER,		/* Power */
+	AC_WID_VOL_KNB,		/* Volume Knob */
+	AC_WID_BEEP,		/* Beep Generator */
+	AC_WID_VENDOR = 0x0f	/* Vendor specific */
+};
+
+/*
+ * GET verbs
+ */
+#define AC_VERB_GET_STREAM_FORMAT		0x0a00
+#define AC_VERB_GET_AMP_GAIN_MUTE		0x0b00
+#define AC_VERB_GET_PROC_COEF			0x0c00
+#define AC_VERB_GET_COEF_INDEX			0x0d00
+#define AC_VERB_PARAMETERS			0x0f00
+#define AC_VERB_GET_CONNECT_SEL			0x0f01
+#define AC_VERB_GET_CONNECT_LIST		0x0f02
+#define AC_VERB_GET_PROC_STATE			0x0f03
+#define AC_VERB_GET_SDI_SELECT			0x0f04
+#define AC_VERB_GET_POWER_STATE			0x0f05
+#define AC_VERB_GET_CONV			0x0f06
+#define AC_VERB_GET_PIN_WIDGET_CONTROL		0x0f07
+#define AC_VERB_GET_UNSOLICITED_RESPONSE	0x0f08
+#define AC_VERB_GET_PIN_SENSE			0x0f09
+#define AC_VERB_GET_BEEP_CONTROL		0x0f0a
+#define AC_VERB_GET_EAPD_BTLENABLE		0x0f0c
+#define AC_VERB_GET_DIGI_CONVERT		0x0f0d
+#define AC_VERB_GET_VOLUME_KNOB_CONTROL		0x0f0f
+/* f10-f1a: GPIO */
+#define AC_VERB_GET_CONFIG_DEFAULT		0x0f1c
+
+/*
+ * SET verbs
+ */
+#define AC_VERB_SET_STREAM_FORMAT		0x200
+#define AC_VERB_SET_AMP_GAIN_MUTE		0x300
+#define AC_VERB_SET_PROC_COEF			0x400
+#define AC_VERB_SET_COEF_INDEX			0x500
+#define AC_VERB_SET_CONNECT_SEL			0x701
+#define AC_VERB_SET_PROC_STATE			0x703
+#define AC_VERB_SET_SDI_SELECT			0x704
+#define AC_VERB_SET_POWER_STATE			0x705
+#define AC_VERB_SET_CHANNEL_STREAMID		0x706
+#define AC_VERB_SET_PIN_WIDGET_CONTROL		0x707
+#define AC_VERB_SET_UNSOLICITED_ENABLE		0x708
+#define AC_VERB_SET_PIN_SENSE			0x709
+#define AC_VERB_SET_BEEP_CONTROL		0x70a
+#define AC_VERB_SET_EAPD_BTLENALBE		0x70c
+#define AC_VERB_SET_DIGI_CONVERT_1		0x70d
+#define AC_VERB_SET_DIGI_CONVERT_2		0x70e
+#define AC_VERB_SET_VOLUME_KNOB_CONTROL		0x70f
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0	0x71c
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1	0x71d
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2	0x71e
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3	0x71f
+#define AC_VERB_SET_CODEC_RESET			0x7ff
+
+/*
+ * Parameter IDs
+ */
+#define AC_PAR_VENDOR_ID		0x00
+#define AC_PAR_SUBSYSTEM_ID		0x01
+#define AC_PAR_REV_ID			0x02
+#define AC_PAR_NODE_COUNT		0x04
+#define AC_PAR_FUNCTION_TYPE		0x05
+#define AC_PAR_AUDIO_FG_CAP		0x08
+#define AC_PAR_AUDIO_WIDGET_CAP		0x09
+#define AC_PAR_PCM			0x0a
+#define AC_PAR_STREAM			0x0b
+#define AC_PAR_PIN_CAP			0x0c
+#define AC_PAR_AMP_IN_CAP		0x0d
+#define AC_PAR_CONNLIST_LEN		0x0e
+#define AC_PAR_POWER_STATE		0x0f
+#define AC_PAR_PROC_CAP			0x10
+#define AC_PAR_GPIO_CAP			0x11
+#define AC_PAR_AMP_OUT_CAP		0x12
+
+/*
+ * AC_VERB_PARAMETERS results (32bit)
+ */
+
+/* Function Group Type */
+#define AC_FGT_TYPE			(0xff<<0)
+#define AC_FGT_TYPE_SHIFT		0
+#define AC_FGT_UNSOL_CAP		(1<<8)
+
+/* Audio Function Group Capabilities */
+#define AC_AFG_OUT_DELAY		(0xf<<0)
+#define AC_AFG_IN_DELAY			(0xf<<8)
+#define AC_AFG_BEEP_GEN			(1<<16)
+
+/* Audio Widget Capabilities */
+#define AC_WCAP_STEREO			(1<<0)	/* stereo I/O */
+#define AC_WCAP_IN_AMP			(1<<1)	/* AMP-in present */
+#define AC_WCAP_OUT_AMP			(1<<2)	/* AMP-out present */
+#define AC_WCAP_AMP_OVRD		(1<<3)	/* AMP-parameter override */
+#define AC_WCAP_FORMAT_OVRD		(1<<4)	/* format override */
+#define AC_WCAP_STRIPE			(1<<5)	/* stripe */
+#define AC_WCAP_PROC_WID		(1<<6)	/* Proc Widget */
+#define AC_WCAP_UNSOL_CAP		(1<<7)	/* Unsol capable */
+#define AC_WCAP_CONN_LIST		(1<<8)	/* connection list */
+#define AC_WCAP_DIGITAL			(1<<9)	/* digital I/O */
+#define AC_WCAP_POWER			(1<<10)	/* power control */
+#define AC_WCAP_LR_SWAP			(1<<11)	/* L/R swap */
+#define AC_WCAP_DELAY			(0xf<<16)
+#define AC_WCAP_DELAY_SHIFT		16
+#define AC_WCAP_TYPE			(0xf<<20)
+#define AC_WCAP_TYPE_SHIFT		20
+
+/* supported PCM rates and bits */
+#define AC_SUPPCM_RATES			(0xfff << 0)
+#define AC_SUPPCM_BITS_8		(1<<16)
+#define AC_SUPPCM_BITS_16		(1<<17)
+#define AC_SUPPCM_BITS_20		(1<<18)
+#define AC_SUPPCM_BITS_24		(1<<19)
+#define AC_SUPPCM_BITS_32		(1<<20)
+
+/* supported PCM stream format */
+#define AC_SUPFMT_PCM			(1<<0)
+#define AC_SUPFMT_FLOAT32		(1<<1)
+#define AC_SUPFMT_AC3			(1<<2)
+
+/* Pin widget capabilies */
+#define AC_PINCAP_IMP_SENSE		(1<<0)	/* impedance sense capable */
+#define AC_PINCAP_TRIG_REQ		(1<<1)	/* trigger required */
+#define AC_PINCAP_PRES_DETECT		(1<<2)	/* presence detect capable */
+#define AC_PINCAP_HP_DRV		(1<<3)	/* headphone drive capable */
+#define AC_PINCAP_OUT			(1<<4)	/* output capable */
+#define AC_PINCAP_IN			(1<<5)	/* input capable */
+#define AC_PINCAP_BALANCE		(1<<6)	/* balanced I/O capable */
+#define AC_PINCAP_VREF			(7<<8)
+#define AC_PINCAP_VREF_SHIFT		8
+#define AC_PINCAP_EAPD			(1<<16)	/* EAPD capable */
+/* Vref status (used in pin cap and pin ctl) */
+#define AC_PIN_VREF_HIZ			(1<<0)	/* Hi-Z */
+#define AC_PIN_VREF_50			(1<<1)	/* 50% */
+#define AC_PIN_VREF_GRD			(1<<2)	/* ground */
+#define AC_PIN_VREF_80			(1<<4)	/* 80% */
+#define AC_PIN_VREF_100			(1<<5)	/* 100% */
+
+
+/* Amplifier capabilities */
+#define AC_AMPCAP_OFFSET		(0x7f<<0)  /* 0dB offset */
+#define AC_AMPCAP_OFFSET_SHIFT		0
+#define AC_AMPCAP_NUM_STEPS		(0x7f<<8)  /* number of steps */
+#define AC_AMPCAP_NUM_STEPS_SHIFT	8
+#define AC_AMPCAP_STEP_SIZE		(0x7f<<16) /* step size 0-32dB in 0.25dB */
+#define AC_AMPCAP_STEP_SIZE_SHIFT	16
+#define AC_AMPCAP_MUTE			(1<<31)    /* mute capable */
+#define AC_AMPCAP_MUTE_SHIFT		31
+
+/* Connection list */
+#define AC_CLIST_LENGTH			(0x7f<<0)
+#define AC_CLIST_LONG			(1<<7)
+
+/* Supported power status */
+#define AC_PWRST_D0SUP			(1<<0)
+#define AC_PWRST_D1SUP			(1<<1)
+#define AC_PWRST_D2SUP			(1<<2)
+#define AC_PWRST_D3SUP			(1<<3)
+
+/* Processing capabilies */
+#define AC_PCAP_BENIGN			(1<<0)
+#define AC_PCAP_NUM_COEF		(0xff<<8)
+
+/* Volume knobs capabilities */
+#define AC_KNBCAP_NUM_STEPS		(0x7f<<0)
+#define AC_KNBCAP_DELTA			(1<<8)
+
+/*
+ * Control Parameters
+ */
+
+/* Amp gain/mute */
+#define AC_AMP_MUTE			(1<<8)
+#define AC_AMP_GAIN			(0x7f)
+#define AC_AMP_GET_INDEX		(0xf<<0)
+
+#define AC_AMP_GET_LEFT			(1<<13)
+#define AC_AMP_GET_RIGHT		(0<<13)
+#define AC_AMP_GET_OUTPUT		(1<<15)
+#define AC_AMP_GET_INPUT		(0<<15)
+
+#define AC_AMP_SET_INDEX		(0xf<<8)
+#define AC_AMP_SET_INDEX_SHIFT		8
+#define AC_AMP_SET_RIGHT		(1<<12)
+#define AC_AMP_SET_LEFT			(1<<13)
+#define AC_AMP_SET_INPUT		(1<<14)
+#define AC_AMP_SET_OUTPUT		(1<<15)
+
+/* DIGITAL1 bits */
+#define AC_DIG1_ENABLE			(1<<0)
+#define AC_DIG1_V			(1<<1)
+#define AC_DIG1_VCFG			(1<<2)
+#define AC_DIG1_EMPHASIS		(1<<3)
+#define AC_DIG1_COPYRIGHT		(1<<4)
+#define AC_DIG1_NONAUDIO		(1<<5)
+#define AC_DIG1_PROFESSIONAL		(1<<6)
+#define AC_DIG1_LEVEL			(1<<7)
+
+/* Pin widget control - 8bit */
+#define AC_PINCTL_VREFEN		(0x7<<0)
+#define AC_PINCTL_IN_EN			(1<<5)
+#define AC_PINCTL_OUT_EN		(1<<6)
+#define AC_PINCTL_HP_EN			(1<<7)
+
+/* configuration default - 32bit */
+#define AC_DEFCFG_SEQUENCE		(0xf<<0)
+#define AC_DEFCFG_DEF_ASSOC		(0xf<<4)
+#define AC_DEFCFG_MISC			(0xf<<8)
+#define AC_DEFCFG_COLOR			(0xf<<12)
+#define AC_DEFCFG_COLOR_SHIFT		12
+#define AC_DEFCFG_CONN_TYPE		(0xf<<16)
+#define AC_DEFCFG_CONN_TYPE_SHIFT	16
+#define AC_DEFCFG_DEVICE		(0xf<<20)
+#define AC_DEFCFG_DEVICE_SHIFT		20
+#define AC_DEFCFG_LOCATION		(0x3f<<24)
+#define AC_DEFCFG_LOCATION_SHIFT	24
+#define AC_DEFCFG_PORT_CONN		(0x3<<30)
+#define AC_DEFCFG_PORT_CONN_SHIFT	30
+
+/* device device types (0x0-0xf) */
+enum {
+	AC_JACK_LINE_OUT,
+	AC_JACK_SPEAKER,
+	AC_JACK_HP_OUT,
+	AC_JACK_CD,
+	AC_JACK_SPDIF_OUT,
+	AC_JACK_DIG_OTHER_OUT,
+	AC_JACK_MODEM_LINE_SIDE,
+	AC_JACK_MODEM_HAND_SIDE,
+	AC_JACK_LINE_IN,
+	AC_JACK_AUX,
+	AC_JACK_MIC_IN,
+	AC_JACK_TELEPHONY,
+	AC_JACK_SPDIF_IN,
+	AC_JACK_DIG_OTHER_IN,
+	AC_JACK_OTHER = 0xf,
+};
+
+/* jack connection types (0x0-0xf) */
+enum {
+	AC_JACK_CONN_UNKNOWN,
+	AC_JACK_CONN_1_8,
+	AC_JACK_CONN_1_4,
+	AC_JACK_CONN_ATAPI,
+	AC_JACK_CONN_RCA,
+	AC_JACK_CONN_OPTICAL,
+	AC_JACK_CONN_OTHER_DIGITAL,
+	AC_JACK_CONN_OTHER_ANALOG,
+	AC_JACK_CONN_DIN,
+	AC_JACK_CONN_XLR,
+	AC_JACK_CONN_RJ11,
+	AC_JACK_CONN_COMB,
+	AC_JACK_CONN_OTHER = 0xf,
+};
+
+/* jack colors (0x0-0xf) */
+enum {
+	AC_JACK_COLOR_UNKNOWN,
+	AC_JACK_COLOR_BLACK,
+	AC_JACK_COLOR_GREY,
+	AC_JACK_COLOR_BLUE,
+	AC_JACK_COLOR_GREEN,
+	AC_JACK_COLOR_RED,
+	AC_JACK_COLOR_ORANGE,
+	AC_JACK_COLOR_YELLOW,
+	AC_JACK_COLOR_PURPLE,
+	AC_JACK_COLOR_PINK,
+	AC_JACK_COLOR_WHITE = 0xe,
+	AC_JACK_COLOR_OTHER,
+};
+
+/* Jack location (0x0-0x3f) */
+/* common case */
+enum {
+	AC_JACK_LOC_NONE,
+	AC_JACK_LOC_REAR,
+	AC_JACK_LOC_FRONT,
+	AC_JACK_LOC_LEFT,
+	AC_JACK_LOC_RIGHT,
+	AC_JACK_LOC_TOP,
+	AC_JACK_LOC_BOTTOM,
+};
+/* bits 4-5 */
+enum {
+	AC_JACK_LOC_EXTERNAL = 0x00,
+	AC_JACK_LOC_INTERNAL = 0x10,
+	AC_JACK_LOC_SEPARATE = 0x20,
+	AC_JACK_LOC_OTHER    = 0x30,
+};
+enum {
+	/* external on primary chasis */
+	AC_JACK_LOC_REAR_PANEL = 0x07,
+	AC_JACK_LOC_DRIVE_BAY,
+	/* internal */
+	AC_JACK_LOC_RISER = 0x17,
+	AC_JACK_LOC_HDMI,
+	AC_JACK_LOC_ATAPI,
+	/* others */
+	AC_JACK_LOC_MOBILE_IN = 0x37,
+	AC_JACK_LOC_MOBILE_OUT,
+};
+
+/* Port connectivity (0-3) */
+enum {
+	AC_JACK_PORT_COMPLEX,
+	AC_JACK_PORT_NONE,
+	AC_JACK_PORT_FIXED,
+	AC_JACK_PORT_BOTH,
+};
+
+/* max. connections to a widget */
+#define HDA_MAX_CONNECTIONS	16
+
+/* max. codec address */
+#define HDA_MAX_CODEC_ADDRESS	0x0f
+
+/*
+ * Structures
+ */
+
+struct hda_bus;
+struct hda_codec;
+struct hda_pcm;
+struct hda_pcm_stream;
+struct hda_bus_unsolicited;
+
+/* NID type */
+typedef u16 hda_nid_t;
+
+/* bus operators */
+struct hda_bus_ops {
+	/* send a single command */
+	int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct,
+		       unsigned int verb, unsigned int parm);
+	/* get a response from the last command */
+	unsigned int (*get_response)(struct hda_codec *codec);
+	/* free the private data */
+	void (*private_free)(struct hda_bus *);
+};
+
+/* template to pass to the bus constructor */
+struct hda_bus_template {
+	void *private_data;
+	struct pci_dev *pci;
+	const char *modelname;
+	struct hda_bus_ops ops;
+};
+
+/*
+ * codec bus
+ *
+ * each controller needs to creata a hda_bus to assign the accessor.
+ * A hda_bus contains several codecs in the list codec_list.
+ */
+struct hda_bus {
+	snd_card_t *card;
+
+	/* copied from template */
+	void *private_data;
+	struct pci_dev *pci;
+	const char *modelname;
+	struct hda_bus_ops ops;
+
+	/* codec linked list */
+	struct list_head codec_list;
+	struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS]; /* caddr -> codec */
+
+	struct semaphore cmd_mutex;
+
+	/* unsolicited event queue */
+	struct hda_bus_unsolicited *unsol;
+
+	snd_info_entry_t *proc;
+};
+
+/*
+ * codec preset
+ *
+ * Known codecs have the patch to build and set up the controls/PCMs
+ * better than the generic parser.
+ */
+struct hda_codec_preset {
+	unsigned int id;
+	unsigned int mask;
+	unsigned int subs;
+	unsigned int subs_mask;
+	unsigned int rev;
+	const char *name;
+	int (*patch)(struct hda_codec *codec);
+};
+	
+/* ops set by the preset patch */
+struct hda_codec_ops {
+	int (*build_controls)(struct hda_codec *codec);
+	int (*build_pcms)(struct hda_codec *codec);
+	int (*init)(struct hda_codec *codec);
+	void (*free)(struct hda_codec *codec);
+	void (*unsol_event)(struct hda_codec *codec, unsigned int res);
+#ifdef CONFIG_PM
+	int (*suspend)(struct hda_codec *codec, unsigned int state);
+	int (*resume)(struct hda_codec *codec, unsigned int state);
+#endif
+};
+
+/* record for amp information cache */
+struct hda_amp_info {
+	u32 key;		/* hash key */
+	u32 amp_caps;		/* amp capabilities */
+	u16 vol[2];		/* current volume & mute*/
+	u16 status;		/* update flag */
+	u16 next;		/* next link */
+};
+
+/* PCM callbacks */
+struct hda_pcm_ops {
+	int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		    snd_pcm_substream_t *substream);
+	int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		     snd_pcm_substream_t *substream);
+	int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		       unsigned int stream_tag, unsigned int format,
+		       snd_pcm_substream_t *substream);
+	int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec,
+		       snd_pcm_substream_t *substream);
+};
+
+/* PCM information for each substream */
+struct hda_pcm_stream {
+	unsigned int substreams;	/* number of substreams, 0 = not exist */
+	unsigned int channels_min;	/* min. number of channels */
+	unsigned int channels_max;	/* max. number of channels */
+	hda_nid_t nid;	/* default NID to query rates/formats/bps, or set up */
+	u32 rates;	/* supported rates */
+	u64 formats;	/* supported formats (SNDRV_PCM_FMTBIT_) */
+	unsigned int maxbps;	/* supported max. bit per sample */
+	struct hda_pcm_ops ops;
+};
+
+/* for PCM creation */
+struct hda_pcm {
+	char *name;
+	struct hda_pcm_stream stream[2];
+};
+
+/* codec information */
+struct hda_codec {
+	struct hda_bus *bus;
+	unsigned int addr;	/* codec addr*/
+	struct list_head list;	/* list point */
+
+	hda_nid_t afg;	/* AFG node id */
+
+	/* ids */
+	u32 vendor_id;
+	u32 subsystem_id;
+	u32 revision_id;
+
+	/* detected preset */
+	const struct hda_codec_preset *preset;
+
+	/* set by patch */
+	struct hda_codec_ops patch_ops;
+
+	/* resume phase - all controls should update even if
+	 * the values are not changed
+	 */
+	unsigned int in_resume;
+
+	/* PCM to create, set by patch_ops.build_pcms callback */
+	unsigned int num_pcms;
+	struct hda_pcm *pcm_info;
+
+	/* codec specific info */
+	void *spec;
+
+	/* hash for amp access */
+	u16 amp_hash[32];
+	int num_amp_entries;
+	struct hda_amp_info amp_info[128]; /* big enough? */
+
+	struct semaphore spdif_mutex;
+	unsigned int spdif_status;
+};
+
+/* direction */
+enum {
+	HDA_INPUT, HDA_OUTPUT
+};
+
+
+/*
+ * constructors
+ */
+int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp,
+		    struct hda_bus **busp);
+int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
+		      struct hda_codec **codecp);
+
+/*
+ * low level functions
+ */
+unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct,
+				unsigned int verb, unsigned int parm);
+int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
+			unsigned int verb, unsigned int parm);
+#define snd_hda_param_read(codec, nid, param) snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param)
+int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id);
+int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns);
+
+struct hda_verb {
+	hda_nid_t nid;
+	u32 verb;
+	u32 param;
+};
+
+void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq);
+
+/* unsolicited event */
+int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
+
+/*
+ * Mixer
+ */
+int snd_hda_build_controls(struct hda_bus *bus);
+
+/*
+ * PCM
+ */
+int snd_hda_build_pcms(struct hda_bus *bus);
+void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag,
+				int channel_id, int format);
+unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels,
+					unsigned int format, unsigned int maxbps);
+int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+				u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
+int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
+				unsigned int format);
+
+/*
+ * Misc
+ */
+void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
+
+/*
+ * power management
+ */
+#ifdef CONFIG_PM
+int snd_hda_suspend(struct hda_bus *bus, unsigned int state);
+int snd_hda_resume(struct hda_bus *bus, unsigned int state);
+#endif
+
+#endif /* __SOUND_HDA_CODEC_H */
diff -Nru a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/pci/hda/hda_generic.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,898 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * Generic widget tree parser
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This driver 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 driver 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/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+/* widget node for parsing */
+struct hda_gnode {
+	hda_nid_t nid;		/* NID of this widget */
+	unsigned short nconns;	/* number of input connections */
+	hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; /* input connections */
+	unsigned int wid_caps;	/* widget capabilities */
+	unsigned char type;	/* widget type */
+	unsigned char pin_ctl;	/* pin controls */
+	unsigned char checked;	/* the flag indicates that the node is already parsed */
+	unsigned int pin_caps;	/* pin widget capabilities */
+	unsigned int def_cfg;	/* default configuration */
+	unsigned int amp_out_caps;	/* AMP out capabilities */
+	unsigned int amp_in_caps;	/* AMP in capabilities */
+	struct list_head list;
+};
+
+/* pathc-specific record */
+struct hda_gspec {
+	struct hda_gnode *dac_node;	/* DAC node */
+	struct hda_gnode *out_pin_node;	/* Output pin (Line-Out) node */
+	struct hda_gnode *pcm_vol_node;	/* Node for PCM volume */
+	unsigned int pcm_vol_index;	/* connection of PCM volume */
+
+	struct hda_gnode *adc_node;	/* ADC node */
+	struct hda_gnode *cap_vol_node;	/* Node for capture volume */
+	unsigned int cur_cap_src;	/* current capture source */
+	struct hda_input_mux input_mux;
+	char cap_labels[HDA_MAX_NUM_INPUTS][16];
+
+	unsigned int def_amp_in_caps;
+	unsigned int def_amp_out_caps;
+
+	struct hda_pcm pcm_rec;		/* PCM information */
+
+	struct list_head nid_list;	/* list of widgets */
+};
+
+/*
+ * retrieve the default device type from the default config value
+ */
+#define get_defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
+#define get_defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
+
+/*
+ * destructor
+ */
+static void snd_hda_generic_free(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct list_head *p, *n;
+
+	if (! spec)
+		return;
+	/* free all widgets */
+	list_for_each_safe(p, n, &spec->nid_list) {
+		struct hda_gnode *node = list_entry(p, struct hda_gnode, list);
+		kfree(node);
+	}
+	kfree(spec);
+}
+
+
+/*
+ * add a new widget node and read its attributes
+ */
+static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid_t nid)
+{
+	struct hda_gnode *node;
+	int nconns;
+
+	node = kcalloc(1, sizeof(*node), GFP_KERNEL);
+	if (node == NULL)
+		return -ENOMEM;
+	node->nid = nid;
+	nconns = snd_hda_get_connections(codec, nid, node->conn_list, HDA_MAX_CONNECTIONS);
+	if (nconns < 0) {
+		kfree(node);
+		return nconns;
+	}
+	node->nconns = nconns;
+	node->wid_caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
+	node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+
+	if (node->type == AC_WID_PIN) {
+		node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP);
+		node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+		node->def_cfg = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+	}
+
+	if (node->wid_caps & AC_WCAP_OUT_AMP) {
+		if (node->wid_caps & AC_WCAP_AMP_OVRD)
+			node->amp_out_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_OUT_CAP);
+		if (! node->amp_out_caps)
+			node->amp_out_caps = spec->def_amp_out_caps;
+	}
+	if (node->wid_caps & AC_WCAP_IN_AMP) {
+		if (node->wid_caps & AC_WCAP_AMP_OVRD)
+			node->amp_in_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_IN_CAP);
+		if (! node->amp_in_caps)
+			node->amp_in_caps = spec->def_amp_in_caps;
+	}
+	list_add_tail(&node->list, &spec->nid_list);
+	return 0;
+}
+
+/*
+ * build the AFG subtree
+ */
+static int build_afg_tree(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	int i, nodes, err;
+	hda_nid_t nid;
+
+	snd_assert(spec, return -EINVAL);
+
+	spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP);
+	spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP);
+
+	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
+	if (! nid || nodes < 0) {
+		printk(KERN_ERR "Invalid AFG subtree\n");
+		return -EINVAL;
+	}
+
+	/* parse all nodes belonging to the AFG */
+	for (i = 0; i < nodes; i++, nid++) {
+		if ((err = add_new_node(codec, spec, nid)) < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+
+/*
+ * look for the node record for the given NID
+ */
+/* FIXME: should avoid the braindead linear search */
+static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid)
+{
+	struct list_head *p;
+	struct hda_gnode *node;
+
+	list_for_each(p, &spec->nid_list) {
+		node = list_entry(p, struct hda_gnode, list);
+		if (node->nid == nid)
+			return node;
+	}
+	return NULL;
+}
+
+/*
+ * unmute (and set max vol) the output amplifier
+ */
+static int unmute_output(struct hda_codec *codec, struct hda_gnode *node)
+{
+	unsigned int val, ofs;
+	snd_printdd("UNMUTE OUT: NID=0x%x\n", node->nid);
+	val = (node->amp_out_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+	ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
+	if (val >= ofs)
+		val -= ofs;
+	val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;
+	val |= AC_AMP_SET_OUTPUT;
+	return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val);
+}
+
+/*
+ * unmute (and set max vol) the input amplifier
+ */
+static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigned int index)
+{
+	unsigned int val, ofs;
+	snd_printdd("UNMUTE IN: NID=0x%x IDX=0x%x\n", node->nid, index);
+	val = (node->amp_in_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+	ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
+	if (val >= ofs)
+		val -= ofs;
+	val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;
+	val |= AC_AMP_SET_INPUT;
+	// awk added - fixed to allow unmuting of indexed amps
+	val |= index << AC_AMP_SET_INDEX_SHIFT;
+	return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val);
+}
+
+/*
+ * select the input connection of the given node.
+ */
+static int select_input_connection(struct hda_codec *codec, struct hda_gnode *node,
+				   unsigned int index)
+{
+	snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index);
+	return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_CONNECT_SEL, index);
+}
+
+/*
+ * clear checked flag of each node in the node list
+ */
+static void clear_check_flags(struct hda_gspec *spec)
+{
+	struct list_head *p;
+	struct hda_gnode *node;
+
+	list_for_each(p, &spec->nid_list) {
+		node = list_entry(p, struct hda_gnode, list);
+		node->checked = 0;
+	}
+}
+
+/*
+ * parse the output path recursively until reach to an audio output widget
+ *
+ * returns 0 if not found, 1 if found, or a negative error code.
+ */
+static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec,
+			     struct hda_gnode *node)
+{
+	int i, err;
+	struct hda_gnode *child;
+
+	if (node->checked)
+		return 0;
+
+	node->checked = 1;
+	if (node->type == AC_WID_AUD_OUT) {
+		snd_printdd("AUD_OUT found %x\n", node->nid);
+		if (spec->dac_node) {
+			/* already DAC node is assigned, just unmute & connect */
+			return node == spec->dac_node;
+		}
+		spec->dac_node = node;
+		if (node->wid_caps & AC_WCAP_OUT_AMP) {
+			spec->pcm_vol_node = node;
+			spec->pcm_vol_index = 0;
+		}
+		return 1; /* found */
+	}
+
+	for (i = 0; i < node->nconns; i++) {
+		child = hda_get_node(spec, node->conn_list[i]);
+		if (! child)
+			continue;
+		err = parse_output_path(codec, spec, child);
+		if (err < 0)
+			return err;
+		else if (err > 0) {
+			/* found one,
+			 * select the path, unmute both input and output
+			 */
+			if (node->nconns > 1)
+				select_input_connection(codec, node, i);
+			unmute_input(codec, node, i);
+			unmute_output(codec, node);
+			if (! spec->pcm_vol_node) {
+				if (node->wid_caps & AC_WCAP_IN_AMP) {
+					spec->pcm_vol_node = node;
+					spec->pcm_vol_index = i;
+				} else if (node->wid_caps & AC_WCAP_OUT_AMP) {
+					spec->pcm_vol_node = node;
+					spec->pcm_vol_index = 0;
+				}
+			}
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Look for the output PIN widget with the given jack type
+ * and parse the output path to that PIN.
+ *
+ * Returns the PIN node when the path to DAC is established.
+ */
+static struct hda_gnode *parse_output_jack(struct hda_codec *codec,
+					   struct hda_gspec *spec,
+					   int jack_type)
+{
+	struct list_head *p;
+	struct hda_gnode *node;
+	int err;
+
+	list_for_each(p, &spec->nid_list) {
+		node = list_entry(p, struct hda_gnode, list);
+		if (node->type != AC_WID_PIN)
+			continue;
+		/* output capable? */
+		if (! (node->pin_caps & AC_PINCAP_OUT))
+			continue;
+		if (jack_type >= 0) {
+			if (jack_type != get_defcfg_type(node))
+				continue;
+		} else {
+			/* output as default? */
+			if (! (node->pin_ctl & AC_PINCTL_OUT_EN))
+				continue;
+		}
+		clear_check_flags(spec);
+		err = parse_output_path(codec, spec, node);
+		if (err < 0)
+			return NULL;
+		else if (err > 0) {
+			/* unmute the PIN output */
+			unmute_output(codec, node);
+			/* set PIN-Out enable */
+			snd_hda_codec_write(codec, node->nid, 0,
+					    AC_VERB_SET_PIN_WIDGET_CONTROL,
+					    AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+			return node;
+		}
+	}
+	return NULL;
+}
+
+
+/*
+ * parse outputs
+ */
+static int parse_output(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct hda_gnode *node;
+
+	/*
+	 * Look for the output PIN widget
+	 */
+	/* first, look for the line-out pin */
+	node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT);
+	if (node) /* found, remember the PIN node */
+		spec->out_pin_node = node;
+	/* look for the HP-out pin */
+	node = parse_output_jack(codec, spec, AC_JACK_HP_OUT);
+	if (node) {
+		if (! spec->out_pin_node)
+			spec->out_pin_node = node;
+	}
+
+	if (! spec->out_pin_node) {
+		/* no line-out or HP pins found,
+		 * then choose for the first output pin
+		 */
+		spec->out_pin_node = parse_output_jack(codec, spec, -1);
+		if (! spec->out_pin_node)
+			snd_printd("hda_generic: no proper output path found\n");
+	}
+
+	return 0;
+}
+
+/*
+ * input MUX
+ */
+
+/* control callbacks */
+static int capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct hda_gspec *spec = codec->spec;
+	return snd_hda_input_mux_info(&spec->input_mux, uinfo);
+}
+
+static int capture_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct hda_gspec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_cap_src;
+	return 0;
+}
+
+static int capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct hda_gspec *spec = codec->spec;
+	return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol,
+				     spec->adc_node->nid, &spec->cur_cap_src);
+}
+
+/*
+ * return the string name of the given input PIN widget
+ */
+static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
+{
+	unsigned int location = get_defcfg_location(node);
+	switch (get_defcfg_type(node)) {
+	case AC_JACK_LINE_IN:
+		if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+			return "Front Line";
+		return "Line";
+	case AC_JACK_CD:
+		if (pinctl)
+			*pinctl |= AC_PIN_VREF_GRD;
+		return "CD";
+	case AC_JACK_AUX:
+		if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+			return "Front Aux";
+		return "Aux";
+	case AC_JACK_MIC_IN:
+		if ((location & 0x0f) == AC_JACK_LOC_FRONT)
+			return "Front Mic";
+		return "Mic";
+	case AC_JACK_SPDIF_IN:
+		return "SPDIF";
+	case AC_JACK_DIG_OTHER_IN:
+		return "Digital";
+	}
+	return NULL;
+}
+
+/*
+ * parse the nodes recursively until reach to the input PIN
+ *
+ * returns 0 if not found, 1 if found, or a negative error code.
+ */
+static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
+			       struct hda_gnode *node)
+{
+	int i, err;
+	unsigned int pinctl;
+	char *label;
+	const char *type;
+
+	if (node->checked)
+		return 0;
+
+	node->checked = 1;
+	if (node->type != AC_WID_PIN) {
+		for (i = 0; i < node->nconns; i++) {
+			struct hda_gnode *child;
+			child = hda_get_node(spec, node->conn_list[i]);
+			if (! child)
+				continue;
+			err = parse_adc_sub_nodes(codec, spec, child);
+			if (err < 0)
+				return err;
+			if (err > 0) {
+				/* found one,
+				 * select the path, unmute both input and output
+				 */
+				if (node->nconns > 1)
+					select_input_connection(codec, node, i);
+				unmute_input(codec, node, i);
+				unmute_output(codec, node);
+				return err;
+			}
+		}
+		return 0;
+	}
+
+	/* input capable? */
+	if (! (node->pin_caps & AC_PINCAP_IN))
+		return 0;
+
+	if (spec->input_mux.num_items >= HDA_MAX_NUM_INPUTS) {
+		snd_printk(KERN_ERR "hda_generic: Too many items for capture\n");
+		return -EINVAL;
+	}
+
+	pinctl = AC_PINCTL_IN_EN;
+	/* create a proper capture source label */
+	type = get_input_type(node, &pinctl);
+	if (! type) {
+		/* input as default? */
+		if (! (node->pin_ctl & AC_PINCTL_IN_EN))
+			return 0;
+		type = "Input";
+	}
+	label = spec->cap_labels[spec->input_mux.num_items];
+	strcpy(label, type);
+	spec->input_mux.items[spec->input_mux.num_items].label = label;
+
+	/* unmute the PIN external input */
+	unmute_input(codec, node, 0); /* index = 0? */
+	/* set PIN-In enable */
+	snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+
+	return 1; /* found */
+}
+
+/*
+ * parse input
+ */
+static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct hda_gnode *node;
+	int i, err;
+
+	snd_printdd("AUD_IN = %x\n", adc_node->nid);
+	clear_check_flags(spec);
+
+	// awk added - fixed no recording due to muted widget
+	unmute_input(codec, adc_node, 0);
+	
+	/*
+	 * check each connection of the ADC
+	 * if it reaches to a proper input PIN, add the path as the
+	 * input path.
+	 */
+	for (i = 0; i < adc_node->nconns; i++) {
+		node = hda_get_node(spec, adc_node->conn_list[i]);
+		if (! node)
+			continue;
+		err = parse_adc_sub_nodes(codec, spec, node);
+		if (err < 0)
+			return err;
+		else if (err > 0) {
+			struct hda_input_mux_item *csrc = &spec->input_mux.items[spec->input_mux.num_items];
+			char *buf = spec->cap_labels[spec->input_mux.num_items];
+			int ocap;
+			for (ocap = 0; ocap < spec->input_mux.num_items; ocap++) {
+				if (! strcmp(buf, spec->cap_labels[ocap])) {
+					/* same label already exists,
+					 * put the index number to be unique
+					 */
+					sprintf(buf, "%s %d", spec->cap_labels[ocap],
+						spec->input_mux.num_items);
+				}
+			}
+			csrc->index = i;
+			spec->input_mux.num_items++;
+		}
+	}
+
+	if (! spec->input_mux.num_items)
+		return 0; /* no input path found... */
+
+	snd_printdd("[Capture Source] NID=0x%x, #SRC=%d\n", adc_node->nid, spec->input_mux.num_items);
+	for (i = 0; i < spec->input_mux.num_items; i++)
+		snd_printdd("  [%s] IDX=0x%x\n", spec->input_mux.items[i].label,
+			    spec->input_mux.items[i].index);
+
+	spec->adc_node = adc_node;
+	return 1;
+}
+
+/*
+ * parse input
+ */
+static int parse_input(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct list_head *p;
+	struct hda_gnode *node;
+	int err;
+
+	/*
+	 * At first we look for an audio input widget.
+	 * If it reaches to certain input PINs, we take it as the
+	 * input path.
+	 */
+	list_for_each(p, &spec->nid_list) {
+		node = list_entry(p, struct hda_gnode, list);
+		if (node->type == AC_WID_AUD_IN) {
+			err = parse_input_path(codec, node);
+			if (err < 0)
+				return err;
+			else if (err > 0)
+				return 0;
+		}
+	}
+	snd_printd("hda_generic: no proper input path found\n");
+	return 0;
+}
+
+/*
+ * create mixer controls if possible
+ */
+#define DIR_OUT		0x1
+#define DIR_IN		0x2
+
+static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
+			unsigned int index, const char *type, const char *dir_sfx)
+{
+	char name[32];
+	int err;
+	int created = 0;
+
+	if (type)
+		sprintf(name, "%s %s Switch", type, dir_sfx);
+	else
+		sprintf(name, "%s Switch", dir_sfx);
+	if ((node->wid_caps & AC_WCAP_IN_AMP) &&
+	    (node->amp_in_caps & AC_AMPCAP_MUTE)) {
+		snd_kcontrol_new_t knew =
+			HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT);
+		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
+		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+			return err;
+		created = 1;
+	} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
+		   (node->amp_out_caps & AC_AMPCAP_MUTE)) {
+		snd_kcontrol_new_t knew =
+			HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT);
+		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
+		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+			return err;
+		created = 1;
+	}
+
+	if (type)
+		sprintf(name, "%s %s Volume", type, dir_sfx);
+	else
+		sprintf(name, "%s Volume", dir_sfx);
+	if ((node->wid_caps & AC_WCAP_IN_AMP) &&
+	    (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
+		snd_kcontrol_new_t knew =
+			HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
+		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
+		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+			return err;
+		created = 1;
+	} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
+		   (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
+		snd_kcontrol_new_t knew =
+			HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
+		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
+		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+			return err;
+		created = 1;
+	}
+
+	return created;
+}
+
+/*
+ * check whether the controls with the given name and direction suffix already exist
+ */
+static int check_existing_control(struct hda_codec *codec, const char *type, const char *dir)
+{
+	snd_ctl_elem_id_t id;
+	memset(&id, 0, sizeof(id));
+	sprintf(id.name, "%s %s Volume", type, dir);
+	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	if (snd_ctl_find_id(codec->bus->card, &id))
+		return 1;
+	sprintf(id.name, "%s %s Switch", type, dir);
+	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	if (snd_ctl_find_id(codec->bus->card, &id))
+		return 1;
+	return 0;
+}
+
+/*
+ * build output mixer controls
+ */
+static int build_output_controls(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	int err;
+
+	err = create_mixer(codec, spec->pcm_vol_node, spec->pcm_vol_index,
+			   "PCM", "Playback");
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+/* create capture volume/switch */
+static int build_input_controls(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct hda_gnode *adc_node = spec->adc_node;
+	int err;
+
+	if (! adc_node)
+		return 0; /* not found */
+
+	/* create capture volume and switch controls if the ADC has an amp */
+	err = create_mixer(codec, adc_node, 0, NULL, "Capture");
+
+	/* create input MUX if multiple sources are available */
+	if (spec->input_mux.num_items > 1) {
+		static snd_kcontrol_new_t cap_sel = {
+			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+			.name = "Capture Source",
+			.info = capture_source_info,
+			.get = capture_source_get,
+			.put = capture_source_put,
+		};
+		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0)
+			return err;
+		spec->cur_cap_src = 0;
+		select_input_connection(codec, adc_node, spec->input_mux.items[0].index);
+	}
+	return 0;
+}
+
+
+/*
+ * parse the nodes recursively until reach to the output PIN.
+ *
+ * returns 0 - if not found,
+ *         1 - if found, but no mixer is created
+ *         2 - if found and mixer was already created, (just skip)
+ *         a negative error code
+ */
+static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec,
+			       struct hda_gnode *node, struct hda_gnode *dest_node,
+			       const char *type)
+{
+	int i, err;
+
+	if (node->checked)
+		return 0;
+
+	node->checked = 1;
+	if (node == dest_node) {
+		/* loopback connection found */
+		return 1;
+	}
+
+	for (i = 0; i < node->nconns; i++) {
+		struct hda_gnode *child = hda_get_node(spec, node->conn_list[i]);
+		if (! child)
+			continue;
+		err = parse_loopback_path(codec, spec, child, dest_node, type);
+		if (err < 0)
+			return err;
+		else if (err >= 1) {
+			if (err == 1) {
+				err = create_mixer(codec, node, i, type, "Playback");
+				if (err < 0)
+					return err;
+				if (err > 0)
+					return 2; /* ok, created */
+				/* not created, maybe in the lower path */
+				err = 1;
+			}
+			/* connect and unmute */
+			if (node->nconns > 1)
+				select_input_connection(codec, node, i);
+			unmute_input(codec, node, i);
+			unmute_output(codec, node);
+			return err;
+		}
+	}
+	return 0;
+}
+
+/*
+ * parse the tree and build the loopback controls
+ */
+static int build_loopback_controls(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct list_head *p;
+	struct hda_gnode *node;
+	int err;
+	const char *type;
+
+	if (! spec->out_pin_node)
+		return 0;
+
+	list_for_each(p, &spec->nid_list) {
+		node = list_entry(p, struct hda_gnode, list);
+		if (node->type != AC_WID_PIN)
+			continue;
+		/* input capable? */
+		if (! (node->pin_caps & AC_PINCAP_IN))
+			return 0;
+		type = get_input_type(node, NULL);
+		if (type) {
+			if (check_existing_control(codec, type, "Playback"))
+				continue;
+			clear_check_flags(spec);
+			err = parse_loopback_path(codec, spec, spec->out_pin_node,
+						  node, type);
+			if (err < 0)
+				return err;
+			if (! err)
+				continue;
+		}
+	}
+	return 0;
+}
+
+/*
+ * build mixer controls
+ */
+static int build_generic_controls(struct hda_codec *codec)
+{
+	int err;
+
+	if ((err = build_input_controls(codec)) < 0 ||
+	    (err = build_output_controls(codec)) < 0 ||
+	    (err = build_loopback_controls(codec)) < 0)
+		return err;
+
+	return 0;
+}
+
+/*
+ * PCM
+ */
+static struct hda_pcm_stream generic_pcm_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+static int build_generic_pcms(struct hda_codec *codec)
+{
+	struct hda_gspec *spec = codec->spec;
+	struct hda_pcm *info = &spec->pcm_rec;
+
+	if (! spec->dac_node && ! spec->adc_node) {
+		snd_printd("hda_generic: no PCM found\n");
+		return 0;
+	}
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = "HDA Generic";
+	if (spec->dac_node) {
+		info->stream[0] = generic_pcm_playback;
+		info->stream[0].nid = spec->dac_node->nid;
+	}
+	if (spec->adc_node) {
+		info->stream[1] = generic_pcm_playback;
+		info->stream[1].nid = spec->adc_node->nid;
+	}
+
+	return 0;
+}
+
+
+/*
+ */
+static struct hda_codec_ops generic_patch_ops = {
+	.build_controls = build_generic_controls,
+	.build_pcms = build_generic_pcms,
+	.free = snd_hda_generic_free,
+};
+
+/*
+ * the generic parser
+ */
+int snd_hda_parse_generic_codec(struct hda_codec *codec)
+{
+	struct hda_gspec *spec;
+	int err;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL) {
+		printk(KERN_ERR "hda_generic: can't allocate spec\n");
+		return -ENOMEM;
+	}
+	codec->spec = spec;
+	INIT_LIST_HEAD(&spec->nid_list);
+
+	if ((err = build_afg_tree(codec)) < 0)
+		goto error;
+
+	if ((err = parse_input(codec)) < 0 ||
+	    (err = parse_output(codec)) < 0)
+		goto error;
+
+	codec->patch_ops = generic_patch_ops;
+
+	return 0;
+
+ error:
+	snd_hda_generic_free(codec);
+	return err;
+}
diff -Nru a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/pci/hda/hda_intel.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,1449 @@
+/*
+ *
+ *  hda_intel.c - Implementation of primary alsa driver code base for Intel HD Audio.
+ *
+ *  Copyright(c) 2004 Intel Corporation. All rights reserved.
+ *
+ *  Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *                     PeiSen Hou <pshou@realtek.com.tw>
+ *
+ *  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.
+ *
+ *  CONTACTS:
+ *
+ *  Matt Jared		matt.jared@intel.com
+ *  Andy Kopp		andy.kopp@intel.com
+ *  Dan Kogan		dan.d.kogan@intel.com
+ *
+ *  CHANGES:
+ *
+ *  2004.12.01	Major rewrite by tiwai, merged the work of pshou
+ * 
+ */
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include "hda_codec.h"
+
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static char *model[SNDRV_CARDS];
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Intel HD audio interface.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
+module_param_array(model, charp, NULL, 0444);
+MODULE_PARM_DESC(model, "Use the given board model.");
+
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
+			 "{Intel, ICH6M},"
+			 "{Intel, ICH7}}");
+MODULE_DESCRIPTION("Intel HDA driver");
+
+#define SFX	"hda-intel: "
+
+/*
+ * registers
+ */
+#define ICH6_REG_GCAP			0x00
+#define ICH6_REG_VMIN			0x02
+#define ICH6_REG_VMAJ			0x03
+#define ICH6_REG_OUTPAY			0x04
+#define ICH6_REG_INPAY			0x06
+#define ICH6_REG_GCTL			0x08
+#define ICH6_REG_WAKEEN			0x0c
+#define ICH6_REG_STATESTS		0x0e
+#define ICH6_REG_GSTS			0x10
+#define ICH6_REG_INTCTL			0x20
+#define ICH6_REG_INTSTS			0x24
+#define ICH6_REG_WALCLK			0x30
+#define ICH6_REG_SYNC			0x34	
+#define ICH6_REG_CORBLBASE		0x40
+#define ICH6_REG_CORBUBASE		0x44
+#define ICH6_REG_CORBWP			0x48
+#define ICH6_REG_CORBRP			0x4A
+#define ICH6_REG_CORBCTL		0x4c
+#define ICH6_REG_CORBSTS		0x4d
+#define ICH6_REG_CORBSIZE		0x4e
+
+#define ICH6_REG_RIRBLBASE		0x50
+#define ICH6_REG_RIRBUBASE		0x54
+#define ICH6_REG_RIRBWP			0x58
+#define ICH6_REG_RINTCNT		0x5a
+#define ICH6_REG_RIRBCTL		0x5c
+#define ICH6_REG_RIRBSTS		0x5d
+#define ICH6_REG_RIRBSIZE		0x5e
+
+#define ICH6_REG_IC			0x60
+#define ICH6_REG_IR			0x64
+#define ICH6_REG_IRS			0x68
+#define   ICH6_IRS_VALID	(1<<1)
+#define   ICH6_IRS_BUSY		(1<<0)
+
+#define ICH6_REG_DPLBASE		0x70
+#define ICH6_REG_DPUBASE		0x74
+#define   ICH6_DPLBASE_ENABLE	0x1	/* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define ICH6_REG_SD_CTL			0x00
+#define ICH6_REG_SD_STS			0x03
+#define ICH6_REG_SD_LPIB		0x04
+#define ICH6_REG_SD_CBL			0x08
+#define ICH6_REG_SD_LVI			0x0c
+#define ICH6_REG_SD_FIFOW		0x0e
+#define ICH6_REG_SD_FIFOSIZE		0x10
+#define ICH6_REG_SD_FORMAT		0x12
+#define ICH6_REG_SD_BDLPL		0x18
+#define ICH6_REG_SD_BDLPU		0x1c
+
+/* PCI space */
+#define ICH6_PCIREG_TCSEL	0x44
+
+/*
+ * other constants
+ */
+
+/* max number of SDs */
+#define MAX_ICH6_DEV		8
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define AZX_MAX_FRAG		(PAGE_SIZE / (MAX_ICH6_DEV * 16))
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE	(1024*1024*1024)
+/* max number of PCM devics per card */
+#define AZX_MAX_PCMS		8
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE	0x01
+#define RIRB_INT_OVERRUN	0x04
+#define RIRB_INT_MASK		0x05
+
+/* STATESTS int mask: SD2,SD1,SD0 */
+#define STATESTS_INT_MASK	0x07
+#define AZX_MAX_CODECS		3
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
+#define SD_CTL_DMA_START	0x02	/* stream DMA start bit */
+#define SD_CTL_STREAM_TAG_MASK	(0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT	20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR		0x10	/* descriptor error interrupt */
+#define SD_INT_FIFO_ERR		0x08	/* FIFO error interrupt */
+#define SD_INT_COMPLETE		0x04	/* completion interrupt */
+#define SD_INT_MASK		(SD_INT_DESC_ERR|SD_INT_FIFO_ERR|SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY	0x20	/* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define ICH6_INT_ALL_STREAM	0xff		/* all stream interrupts */
+#define ICH6_INT_CTRL_EN	0x40000000	/* controller interrupt enable bit */
+#define ICH6_INT_GLOBAL_EN	0x80000000	/* global interrupt enable bit */
+
+/* GCTL reset bit */
+#define ICH6_GCTL_RESET		(1<<0)
+
+/* CORB/RIRB control, read/write pointer */
+#define ICH6_RBCTL_DMA_EN	0x02	/* enable DMA */
+#define ICH6_RBCTL_IRQ_EN	0x01	/* enable IRQ */
+#define ICH6_RBRWP_CLR		0x8000	/* read/write pointer clear */
+/* below are so far hardcoded - should read registers in future */
+#define ICH6_MAX_CORB_ENTRIES	256
+#define ICH6_MAX_RIRB_ENTRIES	256
+
+
+/*
+ * Use CORB/RIRB for communication from/to codecs.
+ * This is the way recommended by Intel (see below).
+ */
+#define USE_CORB_RIRB
+
+/*
+ * Define this if use the position buffer instead of reading SD_LPIB
+ * It's not used as default since SD_LPIB seems to give more accurate position
+ */
+/* #define USE_POSBUF */
+
+/*
+ */
+
+typedef struct snd_azx azx_t;
+typedef struct snd_azx_rb azx_rb_t;
+typedef struct snd_azx_dev azx_dev_t;
+
+struct snd_azx_dev {
+	u32 *bdl;			/* virtual address of the BDL */
+	dma_addr_t bdl_addr;		/* physical address of the BDL */
+	volatile u32 *posbuf;			/* position buffer pointer */
+
+	unsigned int bufsize;		/* size of the play buffer in bytes */
+	unsigned int fragsize;		/* size of each period in bytes */
+	unsigned int frags;		/* number for period in the play buffer */
+	unsigned int fifo_size;		/* FIFO size */
+
+	void __iomem *sd_addr;		/* stream descriptor pointer */
+
+	u32 sd_int_sta_mask;		/* stream int status mask */
+
+	/* pcm support */
+	snd_pcm_substream_t *substream;	/* assigned substream, set in PCM open */
+	unsigned int format_val;	/* format value to be set in the controller and the codec */
+	unsigned char stream_tag;	/* assigned stream */
+	unsigned char index;		/* stream index */
+
+	unsigned int opened: 1;
+	unsigned int running: 1;
+};
+
+/* CORB/RIRB */
+struct snd_azx_rb {
+	u32 *buf;		/* CORB/RIRB buffer
+				 * Each CORB entry is 4byte, RIRB is 8byte
+				 */
+	dma_addr_t addr;	/* physical address of CORB/RIRB buffer */
+	/* for RIRB */
+	unsigned short rp, wp;	/* read/write pointers */
+	int cmds;		/* number of pending requests */
+	u32 res;		/* last read value */
+};
+
+struct snd_azx {
+	snd_card_t *card;
+	struct pci_dev *pci;
+
+	/* pci resources */
+	unsigned long addr;
+	void __iomem *remap_addr;
+	int irq;
+
+	/* locks */
+	spinlock_t reg_lock;
+	struct semaphore open_mutex;
+
+	/* streams */
+	azx_dev_t azx_dev[MAX_ICH6_DEV];
+
+	/* PCM */
+	unsigned int pcm_devs;
+	snd_pcm_t *pcm[AZX_MAX_PCMS];
+
+	/* HD codec */
+	unsigned short codec_mask;
+	struct hda_bus *bus;
+
+	/* CORB/RIRB */
+	azx_rb_t corb;
+	azx_rb_t rirb;
+
+	/* BDL, CORB/RIRB and position buffers */
+	struct snd_dma_buffer bdl;
+	struct snd_dma_buffer rb;
+	struct snd_dma_buffer posbuf;
+};
+
+/*
+ * macros for easy use
+ */
+#define azx_writel(chip,reg,value) \
+	writel(value, (chip)->remap_addr + ICH6_REG_##reg)
+#define azx_readl(chip,reg) \
+	readl((chip)->remap_addr + ICH6_REG_##reg)
+#define azx_writew(chip,reg,value) \
+	writew(value, (chip)->remap_addr + ICH6_REG_##reg)
+#define azx_readw(chip,reg) \
+	readw((chip)->remap_addr + ICH6_REG_##reg)
+#define azx_writeb(chip,reg,value) \
+	writeb(value, (chip)->remap_addr + ICH6_REG_##reg)
+#define azx_readb(chip,reg) \
+	readb((chip)->remap_addr + ICH6_REG_##reg)
+
+#define azx_sd_writel(dev,reg,value) \
+	writel(value, (dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_readl(dev,reg) \
+	readl((dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_writew(dev,reg,value) \
+	writew(value, (dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_readw(dev,reg) \
+	readw((dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_writeb(dev,reg,value) \
+	writeb(value, (dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_readb(dev,reg) \
+	readb((dev)->sd_addr + ICH6_REG_##reg)
+
+/* for pcm support */
+#define get_azx_dev(substream) (azx_dev_t*)(substream->runtime->private_data)
+
+/* Get the upper 32bit of the given dma_addr_t
+ * Compiler should optimize and eliminate the code if dma_addr_t is 32bit
+ */
+#define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0)
+
+
+/*
+ * Interface for HD codec
+ */
+
+#ifdef USE_CORB_RIRB
+/*
+ * CORB / RIRB interface
+ */
+static int azx_alloc_cmd_io(azx_t *chip)
+{
+	int err;
+
+	/* single page (at least 4096 bytes) must suffice for both ringbuffes */
+	err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+				  PAGE_SIZE, &chip->rb);
+	if (err < 0) {
+		snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n");
+		return err;
+	}
+	return 0;
+}
+
+static void azx_init_cmd_io(azx_t *chip)
+{
+	/* CORB set up */
+	chip->corb.addr = chip->rb.addr;
+	chip->corb.buf = (u32 *)chip->rb.area;
+	azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
+	azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr));
+
+	/* set the corb write pointer to 0 */
+	azx_writew(chip, CORBWP, 0);
+	/* reset the corb hw read pointer */
+	azx_writew(chip, CORBRP, ICH6_RBRWP_CLR);
+	/* enable corb dma */
+	azx_writeb(chip, CORBCTL, ICH6_RBCTL_DMA_EN);
+
+	/* RIRB set up */
+	chip->rirb.addr = chip->rb.addr + 2048;
+	chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+	azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
+	azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr));
+
+	/* reset the rirb hw write pointer */
+	azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR);
+	/* set N=1, get RIRB response interrupt for new entry */
+	azx_writew(chip, RINTCNT, 1);
+	/* enable rirb dma and response irq */
+#ifdef USE_CORB_RIRB
+	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
+#else
+	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN);
+#endif
+	chip->rirb.rp = chip->rirb.cmds = 0;
+}
+
+static void azx_free_cmd_io(azx_t *chip)
+{
+	/* disable ringbuffer DMAs */
+	azx_writeb(chip, RIRBCTL, 0);
+	azx_writeb(chip, CORBCTL, 0);
+}
+
+/* send a command */
+static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+			unsigned int verb, unsigned int para)
+{
+	azx_t *chip = codec->bus->private_data;
+	unsigned int wp;
+	u32 val;
+
+	val = (u32)(codec->addr & 0x0f) << 28;
+	val |= (u32)direct << 27;
+	val |= (u32)nid << 20;
+	val |= verb << 8;
+	val |= para;
+
+	/* add command to corb */
+	wp = azx_readb(chip, CORBWP);
+	wp++;
+	wp %= ICH6_MAX_CORB_ENTRIES;
+
+	spin_lock_irq(&chip->reg_lock);
+	chip->rirb.cmds++;
+	chip->corb.buf[wp] = cpu_to_le32(val);
+	azx_writel(chip, CORBWP, wp);
+	spin_unlock_irq(&chip->reg_lock);
+
+	return 0;
+}
+
+#define ICH6_RIRB_EX_UNSOL_EV	(1<<4)
+
+/* retrieve RIRB entry - called from interrupt handler */
+static void azx_update_rirb(azx_t *chip)
+{
+	unsigned int rp, wp;
+	u32 res, res_ex;
+
+	wp = azx_readb(chip, RIRBWP);
+	if (wp == chip->rirb.wp)
+		return;
+	chip->rirb.wp = wp;
+		
+	while (chip->rirb.rp != wp) {
+		chip->rirb.rp++;
+		chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES;
+
+		rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
+		res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
+		res = le32_to_cpu(chip->rirb.buf[rp]);
+		if (res_ex & ICH6_RIRB_EX_UNSOL_EV)
+			snd_hda_queue_unsol_event(chip->bus, res, res_ex);
+		else if (chip->rirb.cmds) {
+			chip->rirb.cmds--;
+			chip->rirb.res = res;
+		}
+	}
+}
+
+/* receive a response */
+static unsigned int azx_get_response(struct hda_codec *codec)
+{
+	azx_t *chip = codec->bus->private_data;
+	int timeout = 50;
+
+	while (chip->rirb.cmds) {
+		if (! --timeout) {
+			snd_printk(KERN_ERR "azx_get_response timeout\n");
+			chip->rirb.rp = azx_readb(chip, RIRBWP);
+			chip->rirb.cmds = 0;
+			return -1;
+		}
+		msleep(1);
+	}
+	return chip->rirb.res; /* the last value */
+}
+
+#else
+/*
+ * Use the single immediate command instead of CORB/RIRB for simplicity
+ *
+ * Note: according to Intel, this is not preferred use.  The command was
+ *       intended for the BIOS only, and may get confused with unsolicited
+ *       responses.  So, we shouldn't use it for normal operation from the
+ *       driver.
+ *       I left the codes, however, for debugging/testing purposes.
+ */
+
+#define azx_alloc_cmd_io(chip)	0
+#define azx_init_cmd_io(chip)
+#define azx_free_cmd_io(chip)
+
+/* send a command */
+static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+			unsigned int verb, unsigned int para)
+{
+	azx_t *chip = codec->bus->private_data;
+	u32 val;
+	int timeout = 50;
+
+	val = (u32)(codec->addr & 0x0f) << 28;
+	val |= (u32)direct << 27;
+	val |= (u32)nid << 20;
+	val |= verb << 8;
+	val |= para;
+
+	while (timeout--) {
+		/* check ICB busy bit */
+		if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) {
+			/* Clear IRV valid bit */
+			azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_VALID);
+			azx_writel(chip, IC, val);
+			azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY);
+			return 0;
+		}
+		udelay(1);
+	}
+	snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", azx_readw(chip, IRS), val);
+	return -EIO;
+}
+
+/* receive a response */
+static unsigned int azx_get_response(struct hda_codec *codec)
+{
+	azx_t *chip = codec->bus->private_data;
+	int timeout = 50;
+
+	while (timeout--) {
+		/* check IRV busy bit */
+		if (azx_readw(chip, IRS) & ICH6_IRS_VALID)
+			return azx_readl(chip, IR);
+		udelay(1);
+	}
+	snd_printd(SFX "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS));
+	return (unsigned int)-1;
+}
+
+#define azx_update_rirb(chip)
+
+#endif /* USE_CORB_RIRB */
+
+/* reset codec link */
+static int azx_reset(azx_t *chip)
+{
+	int count;
+
+	/* reset controller */
+	azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
+
+	count = 50;
+	while (azx_readb(chip, GCTL) && --count)
+		msleep(1);
+
+	/* delay for >= 100us for codec PLL to settle per spec
+	 * Rev 0.9 section 5.5.1
+	 */
+	msleep(1);
+
+	/* Bring controller out of reset */
+	azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET);
+
+	count = 50;
+	while (! azx_readb(chip, GCTL) && --count)
+		msleep(1);
+
+	/* Brent Chartrand said to wait >= 540us for codecs to intialize */
+	msleep(1);
+
+	/* check to see if controller is ready */
+	if (! azx_readb(chip, GCTL)) {
+		snd_printd("azx_reset: controller not ready!\n");
+		return -EBUSY;
+	}
+
+	/* detect codecs */
+	if (! chip->codec_mask) {
+		chip->codec_mask = azx_readw(chip, STATESTS);
+		snd_printdd("codec_mask = 0x%x\n", chip->codec_mask);
+	}
+
+	return 0;
+}
+
+
+/*
+ * Lowlevel interface
+ */  
+
+/* enable interrupts */
+static void azx_int_enable(azx_t *chip)
+{
+	/* enable controller CIE and GIE */
+	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |
+		   ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN);
+}
+
+/* disable interrupts */
+static void azx_int_disable(azx_t *chip)
+{
+	int i;
+
+	/* disable interrupts in stream descriptor */
+	for (i = 0; i < MAX_ICH6_DEV; i++) {
+		azx_dev_t *azx_dev = &chip->azx_dev[i];
+		azx_sd_writeb(azx_dev, SD_CTL,
+			      azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK);
+	}
+
+	/* disable SIE for all streams */
+	azx_writeb(chip, INTCTL, 0);
+
+	/* disable controller CIE and GIE */
+	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &
+		   ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN));
+}
+
+/* clear interrupts */
+static void azx_int_clear(azx_t *chip)
+{
+	int i;
+
+	/* clear stream status */
+	for (i = 0; i < MAX_ICH6_DEV; i++) {
+		azx_dev_t *azx_dev = &chip->azx_dev[i];
+		azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
+	}
+
+	/* clear STATESTS */
+	azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+
+	/* clear rirb status */
+	azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
+
+	/* clear int status */
+	azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM);
+}
+
+/* start a stream */
+static void azx_stream_start(azx_t *chip, azx_dev_t *azx_dev)
+{
+	/* enable SIE */
+	azx_writeb(chip, INTCTL,
+		   azx_readb(chip, INTCTL) | (1 << azx_dev->index));
+	/* set DMA start and interrupt mask */
+	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
+		      SD_CTL_DMA_START | SD_INT_MASK);
+}
+
+/* stop a stream */
+static void azx_stream_stop(azx_t *chip, azx_dev_t *azx_dev)
+{
+	/* stop DMA */
+	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
+		      ~(SD_CTL_DMA_START | SD_INT_MASK));
+	azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+	/* disable SIE */
+	azx_writeb(chip, INTCTL,
+		   azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
+}
+
+
+/*
+ * initialize the chip
+ */
+static void azx_init_chip(azx_t *chip)
+{
+	unsigned char tcsel_reg;
+
+	/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
+	 * TCSEL == Traffic Class Select Register, which sets PCI express QOS
+	 * Ensuring these bits are 0 clears playback static on some HD Audio codecs
+	 */
+	pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, &tcsel_reg);
+	pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, tcsel_reg & 0xf8);
+
+	/* reset controller */
+	azx_reset(chip);
+
+	/* initialize interrupts */
+	azx_int_clear(chip);
+	azx_int_enable(chip);
+
+	/* initialize the codec command I/O */
+	azx_init_cmd_io(chip);
+
+#ifdef USE_POSBUF
+	/* program the position buffer */
+	azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
+	azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
+#endif
+}
+
+
+/*
+ * interrupt handler
+ */
+static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs)
+{
+	azx_t *chip = dev_id;
+	azx_dev_t *azx_dev;
+	u32 status;
+	int i;
+
+	spin_lock(&chip->reg_lock);
+
+	status = azx_readl(chip, INTSTS);
+	if (status == 0) {
+		spin_unlock(&chip->reg_lock);
+		return IRQ_NONE;
+	}
+	
+	for (i = 0; i < MAX_ICH6_DEV; i++) {
+		azx_dev = &chip->azx_dev[i];
+		if (status & azx_dev->sd_int_sta_mask) {
+			azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
+			if (azx_dev->substream && azx_dev->running) {
+				spin_unlock(&chip->reg_lock);
+				snd_pcm_period_elapsed(azx_dev->substream);
+				spin_lock(&chip->reg_lock);
+			}
+		}
+	}
+
+	/* clear rirb int */
+	status = azx_readb(chip, RIRBSTS);
+	if (status & RIRB_INT_MASK) {
+		if (status & RIRB_INT_RESPONSE)
+			azx_update_rirb(chip);
+		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
+	}
+
+#if 0
+	/* clear state status int */
+	if (azx_readb(chip, STATESTS) & 0x04)
+		azx_writeb(chip, STATESTS, 0x04);
+#endif
+	spin_unlock(&chip->reg_lock);
+	
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * set up BDL entries
+ */
+static void azx_setup_periods(azx_dev_t *azx_dev)
+{
+	u32 *bdl = azx_dev->bdl;
+	dma_addr_t dma_addr = azx_dev->substream->runtime->dma_addr;
+	int idx;
+
+	/* reset BDL address */
+	azx_sd_writel(azx_dev, SD_BDLPL, 0);
+	azx_sd_writel(azx_dev, SD_BDLPU, 0);
+
+	/* program the initial BDL entries */
+	for (idx = 0; idx < azx_dev->frags; idx++) {
+		unsigned int off = idx << 2; /* 4 dword step */
+		dma_addr_t addr = dma_addr + idx * azx_dev->fragsize;
+		/* program the address field of the BDL entry */
+		bdl[off] = cpu_to_le32((u32)addr);
+		bdl[off+1] = cpu_to_le32(upper_32bit(addr));
+
+		/* program the size field of the BDL entry */
+		bdl[off+2] = cpu_to_le32(azx_dev->fragsize);
+
+		/* program the IOC to enable interrupt when buffer completes */
+		bdl[off+3] = cpu_to_le32(0x01);
+	}
+}
+
+/*
+ * set up the SD for streaming
+ */
+static int azx_setup_controller(azx_t *chip, azx_dev_t *azx_dev)
+{
+	unsigned char val;
+	int timeout;
+
+	/* make sure the run bit is zero for SD */
+	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & ~SD_CTL_DMA_START);
+	/* reset stream */
+	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | SD_CTL_STREAM_RESET);
+	udelay(3);
+	timeout = 300;
+	while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
+	       --timeout)
+		;
+	val &= ~SD_CTL_STREAM_RESET;
+	azx_sd_writeb(azx_dev, SD_CTL, val);
+	udelay(3);
+
+	timeout = 300;
+	/* waiting for hardware to report that the stream is out of reset */
+	while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
+	       --timeout)
+		;
+
+	/* program the stream_tag */
+	azx_sd_writel(azx_dev, SD_CTL,
+		      (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK) |
+		      (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT));
+
+	/* program the length of samples in cyclic buffer */
+	azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize);
+
+	/* program the stream format */
+	/* this value needs to be the same as the one programmed */
+	azx_sd_writew(azx_dev, SD_FORMAT, azx_dev->format_val);
+
+	/* program the stream LVI (last valid index) of the BDL */
+	azx_sd_writew(azx_dev, SD_LVI, azx_dev->frags - 1);
+
+	/* program the BDL address */
+	/* lower BDL address */
+	azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl_addr);
+	/* upper BDL address */
+	azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));
+
+#ifdef USE_POSBUF
+	/* enable the position buffer */
+	if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
+		azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
+#endif
+	/* set the interrupt enable bits in the descriptor control register */
+	azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);
+
+	return 0;
+}
+
+
+/*
+ * Codec initialization
+ */
+
+static int __devinit azx_codec_create(azx_t *chip, const char *model)
+{
+	struct hda_bus_template bus_temp;
+	int c, codecs, err;
+
+	memset(&bus_temp, 0, sizeof(bus_temp));
+	bus_temp.private_data = chip;
+	bus_temp.modelname = model;
+	bus_temp.pci = chip->pci;
+	bus_temp.ops.command = azx_send_cmd;
+	bus_temp.ops.get_response = azx_get_response;
+
+	if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0)
+		return err;
+
+	codecs = 0;
+	for (c = 0; c < AZX_MAX_CODECS; c++) {
+		if (chip->codec_mask & (1 << c)) {
+			err = snd_hda_codec_new(chip->bus, c, NULL);
+			if (err < 0)
+				continue;
+			codecs++;
+		}
+	}
+	if (! codecs) {
+		snd_printk(KERN_ERR SFX "no codecs initialized\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+
+/*
+ * PCM support
+ */
+
+/* assign a stream for the PCM */
+static inline azx_dev_t *azx_assign_device(azx_t *chip, int stream)
+{
+	int dev, i;
+	dev = stream == SNDRV_PCM_STREAM_PLAYBACK ? 4 : 0;
+	for (i = 0; i < 4; i++, dev++)
+		if (! chip->azx_dev[dev].opened) {
+			chip->azx_dev[dev].opened = 1;
+			return &chip->azx_dev[dev];
+		}
+	return NULL;
+}
+
+/* release the assigned stream */
+static inline void azx_release_device(azx_dev_t *azx_dev)
+{
+	azx_dev->opened = 0;
+}
+
+static snd_pcm_hardware_t azx_pcm_hw = {
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_PAUSE |
+				 SNDRV_PCM_INFO_RESUME),
+	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_48000,
+	.rate_min =		48000,
+	.rate_max =		48000,
+	.channels_min =		2,
+	.channels_max =		2,
+	.buffer_bytes_max =	AZX_MAX_BUF_SIZE,
+	.period_bytes_min =	128,
+	.period_bytes_max =	AZX_MAX_BUF_SIZE / 2,
+	.periods_min =		2,
+	.periods_max =		AZX_MAX_FRAG,
+	.fifo_size =		0,
+};
+
+struct azx_pcm {
+	azx_t *chip;
+	struct hda_codec *codec;
+	struct hda_pcm_stream *hinfo[2];
+};
+
+static int azx_pcm_open(snd_pcm_substream_t *substream)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	azx_t *chip = apcm->chip;
+	azx_dev_t *azx_dev;
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	unsigned long flags;
+	int err;
+
+	down(&chip->open_mutex);
+	azx_dev = azx_assign_device(chip, substream->stream);
+	if (azx_dev == NULL) {
+		up(&chip->open_mutex);
+		return -EBUSY;
+	}
+	runtime->hw = azx_pcm_hw;
+	runtime->hw.channels_min = hinfo->channels_min;
+	runtime->hw.channels_max = hinfo->channels_max;
+	runtime->hw.formats = hinfo->formats;
+	runtime->hw.rates = hinfo->rates;
+	snd_pcm_limit_hw_rates(runtime);
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) {
+		azx_release_device(azx_dev);
+		up(&chip->open_mutex);
+		return err;
+	}
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	azx_dev->substream = substream;
+	azx_dev->running = 0;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	runtime->private_data = azx_dev;
+	up(&chip->open_mutex);
+	return 0;
+}
+
+static int azx_pcm_close(snd_pcm_substream_t *substream)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	azx_t *chip = apcm->chip;
+	azx_dev_t *azx_dev = get_azx_dev(substream);
+	unsigned long flags;
+
+	down(&chip->open_mutex);
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	azx_dev->substream = NULL;
+	azx_dev->running = 0;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	azx_release_device(azx_dev);
+	hinfo->ops.close(hinfo, apcm->codec, substream);
+	up(&chip->open_mutex);
+	return 0;
+}
+
+static int azx_pcm_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));
+}
+
+static int azx_pcm_hw_free(snd_pcm_substream_t *substream)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	azx_dev_t *azx_dev = get_azx_dev(substream);
+	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+
+	/* reset BDL address */
+	azx_sd_writel(azx_dev, SD_BDLPL, 0);
+	azx_sd_writel(azx_dev, SD_BDLPU, 0);
+	azx_sd_writel(azx_dev, SD_CTL, 0);
+
+	hinfo->ops.cleanup(hinfo, apcm->codec, substream);
+
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int azx_pcm_prepare(snd_pcm_substream_t *substream)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	azx_t *chip = apcm->chip;
+	azx_dev_t *azx_dev = get_azx_dev(substream);
+	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);
+	azx_dev->fragsize = snd_pcm_lib_period_bytes(substream);
+	azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize;
+	azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,
+							 runtime->channels,
+							 runtime->format,
+							 hinfo->maxbps);
+	if (! azx_dev->format_val) {
+		snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n",
+			   runtime->rate, runtime->channels, runtime->format);
+		return -EINVAL;
+	}
+
+	snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, format=0x%x\n",
+		    azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val);
+	azx_setup_periods(azx_dev);
+	azx_setup_controller(chip, azx_dev);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
+	else
+		azx_dev->fifo_size = 0;
+
+	return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag,
+				  azx_dev->format_val, substream);
+}
+
+static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+	azx_dev_t *azx_dev = get_azx_dev(substream);
+	azx_t *chip = apcm->chip;
+	int err = 0;
+
+	spin_lock(&chip->reg_lock);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_START:
+		azx_stream_start(chip, azx_dev);
+		azx_dev->running = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		azx_stream_stop(chip, azx_dev);
+		azx_dev->running = 0;
+		break;
+	default:
+		err = -EINVAL;
+	}
+	spin_unlock(&chip->reg_lock);
+	if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
+	    cmd == SNDRV_PCM_TRIGGER_STOP) {
+		int timeout = 5000;
+		while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout)
+			;
+	}
+	return err;
+}
+
+static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream)
+{
+	azx_dev_t *azx_dev = get_azx_dev(substream);
+	unsigned int pos;
+
+#ifdef USE_POSBUF
+	/* use the position buffer */
+	pos = *azx_dev->posbuf;
+#else
+	/* read LPIB */
+	pos = azx_sd_readl(azx_dev, SD_LPIB) + azx_dev->fifo_size;
+#endif
+	if (pos >= azx_dev->bufsize)
+		pos = 0;
+	return bytes_to_frames(substream->runtime, pos);
+}
+
+static snd_pcm_ops_t azx_pcm_ops = {
+	.open = azx_pcm_open,
+	.close = azx_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = azx_pcm_hw_params,
+	.hw_free = azx_pcm_hw_free,
+	.prepare = azx_pcm_prepare,
+	.trigger = azx_pcm_trigger,
+	.pointer = azx_pcm_pointer,
+};
+
+static void azx_pcm_free(snd_pcm_t *pcm)
+{
+	kfree(pcm->private_data);
+}
+
+static int __devinit create_codec_pcm(azx_t *chip, struct hda_codec *codec,
+				      struct hda_pcm *cpcm, int pcm_dev)
+{
+	int err;
+	snd_pcm_t *pcm;
+	struct azx_pcm *apcm;
+
+	snd_assert(cpcm->stream[0].substreams || cpcm->stream[1].substreams, return -EINVAL);
+	snd_assert(cpcm->name, return -EINVAL);
+
+	err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+			  cpcm->stream[0].substreams, cpcm->stream[1].substreams,
+			  &pcm);
+	if (err < 0)
+		return err;
+	strcpy(pcm->name, cpcm->name);
+	apcm = kmalloc(sizeof(*apcm), GFP_KERNEL);
+	if (apcm == NULL)
+		return -ENOMEM;
+	apcm->chip = chip;
+	apcm->codec = codec;
+	apcm->hinfo[0] = &cpcm->stream[0];
+	apcm->hinfo[1] = &cpcm->stream[1];
+	pcm->private_data = apcm;
+	pcm->private_free = azx_pcm_free;
+	if (cpcm->stream[0].substreams)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
+	if (cpcm->stream[1].substreams)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      snd_dma_pci_data(chip->pci),
+					      1024 * 64, 1024 * 128);
+	chip->pcm[pcm_dev] = pcm;
+
+	return 0;
+}
+
+static int __devinit azx_pcm_create(azx_t *chip)
+{
+	struct list_head *p;
+	struct hda_codec *codec;
+	int c, err;
+	int pcm_dev;
+
+	if ((err = snd_hda_build_pcms(chip->bus)) < 0)
+		return err;
+
+	pcm_dev = 0;
+	list_for_each(p, &chip->bus->codec_list) {
+		codec = list_entry(p, struct hda_codec, list);
+		for (c = 0; c < codec->num_pcms; c++) {
+			if (pcm_dev >= AZX_MAX_PCMS) {
+				snd_printk(KERN_ERR SFX "Too many PCMs\n");
+				return -EINVAL;
+			}
+			err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev);
+			if (err < 0)
+				return err;
+			pcm_dev++;
+		}
+	}
+	return 0;
+}
+
+/*
+ * mixer creation - all stuff is implemented in hda module
+ */
+static int __devinit azx_mixer_create(azx_t *chip)
+{
+	return snd_hda_build_controls(chip->bus);
+}
+
+
+/*
+ * initialize SD streams
+ */
+static int __devinit azx_init_stream(azx_t *chip)
+{
+	int i;
+
+	/* initialize each stream (aka device)
+	 * assign the starting bdl address to each stream (device) and initialize
+	 */
+	for (i = 0; i < MAX_ICH6_DEV; i++) {
+		unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
+		azx_dev_t *azx_dev = &chip->azx_dev[i];
+		azx_dev->bdl = (u32 *)(chip->bdl.area + off);
+		azx_dev->bdl_addr = chip->bdl.addr + off;
+#ifdef USE_POSBUF
+		azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8);
+#endif
+		/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+		azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
+		/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
+		azx_dev->sd_int_sta_mask = 1 << i;
+		/* stream tag: must be non-zero and unique */
+		azx_dev->index = i;
+		azx_dev->stream_tag = i + 1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_PM
+/*
+ * power management
+ */
+static int azx_suspend(snd_card_t *card, unsigned int state)
+{
+	azx_t *chip = card->pm_private_data;
+	int i;
+
+	for (i = 0; i < chip->pcm_devs; i++)
+		if (chip->pcm[i])
+			snd_pcm_suspend_all(chip->pcm[i]);
+	snd_hda_suspend(chip->bus, state);
+	azx_free_cmd_io(chip);
+	pci_disable_device(chip->pci);
+	return 0;
+}
+
+static int azx_resume(snd_card_t *card, unsigned int state)
+{
+	azx_t *chip = card->pm_private_data;
+
+	pci_enable_device(chip->pci);
+	pci_set_master(chip->pci);
+	azx_init_chip(chip);
+	snd_hda_resume(chip->bus, state);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+
+/*
+ * destructor
+ */
+static int azx_free(azx_t *chip)
+{
+	if (chip->remap_addr) {
+		int i;
+
+		for (i = 0; i < MAX_ICH6_DEV; i++)
+			azx_stream_stop(chip, &chip->azx_dev[i]);
+
+		/* disable interrupts */
+		azx_int_disable(chip);
+		azx_int_clear(chip);
+
+		/* disable CORB/RIRB */
+		azx_free_cmd_io(chip);
+
+		/* disable position buffer */
+		azx_writel(chip, DPLBASE, 0);
+		azx_writel(chip, DPUBASE, 0);
+
+		/* wait a little for interrupts to finish */
+		msleep(1);
+
+		iounmap(chip->remap_addr);
+	}
+
+	if (chip->irq >= 0)
+		free_irq(chip->irq, (void*)chip);
+
+	if (chip->bdl.area)
+		snd_dma_free_pages(&chip->bdl);
+	if (chip->rb.area)
+		snd_dma_free_pages(&chip->rb);
+#ifdef USE_POSBUF
+	if (chip->posbuf.area)
+		snd_dma_free_pages(&chip->posbuf);
+#endif
+	pci_release_regions(chip->pci);
+	pci_disable_device(chip->pci);
+	kfree(chip);
+
+	return 0;
+}
+
+static int azx_dev_free(snd_device_t *device)
+{
+	return azx_free(device->device_data);
+}
+
+/*
+ * constructor
+ */
+static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **rchip)
+{
+	azx_t *chip;
+	int err = 0;
+	static snd_device_ops_t ops = {
+		.dev_free = azx_dev_free,
+	};
+
+	*rchip = NULL;
+	
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+
+	chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+	
+	if (NULL == chip) {
+		snd_printk(KERN_ERR SFX "cannot allocate chip\n");
+		pci_disable_device(pci);
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&chip->reg_lock);
+	init_MUTEX(&chip->open_mutex);
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+
+	if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
+		kfree(chip);
+		pci_disable_device(pci);
+		return err;
+	}
+
+	chip->addr = pci_resource_start(pci,0);
+	chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0));
+	if (chip->remap_addr == NULL) {
+		snd_printk(KERN_ERR SFX "ioremap error\n");
+		err = -ENXIO;
+		goto errout;
+	}
+
+	if (request_irq(pci->irq, azx_interrupt, SA_INTERRUPT|SA_SHIRQ,
+			"HDA Intel", (void*)chip)) {
+		snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
+		err = -EBUSY;
+		goto errout;
+	}
+	chip->irq = pci->irq;
+
+	pci_set_master(pci);
+	synchronize_irq(chip->irq);
+
+	/* allocate memory for the BDL for each stream */
+	if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+				       PAGE_SIZE, &chip->bdl)) < 0) {
+		snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
+		goto errout;
+	}
+#ifdef USE_POSBUF
+	/* allocate memory for the position buffer */
+	if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+				       MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
+		snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
+		goto errout;
+	}
+#endif
+	/* allocate CORB/RIRB */
+	if ((err = azx_alloc_cmd_io(chip)) < 0)
+		goto errout;
+
+	/* initialize streams */
+	azx_init_stream(chip);
+
+	/* initialize chip */
+	azx_init_chip(chip);
+
+	/* codec detection */
+	if (! chip->codec_mask) {
+		snd_printk(KERN_ERR SFX "no codecs found!\n");
+		err = -ENODEV;
+		goto errout;
+	}
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) {
+		snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
+		goto errout;
+	}
+
+	*rchip = chip;
+	return 0;
+
+ errout:
+	azx_free(chip);
+	return err;
+}
+
+static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+	static int dev;
+	snd_card_t *card;
+	azx_t *chip;
+	int err = 0;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (! enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+	if (NULL == card) {
+		snd_printk(KERN_ERR SFX "Error creating card!\n");
+		return -ENOMEM;
+	}
+
+	if ((err = azx_create(card, pci, &chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	strcpy(card->driver, "HDA-Intel");
+	strcpy(card->shortname, "HDA Intel");
+	sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
+
+	/* create codec instances */
+	if ((err = azx_codec_create(chip, model[dev])) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	/* create PCM streams */
+	if ((err = azx_pcm_create(chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	/* create mixer controls */
+	if ((err = azx_mixer_create(chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	snd_card_set_pm_callback(card, azx_suspend, azx_resume, chip);
+	snd_card_set_dev(card, &pci->dev);
+
+	if ((err = snd_card_register(card)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	pci_set_drvdata(pci, card);
+	dev++;
+
+	return err;
+}
+
+static void __devexit azx_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+/* PCI IDs */
+static struct pci_device_id azx_ids[] = {
+	{ 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */
+	{ 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, azx_ids);
+
+/* pci_driver definition */
+static struct pci_driver driver = {
+	.name = "HDA Intel",
+	.id_table = azx_ids,
+	.probe = azx_probe,
+	.remove = __devexit_p(azx_remove),
+	SND_PCI_PM_CALLBACKS
+};
+
+static int __init alsa_card_azx_init(void)
+{
+	return pci_module_init(&driver);
+}
+
+static void __exit alsa_card_azx_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_azx_init)
+module_exit(alsa_card_azx_exit)
diff -Nru a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/pci/hda/hda_local.h	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,159 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * Local helper functions
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by 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.
+ */
+
+#ifndef __SOUND_HDA_LOCAL_H
+#define __SOUND_HDA_LOCAL_H
+
+/*
+ * for mixer controls
+ */
+#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19))
+#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
+	  .info = snd_hda_mixer_amp_volume_info, \
+	  .get = snd_hda_mixer_amp_volume_get, \
+	  .put = snd_hda_mixer_amp_volume_put, \
+	  .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
+#define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
+	HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
+#define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
+	HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, 3, xindex, direction)
+#define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
+	HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
+#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
+	  .info = snd_hda_mixer_amp_switch_info, \
+	  .get = snd_hda_mixer_amp_switch_get, \
+	  .put = snd_hda_mixer_amp_switch_put, \
+	  .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
+#define HDA_CODEC_MUTE_IDX(xname, xcidx, nid, xindex, direction) \
+	HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
+#define HDA_CODEC_MUTE_MONO(xname, nid, channel, xindex, direction) \
+	HDA_CODEC_MUTE_MONO_IDX(xname, 0, nid, 3, xindex, direction)
+#define HDA_CODEC_MUTE(xname, nid, xindex, direction) \
+	HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction)
+
+int snd_hda_mixer_amp_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo);
+int snd_hda_mixer_amp_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol);
+int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol);
+int snd_hda_mixer_amp_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo);
+int snd_hda_mixer_amp_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol);
+int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol);
+
+int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid);
+
+/*
+ * input MUX helper
+ */
+#define HDA_MAX_NUM_INPUTS	8
+struct hda_input_mux_item {
+	const char *label;
+	unsigned int index;
+};
+struct hda_input_mux {
+	unsigned int num_items;
+	struct hda_input_mux_item items[HDA_MAX_NUM_INPUTS];
+};
+
+int snd_hda_input_mux_info(const struct hda_input_mux *imux, snd_ctl_elem_info_t *uinfo);
+int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux,
+			  snd_ctl_elem_value_t *ucontrol, hda_nid_t nid,
+			  unsigned int *cur_val);
+
+/*
+ * Multi-channel / digital-out PCM helper
+ */
+
+enum { HDA_FRONT, HDA_REAR, HDA_CLFE, HDA_SIDE }; /* index for dac_nidx */
+enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */
+
+struct hda_multi_out {
+	int num_dacs;		/* # of DACs, must be more than 1 */
+	hda_nid_t *dac_nids;	/* DAC list */
+	hda_nid_t hp_nid;	/* optional DAC for HP, 0 when not exists */
+	hda_nid_t dig_out_nid;	/* digital out audio widget */
+	int max_channels;	/* currently supported analog channels */
+	int dig_out_used;	/* current usage of digital out (HDA_DIG_XXX) */
+};
+
+int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout);
+int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout);
+int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout,
+				  snd_pcm_substream_t *substream);
+int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout,
+				     unsigned int stream_tag,
+				     unsigned int format,
+				     snd_pcm_substream_t *substream);
+int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout);
+
+/*
+ * generic codec parser
+ */
+int snd_hda_parse_generic_codec(struct hda_codec *codec);
+
+/*
+ * generic proc interface
+ */
+#ifdef CONFIG_PROC_FS
+int snd_hda_codec_proc_new(struct hda_codec *codec);
+#else
+static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
+#endif
+
+/*
+ * Misc
+ */
+struct hda_board_config {
+	const char *modelname;
+	int config;
+	unsigned short pci_vendor;
+	unsigned short pci_device;
+};
+
+int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl);
+int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew);
+
+/*
+ * power management
+ */
+#ifdef CONFIG_PM
+int snd_hda_resume_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew);
+int snd_hda_resume_spdif_out(struct hda_codec *codec);
+#endif
+
+/*
+ * unsolicited event handler
+ */
+
+#define HDA_UNSOL_QUEUE_SIZE	64
+
+struct hda_bus_unsolicited {
+	/* ring buffer */
+	u32 queue[HDA_UNSOL_QUEUE_SIZE * 2];
+	unsigned int rp, wp;
+
+	/* workqueue */
+	struct workqueue_struct *workq;
+	struct work_struct work;
+};
+
+#endif /* __SOUND_HDA_LOCAL_H */
diff -Nru a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/pci/hda/hda_patch.h	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,14 @@
+/*
+ * HDA Patches - included by hda_codec.c
+ */
+
+/* Realtek codecs */
+extern struct hda_codec_preset snd_hda_preset_realtek[];
+/* C-Media codecs */
+extern struct hda_codec_preset snd_hda_preset_cmedia[];
+
+static const struct hda_codec_preset *hda_preset_tables[] = {
+	snd_hda_preset_realtek,
+	snd_hda_preset_cmedia,
+	NULL
+};
diff -Nru a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/pci/hda/hda_proc.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,298 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ * 
+ * Generic proc interface
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ *  This driver 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 driver 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/init.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+
+static const char *get_wid_type_name(unsigned int wid_value)
+{
+	static char *names[16] = {
+		[AC_WID_AUD_OUT] = "Audio Output",
+		[AC_WID_AUD_IN] = "Audio Input",
+		[AC_WID_AUD_MIX] = "Audio Mixer",
+		[AC_WID_AUD_SEL] = "Audio Selector",
+		[AC_WID_PIN] = "Pin Complex",
+		[AC_WID_POWER] = "Power Widget",
+		[AC_WID_VOL_KNB] = "Volume Knob Widget",
+		[AC_WID_BEEP] = "Beep Generator Widget",
+		[AC_WID_VENDOR] = "Vendor Defined Widget",
+	};
+	wid_value &= 0xf;
+	if (names[wid_value])
+		return names[wid_value];
+	else
+		return "UNKOWN Widget";
+}
+
+static void print_amp_caps(snd_info_buffer_t *buffer,
+			   struct hda_codec *codec, hda_nid_t nid, int dir)
+{
+	unsigned int caps;
+	if (dir == HDA_OUTPUT)
+		caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_OUT_CAP);
+	else
+		caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_IN_CAP);
+	if (caps == -1 || caps == 0) {
+		snd_iprintf(buffer, "N/A\n");
+		return;
+	}
+	snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, mute=%x\n",
+		    caps & AC_AMPCAP_OFFSET,
+		    (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT,
+		    (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT,
+		    (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT);
+}
+
+static void print_amp_vals(snd_info_buffer_t *buffer,
+			   struct hda_codec *codec, hda_nid_t nid,
+			   int dir, int stereo)
+{
+	unsigned int val;
+	if (stereo) {
+		val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
+					  AC_AMP_GET_LEFT |
+					 (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT :
+					  AC_AMP_GET_INPUT));
+		snd_iprintf(buffer, "0x%02x ", val);
+	}
+	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE,
+				 AC_AMP_GET_RIGHT |
+				 (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT :
+				  AC_AMP_GET_INPUT));
+	snd_iprintf(buffer, "0x%02x\n", val);
+}
+
+static void print_pcm_caps(snd_info_buffer_t *buffer,
+			   struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+	unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+	if (pcm == -1 || stream == -1) {
+		snd_iprintf(buffer, "N/A\n");
+		return;
+	}
+	snd_iprintf(buffer, "rates 0x%03x, bits 0x%02x, types 0x%x\n",
+		    pcm & AC_SUPPCM_RATES, (pcm >> 16) & 0xff, stream & 0xf);
+}
+
+static const char *get_jack_location(u32 cfg)
+{
+	static char *bases[7] = {
+		"N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
+	};
+	static unsigned char specials_idx[] = {
+		0x07, 0x08,
+		0x17, 0x18, 0x19,
+		0x37, 0x38
+	};
+	static char *specials[] = {
+		"Rear Panel", "Drive Bar",
+		"Riser", "HDMI", "ATAPI",
+		"Mobile-In", "Mobile-Out"
+	};
+	int i;
+	cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
+	if ((cfg & 0x0f) < 7)
+		return bases[cfg & 0x0f];
+	for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
+		if (cfg == specials_idx[i])
+			return specials[i];
+	}
+	return "UNKNOWN";
+}
+
+static const char *get_jack_connection(u32 cfg)
+{
+	static char *names[16] = {
+		"Unknown", "1/8", "1/4", "ATAPI",
+		"RCA", "Optical","Digital", "Analog",
+		"DIN", "XLR", "RJ11", "Comb",
+		NULL, NULL, NULL, "Other"
+	};
+	cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT;
+	if (names[cfg])
+		return names[cfg];
+	else
+		return "UNKNOWN";
+}
+
+static const char *get_jack_color(u32 cfg)
+{
+	static char *names[16] = {
+		"Unknown", "Black", "Grey", "Blue",
+		"Green", "Red", "Orange", "Yellow",
+		"Purple", "Pink", NULL, NULL,
+		NULL, NULL, "White", "Other",
+	};
+	cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT;
+	if (names[cfg])
+		return names[cfg];
+	else
+		return "UNKNOWN";
+}
+
+static void print_pin_caps(snd_info_buffer_t *buffer,
+			   struct hda_codec *codec, hda_nid_t nid)
+{
+	static char *jack_types[16] = {
+		"Line Out", "Speaker", "HP Out", "CD",
+		"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
+		"Line In", "Aux", "Mic", "Telephony",
+		"SPDIF In", "Digitial In", "Reserved", "Other"
+	};
+	static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
+	unsigned int caps;
+
+	caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+	snd_iprintf(buffer, "  Pincap 0x08%x:", caps);
+	if (caps & AC_PINCAP_IN)
+		snd_iprintf(buffer, " IN");
+	if (caps & AC_PINCAP_OUT)
+		snd_iprintf(buffer, " OUT");
+	if (caps & AC_PINCAP_HP_DRV)
+		snd_iprintf(buffer, " HP");
+	snd_iprintf(buffer, "\n");
+	caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+	snd_iprintf(buffer, "  Pin Default 0x%08x: %s at %s %s\n", caps,
+		    jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
+		    jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
+		    get_jack_location(caps));
+	snd_iprintf(buffer, "    Conn = %s, Color = %s\n",
+		    get_jack_connection(caps),
+		    get_jack_color(caps));
+}
+
+
+static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+	struct hda_codec *codec = entry->private_data;
+	char buf[32];
+	hda_nid_t nid;
+	int i, nodes;
+
+	snd_hda_get_codec_name(codec, buf, sizeof(buf));
+	snd_iprintf(buffer, "Codec: %s\n", buf);
+	snd_iprintf(buffer, "Address: %d\n", codec->addr);
+	snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
+	snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
+	snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
+	snd_iprintf(buffer, "Default PCM: ");
+	print_pcm_caps(buffer, codec, codec->afg);
+	snd_iprintf(buffer, "Default Amp-In caps: ");
+	print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
+	snd_iprintf(buffer, "Default Amp-Out caps: ");
+	print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
+
+	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
+	if (! nid || nodes < 0) {
+		snd_iprintf(buffer, "Invalid AFG subtree\n");
+		return;
+	}
+	for (i = 0; i < nodes; i++, nid++) {
+		unsigned int wid_caps = snd_hda_param_read(codec, nid,
+							   AC_PAR_AUDIO_WIDGET_CAP);
+		unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+		snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
+			    get_wid_type_name(wid_type), wid_caps);
+		if (wid_caps & AC_WCAP_STEREO)
+			snd_iprintf(buffer, " Stereo");
+		else
+			snd_iprintf(buffer, " Mono");
+		if (wid_caps & AC_WCAP_DIGITAL)
+			snd_iprintf(buffer, " Digital");
+		if (wid_caps & AC_WCAP_IN_AMP)
+			snd_iprintf(buffer, " Amp-In");
+		if (wid_caps & AC_WCAP_OUT_AMP)
+			snd_iprintf(buffer, " Amp-Out");
+		snd_iprintf(buffer, "\n");
+
+		if (wid_caps & AC_WCAP_IN_AMP) {
+			snd_iprintf(buffer, "  Amp-In caps: ");
+			print_amp_caps(buffer, codec, nid, HDA_INPUT);
+			snd_iprintf(buffer, "  Amp-In vals: ");
+			print_amp_vals(buffer, codec, nid, HDA_INPUT,
+				       wid_caps & AC_WCAP_STEREO);
+		}
+		if (wid_caps & AC_WCAP_OUT_AMP) {
+			snd_iprintf(buffer, "  Amp-Out caps: ");
+			print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
+			snd_iprintf(buffer, "  Amp-Out vals: ");
+			print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
+				       wid_caps & AC_WCAP_STEREO);
+		}
+
+		if (wid_type == AC_WID_PIN) {
+			unsigned int pinctls;
+			print_pin_caps(buffer, codec, nid);
+			pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+			snd_iprintf(buffer, "  Pin-ctls: 0x%02x:", pinctls);
+			if (pinctls & AC_PINCTL_IN_EN)
+				snd_iprintf(buffer, " IN");
+			if (pinctls & AC_PINCTL_OUT_EN)
+				snd_iprintf(buffer, " OUT");
+			if (pinctls & AC_PINCTL_HP_EN)
+				snd_iprintf(buffer, " HP");
+			snd_iprintf(buffer, "\n");
+		}
+
+		if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) &&
+		    (wid_caps & AC_WCAP_FORMAT_OVRD)) {
+			snd_iprintf(buffer, "  PCM: ");
+			print_pcm_caps(buffer, codec, nid);
+		}
+
+		if (wid_caps & AC_WCAP_CONN_LIST) {
+			hda_nid_t conn[HDA_MAX_CONNECTIONS];
+			int c, conn_len;
+			conn_len = snd_hda_get_connections(codec, nid, conn,
+							   HDA_MAX_CONNECTIONS);
+			snd_iprintf(buffer, "  Connection: %d\n", conn_len);
+			snd_iprintf(buffer, "    ");
+			for (c = 0; c < conn_len; c++)
+				snd_iprintf(buffer, " 0x%02x", conn[c]);
+			snd_iprintf(buffer, "\n");
+		}
+	}
+}
+
+/*
+ * create a proc read
+ */
+int snd_hda_codec_proc_new(struct hda_codec *codec)
+{
+	char name[32];
+	snd_info_entry_t *entry;
+	int err;
+
+	snprintf(name, sizeof(name), "codec#%d", codec->addr);
+	err = snd_card_proc_new(codec->bus->card, name, &entry);
+	if (err < 0)
+		return err;
+
+	snd_info_set_text_ops(entry, codec, 32 * 1024, print_codec_info);
+	return 0;
+}
+
diff -Nru a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/pci/hda/patch_cmedia.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,614 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for C-Media CMI9880
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ *  This driver 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 driver 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/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* board config type */
+enum {
+	CMI_MINIMAL,	/* back 3-jack */
+	CMI_MIN_FP,	/* back 3-jack + front-panel 2-jack */
+	CMI_FULL,	/* back 6-jack + front-panel 2-jack */
+	CMI_FULL_DIG,	/* back 6-jack + front-panel 2-jack + digital I/O */
+	CMI_ALLOUT,	/* back 5-jack + front-panel 2-jack + digital out */
+};
+
+struct cmi_spec {
+	int board_config;
+	unsigned int surr_switch: 1;	/* switchable line,mic */
+	unsigned int no_line_in: 1;	/* no line-in (5-jack) */
+	unsigned int front_panel: 1;	/* has front-panel 2-jack */
+
+	/* playback */
+	struct hda_multi_out multiout;
+
+	/* capture */
+	hda_nid_t *adc_nids;
+	hda_nid_t dig_in_nid;
+
+	/* capture source */
+	const struct hda_input_mux *input_mux;
+	unsigned int cur_mux[2];
+
+	/* channel mode */
+	unsigned int num_ch_modes;
+	unsigned int cur_ch_mode;
+	const struct cmi_channel_mode *channel_modes;
+
+	struct hda_pcm pcm_rec[2];	/* PCM information */
+};
+
+/*
+ * input MUX
+ */
+static int cmi_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int cmi_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+	return 0;
+}
+
+static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+				     spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
+}
+
+/*
+ * shared line-in, mic for surrounds
+ */
+
+/* 3-stack / 2 channel */
+static struct hda_verb cmi9880_ch2_init[] = {
+	/* set line-in PIN for input */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* set mic PIN for input, also enable vref */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* route front PCM (DAC1) to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	{}
+};
+
+/* 3-stack / 6 channel */
+static struct hda_verb cmi9880_ch6_init[] = {
+	/* set line-in PIN for input */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* set mic PIN for input, also enable vref */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* route front PCM (DAC1) to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	{}
+};
+
+/* 3-stack+front / 8 channel */
+static struct hda_verb cmi9880_ch8_init[] = {
+	/* set line-in PIN for input */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* set mic PIN for input, also enable vref */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* route rear-surround PCM (DAC4) to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 },
+	{}
+};
+
+struct cmi_channel_mode {
+	unsigned int channels;
+	const struct hda_verb *sequence;
+};
+
+static struct cmi_channel_mode cmi9880_channel_modes[3] = {
+	{ 2, cmi9880_ch2_init },
+	{ 6, cmi9880_ch6_init },
+	{ 8, cmi9880_ch8_init },
+};
+
+static int cmi_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+
+	snd_assert(spec->channel_modes, return -EINVAL);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = spec->num_ch_modes;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	sprintf(uinfo->value.enumerated.name, "%dch",
+		spec->channel_modes[uinfo->value.enumerated.item].channels);
+	return 0;
+}
+
+static int cmi_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_ch_mode;
+	return 0;
+}
+
+static int cmi_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+
+	snd_assert(spec->channel_modes, return -EINVAL);
+	if (ucontrol->value.enumerated.item[0] >= spec->num_ch_modes)
+		ucontrol->value.enumerated.item[0] = spec->num_ch_modes;
+	if (ucontrol->value.enumerated.item[0] == spec->cur_ch_mode &&
+	    ! codec->in_resume)
+		return 0;
+
+	spec->cur_ch_mode = ucontrol->value.enumerated.item[0];
+	snd_hda_sequence_write(codec, spec->channel_modes[spec->cur_ch_mode].sequence);
+	spec->multiout.max_channels = spec->channel_modes[spec->cur_ch_mode].channels;
+	return 1;
+}
+
+/*
+ */
+static snd_kcontrol_new_t cmi9880_basic_mixer[] = {
+	/* CMI9880 has no playback volumes! */
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = cmi_mux_enum_info,
+		.get = cmi_mux_enum_get,
+		.put = cmi_mux_enum_put,
+	},
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT),
+	{ } /* end */
+};
+
+/*
+ * shared I/O pins
+ */
+static snd_kcontrol_new_t cmi9880_ch_mode_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = cmi_ch_mode_info,
+		.get = cmi_ch_mode_get,
+		.put = cmi_ch_mode_put,
+	},
+	{ } /* end */
+};
+
+/* AUD-in selections:
+ * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20
+ */
+static struct hda_input_mux cmi9880_basic_mux = {
+	.num_items = 4,
+	.items = {
+		{ "Front Mic", 0x5 },
+		{ "Rear Mic", 0x2 },
+		{ "Line", 0x1 },
+		{ "CD", 0x7 },
+	}
+};
+
+static struct hda_input_mux cmi9880_no_line_mux = {
+	.num_items = 3,
+	.items = {
+		{ "Front Mic", 0x5 },
+		{ "Rear Mic", 0x2 },
+		{ "CD", 0x7 },
+	}
+};
+
+/* front, rear, clfe, rear_surr */
+static hda_nid_t cmi9880_dac_nids[4] = {
+	0x03, 0x04, 0x05, 0x06
+};
+/* ADC0, ADC1 */
+static hda_nid_t cmi9880_adc_nids[2] = {
+	0x08, 0x09
+};
+
+#define CMI_DIG_OUT_NID	0x07
+#define CMI_DIG_IN_NID	0x0a
+
+/*
+ */
+static struct hda_verb cmi9880_basic_init[] = {
+	/* port-D for line out (rear panel) */
+	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-E for HP out (front panel) */
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* route front PCM to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	/* port-A for surround (rear panel) */
+	{ 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-G for CLFE (rear panel) */
+	{ 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-H for side (rear panel) */
+	{ 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-C for line-in (rear panel) */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* port-B for mic-in (rear panel) with vref */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* port-F for mic-in (front panel) with vref */
+	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* CD-in */
+	{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* route front mic to ADC1/2 */
+	{ 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
+	{ 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
+	{} /* terminator */
+};
+
+static struct hda_verb cmi9880_allout_init[] = {
+	/* port-D for line out (rear panel) */
+	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-E for HP out (front panel) */
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* route front PCM to HP */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	/* port-A for side (rear panel) */
+	{ 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-G for CLFE (rear panel) */
+	{ 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-C for surround (rear panel) */
+	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+	/* port-B for mic-in (rear panel) with vref */
+	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* port-F for mic-in (front panel) with vref */
+	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* CD-in */
+	{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* route front mic to ADC1/2 */
+	{ 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },
+	{ 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },
+	{} /* terminator */
+};
+
+/*
+ */
+static int cmi9880_build_controls(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+	int err;
+
+	err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);
+	if (err < 0)
+		return err;
+	if (spec->surr_switch) {
+		err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer);
+		if (err < 0)
+			return err;
+	}
+	if (spec->multiout.dig_out_nid) {
+		err = snd_hda_create_spdif_out_ctls(codec, CMI_DIG_OUT_NID);
+		if (err < 0)
+			return err;
+	}
+	/* TODO: digital-in */
+	return 0;
+}
+
+static int cmi9880_init(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+	if (spec->board_config == CMI_ALLOUT)
+		snd_hda_sequence_write(codec, cmi9880_allout_init);
+	else
+		snd_hda_sequence_write(codec, cmi9880_basic_init);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * resume
+ */
+static int cmi9880_resume(struct hda_codec *codec, unsigned int state)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	cmi9880_init(codec);
+	snd_hda_resume_ctls(codec, cmi9880_basic_mixer);
+	if (spec->surr_switch)
+		snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer);
+	if (spec->multiout.dig_out_nid)
+		snd_hda_resume_spdif_out(codec);
+
+	return 0;
+}
+#endif
+
+/*
+ * Analog playback callbacks
+ */
+static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					unsigned int stream_tag,
+					unsigned int format,
+					snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+						format, substream);
+}
+
+static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+					  struct hda_codec *codec,
+					  snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int cmi9880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      unsigned int stream_tag,
+				      unsigned int format,
+				      snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+				   stream_tag, 0, format);
+	return 0;
+}
+
+static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      snd_pcm_substream_t *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
+	return 0;
+}
+
+
+/*
+ */
+static struct hda_pcm_stream cmi9880_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 8,
+	.nid = 0x03, /* NID to query formats and rates */
+	.ops = {
+		.open = cmi9880_playback_pcm_open,
+		.prepare = cmi9880_playback_pcm_prepare,
+		.cleanup = cmi9880_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream cmi9880_pcm_analog_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x08, /* NID to query formats and rates */
+	.ops = {
+		.prepare = cmi9880_capture_pcm_prepare,
+		.cleanup = cmi9880_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream cmi9880_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in cmi9880_build_pcms */
+	.ops = {
+		.open = cmi9880_dig_playback_pcm_open,
+		.close = cmi9880_dig_playback_pcm_close
+	},
+};
+
+static struct hda_pcm_stream cmi9880_pcm_digital_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in cmi9880_build_pcms */
+};
+
+static int cmi9880_build_pcms(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+	struct hda_pcm *info = spec->pcm_rec;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = "CMI9880";
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture;
+
+	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+		codec->num_pcms++;
+		info++;
+		info->name = "CMI9880 Digital";
+		if (spec->multiout.dig_out_nid) {
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback;
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
+		}
+		if (spec->dig_in_nid) {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture;
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
+		}
+	}
+
+	return 0;
+}
+
+static void cmi9880_free(struct hda_codec *codec)
+{
+	kfree(codec->spec);
+}
+
+/*
+ */
+
+static struct hda_board_config cmi9880_cfg_tbl[] = {
+	{ .modelname = "minimal", .config = CMI_MINIMAL },
+	{ .modelname = "min_fp", .config = CMI_MIN_FP },
+	{ .modelname = "full", .config = CMI_FULL },
+	{ .modelname = "full_dig", .config = CMI_FULL_DIG },
+	{ .modelname = "allout", .config = CMI_ALLOUT },
+	{} /* terminator */
+};
+
+static struct hda_codec_ops cmi9880_patch_ops = {
+	.build_controls = cmi9880_build_controls,
+	.build_pcms = cmi9880_build_pcms,
+	.init = cmi9880_init,
+	.free = cmi9880_free,
+#ifdef CONFIG_PM
+	.resume = cmi9880_resume,
+#endif
+};
+
+static int patch_cmi9880(struct hda_codec *codec)
+{
+	struct cmi_spec *spec;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+	spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl);
+	if (spec->board_config < 0) {
+		snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
+		spec->board_config = CMI_MINIMAL;
+	}
+
+	switch (spec->board_config) {
+	case CMI_MINIMAL:
+	case CMI_MIN_FP:
+		spec->surr_switch = 1;
+		if (spec->board_config == CMI_MINIMAL)
+			spec->num_ch_modes = 2;
+		else {
+			spec->front_panel = 1;
+			spec->num_ch_modes = 3;
+		}
+		spec->channel_modes = cmi9880_channel_modes;
+		spec->multiout.max_channels = cmi9880_channel_modes[0].channels;
+		spec->input_mux = &cmi9880_basic_mux;
+		break;
+	case CMI_FULL:
+	case CMI_FULL_DIG:
+		spec->front_panel = 1;
+		spec->multiout.max_channels = 8;
+		spec->input_mux = &cmi9880_basic_mux;
+		if (spec->board_config == CMI_FULL_DIG) {
+			spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
+			spec->dig_in_nid = CMI_DIG_IN_NID;
+		}
+		break;
+	case CMI_ALLOUT:
+		spec->front_panel = 1;
+		spec->multiout.max_channels = 8;
+		spec->no_line_in = 1;
+		spec->input_mux = &cmi9880_no_line_mux;
+		spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
+		break;
+	}
+
+	spec->multiout.num_dacs = 4;
+	spec->multiout.dac_nids = cmi9880_dac_nids;
+
+	spec->adc_nids = cmi9880_adc_nids;
+
+	codec->patch_ops = cmi9880_patch_ops;
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_cmedia[] = {
+ 	{ .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
+	{} /* terminator */
+};
diff -Nru a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sound/pci/hda/patch_realtek.c	2005-02-09 18:36:41 -08:00
@@ -0,0 +1,1174 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for ALC 260/880 codecs
+ *
+ * Copyright (c) 2004 PeiSen Hou <pshou@realtek.com.tw>
+ *                    Takashi Iwai <tiwai@suse.de>
+ *
+ *  This driver 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 driver 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/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* ALC880 board config type */
+enum {
+	ALC880_MINIMAL,
+	ALC880_3ST,
+	ALC880_3ST_DIG,
+	ALC880_5ST,
+	ALC880_5ST_DIG,
+	ALC880_W810,
+};
+
+struct alc_spec {
+	/* codec parameterization */
+	unsigned int front_panel: 1;
+
+	snd_kcontrol_new_t* mixers[2];
+	unsigned int num_mixers;
+
+	struct hda_verb *init_verbs;
+
+	char* stream_name_analog;
+	struct hda_pcm_stream *stream_analog_playback;
+	struct hda_pcm_stream *stream_analog_capture;
+
+	char* stream_name_digital;
+	struct hda_pcm_stream *stream_digital_playback;
+	struct hda_pcm_stream *stream_digital_capture;
+
+	/* playback */
+	struct hda_multi_out multiout;
+
+	/* capture */
+	unsigned int num_adc_nids;
+	hda_nid_t *adc_nids;
+	hda_nid_t dig_in_nid;
+
+	/* capture source */
+	const struct hda_input_mux *input_mux;
+	unsigned int cur_mux[3];
+
+	/* channel model */
+	const struct alc_channel_mode *channel_mode;
+	int num_channel_mode;
+
+	/* PCM information */
+	struct hda_pcm pcm_rec[2];
+};
+
+/* DAC/ADC assignment */
+
+static hda_nid_t alc880_dac_nids[4] = {
+	/* front, rear, clfe, rear_surr */
+	0x02, 0x05, 0x04, 0x03
+};
+
+static hda_nid_t alc880_w810_dac_nids[3] = {
+	/* front, rear/surround, clfe */
+	0x02, 0x03, 0x04
+};
+
+static hda_nid_t alc880_adc_nids[3] = {
+	/* ADC0-2 */
+	0x07, 0x08, 0x09,
+};
+
+#define ALC880_DIGOUT_NID	0x06
+#define ALC880_DIGIN_NID	0x0a
+
+static hda_nid_t alc260_dac_nids[1] = {
+	/* front */
+	0x02,
+};
+
+static hda_nid_t alc260_adc_nids[2] = {
+	/* ADC0-1 */
+	0x04, 0x05,
+};
+
+#define ALC260_DIGOUT_NID	0x03
+#define ALC260_DIGIN_NID	0x06
+
+static struct hda_input_mux alc880_capture_source = {
+	.num_items = 4,
+	.items = {
+		{ "Mic-1", 0x0 },
+		{ "Mic-2", 0x3 },
+		{ "Line", 0x2 },
+		{ "CD", 0x4 },
+	},
+};
+
+static struct hda_input_mux alc260_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Line", 0x2 },
+		{ "CD", 0x4 },
+	},
+};
+
+/*
+ * input MUX handling
+ */
+static int alc_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->input_mux, uinfo);
+}
+
+static int alc_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+	return 0;
+}
+
+static int alc_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+				     spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
+}
+
+/*
+ * channel mode setting
+ */
+struct alc_channel_mode {
+	int channels;
+	const struct hda_verb *sequence;
+};
+
+
+/*
+ * channel source setting (2/6 channel selection for 3-stack)
+ */
+
+/*
+ * set the path ways for 2 channel output
+ * need to set the codec line out and mic 1 pin widgets to inputs
+ */
+static struct hda_verb alc880_threestack_ch2_init[] = {
+	/* set pin widget 1Ah (line in) for input */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* set pin widget 18h (mic1) for input, for mic also enable the vref */
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	/* mute the output for Line In PW */
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+	/* mute for Mic1 PW */
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+	{ } /* end */
+};
+
+/*
+ * 6ch mode
+ * need to set the codec line out and mic 1 pin widgets to outputs
+ */
+static struct hda_verb alc880_threestack_ch6_init[] = {
+	/* set pin widget 1Ah (line in) for output */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* set pin widget 18h (mic1) for output */
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* unmute the output for Line In PW */
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
+	/* unmute for Mic1 PW */
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
+	/* for rear channel output using Line In 1
+	 * set select widget connection (nid = 0x12) - to summer node
+	 * for rear NID = 0x0f...offset 3 in connection list
+	 */
+	{ 0x12, AC_VERB_SET_CONNECT_SEL, 0x3 },
+	/* for Mic1 - retask for center/lfe */
+	/* set select widget connection (nid = 0x10) - to summer node for
+	 * front CLFE NID = 0x0e...offset 2 in connection list
+	 */
+	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x2 },
+	{ } /* end */
+};
+
+static struct alc_channel_mode alc880_threestack_modes[2] = {
+	{ 2, alc880_threestack_ch2_init },
+	{ 6, alc880_threestack_ch6_init },
+};
+
+
+/*
+ * channel source setting (6/8 channel selection for 5-stack)
+ */
+
+/* set the path ways for 6 channel output
+ * need to set the codec line out and mic 1 pin widgets to inputs
+ */
+static struct hda_verb alc880_fivestack_ch6_init[] = {
+	/* set pin widget 1Ah (line in) for input */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+	/* mute the output for Line In PW */
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
+	{ } /* end */
+};
+
+/* need to set the codec line out and mic 1 pin widgets to outputs */
+static struct hda_verb alc880_fivestack_ch8_init[] = {
+	/* set pin widget 1Ah (line in) for output */
+	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	/* unmute the output for Line In PW */
+	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
+	/* output for surround channel output using Line In 1 */
+	/* set select widget connection (nid = 0x12) - to summer node
+	 * for surr_rear NID = 0x0d...offset 1 in connection list
+	 */
+	{ 0x12, AC_VERB_SET_CONNECT_SEL, 0x1 },
+	{ } /* end */
+};
+
+static struct alc_channel_mode alc880_fivestack_modes[2] = {
+	{ 6, alc880_fivestack_ch6_init },
+	{ 8, alc880_fivestack_ch8_init },
+};
+
+/*
+ * channel source setting for W810 system
+ *
+ * W810 has rear IO for:
+ * Front (DAC 02)
+ * Surround (DAC 03)
+ * Center/LFE (DAC 04)
+ * Digital out (06)
+ *
+ * The system also has a pair of internal speakers, and a headphone jack.
+ * These are both connected to Line2 on the codec, hence to DAC 02.
+ * 
+ * There is a variable resistor to control the speaker or headphone
+ * volume. This is a hardware-only device without a software API.
+ *
+ * Plugging headphones in will disable the internal speakers. This is
+ * implemented in hardware, not via the driver using jack sense. In
+ * a similar fashion, plugging into the rear socket marked "front" will
+ * disable both the speakers and headphones.
+ *
+ * For input, there's a microphone jack, and an "audio in" jack.
+ * These may not do anything useful with this driver yet, because I
+ * haven't setup any initialization verbs for these yet...
+ */
+
+static struct alc_channel_mode alc880_w810_modes[1] = {
+	{ 6, NULL }
+};
+
+/*
+ */
+static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+
+	snd_assert(spec->channel_mode, return -ENXIO);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item >= 2)
+		uinfo->value.enumerated.item = 1;
+	sprintf(uinfo->value.enumerated.name, "%dch",
+		spec->channel_mode[uinfo->value.enumerated.item].channels);
+	return 0;
+}
+
+static int alc880_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+
+	snd_assert(spec->channel_mode, return -ENXIO);
+	ucontrol->value.enumerated.item[0] =
+		(spec->multiout.max_channels == spec->channel_mode[0].channels) ? 0 : 1;
+	return 0;
+}
+
+static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	int mode;
+
+	snd_assert(spec->channel_mode, return -ENXIO);
+	mode = ucontrol->value.enumerated.item[0] ? 1 : 0;
+	if (spec->multiout.max_channels == spec->channel_mode[mode].channels &&
+	    ! codec->in_resume)
+		return 0;
+
+	/* change the current channel setting */
+	spec->multiout.max_channels = spec->channel_mode[mode].channels;
+	if (spec->channel_mode[mode].sequence)
+		snd_hda_sequence_write(codec, spec->channel_mode[mode].sequence);
+
+	return 1;
+}
+
+
+/*
+ */
+
+static snd_kcontrol_new_t alc880_base_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x18, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x18, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic-2 Playback Volume", 0x0b, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic-2 Playback Switch", 0x0b, 0x3, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = alc880_ch_mode_info,
+		.get = alc880_ch_mode_get,
+		.put = alc880_ch_mode_put,
+	},
+	{ } /* end */
+};
+
+static snd_kcontrol_new_t alc880_side_mixer[] = {
+	HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Side Playback Switch", 0x19, 0x0, HDA_OUTPUT),
+	{ } /* end */
+};
+
+static snd_kcontrol_new_t alc880_w810_base_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 3,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+/*
+ */
+static int alc_build_controls(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int err;
+	int i;
+
+	for (i = 0; i < spec->num_mixers; i++) {
+		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+		if (err < 0)
+			return err;
+	}
+
+	if (spec->multiout.dig_out_nid) {
+		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/*
+ * initialize the codec volumes, etc
+ */
+
+static struct hda_verb alc880_init_verbs_three_stack[] = {
+	/* Line In pin widget for input */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* CD pin widget for input */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* Mic1 (rear panel) pin widget for input and vref at 80% */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* Mic2 (front panel) pin widget for input and vref at 80% */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* unmute amp left and right */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+	/* set connection select to line in (default select for this ADC) */
+	{0x07, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* unmute front mixer amp left (volume = 0) */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* unmute rear mixer amp left and right (volume = 0) */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* unmute rear mixer amp left and right (volume = 0) */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+
+	/* using rear surround as the path for headphone output */
+	/* unmute rear surround mixer amp left and right (volume = 0) */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* PASD 3 stack boards use the Mic 2 as the headphone output */
+	/* need to program the selector associated with the Mic 2 pin widget to
+	 * surround path (index 0x01) for headphone output */
+	{0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* need to retask the Mic 2 pin widget to output */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer widget(nid=0x0B)
+	 * to support the input path of analog loopback
+	 * Note: PASD motherboards uses the Line In 2 as the input for front panel
+	 * mic (mic 2)
+	 */
+	/* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
+	/* unmute CD */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+	/* unmute Line In */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+	/* unmute Mic 1 */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	/* unmute Line In 2 (for PASD boards Mic 2) */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+
+	/* Unmute input amps for the line out paths to support the output path of
+	 * analog loopback
+	 * the mixers on the output path has 2 inputs, one from the DAC and one
+	 * from the mixer
+	 */
+	/* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
+	/* Unmute Front out path */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute Surround (used as HP) out path */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute C/LFE out path */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute rear Surround out path */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+	{ }
+};
+
+static struct hda_verb alc880_init_verbs_five_stack[] = {
+	/* Line In pin widget for input */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* CD pin widget for input */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* Mic1 (rear panel) pin widget for input and vref at 80% */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* Mic2 (front panel) pin widget for input and vref at 80% */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* unmute amp left and right */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+	/* set connection select to line in (default select for this ADC) */
+	{0x07, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* unmute front mixer amp left and right (volume = 0) */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* five rear and clfe */
+	/* unmute rear mixer amp left and right (volume = 0)  */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* unmute clfe mixer amp left and right (volume = 0) */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+
+	/* using rear surround as the path for headphone output */
+	/* unmute rear surround mixer amp left and right (volume = 0) */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* PASD 3 stack boards use the Mic 2 as the headphone output */
+	/* need to program the selector associated with the Mic 2 pin widget to
+	 * surround path (index 0x01) for headphone output
+	 */
+	{0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* need to retask the Mic 2 pin widget to output */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer
+	 * widget(nid=0x0B) to support the input path of analog loopback
+	 */
+	/* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */
+	/* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/
+	/* unmute CD */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+	/* unmute Line In */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+	/* unmute Mic 1 */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	/* unmute Line In 2 (for PASD boards Mic 2) */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+
+	/* Unmute input amps for the line out paths to support the output path of
+	 * analog loopback
+	 * the mixers on the output path has 2 inputs, one from the DAC and
+	 * one from the mixer
+	 */
+	/* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
+	/* Unmute Front out path */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute Surround (used as HP) out path */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute C/LFE out path */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute rear Surround out path */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+
+	{ }
+};
+
+static struct hda_verb alc880_w810_init_verbs[] = {
+	/* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+
+	/* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+
+	/* front channel selector/amp: output 0: unmuted, max volume */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+
+	/* front out pin: muted, (no volume selection)  */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+
+	/* front out pin: NOT headphone enable, out enable, vref disabled */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+	/* surround channel selector/amp: input 0: DAC: unmuted, (no volume selection) */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+
+	/* surround channel selector/amp: input 1: capture mix: muted, (no volume selection) */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+
+	/* surround channel selector/amp: output 0: unmuted, max volume */
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+
+	/* surround out pin: muted, (no volume selection)  */
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+
+	/* surround out pin: NOT headphone enable, out enable, vref disabled */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+	/* c/lfe channel selector/amp: input 0: DAC: unmuted, (no volume selection) */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+
+	/* c/lfe channel selector/amp: input 1: capture mix: muted, (no volume selection) */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+
+	/* c/lfe channel selector/amp: output 0: unmuted, max volume */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+
+	/* c/lfe out pin: muted, (no volume selection)  */
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+
+	/* c/lfe out pin: NOT headphone enable, out enable, vref disabled */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+	/* hphone/speaker input selector: front DAC */
+	{0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
+
+	/* hphone/speaker out pin: muted, (no volume selection)  */
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+
+	/* hphone/speaker out pin: NOT headphone enable, out enable, vref disabled */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+	{ }
+};
+
+static int alc_init(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	snd_hda_sequence_write(codec, spec->init_verbs);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * resume
+ */
+static int alc_resume(struct hda_codec *codec, unsigned int state)
+{
+	struct alc_spec *spec = codec->spec;
+	int i;
+
+	alc_init(codec);
+	for (i = 0; i < spec->num_mixers; i++) {
+		snd_hda_resume_ctls(codec, spec->mixers[i]);
+	}
+	if (spec->multiout.dig_out_nid)
+		snd_hda_resume_spdif_out(codec);
+
+	return 0;
+}
+#endif
+
+/*
+ * Analog playback callbacks
+ */
+static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
+				    struct hda_codec *codec,
+				    snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+}
+
+static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       unsigned int stream_tag,
+				       unsigned int format,
+				       snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+						format, substream);
+}
+
+static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+}
+
+/*
+ * Digital out
+ */
+static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      unsigned int stream_tag,
+				      unsigned int format,
+				      snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+				   stream_tag, 0, format);
+	return 0;
+}
+
+static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      snd_pcm_substream_t *substream)
+{
+	struct alc_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
+	return 0;
+}
+
+
+/*
+ */
+static struct hda_pcm_stream alc880_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 8,
+	.nid = 0x02, /* NID to query formats and rates */
+	.ops = {
+		.open = alc880_playback_pcm_open,
+		.prepare = alc880_playback_pcm_prepare,
+		.cleanup = alc880_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream alc880_pcm_analog_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x07, /* NID to query formats and rates */
+	.ops = {
+		.prepare = alc880_capture_pcm_prepare,
+		.cleanup = alc880_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream alc880_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+	.ops = {
+		.open = alc880_dig_playback_pcm_open,
+		.close = alc880_dig_playback_pcm_close
+	},
+};
+
+static struct hda_pcm_stream alc880_pcm_digital_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+};
+
+static int alc_build_pcms(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	struct hda_pcm *info = spec->pcm_rec;
+	int i;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = spec->stream_name_analog;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
+	info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
+
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
+	for (i = 0; i < spec->num_channel_mode; i++) {
+		if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
+		    info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
+		}
+	}
+
+	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+		codec->num_pcms++;
+		info++;
+		info->name = spec->stream_name_digital;
+		if (spec->multiout.dig_out_nid) {
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
+		}
+		if (spec->dig_in_nid) {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
+		}
+	}
+
+	return 0;
+}
+
+static void alc_free(struct hda_codec *codec)
+{
+	kfree(codec->spec);
+}
+
+/*
+ */
+static struct hda_codec_ops alc_patch_ops = {
+	.build_controls = alc_build_controls,
+	.build_pcms = alc_build_pcms,
+	.init = alc_init,
+	.free = alc_free,
+#ifdef CONFIG_PM
+	.resume = alc_resume,
+#endif
+};
+
+/*
+ */
+
+static struct hda_board_config alc880_cfg_tbl[] = {
+	/* Back 3 jack, front 2 jack */
+	{ .modelname = "3stack", .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe200, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe201, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe202, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe203, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe204, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe205, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe206, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe207, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe208, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe209, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20a, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20b, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20c, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20d, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20e, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe20f, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe210, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe211, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe214, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe302, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe303, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe304, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe306, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe307, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe404, .config = ALC880_3ST },
+	{ .pci_vendor = 0x8086, .pci_device = 0xa101, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x3031, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4036, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4037, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4038, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4040, .config = ALC880_3ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4041, .config = ALC880_3ST },
+
+	/* Back 3 jack, front 2 jack (Internal add Aux-In) */
+	{ .pci_vendor = 0x1025, .pci_device = 0xe310, .config = ALC880_3ST },
+
+	/* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
+	{ .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe308, .config = ALC880_3ST_DIG },
+
+	/* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
+	{ .pci_vendor = 0x8086, .pci_device = 0xe305, .config = ALC880_3ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xd402, .config = ALC880_3ST_DIG },
+	{ .pci_vendor = 0x1025, .pci_device = 0xe309, .config = ALC880_3ST_DIG },
+
+	/* Back 5 jack, front 2 jack */
+	{ .modelname = "5stack", .config = ALC880_5ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x3033, .config = ALC880_5ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x4039, .config = ALC880_5ST },
+	{ .pci_vendor = 0x107b, .pci_device = 0x3032, .config = ALC880_5ST },
+	{ .pci_vendor = 0x103c, .pci_device = 0x2a09, .config = ALC880_5ST },
+
+	/* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
+	{ .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe224, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe400, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe401, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xe402, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xd400, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xd401, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x8086, .pci_device = 0xa100, .config = ALC880_5ST_DIG },
+	{ .pci_vendor = 0x1565, .pci_device = 0x8202, .config = ALC880_5ST_DIG },
+
+	{ .modelname = "w810", .config = ALC880_W810 },
+	{ .pci_vendor = 0x161f, .pci_device = 0x203d, .config = ALC880_W810 },
+
+	{}
+};
+
+static int patch_alc880(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int board_config;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
+	if (board_config < 0) {
+		snd_printd(KERN_INFO "hda_codec: Unknown model for ALC880\n");
+		board_config = ALC880_MINIMAL;
+	}
+
+	switch (board_config) {
+	case ALC880_W810:
+		spec->mixers[spec->num_mixers] = alc880_w810_base_mixer;
+		spec->num_mixers++;
+		break;
+	default:
+		spec->mixers[spec->num_mixers] = alc880_base_mixer;
+		spec->num_mixers++;
+		break;
+	}
+
+	switch (board_config) {
+	case ALC880_3ST_DIG:
+	case ALC880_5ST_DIG:
+	case ALC880_W810:
+		spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
+		break;
+	default:
+		break;
+	}
+
+	switch (board_config) {
+	case ALC880_3ST:
+	case ALC880_3ST_DIG:
+	case ALC880_5ST:
+	case ALC880_5ST_DIG:
+	case ALC880_W810:
+		spec->front_panel = 1;
+		break;
+	default:
+		break;
+	}
+
+	switch (board_config) {
+	case ALC880_5ST:
+	case ALC880_5ST_DIG:
+		spec->mixers[spec->num_mixers] = alc880_side_mixer;
+		spec->num_mixers++;
+		spec->init_verbs = alc880_init_verbs_five_stack;
+		spec->channel_mode = alc880_fivestack_modes;
+		spec->num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes);
+		break;
+	case ALC880_W810:
+		spec->init_verbs = alc880_w810_init_verbs;
+		spec->channel_mode = alc880_w810_modes;
+		spec->num_channel_mode = ARRAY_SIZE(alc880_w810_modes);
+		break;
+	default:
+		spec->init_verbs = alc880_init_verbs_three_stack;
+		spec->channel_mode = alc880_threestack_modes;
+		spec->num_channel_mode = ARRAY_SIZE(alc880_threestack_modes);
+		break;
+	}
+
+	spec->stream_name_analog = "ALC880 Analog";
+	spec->stream_analog_playback = &alc880_pcm_analog_playback;
+	spec->stream_analog_capture = &alc880_pcm_analog_capture;
+
+	spec->stream_name_digital = "ALC880 Digital";
+	spec->stream_digital_playback = &alc880_pcm_digital_playback;
+	spec->stream_digital_capture = &alc880_pcm_digital_capture;
+
+	spec->multiout.max_channels = spec->channel_mode[0].channels;
+
+	switch (board_config) {
+	case ALC880_W810:
+		spec->multiout.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids);
+		spec->multiout.dac_nids = alc880_w810_dac_nids;
+		// No dedicated headphone socket - it's shared with built-in speakers.
+		break;
+	default:
+		spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids);
+		spec->multiout.dac_nids = alc880_dac_nids;
+		spec->multiout.hp_nid = 0x03; /* rear-surround NID */
+		break;
+	}
+
+	spec->input_mux = &alc880_capture_source;
+	spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
+	spec->adc_nids = alc880_adc_nids;
+
+	codec->patch_ops = alc_patch_ops;
+
+	return 0;
+}
+
+/*
+ * ALC260 support
+ */
+
+/*
+ * This is just place-holder, so there's something for alc_build_pcms to look
+ * at when it calculates the maximum number of channels. ALC260 has no mixer
+ * element which allows changing the channel mode, so the verb list is
+ * never used.
+ */
+static struct alc_channel_mode alc260_modes[1] = {
+	{ 2, 0 },
+};
+
+snd_kcontrol_new_t alc260_base_mixer[] = {
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_verb alc260_init_verbs[] = {
+	/* Line In pin widget for input */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* CD pin widget for input */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	/* Mic1 (rear panel) pin widget for input and vref at 80% */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* Mic2 (front panel) pin widget for input and vref at 80% */
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	/* unmute amp left and right */
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+	/* set connection select to line in (default select for this ADC) */
+	{0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* unmute Line-Out mixer amp left and right (volume = 0) */
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* unmute HP mixer amp left and right (volume = 0) */
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* mute pin widget amp left and right (no gain on this amp) */
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
+	/* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
+	/* unmute CD */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
+	/* unmute Line In */
+	{0x07,  AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+	/* unmute Mic */
+	{0x07,  AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	/* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
+	/* Unmute Front out path */
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	/* Unmute Headphone out path */
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{ }
+};
+
+static struct hda_pcm_stream alc260_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x2,
+};
+
+static struct hda_pcm_stream alc260_pcm_analog_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x4,
+};
+
+static int patch_alc260(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	spec->mixers[spec->num_mixers] = alc260_base_mixer;
+	spec->num_mixers++;
+
+	spec->init_verbs = alc260_init_verbs;
+	spec->channel_mode = alc260_modes;
+	spec->num_channel_mode = ARRAY_SIZE(alc260_modes);
+
+	spec->stream_name_analog = "ALC260 Analog";
+	spec->stream_analog_playback = &alc260_pcm_analog_playback;
+	spec->stream_analog_capture = &alc260_pcm_analog_capture;
+
+	spec->multiout.max_channels = spec->channel_mode[0].channels;
+	spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids);
+	spec->multiout.dac_nids = alc260_dac_nids;
+
+	spec->input_mux = &alc260_capture_source;
+	spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
+	spec->adc_nids = alc260_adc_nids;
+
+	codec->patch_ops = alc_patch_ops;
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_realtek[] = {
+ 	{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
+	{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
+	{} /* terminator */
+};
diff -Nru a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c
--- a/sound/pci/ice1712/vt1720_mobo.c	2005-02-09 18:36:40 -08:00
+++ b/sound/pci/ice1712/vt1720_mobo.c	2005-02-09 18:36:40 -08:00
@@ -101,6 +101,15 @@
 		.eeprom_size = sizeof(k8x800_eeprom),
 		.eeprom_data = k8x800_eeprom,
 	},
+	{
+		.subvendor = VT1720_SUBDEVICE_9CJS,
+		.name = "Chaintech 9CJS",
+		/* identical with k8x800 */
+		.chip_init = k8x800_init,
+		.build_controls = k8x800_add_controls,
+		.eeprom_size = sizeof(k8x800_eeprom),
+		.eeprom_data = k8x800_eeprom,
+	},
 	{ } /* terminator */
 };
 
diff -Nru a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h
--- a/sound/pci/ice1712/vt1720_mobo.h	2005-02-09 18:36:41 -08:00
+++ b/sound/pci/ice1712/vt1720_mobo.h	2005-02-09 18:36:41 -08:00
@@ -26,11 +26,13 @@
 
 #define VT1720_MOBO_DEVICE_DESC        "{Albatron,K8X800 Pro II},"\
 				       "{Chaintech,ZNF3-150},"\
-				       "{Chaintech,ZNF3-250},"
+				       "{Chaintech,ZNF3-250},"\
+				       "{Chaintech,9CJS},"
 
 #define VT1720_SUBDEVICE_K8X800		0xf217052c
 #define VT1720_SUBDEVICE_ZNF3_150	0x0f2741f6
 #define VT1720_SUBDEVICE_ZNF3_250	0x0f2745f6
+#define VT1720_SUBDEVICE_9CJS		0x0f272327
 
 extern struct snd_ice1712_card_info  snd_vt1720_mobo_cards[];
 
diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
--- a/sound/pci/intel8x0.c	2005-02-09 18:36:41 -08:00
+++ b/sound/pci/intel8x0.c	2005-02-09 18:36:41 -08:00
@@ -53,6 +53,7 @@
 		"{Intel,82801DB-ICH4},"
 		"{Intel,ICH5},"
 		"{Intel,ICH6},"
+		"{Intel,ICH7},"
 		"{Intel,6300ESB},"
 		"{Intel,MX440},"
 		"{SiS,SI7012},"
@@ -120,6 +121,9 @@
 #ifndef PCI_DEVICE_ID_INTEL_ICH6_3
 #define PCI_DEVICE_ID_INTEL_ICH6_3	0x266e
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH7_20
+#define PCI_DEVICE_ID_INTEL_ICH7_20	0x27de
+#endif
 #ifndef PCI_DEVICE_ID_SI_7012
 #define PCI_DEVICE_ID_SI_7012		0x7012
 #endif
@@ -438,6 +442,7 @@
 	{ 0x8086, 0x24d5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH5 */
 	{ 0x8086, 0x25a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB */
 	{ 0x8086, 0x266e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH6 */
+	{ 0x8086, 0x27de, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH7 */
 	{ 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 440MX */
 	{ 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },	/* SI7012 */
 	{ 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },	/* NFORCE */
@@ -1780,18 +1785,24 @@
 	},
 	{
 		.vendor = 0x103c,
-		.device = 0x129d,
-		.name = "HP xw8000",
-		.type = AC97_TUNE_HP_ONLY
+		.device = 0x088c,
+		.name = "HP nc8000",
+		.type = AC97_TUNE_MUTE_LED
 	},
 	{
 		.vendor = 0x103c,
 		.device = 0x0890,
-		.name = "HP NC6000",
+		.name = "HP nc6000",
 		.type = AC97_TUNE_MUTE_LED
 	},
 	{
 		.vendor = 0x103c,
+		.device = 0x129d,
+		.name = "HP xw8000",
+		.type = AC97_TUNE_HP_ONLY
+	},
+	{
+		.vendor = 0x103c,
 		.device = 0x12f1,
 		.name = "HP xw8200",	/* AD1981B*/
 		.type = AC97_TUNE_HP_ONLY
@@ -2703,6 +2714,7 @@
 	{ PCI_DEVICE_ID_INTEL_ICH5, "Intel ICH5" },
 	{ PCI_DEVICE_ID_INTEL_ESB_5, "Intel 6300ESB" },
 	{ PCI_DEVICE_ID_INTEL_ICH6_3, "Intel ICH6" },
+	{ PCI_DEVICE_ID_INTEL_ICH7_20, "Intel ICH7" },
 	{ PCI_DEVICE_ID_SI_7012, "SiS SI7012" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" },
diff -Nru a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
--- a/sound/pci/rme9652/hdsp.c	2005-02-09 18:36:41 -08:00
+++ b/sound/pci/rme9652/hdsp.c	2005-02-09 18:36:41 -08:00
@@ -4958,7 +4958,7 @@
 #ifdef SNDRV_BIG_ENDIAN
 	{
 		int i;
-		u32 *src = (void *)fw->data;
+		u32 *src = (u32*)fw->data;
 		for (i = 0; i < ARRAY_SIZE(hdsp->firmware_cache); i++, src++)
 			hdsp->firmware_cache[i] = ((*src & 0x000000ff) << 16) |
 				((*src & 0x0000ff00) << 8)  |
diff -Nru a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
--- a/sound/pci/vx222/vx222_ops.c	2005-02-09 18:36:40 -08:00
+++ b/sound/pci/vx222/vx222_ops.c	2005-02-09 18:36:40 -08:00
@@ -22,6 +22,7 @@
 
 #include <sound/driver.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/firmware.h>
 #include <sound/core.h>
 #include <sound/control.h>
diff -Nru a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
--- a/sound/pcmcia/vx/vxp_ops.c	2005-02-09 18:36:41 -08:00
+++ b/sound/pcmcia/vx/vxp_ops.c	2005-02-09 18:36:41 -08:00
@@ -22,6 +22,7 @@
 
 #include <sound/driver.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/firmware.h>
 #include <sound/core.h>
 #include <asm/io.h>
diff -Nru a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
--- a/sound/usb/usbaudio.c	2005-02-09 18:36:41 -08:00
+++ b/sound/usb/usbaudio.c	2005-02-09 18:36:41 -08:00
@@ -2980,6 +2980,8 @@
 		return create_ua700_ua25_quirk(chip, iface);
 	case QUIRK_AUDIO_EDIROL_UA1000:
 		return create_ua1000_quirk(chip, iface);
+	case QUIRK_IGNORE_INTERFACE:
+		return 0;
 	default:
 		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
 		return -ENXIO;
diff -Nru a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
--- a/sound/usb/usbaudio.h	2005-02-09 18:36:41 -08:00
+++ b/sound/usb/usbaudio.h	2005-02-09 18:36:41 -08:00
@@ -157,6 +157,7 @@
 #define QUIRK_MIDI_STANDARD_INTERFACE	6
 #define QUIRK_AUDIO_EDIROL_UA700_UA25	7
 #define QUIRK_AUDIO_EDIROL_UA1000	8
+#define QUIRK_IGNORE_INTERFACE		9
 
 typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
 typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
@@ -189,6 +190,8 @@
 /* for QUIRK_AUDIO/MIDI_STANDARD_INTERFACE, data is NULL */
 
 /* for QUIRK_AUDIO_EDIROL_UA700_UA25/UA1000, data is NULL */
+
+/* for QUIRK_IGNORE_INTERFACE, data is null */
 
 /*
  */
diff -Nru a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
--- a/sound/usb/usbquirks.h	2005-02-09 18:36:41 -08:00
+++ b/sound/usb/usbquirks.h	2005-02-09 18:36:41 -08:00
@@ -72,6 +72,8 @@
 YAMAHA_DEVICE(0x1008, "UX96"),
 YAMAHA_DEVICE(0x1009, "UX16"),
 YAMAHA_INTERFACE(0x100a, 3, "EOS BX"),
+YAMAHA_DEVICE(0x100c, "UC-MX"),
+YAMAHA_DEVICE(0x100d, "UC-KX"),
 YAMAHA_DEVICE(0x100e, "S08"),
 YAMAHA_DEVICE(0x100f, "CLP-150"),
 YAMAHA_DEVICE(0x1010, "CLP-170"),
@@ -86,6 +88,7 @@
 YAMAHA_DEVICE(0x101a, "CVP-210"),
 YAMAHA_DEVICE(0x101b, "PSR-1100"),
 YAMAHA_DEVICE(0x101c, "PSR-2100"),
+YAMAHA_DEVICE(0x101d, "CLP-175"),
 YAMAHA_DEVICE(0x101e, "PSR-K1"),
 YAMAHA_DEVICE(0x1020, "EZ-250i"),
 YAMAHA_DEVICE(0x1021, "MOTIF ES 6"),
@@ -125,9 +128,12 @@
 YAMAHA_DEVICE(0x5006, "NHB32-C"),
 YAMAHA_DEVICE(0x5007, "DM1000"),
 YAMAHA_DEVICE(0x5008, "01V96"),
+YAMAHA_DEVICE(0x5009, "SPX2000"),
 YAMAHA_DEVICE(0x500a, "PM5D"),
 YAMAHA_DEVICE(0x500b, "DME64N"),
 YAMAHA_DEVICE(0x500c, "DME24N"),
+YAMAHA_DEVICE(0x500d, NULL),
+YAMAHA_DEVICE(0x500e, NULL),
 YAMAHA_DEVICE(0x7000, "DTX"),
 YAMAHA_DEVICE(0x7010, "UB99"),
 #undef YAMAHA_DEVICE
@@ -876,6 +882,22 @@
 			 * but captured samples are big-endian (see usbaudio.c).
 			 */
 			{
+				.ifnum = 0,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
 				.ifnum = 4,
 				.type = QUIRK_AUDIO_STANDARD_INTERFACE
 			},
@@ -884,6 +906,10 @@
 				.type = QUIRK_AUDIO_STANDARD_INTERFACE
 			},
 			{
+				.ifnum = 6,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
 				.ifnum = 7,
 				.type = QUIRK_AUDIO_STANDARD_INTERFACE
 			},
@@ -936,11 +962,56 @@
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "M-Audio",
 		.product_name = "OmniStudio",
-		.ifnum = 9,
-		.type = QUIRK_MIDI_MIDIMAN,
-		.data = & (const snd_usb_midi_endpoint_info_t) {
-			.out_cables = 0x0001,
-			.in_cables  = 0x0001
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = & (const snd_usb_audio_quirk_t[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 3,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 4,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 5,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 6,
+				.type = QUIRK_IGNORE_INTERFACE
+			},
+			{
+				.ifnum = 7,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 8,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 9,
+				.type = QUIRK_MIDI_MIDIMAN,
+				.data = & (const snd_usb_midi_endpoint_info_t) {
+					.out_cables = 0x0001,
+					.in_cables  = 0x0001
+				}
+			},
+			{
+				.ifnum = -1
+			}
 		}
 	}
 },