Ver Fonte

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (346 commits)
  ASoC: core: Don't set "(null)" as a driver name
  ALSA: hda - Use LPIB for ATI/AMD chipsets as default
  Revert "ALSA: hda - Use position_fix=3 as default for AMD chipsets"
  ASoC: Tegra: Fix compile when debugfs not enabled
  ASoC: spdif-dit: Add missing MODULE_*
  SOUND: OSS: Remove Au1550 driver.
  ALSA: hda - add Intel Panther Point HDMI codec id
  ALSA: emu10k1 - Add dB range to Bass and Treble for SB Live!
  ALSA: hda - Remove PCM mixer elements from Virtual Master of realtek
  ALSA: hda - Fix input-src parse in patch_analog.c
  ASoC: davinci-mcasp: enable ping-pong SRAM buffers
  ASoC: add iPAQ hx4700 machine driver
  ASoC: Asahi Kasei AK4641 codec driver
  ALSA: hda - Enable Realtek ALC269 codec input layer beep
  ALSA: intel8x0m: enable AMD8111 modem
  ALSA: HDA: Add jack detection for HDMI
  ALSA: sound, core, pcm_lib: fix xrun_log
  ASoC: Max98095: Move existing NULL check before pointer dereference.
  ALSA: sound, core, pcm_lib: xrun_log: log also in_interrupt
  ALSA: usb-audio - Add support for USB X-Fi S51 Pro
  ...
Linus Torvalds há 14 anos atrás
pai
commit
710421cc7d
100 ficheiros alterados com 9795 adições e 8384 exclusões
  1. 7 0
      Documentation/sound/alsa/ALSA-Configuration.txt
  2. 1 1
      Documentation/sound/alsa/HD-Audio-Models.txt
  3. 10 3
      MAINTAINERS
  4. 3 0
      arch/arm/mach-tegra/Kconfig
  5. 4 3
      arch/arm/mach-tegra/board-harmony.c
  6. 3 2
      arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
  7. 0 15
      drivers/media/radio/Kconfig
  8. 0 1
      drivers/media/radio/Makefile
  9. 0 452
      drivers/media/radio/radio-maestro.c
  10. 0 1
      drivers/staging/intel_sst/intel_sst_drv_interface.c
  11. 4 0
      drivers/staging/intel_sst/intelmid.c
  12. 49 0
      include/linux/mfd/wm8994/pdata.h
  13. 26 0
      include/sound/ak4641.h
  14. 1 0
      include/sound/control.h
  15. 54 0
      include/sound/max98095.h
  16. 44 36
      include/sound/soc-dapm.h
  17. 27 5
      include/sound/soc.h
  18. 17 9
      include/sound/tea575x-tuner.h
  19. 1 1
      include/sound/tlv320dac33-plat.h
  20. 1 1
      include/sound/tpa6130a2-plat.h
  21. 55 0
      include/sound/wm8915.h
  22. 22 0
      include/sound/wm8962.h
  23. 64 0
      sound/core/control.c
  24. 1 1
      sound/core/init.c
  25. 9 5
      sound/core/pcm_lib.c
  26. 11 0
      sound/firewire/Kconfig
  27. 2 0
      sound/firewire/Makefile
  28. 755 0
      sound/firewire/isight.c
  29. 5 0
      sound/firewire/iso-resources.c
  30. 2 0
      sound/firewire/packets-buffer.c
  31. 1 1
      sound/i2c/other/Makefile
  32. 112 41
      sound/i2c/other/tea575x-tuner.c
  33. 0 4
      sound/oss/Kconfig
  34. 0 1
      sound/oss/Makefile
  35. 0 1203
      sound/oss/ac97_codec.c
  36. 0 2147
      sound/oss/au1550_ac97.c
  37. 22 5
      sound/pci/Kconfig
  38. 1 0
      sound/pci/Makefile
  39. 142 186
      sound/pci/asihpi/asihpi.c
  40. 15 24
      sound/pci/asihpi/hpi6000.c
  41. 48 47
      sound/pci/asihpi/hpi6205.c
  42. 8 11
      sound/pci/asihpi/hpi_internal.h
  43. 7 3
      sound/pci/asihpi/hpicmn.c
  44. 2 0
      sound/pci/asihpi/hpicmn.h
  45. 0 27
      sound/pci/asihpi/hpifunc.c
  46. 13 18
      sound/pci/asihpi/hpimsgx.c
  47. 31 32
      sound/pci/asihpi/hpioctl.c
  48. 1 1
      sound/pci/au88x0/au8810.h
  49. 1 1
      sound/pci/au88x0/au8820.h
  50. 1 1
      sound/pci/au88x0/au8830.h
  51. 7 6
      sound/pci/au88x0/au88x0_pcm.c
  52. 5 0
      sound/pci/emu10k1/emufx.c
  53. 8 2
      sound/pci/emu10k1/emumixer.c
  54. 78 0
      sound/pci/es1968.c
  55. 79 292
      sound/pci/fm801.c
  56. 84 13
      sound/pci/hda/hda_codec.c
  57. 3 1
      sound/pci/hda/hda_codec.h
  58. 36 2
      sound/pci/hda/hda_intel.c
  59. 11 5
      sound/pci/hda/hda_local.h
  60. 173 172
      sound/pci/hda/patch_analog.c
  61. 8 8
      sound/pci/hda/patch_ca0110.c
  62. 25 27
      sound/pci/hda/patch_cirrus.c
  63. 20 20
      sound/pci/hda/patch_cmedia.c
  64. 808 277
      sound/pci/hda/patch_conexant.c
  65. 26 13
      sound/pci/hda/patch_hdmi.c
  66. 1848 1873
      sound/pci/hda/patch_realtek.c
  67. 6 5
      sound/pci/hda/patch_si3054.c
  68. 214 217
      sound/pci/hda/patch_sigmatel.c
  69. 864 662
      sound/pci/hda/patch_via.c
  70. 2 2
      sound/pci/intel8x0m.c
  71. 4 0
      sound/pci/lola/Makefile
  72. 791 0
      sound/pci/lola/lola.c
  73. 527 0
      sound/pci/lola/lola.h
  74. 323 0
      sound/pci/lola/lola_clock.c
  75. 839 0
      sound/pci/lola/lola_mixer.c
  76. 706 0
      sound/pci/lola/lola_pcm.c
  77. 222 0
      sound/pci/lola/lola_proc.c
  78. 1 1
      sound/ppc/tumbler.c
  79. 1 1
      sound/soc/atmel/sam9g20_wm8731.c
  80. 1 1
      sound/soc/au1x/db1200.c
  81. 10 3
      sound/soc/blackfin/bf5xx-ac97-pcm.c
  82. 53 113
      sound/soc/blackfin/bf5xx-ac97.c
  83. 21 21
      sound/soc/blackfin/bf5xx-ad1836.c
  84. 35 21
      sound/soc/blackfin/bf5xx-ad193x.c
  85. 20 25
      sound/soc/blackfin/bf5xx-ad1980.c
  86. 21 21
      sound/soc/blackfin/bf5xx-ad73311.c
  87. 13 10
      sound/soc/blackfin/bf5xx-i2s-pcm.c
  88. 73 99
      sound/soc/blackfin/bf5xx-i2s.c
  89. 119 40
      sound/soc/blackfin/bf5xx-sport.c
  90. 11 5
      sound/soc/blackfin/bf5xx-sport.h
  91. 21 21
      sound/soc/blackfin/bf5xx-ssm2602.c
  92. 13 10
      sound/soc/blackfin/bf5xx-tdm-pcm.c
  93. 38 72
      sound/soc/blackfin/bf5xx-tdm.c
  94. 1 1
      sound/soc/codecs/88pm860x-codec.c
  95. 18 2
      sound/soc/codecs/Kconfig
  96. 9 1
      sound/soc/codecs/Makefile
  97. 9 14
      sound/soc/codecs/ad193x.c
  98. 1 1
      sound/soc/codecs/ad1980.c
  99. 1 1
      sound/soc/codecs/ad73311.c
  100. 5 14
      sound/soc/codecs/ak4535.c

+ 7 - 0
Documentation/sound/alsa/ALSA-Configuration.txt

@@ -1230,6 +1230,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     This module supports multiple cards.
     This module supports multiple cards.
     The driver requires the firmware loader support on kernel.
     The driver requires the firmware loader support on kernel.
 
 
+  Module snd-lola
+  ---------------
+
+    Module for Digigram Lola PCI-e boards
+
+    This module supports multiple cards.
+
   Module snd-lx6464es
   Module snd-lx6464es
   -------------------
   -------------------
 
 

+ 1 - 1
Documentation/sound/alsa/HD-Audio-Models.txt

@@ -94,7 +94,7 @@ ALC662/663/272
   3stack-dig	3-stack (2-channel) with SPDIF
   3stack-dig	3-stack (2-channel) with SPDIF
   3stack-6ch	 3-stack (6-channel)
   3stack-6ch	 3-stack (6-channel)
   3stack-6ch-dig 3-stack (6-channel) with SPDIF
   3stack-6ch-dig 3-stack (6-channel) with SPDIF
-  6stack-dig	 6-stack with SPDIF
+  5stack-dig	 5-stack with SPDIF
   lenovo-101e	 Lenovo laptop
   lenovo-101e	 Lenovo laptop
   eeepc-p701	ASUS Eeepc P701
   eeepc-p701	ASUS Eeepc P701
   eeepc-ep20	ASUS Eeepc EP20
   eeepc-ep20	ASUS Eeepc EP20

+ 10 - 3
MAINTAINERS

@@ -4269,6 +4269,13 @@ M:	Tim Hockin <thockin@hockin.org>
 S:	Maintained
 S:	Maintained
 F:	drivers/net/natsemi.c
 F:	drivers/net/natsemi.c
 
 
+NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
+M:	Daniel Mack <zonque@gmail.com>
+S:	Maintained
+L:	alsa-devel@alsa-project.org
+W:	http://www.native-instruments.com
+F:	sound/usb/caiaq/
+
 NCP FILESYSTEM
 NCP FILESYSTEM
 M:	Petr Vandrovec <petr@vandrovec.name>
 M:	Petr Vandrovec <petr@vandrovec.name>
 S:	Odd Fixes
 S:	Odd Fixes
@@ -5868,7 +5875,7 @@ F:	include/sound/
 F:	sound/
 F:	sound/
 
 
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
-M:	Liam Girdwood <lrg@slimlogic.co.uk>
+M:	Liam Girdwood <lrg@ti.com>
 M:	Mark Brown <broonie@opensource.wolfsonmicro.com>
 M:	Mark Brown <broonie@opensource.wolfsonmicro.com>
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -6119,7 +6126,7 @@ F:	drivers/mmc/host/tifm_sd.c
 F:	include/linux/tifm.h
 F:	include/linux/tifm.h
 
 
 TI TWL4030 SERIES SOC CODEC DRIVER
 TI TWL4030 SERIES SOC CODEC DRIVER
-M:	Peter Ujfalusi <peter.ujfalusi@nokia.com>
+M:	Peter Ujfalusi <peter.ujfalusi@ti.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:	Maintained
 S:	Maintained
 F:	sound/soc/codecs/twl4030*
 F:	sound/soc/codecs/twl4030*
@@ -6763,7 +6770,7 @@ F:	drivers/scsi/vmw_pvscsi.c
 F:	drivers/scsi/vmw_pvscsi.h
 F:	drivers/scsi/vmw_pvscsi.h
 
 
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
-M:	Liam Girdwood <lrg@slimlogic.co.uk>
+M:	Liam Girdwood <lrg@ti.com>
 M:	Mark Brown <broonie@opensource.wolfsonmicro.com>
 M:	Mark Brown <broonie@opensource.wolfsonmicro.com>
 W:	http://opensource.wolfsonmicro.com/node/15
 W:	http://opensource.wolfsonmicro.com/node/15
 W:	http://www.slimlogic.co.uk/?p=48
 W:	http://www.slimlogic.co.uk/?p=48

+ 3 - 0
arch/arm/mach-tegra/Kconfig

@@ -27,12 +27,14 @@ comment "Tegra board type"
 
 
 config MACH_HARMONY
 config MACH_HARMONY
        bool "Harmony board"
        bool "Harmony board"
+       select MACH_HAS_SND_SOC_TEGRA_WM8903
        help
        help
          Support for nVidia Harmony development platform
          Support for nVidia Harmony development platform
 
 
 config MACH_KAEN
 config MACH_KAEN
        bool "Kaen board"
        bool "Kaen board"
        select MACH_SEABOARD
        select MACH_SEABOARD
+       select MACH_HAS_SND_SOC_TEGRA_WM8903
        help
        help
          Support for the Kaen version of Seaboard
          Support for the Kaen version of Seaboard
 
 
@@ -43,6 +45,7 @@ config MACH_PAZ00
 
 
 config MACH_SEABOARD
 config MACH_SEABOARD
        bool "Seaboard board"
        bool "Seaboard board"
+       select MACH_HAS_SND_SOC_TEGRA_WM8903
        help
        help
          Support for nVidia Seaboard development platform. It will
          Support for nVidia Seaboard development platform. It will
 	 also be included for some of the derivative boards that
 	 also be included for some of the derivative boards that

+ 4 - 3
arch/arm/mach-tegra/board-harmony.c

@@ -34,7 +34,7 @@
 #include <asm/mach/time.h>
 #include <asm/mach/time.h>
 #include <asm/setup.h>
 #include <asm/setup.h>
 
 
-#include <mach/harmony_audio.h>
+#include <mach/tegra_wm8903_pdata.h>
 #include <mach/iomap.h>
 #include <mach/iomap.h>
 #include <mach/irqs.h>
 #include <mach/irqs.h>
 #include <mach/sdhci.h>
 #include <mach/sdhci.h>
@@ -67,15 +67,16 @@ static struct platform_device debug_uart = {
 	},
 	},
 };
 };
 
 
-static struct harmony_audio_platform_data harmony_audio_pdata = {
+static struct tegra_wm8903_platform_data harmony_audio_pdata = {
 	.gpio_spkr_en		= TEGRA_GPIO_SPKR_EN,
 	.gpio_spkr_en		= TEGRA_GPIO_SPKR_EN,
 	.gpio_hp_det		= TEGRA_GPIO_HP_DET,
 	.gpio_hp_det		= TEGRA_GPIO_HP_DET,
+	.gpio_hp_mute		= -1,
 	.gpio_int_mic_en	= TEGRA_GPIO_INT_MIC_EN,
 	.gpio_int_mic_en	= TEGRA_GPIO_INT_MIC_EN,
 	.gpio_ext_mic_en	= TEGRA_GPIO_EXT_MIC_EN,
 	.gpio_ext_mic_en	= TEGRA_GPIO_EXT_MIC_EN,
 };
 };
 
 
 static struct platform_device harmony_audio_device = {
 static struct platform_device harmony_audio_device = {
-	.name	= "tegra-snd-harmony",
+	.name	= "tegra-snd-wm8903",
 	.id	= 0,
 	.id	= 0,
 	.dev	= {
 	.dev	= {
 		.platform_data  = &harmony_audio_pdata,
 		.platform_data  = &harmony_audio_pdata,

+ 3 - 2
arch/arm/mach-tegra/include/mach/harmony_audio.h → arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h

@@ -1,5 +1,5 @@
 /*
 /*
- * arch/arm/mach-tegra/include/mach/harmony_audio.h
+ * arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
  *
  *
  * Copyright 2011 NVIDIA, Inc.
  * Copyright 2011 NVIDIA, Inc.
  *
  *
@@ -14,9 +14,10 @@
  *
  *
  */
  */
 
 
-struct harmony_audio_platform_data {
+struct tegra_wm8903_platform_data {
 	int gpio_spkr_en;
 	int gpio_spkr_en;
 	int gpio_hp_det;
 	int gpio_hp_det;
+	int gpio_hp_mute;
 	int gpio_int_mic_en;
 	int gpio_int_mic_en;
 	int gpio_ext_mic_en;
 	int gpio_ext_mic_en;
 };
 };

+ 0 - 15
drivers/media/radio/Kconfig

@@ -166,21 +166,6 @@ config RADIO_MAXIRADIO
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called radio-maxiradio.
 	  module will be called radio-maxiradio.
 
 
-config RADIO_MAESTRO
-	tristate "Maestro on board radio"
-	depends on VIDEO_V4L2 && PCI
-	---help---
-	  Say Y here to directly support the on-board radio tuner on the
-	  Maestro 2 or 2E sound card.
-
-	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video For Linux API.  Information on
-	  this API and pointers to "v4l" programs may be found at
-	  <file:Documentation/video4linux/API.html>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called radio-maestro.
-
 config RADIO_MIROPCM20
 config RADIO_MIROPCM20
 	tristate "miroSOUND PCM20 radio"
 	tristate "miroSOUND PCM20 radio"
 	depends on ISA && VIDEO_V4L2 && SND
 	depends on ISA && VIDEO_V4L2 && SND

+ 0 - 1
drivers/media/radio/Makefile

@@ -16,7 +16,6 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
 obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
 obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
 obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
-obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
 obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_RADIO_SI470X) += si470x/
 obj-$(CONFIG_RADIO_SI470X) += si470x/

+ 0 - 452
drivers/media/radio/radio-maestro.c

@@ -1,452 +0,0 @@
-/* Maestro PCI sound card radio driver for Linux support
- * (c) 2000 A. Tlalka, atlka@pg.gda.pl
- * Notes on the hardware
- *
- *  + Frequency control is done digitally
- *  + No volume control - only mute/unmute - you have to use Aux line volume
- *  control on Maestro card to set the volume
- *  + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
- *  frequency setting (>100ms) and only when the radio is unmuted.
- *  version 0.02
- *  + io port is automatically detected - only the first radio is used
- *  version 0.03
- *  + thread access locking additions
- *  version 0.04
- * + code improvements
- * + VIDEO_TUNER_LOW is permanent
- *
- * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#include <linux/pci.h>
-#include <linux/videodev2.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-
-MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
-MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
-MODULE_LICENSE("GPL");
-
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 6)
-#define DRIVER_VERSION	"0.06"
-
-#define GPIO_DATA	0x60   /* port offset from ESS_IO_BASE */
-
-#define IO_MASK		4      /* mask      register offset from GPIO_DATA
-				bits 1=unmask write to given bit */
-#define IO_DIR		8      /* direction register offset from GPIO_DATA
-				bits 0/1=read/write direction */
-
-#define GPIO6		0x0040 /* mask bits for GPIO lines */
-#define GPIO7		0x0080
-#define GPIO8		0x0100
-#define GPIO9		0x0200
-
-#define STR_DATA	GPIO6  /* radio TEA5757 pins and GPIO bits */
-#define STR_CLK		GPIO7
-#define STR_WREN	GPIO8
-#define STR_MOST	GPIO9
-
-#define FREQ_LO		 50*16000
-#define FREQ_HI		150*16000
-
-#define FREQ_IF		171200 /* 10.7*16000   */
-#define FREQ_STEP	200    /* 12.5*16      */
-
-#define FREQ2BITS(x)	((((unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
-			/(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
-
-#define BITS2FREQ(x)	((x) * FREQ_STEP - FREQ_IF)
-
-struct maestro {
-	struct v4l2_device v4l2_dev;
-	struct video_device vdev;
-	struct pci_dev *pdev;
-	struct mutex lock;
-
-	u16	io;	/* base of Maestro card radio io (GPIO_DATA)*/
-	u16	muted;	/* VIDEO_AUDIO_MUTE */
-	u16	stereo;	/* VIDEO_TUNER_STEREO_ON */
-	u16	tuned;	/* signal strength (0 or 0xffff) */
-};
-
-static inline struct maestro *to_maestro(struct v4l2_device *v4l2_dev)
-{
-	return container_of(v4l2_dev, struct maestro, v4l2_dev);
-}
-
-static u32 radio_bits_get(struct maestro *dev)
-{
-	u16 io = dev->io, l, rdata;
-	u32 data = 0;
-	u16 omask;
-
-	omask = inw(io + IO_MASK);
-	outw(~(STR_CLK | STR_WREN), io + IO_MASK);
-	outw(0, io);
-	udelay(16);
-
-	for (l = 24; l--;) {
-		outw(STR_CLK, io);		/* HI state */
-		udelay(2);
-		if (!l)
-			dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
-		outw(0, io);			/* LO state */
-		udelay(2);
-		data <<= 1;			/* shift data */
-		rdata = inw(io);
-		if (!l)
-			dev->stereo = (rdata & STR_MOST) ?  0 : 1;
-		else if (rdata & STR_DATA)
-			data++;
-		udelay(2);
-	}
-
-	if (dev->muted)
-		outw(STR_WREN, io);
-
-	udelay(4);
-	outw(omask, io + IO_MASK);
-
-	return data & 0x3ffe;
-}
-
-static void radio_bits_set(struct maestro *dev, u32 data)
-{
-	u16 io = dev->io, l, bits;
-	u16 omask, odir;
-
-	omask = inw(io + IO_MASK);
-	odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
-	outw(odir | STR_DATA, io + IO_DIR);
-	outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
-	udelay(16);
-	for (l = 25; l; l--) {
-		bits = ((data >> 18) & STR_DATA) | STR_WREN;
-		data <<= 1;			/* shift data */
-		outw(bits, io);			/* start strobe */
-		udelay(2);
-		outw(bits | STR_CLK, io);	/* HI level */
-		udelay(2);
-		outw(bits, io);			/* LO level */
-		udelay(4);
-	}
-
-	if (!dev->muted)
-		outw(0, io);
-
-	udelay(4);
-	outw(omask, io + IO_MASK);
-	outw(odir, io + IO_DIR);
-	msleep(125);
-}
-
-static int vidioc_querycap(struct file *file, void  *priv,
-					struct v4l2_capability *v)
-{
-	struct maestro *dev = video_drvdata(file);
-
-	strlcpy(v->driver, "radio-maestro", sizeof(v->driver));
-	strlcpy(v->card, "Maestro Radio", sizeof(v->card));
-	snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
-	v->version = RADIO_VERSION;
-	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-	return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
-{
-	struct maestro *dev = video_drvdata(file);
-
-	if (v->index > 0)
-		return -EINVAL;
-
-	mutex_lock(&dev->lock);
-	radio_bits_get(dev);
-
-	strlcpy(v->name, "FM", sizeof(v->name));
-	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = FREQ_LO;
-	v->rangehigh = FREQ_HI;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	if (dev->stereo)
-		v->audmode = V4L2_TUNER_MODE_STEREO;
-	else
-		v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = dev->tuned;
-	mutex_unlock(&dev->lock);
-	return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
-{
-	return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
-{
-	struct maestro *dev = video_drvdata(file);
-
-	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-		return -EINVAL;
-	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
-		return -EINVAL;
-	mutex_lock(&dev->lock);
-	radio_bits_set(dev, FREQ2BITS(f->frequency));
-	mutex_unlock(&dev->lock);
-	return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
-{
-	struct maestro *dev = video_drvdata(file);
-
-	if (f->tuner != 0)
-		return -EINVAL;
-	f->type = V4L2_TUNER_RADIO;
-	mutex_lock(&dev->lock);
-	f->frequency = BITS2FREQ(radio_bits_get(dev));
-	mutex_unlock(&dev->lock);
-	return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct maestro *dev = video_drvdata(file);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = dev->muted;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
-{
-	struct maestro *dev = video_drvdata(file);
-	u16 io = dev->io;
-	u16 omask;
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		mutex_lock(&dev->lock);
-		omask = inw(io + IO_MASK);
-		outw(~STR_WREN, io + IO_MASK);
-		dev->muted = ctrl->value;
-		outw(dev->muted ? STR_WREN : 0, io);
-		udelay(4);
-		outw(omask, io + IO_MASK);
-		msleep(125);
-		mutex_unlock(&dev->lock);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	a->index = 0;
-	strlcpy(a->name, "Radio", sizeof(a->name));
-	a->capability = V4L2_AUDCAP_STEREO;
-	return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
-{
-	return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations maestro_fops = {
-	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
-};
-
-static u16 __devinit radio_power_on(struct maestro *dev)
-{
-	register u16 io = dev->io;
-	register u32 ofreq;
-	u16 omask, odir;
-
-	omask = inw(io + IO_MASK);
-	odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
-	outw(odir & ~STR_WREN, io + IO_DIR);
-	dev->muted = inw(io) & STR_WREN ? 0 : 1;
-	outw(odir, io + IO_DIR);
-	outw(~(STR_WREN | STR_CLK), io + IO_MASK);
-	outw(dev->muted ? 0 : STR_WREN, io);
-	udelay(16);
-	outw(omask, io + IO_MASK);
-	ofreq = radio_bits_get(dev);
-
-	if ((ofreq < FREQ2BITS(FREQ_LO)) || (ofreq > FREQ2BITS(FREQ_HI)))
-		ofreq = FREQ2BITS(FREQ_LO);
-	radio_bits_set(dev, ofreq);
-
-	return (ofreq == radio_bits_get(dev));
-}
-
-static int __devinit maestro_probe(struct pci_dev *pdev,
-	const struct pci_device_id *ent)
-{
-	struct maestro *dev;
-	struct v4l2_device *v4l2_dev;
-	int retval;
-
-	retval = pci_enable_device(pdev);
-	if (retval) {
-		dev_err(&pdev->dev, "enabling pci device failed!\n");
-		goto err;
-	}
-
-	retval = -ENOMEM;
-
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (dev == NULL) {
-		dev_err(&pdev->dev, "not enough memory\n");
-		goto err;
-	}
-
-	v4l2_dev = &dev->v4l2_dev;
-	mutex_init(&dev->lock);
-	dev->pdev = pdev;
-
-	strlcpy(v4l2_dev->name, "maestro", sizeof(v4l2_dev->name));
-
-	retval = v4l2_device_register(&pdev->dev, v4l2_dev);
-	if (retval < 0) {
-		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-		goto errfr;
-	}
-
-	dev->io = pci_resource_start(pdev, 0) + GPIO_DATA;
-
-	strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
-	dev->vdev.v4l2_dev = v4l2_dev;
-	dev->vdev.fops = &maestro_fops;
-	dev->vdev.ioctl_ops = &maestro_ioctl_ops;
-	dev->vdev.release = video_device_release_empty;
-	video_set_drvdata(&dev->vdev, dev);
-
-	if (!radio_power_on(dev)) {
-		retval = -EIO;
-		goto errfr1;
-	}
-
-	retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
-	if (retval) {
-		v4l2_err(v4l2_dev, "can't register video device!\n");
-		goto errfr1;
-	}
-
-	v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
-
-	return 0;
-errfr1:
-	v4l2_device_unregister(v4l2_dev);
-errfr:
-	kfree(dev);
-err:
-	return retval;
-
-}
-
-static void __devexit maestro_remove(struct pci_dev *pdev)
-{
-	struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
-	struct maestro *dev = to_maestro(v4l2_dev);
-
-	video_unregister_device(&dev->vdev);
-	v4l2_device_unregister(&dev->v4l2_dev);
-}
-
-static struct pci_device_id maestro_r_pci_tbl[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968),
-		.class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
-		.class_mask = 0xffff00 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978),
-		.class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
-		.class_mask = 0xffff00 },
-	{ 0 }
-};
-MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl);
-
-static struct pci_driver maestro_r_driver = {
-	.name		= "maestro_radio",
-	.id_table	= maestro_r_pci_tbl,
-	.probe		= maestro_probe,
-	.remove		= __devexit_p(maestro_remove),
-};
-
-static int __init maestro_radio_init(void)
-{
-	int retval = pci_register_driver(&maestro_r_driver);
-
-	if (retval)
-		printk(KERN_ERR "error during registration pci driver\n");
-
-	return retval;
-}
-
-static void __exit maestro_radio_exit(void)
-{
-	pci_unregister_driver(&maestro_r_driver);
-}
-
-module_init(maestro_radio_init);
-module_exit(maestro_radio_exit);

+ 0 - 1
drivers/staging/intel_sst/intel_sst_drv_interface.c

@@ -508,7 +508,6 @@ int register_sst_card(struct intel_sst_card_ops *card)
 			sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE;
 			sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE;
 			sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/
 			sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/
 			card->pcm_control = sst_pmic_ops.pcm_control;
 			card->pcm_control = sst_pmic_ops.pcm_control;
-			sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
 			return 0;
 			return 0;
 		} else {
 		} else {
 			pr_err("strcmp fail %s\n", card->module_name);
 			pr_err("strcmp fail %s\n", card->module_name);

+ 4 - 0
drivers/staging/intel_sst/intelmid.c

@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
+#include <linux/firmware.h>
 #include <sound/control.h>
 #include <sound/control.h>
 #include <asm/mrst.h>
 #include <asm/mrst.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
@@ -40,6 +41,8 @@
 #include <sound/initval.h>
 #include <sound/initval.h>
 #include "intel_sst.h"
 #include "intel_sst.h"
 #include "intel_sst_ioctl.h"
 #include "intel_sst_ioctl.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
 #include "intelmid_snd_control.h"
 #include "intelmid_snd_control.h"
 #include "intelmid.h"
 #include "intelmid.h"
 
 
@@ -802,6 +805,7 @@ static int __devinit snd_intelmad_sst_register(
 		pr_err("sst card registration failed\n");
 		pr_err("sst card registration failed\n");
 		return ret_val;
 		return ret_val;
 	}
 	}
+	sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
 
 
 	sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id;
 	sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id;
 	intelmaddata->pmic_status = PMIC_UNINIT;
 	intelmaddata->pmic_status = PMIC_UNINIT;

+ 49 - 0
include/linux/mfd/wm8994/pdata.h

@@ -32,6 +32,10 @@ struct wm8994_ldo_pdata {
 #define WM8994_EQ_REGS  20
 #define WM8994_EQ_REGS  20
 #define WM8958_MBC_CUTOFF_REGS 20
 #define WM8958_MBC_CUTOFF_REGS 20
 #define WM8958_MBC_COEFF_REGS  48
 #define WM8958_MBC_COEFF_REGS  48
+#define WM8958_MBC_COMBINED_REGS 56
+#define WM8958_VSS_HPF_REGS 2
+#define WM8958_VSS_REGS 148
+#define WM8958_ENH_EQ_REGS 32
 
 
 /**
 /**
  * DRC configurations are specified with a label and a set of register
  * DRC configurations are specified with a label and a set of register
@@ -71,6 +75,42 @@ struct wm8958_mbc_cfg {
 	const char *name;
 	const char *name;
 	u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
 	u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
 	u16 coeff_regs[WM8958_MBC_COEFF_REGS];
 	u16 coeff_regs[WM8958_MBC_COEFF_REGS];
+
+	/* Coefficient layout when using MBC+VSS firmware */
+	u16 combined_regs[WM8958_MBC_COMBINED_REGS];
+};
+
+/**
+ * VSS HPF configurations are specified with a label and two values to
+ * write.  Configurations are expected to be generated using the
+ * multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_vss_hpf_cfg {
+	const char *name;
+	u16 regs[WM8958_VSS_HPF_REGS];
+};
+
+/**
+ * VSS configurations are specified with a label and array of values
+ * to write.  Configurations are expected to be generated using the
+ * multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_vss_cfg {
+	const char *name;
+	u16 regs[WM8958_VSS_REGS];
+};
+
+/**
+ * Enhanced EQ configurations are specified with a label and array of
+ * values to write.  Configurations are expected to be generated using
+ * the multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_enh_eq_cfg {
+	const char *name;
+	u16 regs[WM8958_ENH_EQ_REGS];
 };
 };
 
 
 struct wm8994_pdata {
 struct wm8994_pdata {
@@ -95,6 +135,15 @@ struct wm8994_pdata {
 	int num_mbc_cfgs;
 	int num_mbc_cfgs;
 	struct wm8958_mbc_cfg *mbc_cfgs;
 	struct wm8958_mbc_cfg *mbc_cfgs;
 
 
+	int num_vss_cfgs;
+	struct wm8958_vss_cfg *vss_cfgs;
+
+	int num_vss_hpf_cfgs;
+	struct wm8958_vss_hpf_cfg *vss_hpf_cfgs;
+
+	int num_enh_eq_cfgs;
+	struct wm8958_enh_eq_cfg *enh_eq_cfgs;
+
         /* LINEOUT can be differential or single ended */
         /* LINEOUT can be differential or single ended */
         unsigned int lineout1_diff:1;
         unsigned int lineout1_diff:1;
         unsigned int lineout2_diff:1;
         unsigned int lineout2_diff:1;

+ 26 - 0
include/sound/ak4641.h

@@ -0,0 +1,26 @@
+/*
+ * AK4641 ALSA SoC Codec driver
+ *
+ * Copyright 2009 Philipp Zabel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __AK4641_H
+#define __AK4641_H
+
+/**
+ * struct ak4641_platform_data - platform specific AK4641 configuration
+ * @gpio_power:	GPIO to control external power to AK4641
+ * @gpio_npdn:	GPIO connected to AK4641 nPDN pin
+ *
+ * Both GPIO parameters are optional.
+ */
+struct ak4641_platform_data {
+	int gpio_power;
+	int gpio_npdn;
+};
+
+#endif /* __AK4641_H */

+ 1 - 0
include/sound/control.h

@@ -113,6 +113,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, v
 void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
 void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
 int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
 int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
 int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol);
 int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol);
+int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace);
 int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
 int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
 int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
 int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
 int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
 int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,

+ 54 - 0
include/sound/max98095.h

@@ -0,0 +1,54 @@
+/*
+ * Platform data for MAX98095
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ *  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.
+ *
+ */
+
+#ifndef __SOUND_MAX98095_PDATA_H__
+#define __SOUND_MAX98095_PDATA_H__
+
+/* Equalizer filter response configuration */
+struct max98095_eq_cfg {
+	const char *name;
+	unsigned int rate;
+	u16 band1[5];
+	u16 band2[5];
+	u16 band3[5];
+	u16 band4[5];
+	u16 band5[5];
+};
+
+/* Biquad filter response configuration */
+struct max98095_biquad_cfg {
+	const char *name;
+	unsigned int rate;
+	u16 band1[5];
+	u16 band2[5];
+};
+
+/* codec platform data */
+struct max98095_pdata {
+
+	/* Equalizers for DAI1 and DAI2 */
+	struct max98095_eq_cfg *eq_cfg;
+	unsigned int eq_cfgcnt;
+
+	/* Biquad filter for DAI1 and DAI2 */
+	struct max98095_biquad_cfg *bq_cfg;
+	unsigned int bq_cfgcnt;
+
+	/* Analog/digital microphone configuration:
+	 * 0 = analog microphone input (normal setting)
+	 * 1 = digital microphone input
+	 */
+	unsigned int digmic_left_mode:1;
+	unsigned int digmic_right_mode:1;
+};
+
+#endif

+ 44 - 36
include/sound/soc-dapm.h

@@ -24,7 +24,7 @@
  * SoC dynamic audio power management
  * SoC dynamic audio power management
  *
  *
  * We can have up to 4 power domains
  * We can have up to 4 power domains
- * 	1. Codec domain - VREF, VMID
+ *  1. Codec domain - VREF, VMID
  *     Usually controlled at codec probe/remove, although can be set
  *     Usually controlled at codec probe/remove, although can be set
  *     at stream time if power is not needed for sidetone, etc.
  *     at stream time if power is not needed for sidetone, etc.
  *  2. Platform/Machine domain - physically connected inputs and outputs
  *  2. Platform/Machine domain - physically connected inputs and outputs
@@ -39,30 +39,30 @@
 
 
 /* codec domain */
 /* codec domain */
 #define SND_SOC_DAPM_VMID(wname) \
 #define SND_SOC_DAPM_VMID(wname) \
-{	.id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0}
 	.num_kcontrols = 0}
 
 
 /* platform domain */
 /* platform domain */
 #define SND_SOC_DAPM_INPUT(wname) \
 #define SND_SOC_DAPM_INPUT(wname) \
-{	.id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_OUTPUT(wname) \
 #define SND_SOC_DAPM_OUTPUT(wname) \
-{	.id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_MIC(wname, wevent) \
 #define SND_SOC_DAPM_MIC(wname, wevent) \
-{	.id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 #define SND_SOC_DAPM_HP(wname, wevent) \
 #define SND_SOC_DAPM_HP(wname, wevent) \
-{	.id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_SPK(wname, wevent) \
 #define SND_SOC_DAPM_SPK(wname, wevent) \
-{	.id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_LINE(wname, wevent) \
 #define SND_SOC_DAPM_LINE(wname, wevent) \
-{	.id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 
 
@@ -70,91 +70,91 @@
 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
 	 wcontrols, wncontrols) \
 	 wcontrols, wncontrols) \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
 	 wcontrols, wncontrols) \
 	 wcontrols, wncontrols) \
 {	.id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
 	 wcontrols, wncontrols)\
 	 wcontrols, wncontrols)\
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
 #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
 	 wcontrols, wncontrols)\
 	 wcontrols, wncontrols)\
 {       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
 {       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
+	.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = wncontrols}
 	.num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
+	.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0}
 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
 {	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
 #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {	.id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {	.id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
 {	.id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
+	.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = 1}
 	.num_kcontrols = 1}
 
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
 	 wcontrols) \
 	 wcontrols) \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
 #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
 	 wcontrols)\
 	 wcontrols)\
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
 #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
 	 wcontrols)\
 	 wcontrols)\
 {       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
 {       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
+	.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = ARRAY_SIZE(wcontrols)}
 	.num_kcontrols = ARRAY_SIZE(wcontrols)}
 
 
 /* path domain with event - event handler must return 0 for success */
 /* path domain with event - event handler must return 0 for success */
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
 	wncontrols, wevent, wflags) \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
 	wncontrols, wevent, wflags) \
 {	.id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
 	wncontrols, wevent, wflags) \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
 #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
 	wcontrols, wncontrols, wevent, wflags) \
 	wcontrols, wncontrols, wevent, wflags) \
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, \
+	.invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
 	.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
 #define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
 {	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \
+	.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 
 
 /* additional sequencing control within an event type */
 /* additional sequencing control within an event type */
@@ -173,26 +173,26 @@
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
 #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
 	wcontrols, wevent, wflags) \
 	wcontrols, wevent, wflags) \
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, \
+	.invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
 	.num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
 
 
 /* events that are pre and post DAPM */
 /* events that are pre and post DAPM */
 #define SND_SOC_DAPM_PRE(wname, wevent) \
 #define SND_SOC_DAPM_PRE(wname, wevent) \
-{	.id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_POST(wname, wevent) \
 #define SND_SOC_DAPM_POST(wname, wevent) \
-{	.id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
 
 
@@ -232,7 +232,7 @@
 
 
 /* generic widgets */
 /* generic widgets */
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
-{	.id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \
+{	.id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \
 	.reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
 	.reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
 	.on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
 	.on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
@@ -356,7 +356,8 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 
 /* dapm sys fs - used by the core */
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
 int snd_soc_dapm_sys_add(struct device *dev);
-void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm);
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
+				struct dentry *parent);
 
 
 /* dapm audio pin control and status */
 /* dapm audio pin control and status */
 int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
 int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
@@ -472,7 +473,8 @@ struct snd_soc_dapm_widget {
 
 
 	/* kcontrols that relate to this widget */
 	/* kcontrols that relate to this widget */
 	int num_kcontrols;
 	int num_kcontrols;
-	const struct snd_kcontrol_new *kcontrols;
+	const struct snd_kcontrol_new *kcontrol_news;
+	struct snd_kcontrol **kcontrols;
 
 
 	/* widget input and outputs */
 	/* widget input and outputs */
 	struct list_head sources;
 	struct list_head sources;
@@ -516,4 +518,10 @@ struct snd_soc_dapm_context {
 #endif
 #endif
 };
 };
 
 
+/* A list of widgets associated with an object, typically a snd_kcontrol */
+struct snd_soc_dapm_widget_list {
+	int num_widgets;
+	struct snd_soc_dapm_widget *widgets[0];
+};
+
 #endif
 #endif

+ 27 - 5
include/sound/soc.h

@@ -248,7 +248,7 @@ typedef int (*hw_write_t)(void *,const char* ,int);
 extern struct snd_ac97_bus_ops soc_ac97_ops;
 extern struct snd_ac97_bus_ops soc_ac97_ops;
 
 
 enum snd_soc_control_type {
 enum snd_soc_control_type {
-	SND_SOC_CUSTOM,
+	SND_SOC_CUSTOM = 1,
 	SND_SOC_I2C,
 	SND_SOC_I2C,
 	SND_SOC_SPI,
 	SND_SOC_SPI,
 };
 };
@@ -278,6 +278,10 @@ int snd_soc_register_codec(struct device *dev,
 void snd_soc_unregister_codec(struct device *dev);
 void snd_soc_unregister_codec(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
 				    unsigned int reg);
 				    unsigned int reg);
+int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
+				    unsigned int reg);
+int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
+				    unsigned int reg);
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 			       int addr_bits, int data_bits,
 			       int addr_bits, int data_bits,
 			       enum snd_soc_control_type control);
 			       enum snd_soc_control_type control);
@@ -292,6 +296,8 @@ int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
 				      unsigned int reg);
 				      unsigned int reg);
 int snd_soc_default_readable_register(struct snd_soc_codec *codec,
 int snd_soc_default_readable_register(struct snd_soc_codec *codec,
 				      unsigned int reg);
 				      unsigned int reg);
+int snd_soc_default_writable_register(struct snd_soc_codec *codec,
+				      unsigned int reg);
 
 
 /* Utility functions to get clock rates from various things */
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
@@ -523,6 +529,7 @@ struct snd_soc_codec {
 	size_t reg_size;	/* reg_cache_size * reg_word_size */
 	size_t reg_size;	/* reg_cache_size * reg_word_size */
 	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
 	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
 	int (*readable_register)(struct snd_soc_codec *, unsigned int);
 	int (*readable_register)(struct snd_soc_codec *, unsigned int);
+	int (*writable_register)(struct snd_soc_codec *, unsigned int);
 
 
 	/* runtime */
 	/* runtime */
 	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
 	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
@@ -539,10 +546,12 @@ struct snd_soc_codec {
 
 
 	/* codec IO */
 	/* codec IO */
 	void *control_data; /* codec control (i2c/3wire) data */
 	void *control_data; /* codec control (i2c/3wire) data */
+	enum snd_soc_control_type control_type;
 	hw_write_t hw_write;
 	hw_write_t hw_write;
 	unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
 	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
 	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+	int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t);
 	void *reg_cache;
 	void *reg_cache;
 	const void *reg_def_copy;
 	const void *reg_def_copy;
 	const struct snd_soc_cache_ops *cache_ops;
 	const struct snd_soc_cache_ops *cache_ops;
@@ -568,7 +577,9 @@ struct snd_soc_codec_driver {
 			pm_message_t state);
 			pm_message_t state);
 	int (*resume)(struct snd_soc_codec *);
 	int (*resume)(struct snd_soc_codec *);
 
 
-	/* Default DAPM setup, added after probe() is run */
+	/* Default control and setup, added after probe() is run */
+	const struct snd_kcontrol_new *controls;
+	int num_controls;
 	const struct snd_soc_dapm_widget *dapm_widgets;
 	const struct snd_soc_dapm_widget *dapm_widgets;
 	int num_dapm_widgets;
 	int num_dapm_widgets;
 	const struct snd_soc_dapm_route *dapm_routes;
 	const struct snd_soc_dapm_route *dapm_routes;
@@ -587,6 +598,7 @@ struct snd_soc_codec_driver {
 				size_t, unsigned int);
 				size_t, unsigned int);
 	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
 	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
 	int (*readable_register)(struct snd_soc_codec *, unsigned int);
 	int (*readable_register)(struct snd_soc_codec *, unsigned int);
+	int (*writable_register)(struct snd_soc_codec *, unsigned int);
 	short reg_cache_size;
 	short reg_cache_size;
 	short reg_cache_step;
 	short reg_cache_step;
 	short reg_word_size;
 	short reg_word_size;
@@ -690,6 +702,8 @@ struct snd_soc_aux_dev {
 /* SoC card */
 /* SoC card */
 struct snd_soc_card {
 struct snd_soc_card {
 	const char *name;
 	const char *name;
+	const char *long_name;
+	const char *driver_name;
 	struct device *dev;
 	struct device *dev;
 	struct snd_card *snd_card;
 	struct snd_card *snd_card;
 	struct module *owner;
 	struct module *owner;
@@ -737,12 +751,15 @@ struct snd_soc_card {
 	struct snd_soc_pcm_runtime *rtd_aux;
 	struct snd_soc_pcm_runtime *rtd_aux;
 	int num_aux_rtd;
 	int num_aux_rtd;
 
 
+	const struct snd_kcontrol_new *controls;
+	int num_controls;
+
 	/*
 	/*
 	 * Card-specific routes and widgets.
 	 * Card-specific routes and widgets.
 	 */
 	 */
-	struct snd_soc_dapm_widget *dapm_widgets;
+	const struct snd_soc_dapm_widget *dapm_widgets;
 	int num_dapm_widgets;
 	int num_dapm_widgets;
-	struct snd_soc_dapm_route *dapm_routes;
+	const struct snd_soc_dapm_route *dapm_routes;
 	int num_dapm_routes;
 	int num_dapm_routes;
 
 
 	struct work_struct deferred_resume_work;
 	struct work_struct deferred_resume_work;
@@ -805,7 +822,7 @@ struct soc_enum {
 	unsigned char shift_r;
 	unsigned char shift_r;
 	unsigned int max;
 	unsigned int max;
 	unsigned int mask;
 	unsigned int mask;
-	const char **texts;
+	const char * const *texts;
 	const unsigned int *values;
 	const unsigned int *values;
 	void *dapm;
 	void *dapm;
 };
 };
@@ -814,6 +831,8 @@ struct soc_enum {
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 unsigned int snd_soc_write(struct snd_soc_codec *codec,
 unsigned int snd_soc_write(struct snd_soc_codec *codec,
 			   unsigned int reg, unsigned int val);
 			   unsigned int reg, unsigned int val);
+unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
+				    unsigned int reg, const void *data, size_t len);
 
 
 /* device driver data */
 /* device driver data */
 
 
@@ -871,6 +890,9 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
 	INIT_LIST_HEAD(&card->dapm_list);
 	INIT_LIST_HEAD(&card->dapm_list);
 }
 }
 
 
+int snd_soc_util_init(void);
+void snd_soc_util_exit(void);
+
 #include <sound/soc-dai.h>
 #include <sound/soc-dai.h>
 
 
 #ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_DEBUG_FS

+ 17 - 9
include/sound/tea575x-tuner.h

@@ -26,29 +26,37 @@
 #include <media/v4l2-dev.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ioctl.h>
 
 
+#define TEA575X_FMIF	10700
+
+#define TEA575X_DATA	(1 << 0)
+#define TEA575X_CLK	(1 << 1)
+#define TEA575X_WREN	(1 << 2)
+#define TEA575X_MOST	(1 << 3)
+
 struct snd_tea575x;
 struct snd_tea575x;
 
 
 struct snd_tea575x_ops {
 struct snd_tea575x_ops {
-	void (*write)(struct snd_tea575x *tea, unsigned int val);
-	unsigned int (*read)(struct snd_tea575x *tea);
-	void (*mute)(struct snd_tea575x *tea, unsigned int mute);
+	void (*set_pins)(struct snd_tea575x *tea, u8 pins);
+	u8 (*get_pins)(struct snd_tea575x *tea);
+	void (*set_direction)(struct snd_tea575x *tea, bool output);
 };
 };
 
 
 struct snd_tea575x {
 struct snd_tea575x {
-	struct snd_card *card;
 	struct video_device *vd;	/* video device */
 	struct video_device *vd;	/* video device */
-	int dev_nr;			/* requested device number + 1 */
-	int tea5759;			/* 5759 chip is present */
-	int mute;			/* Device is muted? */
-	unsigned int freq_fixup;	/* crystal onboard */
+	bool tea5759;			/* 5759 chip is present */
+	bool mute;			/* Device is muted? */
+	bool stereo;			/* receiving stereo */
+	bool tuned;			/* tuned to a station */
 	unsigned int val;		/* hw value */
 	unsigned int val;		/* hw value */
 	unsigned long freq;		/* frequency */
 	unsigned long freq;		/* frequency */
 	unsigned long in_use;		/* set if the device is in use */
 	unsigned long in_use;		/* set if the device is in use */
 	struct snd_tea575x_ops *ops;
 	struct snd_tea575x_ops *ops;
 	void *private_data;
 	void *private_data;
+	u8 card[32];
+	u8 bus_info[32];
 };
 };
 
 
-void snd_tea575x_init(struct snd_tea575x *tea);
+int snd_tea575x_init(struct snd_tea575x *tea);
 void snd_tea575x_exit(struct snd_tea575x *tea);
 void snd_tea575x_exit(struct snd_tea575x *tea);
 
 
 #endif /* __SOUND_TEA575X_TUNER_H */
 #endif /* __SOUND_TEA575X_TUNER_H */

+ 1 - 1
include/sound/tlv320dac33-plat.h

@@ -1,7 +1,7 @@
 /*
 /*
  * Platform header for Texas Instruments TLV320DAC33 codec driver
  * Platform header for Texas Instruments TLV320DAC33 codec driver
  *
  *
- * Author:	Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * Copyright:   (C) 2009 Nokia Corporation
  * Copyright:   (C) 2009 Nokia Corporation
  *
  *

+ 1 - 1
include/sound/tpa6130a2-plat.h

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) Nokia Corporation
  * Copyright (C) Nokia Corporation
  *
  *
- * Written by Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * This program is free software; you can redistribute it and/or
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * modify it under the terms of the GNU General Public License

+ 55 - 0
include/sound/wm8915.h

@@ -0,0 +1,55 @@
+/*
+ * linux/sound/wm8915.h -- Platform data for WM8915
+ *
+ * Copyright 2011 Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_WM8903_H
+#define __LINUX_SND_WM8903_H
+
+enum wm8915_inmode {
+	WM8915_DIFFERRENTIAL_1 = 0,   /* IN1xP - IN1xN */
+	WM8915_INVERTING = 1,         /* IN1xN */
+	WM8915_NON_INVERTING = 2,     /* IN1xP */
+	WM8915_DIFFERENTIAL_2 = 3,    /* IN2xP - IN2xP */
+};
+
+/**
+ * ReTune Mobile configurations are specified with a label, sample
+ * rate and set of values to write (the enable bits will be ignored).
+ *
+ * Configurations are expected to be generated using the ReTune Mobile
+ * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8915_retune_mobile_config {
+	const char *name;
+	int rate;
+	u16 regs[20];
+};
+
+#define WM8915_SET_DEFAULT 0x10000
+
+struct wm8915_pdata {
+	int irq_flags;  /** Set IRQ trigger flags; default active low */
+
+	int ldo_ena;  /** GPIO for LDO1; -1 for none */
+
+	int micdet_def;  /** Default MICDET_SRC/HP1FB_SRC/MICD_BIAS */
+
+	enum wm8915_inmode inl_mode;
+	enum wm8915_inmode inr_mode;
+
+	u32 spkmute_seq;  /** Value for register 0x802 */
+
+	int gpio_base;
+	u32 gpio_default[5];
+
+	int num_retune_mobile_cfgs;
+	struct wm8915_retune_mobile_config *retune_mobile_cfgs;
+};
+
+#endif

+ 22 - 0
include/sound/wm8962.h

@@ -14,6 +14,28 @@
 /* Use to set GPIO default values to zero */
 /* Use to set GPIO default values to zero */
 #define WM8962_GPIO_SET 0x10000
 #define WM8962_GPIO_SET 0x10000
 
 
+#define WM8962_GPIO_FN_CLKOUT           0
+#define WM8962_GPIO_FN_LOGIC            1
+#define WM8962_GPIO_FN_SDOUT            2
+#define WM8962_GPIO_FN_IRQ              3
+#define WM8962_GPIO_FN_THERMAL          4
+#define WM8962_GPIO_FN_PLL2_LOCK        6
+#define WM8962_GPIO_FN_PLL3_LOCK        7
+#define WM8962_GPIO_FN_FLL_LOCK         9
+#define WM8962_GPIO_FN_DRC_ACT         10
+#define WM8962_GPIO_FN_WSEQ_DONE       11
+#define WM8962_GPIO_FN_ALC_NG_ACT      12
+#define WM8962_GPIO_FN_ALC_PEAK_LIMIT  13
+#define WM8962_GPIO_FN_ALC_SATURATION  14
+#define WM8962_GPIO_FN_ALC_LEVEL_THR   15
+#define WM8962_GPIO_FN_ALC_LEVEL_LOCK  16
+#define WM8962_GPIO_FN_FIFO_ERR        17
+#define WM8962_GPIO_FN_OPCLK           18
+#define WM8962_GPIO_FN_DMICCLK         19
+#define WM8962_GPIO_FN_DMICDAT         20
+#define WM8962_GPIO_FN_MICD            21
+#define WM8962_GPIO_FN_MICSCD          22
+
 struct wm8962_pdata {
 struct wm8962_pdata {
 	int gpio_base;
 	int gpio_base;
 	u32 gpio_init[WM8962_MAX_GPIO];
 	u32 gpio_init[WM8962_MAX_GPIO];

+ 64 - 0
sound/core/control.c

@@ -365,6 +365,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
 
 
 EXPORT_SYMBOL(snd_ctl_add);
 EXPORT_SYMBOL(snd_ctl_add);
 
 
+/**
+ * snd_ctl_replace - replace the control instance of the card
+ * @card: the card instance
+ * @kcontrol: the control instance to replace
+ * @add_on_replace: add the control if not already added
+ *
+ * Replaces the given control.  If the given control does not exist
+ * and the add_on_replace flag is set, the control is added.  If the
+ * control exists, it is destroyed first.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ *
+ * It frees automatically the control which cannot be added or replaced.
+ */
+int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
+		    bool add_on_replace)
+{
+	struct snd_ctl_elem_id id;
+	unsigned int idx;
+	struct snd_kcontrol *old;
+	int ret;
+
+	if (!kcontrol)
+		return -EINVAL;
+	if (snd_BUG_ON(!card || !kcontrol->info)) {
+		ret = -EINVAL;
+		goto error;
+	}
+	id = kcontrol->id;
+	down_write(&card->controls_rwsem);
+	old = snd_ctl_find_id(card, &id);
+	if (!old) {
+		if (add_on_replace)
+			goto add;
+		up_write(&card->controls_rwsem);
+		ret = -EINVAL;
+		goto error;
+	}
+	ret = snd_ctl_remove(card, old);
+	if (ret < 0) {
+		up_write(&card->controls_rwsem);
+		goto error;
+	}
+add:
+	if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
+		up_write(&card->controls_rwsem);
+		ret = -ENOMEM;
+		goto error;
+	}
+	list_add_tail(&kcontrol->list, &card->controls);
+	card->controls_count += kcontrol->count;
+	kcontrol->id.numid = card->last_numid + 1;
+	card->last_numid += kcontrol->count;
+	up_write(&card->controls_rwsem);
+	for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
+	return 0;
+
+error:
+	snd_ctl_free_one(kcontrol);
+	return ret;
+}
+EXPORT_SYMBOL(snd_ctl_replace);
+
 /**
 /**
  * snd_ctl_remove - remove the control from the card and release it
  * snd_ctl_remove - remove the control from the card and release it
  * @card: the card instance
  * @card: the card instance

+ 1 - 1
sound/core/init.c

@@ -514,7 +514,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid)
 	id = card->id;
 	id = card->id;
 	
 	
 	if (*id == '\0')
 	if (*id == '\0')
-		strcpy(id, "default");
+		strcpy(id, "Default");
 
 
 	while (1) {
 	while (1) {
 	      	if (loops-- == 0) {
 	      	if (loops-- == 0) {

+ 9 - 5
sound/core/pcm_lib.c

@@ -189,6 +189,7 @@ static void xrun(struct snd_pcm_substream *substream)
 #define XRUN_LOG_CNT	10
 #define XRUN_LOG_CNT	10
 
 
 struct hwptr_log_entry {
 struct hwptr_log_entry {
+	unsigned int in_interrupt;
 	unsigned long jiffies;
 	unsigned long jiffies;
 	snd_pcm_uframes_t pos;
 	snd_pcm_uframes_t pos;
 	snd_pcm_uframes_t period_size;
 	snd_pcm_uframes_t period_size;
@@ -204,7 +205,7 @@ struct snd_pcm_hwptr_log {
 };
 };
 
 
 static void xrun_log(struct snd_pcm_substream *substream,
 static void xrun_log(struct snd_pcm_substream *substream,
-		     snd_pcm_uframes_t pos)
+		     snd_pcm_uframes_t pos, int in_interrupt)
 {
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
 	struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
@@ -220,6 +221,7 @@ static void xrun_log(struct snd_pcm_substream *substream,
 			return;
 			return;
 	}
 	}
 	entry = &log->entries[log->idx];
 	entry = &log->entries[log->idx];
+	entry->in_interrupt = in_interrupt;
 	entry->jiffies = jiffies;
 	entry->jiffies = jiffies;
 	entry->pos = pos;
 	entry->pos = pos;
 	entry->period_size = runtime->period_size;
 	entry->period_size = runtime->period_size;
@@ -246,9 +248,11 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
 		entry = &log->entries[idx];
 		entry = &log->entries[idx];
 		if (entry->period_size == 0)
 		if (entry->period_size == 0)
 			break;
 			break;
-		snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, "
+		snd_printd("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
 			   "hwptr=%ld/%ld\n",
 			   "hwptr=%ld/%ld\n",
-			   name, entry->jiffies, (unsigned long)entry->pos,
+			   name, entry->in_interrupt ? "[Q] " : "",
+			   entry->jiffies,
+			   (unsigned long)entry->pos,
 			   (unsigned long)entry->period_size,
 			   (unsigned long)entry->period_size,
 			   (unsigned long)entry->buffer_size,
 			   (unsigned long)entry->buffer_size,
 			   (unsigned long)entry->old_hw_ptr,
 			   (unsigned long)entry->old_hw_ptr,
@@ -262,7 +266,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
 #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
 #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
 
 
 #define hw_ptr_error(substream, fmt, args...) do { } while (0)
 #define hw_ptr_error(substream, fmt, args...) do { } while (0)
-#define xrun_log(substream, pos)	do { } while (0)
+#define xrun_log(substream, pos, in_interrupt)	do { } while (0)
 #define xrun_log_show(substream)	do { } while (0)
 #define xrun_log_show(substream)	do { } while (0)
 
 
 #endif
 #endif
@@ -326,7 +330,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 	}
 	}
 	pos -= pos % runtime->min_align;
 	pos -= pos % runtime->min_align;
 	if (xrun_debug(substream, XRUN_DEBUG_LOG))
 	if (xrun_debug(substream, XRUN_DEBUG_LOG))
-		xrun_log(substream, pos);
+		xrun_log(substream, pos, in_interrupt);
 	hw_base = runtime->hw_ptr_base;
 	hw_base = runtime->hw_ptr_base;
 	new_hw_ptr = hw_base + pos;
 	new_hw_ptr = hw_base + pos;
 	if (in_interrupt) {
 	if (in_interrupt) {

+ 11 - 0
sound/firewire/Kconfig

@@ -22,4 +22,15 @@ config SND_FIREWIRE_SPEAKERS
 	  To compile this driver as a module, choose M here: the module
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-firewire-speakers.
 	  will be called snd-firewire-speakers.
 
 
+config SND_ISIGHT
+	tristate "Apple iSight microphone"
+	select SND_PCM
+	select SND_FIREWIRE_LIB
+	help
+	  Say Y here to include support for the front and rear microphones
+	  of the Apple iSight web camera.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-isight.
+
 endif # SND_FIREWIRE
 endif # SND_FIREWIRE

+ 2 - 0
sound/firewire/Makefile

@@ -1,6 +1,8 @@
 snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
 snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
 			 fcp.o cmp.o amdtp.o
 			 fcp.o cmp.o amdtp.o
 snd-firewire-speakers-objs := speakers.o
 snd-firewire-speakers-objs := speakers.o
+snd-isight-objs := isight.o
 
 
 obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
 obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
 obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o
 obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o
+obj-$(CONFIG_SND_ISIGHT) += snd-isight.o

+ 755 - 0
sound/firewire/isight.c

@@ -0,0 +1,755 @@
+/*
+ * Apple iSight audio driver
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "lib.h"
+#include "iso-resources.h"
+#include "packets-buffer.h"
+
+#define OUI_APPLE		0x000a27
+#define MODEL_APPLE_ISIGHT	0x000008
+#define SW_ISIGHT_AUDIO		0x000010
+
+#define REG_AUDIO_ENABLE	0x000
+#define  AUDIO_ENABLE		0x80000000
+#define REG_DEF_AUDIO_GAIN	0x204
+#define REG_GAIN_RAW_START	0x210
+#define REG_GAIN_RAW_END	0x214
+#define REG_GAIN_DB_START	0x218
+#define REG_GAIN_DB_END		0x21c
+#define REG_SAMPLE_RATE_INQUIRY	0x280
+#define REG_ISO_TX_CONFIG	0x300
+#define  SPEED_SHIFT		16
+#define REG_SAMPLE_RATE		0x400
+#define  RATE_48000		0x80000000
+#define REG_GAIN		0x500
+#define REG_MUTE		0x504
+
+#define MAX_FRAMES_PER_PACKET	475
+
+#define QUEUE_LENGTH		20
+
+struct isight {
+	struct snd_card *card;
+	struct fw_unit *unit;
+	struct fw_device *device;
+	u64 audio_base;
+	struct fw_address_handler iris_handler;
+	struct snd_pcm_substream *pcm;
+	struct mutex mutex;
+	struct iso_packets_buffer buffer;
+	struct fw_iso_resources resources;
+	struct fw_iso_context *context;
+	bool pcm_active;
+	bool pcm_running;
+	bool first_packet;
+	int packet_index;
+	u32 total_samples;
+	unsigned int buffer_pointer;
+	unsigned int period_counter;
+	s32 gain_min, gain_max;
+	unsigned int gain_tlv[4];
+};
+
+struct audio_payload {
+	__be32 sample_count;
+	__be32 signature;
+	__be32 sample_total;
+	__be32 reserved;
+	__be16 samples[2 * MAX_FRAMES_PER_PACKET];
+};
+
+MODULE_DESCRIPTION("iSight audio driver");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
+
+static struct fw_iso_packet audio_packet = {
+	.payload_length = sizeof(struct audio_payload),
+	.interrupt = 1,
+	.header_length = 4,
+};
+
+static void isight_update_pointers(struct isight *isight, unsigned int count)
+{
+	struct snd_pcm_runtime *runtime = isight->pcm->runtime;
+	unsigned int ptr;
+
+	smp_wmb(); /* update buffer data before buffer pointer */
+
+	ptr = isight->buffer_pointer;
+	ptr += count;
+	if (ptr >= runtime->buffer_size)
+		ptr -= runtime->buffer_size;
+	ACCESS_ONCE(isight->buffer_pointer) = ptr;
+
+	isight->period_counter += count;
+	if (isight->period_counter >= runtime->period_size) {
+		isight->period_counter -= runtime->period_size;
+		snd_pcm_period_elapsed(isight->pcm);
+	}
+}
+
+static void isight_samples(struct isight *isight,
+			   const __be16 *samples, unsigned int count)
+{
+	struct snd_pcm_runtime *runtime;
+	unsigned int count1;
+
+	if (!ACCESS_ONCE(isight->pcm_running))
+		return;
+
+	runtime = isight->pcm->runtime;
+	if (isight->buffer_pointer + count <= runtime->buffer_size) {
+		memcpy(runtime->dma_area + isight->buffer_pointer * 4,
+		       samples, count * 4);
+	} else {
+		count1 = runtime->buffer_size - isight->buffer_pointer;
+		memcpy(runtime->dma_area + isight->buffer_pointer * 4,
+		       samples, count1 * 4);
+		samples += count1 * 2;
+		memcpy(runtime->dma_area, samples, (count - count1) * 4);
+	}
+
+	isight_update_pointers(isight, count);
+}
+
+static void isight_pcm_abort(struct isight *isight)
+{
+	unsigned long flags;
+
+	if (ACCESS_ONCE(isight->pcm_active)) {
+		snd_pcm_stream_lock_irqsave(isight->pcm, flags);
+		if (snd_pcm_running(isight->pcm))
+			snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN);
+		snd_pcm_stream_unlock_irqrestore(isight->pcm, flags);
+	}
+}
+
+static void isight_dropped_samples(struct isight *isight, unsigned int total)
+{
+	struct snd_pcm_runtime *runtime;
+	u32 dropped;
+	unsigned int count1;
+
+	if (!ACCESS_ONCE(isight->pcm_running))
+		return;
+
+	runtime = isight->pcm->runtime;
+	dropped = total - isight->total_samples;
+	if (dropped < runtime->buffer_size) {
+		if (isight->buffer_pointer + dropped <= runtime->buffer_size) {
+			memset(runtime->dma_area + isight->buffer_pointer * 4,
+			       0, dropped * 4);
+		} else {
+			count1 = runtime->buffer_size - isight->buffer_pointer;
+			memset(runtime->dma_area + isight->buffer_pointer * 4,
+			       0, count1 * 4);
+			memset(runtime->dma_area, 0, (dropped - count1) * 4);
+		}
+		isight_update_pointers(isight, dropped);
+	} else {
+		isight_pcm_abort(isight);
+	}
+}
+
+static void isight_packet(struct fw_iso_context *context, u32 cycle,
+			  size_t header_length, void *header, void *data)
+{
+	struct isight *isight = data;
+	const struct audio_payload *payload;
+	unsigned int index, length, count, total;
+	int err;
+
+	if (isight->packet_index < 0)
+		return;
+	index = isight->packet_index;
+	payload = isight->buffer.packets[index].buffer;
+	length = be32_to_cpup(header) >> 16;
+
+	if (likely(length >= 16 &&
+		   payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) {
+		count = be32_to_cpu(payload->sample_count);
+		if (likely(count <= (length - 16) / 4)) {
+			total = be32_to_cpu(payload->sample_total);
+			if (unlikely(total != isight->total_samples)) {
+				if (!isight->first_packet)
+					isight_dropped_samples(isight, total);
+				isight->first_packet = false;
+				isight->total_samples = total;
+			}
+
+			isight_samples(isight, payload->samples, count);
+			isight->total_samples += count;
+		}
+	}
+
+	err = fw_iso_context_queue(isight->context, &audio_packet,
+				   &isight->buffer.iso_buffer,
+				   isight->buffer.packets[index].offset);
+	if (err < 0) {
+		dev_err(&isight->unit->device, "queueing error: %d\n", err);
+		isight_pcm_abort(isight);
+		isight->packet_index = -1;
+		return;
+	}
+
+	if (++index >= QUEUE_LENGTH)
+		index = 0;
+	isight->packet_index = index;
+}
+
+static int isight_connect(struct isight *isight)
+{
+	int ch, err, rcode, errors = 0;
+	__be32 value;
+
+retry_after_bus_reset:
+	ch = fw_iso_resources_allocate(&isight->resources,
+				       sizeof(struct audio_payload),
+				       isight->device->max_speed);
+	if (ch < 0) {
+		err = ch;
+		goto error;
+	}
+
+	value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT));
+	for (;;) {
+		rcode = fw_run_transaction(
+				isight->device->card,
+				TCODE_WRITE_QUADLET_REQUEST,
+				isight->device->node_id,
+				isight->resources.generation,
+				isight->device->max_speed,
+				isight->audio_base + REG_ISO_TX_CONFIG,
+				&value, 4);
+		if (rcode == RCODE_COMPLETE) {
+			return 0;
+		} else if (rcode == RCODE_GENERATION) {
+			fw_iso_resources_free(&isight->resources);
+			goto retry_after_bus_reset;
+		} else if (rcode_is_permanent_error(rcode) || ++errors >= 3) {
+			err = -EIO;
+			goto err_resources;
+		}
+		msleep(5);
+	}
+
+err_resources:
+	fw_iso_resources_free(&isight->resources);
+error:
+	return err;
+}
+
+static int isight_open(struct snd_pcm_substream *substream)
+{
+	static const struct snd_pcm_hardware hardware = {
+		.info = SNDRV_PCM_INFO_MMAP |
+			SNDRV_PCM_INFO_MMAP_VALID |
+			SNDRV_PCM_INFO_BATCH |
+			SNDRV_PCM_INFO_INTERLEAVED |
+			SNDRV_PCM_INFO_BLOCK_TRANSFER,
+		.formats = SNDRV_PCM_FMTBIT_S16_BE,
+		.rates = SNDRV_PCM_RATE_48000,
+		.rate_min = 48000,
+		.rate_max = 48000,
+		.channels_min = 2,
+		.channels_max = 2,
+		.buffer_bytes_max = 4 * 1024 * 1024,
+		.period_bytes_min = MAX_FRAMES_PER_PACKET * 4,
+		.period_bytes_max = 1024 * 1024,
+		.periods_min = 2,
+		.periods_max = UINT_MAX,
+	};
+	struct isight *isight = substream->private_data;
+
+	substream->runtime->hw = hardware;
+
+	return iso_packets_buffer_init(&isight->buffer, isight->unit,
+				       QUEUE_LENGTH,
+				       sizeof(struct audio_payload),
+				       DMA_FROM_DEVICE);
+}
+
+static int isight_close(struct snd_pcm_substream *substream)
+{
+	struct isight *isight = substream->private_data;
+
+	iso_packets_buffer_destroy(&isight->buffer, isight->unit);
+
+	return 0;
+}
+
+static int isight_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *hw_params)
+{
+	struct isight *isight = substream->private_data;
+	int err;
+
+	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+					       params_buffer_bytes(hw_params));
+	if (err < 0)
+		return err;
+
+	ACCESS_ONCE(isight->pcm_active) = true;
+
+	return 0;
+}
+
+static int reg_read(struct isight *isight, int offset, __be32 *value)
+{
+	return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
+				  isight->audio_base + offset, value, 4);
+}
+
+static int reg_write(struct isight *isight, int offset, __be32 value)
+{
+	return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
+				  isight->audio_base + offset, &value, 4);
+}
+
+static void isight_stop_streaming(struct isight *isight)
+{
+	if (!isight->context)
+		return;
+
+	fw_iso_context_stop(isight->context);
+	fw_iso_context_destroy(isight->context);
+	isight->context = NULL;
+	fw_iso_resources_free(&isight->resources);
+	reg_write(isight, REG_AUDIO_ENABLE, 0);
+}
+
+static int isight_hw_free(struct snd_pcm_substream *substream)
+{
+	struct isight *isight = substream->private_data;
+
+	ACCESS_ONCE(isight->pcm_active) = false;
+
+	mutex_lock(&isight->mutex);
+	isight_stop_streaming(isight);
+	mutex_unlock(&isight->mutex);
+
+	return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int isight_start_streaming(struct isight *isight)
+{
+	unsigned int i;
+	int err;
+
+	if (isight->context) {
+		if (isight->packet_index < 0)
+			isight_stop_streaming(isight);
+		else
+			return 0;
+	}
+
+	err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000));
+	if (err < 0)
+		goto error;
+
+	err = isight_connect(isight);
+	if (err < 0)
+		goto error;
+
+	err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE));
+	if (err < 0)
+		goto err_resources;
+
+	isight->context = fw_iso_context_create(isight->device->card,
+						FW_ISO_CONTEXT_RECEIVE,
+						isight->resources.channel,
+						isight->device->max_speed,
+						4, isight_packet, isight);
+	if (IS_ERR(isight->context)) {
+		err = PTR_ERR(isight->context);
+		isight->context = NULL;
+		goto err_resources;
+	}
+
+	for (i = 0; i < QUEUE_LENGTH; ++i) {
+		err = fw_iso_context_queue(isight->context, &audio_packet,
+					   &isight->buffer.iso_buffer,
+					   isight->buffer.packets[i].offset);
+		if (err < 0)
+			goto err_context;
+	}
+
+	isight->first_packet = true;
+	isight->packet_index = 0;
+
+	err = fw_iso_context_start(isight->context, -1, 0,
+				   FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/);
+	if (err < 0)
+		goto err_context;
+
+	return 0;
+
+err_context:
+	fw_iso_context_destroy(isight->context);
+	isight->context = NULL;
+err_resources:
+	fw_iso_resources_free(&isight->resources);
+	reg_write(isight, REG_AUDIO_ENABLE, 0);
+error:
+	return err;
+}
+
+static int isight_prepare(struct snd_pcm_substream *substream)
+{
+	struct isight *isight = substream->private_data;
+	int err;
+
+	isight->buffer_pointer = 0;
+	isight->period_counter = 0;
+
+	mutex_lock(&isight->mutex);
+	err = isight_start_streaming(isight);
+	mutex_unlock(&isight->mutex);
+
+	return err;
+}
+
+static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct isight *isight = substream->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		ACCESS_ONCE(isight->pcm_running) = true;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		ACCESS_ONCE(isight->pcm_running) = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream)
+{
+	struct isight *isight = substream->private_data;
+
+	return ACCESS_ONCE(isight->buffer_pointer);
+}
+
+static int isight_create_pcm(struct isight *isight)
+{
+	static struct snd_pcm_ops ops = {
+		.open      = isight_open,
+		.close     = isight_close,
+		.ioctl     = snd_pcm_lib_ioctl,
+		.hw_params = isight_hw_params,
+		.hw_free   = isight_hw_free,
+		.prepare   = isight_prepare,
+		.trigger   = isight_trigger,
+		.pointer   = isight_pointer,
+		.page      = snd_pcm_lib_get_vmalloc_page,
+		.mmap      = snd_pcm_lib_mmap_vmalloc,
+	};
+	struct snd_pcm *pcm;
+	int err;
+
+	err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm);
+	if (err < 0)
+		return err;
+	pcm->private_data = isight;
+	strcpy(pcm->name, "iSight");
+	isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+	isight->pcm->ops = &ops;
+
+	return 0;
+}
+
+static int isight_gain_info(struct snd_kcontrol *ctl,
+			    struct snd_ctl_elem_info *info)
+{
+	struct isight *isight = ctl->private_data;
+
+	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	info->count = 1;
+	info->value.integer.min = isight->gain_min;
+	info->value.integer.max = isight->gain_max;
+
+	return 0;
+}
+
+static int isight_gain_get(struct snd_kcontrol *ctl,
+			   struct snd_ctl_elem_value *value)
+{
+	struct isight *isight = ctl->private_data;
+	__be32 gain;
+	int err;
+
+	err = reg_read(isight, REG_GAIN, &gain);
+	if (err < 0)
+		return err;
+
+	value->value.integer.value[0] = (s32)be32_to_cpu(gain);
+
+	return 0;
+}
+
+static int isight_gain_put(struct snd_kcontrol *ctl,
+			   struct snd_ctl_elem_value *value)
+{
+	struct isight *isight = ctl->private_data;
+
+	if (value->value.integer.value[0] < isight->gain_min ||
+	    value->value.integer.value[0] > isight->gain_max)
+		return -EINVAL;
+
+	return reg_write(isight, REG_GAIN,
+			 cpu_to_be32(value->value.integer.value[0]));
+}
+
+static int isight_mute_get(struct snd_kcontrol *ctl,
+			   struct snd_ctl_elem_value *value)
+{
+	struct isight *isight = ctl->private_data;
+	__be32 mute;
+	int err;
+
+	err = reg_read(isight, REG_MUTE, &mute);
+	if (err < 0)
+		return err;
+
+	value->value.integer.value[0] = !mute;
+
+	return 0;
+}
+
+static int isight_mute_put(struct snd_kcontrol *ctl,
+			   struct snd_ctl_elem_value *value)
+{
+	struct isight *isight = ctl->private_data;
+
+	return reg_write(isight, REG_MUTE,
+			 (__force __be32)!value->value.integer.value[0]);
+}
+
+static int isight_create_mixer(struct isight *isight)
+{
+	static const struct snd_kcontrol_new gain_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic Capture Volume",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+		.info = isight_gain_info,
+		.get = isight_gain_get,
+		.put = isight_gain_put,
+	};
+	static const struct snd_kcontrol_new mute_control = {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic Capture Switch",
+		.info = snd_ctl_boolean_mono_info,
+		.get = isight_mute_get,
+		.put = isight_mute_put,
+	};
+	__be32 value;
+	struct snd_kcontrol *ctl;
+	int err;
+
+	err = reg_read(isight, REG_GAIN_RAW_START, &value);
+	if (err < 0)
+		return err;
+	isight->gain_min = be32_to_cpu(value);
+
+	err = reg_read(isight, REG_GAIN_RAW_END, &value);
+	if (err < 0)
+		return err;
+	isight->gain_max = be32_to_cpu(value);
+
+	isight->gain_tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX;
+	isight->gain_tlv[1] = 2 * sizeof(unsigned int);
+
+	err = reg_read(isight, REG_GAIN_DB_START, &value);
+	if (err < 0)
+		return err;
+	isight->gain_tlv[2] = (s32)be32_to_cpu(value) * 100;
+
+	err = reg_read(isight, REG_GAIN_DB_END, &value);
+	if (err < 0)
+		return err;
+	isight->gain_tlv[3] = (s32)be32_to_cpu(value) * 100;
+
+	ctl = snd_ctl_new1(&gain_control, isight);
+	if (ctl)
+		ctl->tlv.p = isight->gain_tlv;
+	err = snd_ctl_add(isight->card, ctl);
+	if (err < 0)
+		return err;
+
+	err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static void isight_card_free(struct snd_card *card)
+{
+	struct isight *isight = card->private_data;
+
+	fw_iso_resources_destroy(&isight->resources);
+	fw_unit_put(isight->unit);
+	fw_device_put(isight->device);
+	mutex_destroy(&isight->mutex);
+}
+
+static u64 get_unit_base(struct fw_unit *unit)
+{
+	struct fw_csr_iterator i;
+	int key, value;
+
+	fw_csr_iterator_init(&i, unit->directory);
+	while (fw_csr_iterator_next(&i, &key, &value))
+		if (key == CSR_OFFSET)
+			return CSR_REGISTER_BASE + value * 4;
+	return 0;
+}
+
+static int isight_probe(struct device *unit_dev)
+{
+	struct fw_unit *unit = fw_unit(unit_dev);
+	struct fw_device *fw_dev = fw_parent_device(unit);
+	struct snd_card *card;
+	struct isight *isight;
+	int err;
+
+	err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card);
+	if (err < 0)
+		return err;
+	snd_card_set_dev(card, unit_dev);
+
+	isight = card->private_data;
+	isight->card = card;
+	mutex_init(&isight->mutex);
+	isight->unit = fw_unit_get(unit);
+	isight->device = fw_device_get(fw_dev);
+	isight->audio_base = get_unit_base(unit);
+	if (!isight->audio_base) {
+		dev_err(&unit->device, "audio unit base not found\n");
+		err = -ENXIO;
+		goto err_unit;
+	}
+	fw_iso_resources_init(&isight->resources, unit);
+
+	card->private_free = isight_card_free;
+
+	strcpy(card->driver, "iSight");
+	strcpy(card->shortname, "Apple iSight");
+	snprintf(card->longname, sizeof(card->longname),
+		 "Apple iSight (GUID %08x%08x) at %s, S%d",
+		 fw_dev->config_rom[3], fw_dev->config_rom[4],
+		 dev_name(&unit->device), 100 << fw_dev->max_speed);
+	strcpy(card->mixername, "iSight");
+
+	err = isight_create_pcm(isight);
+	if (err < 0)
+		goto error;
+
+	err = isight_create_mixer(isight);
+	if (err < 0)
+		goto error;
+
+	err = snd_card_register(card);
+	if (err < 0)
+		goto error;
+
+	dev_set_drvdata(unit_dev, isight);
+
+	return 0;
+
+err_unit:
+	fw_unit_put(isight->unit);
+	fw_device_put(isight->device);
+	mutex_destroy(&isight->mutex);
+error:
+	snd_card_free(card);
+	return err;
+}
+
+static int isight_remove(struct device *dev)
+{
+	struct isight *isight = dev_get_drvdata(dev);
+
+	isight_pcm_abort(isight);
+
+	snd_card_disconnect(isight->card);
+
+	mutex_lock(&isight->mutex);
+	isight_stop_streaming(isight);
+	mutex_unlock(&isight->mutex);
+
+	snd_card_free_when_closed(isight->card);
+
+	return 0;
+}
+
+static void isight_bus_reset(struct fw_unit *unit)
+{
+	struct isight *isight = dev_get_drvdata(&unit->device);
+
+	if (fw_iso_resources_update(&isight->resources) < 0) {
+		isight_pcm_abort(isight);
+
+		mutex_lock(&isight->mutex);
+		isight_stop_streaming(isight);
+		mutex_unlock(&isight->mutex);
+	}
+}
+
+static const struct ieee1394_device_id isight_id_table[] = {
+	{
+		.match_flags  = IEEE1394_MATCH_SPECIFIER_ID |
+				IEEE1394_MATCH_VERSION,
+		.specifier_id = OUI_APPLE,
+		.version      = SW_ISIGHT_AUDIO,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(ieee1394, isight_id_table);
+
+static struct fw_driver isight_driver = {
+	.driver   = {
+		.owner	= THIS_MODULE,
+		.name	= KBUILD_MODNAME,
+		.bus	= &fw_bus_type,
+		.probe	= isight_probe,
+		.remove	= isight_remove,
+	},
+	.update   = isight_bus_reset,
+	.id_table = isight_id_table,
+};
+
+static int __init alsa_isight_init(void)
+{
+	return driver_register(&isight_driver.driver);
+}
+
+static void __exit alsa_isight_exit(void)
+{
+	driver_unregister(&isight_driver.driver);
+}
+
+module_init(alsa_isight_init);
+module_exit(alsa_isight_exit);

+ 5 - 0
sound/firewire/iso-resources.c

@@ -31,6 +31,7 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
 
 
 	return 0;
 	return 0;
 }
 }
+EXPORT_SYMBOL(fw_iso_resources_init);
 
 
 /**
 /**
  * fw_iso_resources_destroy - destroy a resource manager
  * fw_iso_resources_destroy - destroy a resource manager
@@ -42,6 +43,7 @@ void fw_iso_resources_destroy(struct fw_iso_resources *r)
 	mutex_destroy(&r->mutex);
 	mutex_destroy(&r->mutex);
 	fw_unit_put(r->unit);
 	fw_unit_put(r->unit);
 }
 }
+EXPORT_SYMBOL(fw_iso_resources_destroy);
 
 
 static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed)
 static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed)
 {
 {
@@ -146,6 +148,7 @@ retry_after_bus_reset:
 
 
 	return channel;
 	return channel;
 }
 }
+EXPORT_SYMBOL(fw_iso_resources_allocate);
 
 
 /**
 /**
  * fw_iso_resources_update - update resource allocations after a bus reset
  * fw_iso_resources_update - update resource allocations after a bus reset
@@ -197,6 +200,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r)
 
 
 	return channel;
 	return channel;
 }
 }
+EXPORT_SYMBOL(fw_iso_resources_update);
 
 
 /**
 /**
  * fw_iso_resources_free - frees allocated resources
  * fw_iso_resources_free - frees allocated resources
@@ -224,3 +228,4 @@ void fw_iso_resources_free(struct fw_iso_resources *r)
 
 
 	mutex_unlock(&r->mutex);
 	mutex_unlock(&r->mutex);
 }
 }
+EXPORT_SYMBOL(fw_iso_resources_free);

+ 2 - 0
sound/firewire/packets-buffer.c

@@ -60,6 +60,7 @@ err_packets:
 error:
 error:
 	return err;
 	return err;
 }
 }
+EXPORT_SYMBOL(iso_packets_buffer_init);
 
 
 /**
 /**
  * iso_packets_buffer_destroy - frees packet buffer resources
  * iso_packets_buffer_destroy - frees packet buffer resources
@@ -72,3 +73,4 @@ void iso_packets_buffer_destroy(struct iso_packets_buffer *b,
 	fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card);
 	fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card);
 	kfree(b->packets);
 	kfree(b->packets);
 }
 }
+EXPORT_SYMBOL(iso_packets_buffer_destroy);

+ 1 - 1
sound/i2c/other/Makefile

@@ -14,4 +14,4 @@ snd-tea575x-tuner-objs := tea575x-tuner.o
 obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
 obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
 obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
 obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
 obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o
 obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o
-obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
+obj-$(CONFIG_SND_TEA575X) += snd-tea575x-tuner.o

+ 112 - 41
sound/i2c/other/tea575x-tuner.c

@@ -37,8 +37,8 @@ static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 module_param(radio_nr, int, 0);
 
 
 #define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
 #define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-#define FREQ_LO		 (87 * 16000)
-#define FREQ_HI		(108 * 16000)
+#define FREQ_LO		 (50UL * 16000)
+#define FREQ_HI		(150UL * 16000)
 
 
 /*
 /*
  * definitions
  * definitions
@@ -77,27 +77,95 @@ static struct v4l2_queryctrl radio_qctrl[] = {
  * lowlevel part
  * lowlevel part
  */
  */
 
 
+static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val)
+{
+	u16 l;
+	u8 data;
+
+	tea->ops->set_direction(tea, 1);
+	udelay(16);
+
+	for (l = 25; l > 0; l--) {
+		data = (val >> 24) & TEA575X_DATA;
+		val <<= 1;			/* shift data */
+		tea->ops->set_pins(tea, data | TEA575X_WREN);
+		udelay(2);
+		tea->ops->set_pins(tea, data | TEA575X_WREN | TEA575X_CLK);
+		udelay(2);
+		tea->ops->set_pins(tea, data | TEA575X_WREN);
+		udelay(2);
+	}
+
+	if (!tea->mute)
+		tea->ops->set_pins(tea, 0);
+}
+
+static unsigned int snd_tea575x_read(struct snd_tea575x *tea)
+{
+	u16 l, rdata;
+	u32 data = 0;
+
+	tea->ops->set_direction(tea, 0);
+	tea->ops->set_pins(tea, 0);
+	udelay(16);
+
+	for (l = 24; l--;) {
+		tea->ops->set_pins(tea, TEA575X_CLK);
+		udelay(2);
+		if (!l)
+			tea->tuned = tea->ops->get_pins(tea) & TEA575X_MOST ? 0 : 1;
+		tea->ops->set_pins(tea, 0);
+		udelay(2);
+		data <<= 1;			/* shift data */
+		rdata = tea->ops->get_pins(tea);
+		if (!l)
+			tea->stereo = (rdata & TEA575X_MOST) ?  0 : 1;
+		if (rdata & TEA575X_DATA)
+			data++;
+		udelay(2);
+	}
+
+	if (tea->mute)
+		tea->ops->set_pins(tea, TEA575X_WREN);
+
+	return data;
+}
+
+static void snd_tea575x_get_freq(struct snd_tea575x *tea)
+{
+	unsigned long freq;
+
+	freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
+	/* freq *= 12.5 */
+	freq *= 125;
+	freq /= 10;
+	/* crystal fixup */
+	if (tea->tea5759)
+		freq += TEA575X_FMIF;
+	else
+		freq -= TEA575X_FMIF;
+
+	tea->freq = freq * 16;		/* from kHz */
+}
+
 static void snd_tea575x_set_freq(struct snd_tea575x *tea)
 static void snd_tea575x_set_freq(struct snd_tea575x *tea)
 {
 {
 	unsigned long freq;
 	unsigned long freq;
 
 
-	freq = tea->freq / 16;		/* to kHz */
-	if (freq > 108000)
-		freq = 108000;
-	if (freq < 87000)
-		freq = 87000;
+	freq = clamp(tea->freq, FREQ_LO, FREQ_HI);
+	freq /= 16;		/* to kHz */
 	/* crystal fixup */
 	/* crystal fixup */
 	if (tea->tea5759)
 	if (tea->tea5759)
-		freq -= tea->freq_fixup;
+		freq -= TEA575X_FMIF;
 	else
 	else
-		freq += tea->freq_fixup;
+		freq += TEA575X_FMIF;
 	/* freq /= 12.5 */
 	/* freq /= 12.5 */
 	freq *= 10;
 	freq *= 10;
 	freq /= 125;
 	freq /= 125;
 
 
 	tea->val &= ~TEA575X_BIT_FREQ_MASK;
 	tea->val &= ~TEA575X_BIT_FREQ_MASK;
 	tea->val |= freq & TEA575X_BIT_FREQ_MASK;
 	tea->val |= freq & TEA575X_BIT_FREQ_MASK;
-	tea->ops->write(tea, tea->val);
+	snd_tea575x_write(tea, tea->val);
 }
 }
 
 
 /*
 /*
@@ -109,29 +177,34 @@ static int vidioc_querycap(struct file *file, void  *priv,
 {
 {
 	struct snd_tea575x *tea = video_drvdata(file);
 	struct snd_tea575x *tea = video_drvdata(file);
 
 
-	strcpy(v->card, tea->tea5759 ? "TEA5759" : "TEA5757");
 	strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver));
 	strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver));
-	strlcpy(v->card, "Maestro Radio", sizeof(v->card));
-	sprintf(v->bus_info, "PCI");
+	strlcpy(v->card, tea->card, sizeof(v->card));
+	strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
+	strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
 	v->version = RADIO_VERSION;
 	v->version = RADIO_VERSION;
-	v->capabilities = V4L2_CAP_TUNER;
+	v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 	return 0;
 	return 0;
 }
 }
 
 
 static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
 					struct v4l2_tuner *v)
 					struct v4l2_tuner *v)
 {
 {
+	struct snd_tea575x *tea = video_drvdata(file);
+
 	if (v->index > 0)
 	if (v->index > 0)
 		return -EINVAL;
 		return -EINVAL;
 
 
+	snd_tea575x_read(tea);
+
 	strcpy(v->name, "FM");
 	strcpy(v->name, "FM");
 	v->type = V4L2_TUNER_RADIO;
 	v->type = V4L2_TUNER_RADIO;
+	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
 	v->rangelow = FREQ_LO;
 	v->rangelow = FREQ_LO;
 	v->rangehigh = FREQ_HI;
 	v->rangehigh = FREQ_HI;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xffff;
+	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+	v->signal = tea->tuned ? 0xffff : 0;
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -148,7 +221,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
 {
 	struct snd_tea575x *tea = video_drvdata(file);
 	struct snd_tea575x *tea = video_drvdata(file);
 
 
+	if (f->tuner != 0)
+		return -EINVAL;
 	f->type = V4L2_TUNER_RADIO;
 	f->type = V4L2_TUNER_RADIO;
+	snd_tea575x_get_freq(tea);
 	f->frequency = tea->freq;
 	f->frequency = tea->freq;
 	return 0;
 	return 0;
 }
 }
@@ -158,6 +234,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 {
 	struct snd_tea575x *tea = video_drvdata(file);
 	struct snd_tea575x *tea = video_drvdata(file);
 
 
+	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
+
 	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
 	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
 		return -EINVAL;
 		return -EINVAL;
 
 
@@ -209,10 +288,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 
 
 	switch (ctrl->id) {
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 	case V4L2_CID_AUDIO_MUTE:
-		if (tea->ops->mute) {
-			ctrl->value = tea->mute;
-			return 0;
-		}
+		ctrl->value = tea->mute;
+		return 0;
 	}
 	}
 	return -EINVAL;
 	return -EINVAL;
 }
 }
@@ -224,11 +301,11 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
 
 	switch (ctrl->id) {
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 	case V4L2_CID_AUDIO_MUTE:
-		if (tea->ops->mute) {
-			tea->ops->mute(tea, ctrl->value);
+		if (tea->mute != ctrl->value) {
 			tea->mute = ctrl->value;
 			tea->mute = ctrl->value;
-			return 0;
+			snd_tea575x_set_freq(tea);
 		}
 		}
+		return 0;
 	}
 	}
 	return -EINVAL;
 	return -EINVAL;
 }
 }
@@ -293,18 +370,16 @@ static struct video_device tea575x_radio = {
 /*
 /*
  * initialize all the tea575x chips
  * initialize all the tea575x chips
  */
  */
-void snd_tea575x_init(struct snd_tea575x *tea)
+int snd_tea575x_init(struct snd_tea575x *tea)
 {
 {
 	int retval;
 	int retval;
-	unsigned int val;
 	struct video_device *tea575x_radio_inst;
 	struct video_device *tea575x_radio_inst;
 
 
-	val = tea->ops->read(tea);
-	if (val == 0x1ffffff || val == 0) {
-		snd_printk(KERN_ERR
-			   "tea575x-tuner: Cannot find TEA575x chip\n");
-		return;
-	}
+	tea->mute = 1;
+
+	snd_tea575x_write(tea, 0x55AA);
+	if (snd_tea575x_read(tea) != 0x55AA)
+		return -ENODEV;
 
 
 	tea->in_use = 0;
 	tea->in_use = 0;
 	tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
 	tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
@@ -313,7 +388,7 @@ void snd_tea575x_init(struct snd_tea575x *tea)
 	tea575x_radio_inst = video_device_alloc();
 	tea575x_radio_inst = video_device_alloc();
 	if (tea575x_radio_inst == NULL) {
 	if (tea575x_radio_inst == NULL) {
 		printk(KERN_ERR "tea575x-tuner: not enough memory\n");
 		printk(KERN_ERR "tea575x-tuner: not enough memory\n");
-		return;
+		return -ENOMEM;
 	}
 	}
 
 
 	memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
 	memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
@@ -328,17 +403,13 @@ void snd_tea575x_init(struct snd_tea575x *tea)
 	if (retval) {
 	if (retval) {
 		printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
 		printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
 		kfree(tea575x_radio_inst);
 		kfree(tea575x_radio_inst);
-		return;
+		return retval;
 	}
 	}
 
 
 	snd_tea575x_set_freq(tea);
 	snd_tea575x_set_freq(tea);
-
-	/* mute on init */
-	if (tea->ops->mute) {
-		tea->ops->mute(tea, 1);
-		tea->mute = 1;
-	}
 	tea->vd = tea575x_radio_inst;
 	tea->vd = tea575x_radio_inst;
+
+	return 0;
 }
 }
 
 
 void snd_tea575x_exit(struct snd_tea575x *tea)
 void snd_tea575x_exit(struct snd_tea575x *tea)

+ 0 - 4
sound/oss/Kconfig

@@ -22,10 +22,6 @@ config SOUND_VWSND
 	  <file:Documentation/sound/oss/vwsnd> for more info on this driver's
 	  <file:Documentation/sound/oss/vwsnd> for more info on this driver's
 	  capabilities.
 	  capabilities.
 
 
-config SOUND_AU1550_AC97
-	tristate "Au1550/Au1200 AC97 Sound"
-	depends on SOC_AU1550 || SOC_AU1200
-
 config SOUND_MSNDCLAS
 config SOUND_MSNDCLAS
 	tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
 	tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
 	depends on (m || !STANDALONE) && ISA
 	depends on (m || !STANDALONE) && ISA

+ 0 - 1
sound/oss/Makefile

@@ -25,7 +25,6 @@ obj-$(CONFIG_SOUND_WAVEARTIST)	+= waveartist.o
 obj-$(CONFIG_SOUND_MSNDCLAS)	+= msnd.o msnd_classic.o
 obj-$(CONFIG_SOUND_MSNDCLAS)	+= msnd.o msnd_classic.o
 obj-$(CONFIG_SOUND_MSNDPIN)	+= msnd.o msnd_pinnacle.o
 obj-$(CONFIG_SOUND_MSNDPIN)	+= msnd.o msnd_pinnacle.o
 obj-$(CONFIG_SOUND_VWSND)	+= vwsnd.o
 obj-$(CONFIG_SOUND_VWSND)	+= vwsnd.o
-obj-$(CONFIG_SOUND_AU1550_AC97)	+= au1550_ac97.o ac97_codec.o
 obj-$(CONFIG_SOUND_BCM_CS4297A)	+= swarm_cs4297a.o
 obj-$(CONFIG_SOUND_BCM_CS4297A)	+= swarm_cs4297a.o
 
 
 obj-$(CONFIG_DMASOUND)		+= dmasound/
 obj-$(CONFIG_DMASOUND)		+= dmasound/

+ 0 - 1203
sound/oss/ac97_codec.c

@@ -1,1203 +0,0 @@
-/*
- * ac97_codec.c: Generic AC97 mixer/modem module
- *
- * Derived from ac97 mixer in maestro and trident driver.
- *
- * Copyright 2000 Silicon Integrated System Corporation
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You should have received a copy of the GNU General Public License
- *	along with this program; if not, write to the Free Software
- *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- **************************************************************************
- *
- * The Intel Audio Codec '97 specification is available at:
- * http://download.intel.com/support/motherboards/desktop/sb/ac97_r23.pdf
- *
- **************************************************************************
- *
- * History
- * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
- *	Removed non existent WM9700
- *	Added support for WM9705, WM9708, WM9709, WM9710, WM9711
- *	WM9712 and WM9717
- * Mar 28, 2002 Randolph Bentson <bentson@holmsjoen.com>
- *	corrections to support WM9707 in ViewPad 1000
- * v0.4 Mar 15 2000 Ollie Lho
- *	dual codecs support verified with 4 channels output
- * v0.3 Feb 22 2000 Ollie Lho
- *	bug fix for record mask setting
- * v0.2 Feb 10 2000 Ollie Lho
- *	add ac97_read_proc for /proc/driver/{vendor}/ac97
- * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw> 
- *	Isolated from trident.c to support multiple ac97 codec
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/ac97_codec.h>
-#include <asm/uaccess.h>
-#include <linux/mutex.h>
-
-#define CODEC_ID_BUFSZ 14
-
-static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
-static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, 
-			     unsigned int left, unsigned int right);
-static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val );
-static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
-static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
-
-static int ac97_init_mixer(struct ac97_codec *codec);
-
-static int wolfson_init03(struct ac97_codec * codec);
-static int wolfson_init04(struct ac97_codec * codec);
-static int wolfson_init05(struct ac97_codec * codec);
-static int wolfson_init11(struct ac97_codec * codec);
-static int wolfson_init13(struct ac97_codec * codec);
-static int tritech_init(struct ac97_codec * codec);
-static int tritech_maestro_init(struct ac97_codec * codec);
-static int sigmatel_9708_init(struct ac97_codec *codec);
-static int sigmatel_9721_init(struct ac97_codec *codec);
-static int sigmatel_9744_init(struct ac97_codec *codec);
-static int ad1886_init(struct ac97_codec *codec);
-static int eapd_control(struct ac97_codec *codec, int);
-static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-static int cmedia_init(struct ac97_codec * codec);
-static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-
-
-/*
- *	AC97 operations.
- *
- *	If you are adding a codec then you should be able to use
- *		eapd_ops - any codec that supports EAPD amp control (most)
- *		null_ops - any ancient codec that supports nothing
- *
- *	The three functions are
- *		init - used for non AC97 standard initialisation
- *		amplifier - used to do amplifier control (1=on 0=off)
- *		digital - switch to digital modes (0 = analog)
- *
- *	Not all codecs support all features, not all drivers use all the
- *	operations yet
- */
- 
-static struct ac97_ops null_ops = { NULL, NULL, NULL };
-static struct ac97_ops default_ops = { NULL, eapd_control, NULL };
-static struct ac97_ops default_digital_ops = { NULL, eapd_control, generic_digital_control};
-static struct ac97_ops wolfson_ops03 = { wolfson_init03, NULL, NULL };
-static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL };
-static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL };
-static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL };
-static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL };
-static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL };
-static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL };
-static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL };
-static struct ac97_ops sigmatel_9721_ops = { sigmatel_9721_init, NULL, NULL };
-static struct ac97_ops sigmatel_9744_ops = { sigmatel_9744_init, NULL, NULL };
-static struct ac97_ops crystal_digital_ops = { NULL, eapd_control, crystal_digital_control };
-static struct ac97_ops ad1886_ops = { ad1886_init, eapd_control, NULL };
-static struct ac97_ops cmedia_ops = { NULL, eapd_control, NULL};
-static struct ac97_ops cmedia_digital_ops = { cmedia_init, eapd_control, cmedia_digital_control};
-
-/* sorted by vendor/device id */
-static const struct {
-	u32 id;
-	char *name;
-	struct ac97_ops *ops;
-	int flags;
-} ac97_codec_ids[] = {
-	{0x41445303, "Analog Devices AD1819",	&null_ops},
-	{0x41445340, "Analog Devices AD1881",	&null_ops},
-	{0x41445348, "Analog Devices AD1881A",	&null_ops},
-	{0x41445360, "Analog Devices AD1885",	&default_ops},
-	{0x41445361, "Analog Devices AD1886",	&ad1886_ops},
-	{0x41445370, "Analog Devices AD1981",	&null_ops},
-	{0x41445372, "Analog Devices AD1981A",	&null_ops},
-	{0x41445374, "Analog Devices AD1981B",	&null_ops},
-	{0x41445460, "Analog Devices AD1885",	&default_ops},
-	{0x41445461, "Analog Devices AD1886",	&ad1886_ops},
-	{0x414B4D00, "Asahi Kasei AK4540",	&null_ops},
-	{0x414B4D01, "Asahi Kasei AK4542",	&null_ops},
-	{0x414B4D02, "Asahi Kasei AK4543",	&null_ops},
-	{0x414C4326, "ALC100P",			&null_ops},
-	{0x414C4710, "ALC200/200P",		&null_ops},
-	{0x414C4720, "ALC650",			&default_digital_ops},
-	{0x434D4941, "CMedia",			&cmedia_ops,		AC97_NO_PCM_VOLUME },
-	{0x434D4942, "CMedia",			&cmedia_ops,		AC97_NO_PCM_VOLUME },
-	{0x434D4961, "CMedia",			&cmedia_digital_ops,	AC97_NO_PCM_VOLUME },
-	{0x43525900, "Cirrus Logic CS4297",	&default_ops},
-	{0x43525903, "Cirrus Logic CS4297",	&default_ops},
-	{0x43525913, "Cirrus Logic CS4297A rev A", &default_ops},
-	{0x43525914, "Cirrus Logic CS4297A rev B", &default_ops},
-	{0x43525923, "Cirrus Logic CS4298",	&null_ops},
-	{0x4352592B, "Cirrus Logic CS4294",	&null_ops},
-	{0x4352592D, "Cirrus Logic CS4294",	&null_ops},
-	{0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops},
-	{0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops},
-	{0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops},
-	{0x43585430, "CXT48",			&default_ops,		AC97_DELUDED_MODEM },
-	{0x43585442, "CXT66",			&default_ops,		AC97_DELUDED_MODEM },
-	{0x44543031, "Diamond Technology DT0893", &default_ops},
-	{0x45838308, "ESS Allegro ES1988",	&null_ops},
-	{0x49434511, "ICE1232",			&null_ops}, /* I hope --jk */
-	{0x4e534331, "National Semiconductor LM4549", &null_ops},
-	{0x53494c22, "Silicon Laboratory Si3036", &null_ops},
-	{0x53494c23, "Silicon Laboratory Si3038", &null_ops},
-	{0x545200FF, "TriTech TR?????",		&tritech_m_ops},
-	{0x54524102, "TriTech TR28022",		&null_ops},
-	{0x54524103, "TriTech TR28023",		&null_ops},
-	{0x54524106, "TriTech TR28026",		&null_ops},
-	{0x54524108, "TriTech TR28028",		&tritech_ops},
-	{0x54524123, "TriTech TR A5",		&null_ops},
-	{0x574D4C03, "Wolfson WM9703/07/08/17",	&wolfson_ops03},
-	{0x574D4C04, "Wolfson WM9704M/WM9704Q",	&wolfson_ops04},
-	{0x574D4C05, "Wolfson WM9705/WM9710",   &wolfson_ops05},
-	{0x574D4C09, "Wolfson WM9709",		&null_ops},
-	{0x574D4C12, "Wolfson WM9711/9712",	&wolfson_ops11},
-	{0x574D4C13, "Wolfson WM9713",	&wolfson_ops13, AC97_DEFAULT_POWER_OFF},
-	{0x83847600, "SigmaTel STAC????",	&null_ops},
-	{0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops},
-	{0x83847605, "SigmaTel STAC9704",	&null_ops},
-	{0x83847608, "SigmaTel STAC9708",	&sigmatel_9708_ops},
-	{0x83847609, "SigmaTel STAC9721/23",	&sigmatel_9721_ops},
-	{0x83847644, "SigmaTel STAC9744/45",	&sigmatel_9744_ops},
-	{0x83847652, "SigmaTel STAC9752/53",	&default_ops},
-	{0x83847656, "SigmaTel STAC9756/57",	&sigmatel_9744_ops},
-	{0x83847666, "SigmaTel STAC9750T",	&sigmatel_9744_ops},
-	{0x83847684, "SigmaTel STAC9783/84?",	&null_ops},
-	{0x57454301, "Winbond 83971D",		&null_ops},
-};
-
-/* this table has default mixer values for all OSS mixers. */
-static struct mixer_defaults {
-	int mixer;
-	unsigned int value;
-} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
-	/* all values 0 -> 100 in bytes */
-	{SOUND_MIXER_VOLUME,	0x4343},
-	{SOUND_MIXER_BASS,	0x4343},
-	{SOUND_MIXER_TREBLE,	0x4343},
-	{SOUND_MIXER_PCM,	0x4343},
-	{SOUND_MIXER_SPEAKER,	0x4343},
-	{SOUND_MIXER_LINE,	0x4343},
-	{SOUND_MIXER_MIC,	0x0000},
-	{SOUND_MIXER_CD,	0x4343},
-	{SOUND_MIXER_ALTPCM,	0x4343},
-	{SOUND_MIXER_IGAIN,	0x4343},
-	{SOUND_MIXER_LINE1,	0x4343},
-	{SOUND_MIXER_PHONEIN,	0x4343},
-	{SOUND_MIXER_PHONEOUT,	0x4343},
-	{SOUND_MIXER_VIDEO,	0x4343},
-	{-1,0}
-};
-
-/* table to scale scale from OSS mixer value to AC97 mixer register value */	
-static struct ac97_mixer_hw {
-	unsigned char offset;
-	int scale;
-} ac97_hw[SOUND_MIXER_NRDEVICES]= {
-	[SOUND_MIXER_VOLUME]	=	{AC97_MASTER_VOL_STEREO,64},
-	[SOUND_MIXER_BASS]	=	{AC97_MASTER_TONE,	16},
-	[SOUND_MIXER_TREBLE]	=	{AC97_MASTER_TONE,	16},
-	[SOUND_MIXER_PCM]	=	{AC97_PCMOUT_VOL,	32},
-	[SOUND_MIXER_SPEAKER]	=	{AC97_PCBEEP_VOL,	16},
-	[SOUND_MIXER_LINE]	=	{AC97_LINEIN_VOL,	32},
-	[SOUND_MIXER_MIC]	=	{AC97_MIC_VOL,		32},
-	[SOUND_MIXER_CD]	=	{AC97_CD_VOL,		32},
-	[SOUND_MIXER_ALTPCM]	=	{AC97_HEADPHONE_VOL,	64},
-	[SOUND_MIXER_IGAIN]	=	{AC97_RECORD_GAIN,	16},
-	[SOUND_MIXER_LINE1]	=	{AC97_AUX_VOL,		32},
-	[SOUND_MIXER_PHONEIN]	= 	{AC97_PHONE_VOL,	32},
-	[SOUND_MIXER_PHONEOUT]	= 	{AC97_MASTER_VOL_MONO,	64},
-	[SOUND_MIXER_VIDEO]	=	{AC97_VIDEO_VOL,	32},
-};
-
-/* the following tables allow us to go from OSS <-> ac97 quickly. */
-enum ac97_recsettings {
-	AC97_REC_MIC=0,
-	AC97_REC_CD,
-	AC97_REC_VIDEO,
-	AC97_REC_AUX,
-	AC97_REC_LINE,
-	AC97_REC_STEREO, /* combination of all enabled outputs..  */
-	AC97_REC_MONO,	      /*.. or the mono equivalent */
-	AC97_REC_PHONE
-};
-
-static const unsigned int ac97_rm2oss[] = {
-	[AC97_REC_MIC] 	 = SOUND_MIXER_MIC,
-	[AC97_REC_CD] 	 = SOUND_MIXER_CD,
-	[AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
-	[AC97_REC_AUX] 	 = SOUND_MIXER_LINE1,
-	[AC97_REC_LINE]  = SOUND_MIXER_LINE,
-	[AC97_REC_STEREO]= SOUND_MIXER_IGAIN,
-	[AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
-};
-
-/* indexed by bit position */
-static const unsigned int ac97_oss_rm[] = {
-	[SOUND_MIXER_MIC] 	= AC97_REC_MIC,
-	[SOUND_MIXER_CD] 	= AC97_REC_CD,
-	[SOUND_MIXER_VIDEO] 	= AC97_REC_VIDEO,
-	[SOUND_MIXER_LINE1] 	= AC97_REC_AUX,
-	[SOUND_MIXER_LINE] 	= AC97_REC_LINE,
-	[SOUND_MIXER_IGAIN]	= AC97_REC_STEREO,
-	[SOUND_MIXER_PHONEIN] 	= AC97_REC_PHONE
-};
-
-static LIST_HEAD(codecs);
-static LIST_HEAD(codec_drivers);
-static DEFINE_MUTEX(codec_mutex);
-
-/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows
-   about that given mixer, and should be holding a spinlock for the card */
-static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) 
-{
-	u16 val;
-	int ret = 0;
-	int scale;
-	struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
-
-	val = codec->codec_read(codec , mh->offset);
-
-	if (val & AC97_MUTE) {
-		ret = 0;
-	} else if (AC97_STEREO_MASK & (1 << oss_channel)) {
-		/* nice stereo mixers .. */
-		int left,right;
-
-		left = (val >> 8)  & 0x7f;
-		right = val  & 0x7f;
-
-		if (oss_channel == SOUND_MIXER_IGAIN) {
-			right = (right * 100) / mh->scale;
-			left = (left * 100) / mh->scale;
-		} else {
-			/* these may have 5 or 6 bit resolution */
-			if(oss_channel == SOUND_MIXER_VOLUME || oss_channel == SOUND_MIXER_ALTPCM)
-				scale = (1 << codec->bit_resolution);
-			else
-				scale = mh->scale;
-
-			right = 100 - ((right * 100) / scale);
-			left = 100 - ((left * 100) / scale);
-		}
-		ret = left | (right << 8);
-	} else if (oss_channel == SOUND_MIXER_SPEAKER) {
-		ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
-	} else if (oss_channel == SOUND_MIXER_PHONEIN) {
-		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
-	} else if (oss_channel == SOUND_MIXER_PHONEOUT) {
-		scale = (1 << codec->bit_resolution);
-		ret = 100 - (((val & 0x1f) * 100) / scale);
-	} else if (oss_channel == SOUND_MIXER_MIC) {
-		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
-		/*  the low bit is optional in the tone sliders and masking
-		    it lets us avoid the 0xf 'bypass'.. */
-	} else if (oss_channel == SOUND_MIXER_BASS) {
-		ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
-	} else if (oss_channel == SOUND_MIXER_TREBLE) {
-		ret = 100 - (((val & 0xe) * 100) / mh->scale);
-	}
-
-#ifdef DEBUG
-	printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), "
-	       "0x%04x -> 0x%04x\n",
-	       oss_channel, codec->id ? "Secondary" : "Primary",
-	       mh->offset, val, ret);
-#endif
-
-	return ret;
-}
-
-/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to
-   make sure all is well in arg land, call with spinlock held */
-static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
-		      unsigned int left, unsigned int right)
-{
-	u16 val = 0;
-	int scale;
-	struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
-
-#ifdef DEBUG
-	printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), "
-	       "left vol:%2d, right vol:%2d:",
-	       oss_channel, codec->id ? "Secondary" : "Primary",
-	       mh->offset, left, right);
-#endif
-
-	if (AC97_STEREO_MASK & (1 << oss_channel)) {
-		/* stereo mixers */
-		if (left == 0 && right == 0) {
-			val = AC97_MUTE;
-		} else {
-			if (oss_channel == SOUND_MIXER_IGAIN) {
-				right = (right * mh->scale) / 100;
-				left = (left * mh->scale) / 100;
-				if (right >= mh->scale)
-					right = mh->scale-1;
-				if (left >= mh->scale)
-					left = mh->scale-1;
-			} else {
-				/* these may have 5 or 6 bit resolution */
-				if (oss_channel == SOUND_MIXER_VOLUME ||
-				    oss_channel == SOUND_MIXER_ALTPCM)
-					scale = (1 << codec->bit_resolution);
-				else
-					scale = mh->scale;
-
-				right = ((100 - right) * scale) / 100;
-				left = ((100 - left) * scale) / 100;
-				if (right >= scale)
-					right = scale-1;
-				if (left >= scale)
-					left = scale-1;
-			}
-			val = (left << 8) | right;
-		}
-	} else if (oss_channel == SOUND_MIXER_BASS) {
-		val = codec->codec_read(codec , mh->offset) & ~0x0f00;
-		left = ((100 - left) * mh->scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val |= (left << 8) & 0x0e00;
-	} else if (oss_channel == SOUND_MIXER_TREBLE) {
-		val = codec->codec_read(codec , mh->offset) & ~0x000f;
-		left = ((100 - left) * mh->scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val |= left & 0x000e;
-	} else if(left == 0) {
-		val = AC97_MUTE;
-	} else if (oss_channel == SOUND_MIXER_SPEAKER) {
-		left = ((100 - left) * mh->scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val = left << 1;
-	} else if (oss_channel == SOUND_MIXER_PHONEIN) {
-		left = ((100 - left) * mh->scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val = left;
-	} else if (oss_channel == SOUND_MIXER_PHONEOUT) {
-		scale = (1 << codec->bit_resolution);
-		left = ((100 - left) * scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val = left;
-	} else if (oss_channel == SOUND_MIXER_MIC) {
-		val = codec->codec_read(codec , mh->offset) & ~0x801f;
-		left = ((100 - left) * mh->scale) / 100;
-		if (left >= mh->scale)
-			left = mh->scale-1;
-		val |= left;
-		/*  the low bit is optional in the tone sliders and masking
-		    it lets us avoid the 0xf 'bypass'.. */
-	}
-#ifdef DEBUG
-	printk(" 0x%04x", val);
-#endif
-
-	codec->codec_write(codec, mh->offset, val);
-
-#ifdef DEBUG
-	val = codec->codec_read(codec, mh->offset);
-	printk(" -> 0x%04x\n", val);
-#endif
-}
-
-/* a thin wrapper for write_mixer */
-static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ) 
-{
-	unsigned int left,right;
-
-	/* cleanse input a little */
-	right = ((val >> 8)  & 0xff) ;
-	left = (val  & 0xff) ;
-
-	if (right > 100) right = 100;
-	if (left > 100) left = 100;
-
-	codec->mixer_state[oss_mixer] = (right << 8) | left;
-	codec->write_mixer(codec, oss_mixer, left, right);
-}
-
-/* read or write the recmask, the ac97 can really have left and right recording
-   inputs independently set, but OSS doesn't seem to want us to express that to
-   the user. the caller guarantees that we have a supported bit set, and they
-   must be holding the card's spinlock */
-static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask) 
-{
-	unsigned int val;
-
-	if (rw) {
-		/* read it from the card */
-		val = codec->codec_read(codec, AC97_RECORD_SELECT);
-#ifdef DEBUG
-		printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val);
-#endif
-		return (1 << ac97_rm2oss[val & 0x07]);
-	}
-
-	/* else, write the first set in the mask as the
-	   output */	
-	/* clear out current set value first (AC97 supports only 1 input!) */
-	val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT) & 0x07]);
-	if (mask != val)
-	    mask &= ~val;
-       
-	val = ffs(mask); 
-	val = ac97_oss_rm[val-1];
-	val |= val << 8;  /* set both channels */
-
-#ifdef DEBUG
-	printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val);
-#endif
-
-	codec->codec_write(codec, AC97_RECORD_SELECT, val);
-
-	return 0;
-};
-
-static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg)
-{
-	int i, val = 0;
-
-	if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, codec->name, sizeof(info.id));
-		strlcpy(info.name, codec->name, sizeof(info.name));
-		info.modify_counter = codec->modcnt;
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, codec->name, sizeof(info.id));
-		strlcpy(info.name, codec->name, sizeof(info.name));
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
-		return -EINVAL;
-
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, (int __user *)arg);
-
-	if (_SIOC_DIR(cmd) == _SIOC_READ) {
-		switch (_IOC_NR(cmd)) {
-		case SOUND_MIXER_RECSRC: /* give them the current record source */
-			if (!codec->recmask_io) {
-				val = 0;
-			} else {
-				val = codec->recmask_io(codec, 1, 0);
-			}
-			break;
-
-		case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
-			val = codec->supported_mixers;
-			break;
-
-		case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-			val = codec->record_sources;
-			break;
-
-		case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-			val = codec->stereo_mixers;
-			break;
-
-		case SOUND_MIXER_CAPS:
-			val = SOUND_CAP_EXCL_INPUT;
-			break;
-
-		default: /* read a specific mixer */
-			i = _IOC_NR(cmd);
-
-			if (!supported_mixer(codec, i)) 
-				return -EINVAL;
-
-			/* do we ever want to touch the hardware? */
-		        /* val = codec->read_mixer(codec, i); */
-			val = codec->mixer_state[i];
- 			break;
-		}
-		return put_user(val, (int __user *)arg);
-	}
-
-	if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) {
-		codec->modcnt++;
-		if (get_user(val, (int __user *)arg))
-			return -EFAULT;
-
-		switch (_IOC_NR(cmd)) {
-		case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			if (!codec->recmask_io) return -EINVAL;
-			if (!val) return 0;
-			if (!(val &= codec->record_sources)) return -EINVAL;
-
-			codec->recmask_io(codec, 0, val);
-
-			return 0;
-		default: /* write a specific mixer */
-			i = _IOC_NR(cmd);
-
-			if (!supported_mixer(codec, i)) 
-				return -EINVAL;
-
-			ac97_set_mixer(codec, i, val);
-
-			return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-/**
- *	codec_id	-  Turn id1/id2 into a PnP string
- *	@id1: Vendor ID1
- *	@id2: Vendor ID2
- *	@buf: CODEC_ID_BUFSZ byte buffer
- *
- *	Fills buf with a zero terminated PnP ident string for the id1/id2
- *	pair. For convenience the return is the passed in buffer pointer.
- */
- 
-static char *codec_id(u16 id1, u16 id2, char *buf)
-{
-	if(id1&0x8080) {
-		snprintf(buf, CODEC_ID_BUFSZ, "0x%04x:0x%04x", id1, id2);
-	} else {
-		buf[0] = (id1 >> 8);
-		buf[1] = (id1 & 0xFF);
-		buf[2] = (id2 >> 8);
-		snprintf(buf+3, CODEC_ID_BUFSZ - 3, "%d", id2&0xFF);
-	}
-	return buf;
-}
- 
-/**
- *	ac97_check_modem - Check if the Codec is a modem
- *	@codec: codec to check
- *
- *	Return true if the device is an AC97 1.0 or AC97 2.0 modem
- */
- 
-static int ac97_check_modem(struct ac97_codec *codec)
-{
-	/* Check for an AC97 1.0 soft modem (ID1) */
-	if(codec->codec_read(codec, AC97_RESET) & 2)
-		return 1;
-	/* Check for an AC97 2.x soft modem */
-	codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
-	if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1)
-		return 1;
-	return 0;
-}
-
-
-/**
- *	ac97_alloc_codec - Allocate an AC97 codec
- *
- *	Returns a new AC97 codec structure. AC97 codecs may become
- *	refcounted soon so this interface is needed. Returns with
- *	one reference taken.
- */
- 
-struct ac97_codec *ac97_alloc_codec(void)
-{
-	struct ac97_codec *codec = kzalloc(sizeof(struct ac97_codec), GFP_KERNEL);
-	if(!codec)
-		return NULL;
-
-	spin_lock_init(&codec->lock);
-	INIT_LIST_HEAD(&codec->list);
-	return codec;
-}
-
-EXPORT_SYMBOL(ac97_alloc_codec);
-
-/**
- *	ac97_release_codec -	Release an AC97 codec
- *	@codec: codec to release
- *
- *	Release an allocated AC97 codec. This will be refcounted in
- *	time but for the moment is trivial. Calls the unregister
- *	handler if the codec is now defunct.
- */
- 
-void ac97_release_codec(struct ac97_codec *codec)
-{
-	/* Remove from the list first, we don't want to be
-	   "rediscovered" */
-	mutex_lock(&codec_mutex);
-	list_del(&codec->list);
-	mutex_unlock(&codec_mutex);
-	/*
-	 *	The driver needs to deal with internal
-	 *	locking to avoid accidents here. 
-	 */
-	if(codec->driver)
-		codec->driver->remove(codec, codec->driver);
-	kfree(codec);
-}
-
-EXPORT_SYMBOL(ac97_release_codec);
-
-/**
- *	ac97_probe_codec - Initialize and setup AC97-compatible codec
- *	@codec: (in/out) Kernel info for a single AC97 codec
- *
- *	Reset the AC97 codec, then initialize the mixer and
- *	the rest of the @codec structure.
- *
- *	The codec_read and codec_write fields of @codec are
- *	required to be setup and working when this function
- *	is called.  All other fields are set by this function.
- *
- *	codec_wait field of @codec can optionally be provided
- *	when calling this function.  If codec_wait is not %NULL,
- *	this function will call codec_wait any time it is
- *	necessary to wait for the audio chip to reach the
- *	codec-ready state.  If codec_wait is %NULL, then
- *	the default behavior is to call schedule_timeout.
- *	Currently codec_wait is used to wait for AC97 codec
- *	reset to complete. 
- *
- *     Some codecs will power down when a register reset is
- *     performed. We now check for such codecs.
- *
- *	Returns 1 (true) on success, or 0 (false) on failure.
- */
- 
-int ac97_probe_codec(struct ac97_codec *codec)
-{
-	u16 id1, id2;
-	u16 audio;
-	int i;
-	char cidbuf[CODEC_ID_BUFSZ];
-	u16 f;
-	struct list_head *l;
-	struct ac97_driver *d;
-	
-	/* wait for codec-ready state */
-	if (codec->codec_wait)
-		codec->codec_wait(codec);
-	else
-		udelay(10);
-
-	/* will the codec power down if register reset ? */
-	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
-	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
-	codec->name = NULL;
-	codec->codec_ops = &null_ops;
-	for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) {
-		if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
-			codec->type = ac97_codec_ids[i].id;
-			codec->name = ac97_codec_ids[i].name;
-			codec->codec_ops = ac97_codec_ids[i].ops;
-			codec->flags = ac97_codec_ids[i].flags;
-			break;
-		}
-	}
-
-	codec->model = (id1 << 16) | id2;
-	if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) {
-		/* reset codec and wait for the ready bit before we continue */
-		codec->codec_write(codec, AC97_RESET, 0L);
-		if (codec->codec_wait)
-			codec->codec_wait(codec);
-		else
-			udelay(10);
-	}
-
-	/* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should
-	 * be read zero.
-	 *
-	 * FIXME: is the following comment outdated?  -jgarzik
-	 * Probing of AC97 in this way is not reliable, it is not even SAFE !!
-	 */
-	if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
-		printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
-		       (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary")
-		       : (codec->id&1 ? "Secondary":  "Primary"));
-		return 0;
-	}
-	
-	/* probe for Modem Codec */
-	codec->modem = ac97_check_modem(codec);
-
-	/* enable SPDIF */
-	f = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-	if((codec->codec_ops == &null_ops) && (f & 4))
-		codec->codec_ops = &default_digital_ops;
-	
-	/* A device which thinks its a modem but isn't */
-	if(codec->flags & AC97_DELUDED_MODEM)
-		codec->modem = 0;
-		
-	if (codec->name == NULL)
-		codec->name = "Unknown";
-	printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s (%s)\n", 
-		codec->modem ? "Modem" : (audio ? "Audio" : ""),
-	       codec_id(id1, id2, cidbuf), codec->name);
-
-	if(!ac97_init_mixer(codec))
-		return 0;
-		
-	/* 
-	 *	Attach last so the caller can override the mixer
-	 *	callbacks.
-	 */
-	 
-	mutex_lock(&codec_mutex);
-	list_add(&codec->list, &codecs);
-
-	list_for_each(l, &codec_drivers) {
-		d = list_entry(l, struct ac97_driver, list);
-		if ((codec->model ^ d->codec_id) & d->codec_mask)
-			continue;
-		if(d->probe(codec, d) == 0)
-		{
-			codec->driver = d;
-			break;
-		}
-	}
-
-	mutex_unlock(&codec_mutex);
-	return 1;
-}
-
-static int ac97_init_mixer(struct ac97_codec *codec)
-{
-	u16 cap;
-	int i;
-
-	cap = codec->codec_read(codec, AC97_RESET);
-
-	/* mixer masks */
-	codec->supported_mixers = AC97_SUPPORTED_MASK;
-	codec->stereo_mixers = AC97_STEREO_MASK;
-	codec->record_sources = AC97_RECORD_MASK;
-	if (!(cap & 0x04))
-		codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
-	if (!(cap & 0x10))
-		codec->supported_mixers &= ~SOUND_MASK_ALTPCM;
-
-
-	/* detect bit resolution */
-	codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020);
-	if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x2020)
-		codec->bit_resolution = 6;
-	else
-		codec->bit_resolution = 5;
-
-	/* generic OSS to AC97 wrapper */
-	codec->read_mixer = ac97_read_mixer;
-	codec->write_mixer = ac97_write_mixer;
-	codec->recmask_io = ac97_recmask_io;
-	codec->mixer_ioctl = ac97_mixer_ioctl;
-
-	/* initialize mixer channel volumes */
-	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-		struct mixer_defaults *md = &mixer_defaults[i];
-		if (md->mixer == -1) 
-			break;
-		if (!supported_mixer(codec, md->mixer)) 
-			continue;
-		ac97_set_mixer(codec, md->mixer, md->value);
-	}
-
-	/* codec specific initialization for 4-6 channel output or secondary codec stuff */
-	if (codec->codec_ops->init != NULL) {
-		codec->codec_ops->init(codec);
-	}
-
-	/*
-	 *	Volume is MUTE only on this device. We have to initialise
-	 *	it but its useless beyond that.
-	 */
-	if(codec->flags & AC97_NO_PCM_VOLUME)
-	{
-		codec->supported_mixers &= ~SOUND_MASK_PCM;
-		printk(KERN_WARNING "AC97 codec does not have proper volume support.\n");
-	}
-	return 1;
-}
-
-#define AC97_SIGMATEL_ANALOG    0x6c	/* Analog Special */
-#define AC97_SIGMATEL_DAC2INVERT 0x6e
-#define AC97_SIGMATEL_BIAS1     0x70
-#define AC97_SIGMATEL_BIAS2     0x72
-#define AC97_SIGMATEL_MULTICHN  0x74	/* Multi-Channel programming */
-#define AC97_SIGMATEL_CIC1      0x76
-#define AC97_SIGMATEL_CIC2      0x78
-
-
-static int sigmatel_9708_init(struct ac97_codec * codec)
-{
-	u16 codec72, codec6c;
-
-	codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000;
-	codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG);
-
-	if ((codec72==0) && (codec6c==0)) {
-		codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-		codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000);
-		codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
-		codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007);
-	} else if ((codec72==0x8000) && (codec6c==0)) {
-		codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-		codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001);
-		codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008);
-	} else if ((codec72==0x8000) && (codec6c==0x0080)) {
-		/* nothing */
-	}
-	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
-	return 0;
-}
-
-
-static int sigmatel_9721_init(struct ac97_codec * codec)
-{
-	/* Only set up secondary codec */
-	if (codec->id == 0)
-		return 0;
-
-	codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
-
-	/* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link
-	   sloc 3,4 = 0x01, slot 7,8 = 0x00, */
-	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00);
-
-	/* we don't have the crystal when we are on an AMR card, so use
-	   BIT_CLK as our clock source. Write the magic word ABBA and read
-	   back to enable register 0x78 */
-	codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-	codec->codec_read(codec, AC97_SIGMATEL_CIC1);
-
-	/* sync all the clocks*/
-	codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802);
-
-	return 0;
-}
-
-
-static int sigmatel_9744_init(struct ac97_codec * codec)
-{
-	// patch for SigmaTel
-	codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
-	codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk
-	codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
-	codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002);
-	codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
-	return 0;
-}
-
-static int cmedia_init(struct ac97_codec *codec)
-{
-	/* Initialise the CMedia 9739 */
-	/*
-		We could set various options here
-		Register 0x20 bit 0x100 sets mic as center bass
-		Also do multi_channel_ctrl &=~0x3000 |=0x1000
-		
-		For now we set up the GPIO and PC beep 
-	*/
-	
-	u16 v;
-	
-	/* MIC */
-	codec->codec_write(codec, 0x64, 0x3000);
-	v = codec->codec_read(codec, 0x64);
-	v &= ~0x8000;
-	codec->codec_write(codec, 0x64, v);
-	codec->codec_write(codec, 0x70, 0x0100);
-	codec->codec_write(codec, 0x72, 0x0020);
-	return 0;
-}
-	
-#define AC97_WM97XX_FMIXER_VOL 0x72
-#define AC97_WM97XX_RMIXER_VOL 0x74
-#define AC97_WM97XX_TEST 0x5a
-#define AC97_WM9704_RPCM_VOL 0x70
-#define AC97_WM9711_OUT3VOL 0x16
-
-static int wolfson_init03(struct ac97_codec * codec)
-{
-	/* this is known to work for the ViewSonic ViewPad 1000 */
-	codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
-	codec->codec_write(codec, AC97_GENERAL_PURPOSE, 0x8000);
-	return 0;
-}
-
-static int wolfson_init04(struct ac97_codec * codec)
-{
-	codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
-	codec->codec_write(codec, AC97_WM97XX_RMIXER_VOL, 0x0808);
-
-	// patch for DVD noise
-	codec->codec_write(codec, AC97_WM97XX_TEST, 0x0200);
-
-	// init vol as PCM vol
-	codec->codec_write(codec, AC97_WM9704_RPCM_VOL,
-		codec->codec_read(codec, AC97_PCMOUT_VOL));
-
-	/* set rear surround volume */
-	codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
-	return 0;
-}
-
-/* WM9705, WM9710 */
-static int wolfson_init05(struct ac97_codec * codec)
-{
-	/* set front mixer volume */
-	codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
-	return 0;
-}
-
-/* WM9711, WM9712 */
-static int wolfson_init11(struct ac97_codec * codec)
-{
-	/* stop pop's during suspend/resume */
-	codec->codec_write(codec, AC97_WM97XX_TEST,
-		codec->codec_read(codec, AC97_WM97XX_TEST) & 0xffbf);
-
-	/* set out3 volume */
-	codec->codec_write(codec, AC97_WM9711_OUT3VOL, 0x0808);
-	return 0;
-}
-
-/* WM9713 */
-static int wolfson_init13(struct ac97_codec * codec)
-{
-	codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0);
-	codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000);
-	codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00);
-	codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810);
-	codec->codec_write(codec, AC97_PHONE_VOL, 0x0808);
-	codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808);
-
-	return 0;
-}
-
-static int tritech_init(struct ac97_codec * codec)
-{
-	codec->codec_write(codec, 0x26, 0x0300);
-	codec->codec_write(codec, 0x26, 0x0000);
-	codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
-	codec->codec_write(codec, AC97_RESERVED_3A, 0x0000);
-	return 0;
-}
-
-
-/* copied from drivers/sound/maestro.c */
-static int tritech_maestro_init(struct ac97_codec * codec)
-{
-	/* no idea what this does */
-	codec->codec_write(codec, 0x2A, 0x0001);
-	codec->codec_write(codec, 0x2C, 0x0000);
-	codec->codec_write(codec, 0x2C, 0XFFFF);
-	return 0;
-}
-
-
-
-/* 
- *	Presario700 workaround 
- * 	for Jack Sense/SPDIF Register mis-setting causing
- *	no audible output
- *	by Santiago Nullo 04/05/2002
- */
-
-#define AC97_AD1886_JACK_SENSE 0x72
-
-static int ad1886_init(struct ac97_codec * codec)
-{
-	/* from AD1886 Specs */
-	codec->codec_write(codec, AC97_AD1886_JACK_SENSE, 0x0010);
-	return 0;
-}
-
-
-
-
-/*
- *	This is basically standard AC97. It should work as a default for
- *	almost all modern codecs. Note that some cards wire EAPD *backwards*
- *	That side of it is up to the card driver not us to cope with.
- *
- */
-
-static int eapd_control(struct ac97_codec * codec, int on)
-{
-	if(on)
-		codec->codec_write(codec, AC97_POWER_CONTROL,
-			codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000);
-	else
-		codec->codec_write(codec, AC97_POWER_CONTROL,
-			codec->codec_read(codec, AC97_POWER_CONTROL)&~0x8000);
-	return 0;
-}
-
-static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
-	u16 reg;
-	
-	reg = codec->codec_read(codec, AC97_SPDIF_CONTROL);
-	
-	switch(rate)
-	{
-		/* Off by default */
-		default:
-		case 0:
-			reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-			codec->codec_write(codec, AC97_EXTENDED_STATUS, (reg & ~AC97_EA_SPDIF));
-			if(rate == 0)
-				return 0;
-			return -EINVAL;
-		case 1:
-			reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
-			break;
-		case 2:
-			reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
-			break;
-		case 3:
-			reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
-			break;
-	}
-	
-	reg &= ~AC97_SC_CC_MASK;
-	reg |= (mode & AUDIO_CCMASK) << 6;
-	
-	if(mode & AUDIO_DIGITAL)
-		reg |= 2;
-	if(mode & AUDIO_PRO)
-		reg |= 1;
-	if(mode & AUDIO_DRS)
-		reg |= 0x4000;
-
-	codec->codec_write(codec, AC97_SPDIF_CONTROL, reg);
-
-	reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-	reg &= (AC97_EA_SLOT_MASK);
-	reg |= AC97_EA_VRA | AC97_EA_SPDIF | slots;
-	codec->codec_write(codec, AC97_EXTENDED_STATUS, reg);
-	
-	reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-	if(!(reg & 0x0400))
-	{
-		codec->codec_write(codec, AC97_EXTENDED_STATUS, reg & ~ AC97_EA_SPDIF);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/*
- *	Crystal digital audio control (CS4299)
- */
- 
-static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
-	u16 cv;
-
-	if(mode & AUDIO_DIGITAL)
-		return -EINVAL;
-		
-	switch(rate)
-	{
-		case 0: cv = 0x0; break;	/* SPEN off */
-		case 48000: cv = 0x8004; break;	/* 48KHz digital */
-		case 44100: cv = 0x8104; break;	/* 44.1KHz digital */
-		case 32768: 			/* 32Khz */
-		default:
-			return -EINVAL;
-	}
-	codec->codec_write(codec, 0x68, cv);
-	return 0;
-}
-
-/*
- *	CMedia digital audio control
- *	Needs more work.
- */
- 
-static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
-	u16 cv;
-
-	if(mode & AUDIO_DIGITAL)
-		return -EINVAL;
-		
-	switch(rate)
-	{
-		case 0:		cv = 0x0001; break;	/* SPEN off */
-		case 48000:	cv = 0x0009; break;	/* 48KHz digital */
-		default:
-			return -EINVAL;
-	}
-	codec->codec_write(codec, 0x2A, 0x05c4);
-	codec->codec_write(codec, 0x6C, cv);
-	
-	/* Switch on mix to surround */
-	cv = codec->codec_read(codec, 0x64);
-	cv &= ~0x0200;
-	if(mode)
-		cv |= 0x0200;
-	codec->codec_write(codec, 0x64, cv);
-	return 0;
-}
-
-
-/* copied from drivers/sound/maestro.c */
-#if 0  /* there has been 1 person on the planet with a pt101 that we
-        know of.  If they care, they can put this back in :) */
-static int pt101_init(struct ac97_codec * codec)
-{
-	printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
-	/* who knows.. */
-	codec->codec_write(codec, 0x2A, 0x0001);
-	codec->codec_write(codec, 0x2C, 0x0000);
-	codec->codec_write(codec, 0x2C, 0xFFFF);
-	codec->codec_write(codec, 0x10, 0x9F1F);
-	codec->codec_write(codec, 0x12, 0x0808);
-	codec->codec_write(codec, 0x14, 0x9F1F);
-	codec->codec_write(codec, 0x16, 0x9F1F);
-	codec->codec_write(codec, 0x18, 0x0404);
-	codec->codec_write(codec, 0x1A, 0x0000);
-	codec->codec_write(codec, 0x1C, 0x0000);
-	codec->codec_write(codec, 0x02, 0x0404);
-	codec->codec_write(codec, 0x04, 0x0808);
-	codec->codec_write(codec, 0x0C, 0x801F);
-	codec->codec_write(codec, 0x0E, 0x801F);
-	return 0;
-}
-#endif
-	
-
-EXPORT_SYMBOL(ac97_probe_codec);
-
-MODULE_LICENSE("GPL");
-

+ 0 - 2147
sound/oss/au1550_ac97.c

@@ -1,2147 +0,0 @@
-/*
- * au1550_ac97.c  --  Sound driver for Alchemy Au1550 MIPS Internet Edge
- *                    Processor.
- *
- * Copyright 2004 Embedded Edge, LLC
- *	dan@embeddededge.com
- *
- * Mostly copied from the au1000.c driver and some from the
- * PowerMac dbdma driver.
- * We assume the processor can do memory coherent DMA.
- *
- * Ported to 2.6 by Matt Porter <mporter@kernel.crashing.org>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#undef DEBUG
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
-#include <linux/ac97_codec.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/hardirq.h>
-#include <asm/mach-au1x00/au1xxx_psc.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/mach-au1x00/au1xxx.h>
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-/* misc stuff */
-#define POLL_COUNT   0x50000
-#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC)
-
-/* The number of DBDMA ring descriptors to allocate.  No sense making
- * this too large....if you can't keep up with a few you aren't likely
- * to be able to with lots of them, either.
- */
-#define NUM_DBDMA_DESCRIPTORS 4
-
-#define err(format, arg...) printk(KERN_ERR format "\n" , ## arg)
-
-/* Boot options
- * 0 = no VRA, 1 = use VRA if codec supports it
- */
-static DEFINE_MUTEX(au1550_ac97_mutex);
-static int      vra = 1;
-module_param(vra, bool, 0);
-MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
-
-static struct au1550_state {
-	/* soundcore stuff */
-	int             dev_audio;
-
-	struct ac97_codec *codec;
-	unsigned        codec_base_caps; /* AC'97 reg 00h, "Reset Register" */
-	unsigned        codec_ext_caps;  /* AC'97 reg 28h, "Extended Audio ID" */
-	int             no_vra;		/* do not use VRA */
-
-	spinlock_t      lock;
-	struct mutex open_mutex;
-	struct mutex sem;
-	fmode_t          open_mode;
-	wait_queue_head_t open_wait;
-
-	struct dmabuf {
-		u32		dmanr;
-		unsigned        sample_rate;
-		unsigned	src_factor;
-		unsigned        sample_size;
-		int             num_channels;
-		int		dma_bytes_per_sample;
-		int		user_bytes_per_sample;
-		int		cnt_factor;
-
-		void		*rawbuf;
-		unsigned        buforder;
-		unsigned	numfrag;
-		unsigned        fragshift;
-		void		*nextIn;
-		void		*nextOut;
-		int		count;
-		unsigned        total_bytes;
-		unsigned        error;
-		wait_queue_head_t wait;
-
-		/* redundant, but makes calculations easier */
-		unsigned	fragsize;
-		unsigned	dma_fragsize;
-		unsigned	dmasize;
-		unsigned	dma_qcount;
-
-		/* OSS stuff */
-		unsigned        mapped:1;
-		unsigned        ready:1;
-		unsigned        stopped:1;
-		unsigned        ossfragshift;
-		int             ossmaxfrags;
-		unsigned        subdivision;
-	} dma_dac, dma_adc;
-} au1550_state;
-
-static unsigned
-ld2(unsigned int x)
-{
-	unsigned        r = 0;
-
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-static void
-au1550_delay(int msec)
-{
-	if (in_interrupt())
-		return;
-
-	schedule_timeout_uninterruptible(msecs_to_jiffies(msec));
-}
-
-static u16
-rdcodec(struct ac97_codec *codec, u8 addr)
-{
-	struct au1550_state *s = codec->private_data;
-	unsigned long   flags;
-	u32             cmd, val;
-	u16             data;
-	int             i;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-		if (!(val & PSC_AC97STAT_CP))
-			break;
-	}
-	if (i == POLL_COUNT)
-		err("rdcodec: codec cmd pending expired!");
-
-	cmd = (u32)PSC_AC97CDC_INDX(addr);
-	cmd |= PSC_AC97CDC_RD;	/* read command */
-	au_writel(cmd, PSC_AC97CDC);
-	au_sync();
-
-	/* now wait for the data
-	*/
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-		if (!(val & PSC_AC97STAT_CP))
-			break;
-	}
-	if (i == POLL_COUNT) {
-		err("rdcodec: read poll expired!");
-		data = 0;
-		goto out;
-	}
-
-	/* wait for command done?
-	*/
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97EVNT);
-		au_sync();
-		if (val & PSC_AC97EVNT_CD)
-			break;
-	}
-	if (i == POLL_COUNT) {
-		err("rdcodec: read cmdwait expired!");
-		data = 0;
-		goto out;
-	}
-
-	data = au_readl(PSC_AC97CDC) & 0xffff;
-	au_sync();
-
-	/* Clear command done event.
-	*/
-	au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
-	au_sync();
-
- out:
-	spin_unlock_irqrestore(&s->lock, flags);
-
-	return data;
-}
-
-
-static void
-wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
-{
-	struct au1550_state *s = codec->private_data;
-	unsigned long   flags;
-	u32             cmd, val;
-	int             i;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-		if (!(val & PSC_AC97STAT_CP))
-			break;
-	}
-	if (i == POLL_COUNT)
-		err("wrcodec: codec cmd pending expired!");
-
-	cmd = (u32)PSC_AC97CDC_INDX(addr);
-	cmd |= (u32)data;
-	au_writel(cmd, PSC_AC97CDC);
-	au_sync();
-
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-		if (!(val & PSC_AC97STAT_CP))
-			break;
-	}
-	if (i == POLL_COUNT)
-		err("wrcodec: codec cmd pending expired!");
-
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97EVNT);
-		au_sync();
-		if (val & PSC_AC97EVNT_CD)
-			break;
-	}
-	if (i == POLL_COUNT)
-		err("wrcodec: read cmdwait expired!");
-
-	/* Clear command done event.
-	*/
-	au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
-	au_sync();
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void
-waitcodec(struct ac97_codec *codec)
-{
-	u16	temp;
-	u32	val;
-	int	i;
-
-	/* codec_wait is used to wait for a ready state after
-	 * an AC97C_RESET.
-	 */
-	au1550_delay(10);
-
-	/* first poll the CODEC_READY tag bit
-	*/
-	for (i = 0; i < POLL_COUNT; i++) {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-		if (val & PSC_AC97STAT_CR)
-			break;
-	}
-	if (i == POLL_COUNT) {
-		err("waitcodec: CODEC_READY poll expired!");
-		return;
-	}
-
-	/* get AC'97 powerdown control/status register
-	*/
-	temp = rdcodec(codec, AC97_POWER_CONTROL);
-
-	/* If anything is powered down, power'em up
-	*/
-	if (temp & 0x7f00) {
-		/* Power on
-		*/
-		wrcodec(codec, AC97_POWER_CONTROL, 0);
-		au1550_delay(100);
-
-		/* Reread
-		*/
-		temp = rdcodec(codec, AC97_POWER_CONTROL);
-	}
-
-	/* Check if Codec REF,ANL,DAC,ADC ready
-	*/
-	if ((temp & 0x7f0f) != 0x000f)
-		err("codec reg 26 status (0x%x) not ready!!", temp);
-}
-
-/* stop the ADC before calling */
-static void
-set_adc_rate(struct au1550_state *s, unsigned rate)
-{
-	struct dmabuf  *adc = &s->dma_adc;
-	struct dmabuf  *dac = &s->dma_dac;
-	unsigned        adc_rate, dac_rate;
-	u16             ac97_extstat;
-
-	if (s->no_vra) {
-		/* calc SRC factor
-		*/
-		adc->src_factor = ((96000 / rate) + 1) >> 1;
-		adc->sample_rate = 48000 / adc->src_factor;
-		return;
-	}
-
-	adc->src_factor = 1;
-
-	ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-
-	rate = rate > 48000 ? 48000 : rate;
-
-	/* enable VRA
-	*/
-	wrcodec(s->codec, AC97_EXTENDED_STATUS,
-		ac97_extstat | AC97_EXTSTAT_VRA);
-
-	/* now write the sample rate
-	*/
-	wrcodec(s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate);
-
-	/* read it back for actual supported rate
-	*/
-	adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
-
-	pr_debug("set_adc_rate: set to %d Hz\n", adc_rate);
-
-	/* some codec's don't allow unequal DAC and ADC rates, in which case
-	 * writing one rate reg actually changes both.
-	 */
-	dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
-	if (dac->num_channels > 2)
-		wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate);
-	if (dac->num_channels > 4)
-		wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate);
-
-	adc->sample_rate = adc_rate;
-	dac->sample_rate = dac_rate;
-}
-
-/* stop the DAC before calling */
-static void
-set_dac_rate(struct au1550_state *s, unsigned rate)
-{
-	struct dmabuf  *dac = &s->dma_dac;
-	struct dmabuf  *adc = &s->dma_adc;
-	unsigned        adc_rate, dac_rate;
-	u16             ac97_extstat;
-
-	if (s->no_vra) {
-		/* calc SRC factor
-		*/
-		dac->src_factor = ((96000 / rate) + 1) >> 1;
-		dac->sample_rate = 48000 / dac->src_factor;
-		return;
-	}
-
-	dac->src_factor = 1;
-
-	ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-
-	rate = rate > 48000 ? 48000 : rate;
-
-	/* enable VRA
-	*/
-	wrcodec(s->codec, AC97_EXTENDED_STATUS,
-		ac97_extstat | AC97_EXTSTAT_VRA);
-
-	/* now write the sample rate
-	*/
-	wrcodec(s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate);
-
-	/* I don't support different sample rates for multichannel,
-	 * so make these channels the same.
-	 */
-	if (dac->num_channels > 2)
-		wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate);
-	if (dac->num_channels > 4)
-		wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate);
-	/* read it back for actual supported rate
-	*/
-	dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
-
-	pr_debug("set_dac_rate: set to %d Hz\n", dac_rate);
-
-	/* some codec's don't allow unequal DAC and ADC rates, in which case
-	 * writing one rate reg actually changes both.
-	 */
-	adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
-
-	dac->sample_rate = dac_rate;
-	adc->sample_rate = adc_rate;
-}
-
-static void
-stop_dac(struct au1550_state *s)
-{
-	struct dmabuf  *db = &s->dma_dac;
-	u32		stat;
-	unsigned long   flags;
-
-	if (db->stopped)
-		return;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	au_writel(PSC_AC97PCR_TP, PSC_AC97PCR);
-	au_sync();
-
-	/* Wait for Transmit Busy to show disabled.
-	*/
-	do {
-		stat = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((stat & PSC_AC97STAT_TB) != 0);
-
-	au1xxx_dbdma_reset(db->dmanr);
-
-	db->stopped = 1;
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void
-stop_adc(struct au1550_state *s)
-{
-	struct dmabuf  *db = &s->dma_adc;
-	unsigned long   flags;
-	u32		stat;
-
-	if (db->stopped)
-		return;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	au_writel(PSC_AC97PCR_RP, PSC_AC97PCR);
-	au_sync();
-
-	/* Wait for Receive Busy to show disabled.
-	*/
-	do {
-		stat = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((stat & PSC_AC97STAT_RB) != 0);
-
-	au1xxx_dbdma_reset(db->dmanr);
-
-	db->stopped = 1;
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void
-set_xmit_slots(int num_channels)
-{
-	u32	ac97_config, stat;
-
-	ac97_config = au_readl(PSC_AC97CFG);
-	au_sync();
-	ac97_config &= ~(PSC_AC97CFG_TXSLOT_MASK | PSC_AC97CFG_DE_ENABLE);
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	switch (num_channels) {
-	case 6:		/* stereo with surround and center/LFE,
-			 * slots 3,4,6,7,8,9
-			 */
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(6);
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(9);
-
-	case 4:		/* stereo with surround, slots 3,4,7,8 */
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(7);
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(8);
-
-	case 2:		/* stereo, slots 3,4 */
-	case 1:		/* mono */
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(3);
-		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(4);
-	}
-
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	ac97_config |= PSC_AC97CFG_DE_ENABLE;
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	/* Wait for Device ready.
-	*/
-	do {
-		stat = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((stat & PSC_AC97STAT_DR) == 0);
-}
-
-static void
-set_recv_slots(int num_channels)
-{
-	u32	ac97_config, stat;
-
-	ac97_config = au_readl(PSC_AC97CFG);
-	au_sync();
-	ac97_config &= ~(PSC_AC97CFG_RXSLOT_MASK | PSC_AC97CFG_DE_ENABLE);
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	/* Always enable slots 3 and 4 (stereo). Slot 6 is
-	 * optional Mic ADC, which we don't support yet.
-	 */
-	ac97_config |= PSC_AC97CFG_RXSLOT_ENA(3);
-	ac97_config |= PSC_AC97CFG_RXSLOT_ENA(4);
-
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	ac97_config |= PSC_AC97CFG_DE_ENABLE;
-	au_writel(ac97_config, PSC_AC97CFG);
-	au_sync();
-
-	/* Wait for Device ready.
-	*/
-	do {
-		stat = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((stat & PSC_AC97STAT_DR) == 0);
-}
-
-/* Hold spinlock for both start_dac() and start_adc() calls */
-static void
-start_dac(struct au1550_state *s)
-{
-	struct dmabuf  *db = &s->dma_dac;
-
-	if (!db->stopped)
-		return;
-
-	set_xmit_slots(db->num_channels);
-	au_writel(PSC_AC97PCR_TC, PSC_AC97PCR);
-	au_sync();
-	au_writel(PSC_AC97PCR_TS, PSC_AC97PCR);
-	au_sync();
-
-	au1xxx_dbdma_start(db->dmanr);
-
-	db->stopped = 0;
-}
-
-static void
-start_adc(struct au1550_state *s)
-{
-	struct dmabuf  *db = &s->dma_adc;
-	int	i;
-
-	if (!db->stopped)
-		return;
-
-	/* Put two buffers on the ring to get things started.
-	*/
-	for (i=0; i<2; i++) {
-		au1xxx_dbdma_put_dest(db->dmanr, virt_to_phys(db->nextIn),
-				db->dma_fragsize, DDMA_FLAGS_IE);
-
-		db->nextIn += db->dma_fragsize;
-		if (db->nextIn >= db->rawbuf + db->dmasize)
-			db->nextIn -= db->dmasize;
-	}
-
-	set_recv_slots(db->num_channels);
-	au1xxx_dbdma_start(db->dmanr);
-	au_writel(PSC_AC97PCR_RC, PSC_AC97PCR);
-	au_sync();
-	au_writel(PSC_AC97PCR_RS, PSC_AC97PCR);
-	au_sync();
-
-	db->stopped = 0;
-}
-
-static int
-prog_dmabuf(struct au1550_state *s, struct dmabuf *db)
-{
-	unsigned user_bytes_per_sec;
-	unsigned        bufs;
-	unsigned        rate = db->sample_rate;
-
-	if (!db->rawbuf) {
-		db->ready = db->mapped = 0;
-		db->buforder = 5;	/* 32 * PAGE_SIZE */
-		db->rawbuf = kmalloc((PAGE_SIZE << db->buforder), GFP_KERNEL);
-		if (!db->rawbuf)
-			return -ENOMEM;
-	}
-
-	db->cnt_factor = 1;
-	if (db->sample_size == 8)
-		db->cnt_factor *= 2;
-	if (db->num_channels == 1)
-		db->cnt_factor *= 2;
-	db->cnt_factor *= db->src_factor;
-
-	db->count = 0;
-	db->dma_qcount = 0;
-	db->nextIn = db->nextOut = db->rawbuf;
-
-	db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels;
-	db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ?
-					2 : db->num_channels);
-
-	user_bytes_per_sec = rate * db->user_bytes_per_sample;
-	bufs = PAGE_SIZE << db->buforder;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < user_bytes_per_sec)
-			db->fragshift = ld2(user_bytes_per_sec/1000);
-		else
-			db->fragshift = db->ossfragshift;
-	} else {
-		db->fragshift = ld2(user_bytes_per_sec / 100 /
-				    (db->subdivision ? db->subdivision : 1));
-		if (db->fragshift < 3)
-			db->fragshift = 3;
-	}
-
-	db->fragsize = 1 << db->fragshift;
-	db->dma_fragsize = db->fragsize * db->cnt_factor;
-	db->numfrag = bufs / db->dma_fragsize;
-
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->fragsize = 1 << db->fragshift;
-		db->dma_fragsize = db->fragsize * db->cnt_factor;
-		db->numfrag = bufs / db->dma_fragsize;
-	}
-
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
-
-	db->dmasize = db->dma_fragsize * db->numfrag;
-	memset(db->rawbuf, 0, bufs);
-
-	pr_debug("prog_dmabuf: rate=%d, samplesize=%d, channels=%d\n",
-	    rate, db->sample_size, db->num_channels);
-	pr_debug("prog_dmabuf: fragsize=%d, cnt_factor=%d, dma_fragsize=%d\n",
-	    db->fragsize, db->cnt_factor, db->dma_fragsize);
-	pr_debug("prog_dmabuf: numfrag=%d, dmasize=%d\n", db->numfrag, db->dmasize);
-
-	db->ready = 1;
-	return 0;
-}
-
-static int
-prog_dmabuf_adc(struct au1550_state *s)
-{
-	stop_adc(s);
-	return prog_dmabuf(s, &s->dma_adc);
-
-}
-
-static int
-prog_dmabuf_dac(struct au1550_state *s)
-{
-	stop_dac(s);
-	return prog_dmabuf(s, &s->dma_dac);
-}
-
-
-static void dac_dma_interrupt(int irq, void *dev_id)
-{
-	struct au1550_state *s = (struct au1550_state *) dev_id;
-	struct dmabuf  *db = &s->dma_dac;
-	u32	ac97c_stat;
-
-	spin_lock(&s->lock);
-
-	ac97c_stat = au_readl(PSC_AC97STAT);
-	if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
-		pr_debug("AC97C status = 0x%08x\n", ac97c_stat);
-	db->dma_qcount--;
-
-	if (db->count >= db->fragsize) {
-		if (au1xxx_dbdma_put_source(db->dmanr,
-				virt_to_phys(db->nextOut), db->fragsize,
-				DDMA_FLAGS_IE) == 0) {
-			err("qcount < 2 and no ring room!");
-		}
-		db->nextOut += db->fragsize;
-		if (db->nextOut >= db->rawbuf + db->dmasize)
-			db->nextOut -= db->dmasize;
-		db->count -= db->fragsize;
-		db->total_bytes += db->dma_fragsize;
-		db->dma_qcount++;
-	}
-
-	/* wake up anybody listening */
-	if (waitqueue_active(&db->wait))
-		wake_up(&db->wait);
-
-	spin_unlock(&s->lock);
-}
-
-
-static void adc_dma_interrupt(int irq, void *dev_id)
-{
-	struct	au1550_state *s = (struct au1550_state *)dev_id;
-	struct	dmabuf  *dp = &s->dma_adc;
-	u32	obytes;
-	char	*obuf;
-
-	spin_lock(&s->lock);
-
-	/* Pull the buffer from the dma queue.
-	*/
-	au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes);
-
-	if ((dp->count + obytes) > dp->dmasize) {
-		/* Overrun. Stop ADC and log the error
-		*/
-		spin_unlock(&s->lock);
-		stop_adc(s);
-		dp->error++;
-		err("adc overrun");
-		return;
-	}
-
-	/* Put a new empty buffer on the destination DMA.
-	*/
-	au1xxx_dbdma_put_dest(dp->dmanr, virt_to_phys(dp->nextIn),
-			      dp->dma_fragsize, DDMA_FLAGS_IE);
-
-	dp->nextIn += dp->dma_fragsize;
-	if (dp->nextIn >= dp->rawbuf + dp->dmasize)
-		dp->nextIn -= dp->dmasize;
-
-	dp->count += obytes;
-	dp->total_bytes += obytes;
-
-	/* wake up anybody listening
-	*/
-	if (waitqueue_active(&dp->wait))
-		wake_up(&dp->wait);
-
-	spin_unlock(&s->lock);
-}
-
-static loff_t
-au1550_llseek(struct file *file, loff_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
-
-static int
-au1550_open_mixdev(struct inode *inode, struct file *file)
-{
-	mutex_lock(&au1550_ac97_mutex);
-	file->private_data = &au1550_state;
-	mutex_unlock(&au1550_ac97_mutex);
-	return 0;
-}
-
-static int
-au1550_release_mixdev(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static int
-mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
-                        unsigned long arg)
-{
-	return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static long
-au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct au1550_state *s = file->private_data;
-	struct ac97_codec *codec = s->codec;
-	int ret;
-
-	mutex_lock(&au1550_ac97_mutex);
-	ret = mixdev_ioctl(codec, cmd, arg);
-	mutex_unlock(&au1550_ac97_mutex);
-
-	return ret;
-}
-
-static /*const */ struct file_operations au1550_mixer_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= au1550_llseek,
-	.unlocked_ioctl	= au1550_ioctl_mixdev,
-	.open		= au1550_open_mixdev,
-	.release	= au1550_release_mixdev,
-};
-
-static int
-drain_dac(struct au1550_state *s, int nonblock)
-{
-	unsigned long   flags;
-	int             count, tmo;
-
-	if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
-		return 0;
-
-	for (;;) {
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= s->dma_dac.fragsize)
-			break;
-		if (signal_pending(current))
-			break;
-		if (nonblock)
-			return -EBUSY;
-		tmo = 1000 * count / (s->no_vra ?
-				      48000 : s->dma_dac.sample_rate);
-		tmo /= s->dma_dac.dma_bytes_per_sample;
-		au1550_delay(tmo);
-	}
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-static inline u8 S16_TO_U8(s16 ch)
-{
-	return (u8) (ch >> 8) + 0x80;
-}
-static inline s16 U8_TO_S16(u8 ch)
-{
-	return (s16) (ch - 0x80) << 8;
-}
-
-/*
- * Translates user samples to dma buffer suitable for AC'97 DAC data:
- *     If mono, copy left channel to right channel in dma buffer.
- *     If 8 bit samples, cvt to 16-bit before writing to dma buffer.
- *     If interpolating (no VRA), duplicate every audio frame src_factor times.
- */
-static int
-translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf,
-							       int dmacount)
-{
-	int             sample, i;
-	int             interp_bytes_per_sample;
-	int             num_samples;
-	int             mono = (db->num_channels == 1);
-	char            usersample[12];
-	s16             ch, dmasample[6];
-
-	if (db->sample_size == 16 && !mono && db->src_factor == 1) {
-		/* no translation necessary, just copy
-		*/
-		if (copy_from_user(dmabuf, userbuf, dmacount))
-			return -EFAULT;
-		return dmacount;
-	}
-
-	interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
-	num_samples = dmacount / interp_bytes_per_sample;
-
-	for (sample = 0; sample < num_samples; sample++) {
-		if (copy_from_user(usersample, userbuf,
-				   db->user_bytes_per_sample)) {
-			return -EFAULT;
-		}
-
-		for (i = 0; i < db->num_channels; i++) {
-			if (db->sample_size == 8)
-				ch = U8_TO_S16(usersample[i]);
-			else
-				ch = *((s16 *) (&usersample[i * 2]));
-			dmasample[i] = ch;
-			if (mono)
-				dmasample[i + 1] = ch;	/* right channel */
-		}
-
-		/* duplicate every audio frame src_factor times
-		*/
-		for (i = 0; i < db->src_factor; i++)
-			memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
-
-		userbuf += db->user_bytes_per_sample;
-		dmabuf += interp_bytes_per_sample;
-	}
-
-	return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Translates AC'97 ADC samples to user buffer:
- *     If mono, send only left channel to user buffer.
- *     If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer.
- *     If decimating (no VRA), skip over src_factor audio frames.
- */
-static int
-translate_to_user(struct dmabuf *db, char* userbuf, char* dmabuf,
-							     int dmacount)
-{
-	int             sample, i;
-	int             interp_bytes_per_sample;
-	int             num_samples;
-	int             mono = (db->num_channels == 1);
-	char            usersample[12];
-
-	if (db->sample_size == 16 && !mono && db->src_factor == 1) {
-		/* no translation necessary, just copy
-		*/
-		if (copy_to_user(userbuf, dmabuf, dmacount))
-			return -EFAULT;
-		return dmacount;
-	}
-
-	interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
-	num_samples = dmacount / interp_bytes_per_sample;
-
-	for (sample = 0; sample < num_samples; sample++) {
-		for (i = 0; i < db->num_channels; i++) {
-			if (db->sample_size == 8)
-				usersample[i] =
-					S16_TO_U8(*((s16 *) (&dmabuf[i * 2])));
-			else
-				*((s16 *) (&usersample[i * 2])) =
-					*((s16 *) (&dmabuf[i * 2]));
-		}
-
-		if (copy_to_user(userbuf, usersample,
-				 db->user_bytes_per_sample)) {
-			return -EFAULT;
-		}
-
-		userbuf += db->user_bytes_per_sample;
-		dmabuf += interp_bytes_per_sample;
-	}
-
-	return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Copy audio data to/from user buffer from/to dma buffer, taking care
- * that we wrap when reading/writing the dma buffer. Returns actual byte
- * count written to or read from the dma buffer.
- */
-static int
-copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
-{
-	char           *bufptr = to_user ? db->nextOut : db->nextIn;
-	char           *bufend = db->rawbuf + db->dmasize;
-	int             cnt, ret;
-
-	if (bufptr + count > bufend) {
-		int             partial = (int) (bufend - bufptr);
-		if (to_user) {
-			if ((cnt = translate_to_user(db, userbuf,
-						     bufptr, partial)) < 0)
-				return cnt;
-			ret = cnt;
-			if ((cnt = translate_to_user(db, userbuf + partial,
-						     db->rawbuf,
-						     count - partial)) < 0)
-				return cnt;
-			ret += cnt;
-		} else {
-			if ((cnt = translate_from_user(db, bufptr, userbuf,
-						       partial)) < 0)
-				return cnt;
-			ret = cnt;
-			if ((cnt = translate_from_user(db, db->rawbuf,
-						       userbuf + partial,
-						       count - partial)) < 0)
-				return cnt;
-			ret += cnt;
-		}
-	} else {
-		if (to_user)
-			ret = translate_to_user(db, userbuf, bufptr, count);
-		else
-			ret = translate_from_user(db, bufptr, userbuf, count);
-	}
-
-	return ret;
-}
-
-
-static ssize_t
-au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
-{
-	struct au1550_state *s = file->private_data;
-	struct dmabuf  *db = &s->dma_adc;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t         ret;
-	unsigned long   flags;
-	int             cnt, usercnt, avail;
-
-	if (db->mapped)
-		return -ENXIO;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	ret = 0;
-
-	count *= db->cnt_factor;
-
-	mutex_lock(&s->sem);
-	add_wait_queue(&db->wait, &wait);
-
-	while (count > 0) {
-		/* wait for samples in ADC dma buffer
-		*/
-		do {
-			spin_lock_irqsave(&s->lock, flags);
-			if (db->stopped)
-				start_adc(s);
-			avail = db->count;
-			if (avail <= 0)
-				__set_current_state(TASK_INTERRUPTIBLE);
-			spin_unlock_irqrestore(&s->lock, flags);
-			if (avail <= 0) {
-				if (file->f_flags & O_NONBLOCK) {
-					if (!ret)
-						ret = -EAGAIN;
-					goto out;
-				}
-				mutex_unlock(&s->sem);
-				schedule();
-				if (signal_pending(current)) {
-					if (!ret)
-						ret = -ERESTARTSYS;
-					goto out2;
-				}
-				mutex_lock(&s->sem);
-			}
-		} while (avail <= 0);
-
-		/* copy from nextOut to user
-		*/
-		if ((cnt = copy_dmabuf_user(db, buffer,
-					    count > avail ?
-					    avail : count, 1)) < 0) {
-			if (!ret)
-				ret = -EFAULT;
-			goto out;
-		}
-
-		spin_lock_irqsave(&s->lock, flags);
-		db->count -= cnt;
-		db->nextOut += cnt;
-		if (db->nextOut >= db->rawbuf + db->dmasize)
-			db->nextOut -= db->dmasize;
-		spin_unlock_irqrestore(&s->lock, flags);
-
-		count -= cnt;
-		usercnt = cnt / db->cnt_factor;
-		buffer += usercnt;
-		ret += usercnt;
-	}			/* while (count > 0) */
-
-out:
-	mutex_unlock(&s->sem);
-out2:
-	remove_wait_queue(&db->wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-static ssize_t
-au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
-{
-	struct au1550_state *s = file->private_data;
-	struct dmabuf  *db = &s->dma_dac;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t         ret = 0;
-	unsigned long   flags;
-	int             cnt, usercnt, avail;
-
-	pr_debug("write: count=%d\n", count);
-
-	if (db->mapped)
-		return -ENXIO;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-
-	count *= db->cnt_factor;
-
-	mutex_lock(&s->sem);
-	add_wait_queue(&db->wait, &wait);
-
-	while (count > 0) {
-		/* wait for space in playback buffer
-		*/
-		do {
-			spin_lock_irqsave(&s->lock, flags);
-			avail = (int) db->dmasize - db->count;
-			if (avail <= 0)
-				__set_current_state(TASK_INTERRUPTIBLE);
-			spin_unlock_irqrestore(&s->lock, flags);
-			if (avail <= 0) {
-				if (file->f_flags & O_NONBLOCK) {
-					if (!ret)
-						ret = -EAGAIN;
-					goto out;
-				}
-				mutex_unlock(&s->sem);
-				schedule();
-				if (signal_pending(current)) {
-					if (!ret)
-						ret = -ERESTARTSYS;
-					goto out2;
-				}
-				mutex_lock(&s->sem);
-			}
-		} while (avail <= 0);
-
-		/* copy from user to nextIn
-		*/
-		if ((cnt = copy_dmabuf_user(db, (char *) buffer,
-					    count > avail ?
-					    avail : count, 0)) < 0) {
-			if (!ret)
-				ret = -EFAULT;
-			goto out;
-		}
-
-		spin_lock_irqsave(&s->lock, flags);
-		db->count += cnt;
-		db->nextIn += cnt;
-		if (db->nextIn >= db->rawbuf + db->dmasize)
-			db->nextIn -= db->dmasize;
-
-		/* If the data is available, we want to keep two buffers
-		 * on the dma queue.  If the queue count reaches zero,
-		 * we know the dma has stopped.
-		 */
-		while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) {
-			if (au1xxx_dbdma_put_source(db->dmanr,
-				virt_to_phys(db->nextOut), db->fragsize,
-				DDMA_FLAGS_IE) == 0) {
-				err("qcount < 2 and no ring room!");
-			}
-			db->nextOut += db->fragsize;
-			if (db->nextOut >= db->rawbuf + db->dmasize)
-				db->nextOut -= db->dmasize;
-			db->total_bytes += db->dma_fragsize;
-			if (db->dma_qcount == 0)
-				start_dac(s);
-			db->dma_qcount++;
-		}
-		spin_unlock_irqrestore(&s->lock, flags);
-
-		count -= cnt;
-		usercnt = cnt / db->cnt_factor;
-		buffer += usercnt;
-		ret += usercnt;
-	}			/* while (count > 0) */
-
-out:
-	mutex_unlock(&s->sem);
-out2:
-	remove_wait_queue(&db->wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int
-au1550_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct au1550_state *s = file->private_data;
-	unsigned long   flags;
-	unsigned int    mask = 0;
-
-	if (file->f_mode & FMODE_WRITE) {
-		if (!s->dma_dac.ready)
-			return 0;
-		poll_wait(file, &s->dma_dac.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!s->dma_adc.ready)
-			return 0;
-		poll_wait(file, &s->dma_adc.wait, wait);
-	}
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->dma_dac.mapped) {
-			if (s->dma_dac.count >=
-			    (signed)s->dma_dac.dma_fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed) s->dma_dac.dmasize >=
-			    s->dma_dac.count + (signed)s->dma_dac.dma_fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int
-au1550_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct au1550_state *s = file->private_data;
-	struct dmabuf  *db;
-	unsigned long   size;
-	int ret = 0;
-
-	mutex_lock(&au1550_ac97_mutex);
-	mutex_lock(&s->sem);
-	if (vma->vm_flags & VM_WRITE)
-		db = &s->dma_dac;
-	else if (vma->vm_flags & VM_READ)
-		db = &s->dma_adc;
-	else {
-		ret = -EINVAL;
-		goto out;
-	}
-	if (vma->vm_pgoff != 0) {
-		ret = -EINVAL;
-		goto out;
-	}
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << db->buforder)) {
-		ret = -EINVAL;
-		goto out;
-	}
-	if (remap_pfn_range(vma, vma->vm_start, page_to_pfn(virt_to_page(db->rawbuf)),
-			     size, vma->vm_page_prot)) {
-		ret = -EAGAIN;
-		goto out;
-	}
-	vma->vm_flags &= ~VM_IO;
-	db->mapped = 1;
-out:
-	mutex_unlock(&s->sem);
-	mutex_unlock(&au1550_ac97_mutex);
-	return ret;
-}
-
-#ifdef DEBUG
-static struct ioctl_str_t {
-	unsigned int    cmd;
-	const char     *str;
-} ioctl_str[] = {
-	{SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
-	{SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
-	{SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
-	{SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
-	{SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
-	{SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
-	{SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
-	{SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
-	{SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
-	{SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
-	{SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
-	{SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
-	{SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
-	{SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
-	{SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
-	{SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
-	{SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
-	{SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
-	{SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
-	{SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
-	{SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
-	{SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
-	{SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
-	{SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
-	{SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
-	{SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
-	{SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
-	{SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
-	{SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
-	{OSS_GETVERSION, "OSS_GETVERSION"},
-	{SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
-	{SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
-	{SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
-	{SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
-};
-#endif
-
-static int
-dma_count_done(struct dmabuf *db)
-{
-	if (db->stopped)
-		return 0;
-
-	return db->dma_fragsize - au1xxx_get_dma_residue(db->dmanr);
-}
-
-
-static int
-au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct au1550_state *s = file->private_data;
-	unsigned long   flags;
-	audio_buf_info  abinfo;
-	count_info      cinfo;
-	int             count;
-	int             val, mapped, ret, diff;
-
-	mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-
-#ifdef DEBUG
-	for (count = 0; count < ARRAY_SIZE(ioctl_str); count++) {
-		if (ioctl_str[count].cmd == cmd)
-			break;
-	}
-	if (count < ARRAY_SIZE(ioctl_str))
-		pr_debug("ioctl %s, arg=0x%lxn", ioctl_str[count].str, arg);
-	else
-		pr_debug("ioctl 0x%x unknown, arg=0x%lx\n", cmd, arg);
-#endif
-
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, (int *) arg);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac(s, file->f_flags & O_NONBLOCK);
-		return 0;
-
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
-				DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
-
-	case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			synchronize_irq();
-			s->dma_dac.count = s->dma_dac.total_bytes = 0;
-			s->dma_dac.nextIn = s->dma_dac.nextOut =
-				s->dma_dac.rawbuf;
-		}
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			synchronize_irq();
-			s->dma_adc.count = s->dma_adc.total_bytes = 0;
-			s->dma_adc.nextIn = s->dma_adc.nextOut =
-				s->dma_adc.rawbuf;
-		}
-		return 0;
-
-	case SNDCTL_DSP_SPEED:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val >= 0) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				set_adc_rate(s, val);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				set_dac_rate(s, val);
-			}
-			if (s->open_mode & FMODE_READ)
-				if ((ret = prog_dmabuf_adc(s)))
-					return ret;
-			if (s->open_mode & FMODE_WRITE)
-				if ((ret = prog_dmabuf_dac(s)))
-					return ret;
-		}
-		return put_user((file->f_mode & FMODE_READ) ?
-				s->dma_adc.sample_rate :
-				s->dma_dac.sample_rate,
-				(int *)arg);
-
-	case SNDCTL_DSP_STEREO:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.num_channels = val ? 2 : 1;
-			if ((ret = prog_dmabuf_adc(s)))
-				return ret;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.num_channels = val ? 2 : 1;
-			if (s->codec_ext_caps & AC97_EXT_DACS) {
-				/* disable surround and center/lfe in AC'97
-				*/
-				u16 ext_stat = rdcodec(s->codec,
-						       AC97_EXTENDED_STATUS);
-				wrcodec(s->codec, AC97_EXTENDED_STATUS,
-					ext_stat | (AC97_EXTSTAT_PRI |
-						    AC97_EXTSTAT_PRJ |
-						    AC97_EXTSTAT_PRK));
-			}
-			if ((ret = prog_dmabuf_dac(s)))
-				return ret;
-		}
-		return 0;
-
-	case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val != 0) {
-			if (file->f_mode & FMODE_READ) {
-				if (val < 0 || val > 2)
-					return -EINVAL;
-				stop_adc(s);
-				s->dma_adc.num_channels = val;
-				if ((ret = prog_dmabuf_adc(s)))
-					return ret;
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				switch (val) {
-				case 1:
-				case 2:
-					break;
-				case 3:
-				case 5:
-					return -EINVAL;
-				case 4:
-					if (!(s->codec_ext_caps &
-					      AC97_EXTID_SDAC))
-						return -EINVAL;
-					break;
-				case 6:
-					if ((s->codec_ext_caps &
-					     AC97_EXT_DACS) != AC97_EXT_DACS)
-						return -EINVAL;
-					break;
-				default:
-					return -EINVAL;
-				}
-
-				stop_dac(s);
-				if (val <= 2 &&
-				    (s->codec_ext_caps & AC97_EXT_DACS)) {
-					/* disable surround and center/lfe
-					 * channels in AC'97
-					 */
-					u16             ext_stat =
-						rdcodec(s->codec,
-							AC97_EXTENDED_STATUS);
-					wrcodec(s->codec,
-						AC97_EXTENDED_STATUS,
-						ext_stat | (AC97_EXTSTAT_PRI |
-							    AC97_EXTSTAT_PRJ |
-							    AC97_EXTSTAT_PRK));
-				} else if (val >= 4) {
-					/* enable surround, center/lfe
-					 * channels in AC'97
-					 */
-					u16             ext_stat =
-						rdcodec(s->codec,
-							AC97_EXTENDED_STATUS);
-					ext_stat &= ~AC97_EXTSTAT_PRJ;
-					if (val == 6)
-						ext_stat &=
-							~(AC97_EXTSTAT_PRI |
-							  AC97_EXTSTAT_PRK);
-					wrcodec(s->codec,
-						AC97_EXTENDED_STATUS,
-						ext_stat);
-				}
-
-				s->dma_dac.num_channels = val;
-				if ((ret = prog_dmabuf_dac(s)))
-					return ret;
-			}
-		}
-		return put_user(val, (int *) arg);
-
-	case SNDCTL_DSP_GETFMTS:	/* Returns a mask */
-		return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
-
-	case SNDCTL_DSP_SETFMT:	/* Selects ONE fmt */
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				if (val == AFMT_S16_LE)
-					s->dma_adc.sample_size = 16;
-				else {
-					val = AFMT_U8;
-					s->dma_adc.sample_size = 8;
-				}
-				if ((ret = prog_dmabuf_adc(s)))
-					return ret;
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				if (val == AFMT_S16_LE)
-					s->dma_dac.sample_size = 16;
-				else {
-					val = AFMT_U8;
-					s->dma_dac.sample_size = 8;
-				}
-				if ((ret = prog_dmabuf_dac(s)))
-					return ret;
-			}
-		} else {
-			if (file->f_mode & FMODE_READ)
-				val = (s->dma_adc.sample_size == 16) ?
-					AFMT_S16_LE : AFMT_U8;
-			else
-				val = (s->dma_dac.sample_size == 16) ?
-					AFMT_S16_LE : AFMT_U8;
-		}
-		return put_user(val, (int *) arg);
-
-	case SNDCTL_DSP_POST:
-		return 0;
-
-	case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		spin_lock_irqsave(&s->lock, flags);
-		if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
-			val |= PCM_ENABLE_OUTPUT;
-		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, (int *) arg);
-
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				spin_lock_irqsave(&s->lock, flags);
-				start_adc(s);
-				spin_unlock_irqrestore(&s->lock, flags);
-			} else
-				stop_adc(s);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				spin_lock_irqsave(&s->lock, flags);
-				start_dac(s);
-				spin_unlock_irqrestore(&s->lock, flags);
-			} else
-				stop_dac(s);
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		abinfo.fragsize = s->dma_dac.fragsize;
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-		count -= dma_count_done(&s->dma_dac);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		abinfo.bytes = (s->dma_dac.dmasize - count) /
-			s->dma_dac.cnt_factor;
-		abinfo.fragstotal = s->dma_dac.numfrag;
-		abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
-		pr_debug("ioctl SNDCTL_DSP_GETOSPACE: bytes=%d, fragments=%d\n", abinfo.bytes, abinfo.fragments);
-		return copy_to_user((void *) arg, &abinfo,
-				    sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		abinfo.fragsize = s->dma_adc.fragsize;
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_adc.count;
-		count += dma_count_done(&s->dma_adc);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		abinfo.bytes = count / s->dma_adc.cnt_factor;
-		abinfo.fragstotal = s->dma_adc.numfrag;
-		abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
-		return copy_to_user((void *) arg, &abinfo,
-				    sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_NONBLOCK:
-		spin_lock(&file->f_lock);
-		file->f_flags |= O_NONBLOCK;
-		spin_unlock(&file->f_lock);
-		return 0;
-
-	case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-		count -= dma_count_done(&s->dma_dac);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		count /= s->dma_dac.cnt_factor;
-		return put_user(count, (int *) arg);
-
-	case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		cinfo.bytes = s->dma_adc.total_bytes;
-		count = s->dma_adc.count;
-		if (!s->dma_adc.stopped) {
-			diff = dma_count_done(&s->dma_adc);
-			count += diff;
-			cinfo.bytes += diff;
-			cinfo.ptr =  virt_to_phys(s->dma_adc.nextIn) + diff -
-				virt_to_phys(s->dma_adc.rawbuf);
-		} else
-			cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) -
-				virt_to_phys(s->dma_adc.rawbuf);
-		if (s->dma_adc.mapped)
-			s->dma_adc.count &= (s->dma_adc.dma_fragsize-1);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		cinfo.blocks = count >> s->dma_adc.fragshift;
-		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
-
-	case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		cinfo.bytes = s->dma_dac.total_bytes;
-		count = s->dma_dac.count;
-		if (!s->dma_dac.stopped) {
-			diff = dma_count_done(&s->dma_dac);
-			count -= diff;
-			cinfo.bytes += diff;
-			cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff -
-				virt_to_phys(s->dma_dac.rawbuf);
-		} else
-			cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) -
-				virt_to_phys(s->dma_dac.rawbuf);
-		if (s->dma_dac.mapped)
-			s->dma_dac.count &= (s->dma_dac.dma_fragsize-1);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		cinfo.blocks = count >> s->dma_dac.fragshift;
-		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
-
-	case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE)
-			return put_user(s->dma_dac.fragsize, (int *) arg);
-		else
-			return put_user(s->dma_adc.fragsize, (int *) arg);
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.ossfragshift = val & 0xffff;
-			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_adc.ossfragshift < 4)
-				s->dma_adc.ossfragshift = 4;
-			if (s->dma_adc.ossfragshift > 15)
-				s->dma_adc.ossfragshift = 15;
-			if (s->dma_adc.ossmaxfrags < 4)
-				s->dma_adc.ossmaxfrags = 4;
-			if ((ret = prog_dmabuf_adc(s)))
-				return ret;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.ossfragshift = val & 0xffff;
-			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_dac.ossfragshift < 4)
-				s->dma_dac.ossfragshift = 4;
-			if (s->dma_dac.ossfragshift > 15)
-				s->dma_dac.ossfragshift = 15;
-			if (s->dma_dac.ossmaxfrags < 4)
-				s->dma_dac.ossmaxfrags = 4;
-			if ((ret = prog_dmabuf_dac(s)))
-				return ret;
-		}
-		return 0;
-
-	case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
-			return -EINVAL;
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.subdivision = val;
-			if ((ret = prog_dmabuf_adc(s)))
-				return ret;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.subdivision = val;
-			if ((ret = prog_dmabuf_dac(s)))
-				return ret;
-		}
-		return 0;
-
-	case SOUND_PCM_READ_RATE:
-		return put_user((file->f_mode & FMODE_READ) ?
-				s->dma_adc.sample_rate :
-				s->dma_dac.sample_rate,
-				(int *)arg);
-
-	case SOUND_PCM_READ_CHANNELS:
-		if (file->f_mode & FMODE_READ)
-			return put_user(s->dma_adc.num_channels, (int *)arg);
-		else
-			return put_user(s->dma_dac.num_channels, (int *)arg);
-
-	case SOUND_PCM_READ_BITS:
-		if (file->f_mode & FMODE_READ)
-			return put_user(s->dma_adc.sample_size, (int *)arg);
-		else
-			return put_user(s->dma_dac.sample_size, (int *)arg);
-
-	case SOUND_PCM_WRITE_FILTER:
-	case SNDCTL_DSP_SETSYNCRO:
-	case SOUND_PCM_READ_FILTER:
-		return -EINVAL;
-	}
-
-	return mixdev_ioctl(s->codec, cmd, arg);
-}
-
-static long
-au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	int ret;
-
-	mutex_lock(&au1550_ac97_mutex);
-	ret = au1550_ioctl(file, cmd, arg);
-	mutex_unlock(&au1550_ac97_mutex);
-
-	return ret;
-}
-
-static int
-au1550_open(struct inode *inode, struct file *file)
-{
-	int             minor = MINOR(inode->i_rdev);
-	DECLARE_WAITQUEUE(wait, current);
-	struct au1550_state *s = &au1550_state;
-	int             ret;
-
-#ifdef DEBUG
-	if (file->f_flags & O_NONBLOCK)
-		pr_debug("open: non-blocking\n");
-	else
-		pr_debug("open: blocking\n");
-#endif
-
-	file->private_data = s;
-	mutex_lock(&au1550_ac97_mutex);
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & file->f_mode) {
-		ret = -EBUSY;
-		if (file->f_flags & O_NONBLOCK)
-			goto out;
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		ret = -ERESTARTSYS;
-		if (signal_pending(current))
-			goto out2;
-		mutex_lock(&s->open_mutex);
-	}
-
-	stop_dac(s);
-	stop_adc(s);
-
-	if (file->f_mode & FMODE_READ) {
-		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
-			s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
-		s->dma_adc.num_channels = 1;
-		s->dma_adc.sample_size = 8;
-		set_adc_rate(s, 8000);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			s->dma_adc.sample_size = 16;
-	}
-
-	if (file->f_mode & FMODE_WRITE) {
-		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
-			s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
-		s->dma_dac.num_channels = 1;
-		s->dma_dac.sample_size = 8;
-		set_dac_rate(s, 8000);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			s->dma_dac.sample_size = 16;
-	}
-
-	if (file->f_mode & FMODE_READ) {
-		if ((ret = prog_dmabuf_adc(s)))
-			goto out;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if ((ret = prog_dmabuf_dac(s)))
-			goto out;
-	}
-
-	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	mutex_init(&s->sem);
-	ret = 0;
-out:
-	mutex_unlock(&s->open_mutex);
-out2:
-	mutex_unlock(&au1550_ac97_mutex);
-	return ret;
-}
-
-static int
-au1550_release(struct inode *inode, struct file *file)
-{
-	struct au1550_state *s = file->private_data;
-
-	mutex_lock(&au1550_ac97_mutex);
-
-	if (file->f_mode & FMODE_WRITE) {
-		mutex_unlock(&au1550_ac97_mutex);
-		drain_dac(s, file->f_flags & O_NONBLOCK);
-		mutex_lock(&au1550_ac97_mutex);
-	}
-
-	mutex_lock(&s->open_mutex);
-	if (file->f_mode & FMODE_WRITE) {
-		stop_dac(s);
-		kfree(s->dma_dac.rawbuf);
-		s->dma_dac.rawbuf = NULL;
-	}
-	if (file->f_mode & FMODE_READ) {
-		stop_adc(s);
-		kfree(s->dma_adc.rawbuf);
-		s->dma_adc.rawbuf = NULL;
-	}
-	s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
-	mutex_unlock(&s->open_mutex);
-	wake_up(&s->open_wait);
-	mutex_unlock(&au1550_ac97_mutex);
-	return 0;
-}
-
-static /*const */ struct file_operations au1550_audio_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= au1550_llseek,
-	.read		= au1550_read,
-	.write		= au1550_write,
-	.poll		= au1550_poll,
-	.unlocked_ioctl	= au1550_unlocked_ioctl,
-	.mmap		= au1550_mmap,
-	.open		= au1550_open,
-	.release	= au1550_release,
-};
-
-MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
-MODULE_DESCRIPTION("Au1550 AC97 Audio Driver");
-MODULE_LICENSE("GPL");
-
-
-static int __devinit
-au1550_probe(void)
-{
-	struct au1550_state *s = &au1550_state;
-	int             val;
-
-	memset(s, 0, sizeof(struct au1550_state));
-
-	init_waitqueue_head(&s->dma_adc.wait);
-	init_waitqueue_head(&s->dma_dac.wait);
-	init_waitqueue_head(&s->open_wait);
-	mutex_init(&s->open_mutex);
-	spin_lock_init(&s->lock);
-
-	s->codec = ac97_alloc_codec();
-	if(s->codec == NULL) {
-		err("Out of memory");
-		return -1;
-	}
-	s->codec->private_data = s;
-	s->codec->id = 0;
-	s->codec->codec_read = rdcodec;
-	s->codec->codec_write = wrcodec;
-	s->codec->codec_wait = waitcodec;
-
-	if (!request_mem_region(CPHYSADDR(AC97_PSC_SEL),
-			    0x30, "Au1550 AC97")) {
-		err("AC'97 ports in use");
-	}
-
-	/* Allocate the DMA Channels
-	*/
-	if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN,
-	    DBDMA_AC97_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) {
-		err("Can't get DAC DMA");
-		goto err_dma1;
-	}
-	au1xxx_dbdma_set_devwidth(s->dma_dac.dmanr, 16);
-	if (au1xxx_dbdma_ring_alloc(s->dma_dac.dmanr,
-					NUM_DBDMA_DESCRIPTORS) == 0) {
-		err("Can't get DAC DMA descriptors");
-		goto err_dma1;
-	}
-
-	if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_AC97_RX_CHAN,
-	    DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) {
-		err("Can't get ADC DMA");
-		goto err_dma2;
-	}
-	au1xxx_dbdma_set_devwidth(s->dma_adc.dmanr, 16);
-	if (au1xxx_dbdma_ring_alloc(s->dma_adc.dmanr,
-					NUM_DBDMA_DESCRIPTORS) == 0) {
-		err("Can't get ADC DMA descriptors");
-		goto err_dma2;
-	}
-
-	pr_info("DAC: DMA%d, ADC: DMA%d", DBDMA_AC97_TX_CHAN, DBDMA_AC97_RX_CHAN);
-
-	/* register devices */
-
-	if ((s->dev_audio = register_sound_dsp(&au1550_audio_fops, -1)) < 0)
-		goto err_dev1;
-	if ((s->codec->dev_mixer =
-	     register_sound_mixer(&au1550_mixer_fops, -1)) < 0)
-		goto err_dev2;
-
-	/* The GPIO for the appropriate PSC was configured by the
-	 * board specific start up.
-	 *
-	 * configure PSC for AC'97
-	 */
-	au_writel(0, AC97_PSC_CTRL);	/* Disable PSC */
-	au_sync();
-	au_writel((PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE), AC97_PSC_SEL);
-	au_sync();
-
-	/* cold reset the AC'97
-	*/
-	au_writel(PSC_AC97RST_RST, PSC_AC97RST);
-	au_sync();
-	au1550_delay(10);
-	au_writel(0, PSC_AC97RST);
-	au_sync();
-
-	/* need to delay around 500msec(bleech) to give
-	   some CODECs enough time to wakeup */
-	au1550_delay(500);
-
-	/* warm reset the AC'97 to start the bitclk
-	*/
-	au_writel(PSC_AC97RST_SNC, PSC_AC97RST);
-	au_sync();
-	udelay(100);
-	au_writel(0, PSC_AC97RST);
-	au_sync();
-
-	/* Enable PSC
-	*/
-	au_writel(PSC_CTRL_ENABLE, AC97_PSC_CTRL);
-	au_sync();
-
-	/* Wait for PSC ready.
-	*/
-	do {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((val & PSC_AC97STAT_SR) == 0);
-
-	/* Configure AC97 controller.
-	 * Deep FIFO, 16-bit sample, DMA, make sure DMA matches fifo size.
-	 */
-	val = PSC_AC97CFG_SET_LEN(16);
-	val |= PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8;
-
-	/* Enable device so we can at least
-	 * talk over the AC-link.
-	 */
-	au_writel(val, PSC_AC97CFG);
-	au_writel(PSC_AC97MSK_ALLMASK, PSC_AC97MSK);
-	au_sync();
-	val |= PSC_AC97CFG_DE_ENABLE;
-	au_writel(val, PSC_AC97CFG);
-	au_sync();
-
-	/* Wait for Device ready.
-	*/
-	do {
-		val = au_readl(PSC_AC97STAT);
-		au_sync();
-	} while ((val & PSC_AC97STAT_DR) == 0);
-
-	/* codec init */
-	if (!ac97_probe_codec(s->codec))
-		goto err_dev3;
-
-	s->codec_base_caps = rdcodec(s->codec, AC97_RESET);
-	s->codec_ext_caps = rdcodec(s->codec, AC97_EXTENDED_ID);
-	pr_info("AC'97 Base/Extended ID = %04x/%04x",
-	     s->codec_base_caps, s->codec_ext_caps);
-
-	if (!(s->codec_ext_caps & AC97_EXTID_VRA)) {
-		/* codec does not support VRA
-		*/
-		s->no_vra = 1;
-	} else if (!vra) {
-		/* Boot option says disable VRA
-		*/
-		u16 ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-		wrcodec(s->codec, AC97_EXTENDED_STATUS,
-			ac97_extstat & ~AC97_EXTSTAT_VRA);
-		s->no_vra = 1;
-	}
-	if (s->no_vra)
-		pr_info("no VRA, interpolating and decimating");
-
-	/* set mic to be the recording source */
-	val = SOUND_MASK_MIC;
-	mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC,
-		     (unsigned long) &val);
-
-	return 0;
-
- err_dev3:
-	unregister_sound_mixer(s->codec->dev_mixer);
- err_dev2:
-	unregister_sound_dsp(s->dev_audio);
- err_dev1:
-	au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
- err_dma2:
-	au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
- err_dma1:
-	release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30);
-
-	ac97_release_codec(s->codec);
-	return -1;
-}
-
-static void __devinit
-au1550_remove(void)
-{
-	struct au1550_state *s = &au1550_state;
-
-	if (!s)
-		return;
-	synchronize_irq();
-	au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
-	au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
-	release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30);
-	unregister_sound_dsp(s->dev_audio);
-	unregister_sound_mixer(s->codec->dev_mixer);
-	ac97_release_codec(s->codec);
-}
-
-static int __init
-init_au1550(void)
-{
-	return au1550_probe();
-}
-
-static void __exit
-cleanup_au1550(void)
-{
-	au1550_remove();
-}
-
-module_init(init_au1550);
-module_exit(cleanup_au1550);
-
-#ifndef MODULE
-
-static int __init
-au1550_setup(char *options)
-{
-	char           *this_opt;
-
-	if (!options || !*options)
-		return 0;
-
-	while ((this_opt = strsep(&options, ","))) {
-		if (!*this_opt)
-			continue;
-		if (!strncmp(this_opt, "vra", 3)) {
-			vra = 1;
-		}
-	}
-
-	return 1;
-}
-
-__setup("au1550_audio=", au1550_setup);
-
-#endif /* MODULE */

+ 22 - 5
sound/pci/Kconfig

@@ -534,6 +534,14 @@ config SND_ES1968_INPUT
 	  If you say N the buttons will directly control the master volume.
 	  If you say N the buttons will directly control the master volume.
 	  It is recommended to say Y.
 	  It is recommended to say Y.
 
 
+config SND_ES1968_RADIO
+	bool "Enable TEA5757 radio tuner support for es1968"
+	depends on SND_ES1968
+	depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_ES1968
+	help
+	  Say Y here to include support for TEA5757 radio tuner integrated on
+	  some MediaForte cards (e.g. SF64-PCE2).
+
 config SND_FM801
 config SND_FM801
 	tristate "ForteMedia FM801"
 	tristate "ForteMedia FM801"
 	select SND_OPL3_LIB
 	select SND_OPL3_LIB
@@ -552,13 +560,13 @@ config SND_FM801_TEA575X_BOOL
 	depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801
 	depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801
 	help
 	help
 	  Say Y here to include support for soundcards based on the ForteMedia
 	  Say Y here to include support for soundcards based on the ForteMedia
-	  FM801 chip with a TEA5757 tuner connected to GPIO1-3 pins (Media
-	  Forte SF256-PCS-02) into the snd-fm801 driver.
+	  FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and
+	  SF64-PCR) into the snd-fm801 driver.
 
 
-config SND_FM801_TEA575X
+config SND_TEA575X
 	tristate
 	tristate
-	depends on SND_FM801_TEA575X_BOOL
-	default SND_FM801
+	depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO
+	default SND_FM801 || SND_ES1968
 
 
 source "sound/pci/hda/Kconfig"
 source "sound/pci/hda/Kconfig"
 
 
@@ -658,6 +666,15 @@ config SND_KORG1212
 	  To compile this driver as a module, choose M here: the module
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-korg1212.
 	  will be called snd-korg1212.
 
 
+config SND_LOLA
+	tristate "Digigram Lola"
+	select SND_PCM
+	help
+	  Say Y to include support for Digigram Lola boards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-lola.
+
 config SND_LX6464ES
 config SND_LX6464ES
 	tristate "Digigram LX6464ES"
 	tristate "Digigram LX6464ES"
 	select SND_PCM
 	select SND_PCM

+ 1 - 0
sound/pci/Makefile

@@ -64,6 +64,7 @@ obj-$(CONFIG_SND) += \
 	ca0106/ \
 	ca0106/ \
 	cs46xx/ \
 	cs46xx/ \
 	cs5535audio/ \
 	cs5535audio/ \
+	lola/ \
 	lx6464es/ \
 	lx6464es/ \
 	echoaudio/ \
 	echoaudio/ \
 	emu10k1/ \
 	emu10k1/ \

+ 142 - 186
sound/pci/asihpi/asihpi.c

@@ -42,10 +42,29 @@
 #include <sound/tlv.h>
 #include <sound/tlv.h>
 #include <sound/hwdep.h>
 #include <sound/hwdep.h>
 
 
+
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
 MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
 MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
 MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
 
 
+#if defined CONFIG_SND_DEBUG
+/* copied from pcm_lib.c, hope later patch will make that version public
+and this copy can be removed */
+static void pcm_debug_name(struct snd_pcm_substream *substream,
+			   char *name, size_t len)
+{
+	snprintf(name, len, "pcmC%dD%d%c:%d",
+		 substream->pcm->card->number,
+		 substream->pcm->device,
+		 substream->stream ? 'c' : 'p',
+		 substream->number);
+}
+#define DEBUG_NAME(substream, name) char name[16]; pcm_debug_name(substream, name, sizeof(name))
+#else
+#define pcm_debug_name(s, n, l) do { } while (0)
+#define DEBUG_NAME(name, substream) do { } while (0)
+#endif
+
 #if defined CONFIG_SND_DEBUG_VERBOSE
 #if defined CONFIG_SND_DEBUG_VERBOSE
 /**
 /**
  * snd_printddd - very verbose debug printk
  * snd_printddd - very verbose debug printk
@@ -58,7 +77,7 @@ MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
 #define snd_printddd(format, args...) \
 #define snd_printddd(format, args...) \
 	__snd_printk(3, __FILE__, __LINE__, format, ##args)
 	__snd_printk(3, __FILE__, __LINE__, format, ##args)
 #else
 #else
-#define snd_printddd(format, args...)	do { } while (0)
+#define snd_printddd(format, args...) do { } while (0)
 #endif
 #endif
 
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* index 0-MAX */
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* index 0-MAX */
@@ -101,13 +120,6 @@ static int adapter_fs = DEFAULT_SAMPLERATE;
 #define PERIOD_BYTES_MIN  2048
 #define PERIOD_BYTES_MIN  2048
 #define BUFFER_BYTES_MAX (512 * 1024)
 #define BUFFER_BYTES_MAX (512 * 1024)
 
 
-/* convert stream to character */
-#define SCHR(s) ((s == SNDRV_PCM_STREAM_PLAYBACK) ? 'P' : 'C')
-
-/*#define TIMER_MILLISECONDS 20
-#define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000)
-*/
-
 #define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)
 #define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)
 
 
 struct clk_source {
 struct clk_source {
@@ -136,7 +148,7 @@ struct snd_card_asihpi {
 	u32 h_mixer;
 	u32 h_mixer;
 	struct clk_cache cc;
 	struct clk_cache cc;
 
 
-	u16 support_mmap;
+	u16 can_dma;
 	u16 support_grouping;
 	u16 support_grouping;
 	u16 support_mrx;
 	u16 support_mrx;
 	u16 update_interval_frames;
 	u16 update_interval_frames;
@@ -155,6 +167,7 @@ struct snd_card_asihpi_pcm {
 	unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */
 	unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */
 	unsigned int pcm_buf_dma_ofs;	/* DMA R/W offset in buffer */
 	unsigned int pcm_buf_dma_ofs;	/* DMA R/W offset in buffer */
 	unsigned int pcm_buf_elapsed_dma_ofs;	/* DMA R/W offset in buffer */
 	unsigned int pcm_buf_elapsed_dma_ofs;	/* DMA R/W offset in buffer */
+	unsigned int drained_count;
 	struct snd_pcm_substream *substream;
 	struct snd_pcm_substream *substream;
 	u32 h_stream;
 	u32 h_stream;
 	struct hpi_format format;
 	struct hpi_format format;
@@ -288,19 +301,26 @@ static u16 handle_error(u16 err, int line, char *filename)
 #define hpi_handle_error(x)  handle_error(x, __LINE__, __FILE__)
 #define hpi_handle_error(x)  handle_error(x, __LINE__, __FILE__)
 
 
 /***************************** GENERAL PCM ****************/
 /***************************** GENERAL PCM ****************/
-static void print_hwparams(struct snd_pcm_hw_params *p)
+
+static void print_hwparams(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *p)
 {
 {
-	snd_printd("HWPARAMS \n");
-	snd_printd("samplerate %d \n", params_rate(p));
-	snd_printd("Channels %d \n", params_channels(p));
-	snd_printd("Format %d \n", params_format(p));
-	snd_printd("subformat %d \n", params_subformat(p));
-	snd_printd("Buffer bytes %d \n", params_buffer_bytes(p));
-	snd_printd("Period bytes %d \n", params_period_bytes(p));
-	snd_printd("access %d \n", params_access(p));
-	snd_printd("period_size %d \n", params_period_size(p));
-	snd_printd("periods %d \n", params_periods(p));
-	snd_printd("buffer_size %d \n", params_buffer_size(p));
+	DEBUG_NAME(substream, name);
+	snd_printd("%s HWPARAMS\n", name);
+	snd_printd(" samplerate %d Hz\n", params_rate(p));
+	snd_printd(" channels %d\n", params_channels(p));
+	snd_printd(" format %d\n", params_format(p));
+	snd_printd(" subformat %d\n", params_subformat(p));
+	snd_printd(" buffer %d B\n", params_buffer_bytes(p));
+	snd_printd(" period %d B\n", params_period_bytes(p));
+	snd_printd(" access %d\n", params_access(p));
+	snd_printd(" period_size %d\n", params_period_size(p));
+	snd_printd(" periods %d\n", params_periods(p));
+	snd_printd(" buffer_size %d\n", params_buffer_size(p));
+	snd_printd(" %d B/s\n", params_rate(p) *
+		params_channels(p) *
+		snd_pcm_format_width(params_format(p)) / 8);
+
 }
 }
 
 
 static snd_pcm_format_t hpi_to_alsa_formats[] = {
 static snd_pcm_format_t hpi_to_alsa_formats[] = {
@@ -451,7 +471,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 	int width;
 	int width;
 	unsigned int bytes_per_sec;
 	unsigned int bytes_per_sec;
 
 
-	print_hwparams(params);
+	print_hwparams(substream, params);
 	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
@@ -459,10 +479,6 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
-	snd_printdd("format %d, %d chans, %d_hz\n",
-				format, params_channels(params),
-				params_rate(params));
-
 	hpi_handle_error(hpi_format_create(&dpcm->format,
 	hpi_handle_error(hpi_format_create(&dpcm->format,
 			params_channels(params),
 			params_channels(params),
 			format, params_rate(params), 0, 0));
 			format, params_rate(params), 0, 0));
@@ -477,8 +493,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 	}
 	}
 
 
 	dpcm->hpi_buffer_attached = 0;
 	dpcm->hpi_buffer_attached = 0;
-	if (card->support_mmap) {
-
+	if (card->can_dma) {
 		err = hpi_stream_host_buffer_attach(dpcm->h_stream,
 		err = hpi_stream_host_buffer_attach(dpcm->h_stream,
 			params_buffer_bytes(params),  runtime->dma_addr);
 			params_buffer_bytes(params),  runtime->dma_addr);
 		if (err == 0) {
 		if (err == 0) {
@@ -509,8 +524,6 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 	dpcm->bytes_per_sec = bytes_per_sec;
 	dpcm->bytes_per_sec = bytes_per_sec;
 	dpcm->buffer_bytes = params_buffer_bytes(params);
 	dpcm->buffer_bytes = params_buffer_bytes(params);
 	dpcm->period_bytes = params_period_bytes(params);
 	dpcm->period_bytes = params_period_bytes(params);
-	snd_printdd("buffer_bytes=%d, period_bytes=%d, bps=%d\n",
-			dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -564,9 +577,10 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
 	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
 	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
 	struct snd_pcm_substream *s;
 	struct snd_pcm_substream *s;
 	u16 e;
 	u16 e;
+	DEBUG_NAME(substream, name);
+
+	snd_printdd("%s trigger\n", name);
 
 
-	snd_printdd("%c%d trigger\n",
-			SCHR(substream->stream), substream->number);
 	switch (cmd) {
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_START:
 		snd_pcm_group_for_each_entry(s, substream) {
 		snd_pcm_group_for_each_entry(s, substream) {
@@ -580,8 +594,8 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
 			if (substream->stream != s->stream)
 			if (substream->stream != s->stream)
 				continue;
 				continue;
 
 
-			if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
-				(card->support_mmap)) {
+			ds->drained_count = 0;
+			if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 				/* How do I know how much valid data is present
 				/* How do I know how much valid data is present
 				* in buffer? Must be at least one period!
 				* in buffer? Must be at least one period!
 				* Guessing 2 periods, but if
 				* Guessing 2 periods, but if
@@ -599,9 +613,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
 			}
 			}
 
 
 			if (card->support_grouping) {
 			if (card->support_grouping) {
-				snd_printdd("\t%c%d group\n",
-						SCHR(s->stream),
-						s->number);
+				snd_printdd("%d group\n", s->number);
 				e = hpi_stream_group_add(
 				e = hpi_stream_group_add(
 					dpcm->h_stream,
 					dpcm->h_stream,
 					ds->h_stream);
 					ds->h_stream);
@@ -618,7 +630,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
 		/* start the master stream */
 		/* start the master stream */
 		snd_card_asihpi_pcm_timer_start(substream);
 		snd_card_asihpi_pcm_timer_start(substream);
 		if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
 		if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
-			!card->support_mmap)
+			!card->can_dma)
 			hpi_handle_error(hpi_stream_start(dpcm->h_stream));
 			hpi_handle_error(hpi_stream_start(dpcm->h_stream));
 		break;
 		break;
 
 
@@ -636,9 +648,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
 			s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
 			s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
 
 
 			if (card->support_grouping) {
 			if (card->support_grouping) {
-				snd_printdd("\t%c%d group\n",
-				SCHR(s->stream),
-					s->number);
+				snd_printdd("%d group\n", s->number);
 				snd_pcm_trigger_done(s, substream);
 				snd_pcm_trigger_done(s, substream);
 			} else
 			} else
 				break;
 				break;
@@ -732,9 +742,9 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 	int loops = 0;
 	int loops = 0;
 	u16 state;
 	u16 state;
 	u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
 	u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
+	DEBUG_NAME(substream, name);
 
 
-	snd_printdd("%c%d snd_card_asihpi_timer_function\n",
-				SCHR(substream->stream), substream->number);
+	snd_printdd("%s snd_card_asihpi_timer_function\n", name);
 
 
 	/* find minimum newdata and buffer pos in group */
 	/* find minimum newdata and buffer pos in group */
 	snd_pcm_group_for_each_entry(s, substream) {
 	snd_pcm_group_for_each_entry(s, substream) {
@@ -756,6 +766,9 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 		/* number of bytes in on-card buffer */
 		/* number of bytes in on-card buffer */
 		runtime->delay = on_card_bytes;
 		runtime->delay = on_card_bytes;
 
 
+		if (!card->can_dma)
+			on_card_bytes = bytes_avail;
+
 		if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 			pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
 			pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
 			if (state == HPI_STATE_STOPPED) {
 			if (state == HPI_STATE_STOPPED) {
@@ -763,12 +776,18 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 				    (on_card_bytes < ds->pcm_buf_host_rw_ofs)) {
 				    (on_card_bytes < ds->pcm_buf_host_rw_ofs)) {
 					hpi_handle_error(hpi_stream_start(ds->h_stream));
 					hpi_handle_error(hpi_stream_start(ds->h_stream));
 					snd_printdd("P%d start\n", s->number);
 					snd_printdd("P%d start\n", s->number);
+					ds->drained_count = 0;
 				}
 				}
 			} else if (state == HPI_STATE_DRAINED) {
 			} else if (state == HPI_STATE_DRAINED) {
 				snd_printd(KERN_WARNING "P%d drained\n",
 				snd_printd(KERN_WARNING "P%d drained\n",
 						s->number);
 						s->number);
-				/*snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
-				continue; */
+				ds->drained_count++;
+				if (ds->drained_count > 2) {
+					snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
+					continue;
+				}
+			} else {
+				ds->drained_count = 0;
 			}
 			}
 		} else
 		} else
 			pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;
 			pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;
@@ -786,16 +805,18 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 				newdata);
 				newdata);
 		}
 		}
 
 
-		snd_printdd("hw_ptr x%04lX, appl_ptr x%04lX\n",
+		snd_printdd("hw_ptr 0x%04lX, appl_ptr 0x%04lX\n",
 			(unsigned long)frames_to_bytes(runtime,
 			(unsigned long)frames_to_bytes(runtime,
 						runtime->status->hw_ptr),
 						runtime->status->hw_ptr),
 			(unsigned long)frames_to_bytes(runtime,
 			(unsigned long)frames_to_bytes(runtime,
 						runtime->control->appl_ptr));
 						runtime->control->appl_ptr));
 
 
-		snd_printdd("%d %c%d S=%d, rw=%04X, dma=x%04X, left=x%04X,"
-			" aux=x%04X space=x%04X\n",
-			loops, SCHR(s->stream),	s->number,
-			state,	ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, (int)bytes_avail,
+		snd_printdd("%d S=%d, "
+			"rw=0x%04X, dma=0x%04X, left=0x%04X, "
+			"aux=0x%04X space=0x%04X\n",
+			s->number, state,
+			ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs,
+			(int)bytes_avail,
 			(int)on_card_bytes, buffer_size-bytes_avail);
 			(int)on_card_bytes, buffer_size-bytes_avail);
 		loops++;
 		loops++;
 	}
 	}
@@ -814,7 +835,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 
 
 	next_jiffies = max(next_jiffies, 1U);
 	next_jiffies = max(next_jiffies, 1U);
 	dpcm->timer.expires = jiffies + next_jiffies;
 	dpcm->timer.expires = jiffies + next_jiffies;
-	snd_printdd("jif %d buf pos x%04X newdata x%04X xfer x%04X\n",
+	snd_printdd("jif %d buf pos 0x%04X newdata 0x%04X xfer 0x%04X\n",
 			next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
 			next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
 
 
 	snd_pcm_group_for_each_entry(s, substream) {
 	snd_pcm_group_for_each_entry(s, substream) {
@@ -826,30 +847,63 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 
 
 		ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
 		ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
 
 
-		if (xfercount && (on_card_bytes <= ds->period_bytes)) {
-			if (card->support_mmap) {
-				if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-					snd_printddd("P%d write x%04x\n",
+		if (xfercount &&
+			/* Limit use of on card fifo for playback */
+			((on_card_bytes <= ds->period_bytes) ||
+			(s->stream == SNDRV_PCM_STREAM_CAPTURE)))
+
+		{
+
+			unsigned int buf_ofs = ds->pcm_buf_host_rw_ofs % ds->buffer_bytes;
+			unsigned int xfer1, xfer2;
+			char *pd = &s->runtime->dma_area[buf_ofs];
+
+			if (card->can_dma) { /* buffer wrap is handled at lower level */
+				xfer1 = xfercount;
+				xfer2 = 0;
+			} else {
+				xfer1 = min(xfercount, ds->buffer_bytes - buf_ofs);
+				xfer2 = xfercount - xfer1;
+			}
+
+			if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+				snd_printddd("P%d write1 0x%04X 0x%04X\n",
+					s->number, xfer1, buf_ofs);
+				hpi_handle_error(
+					hpi_outstream_write_buf(
+						ds->h_stream, pd, xfer1,
+						&ds->format));
+
+				if (xfer2) {
+					pd = s->runtime->dma_area;
+
+					snd_printddd("P%d write2 0x%04X 0x%04X\n",
 							s->number,
 							s->number,
-							ds->period_bytes);
+							xfercount - xfer1, buf_ofs);
 					hpi_handle_error(
 					hpi_handle_error(
 						hpi_outstream_write_buf(
 						hpi_outstream_write_buf(
-							ds->h_stream,
-							&s->runtime->
-								dma_area[0],
-							xfercount,
+							ds->h_stream, pd,
+							xfercount - xfer1,
 							&ds->format));
 							&ds->format));
-				} else {
-					snd_printddd("C%d read x%04x\n",
-						s->number,
-						xfercount);
+				}
+			} else {
+				snd_printddd("C%d read1 0x%04x\n",
+					s->number, xfer1);
+				hpi_handle_error(
+					hpi_instream_read_buf(
+						ds->h_stream,
+						pd, xfer1));
+				if (xfer2) {
+					pd = s->runtime->dma_area;
+					snd_printddd("C%d read2 0x%04x\n",
+						s->number, xfer2);
 					hpi_handle_error(
 					hpi_handle_error(
 						hpi_instream_read_buf(
 						hpi_instream_read_buf(
 							ds->h_stream,
 							ds->h_stream,
-							NULL, xfercount));
+							pd, xfer2));
 				}
 				}
-				ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
-			} /* else R/W will be handled by read/write callbacks */
+			}
+			ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
 			ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
 			ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
 			snd_pcm_period_elapsed(s);
 			snd_pcm_period_elapsed(s);
 		}
 		}
@@ -863,7 +917,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
 static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
 					  unsigned int cmd, void *arg)
 					  unsigned int cmd, void *arg)
 {
 {
-	snd_printdd(KERN_INFO "Playback ioctl %d\n", cmd);
+	snd_printddd(KERN_INFO "P%d ioctl %d\n", substream->number, cmd);
 	return snd_pcm_lib_ioctl(substream, cmd, arg);
 	return snd_pcm_lib_ioctl(substream, cmd, arg);
 }
 }
 
 
@@ -873,7 +927,7 @@ static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
 	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
 
 
-	snd_printdd("playback prepare %d\n", substream->number);
+	snd_printdd("P%d prepare\n", substream->number);
 
 
 	hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
 	hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
 	dpcm->pcm_buf_host_rw_ofs = 0;
 	dpcm->pcm_buf_host_rw_ofs = 0;
@@ -890,7 +944,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
 	snd_pcm_uframes_t ptr;
 	snd_pcm_uframes_t ptr;
 
 
 	ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs  % dpcm->buffer_bytes);
 	ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs  % dpcm->buffer_bytes);
-	snd_printddd("playback_pointer=x%04lx\n", (unsigned long)ptr);
+	snd_printddd("P%d pointer = 0x%04lx\n", substream->number, (unsigned long)ptr);
 	return ptr;
 	return ptr;
 }
 }
 
 
@@ -986,11 +1040,9 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
 					SNDRV_PCM_INFO_DOUBLE |
 					SNDRV_PCM_INFO_DOUBLE |
 					SNDRV_PCM_INFO_BATCH |
 					SNDRV_PCM_INFO_BATCH |
 					SNDRV_PCM_INFO_BLOCK_TRANSFER |
 					SNDRV_PCM_INFO_BLOCK_TRANSFER |
-					SNDRV_PCM_INFO_PAUSE;
-
-	if (card->support_mmap)
-		snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_MMAP |
-						SNDRV_PCM_INFO_MMAP_VALID;
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID;
 
 
 	if (card->support_grouping)
 	if (card->support_grouping)
 		snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
 		snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
@@ -998,7 +1050,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
 	/* struct is copied, so can create initializer dynamically */
 	/* struct is copied, so can create initializer dynamically */
 	runtime->hw = snd_card_asihpi_playback;
 	runtime->hw = snd_card_asihpi_playback;
 
 
-	if (card->support_mmap)
+	if (card->can_dma)
 		err = snd_pcm_hw_constraint_pow2(runtime, 0,
 		err = snd_pcm_hw_constraint_pow2(runtime, 0,
 					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
 					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
 	if (err < 0)
 	if (err < 0)
@@ -1028,58 +1080,6 @@ static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
 	return 0;
 	return 0;
 }
 }
 
 
-static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream,
-					int channel,
-					snd_pcm_uframes_t pos,
-					void __user *src,
-					snd_pcm_uframes_t count)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
-	unsigned int len;
-
-	len = frames_to_bytes(runtime, count);
-
-	if (copy_from_user(runtime->dma_area, src, len))
-		return -EFAULT;
-
-	snd_printddd("playback copy%d %u bytes\n",
-			substream->number, len);
-
-	hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
-				runtime->dma_area, len, &dpcm->format));
-
-	dpcm->pcm_buf_host_rw_ofs += len;
-
-	return 0;
-}
-
-static int snd_card_asihpi_playback_silence(struct snd_pcm_substream *
-					    substream, int channel,
-					    snd_pcm_uframes_t pos,
-					    snd_pcm_uframes_t count)
-{
-	/* Usually writes silence to DMA buffer, which should be overwritten
-	by real audio later.  Our fifos cannot be overwritten, and are not
-	free-running DMAs. Silence is output on fifo underflow.
-	This callback is still required to allow the copy callback to be used.
-	*/
-	return 0;
-}
-
-static struct snd_pcm_ops snd_card_asihpi_playback_ops = {
-	.open = snd_card_asihpi_playback_open,
-	.close = snd_card_asihpi_playback_close,
-	.ioctl = snd_card_asihpi_playback_ioctl,
-	.hw_params = snd_card_asihpi_pcm_hw_params,
-	.hw_free = snd_card_asihpi_hw_free,
-	.prepare = snd_card_asihpi_playback_prepare,
-	.trigger = snd_card_asihpi_trigger,
-	.pointer = snd_card_asihpi_playback_pointer,
-	.copy = snd_card_asihpi_playback_copy,
-	.silence = snd_card_asihpi_playback_silence,
-};
-
 static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
 static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
 	.open = snd_card_asihpi_playback_open,
 	.open = snd_card_asihpi_playback_open,
 	.close = snd_card_asihpi_playback_close,
 	.close = snd_card_asihpi_playback_close,
@@ -1211,18 +1211,16 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
 	snd_card_asihpi_capture_format(card, dpcm->h_stream,
 	snd_card_asihpi_capture_format(card, dpcm->h_stream,
 				       &snd_card_asihpi_capture);
 				       &snd_card_asihpi_capture);
 	snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_capture);
 	snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_capture);
-	snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED;
-
-	if (card->support_mmap)
-		snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP |
-						SNDRV_PCM_INFO_MMAP_VALID;
+	snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID;
 
 
 	if (card->support_grouping)
 	if (card->support_grouping)
 		snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
 		snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
 
 
 	runtime->hw = snd_card_asihpi_capture;
 	runtime->hw = snd_card_asihpi_capture;
 
 
-	if (card->support_mmap)
+	if (card->can_dma)
 		err = snd_pcm_hw_constraint_pow2(runtime, 0,
 		err = snd_pcm_hw_constraint_pow2(runtime, 0,
 					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
 					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
 	if (err < 0)
 	if (err < 0)
@@ -1246,28 +1244,6 @@ static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
 	return 0;
 	return 0;
 }
 }
 
 
-static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream,
-				int channel, snd_pcm_uframes_t pos,
-				void __user *dst, snd_pcm_uframes_t count)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
-	u32 len;
-
-	len = frames_to_bytes(runtime, count);
-
-	snd_printddd("capture copy%d %d bytes\n", substream->number, len);
-	hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream,
-				runtime->dma_area, len));
-
-	dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
-
-	if (copy_to_user(dst, runtime->dma_area, len))
-		return -EFAULT;
-
-	return 0;
-}
-
 static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
 static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
 	.open = snd_card_asihpi_capture_open,
 	.open = snd_card_asihpi_capture_open,
 	.close = snd_card_asihpi_capture_close,
 	.close = snd_card_asihpi_capture_close,
@@ -1279,18 +1255,6 @@ static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
 	.pointer = snd_card_asihpi_capture_pointer,
 	.pointer = snd_card_asihpi_capture_pointer,
 };
 };
 
 
-static struct snd_pcm_ops snd_card_asihpi_capture_ops = {
-	.open = snd_card_asihpi_capture_open,
-	.close = snd_card_asihpi_capture_close,
-	.ioctl = snd_card_asihpi_capture_ioctl,
-	.hw_params = snd_card_asihpi_pcm_hw_params,
-	.hw_free = snd_card_asihpi_hw_free,
-	.prepare = snd_card_asihpi_capture_prepare,
-	.trigger = snd_card_asihpi_trigger,
-	.pointer = snd_card_asihpi_capture_pointer,
-	.copy = snd_card_asihpi_capture_copy
-};
-
 static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
 static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
 				      int device, int substreams)
 				      int device, int substreams)
 {
 {
@@ -1303,17 +1267,10 @@ static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 	/* pointer to ops struct is stored, dont change ops afterwards! */
 	/* pointer to ops struct is stored, dont change ops afterwards! */
-	if (asihpi->support_mmap) {
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 				&snd_card_asihpi_playback_mmap_ops);
 				&snd_card_asihpi_playback_mmap_ops);
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 				&snd_card_asihpi_capture_mmap_ops);
 				&snd_card_asihpi_capture_mmap_ops);
-	} else {
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-				&snd_card_asihpi_playback_ops);
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-				&snd_card_asihpi_capture_ops);
-	}
 
 
 	pcm->private_data = asihpi;
 	pcm->private_data = asihpi;
 	pcm->info_flags = 0;
 	pcm->info_flags = 0;
@@ -1413,14 +1370,16 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
 				struct hpi_control *hpi_ctl,
 				struct hpi_control *hpi_ctl,
 				char *name)
 				char *name)
 {
 {
-	char *dir = "";
+	char *dir;
 	memset(snd_control, 0, sizeof(*snd_control));
 	memset(snd_control, 0, sizeof(*snd_control));
 	snd_control->name = hpi_ctl->name;
 	snd_control->name = hpi_ctl->name;
 	snd_control->private_value = hpi_ctl->h_control;
 	snd_control->private_value = hpi_ctl->h_control;
 	snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	snd_control->index = 0;
 	snd_control->index = 0;
 
 
-	if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
+	if (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE == HPI_SOURCENODE_CLOCK_SOURCE)
+		dir = ""; /* clock is neither capture nor playback */
+	else if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
 		dir = "Capture ";  /* On or towards a PCM capture destination*/
 		dir = "Capture ";  /* On or towards a PCM capture destination*/
 	else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
 	else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
 		(!hpi_ctl->dst_node_type))
 		(!hpi_ctl->dst_node_type))
@@ -1433,7 +1392,7 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
 		dir = "Playback "; /* PCM Playback source, or  output node */
 		dir = "Playback "; /* PCM Playback source, or  output node */
 
 
 	if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
 	if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
-		sprintf(hpi_ctl->name, "%s%d %s%d %s%s",
+		sprintf(hpi_ctl->name, "%s %d %s %d %s%s",
 			asihpi_src_names[hpi_ctl->src_node_type],
 			asihpi_src_names[hpi_ctl->src_node_type],
 			hpi_ctl->src_node_index,
 			hpi_ctl->src_node_index,
 			asihpi_dst_names[hpi_ctl->dst_node_type],
 			asihpi_dst_names[hpi_ctl->dst_node_type],
@@ -2875,14 +2834,14 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
 	if (err)
 	if (err)
 		asihpi->update_interval_frames = 512;
 		asihpi->update_interval_frames = 512;
 
 
-	if (!asihpi->support_mmap)
+	if (!asihpi->can_dma)
 		asihpi->update_interval_frames *= 2;
 		asihpi->update_interval_frames *= 2;
 
 
 	hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
 	hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
 			     0, &h_stream));
 			     0, &h_stream));
 
 
 	err = hpi_instream_host_buffer_free(h_stream);
 	err = hpi_instream_host_buffer_free(h_stream);
-	asihpi->support_mmap = (!err);
+	asihpi->can_dma = (!err);
 
 
 	hpi_handle_error(hpi_instream_close(h_stream));
 	hpi_handle_error(hpi_instream_close(h_stream));
 
 
@@ -2894,8 +2853,8 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
 		asihpi->out_max_chans = 2;
 		asihpi->out_max_chans = 2;
 	}
 	}
 
 
-	snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n",
-			asihpi->support_mmap,
+	snd_printk(KERN_INFO "has dma:%d, grouping:%d, mrx:%d\n",
+			asihpi->can_dma,
 			asihpi->support_grouping,
 			asihpi->support_grouping,
 			asihpi->support_mrx
 			asihpi->support_mrx
 	      );
 	      );
@@ -2925,10 +2884,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
 	    by enable_hwdep  module param*/
 	    by enable_hwdep  module param*/
 	snd_asihpi_hpi_new(asihpi, 0, NULL);
 	snd_asihpi_hpi_new(asihpi, 0, NULL);
 
 
-	if (asihpi->support_mmap)
-		strcpy(card->driver, "ASIHPI-MMAP");
-	else
-		strcpy(card->driver, "ASIHPI");
+	strcpy(card->driver, "ASIHPI");
 
 
 	sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
 	sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
 	sprintf(card->longname, "%s %i",
 	sprintf(card->longname, "%s %i",

+ 15 - 24
sound/pci/asihpi/hpi6000.c

@@ -200,8 +200,8 @@ static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
 static void subsys_create_adapter(struct hpi_message *phm,
 static void subsys_create_adapter(struct hpi_message *phm,
 	struct hpi_response *phr);
 	struct hpi_response *phr);
 
 
-static void subsys_delete_adapter(struct hpi_message *phm,
-	struct hpi_response *phr);
+static void adapter_delete(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
 
 
 static void adapter_get_asserts(struct hpi_adapter_obj *pao,
 static void adapter_get_asserts(struct hpi_adapter_obj *pao,
 	struct hpi_message *phm, struct hpi_response *phr);
 	struct hpi_message *phm, struct hpi_response *phr);
@@ -222,9 +222,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
 	case HPI_SUBSYS_CREATE_ADAPTER:
 	case HPI_SUBSYS_CREATE_ADAPTER:
 		subsys_create_adapter(phm, phr);
 		subsys_create_adapter(phm, phr);
 		break;
 		break;
-	case HPI_SUBSYS_DELETE_ADAPTER:
-		subsys_delete_adapter(phm, phr);
-		break;
 	default:
 	default:
 		phr->error = HPI_ERROR_INVALID_FUNC;
 		phr->error = HPI_ERROR_INVALID_FUNC;
 		break;
 		break;
@@ -279,6 +276,10 @@ static void adapter_message(struct hpi_adapter_obj *pao,
 		adapter_get_asserts(pao, phm, phr);
 		adapter_get_asserts(pao, phm, phr);
 		break;
 		break;
 
 
+	case HPI_ADAPTER_DELETE:
+		adapter_delete(pao, phm, phr);
+		break;
+
 	default:
 	default:
 		hw_message(pao, phm, phr);
 		hw_message(pao, phm, phr);
 		break;
 		break;
@@ -333,26 +334,22 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
 {
 {
 	struct hpi_adapter_obj *pao = NULL;
 	struct hpi_adapter_obj *pao = NULL;
 
 
-	/* subsytem messages get executed by every HPI. */
-	/* All other messages are ignored unless the adapter index matches */
-	/* an adapter in the HPI */
-	/*HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->wObject, phm->wFunction); */
-
-	/* if Dsp has crashed then do not communicate with it any more */
 	if (phm->object != HPI_OBJ_SUBSYSTEM) {
 	if (phm->object != HPI_OBJ_SUBSYSTEM) {
 		pao = hpi_find_adapter(phm->adapter_index);
 		pao = hpi_find_adapter(phm->adapter_index);
 		if (!pao) {
 		if (!pao) {
-			HPI_DEBUG_LOG(DEBUG,
-				" %d,%d refused, for another HPI?\n",
-				phm->object, phm->function);
+			hpi_init_response(phr, phm->object, phm->function,
+				HPI_ERROR_BAD_ADAPTER_NUMBER);
+			HPI_DEBUG_LOG(DEBUG, "invalid adapter index: %d \n",
+				phm->adapter_index);
 			return;
 			return;
 		}
 		}
 
 
+		/* Don't even try to communicate with crashed DSP */
 		if (pao->dsp_crashed >= 10) {
 		if (pao->dsp_crashed >= 10) {
 			hpi_init_response(phr, phm->object, phm->function,
 			hpi_init_response(phr, phm->object, phm->function,
 				HPI_ERROR_DSP_HARDWARE);
 				HPI_ERROR_DSP_HARDWARE);
-			HPI_DEBUG_LOG(DEBUG, " %d,%d dsp crashed.\n",
-				phm->object, phm->function);
+			HPI_DEBUG_LOG(DEBUG, "adapter %d dsp crashed\n",
+				phm->adapter_index);
 			return;
 			return;
 		}
 		}
 	}
 	}
@@ -463,15 +460,9 @@ static void subsys_create_adapter(struct hpi_message *phm,
 	phr->error = 0;
 	phr->error = 0;
 }
 }
 
 
-static void subsys_delete_adapter(struct hpi_message *phm,
-	struct hpi_response *phr)
+static void adapter_delete(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
 {
 {
-	struct hpi_adapter_obj *pao = NULL;
-
-	pao = hpi_find_adapter(phm->obj_index);
-	if (!pao)
-		return;
-
 	delete_adapter_obj(pao);
 	delete_adapter_obj(pao);
 	hpi_delete_adapter(pao);
 	hpi_delete_adapter(pao);
 	phr->error = 0;
 	phr->error = 0;

+ 48 - 47
sound/pci/asihpi/hpi6205.c

@@ -152,8 +152,8 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
 
 
 static void subsys_create_adapter(struct hpi_message *phm,
 static void subsys_create_adapter(struct hpi_message *phm,
 	struct hpi_response *phr);
 	struct hpi_response *phr);
-static void subsys_delete_adapter(struct hpi_message *phm,
-	struct hpi_response *phr);
+static void adapter_delete(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
 
 
 static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 	u32 *pos_error_code);
 	u32 *pos_error_code);
@@ -223,15 +223,13 @@ static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index);
 
 
 /*****************************************************************************/
 /*****************************************************************************/
 
 
-static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
+static void subsys_message(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
 {
 {
 	switch (phm->function) {
 	switch (phm->function) {
 	case HPI_SUBSYS_CREATE_ADAPTER:
 	case HPI_SUBSYS_CREATE_ADAPTER:
 		subsys_create_adapter(phm, phr);
 		subsys_create_adapter(phm, phr);
 		break;
 		break;
-	case HPI_SUBSYS_DELETE_ADAPTER:
-		subsys_delete_adapter(phm, phr);
-		break;
 	default:
 	default:
 		phr->error = HPI_ERROR_INVALID_FUNC;
 		phr->error = HPI_ERROR_INVALID_FUNC;
 		break;
 		break;
@@ -279,6 +277,10 @@ static void adapter_message(struct hpi_adapter_obj *pao,
 	struct hpi_message *phm, struct hpi_response *phr)
 	struct hpi_message *phm, struct hpi_response *phr)
 {
 {
 	switch (phm->function) {
 	switch (phm->function) {
+	case HPI_ADAPTER_DELETE:
+		adapter_delete(pao, phm, phr);
+		break;
+
 	default:
 	default:
 		hw_message(pao, phm, phr);
 		hw_message(pao, phm, phr);
 		break;
 		break;
@@ -371,36 +373,17 @@ static void instream_message(struct hpi_adapter_obj *pao,
 /** Entry point to this HPI backend
 /** Entry point to this HPI backend
  * All calls to the HPI start here
  * All calls to the HPI start here
  */
  */
-void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
+void _HPI_6205(struct hpi_adapter_obj *pao, struct hpi_message *phm,
+	struct hpi_response *phr)
 {
 {
-	struct hpi_adapter_obj *pao = NULL;
-
-	/* subsytem messages are processed by every HPI.
-	 * All other messages are ignored unless the adapter index matches
-	 * an adapter in the HPI
-	 */
-	/* HPI_DEBUG_LOG(DEBUG, "HPI Obj=%d, Func=%d\n", phm->wObject,
-	   phm->wFunction); */
-
-	/* if Dsp has crashed then do not communicate with it any more */
-	if (phm->object != HPI_OBJ_SUBSYSTEM) {
-		pao = hpi_find_adapter(phm->adapter_index);
-		if (!pao) {
-			HPI_DEBUG_LOG(DEBUG,
-				" %d,%d refused, for another HPI?\n",
-				phm->object, phm->function);
-			return;
-		}
-
-		if ((pao->dsp_crashed >= 10)
-			&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
-			/* allow last resort debug read even after crash */
-			hpi_init_response(phr, phm->object, phm->function,
-				HPI_ERROR_DSP_HARDWARE);
-			HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n",
-				phm->object, phm->function);
-			return;
-		}
+	if (pao && (pao->dsp_crashed >= 10)
+		&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
+		/* allow last resort debug read even after crash */
+		hpi_init_response(phr, phm->object, phm->function,
+			HPI_ERROR_DSP_HARDWARE);
+		HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n", phm->object,
+			phm->function);
+		return;
 	}
 	}
 
 
 	/* Init default response  */
 	/* Init default response  */
@@ -412,7 +395,7 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
 	case HPI_TYPE_MESSAGE:
 	case HPI_TYPE_MESSAGE:
 		switch (phm->object) {
 		switch (phm->object) {
 		case HPI_OBJ_SUBSYSTEM:
 		case HPI_OBJ_SUBSYSTEM:
-			subsys_message(phm, phr);
+			subsys_message(pao, phm, phr);
 			break;
 			break;
 
 
 		case HPI_OBJ_ADAPTER:
 		case HPI_OBJ_ADAPTER:
@@ -444,6 +427,26 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
 	}
 	}
 }
 }
 
 
+void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_adapter_obj *pao = NULL;
+
+	if (phm->object != HPI_OBJ_SUBSYSTEM) {
+		/* normal messages must have valid adapter index */
+		pao = hpi_find_adapter(phm->adapter_index);
+	} else {
+		/* subsys messages don't address an adapter */
+		_HPI_6205(NULL, phm, phr);
+		return;
+	}
+
+	if (pao)
+		_HPI_6205(pao, phm, phr);
+	else
+		hpi_init_response(phr, phm->object, phm->function,
+			HPI_ERROR_BAD_ADAPTER_NUMBER);
+}
+
 /*****************************************************************************/
 /*****************************************************************************/
 /* SUBSYSTEM */
 /* SUBSYSTEM */
 
 
@@ -491,13 +494,11 @@ static void subsys_create_adapter(struct hpi_message *phm,
 }
 }
 
 
 /** delete an adapter - required by WDM driver */
 /** delete an adapter - required by WDM driver */
-static void subsys_delete_adapter(struct hpi_message *phm,
-	struct hpi_response *phr)
+static void adapter_delete(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
 {
 {
-	struct hpi_adapter_obj *pao;
 	struct hpi_hw_obj *phw;
 	struct hpi_hw_obj *phw;
 
 
-	pao = hpi_find_adapter(phm->obj_index);
 	if (!pao) {
 	if (!pao) {
 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
 		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
 		return;
 		return;
@@ -563,11 +564,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 	}
 	}
 
 
 	err = adapter_boot_load_dsp(pao, pos_error_code);
 	err = adapter_boot_load_dsp(pao, pos_error_code);
-	if (err)
+	if (err) {
+		HPI_DEBUG_LOG(ERROR, "DSP code load failed\n");
 		/* no need to clean up as SubSysCreateAdapter */
 		/* no need to clean up as SubSysCreateAdapter */
 		/* calls DeleteAdapter on error. */
 		/* calls DeleteAdapter on error. */
 		return err;
 		return err;
-
+	}
 	HPI_DEBUG_LOG(INFO, "load DSP code OK\n");
 	HPI_DEBUG_LOG(INFO, "load DSP code OK\n");
 
 
 	/* allow boot load even if mem alloc wont work */
 	/* allow boot load even if mem alloc wont work */
@@ -604,6 +606,7 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 				control_cache.number_of_controls,
 				control_cache.number_of_controls,
 				interface->control_cache.size_in_bytes,
 				interface->control_cache.size_in_bytes,
 				p_control_cache_virtual);
 				p_control_cache_virtual);
+
 			if (!phw->p_cache)
 			if (!phw->p_cache)
 				err = HPI_ERROR_MEMORY_ALLOC;
 				err = HPI_ERROR_MEMORY_ALLOC;
 		}
 		}
@@ -675,16 +678,14 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
 }
 }
 
 
 /** Free memory areas allocated by adapter
 /** Free memory areas allocated by adapter
- * this routine is called from SubSysDeleteAdapter,
+ * this routine is called from AdapterDelete,
   * and SubSysCreateAdapter if duplicate index
   * and SubSysCreateAdapter if duplicate index
 */
 */
 static void delete_adapter_obj(struct hpi_adapter_obj *pao)
 static void delete_adapter_obj(struct hpi_adapter_obj *pao)
 {
 {
-	struct hpi_hw_obj *phw;
+	struct hpi_hw_obj *phw = pao->priv;
 	int i;
 	int i;
 
 
-	phw = pao->priv;
-
 	if (hpios_locked_mem_valid(&phw->h_control_cache)) {
 	if (hpios_locked_mem_valid(&phw->h_control_cache)) {
 		hpios_locked_mem_free(&phw->h_control_cache);
 		hpios_locked_mem_free(&phw->h_control_cache);
 		hpi_free_control_cache(phw->p_cache);
 		hpi_free_control_cache(phw->p_cache);
@@ -1275,6 +1276,7 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
 	case HPI_ADAPTER_FAMILY_ASI(0x6300):
 	case HPI_ADAPTER_FAMILY_ASI(0x6300):
 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400);
 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400);
 		break;
 		break;
+	case HPI_ADAPTER_FAMILY_ASI(0x5500):
 	case HPI_ADAPTER_FAMILY_ASI(0x5600):
 	case HPI_ADAPTER_FAMILY_ASI(0x5600):
 	case HPI_ADAPTER_FAMILY_ASI(0x6500):
 	case HPI_ADAPTER_FAMILY_ASI(0x6500):
 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600);
 		boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600);
@@ -2059,7 +2061,6 @@ static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us)
 static void send_dsp_command(struct hpi_hw_obj *phw, int cmd)
 static void send_dsp_command(struct hpi_hw_obj *phw, int cmd)
 {
 {
 	struct bus_master_interface *interface = phw->p_interface_buffer;
 	struct bus_master_interface *interface = phw->p_interface_buffer;
-
 	u32 r;
 	u32 r;
 
 
 	interface->host_cmd = cmd;
 	interface->host_cmd = cmd;

+ 8 - 11
sound/pci/asihpi/hpi_internal.h

@@ -294,7 +294,7 @@ enum HPI_CONTROL_ATTRIBUTES {
 
 
 /* These defines are used to fill in protocol information for an Ethernet packet
 /* These defines are used to fill in protocol information for an Ethernet packet
     sent using HMI on CS18102 */
     sent using HMI on CS18102 */
-/** ID supplied by Cirrius for ASI packets. */
+/** ID supplied by Cirrus for ASI packets. */
 #define HPI_ETHERNET_PACKET_ID                  0x85
 #define HPI_ETHERNET_PACKET_ID                  0x85
 /** Simple packet - no special routing required */
 /** Simple packet - no special routing required */
 #define HPI_ETHERNET_PACKET_V1                  0x01
 #define HPI_ETHERNET_PACKET_V1                  0x01
@@ -307,7 +307,7 @@ enum HPI_CONTROL_ATTRIBUTES {
 /** This packet must make its way to the host across the HPI interface */
 /** This packet must make its way to the host across the HPI interface */
 #define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI_V1   0x41
 #define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI_V1   0x41
 
 
-#define HPI_ETHERNET_UDP_PORT (44600)	/*!< UDP messaging port */
+#define HPI_ETHERNET_UDP_PORT 44600 /**< HPI UDP service */
 
 
 /** Default network timeout in milli-seconds. */
 /** Default network timeout in milli-seconds. */
 #define HPI_ETHERNET_TIMEOUT_MS 500
 #define HPI_ETHERNET_TIMEOUT_MS 500
@@ -397,14 +397,14 @@ enum HPI_FUNCTION_IDS {
 	HPI_SUBSYS_OPEN = HPI_FUNC_ID(SUBSYSTEM, 1),
 	HPI_SUBSYS_OPEN = HPI_FUNC_ID(SUBSYSTEM, 1),
 	HPI_SUBSYS_GET_VERSION = HPI_FUNC_ID(SUBSYSTEM, 2),
 	HPI_SUBSYS_GET_VERSION = HPI_FUNC_ID(SUBSYSTEM, 2),
 	HPI_SUBSYS_GET_INFO = HPI_FUNC_ID(SUBSYSTEM, 3),
 	HPI_SUBSYS_GET_INFO = HPI_FUNC_ID(SUBSYSTEM, 3),
-	HPI_SUBSYS_FIND_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 4),
+	/* HPI_SUBSYS_FIND_ADAPTERS     = HPI_FUNC_ID(SUBSYSTEM, 4), */
 	HPI_SUBSYS_CREATE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 5),
 	HPI_SUBSYS_CREATE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 5),
 	HPI_SUBSYS_CLOSE = HPI_FUNC_ID(SUBSYSTEM, 6),
 	HPI_SUBSYS_CLOSE = HPI_FUNC_ID(SUBSYSTEM, 6),
-	HPI_SUBSYS_DELETE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 7),
+	/* HPI_SUBSYS_DELETE_ADAPTER    = HPI_FUNC_ID(SUBSYSTEM, 7), */
 	HPI_SUBSYS_DRIVER_LOAD = HPI_FUNC_ID(SUBSYSTEM, 8),
 	HPI_SUBSYS_DRIVER_LOAD = HPI_FUNC_ID(SUBSYSTEM, 8),
 	HPI_SUBSYS_DRIVER_UNLOAD = HPI_FUNC_ID(SUBSYSTEM, 9),
 	HPI_SUBSYS_DRIVER_UNLOAD = HPI_FUNC_ID(SUBSYSTEM, 9),
-	HPI_SUBSYS_READ_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 10),
-	HPI_SUBSYS_WRITE_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 11),
+	/* HPI_SUBSYS_READ_PORT_8               = HPI_FUNC_ID(SUBSYSTEM, 10), */
+	/* HPI_SUBSYS_WRITE_PORT_8              = HPI_FUNC_ID(SUBSYSTEM, 11), */
 	HPI_SUBSYS_GET_NUM_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 12),
 	HPI_SUBSYS_GET_NUM_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 12),
 	HPI_SUBSYS_GET_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 13),
 	HPI_SUBSYS_GET_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 13),
 	HPI_SUBSYS_SET_NETWORK_INTERFACE = HPI_FUNC_ID(SUBSYSTEM, 14),
 	HPI_SUBSYS_SET_NETWORK_INTERFACE = HPI_FUNC_ID(SUBSYSTEM, 14),
@@ -433,7 +433,8 @@ enum HPI_FUNCTION_IDS {
 	HPI_ADAPTER_DEBUG_READ = HPI_FUNC_ID(ADAPTER, 18),
 	HPI_ADAPTER_DEBUG_READ = HPI_FUNC_ID(ADAPTER, 18),
 	HPI_ADAPTER_IRQ_QUERY_AND_CLEAR = HPI_FUNC_ID(ADAPTER, 19),
 	HPI_ADAPTER_IRQ_QUERY_AND_CLEAR = HPI_FUNC_ID(ADAPTER, 19),
 	HPI_ADAPTER_IRQ_CALLBACK = HPI_FUNC_ID(ADAPTER, 20),
 	HPI_ADAPTER_IRQ_CALLBACK = HPI_FUNC_ID(ADAPTER, 20),
-#define HPI_ADAPTER_FUNCTION_COUNT 20
+	HPI_ADAPTER_DELETE = HPI_FUNC_ID(ADAPTER, 21),
+#define HPI_ADAPTER_FUNCTION_COUNT 21
 
 
 	HPI_OSTREAM_OPEN = HPI_FUNC_ID(OSTREAM, 1),
 	HPI_OSTREAM_OPEN = HPI_FUNC_ID(OSTREAM, 1),
 	HPI_OSTREAM_CLOSE = HPI_FUNC_ID(OSTREAM, 2),
 	HPI_OSTREAM_CLOSE = HPI_FUNC_ID(OSTREAM, 2),
@@ -1561,8 +1562,6 @@ void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr);
 u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
 u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
 	u16 *pw_adapter_index);
 	u16 *pw_adapter_index);
 
 
-u16 hpi_subsys_delete_adapter(u16 adapter_index);
-
 u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer,
 u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer,
 	struct hpi_hostbuffer_status **pp_status);
 	struct hpi_hostbuffer_status **pp_status);
 
 
@@ -1584,9 +1583,7 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR);
 
 
 /*////////////////////////////////////////////////////////////////////////// */
 /*////////////////////////////////////////////////////////////////////////// */
 /* declarations for individual HPI entry points */
 /* declarations for individual HPI entry points */
-hpi_handler_func HPI_1000;
 hpi_handler_func HPI_6000;
 hpi_handler_func HPI_6000;
 hpi_handler_func HPI_6205;
 hpi_handler_func HPI_6205;
-hpi_handler_func HPI_COMMON;
 
 
 #endif				/* _HPI_INTERNAL_H_ */
 #endif				/* _HPI_INTERNAL_H_ */

+ 7 - 3
sound/pci/asihpi/hpicmn.c

@@ -227,8 +227,9 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
 			if (info->control_type) {
 			if (info->control_type) {
 				pC->p_info[info->control_index] = info;
 				pC->p_info[info->control_index] = info;
 				cached++;
 				cached++;
-			} else	/* dummy cache entry */
+			} else {	/* dummy cache entry */
 				pC->p_info[info->control_index] = NULL;
 				pC->p_info[info->control_index] = NULL;
+			}
 
 
 			byte_count += info->size_in32bit_words * 4;
 			byte_count += info->size_in32bit_words * 4;
 
 
@@ -298,7 +299,7 @@ struct pad_ofs_size {
 	unsigned int field_size;
 	unsigned int field_size;
 };
 };
 
 
-static struct pad_ofs_size pad_desc[] = {
+static const struct pad_ofs_size pad_desc[] = {
 	HPICMN_PAD_OFS_AND_SIZE(c_channel),	/* HPI_PAD_CHANNEL_NAME */
 	HPICMN_PAD_OFS_AND_SIZE(c_channel),	/* HPI_PAD_CHANNEL_NAME */
 	HPICMN_PAD_OFS_AND_SIZE(c_artist),	/* HPI_PAD_ARTIST */
 	HPICMN_PAD_OFS_AND_SIZE(c_artist),	/* HPI_PAD_ARTIST */
 	HPICMN_PAD_OFS_AND_SIZE(c_title),	/* HPI_PAD_TITLE */
 	HPICMN_PAD_OFS_AND_SIZE(c_title),	/* HPI_PAD_TITLE */
@@ -617,6 +618,10 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
 	}
 	}
 }
 }
 
 
+/** Allocate control cache.
+
+\return Cache pointer, or NULL if allocation fails.
+*/
 struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
 struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
 	const u32 size_in_bytes, u8 *p_dsp_control_buffer)
 	const u32 size_in_bytes, u8 *p_dsp_control_buffer)
 {
 {
@@ -667,7 +672,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
 		phr->u.s.num_adapters = adapters.gw_num_adapters;
 		phr->u.s.num_adapters = adapters.gw_num_adapters;
 		break;
 		break;
 	case HPI_SUBSYS_CREATE_ADAPTER:
 	case HPI_SUBSYS_CREATE_ADAPTER:
-	case HPI_SUBSYS_DELETE_ADAPTER:
 		break;
 		break;
 	default:
 	default:
 		phr->error = HPI_ERROR_INVALID_FUNC;
 		phr->error = HPI_ERROR_INVALID_FUNC;

+ 2 - 0
sound/pci/asihpi/hpicmn.h

@@ -60,3 +60,5 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC,
 	struct hpi_message *phm, struct hpi_response *phr);
 	struct hpi_message *phm, struct hpi_response *phr);
 
 
 u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
 u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
+
+hpi_handler_func HPI_COMMON;

+ 0 - 27
sound/pci/asihpi/hpifunc.c

@@ -105,33 +105,6 @@ u16 hpi_subsys_get_version_ex(u32 *pversion_ex)
 	return hr.error;
 	return hr.error;
 }
 }
 
 
-u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
-	u16 *pw_adapter_index)
-{
-	struct hpi_message hm;
-	struct hpi_response hr;
-
-	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
-		HPI_SUBSYS_CREATE_ADAPTER);
-	hm.u.s.resource = *p_resource;
-
-	hpi_send_recv(&hm, &hr);
-
-	*pw_adapter_index = hr.u.s.adapter_index;
-	return hr.error;
-}
-
-u16 hpi_subsys_delete_adapter(u16 adapter_index)
-{
-	struct hpi_message hm;
-	struct hpi_response hr;
-	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
-		HPI_SUBSYS_DELETE_ADAPTER);
-	hm.obj_index = adapter_index;
-	hpi_send_recv(&hm, &hr);
-	return hr.error;
-}
-
 u16 hpi_subsys_get_num_adapters(int *pn_num_adapters)
 u16 hpi_subsys_get_num_adapters(int *pn_num_adapters)
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;

+ 13 - 18
sound/pci/asihpi/hpimsgx.c

@@ -211,24 +211,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
 		HPIMSGX__init(phm, phr);
 		HPIMSGX__init(phm, phr);
 		break;
 		break;
 
 
-	case HPI_SUBSYS_DELETE_ADAPTER:
-		HPIMSGX__cleanup(phm->obj_index, h_owner);
-		{
-			struct hpi_message hm;
-			struct hpi_response hr;
-			hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
-				HPI_ADAPTER_CLOSE);
-			hm.adapter_index = phm->obj_index;
-			hw_entry_point(&hm, &hr);
-		}
-		if ((phm->obj_index < HPI_MAX_ADAPTERS)
-			&& hpi_entry_points[phm->obj_index]) {
-			hpi_entry_points[phm->obj_index] (phm, phr);
-			hpi_entry_points[phm->obj_index] = NULL;
-		} else
-			phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
-
-		break;
 	default:
 	default:
 		/* Must explicitly handle every subsys message in this switch */
 		/* Must explicitly handle every subsys message in this switch */
 		hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function,
 		hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function,
@@ -247,6 +229,19 @@ static void adapter_message(struct hpi_message *phm, struct hpi_response *phr,
 	case HPI_ADAPTER_CLOSE:
 	case HPI_ADAPTER_CLOSE:
 		adapter_close(phm, phr);
 		adapter_close(phm, phr);
 		break;
 		break;
+	case HPI_ADAPTER_DELETE:
+		HPIMSGX__cleanup(phm->adapter_index, h_owner);
+		{
+			struct hpi_message hm;
+			struct hpi_response hr;
+			hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+				HPI_ADAPTER_CLOSE);
+			hm.adapter_index = phm->adapter_index;
+			hw_entry_point(&hm, &hr);
+		}
+		hw_entry_point(phm, phr);
+		break;
+
 	default:
 	default:
 		hw_entry_point(phm, phr);
 		hw_entry_point(phm, phr);
 		break;
 		break;

+ 31 - 32
sound/pci/asihpi/hpioctl.c

@@ -25,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions
 #include "hpidebug.h"
 #include "hpidebug.h"
 #include "hpimsgx.h"
 #include "hpimsgx.h"
 #include "hpioctl.h"
 #include "hpioctl.h"
+#include "hpicmn.h"
 
 
 #include <linux/fs.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
@@ -161,26 +162,24 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	pa = &adapters[hm->h.adapter_index];
+	switch (hm->h.function) {
+	case HPI_SUBSYS_CREATE_ADAPTER:
+	case HPI_ADAPTER_DELETE:
+		/* Application must not use these functions! */
+		hr->h.size = sizeof(hr->h);
+		hr->h.error = HPI_ERROR_INVALID_OPERATION;
+		hr->h.function = hm->h.function;
+		uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
+		if (uncopied_bytes)
+			err = -EFAULT;
+		else
+			err = 0;
+		goto out;
+	}
+
 	hr->h.size = res_max_size;
 	hr->h.size = res_max_size;
 	if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
 	if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
-		switch (hm->h.function) {
-		case HPI_SUBSYS_CREATE_ADAPTER:
-		case HPI_SUBSYS_DELETE_ADAPTER:
-			/* Application must not use these functions! */
-			hr->h.size = sizeof(hr->h);
-			hr->h.error = HPI_ERROR_INVALID_OPERATION;
-			hr->h.function = hm->h.function;
-			uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
-			if (uncopied_bytes)
-				err = -EFAULT;
-			else
-				err = 0;
-			goto out;
-
-		default:
-			hpi_send_recv_f(&hm->m0, &hr->r0, file);
-		}
+		hpi_send_recv_f(&hm->m0, &hr->r0, file);
 	} else {
 	} else {
 		u16 __user *ptr = NULL;
 		u16 __user *ptr = NULL;
 		u32 size = 0;
 		u32 size = 0;
@@ -188,8 +187,9 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		/* -1=no data 0=read from user mem, 1=write to user mem */
 		/* -1=no data 0=read from user mem, 1=write to user mem */
 		int wrflag = -1;
 		int wrflag = -1;
 		u32 adapter = hm->h.adapter_index;
 		u32 adapter = hm->h.adapter_index;
+		pa = &adapters[adapter];
 
 
-		if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) {
+		if ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) {
 			hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
 			hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
 				HPI_ADAPTER_OPEN,
 				HPI_ADAPTER_OPEN,
 				HPI_ERROR_BAD_ADAPTER_NUMBER);
 				HPI_ERROR_BAD_ADAPTER_NUMBER);
@@ -317,7 +317,7 @@ out:
 int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 	const struct pci_device_id *pci_id)
 	const struct pci_device_id *pci_id)
 {
 {
-	int err, idx, nm;
+	int idx, nm;
 	unsigned int memlen;
 	unsigned int memlen;
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
@@ -351,11 +351,8 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 	nm = HPI_MAX_ADAPTER_MEM_SPACES;
 	nm = HPI_MAX_ADAPTER_MEM_SPACES;
 
 
 	for (idx = 0; idx < nm; idx++) {
 	for (idx = 0; idx < nm; idx++) {
-		HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n",
-			idx, pci_dev->resource[idx].name,
-			(unsigned long long)pci_resource_start(pci_dev, idx),
-			(unsigned long long)pci_resource_end(pci_dev, idx),
-			(unsigned long long)pci_resource_flags(pci_dev, idx));
+		HPI_DEBUG_LOG(INFO, "resource %d %pR\n", idx,
+			&pci_dev->resource[idx]);
 
 
 		if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
 		if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
 			memlen = pci_resource_len(pci_dev, idx);
 			memlen = pci_resource_len(pci_dev, idx);
@@ -395,17 +392,20 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 
 
 	adapter.index = hr.u.s.adapter_index;
 	adapter.index = hr.u.s.adapter_index;
 	adapter.type = hr.u.s.adapter_type;
 	adapter.type = hr.u.s.adapter_type;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_OPEN);
 	hm.adapter_index = adapter.index;
 	hm.adapter_index = adapter.index;
+	hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 
 
-	err = hpi_adapter_open(adapter.index);
-	if (err)
+	if (hr.error)
 		goto err;
 		goto err;
 
 
 	adapter.snd_card_asihpi = NULL;
 	adapter.snd_card_asihpi = NULL;
 	/* WARNING can't init mutex in 'adapter'
 	/* WARNING can't init mutex in 'adapter'
 	 * and then copy it to adapters[] ?!?!
 	 * and then copy it to adapters[] ?!?!
 	 */
 	 */
-	adapters[hr.u.s.adapter_index] = adapter;
+	adapters[adapter.index] = adapter;
 	mutex_init(&adapters[adapter.index].mutex);
 	mutex_init(&adapters[adapter.index].mutex);
 	pci_set_drvdata(pci_dev, &adapters[adapter.index]);
 	pci_set_drvdata(pci_dev, &adapters[adapter.index]);
 
 
@@ -440,10 +440,9 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
 	struct hpi_adapter *pa;
 	struct hpi_adapter *pa;
 	pa = pci_get_drvdata(pci_dev);
 	pa = pci_get_drvdata(pci_dev);
 
 
-	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
-		HPI_SUBSYS_DELETE_ADAPTER);
-	hm.obj_index = pa->index;
-	hm.adapter_index = HPI_ADAPTER_INDEX_INVALID;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_DELETE);
+	hm.adapter_index = pa->index;
 	hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 	hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 
 
 	/* unmap PCI memory space, mapped during device init. */
 	/* unmap PCI memory space, mapped during device init. */

+ 1 - 1
sound/pci/au88x0/au8810.h

@@ -4,7 +4,7 @@
 
 
 #define CHIP_AU8810
 #define CHIP_AU8810
 
 
-#define CARD_NAME "Aureal Advantage 3D Sound Processor"
+#define CARD_NAME "Aureal Advantage"
 #define CARD_NAME_SHORT "au8810"
 #define CARD_NAME_SHORT "au8810"
 
 
 #define NR_ADB		0x10
 #define NR_ADB		0x10

+ 1 - 1
sound/pci/au88x0/au8820.h

@@ -11,7 +11,7 @@
 
 
 #define CHIP_AU8820
 #define CHIP_AU8820
 
 
-#define CARD_NAME "Aureal Vortex 3D Sound Processor"
+#define CARD_NAME "Aureal Vortex"
 #define CARD_NAME_SHORT "au8820"
 #define CARD_NAME_SHORT "au8820"
 
 
 /* Number of ADB and WT channels */
 /* Number of ADB and WT channels */

+ 1 - 1
sound/pci/au88x0/au8830.h

@@ -11,7 +11,7 @@
 
 
 #define CHIP_AU8830
 #define CHIP_AU8830
 
 
-#define CARD_NAME "Aureal Vortex 2 3D Sound Processor"
+#define CARD_NAME "Aureal Vortex 2"
 #define CARD_NAME_SHORT "au8830"
 #define CARD_NAME_SHORT "au8830"
 
 
 #define NR_ADB 0x20
 #define NR_ADB 0x20

+ 7 - 6
sound/pci/au88x0/au88x0_pcm.c

@@ -426,11 +426,11 @@ static struct snd_pcm_ops snd_vortex_playback_ops = {
 */
 */
 
 
 static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
 static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
-	"AU88x0 ADB",
-	"AU88x0 SPDIF",
-	"AU88x0 A3D",
-	"AU88x0 WT",
-	"AU88x0 I2S",
+	CARD_NAME " ADB",
+	CARD_NAME " SPDIF",
+	CARD_NAME " A3D",
+	CARD_NAME " WT",
+	CARD_NAME " I2S",
 };
 };
 static char *vortex_pcm_name[VORTEX_PCM_LAST] = {
 static char *vortex_pcm_name[VORTEX_PCM_LAST] = {
 	"adb",
 	"adb",
@@ -527,7 +527,8 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
 			  nr_capt, &pcm);
 			  nr_capt, &pcm);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
-	strcpy(pcm->name, vortex_pcm_name[idx]);
+	snprintf(pcm->name, sizeof(pcm->name),
+		"%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]);
 	chip->pcm[idx] = pcm;
 	chip->pcm[idx] = pcm;
 	// This is an evil hack, but it saves a lot of duplicated code.
 	// This is an evil hack, but it saves a lot of duplicated code.
 	VORTEX_PCM_TYPE(pcm) = idx;
 	VORTEX_PCM_TYPE(pcm) = idx;

+ 5 - 0
sound/pci/emu10k1/emufx.c

@@ -303,6 +303,9 @@ static const u32 db_table[101] = {
 static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
 static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
 static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
 static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
 
 
+/* EMU10K1 bass/treble db gain */
+static const DECLARE_TLV_DB_SCALE(snd_emu10k1_bass_treble_db_scale, -1200, 60, 0);
+
 static const u32 onoff_table[2] = {
 static const u32 onoff_table[2] = {
 	0x00000000, 0x00000001
 	0x00000000, 0x00000001
 };
 };
@@ -2163,6 +2166,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
 	ctl->min = 0;
 	ctl->min = 0;
 	ctl->max = 40;
 	ctl->max = 40;
 	ctl->value[0] = ctl->value[1] = 20;
 	ctl->value[0] = ctl->value[1] = 20;
+	ctl->tlv = snd_emu10k1_bass_treble_db_scale;
 	ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
 	ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
 	ctl = &controls[i + 1];
 	ctl = &controls[i + 1];
 	ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -2172,6 +2176,7 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
 	ctl->min = 0;
 	ctl->min = 0;
 	ctl->max = 40;
 	ctl->max = 40;
 	ctl->value[0] = ctl->value[1] = 20;
 	ctl->value[0] = ctl->value[1] = 20;
+	ctl->tlv = snd_emu10k1_bass_treble_db_scale;
 	ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
 	ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
 
 
 #define BASS_GPR	0x8c
 #define BASS_GPR	0x8c

+ 8 - 2
sound/pci/emu10k1/emumixer.c

@@ -1729,8 +1729,6 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
 		"Master Mono Playback Volume",
 		"Master Mono Playback Volume",
 		"PCM Out Path & Mute",
 		"PCM Out Path & Mute",
 		"Mono Output Select",
 		"Mono Output Select",
-		"Front Playback Switch",
-		"Front Playback Volume",
 		"Surround Playback Switch",
 		"Surround Playback Switch",
 		"Surround Playback Volume",
 		"Surround Playback Volume",
 		"Center Playback Switch",
 		"Center Playback Switch",
@@ -1879,6 +1877,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
 				emu->rear_ac97 = 1;
 				emu->rear_ac97 = 1;
 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
+				remove_ctl(card,"Front Playback Volume");
+				remove_ctl(card,"Front Playback Switch");
 			}
 			}
 			/* remove unused AC97 controls */
 			/* remove unused AC97 controls */
 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
@@ -1913,6 +1913,12 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
 	for (; *c; c += 2)
 	for (; *c; c += 2)
 		rename_ctl(card, c[0], c[1]);
 		rename_ctl(card, c[0], c[1]);
 
 
+	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
+		remove_ctl(card, "Center Playback Volume");
+		remove_ctl(card, "LFE Playback Volume");
+		remove_ctl(card, "Wave Center Playback Volume");
+		remove_ctl(card, "Wave LFE Playback Volume");
+	}
 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");

+ 78 - 0
sound/pci/es1968.c

@@ -112,6 +112,10 @@
 #include <sound/ac97_codec.h>
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/initval.h>
 
 
+#ifdef CONFIG_SND_ES1968_RADIO
+#include <sound/tea575x-tuner.h>
+#endif
+
 #define CARD_NAME "ESS Maestro1/2"
 #define CARD_NAME "ESS Maestro1/2"
 #define DRIVER_NAME "ES1968"
 #define DRIVER_NAME "ES1968"
 
 
@@ -553,6 +557,10 @@ struct es1968 {
 	spinlock_t ac97_lock;
 	spinlock_t ac97_lock;
 	struct tasklet_struct hwvol_tq;
 	struct tasklet_struct hwvol_tq;
 #endif
 #endif
+
+#ifdef CONFIG_SND_ES1968_RADIO
+	struct snd_tea575x tea;
+#endif
 };
 };
 
 
 static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
 static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
@@ -2571,6 +2579,63 @@ static int __devinit snd_es1968_input_register(struct es1968 *chip)
 }
 }
 #endif /* CONFIG_SND_ES1968_INPUT */
 #endif /* CONFIG_SND_ES1968_INPUT */
 
 
+#ifdef CONFIG_SND_ES1968_RADIO
+#define GPIO_DATA	0x60
+#define IO_MASK		4      /* mask      register offset from GPIO_DATA
+				bits 1=unmask write to given bit */
+#define IO_DIR		8      /* direction register offset from GPIO_DATA
+				bits 0/1=read/write direction */
+/* mask bits for GPIO lines */
+#define STR_DATA	0x0040 /* GPIO6 */
+#define STR_CLK		0x0080 /* GPIO7 */
+#define STR_WREN	0x0100 /* GPIO8 */
+#define STR_MOST	0x0200 /* GPIO9 */
+
+static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
+{
+	struct es1968 *chip = tea->private_data;
+	unsigned long io = chip->io_port + GPIO_DATA;
+	u16 val = 0;
+
+	val |= (pins & TEA575X_DATA) ? STR_DATA : 0;
+	val |= (pins & TEA575X_CLK)  ? STR_CLK  : 0;
+	val |= (pins & TEA575X_WREN) ? STR_WREN : 0;
+
+	outw(val, io);
+}
+
+static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea)
+{
+	struct es1968 *chip = tea->private_data;
+	unsigned long io = chip->io_port + GPIO_DATA;
+	u16 val = inw(io);
+
+	return  (val & STR_DATA) ? TEA575X_DATA : 0 |
+		(val & STR_MOST) ? TEA575X_MOST : 0;
+}
+
+static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool output)
+{
+	struct es1968 *chip = tea->private_data;
+	unsigned long io = chip->io_port + GPIO_DATA;
+	u16 odir = inw(io + IO_DIR);
+
+	if (output) {
+		outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
+		outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR);
+	} else {
+		outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK);
+		outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR);
+	}
+}
+
+static struct snd_tea575x_ops snd_es1968_tea_ops = {
+	.set_pins = snd_es1968_tea575x_set_pins,
+	.get_pins = snd_es1968_tea575x_get_pins,
+	.set_direction = snd_es1968_tea575x_set_direction,
+};
+#endif
+
 static int snd_es1968_free(struct es1968 *chip)
 static int snd_es1968_free(struct es1968 *chip)
 {
 {
 #ifdef CONFIG_SND_ES1968_INPUT
 #ifdef CONFIG_SND_ES1968_INPUT
@@ -2585,6 +2650,10 @@ static int snd_es1968_free(struct es1968 *chip)
 		outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */
 		outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */
 	}
 	}
 
 
+#ifdef CONFIG_SND_ES1968_RADIO
+	snd_tea575x_exit(&chip->tea);
+#endif
+
 	if (chip->irq >= 0)
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 		free_irq(chip->irq, chip);
 	snd_es1968_free_gameport(chip);
 	snd_es1968_free_gameport(chip);
@@ -2723,6 +2792,15 @@ static int __devinit snd_es1968_create(struct snd_card *card,
 
 
 	snd_card_set_dev(card, &pci->dev);
 	snd_card_set_dev(card, &pci->dev);
 
 
+#ifdef CONFIG_SND_ES1968_RADIO
+	chip->tea.private_data = chip;
+	chip->tea.ops = &snd_es1968_tea_ops;
+	strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
+	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
+	if (!snd_tea575x_init(&chip->tea))
+		printk(KERN_INFO "es1968: detected TEA575x radio\n");
+#endif
+
 	*chip_ret = chip;
 	*chip_ret = chip;
 
 
 	return 0;
 	return 0;

+ 79 - 292
sound/pci/fm801.c

@@ -38,7 +38,6 @@
 
 
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
 #include <sound/tea575x-tuner.h>
 #include <sound/tea575x-tuner.h>
-#define TEA575X_RADIO 1
 #endif
 #endif
 
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -53,7 +52,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card *
 /*
 /*
  *  Enable TEA575x tuner
  *  Enable TEA575x tuner
  *    1 = MediaForte 256-PCS
  *    1 = MediaForte 256-PCS
- *    2 = MediaForte 256-PCPR
+ *    2 = MediaForte 256-PCP
  *    3 = MediaForte 64-PCR
  *    3 = MediaForte 64-PCR
  *   16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card
  *   16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card
  *  High 16-bits are video (radio) device number + 1
  *  High 16-bits are video (radio) device number + 1
@@ -67,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
 MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
 module_param_array(tea575x_tuner, int, NULL, 0444);
 module_param_array(tea575x_tuner, int, NULL, 0444);
-MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only).");
+MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only).");
 
 
 #define TUNER_ONLY		(1<<4)
 #define TUNER_ONLY		(1<<4)
 #define TUNER_TYPE_MASK		(~TUNER_ONLY & 0xFFFF)
 #define TUNER_TYPE_MASK		(~TUNER_ONLY & 0xFFFF)
@@ -196,7 +195,7 @@ struct fm801 {
 	spinlock_t reg_lock;
 	spinlock_t reg_lock;
 	struct snd_info_entry *proc_entry;
 	struct snd_info_entry *proc_entry;
 
 
-#ifdef TEA575X_RADIO
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
 	struct snd_tea575x tea;
 	struct snd_tea575x tea;
 #endif
 #endif
 
 
@@ -715,310 +714,89 @@ static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pc
  *  TEA5757 radio
  *  TEA5757 radio
  */
  */
 
 
-#ifdef TEA575X_RADIO
-
-/* 256PCS GPIO numbers */
-#define TEA_256PCS_DATA			1
-#define TEA_256PCS_WRITE_ENABLE		2	/* inverted */
-#define TEA_256PCS_BUS_CLOCK		3
-
-static void snd_fm801_tea575x_256pcs_write(struct snd_tea575x *tea, unsigned int val)
-{
-	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	int i = 25;
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
 
 
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	/* use GPIO lines and set write enable bit */
-	reg |= FM801_GPIO_GS(TEA_256PCS_DATA) |
-	       FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK);
-	/* all of lines are in the write direction */
-	/* clear data and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_256PCS_DATA) |
-	         FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_256PCS_DATA) |
-	         FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK) |
-		 FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE));
-	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	udelay(1);
-
-	while (i--) {
-		if (val & (1 << i))
-			reg |= FM801_GPIO_GP(TEA_256PCS_DATA);
-		else
-			reg &= ~FM801_GPIO_GP(TEA_256PCS_DATA);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-	}
+/* GPIO to TEA575x maps */
+struct snd_fm801_tea575x_gpio {
+	u8 data, clk, wren, most;
+	char *name;
+};
 
 
-	/* and reset the write enable bit */
-	reg |= FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE) |
-	       FM801_GPIO_GP(TEA_256PCS_DATA);
-	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	spin_unlock_irq(&chip->reg_lock);
-}
+static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = {
+	{ .data = 1, .clk = 3, .wren = 2, .most = 0, .name = "SF256-PCS" },
+	{ .data = 1, .clk = 0, .wren = 2, .most = 3, .name = "SF256-PCP" },
+	{ .data = 2, .clk = 0, .wren = 1, .most = 3, .name = "SF64-PCR" },
+};
 
 
-static unsigned int snd_fm801_tea575x_256pcs_read(struct snd_tea575x *tea)
+static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
 {
 {
 	struct fm801 *chip = tea->private_data;
 	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	unsigned int val = 0;
-	int i;
-	
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	/* use GPIO lines, set data direction to input */
-	reg |= FM801_GPIO_GS(TEA_256PCS_DATA) |
-	       FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK) |
-	       FM801_GPIO_GD(TEA_256PCS_DATA) |
-	       FM801_GPIO_GP(TEA_256PCS_DATA) |
-	       FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE);
-	/* all of lines are in the write direction, except data */
-	/* clear data, write enable and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK));
-
-	for (i = 0; i < 24; i++) {
-		reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		val <<= 1;
-		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCS_DATA))
-			val |= 1;
-	}
+	unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+	struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
 
 
-	spin_unlock_irq(&chip->reg_lock);
+	reg &= ~(FM801_GPIO_GP(gpio.data) |
+		 FM801_GPIO_GP(gpio.clk) |
+		 FM801_GPIO_GP(gpio.wren));
 
 
-	return val;
-}
+	reg |= (pins & TEA575X_DATA) ? FM801_GPIO_GP(gpio.data) : 0;
+	reg |= (pins & TEA575X_CLK)  ? FM801_GPIO_GP(gpio.clk) : 0;
+	/* WRITE_ENABLE is inverted */
+	reg |= (pins & TEA575X_WREN) ? 0 : FM801_GPIO_GP(gpio.wren);
 
 
-/* 256PCPR GPIO numbers */
-#define TEA_256PCPR_BUS_CLOCK		0
-#define TEA_256PCPR_DATA		1
-#define TEA_256PCPR_WRITE_ENABLE	2	/* inverted */
-
-static void snd_fm801_tea575x_256pcpr_write(struct snd_tea575x *tea, unsigned int val)
-{
-	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	int i = 25;
-
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	/* use GPIO lines and set write enable bit */
-	reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) |
-	       FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK);
-	/* all of lines are in the write direction */
-	/* clear data and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_256PCPR_DATA) |
-	         FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_256PCPR_DATA) |
-	         FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK) |
-		 FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE));
 	outw(reg, FM801_REG(chip, GPIO_CTRL));
 	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	udelay(1);
-
-	while (i--) {
-		if (val & (1 << i))
-			reg |= FM801_GPIO_GP(TEA_256PCPR_DATA);
-		else
-			reg &= ~FM801_GPIO_GP(TEA_256PCPR_DATA);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-	}
-
-	/* and reset the write enable bit */
-	reg |= FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE) |
-	       FM801_GPIO_GP(TEA_256PCPR_DATA);
-	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	spin_unlock_irq(&chip->reg_lock);
 }
 }
 
 
-static unsigned int snd_fm801_tea575x_256pcpr_read(struct snd_tea575x *tea)
+static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
 {
 {
 	struct fm801 *chip = tea->private_data;
 	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	unsigned int val = 0;
-	int i;
-	
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	/* use GPIO lines, set data direction to input */
-	reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) |
-	       FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK) |
-	       FM801_GPIO_GD(TEA_256PCPR_DATA) |
-	       FM801_GPIO_GP(TEA_256PCPR_DATA) |
-	       FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE);
-	/* all of lines are in the write direction, except data */
-	/* clear data, write enable and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK));
-
-	for (i = 0; i < 24; i++) {
-		reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		val <<= 1;
-		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCPR_DATA))
-			val |= 1;
-	}
+	unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+	struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
 
 
-	spin_unlock_irq(&chip->reg_lock);
-
-	return val;
+	return  (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 |
+		(reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0;
 }
 }
 
 
-/* 64PCR GPIO numbers */
-#define TEA_64PCR_BUS_CLOCK		0
-#define TEA_64PCR_WRITE_ENABLE		1	/* inverted */
-#define TEA_64PCR_DATA			2
-
-static void snd_fm801_tea575x_64pcr_write(struct snd_tea575x *tea, unsigned int val)
+static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output)
 {
 {
 	struct fm801 *chip = tea->private_data;
 	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	int i = 25;
+	unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
+	struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
 
 
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
 	/* use GPIO lines and set write enable bit */
 	/* use GPIO lines and set write enable bit */
-	reg |= FM801_GPIO_GS(TEA_64PCR_DATA) |
-	       FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK);
-	/* all of lines are in the write direction */
-	/* clear data and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_64PCR_DATA) |
-	         FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_64PCR_DATA) |
-	         FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK) |
-		 FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE));
-	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	udelay(1);
-
-	while (i--) {
-		if (val & (1 << i))
-			reg |= FM801_GPIO_GP(TEA_64PCR_DATA);
-		else
-			reg &= ~FM801_GPIO_GP(TEA_64PCR_DATA);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
+	reg |= FM801_GPIO_GS(gpio.data) |
+	       FM801_GPIO_GS(gpio.wren) |
+	       FM801_GPIO_GS(gpio.clk) |
+	       FM801_GPIO_GS(gpio.most);
+	if (output) {
+		/* all of lines are in the write direction */
+		/* clear data and clock lines */
+		reg &= ~(FM801_GPIO_GD(gpio.data) |
+			 FM801_GPIO_GD(gpio.wren) |
+			 FM801_GPIO_GD(gpio.clk) |
+			 FM801_GPIO_GP(gpio.data) |
+			 FM801_GPIO_GP(gpio.clk) |
+			 FM801_GPIO_GP(gpio.wren));
+	} else {
+		/* use GPIO lines, set data direction to input */
+		reg |= FM801_GPIO_GD(gpio.data) |
+		       FM801_GPIO_GD(gpio.most) |
+		       FM801_GPIO_GP(gpio.data) |
+		       FM801_GPIO_GP(gpio.most) |
+		       FM801_GPIO_GP(gpio.wren);
+		/* all of lines are in the write direction, except data */
+		/* clear data, write enable and clock lines */
+		reg &= ~(FM801_GPIO_GD(gpio.wren) |
+			 FM801_GPIO_GD(gpio.clk) |
+			 FM801_GPIO_GP(gpio.clk));
 	}
 	}
 
 
-	/* and reset the write enable bit */
-	reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE) |
-	       FM801_GPIO_GP(TEA_64PCR_DATA);
 	outw(reg, FM801_REG(chip, GPIO_CTRL));
 	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	spin_unlock_irq(&chip->reg_lock);
-}
-
-static unsigned int snd_fm801_tea575x_64pcr_read(struct snd_tea575x *tea)
-{
-	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-	unsigned int val = 0;
-	int i;
-	
-	spin_lock_irq(&chip->reg_lock);
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	/* use GPIO lines, set data direction to input */
-	reg |= FM801_GPIO_GS(TEA_64PCR_DATA) |
-	       FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) |
-	       FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK) |
-	       FM801_GPIO_GD(TEA_64PCR_DATA) |
-	       FM801_GPIO_GP(TEA_64PCR_DATA) |
-	       FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
-	/* all of lines are in the write direction, except data */
-	/* clear data, write enable and clock lines */
-	reg &= ~(FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) |
-	         FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) |
-	         FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK));
-
-	for (i = 0; i < 24; i++) {
-		reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
-		outw(reg, FM801_REG(chip, GPIO_CTRL));
-		udelay(1);
-		val <<= 1;
-		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_64PCR_DATA))
-			val |= 1;
-	}
-
-	spin_unlock_irq(&chip->reg_lock);
-
-	return val;
 }
 }
 
 
-static void snd_fm801_tea575x_64pcr_mute(struct snd_tea575x *tea,
-					  unsigned int mute)
-{
-	struct fm801 *chip = tea->private_data;
-	unsigned short reg;
-
-	spin_lock_irq(&chip->reg_lock);
-
-	reg = inw(FM801_REG(chip, GPIO_CTRL));
-	if (mute)
-		/* 0xf800 (mute) */
-		reg &= ~FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
-	else
-		/* 0xf802 (unmute) */
-		reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
-	outw(reg, FM801_REG(chip, GPIO_CTRL));
-	udelay(1);
-
-	spin_unlock_irq(&chip->reg_lock);
-}
-
-static struct snd_tea575x_ops snd_fm801_tea_ops[3] = {
-	{
-		/* 1 = MediaForte 256-PCS */
-		.write = snd_fm801_tea575x_256pcs_write,
-		.read = snd_fm801_tea575x_256pcs_read,
-	},
-	{
-		/* 2 = MediaForte 256-PCPR */
-		.write = snd_fm801_tea575x_256pcpr_write,
-		.read = snd_fm801_tea575x_256pcpr_read,
-	},
-	{
-		/* 3 = MediaForte 64-PCR */
-		.write = snd_fm801_tea575x_64pcr_write,
-		.read = snd_fm801_tea575x_64pcr_read,
-		.mute = snd_fm801_tea575x_64pcr_mute,
-	}
+static struct snd_tea575x_ops snd_fm801_tea_ops = {
+	.set_pins = snd_fm801_tea575x_set_pins,
+	.get_pins = snd_fm801_tea575x_get_pins,
+	.set_direction = snd_fm801_tea575x_set_direction,
 };
 };
 #endif
 #endif
 
 
@@ -1371,7 +1149,7 @@ static int snd_fm801_free(struct fm801 *chip)
 	outw(cmdw, FM801_REG(chip, IRQ_MASK));
 	outw(cmdw, FM801_REG(chip, IRQ_MASK));
 
 
       __end_hw:
       __end_hw:
-#ifdef TEA575X_RADIO
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
 	snd_tea575x_exit(&chip->tea);
 	snd_tea575x_exit(&chip->tea);
 #endif
 #endif
 	if (chip->irq >= 0)
 	if (chip->irq >= 0)
@@ -1450,16 +1228,25 @@ static int __devinit snd_fm801_create(struct snd_card *card,
 
 
 	snd_card_set_dev(card, &pci->dev);
 	snd_card_set_dev(card, &pci->dev);
 
 
-#ifdef TEA575X_RADIO
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
+	chip->tea.private_data = chip;
+	chip->tea.ops = &snd_fm801_tea_ops;
+	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
 	if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
 	if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
 	    (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
 	    (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
-		chip->tea.dev_nr = tea575x_tuner >> 16;
-		chip->tea.card = card;
-		chip->tea.freq_fixup = 10700;
-		chip->tea.private_data = chip;
-		chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1];
-		snd_tea575x_init(&chip->tea);
-	}
+		if (snd_tea575x_init(&chip->tea))
+			snd_printk(KERN_ERR "TEA575x radio not found\n");
+	} else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0)
+		/* autodetect tuner connection */
+		for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
+			chip->tea575x_tuner = tea575x_tuner;
+			if (!snd_tea575x_init(&chip->tea)) {
+				snd_printk(KERN_INFO "detected TEA575x radio type %s\n",
+					snd_fm801_tea575x_gpios[tea575x_tuner - 1].name);
+				break;
+			}
+		}
+	strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card));
 #endif
 #endif
 
 
 	*rchip = chip;
 	*rchip = chip;

+ 84 - 13
sound/pci/hda/hda_codec.c

@@ -307,6 +307,12 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
 }
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
 EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
 
 
+static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
+				hda_nid_t *conn_list, int max_conns);
+static bool add_conn_list(struct snd_array *array, hda_nid_t nid);
+static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
+			  hda_nid_t *src, int len);
+
 /**
 /**
  * snd_hda_get_connections - get connection list
  * snd_hda_get_connections - get connection list
  * @codec: the HDA codec
  * @codec: the HDA codec
@@ -320,7 +326,44 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
  * Returns the number of connections, or a negative error code.
  * Returns the number of connections, or a negative error code.
  */
  */
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
-			    hda_nid_t *conn_list, int max_conns)
+			     hda_nid_t *conn_list, int max_conns)
+{
+	struct snd_array *array = &codec->conn_lists;
+	int i, len, old_used;
+	hda_nid_t list[HDA_MAX_CONNECTIONS];
+
+	/* look up the cached results */
+	for (i = 0; i < array->used; ) {
+		hda_nid_t *p = snd_array_elem(array, i);
+		len = p[1];
+		if (nid == *p)
+			return copy_conn_list(nid, conn_list, max_conns,
+					      p + 2, len);
+		i += len + 2;
+	}
+
+	len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
+	if (len < 0)
+		return len;
+
+	/* add to the cache */
+	old_used = array->used;
+	if (!add_conn_list(array, nid) || !add_conn_list(array, len))
+		goto error_add;
+	for (i = 0; i < len; i++)
+		if (!add_conn_list(array, list[i]))
+			goto error_add;
+
+	return copy_conn_list(nid, conn_list, max_conns, list, len);
+		
+ error_add:
+	array->used = old_used;
+	return -ENOMEM;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_connections);
+
+static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
+			     hda_nid_t *conn_list, int max_conns)
 {
 {
 	unsigned int parm;
 	unsigned int parm;
 	int i, conn_len, conns;
 	int i, conn_len, conns;
@@ -417,8 +460,28 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 	}
 	}
 	return conns;
 	return conns;
 }
 }
-EXPORT_SYMBOL_HDA(snd_hda_get_connections);
 
 
+static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
+{
+	hda_nid_t *p = snd_array_new(array);
+	if (!p)
+		return false;
+	*p = nid;
+	return true;
+}
+
+static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
+			  hda_nid_t *src, int len)
+{
+	if (len > max_dst) {
+		snd_printk(KERN_ERR "hda_codec: "
+			   "Too many connections %d for NID 0x%x\n",
+			   len, nid);
+		return -EINVAL;
+	}
+	memcpy(dst, src, len * sizeof(hda_nid_t));
+	return len;
+}
 
 
 /**
 /**
  * snd_hda_queue_unsol_event - add an unsolicited event to queue
  * snd_hda_queue_unsol_event - add an unsolicited event to queue
@@ -1019,6 +1082,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
 	list_del(&codec->list);
 	list_del(&codec->list);
 	snd_array_free(&codec->mixers);
 	snd_array_free(&codec->mixers);
 	snd_array_free(&codec->nids);
 	snd_array_free(&codec->nids);
+	snd_array_free(&codec->conn_lists);
 	codec->bus->caddr_tbl[codec->addr] = NULL;
 	codec->bus->caddr_tbl[codec->addr] = NULL;
 	if (codec->patch_ops.free)
 	if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
 		codec->patch_ops.free(codec);
@@ -1079,6 +1143,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
 	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
 	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
 	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
 	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
 	snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
 	snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
+	snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
 	if (codec->bus->modelname) {
 	if (codec->bus->modelname) {
 		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
 		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
 		if (!codec->modelname) {
 		if (!codec->modelname) {
@@ -2556,7 +2621,7 @@ static unsigned int convert_to_spdif_status(unsigned short val)
 static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
 static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
 			int verb, int val)
 			int verb, int val)
 {
 {
-	hda_nid_t *d;
+	const hda_nid_t *d;
 
 
 	snd_hda_codec_write_cache(codec, nid, 0, verb, val);
 	snd_hda_codec_write_cache(codec, nid, 0, verb, val);
 	d = codec->slave_dig_outs;
 	d = codec->slave_dig_outs;
@@ -3807,7 +3872,8 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config);
  *
  *
  * Returns 0 if successful, or a negative error code.
  * Returns 0 if successful, or a negative error code.
  */
  */
-int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
+int snd_hda_add_new_ctls(struct hda_codec *codec,
+			 const struct snd_kcontrol_new *knew)
 {
 {
 	int err;
 	int err;
 
 
@@ -3950,7 +4016,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 				 struct hda_loopback_check *check,
 				 struct hda_loopback_check *check,
 				 hda_nid_t nid)
 				 hda_nid_t nid)
 {
 {
-	struct hda_amp_list *p;
+	const struct hda_amp_list *p;
 	int ch, v;
 	int ch, v;
 
 
 	if (!check->amplist)
 	if (!check->amplist)
@@ -4118,7 +4184,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
 				    -1);
 				    -1);
 	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
 	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
 	if (codec->slave_dig_outs) {
 	if (codec->slave_dig_outs) {
-		hda_nid_t *d;
+		const hda_nid_t *d;
 		for (d = codec->slave_dig_outs; *d; d++)
 		for (d = codec->slave_dig_outs; *d; d++)
 			snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
 			snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
 						   format);
 						   format);
@@ -4133,7 +4199,7 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
 {
 {
 	snd_hda_codec_cleanup_stream(codec, nid);
 	snd_hda_codec_cleanup_stream(codec, nid);
 	if (codec->slave_dig_outs) {
 	if (codec->slave_dig_outs) {
-		hda_nid_t *d;
+		const hda_nid_t *d;
 		for (d = codec->slave_dig_outs; *d; d++)
 		for (d = codec->slave_dig_outs; *d; d++)
 			snd_hda_codec_cleanup_stream(codec, *d);
 			snd_hda_codec_cleanup_stream(codec, *d);
 	}
 	}
@@ -4280,7 +4346,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
 				     unsigned int format,
 				     unsigned int format,
 				     struct snd_pcm_substream *substream)
 				     struct snd_pcm_substream *substream)
 {
 {
-	hda_nid_t *nids = mout->dac_nids;
+	const hda_nid_t *nids = mout->dac_nids;
 	int chs = substream->runtime->channels;
 	int chs = substream->runtime->channels;
 	int i;
 	int i;
 
 
@@ -4335,7 +4401,7 @@ EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare);
 int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
 int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
 				     struct hda_multi_out *mout)
 				     struct hda_multi_out *mout)
 {
 {
-	hda_nid_t *nids = mout->dac_nids;
+	const hda_nid_t *nids = mout->dac_nids;
 	int i;
 	int i;
 
 
 	for (i = 0; i < mout->num_dacs; i++)
 	for (i = 0; i < mout->num_dacs; i++)
@@ -4360,7 +4426,7 @@ EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup);
  * Helper for automatic pin configuration
  * Helper for automatic pin configuration
  */
  */
 
 
-static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)
+static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list)
 {
 {
 	for (; *list; list++)
 	for (; *list; list++)
 		if (*list == nid)
 		if (*list == nid)
@@ -4441,7 +4507,7 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
  */
  */
 int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 				 struct auto_pin_cfg *cfg,
 				 struct auto_pin_cfg *cfg,
-				 hda_nid_t *ignore_nids)
+				 const hda_nid_t *ignore_nids)
 {
 {
 	hda_nid_t nid, end_nid;
 	hda_nid_t nid, end_nid;
 	short seq, assoc_line_out, assoc_speaker;
 	short seq, assoc_line_out, assoc_speaker;
@@ -4632,10 +4698,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 	/*
 	/*
 	 * debug prints of the parsed results
 	 * debug prints of the parsed results
 	 */
 	 */
-	snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+	snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
 		   cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
 		   cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
 		   cfg->line_out_pins[2], cfg->line_out_pins[3],
 		   cfg->line_out_pins[2], cfg->line_out_pins[3],
-		   cfg->line_out_pins[4]);
+		   cfg->line_out_pins[4],
+		   cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
+		   (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
+		    "speaker" : "line"));
 	snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
 	snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
 		   cfg->speaker_outs, cfg->speaker_pins[0],
 		   cfg->speaker_outs, cfg->speaker_pins[0],
 		   cfg->speaker_pins[1], cfg->speaker_pins[2],
 		   cfg->speaker_pins[1], cfg->speaker_pins[2],
@@ -4986,6 +5055,8 @@ static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid,
 		return "Line-out";
 		return "Line-out";
 	case SND_JACK_HEADSET:
 	case SND_JACK_HEADSET:
 		return "Headset";
 		return "Headset";
+	case SND_JACK_VIDEOOUT:
+		return "HDMI/DP";
 	default:
 	default:
 		return "Misc";
 		return "Misc";
 	}
 	}

+ 3 - 1
sound/pci/hda/hda_codec.h

@@ -825,12 +825,14 @@ struct hda_codec {
 	struct hda_cache_rec amp_cache;	/* cache for amp access */
 	struct hda_cache_rec amp_cache;	/* cache for amp access */
 	struct hda_cache_rec cmd_cache;	/* cache for other commands */
 	struct hda_cache_rec cmd_cache;	/* cache for other commands */
 
 
+	struct snd_array conn_lists;	/* connection-list array */
+
 	struct mutex spdif_mutex;
 	struct mutex spdif_mutex;
 	struct mutex control_mutex;
 	struct mutex control_mutex;
 	unsigned int spdif_status;	/* IEC958 status bits */
 	unsigned int spdif_status;	/* IEC958 status bits */
 	unsigned short spdif_ctls;	/* SPDIF control bits */
 	unsigned short spdif_ctls;	/* SPDIF control bits */
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
-	hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
+	const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
 	struct snd_array init_pins;	/* initial (BIOS) pin configurations */
 	struct snd_array init_pins;	/* initial (BIOS) pin configurations */
 	struct snd_array driver_pins;	/* pin configs set by codec parser */
 	struct snd_array driver_pins;	/* pin configs set by codec parser */
 	struct snd_array cvt_setups;	/* audio convert setups */
 	struct snd_array cvt_setups;	/* audio convert setups */

+ 36 - 2
sound/pci/hda/hda_intel.c

@@ -126,6 +126,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
 			 "{Intel, ICH10},"
 			 "{Intel, ICH10},"
 			 "{Intel, PCH},"
 			 "{Intel, PCH},"
 			 "{Intel, CPT},"
 			 "{Intel, CPT},"
+			 "{Intel, PPT},"
 			 "{Intel, PBG},"
 			 "{Intel, PBG},"
 			 "{Intel, SCH},"
 			 "{Intel, SCH},"
 			 "{ATI, SB450},"
 			 "{ATI, SB450},"
@@ -1091,7 +1092,13 @@ static void azx_init_pci(struct azx *chip)
 				? "Failed" : "OK");
 				? "Failed" : "OK");
 		}
 		}
 		break;
 		break;
-
+	default:
+		/* AMD Hudson needs the similar snoop, as it seems... */
+		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
+			update_pci_byte(chip->pci,
+				ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
+				0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
+		break;
         }
         }
 }
 }
 
 
@@ -1446,6 +1453,17 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
 		}
 		}
 	}
 	}
 
 
+	/* AMD chipsets often cause the communication stalls upon certain
+	 * sequence like the pin-detection.  It seems that forcing the synced
+	 * access works around the stall.  Grrr...
+	 */
+	if (chip->pci->vendor == PCI_VENDOR_ID_AMD ||
+	    chip->pci->vendor == PCI_VENDOR_ID_ATI) {
+		snd_printk(KERN_INFO SFX "Enable sync_write for AMD chipset\n");
+		chip->bus->sync_write = 1;
+		chip->bus->allow_bus_reset = 1;
+	}
+
 	/* Then create codec instances */
 	/* Then create codec instances */
 	for (c = 0; c < max_slots; c++) {
 	for (c = 0; c < max_slots; c++) {
 		if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
 		if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
@@ -2349,9 +2367,16 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
 	/* Check VIA/ATI HD Audio Controller exist */
 	/* Check VIA/ATI HD Audio Controller exist */
 	switch (chip->driver_type) {
 	switch (chip->driver_type) {
 	case AZX_DRIVER_VIA:
 	case AZX_DRIVER_VIA:
-	case AZX_DRIVER_ATI:
 		/* Use link position directly, avoid any transfer problem. */
 		/* Use link position directly, avoid any transfer problem. */
 		return POS_FIX_VIACOMBO;
 		return POS_FIX_VIACOMBO;
+	case AZX_DRIVER_ATI:
+		/* ATI chipsets don't work well with position-buffer */
+		return POS_FIX_LPIB;
+	case AZX_DRIVER_GENERIC:
+		/* AMD chipsets also don't work with position-buffer */
+		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
+			return POS_FIX_LPIB;
+		break;
 	}
 	}
 
 
 	return POS_FIX_AUTO;
 	return POS_FIX_AUTO;
@@ -2549,6 +2574,13 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
 				gcap &= ~ICH6_GCAP_64OK;
 				gcap &= ~ICH6_GCAP_64OK;
 			pci_dev_put(p_smbus);
 			pci_dev_put(p_smbus);
 		}
 		}
+	} else {
+		/* FIXME: not sure whether this is really needed, but
+		 * Hudson isn't stable enough for allowing everything...
+		 * let's check later again.
+		 */
+		if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
+			gcap &= ~ICH6_GCAP_64OK;
 	}
 	}
 
 
 	/* disable 64bit DMA address for Teradici */
 	/* disable 64bit DMA address for Teradici */
@@ -2759,6 +2791,8 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
 	{ PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
 	{ PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
 	/* PBG */
 	/* PBG */
 	{ PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
 	{ PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
+	/* Panther Point */
+	{ PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH },
 	/* SCH */
 	/* SCH */
 	{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
 	{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
 	/* Generic Intel */
 	/* Generic Intel */

+ 11 - 5
sound/pci/hda/hda_local.h

@@ -267,11 +267,11 @@ enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */
 
 
 struct hda_multi_out {
 struct hda_multi_out {
 	int num_dacs;		/* # of DACs, must be more than 1 */
 	int num_dacs;		/* # of DACs, must be more than 1 */
-	hda_nid_t *dac_nids;	/* DAC list */
+	const hda_nid_t *dac_nids;	/* DAC list */
 	hda_nid_t hp_nid;	/* optional DAC for HP, 0 when not exists */
 	hda_nid_t hp_nid;	/* optional DAC for HP, 0 when not exists */
 	hda_nid_t extra_out_nid[3];	/* optional DACs, 0 when not exists */
 	hda_nid_t extra_out_nid[3];	/* optional DACs, 0 when not exists */
 	hda_nid_t dig_out_nid;	/* digital out audio widget */
 	hda_nid_t dig_out_nid;	/* digital out audio widget */
-	hda_nid_t *slave_dig_outs;
+	const hda_nid_t *slave_dig_outs;
 	int max_channels;	/* currently supported analog channels */
 	int max_channels;	/* currently supported analog channels */
 	int dig_out_used;	/* current usage of digital out (HDA_DIG_XXX) */
 	int dig_out_used;	/* current usage of digital out (HDA_DIG_XXX) */
 	int no_share_stream;	/* don't share a stream with multiple pins */
 	int no_share_stream;	/* don't share a stream with multiple pins */
@@ -347,7 +347,7 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
                                int num_configs, const char * const *models,
                                int num_configs, const char * const *models,
                                const struct snd_pci_quirk *tbl);
                                const struct snd_pci_quirk *tbl);
 int snd_hda_add_new_ctls(struct hda_codec *codec,
 int snd_hda_add_new_ctls(struct hda_codec *codec,
-			 struct snd_kcontrol_new *knew);
+			 const struct snd_kcontrol_new *knew);
 
 
 /*
 /*
  * unsolicited event handler
  * unsolicited event handler
@@ -443,7 +443,7 @@ struct auto_pin_cfg {
 
 
 int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 				 struct auto_pin_cfg *cfg,
 				 struct auto_pin_cfg *cfg,
-				 hda_nid_t *ignore_nids);
+				 const hda_nid_t *ignore_nids);
 
 
 /* amp values */
 /* amp values */
 #define AMP_IN_MUTE(idx)	(0x7080 | ((idx)<<8))
 #define AMP_IN_MUTE(idx)	(0x7080 | ((idx)<<8))
@@ -493,6 +493,12 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
 u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
 u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
 
 
+static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
+{
+	return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) &&
+		(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP);
+}
+
 /* flags for hda_nid_item */
 /* flags for hda_nid_item */
 #define HDA_NID_ITEM_AMP	(1<<0)
 #define HDA_NID_ITEM_AMP	(1<<0)
 
 
@@ -567,7 +573,7 @@ struct hda_amp_list {
 };
 };
 
 
 struct hda_loopback_check {
 struct hda_loopback_check {
-	struct hda_amp_list *amplist;
+	const struct hda_amp_list *amplist;
 	int power_on;
 	int power_on;
 };
 };
 
 

+ 173 - 172
sound/pci/hda/patch_analog.c

@@ -30,7 +30,7 @@
 #include "hda_beep.h"
 #include "hda_beep.h"
 
 
 struct ad198x_spec {
 struct ad198x_spec {
-	struct snd_kcontrol_new *mixers[6];
+	const struct snd_kcontrol_new *mixers[6];
 	int num_mixers;
 	int num_mixers;
 	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */
 	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */
 	const struct hda_verb *init_verbs[6];	/* initialization verbs
 	const struct hda_verb *init_verbs[6];	/* initialization verbs
@@ -46,17 +46,17 @@ struct ad198x_spec {
 	unsigned int cur_eapd;
 	unsigned int cur_eapd;
 	unsigned int need_dac_fix;
 	unsigned int need_dac_fix;
 
 
-	hda_nid_t *alt_dac_nid;
-	struct hda_pcm_stream *stream_analog_alt_playback;
+	const hda_nid_t *alt_dac_nid;
+	const struct hda_pcm_stream *stream_analog_alt_playback;
 
 
 	/* capture */
 	/* capture */
 	unsigned int num_adc_nids;
 	unsigned int num_adc_nids;
-	hda_nid_t *adc_nids;
+	const hda_nid_t *adc_nids;
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 
 
 	/* capture source */
 	/* capture source */
 	const struct hda_input_mux *input_mux;
 	const struct hda_input_mux *input_mux;
-	hda_nid_t *capsrc_nids;
+	const hda_nid_t *capsrc_nids;
 	unsigned int cur_mux[3];
 	unsigned int cur_mux[3];
 
 
 	/* channel model */
 	/* channel model */
@@ -182,13 +182,13 @@ static void ad198x_free_kctls(struct hda_codec *codec);
 
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
 /* additional beep mixers; the actual parameters are overwritten at build */
-static struct snd_kcontrol_new ad_beep_mixer[] = {
+static const struct snd_kcontrol_new ad_beep_mixer[] = {
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad_beep2_mixer[] = {
+static const struct snd_kcontrol_new ad_beep2_mixer[] = {
 	HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
 	{ } /* end */
 	{ } /* end */
@@ -231,7 +231,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
 	/* create beep controls if needed */
 	/* create beep controls if needed */
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 	if (spec->beep_amp) {
 	if (spec->beep_amp) {
-		struct snd_kcontrol_new *knew;
+		const struct snd_kcontrol_new *knew;
 		knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
 		knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
 		for ( ; knew->name; knew++) {
 		for ( ; knew->name; knew++) {
 			struct snd_kcontrol *kctl;
 			struct snd_kcontrol *kctl;
@@ -331,7 +331,7 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
 	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
 }
 }
 
 
-static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
+static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -403,7 +403,7 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 
 
 /*
 /*
  */
  */
-static struct hda_pcm_stream ad198x_pcm_analog_playback = {
+static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 6, /* changed later */
 	.channels_max = 6, /* changed later */
@@ -415,7 +415,7 @@ static struct hda_pcm_stream ad198x_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream ad198x_pcm_analog_capture = {
+static const struct hda_pcm_stream ad198x_pcm_analog_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -426,7 +426,7 @@ static struct hda_pcm_stream ad198x_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream ad198x_pcm_digital_playback = {
+static const struct hda_pcm_stream ad198x_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -439,7 +439,7 @@ static struct hda_pcm_stream ad198x_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream ad198x_pcm_digital_capture = {
+static const struct hda_pcm_stream ad198x_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -489,11 +489,6 @@ static int ad198x_build_pcms(struct hda_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
-static inline void ad198x_shutup(struct hda_codec *codec)
-{
-	snd_hda_shutup_pins(codec);
-}
-
 static void ad198x_free_kctls(struct hda_codec *codec)
 static void ad198x_free_kctls(struct hda_codec *codec)
 {
 {
 	struct ad198x_spec *spec = codec->spec;
 	struct ad198x_spec *spec = codec->spec;
@@ -547,6 +542,12 @@ static void ad198x_power_eapd(struct hda_codec *codec)
 	}
 	}
 }
 }
 
 
+static void ad198x_shutup(struct hda_codec *codec)
+{
+	snd_hda_shutup_pins(codec);
+	ad198x_power_eapd(codec);
+}
+
 static void ad198x_free(struct hda_codec *codec)
 static void ad198x_free(struct hda_codec *codec)
 {
 {
 	struct ad198x_spec *spec = codec->spec;
 	struct ad198x_spec *spec = codec->spec;
@@ -564,12 +565,11 @@ static void ad198x_free(struct hda_codec *codec)
 static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
 static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
 {
 {
 	ad198x_shutup(codec);
 	ad198x_shutup(codec);
-	ad198x_power_eapd(codec);
 	return 0;
 	return 0;
 }
 }
 #endif
 #endif
 
 
-static struct hda_codec_ops ad198x_patch_ops = {
+static const struct hda_codec_ops ad198x_patch_ops = {
 	.build_controls = ad198x_build_controls,
 	.build_controls = ad198x_build_controls,
 	.build_pcms = ad198x_build_pcms,
 	.build_pcms = ad198x_build_pcms,
 	.init = ad198x_init,
 	.init = ad198x_init,
@@ -639,13 +639,13 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
 #define AD1986A_CLFE_DAC	0x05
 #define AD1986A_CLFE_DAC	0x05
 #define AD1986A_ADC		0x06
 #define AD1986A_ADC		0x06
 
 
-static hda_nid_t ad1986a_dac_nids[3] = {
+static const hda_nid_t ad1986a_dac_nids[3] = {
 	AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
 	AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
 };
 };
-static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
-static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
+static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
+static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
 
 
-static struct hda_input_mux ad1986a_capture_source = {
+static const struct hda_input_mux ad1986a_capture_source = {
 	.num_items = 7,
 	.num_items = 7,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -659,7 +659,7 @@ static struct hda_input_mux ad1986a_capture_source = {
 };
 };
 
 
 
 
-static struct hda_bind_ctls ad1986a_bind_pcm_vol = {
+static const struct hda_bind_ctls ad1986a_bind_pcm_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
@@ -669,7 +669,7 @@ static struct hda_bind_ctls ad1986a_bind_pcm_vol = {
 	},
 	},
 };
 };
 
 
-static struct hda_bind_ctls ad1986a_bind_pcm_sw = {
+static const struct hda_bind_ctls ad1986a_bind_pcm_sw = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
@@ -682,7 +682,7 @@ static struct hda_bind_ctls ad1986a_bind_pcm_sw = {
 /*
 /*
  * mixers
  * mixers
  */
  */
-static struct snd_kcontrol_new ad1986a_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_mixers[] = {
 	/*
 	/*
 	 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
 	 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
 	 */
 	 */
@@ -723,7 +723,7 @@ static struct snd_kcontrol_new ad1986a_mixers[] = {
 };
 };
 
 
 /* additional mixers for 3stack mode */
 /* additional mixers for 3stack mode */
-static struct snd_kcontrol_new ad1986a_3st_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_3st_mixers[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
 		.name = "Channel Mode",
@@ -735,10 +735,10 @@ static struct snd_kcontrol_new ad1986a_3st_mixers[] = {
 };
 };
 
 
 /* laptop model - 2ch only */
 /* laptop model - 2ch only */
-static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
+static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
 
 
 /* master controls both pins 0x1a and 0x1b */
 /* master controls both pins 0x1a and 0x1b */
-static struct hda_bind_ctls ad1986a_laptop_master_vol = {
+static const struct hda_bind_ctls ad1986a_laptop_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
@@ -747,7 +747,7 @@ static struct hda_bind_ctls ad1986a_laptop_master_vol = {
 	},
 	},
 };
 };
 
 
-static struct hda_bind_ctls ad1986a_laptop_master_sw = {
+static const struct hda_bind_ctls ad1986a_laptop_master_sw = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
@@ -756,7 +756,7 @@ static struct hda_bind_ctls ad1986a_laptop_master_sw = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
@@ -787,7 +787,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
 
 
 /* laptop-eapd model - 2ch only */
 /* laptop-eapd model - 2ch only */
 
 
-static struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
+static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -796,7 +796,7 @@ static struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux ad1986a_automic_capture_source = {
+static const struct hda_input_mux ad1986a_automic_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -804,13 +804,13 @@ static struct hda_input_mux ad1986a_automic_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
 	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
@@ -837,7 +837,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
 	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
 	{ } /* end */
 	{ } /* end */
@@ -931,7 +931,7 @@ static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 	return change;
 	return change;
 }
 }
 
 
-static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
+static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -949,7 +949,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
 /*
 /*
  * initialization verbs
  * initialization verbs
  */
  */
-static struct hda_verb ad1986a_init_verbs[] = {
+static const struct hda_verb ad1986a_init_verbs[] = {
 	/* Front, Surround, CLFE DAC; mute as default */
 	/* Front, Surround, CLFE DAC; mute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
@@ -1004,7 +1004,7 @@ static struct hda_verb ad1986a_init_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb ad1986a_ch2_init[] = {
+static const struct hda_verb ad1986a_ch2_init[] = {
 	/* Surround out -> Line In */
 	/* Surround out -> Line In */
 	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
  	/* Line-in selectors */
  	/* Line-in selectors */
@@ -1016,7 +1016,7 @@ static struct hda_verb ad1986a_ch2_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb ad1986a_ch4_init[] = {
+static const struct hda_verb ad1986a_ch4_init[] = {
 	/* Surround out -> Surround */
 	/* Surround out -> Surround */
 	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
 	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
@@ -1026,7 +1026,7 @@ static struct hda_verb ad1986a_ch4_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb ad1986a_ch6_init[] = {
+static const struct hda_verb ad1986a_ch6_init[] = {
 	/* Surround out -> Surround out */
 	/* Surround out -> Surround out */
 	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
 	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
@@ -1036,19 +1036,19 @@ static struct hda_verb ad1986a_ch6_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode ad1986a_modes[3] = {
+static const struct hda_channel_mode ad1986a_modes[3] = {
 	{ 2, ad1986a_ch2_init },
 	{ 2, ad1986a_ch2_init },
 	{ 4, ad1986a_ch4_init },
 	{ 4, ad1986a_ch4_init },
 	{ 6, ad1986a_ch6_init },
 	{ 6, ad1986a_ch6_init },
 };
 };
 
 
 /* eapd initialization */
 /* eapd initialization */
-static struct hda_verb ad1986a_eapd_init_verbs[] = {
+static const struct hda_verb ad1986a_eapd_init_verbs[] = {
 	{0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
 	{0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb ad1986a_automic_verbs[] = {
+static const struct hda_verb ad1986a_automic_verbs[] = {
 	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	/*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
 	/*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
@@ -1058,7 +1058,7 @@ static struct hda_verb ad1986a_automic_verbs[] = {
 };
 };
 
 
 /* Ultra initialization */
 /* Ultra initialization */
-static struct hda_verb ad1986a_ultra_init[] = {
+static const struct hda_verb ad1986a_ultra_init[] = {
 	/* eapd initialization */
 	/* eapd initialization */
 	{ 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
 	{ 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
 	/* CLFE -> Mic in */
 	/* CLFE -> Mic in */
@@ -1069,7 +1069,7 @@ static struct hda_verb ad1986a_ultra_init[] = {
 };
 };
 
 
 /* pin sensing on HP jack */
 /* pin sensing on HP jack */
-static struct hda_verb ad1986a_hp_init_verbs[] = {
+static const struct hda_verb ad1986a_hp_init_verbs[] = {
 	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
 	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
 	{}
 	{}
 };
 };
@@ -1120,7 +1120,7 @@ static const char * const ad1986a_models[AD1986A_MODELS] = {
 	[AD1986A_SAMSUNG_P50]	= "samsung-p50",
 	[AD1986A_SAMSUNG_P50]	= "samsung-p50",
 };
 };
 
 
-static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
+static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
@@ -1152,7 +1152,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
 };
 };
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1986a_loopbacks[] = {
+static const struct hda_amp_list ad1986a_loopbacks[] = {
 	{ 0x13, HDA_OUTPUT, 0 }, /* Mic */
 	{ 0x13, HDA_OUTPUT, 0 }, /* Mic */
 	{ 0x14, HDA_OUTPUT, 0 }, /* Phone */
 	{ 0x14, HDA_OUTPUT, 0 }, /* Phone */
 	{ 0x15, HDA_OUTPUT, 0 }, /* CD */
 	{ 0x15, HDA_OUTPUT, 0 }, /* CD */
@@ -1329,11 +1329,11 @@ static int patch_ad1986a(struct hda_codec *codec)
 #define AD1983_DAC		0x03
 #define AD1983_DAC		0x03
 #define AD1983_ADC		0x04
 #define AD1983_ADC		0x04
 
 
-static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
-static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
-static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
+static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
+static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
+static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
 
 
-static struct hda_input_mux ad1983_capture_source = {
+static const struct hda_input_mux ad1983_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -1348,7 +1348,7 @@ static struct hda_input_mux ad1983_capture_source = {
  */
  */
 static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
 {
-	static char *texts[] = { "PCM", "ADC" };
+	static const char * const texts[] = { "PCM", "ADC" };
 
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->count = 1;
@@ -1385,7 +1385,7 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
 	return 0;
 	return 0;
 }
 }
 
 
-static struct snd_kcontrol_new ad1983_mixers[] = {
+static const struct snd_kcontrol_new ad1983_mixers[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
@@ -1418,7 +1418,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb ad1983_init_verbs[] = {
+static const struct hda_verb ad1983_init_verbs[] = {
 	/* Front, HP, Mono; mute as default */
 	/* Front, HP, Mono; mute as default */
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
@@ -1458,7 +1458,7 @@ static struct hda_verb ad1983_init_verbs[] = {
 };
 };
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1983_loopbacks[] = {
+static const struct hda_amp_list ad1983_loopbacks[] = {
 	{ 0x12, HDA_OUTPUT, 0 }, /* Mic */
 	{ 0x12, HDA_OUTPUT, 0 }, /* Mic */
 	{ 0x13, HDA_OUTPUT, 0 }, /* Line */
 	{ 0x13, HDA_OUTPUT, 0 }, /* Line */
 	{ } /* end */
 	{ } /* end */
@@ -1518,12 +1518,12 @@ static int patch_ad1983(struct hda_codec *codec)
 #define AD1981_DAC		0x03
 #define AD1981_DAC		0x03
 #define AD1981_ADC		0x04
 #define AD1981_ADC		0x04
 
 
-static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
-static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
-static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
+static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
+static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
+static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
 
 
 /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
 /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
-static struct hda_input_mux ad1981_capture_source = {
+static const struct hda_input_mux ad1981_capture_source = {
 	.num_items = 7,
 	.num_items = 7,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x0 },
 		{ "Front Mic", 0x0 },
@@ -1536,7 +1536,7 @@ static struct hda_input_mux ad1981_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new ad1981_mixers[] = {
+static const struct snd_kcontrol_new ad1981_mixers[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
@@ -1577,7 +1577,7 @@ static struct snd_kcontrol_new ad1981_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb ad1981_init_verbs[] = {
+static const struct hda_verb ad1981_init_verbs[] = {
 	/* Front, HP, Mono; mute as default */
 	/* Front, HP, Mono; mute as default */
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
@@ -1625,7 +1625,7 @@ static struct hda_verb ad1981_init_verbs[] = {
 };
 };
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1981_loopbacks[] = {
+static const struct hda_amp_list ad1981_loopbacks[] = {
 	{ 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
 	{ 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
 	{ 0x13, HDA_OUTPUT, 0 }, /* Line */
 	{ 0x13, HDA_OUTPUT, 0 }, /* Line */
 	{ 0x1b, HDA_OUTPUT, 0 }, /* Aux */
 	{ 0x1b, HDA_OUTPUT, 0 }, /* Aux */
@@ -1645,7 +1645,7 @@ static struct hda_amp_list ad1981_loopbacks[] = {
 #define AD1981_HP_EVENT		0x37
 #define AD1981_HP_EVENT		0x37
 #define AD1981_MIC_EVENT	0x38
 #define AD1981_MIC_EVENT	0x38
 
 
-static struct hda_verb ad1981_hp_init_verbs[] = {
+static const struct hda_verb ad1981_hp_init_verbs[] = {
 	{0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
 	{0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
 	/* pin sensing on HP and Mic jacks */
 	/* pin sensing on HP and Mic jacks */
 	{0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
 	{0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
@@ -1674,7 +1674,7 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 }
 }
 
 
 /* bind volumes of both NID 0x05 and 0x06 */
 /* bind volumes of both NID 0x05 and 0x06 */
-static struct hda_bind_ctls ad1981_hp_bind_master_vol = {
+static const struct hda_bind_ctls ad1981_hp_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
@@ -1696,12 +1696,12 @@ static void ad1981_hp_automute(struct hda_codec *codec)
 /* toggle input of built-in and mic jack appropriately */
 /* toggle input of built-in and mic jack appropriately */
 static void ad1981_hp_automic(struct hda_codec *codec)
 static void ad1981_hp_automic(struct hda_codec *codec)
 {
 {
-	static struct hda_verb mic_jack_on[] = {
+	static const struct hda_verb mic_jack_on[] = {
 		{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{}
 		{}
 	};
 	};
-	static struct hda_verb mic_jack_off[] = {
+	static const struct hda_verb mic_jack_off[] = {
 		{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{}
 		{}
@@ -1730,7 +1730,7 @@ static void ad1981_hp_unsol_event(struct hda_codec *codec,
 	}
 	}
 }
 }
 
 
-static struct hda_input_mux ad1981_hp_capture_source = {
+static const struct hda_input_mux ad1981_hp_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -1739,7 +1739,7 @@ static struct hda_input_mux ad1981_hp_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new ad1981_hp_mixers[] = {
+static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
 	HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1790,7 +1790,7 @@ static int ad1981_hp_init(struct hda_codec *codec)
 }
 }
 
 
 /* configuration for Toshiba Laptops */
 /* configuration for Toshiba Laptops */
-static struct hda_verb ad1981_toshiba_init_verbs[] = {
+static const struct hda_verb ad1981_toshiba_init_verbs[] = {
 	{0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
 	{0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
 	/* pin sensing on HP and Mic jacks */
 	/* pin sensing on HP and Mic jacks */
 	{0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
 	{0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
@@ -1798,14 +1798,14 @@ static struct hda_verb ad1981_toshiba_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
+static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
 	HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
 	{ }
 	{ }
 };
 };
 
 
 /* configuration for Lenovo Thinkpad T60 */
 /* configuration for Lenovo Thinkpad T60 */
-static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
+static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
@@ -1835,7 +1835,7 @@ static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_input_mux ad1981_thinkpad_capture_source = {
+static const struct hda_input_mux ad1981_thinkpad_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -1860,7 +1860,7 @@ static const char * const ad1981_models[AD1981_MODELS] = {
 	[AD1981_TOSHIBA]	= "toshiba"
 	[AD1981_TOSHIBA]	= "toshiba"
 };
 };
 
 
-static struct snd_pci_quirk ad1981_cfg_tbl[] = {
+static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
 	SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
 	SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
 	SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
 	/* All HP models */
 	/* All HP models */
@@ -2075,32 +2075,32 @@ enum {
  * mixers
  * mixers
  */
  */
 
 
-static hda_nid_t ad1988_6stack_dac_nids[4] = {
+static const hda_nid_t ad1988_6stack_dac_nids[4] = {
 	0x04, 0x06, 0x05, 0x0a
 	0x04, 0x06, 0x05, 0x0a
 };
 };
 
 
-static hda_nid_t ad1988_3stack_dac_nids[3] = {
+static const hda_nid_t ad1988_3stack_dac_nids[3] = {
 	0x04, 0x05, 0x0a
 	0x04, 0x05, 0x0a
 };
 };
 
 
 /* for AD1988A revision-2, DAC2-4 are swapped */
 /* for AD1988A revision-2, DAC2-4 are swapped */
-static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
+static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
 	0x04, 0x05, 0x0a, 0x06
 	0x04, 0x05, 0x0a, 0x06
 };
 };
 
 
-static hda_nid_t ad1988_alt_dac_nid[1] = {
+static const hda_nid_t ad1988_alt_dac_nid[1] = {
 	0x03
 	0x03
 };
 };
 
 
-static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
+static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
 	0x04, 0x0a, 0x06
 	0x04, 0x0a, 0x06
 };
 };
 
 
-static hda_nid_t ad1988_adc_nids[3] = {
+static const hda_nid_t ad1988_adc_nids[3] = {
 	0x08, 0x09, 0x0f
 	0x08, 0x09, 0x0f
 };
 };
 
 
-static hda_nid_t ad1988_capsrc_nids[3] = {
+static const hda_nid_t ad1988_capsrc_nids[3] = {
 	0x0c, 0x0d, 0x0e
 	0x0c, 0x0d, 0x0e
 };
 };
 
 
@@ -2108,11 +2108,11 @@ static hda_nid_t ad1988_capsrc_nids[3] = {
 #define AD1988_SPDIF_OUT_HDMI	0x0b
 #define AD1988_SPDIF_OUT_HDMI	0x0b
 #define AD1988_SPDIF_IN		0x07
 #define AD1988_SPDIF_IN		0x07
 
 
-static hda_nid_t ad1989b_slave_dig_outs[] = {
+static const hda_nid_t ad1989b_slave_dig_outs[] = {
 	AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
 	AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
 };
 };
 
 
-static struct hda_input_mux ad1988_6stack_capture_source = {
+static const struct hda_input_mux ad1988_6stack_capture_source = {
 	.num_items = 5,
 	.num_items = 5,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x1 },	/* port-B */
 		{ "Front Mic", 0x1 },	/* port-B */
@@ -2123,7 +2123,7 @@ static struct hda_input_mux ad1988_6stack_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux ad1988_laptop_capture_source = {
+static const struct hda_input_mux ad1988_laptop_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic/Line", 0x1 },	/* port-B */
 		{ "Mic/Line", 0x1 },	/* port-B */
@@ -2166,7 +2166,7 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
 }
 }
 
 
 /* 6-stack mode */
 /* 6-stack mode */
-static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
+static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
@@ -2175,7 +2175,7 @@ static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
+static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
@@ -2184,7 +2184,7 @@ static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
+static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
 	HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
 	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
 	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
@@ -2211,14 +2211,14 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
+static const struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 
 
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
 /* 3-stack mode */
 /* 3-stack mode */
-static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
+static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
@@ -2226,7 +2226,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
+static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
@@ -2234,7 +2234,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
+static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
 	HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
 	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
 	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
@@ -2268,7 +2268,7 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
 };
 };
 
 
 /* laptop mode */
 /* laptop mode */
-static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
+static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
 	HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
@@ -2299,7 +2299,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
 };
 };
 
 
 /* capture */
 /* capture */
-static struct snd_kcontrol_new ad1988_capture_mixers[] = {
+static const struct snd_kcontrol_new ad1988_capture_mixers[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -2324,7 +2324,7 @@ static struct snd_kcontrol_new ad1988_capture_mixers[] = {
 static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
 static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
 					     struct snd_ctl_elem_info *uinfo)
 					     struct snd_ctl_elem_info *uinfo)
 {
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"PCM", "ADC1", "ADC2", "ADC3"
 		"PCM", "ADC1", "ADC2", "ADC3"
 	};
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -2405,7 +2405,7 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
 	return change;
 	return change;
 }
 }
 
 
-static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
+static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
 	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2418,12 +2418,12 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
+static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
 	HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
+static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
 	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
 	{ } /* end */
 	{ } /* end */
@@ -2436,7 +2436,7 @@ static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
 /*
 /*
  * for 6-stack (+dig)
  * for 6-stack (+dig)
  */
  */
-static struct hda_verb ad1988_6stack_init_verbs[] = {
+static const struct hda_verb ad1988_6stack_init_verbs[] = {
 	/* Front, Surround, CLFE, side DAC; unmute as default */
 	/* Front, Surround, CLFE, side DAC; unmute as default */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -2496,7 +2496,7 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
+static const struct hda_verb ad1988_6stack_fp_init_verbs[] = {
 	/* Headphone; unmute as default */
 	/* Headphone; unmute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* Port-A front headphon path */
 	/* Port-A front headphon path */
@@ -2509,7 +2509,7 @@ static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb ad1988_capture_init_verbs[] = {
+static const struct hda_verb ad1988_capture_init_verbs[] = {
 	/* mute analog mix */
 	/* mute analog mix */
 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -2527,7 +2527,7 @@ static struct hda_verb ad1988_capture_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb ad1988_spdif_init_verbs[] = {
+static const struct hda_verb ad1988_spdif_init_verbs[] = {
 	/* SPDIF out sel */
 	/* SPDIF out sel */
 	{0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
 	{0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
 	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
 	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
@@ -2539,14 +2539,14 @@ static struct hda_verb ad1988_spdif_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb ad1988_spdif_in_init_verbs[] = {
+static const struct hda_verb ad1988_spdif_in_init_verbs[] = {
 	/* unmute SPDIF input pin */
 	/* unmute SPDIF input pin */
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ }
 	{ }
 };
 };
 
 
 /* AD1989 has no ADC -> SPDIF route */
 /* AD1989 has no ADC -> SPDIF route */
-static struct hda_verb ad1989_spdif_init_verbs[] = {
+static const struct hda_verb ad1989_spdif_init_verbs[] = {
 	/* SPDIF-1 out pin */
 	/* SPDIF-1 out pin */
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
@@ -2559,7 +2559,7 @@ static struct hda_verb ad1989_spdif_init_verbs[] = {
 /*
 /*
  * verbs for 3stack (+dig)
  * verbs for 3stack (+dig)
  */
  */
-static struct hda_verb ad1988_3stack_ch2_init[] = {
+static const struct hda_verb ad1988_3stack_ch2_init[] = {
 	/* set port-C to line-in */
 	/* set port-C to line-in */
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -2569,7 +2569,7 @@ static struct hda_verb ad1988_3stack_ch2_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb ad1988_3stack_ch6_init[] = {
+static const struct hda_verb ad1988_3stack_ch6_init[] = {
 	/* set port-C to surround out */
 	/* set port-C to surround out */
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -2579,12 +2579,12 @@ static struct hda_verb ad1988_3stack_ch6_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode ad1988_3stack_modes[2] = {
+static const struct hda_channel_mode ad1988_3stack_modes[2] = {
 	{ 2, ad1988_3stack_ch2_init },
 	{ 2, ad1988_3stack_ch2_init },
 	{ 6, ad1988_3stack_ch6_init },
 	{ 6, ad1988_3stack_ch6_init },
 };
 };
 
 
-static struct hda_verb ad1988_3stack_init_verbs[] = {
+static const struct hda_verb ad1988_3stack_init_verbs[] = {
 	/* Front, Surround, CLFE, side DAC; unmute as default */
 	/* Front, Surround, CLFE, side DAC; unmute as default */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -2644,13 +2644,13 @@ static struct hda_verb ad1988_3stack_init_verbs[] = {
 /*
 /*
  * verbs for laptop mode (+dig)
  * verbs for laptop mode (+dig)
  */
  */
-static struct hda_verb ad1988_laptop_hp_on[] = {
+static const struct hda_verb ad1988_laptop_hp_on[] = {
 	/* unmute port-A and mute port-D */
 	/* unmute port-A and mute port-D */
 	{ 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ } /* end */
 	{ } /* end */
 };
 };
-static struct hda_verb ad1988_laptop_hp_off[] = {
+static const struct hda_verb ad1988_laptop_hp_off[] = {
 	/* mute port-A and unmute port-D */
 	/* mute port-A and unmute port-D */
 	{ 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -2659,7 +2659,7 @@ static struct hda_verb ad1988_laptop_hp_off[] = {
 
 
 #define AD1988_HP_EVENT	0x01
 #define AD1988_HP_EVENT	0x01
 
 
-static struct hda_verb ad1988_laptop_init_verbs[] = {
+static const struct hda_verb ad1988_laptop_init_verbs[] = {
 	/* Front, Surround, CLFE, side DAC; unmute as default */
 	/* Front, Surround, CLFE, side DAC; unmute as default */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -2723,7 +2723,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
 } 
 } 
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1988_loopbacks[] = {
+static const struct hda_amp_list ad1988_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Line */
 	{ 0x20, HDA_INPUT, 1 }, /* Line */
 	{ 0x20, HDA_INPUT, 4 }, /* Mic */
 	{ 0x20, HDA_INPUT, 4 }, /* Mic */
@@ -2741,7 +2741,7 @@ enum {
 	AD_CTL_WIDGET_MUTE,
 	AD_CTL_WIDGET_MUTE,
 	AD_CTL_BIND_MUTE,
 	AD_CTL_BIND_MUTE,
 };
 };
-static struct snd_kcontrol_new ad1988_control_templates[] = {
+static const struct snd_kcontrol_new ad1988_control_templates[] = {
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	HDA_BIND_MUTE(NULL, 0, 0, 0),
 	HDA_BIND_MUTE(NULL, 0, 0, 0),
@@ -2770,18 +2770,18 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
 #define AD1988_PIN_CD_NID		0x18
 #define AD1988_PIN_CD_NID		0x18
 #define AD1988_PIN_BEEP_NID		0x10
 #define AD1988_PIN_BEEP_NID		0x10
 
 
-static hda_nid_t ad1988_mixer_nids[8] = {
+static const hda_nid_t ad1988_mixer_nids[8] = {
 	/* A     B     C     D     E     F     G     H */
 	/* A     B     C     D     E     F     G     H */
 	0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
 	0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
 };
 };
 
 
 static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
 static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
 {
 {
-	static hda_nid_t idx_to_dac[8] = {
+	static const hda_nid_t idx_to_dac[8] = {
 		/* A     B     C     D     E     F     G     H */
 		/* A     B     C     D     E     F     G     H */
 		0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
 		0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
 	};
 	};
-	static hda_nid_t idx_to_dac_rev2[8] = {
+	static const hda_nid_t idx_to_dac_rev2[8] = {
 		/* A     B     C     D     E     F     G     H */
 		/* A     B     C     D     E     F     G     H */
 		0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
 		0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
 	};
 	};
@@ -2791,13 +2791,13 @@ static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
 		return idx_to_dac[idx];
 		return idx_to_dac[idx];
 }
 }
 
 
-static hda_nid_t ad1988_boost_nids[8] = {
+static const hda_nid_t ad1988_boost_nids[8] = {
 	0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
 	0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
 };
 };
 
 
 static int ad1988_pin_idx(hda_nid_t nid)
 static int ad1988_pin_idx(hda_nid_t nid)
 {
 {
-	static hda_nid_t ad1988_io_pins[8] = {
+	static const hda_nid_t ad1988_io_pins[8] = {
 		0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
 		0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
 	};
 	};
 	int i;
 	int i;
@@ -2809,7 +2809,7 @@ static int ad1988_pin_idx(hda_nid_t nid)
 
 
 static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
 static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
 {
 {
-	static int loopback_idx[8] = {
+	static const int loopback_idx[8] = {
 		2, 0, 1, 3, 4, 5, 1, 4
 		2, 0, 1, 3, 4, 5, 1, 4
 	};
 	};
 	switch (nid) {
 	switch (nid) {
@@ -2822,7 +2822,7 @@ static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
 
 
 static int ad1988_pin_to_adc_idx(hda_nid_t nid)
 static int ad1988_pin_to_adc_idx(hda_nid_t nid)
 {
 {
-	static int adc_idx[8] = {
+	static const int adc_idx[8] = {
 		0, 1, 2, 8, 4, 3, 6, 7
 		0, 1, 2, 8, 4, 3, 6, 7
 	};
 	};
 	switch (nid) {
 	switch (nid) {
@@ -2845,7 +2845,7 @@ static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,
 	/* check the pins hardwired to audio widget */
 	/* check the pins hardwired to audio widget */
 	for (i = 0; i < cfg->line_outs; i++) {
 	for (i = 0; i < cfg->line_outs; i++) {
 		idx = ad1988_pin_idx(cfg->line_out_pins[i]);
 		idx = ad1988_pin_idx(cfg->line_out_pins[i]);
-		spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx);
+		spec->private_dac_nids[i] = ad1988_idx_to_dac(codec, idx);
 	}
 	}
 	spec->multiout.num_dacs = cfg->line_outs;
 	spec->multiout.num_dacs = cfg->line_outs;
 	return 0;
 	return 0;
@@ -3070,6 +3070,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
 
 
 	for (i = 0; i < cfg->num_inputs; i++) {
 	for (i = 0; i < cfg->num_inputs; i++) {
 		hda_nid_t nid = cfg->inputs[i].pin;
 		hda_nid_t nid = cfg->inputs[i].pin;
+		int type = cfg->inputs[i].type;
 		switch (nid) {
 		switch (nid) {
 		case 0x15: /* port-C */
 		case 0x15: /* port-C */
 			snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
 			snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
@@ -3079,7 +3080,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
 			break;
 			break;
 		}
 		}
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
+				    type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
 		if (nid != AD1988_PIN_CD_NID)
 		if (nid != AD1988_PIN_CD_NID)
 			snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
 			snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
 					    AMP_OUT_MUTE);
 					    AMP_OUT_MUTE);
@@ -3154,7 +3155,7 @@ static const char * const ad1988_models[AD1988_MODEL_LAST] = {
 	[AD1988_AUTO]		= "auto",
 	[AD1988_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk ad1988_cfg_tbl[] = {
+static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
@@ -3342,21 +3343,21 @@ static int patch_ad1988(struct hda_codec *codec)
  * but no build-up framework is given, so far.
  * but no build-up framework is given, so far.
  */
  */
 
 
-static hda_nid_t ad1884_dac_nids[1] = {
+static const hda_nid_t ad1884_dac_nids[1] = {
 	0x04,
 	0x04,
 };
 };
 
 
-static hda_nid_t ad1884_adc_nids[2] = {
+static const hda_nid_t ad1884_adc_nids[2] = {
 	0x08, 0x09,
 	0x08, 0x09,
 };
 };
 
 
-static hda_nid_t ad1884_capsrc_nids[2] = {
+static const hda_nid_t ad1884_capsrc_nids[2] = {
 	0x0c, 0x0d,
 	0x0c, 0x0d,
 };
 };
 
 
 #define AD1884_SPDIF_OUT	0x02
 #define AD1884_SPDIF_OUT	0x02
 
 
-static struct hda_input_mux ad1884_capture_source = {
+static const struct hda_input_mux ad1884_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x0 },
 		{ "Front Mic", 0x0 },
@@ -3366,7 +3367,7 @@ static struct hda_input_mux ad1884_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new ad1884_base_mixers[] = {
+static const struct snd_kcontrol_new ad1884_base_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
 	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
@@ -3410,7 +3411,7 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
+static const struct snd_kcontrol_new ad1984_dmic_mixers[] = {
 	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
 	HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
@@ -3423,7 +3424,7 @@ static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
 /*
 /*
  * initialization verbs
  * initialization verbs
  */
  */
-static struct hda_verb ad1884_init_verbs[] = {
+static const struct hda_verb ad1884_init_verbs[] = {
 	/* DACs; mute as default */
 	/* DACs; mute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -3469,7 +3470,7 @@ static struct hda_verb ad1884_init_verbs[] = {
 };
 };
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1884_loopbacks[] = {
+static const struct hda_amp_list ad1884_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
 	{ 0x20, HDA_INPUT, 2 }, /* CD */
 	{ 0x20, HDA_INPUT, 2 }, /* CD */
@@ -3541,7 +3542,7 @@ static int patch_ad1884(struct hda_codec *codec)
 /*
 /*
  * Lenovo Thinkpad T61/X61
  * Lenovo Thinkpad T61/X61
  */
  */
-static struct hda_input_mux ad1984_thinkpad_capture_source = {
+static const struct hda_input_mux ad1984_thinkpad_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -3555,7 +3556,7 @@ static struct hda_input_mux ad1984_thinkpad_capture_source = {
 /*
 /*
  * Dell Precision T3400
  * Dell Precision T3400
  */
  */
-static struct hda_input_mux ad1984_dell_desktop_capture_source = {
+static const struct hda_input_mux ad1984_dell_desktop_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x0 },
 		{ "Front Mic", 0x0 },
@@ -3565,7 +3566,7 @@ static struct hda_input_mux ad1984_dell_desktop_capture_source = {
 };
 };
 
 
 
 
-static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
+static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
 	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
@@ -3611,7 +3612,7 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
 };
 };
 
 
 /* additional verbs */
 /* additional verbs */
-static struct hda_verb ad1984_thinkpad_init_verbs[] = {
+static const struct hda_verb ad1984_thinkpad_init_verbs[] = {
 	/* Port-E (docking station mic) pin */
 	/* Port-E (docking station mic) pin */
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
@@ -3629,7 +3630,7 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = {
 /*
 /*
  * Dell Precision T3400
  * Dell Precision T3400
  */
  */
-static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
+static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
@@ -3680,7 +3681,7 @@ static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 	return 0;
 }
 }
 
 
-static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
+static const struct hda_pcm_stream ad1984_pcm_dmic_capture = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -3722,7 +3723,7 @@ static const char * const ad1984_models[AD1984_MODELS] = {
 	[AD1984_DELL_DESKTOP]	= "dell_desktop",
 	[AD1984_DELL_DESKTOP]	= "dell_desktop",
 };
 };
 
 
-static struct snd_pci_quirk ad1984_cfg_tbl[] = {
+static const struct snd_pci_quirk ad1984_cfg_tbl[] = {
 	/* Lenovo Thinkpad T61/X61 */
 	/* Lenovo Thinkpad T61/X61 */
 	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
 	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
 	SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
 	SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
@@ -3787,7 +3788,7 @@ static int patch_ad1984(struct hda_codec *codec)
  * We share the single DAC for both HP and line-outs (see AD1884/1984).
  * We share the single DAC for both HP and line-outs (see AD1884/1984).
  */
  */
 
 
-static hda_nid_t ad1884a_dac_nids[1] = {
+static const hda_nid_t ad1884a_dac_nids[1] = {
 	0x03,
 	0x03,
 };
 };
 
 
@@ -3796,7 +3797,7 @@ static hda_nid_t ad1884a_dac_nids[1] = {
 
 
 #define AD1884A_SPDIF_OUT	0x02
 #define AD1884A_SPDIF_OUT	0x02
 
 
-static struct hda_input_mux ad1884a_capture_source = {
+static const struct hda_input_mux ad1884a_capture_source = {
 	.num_items = 5,
 	.num_items = 5,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x0 },
 		{ "Front Mic", 0x0 },
@@ -3807,7 +3808,7 @@ static struct hda_input_mux ad1884a_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new ad1884a_base_mixers[] = {
+static const struct snd_kcontrol_new ad1884a_base_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
@@ -3859,7 +3860,7 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = {
 /*
 /*
  * initialization verbs
  * initialization verbs
  */
  */
-static struct hda_verb ad1884a_init_verbs[] = {
+static const struct hda_verb ad1884a_init_verbs[] = {
 	/* DACs; unmute as default */
 	/* DACs; unmute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
@@ -3914,7 +3915,7 @@ static struct hda_verb ad1884a_init_verbs[] = {
 };
 };
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1884a_loopbacks[] = {
+static const struct hda_amp_list ad1884a_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
 	{ 0x20, HDA_INPUT, 2 }, /* CD */
 	{ 0x20, HDA_INPUT, 2 }, /* CD */
@@ -3947,7 +3948,7 @@ static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
 	return ret;
 	return ret;
 }
 }
 
 
-static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
+static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -3975,7 +3976,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
+static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	/*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
 	/*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
 	{
 	{
@@ -4095,7 +4096,7 @@ static int ad1884a_laptop_init(struct hda_codec *codec)
 }
 }
 
 
 /* additional verbs for laptop model */
 /* additional verbs for laptop model */
-static struct hda_verb ad1884a_laptop_verbs[] = {
+static const struct hda_verb ad1884a_laptop_verbs[] = {
 	/* Port-A (HP) pin - always unmuted */
 	/* Port-A (HP) pin - always unmuted */
 	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* Port-F (int speaker) mixer - route only from analog mixer */
 	/* Port-F (int speaker) mixer - route only from analog mixer */
@@ -4126,7 +4127,7 @@ static struct hda_verb ad1884a_laptop_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb ad1884a_mobile_verbs[] = {
+static const struct hda_verb ad1884a_mobile_verbs[] = {
 	/* DACs; unmute as default */
 	/* DACs; unmute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
@@ -4181,7 +4182,7 @@ static struct hda_verb ad1884a_mobile_verbs[] = {
  * 0x17 - built-in mic
  * 0x17 - built-in mic
  */
  */
 
 
-static struct hda_verb ad1984a_thinkpad_verbs[] = {
+static const struct hda_verb ad1984a_thinkpad_verbs[] = {
 	/* HP unmute */
 	/* HP unmute */
 	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* analog mix */
 	/* analog mix */
@@ -4198,7 +4199,7 @@ static struct hda_verb ad1984a_thinkpad_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
+static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
@@ -4219,7 +4220,7 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_input_mux ad1984a_thinkpad_capture_source = {
+static const struct hda_input_mux ad1984a_thinkpad_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -4262,7 +4263,7 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec)
  * 0x15 - mic-in
  * 0x15 - mic-in
  */
  */
 
 
-static struct hda_verb ad1984a_precision_verbs[] = {
+static const struct hda_verb ad1984a_precision_verbs[] = {
 	/* Unmute main output path */
 	/* Unmute main output path */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */
@@ -4288,7 +4289,7 @@ static struct hda_verb ad1984a_precision_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1984a_precision_mixers[] = {
+static const struct snd_kcontrol_new ad1984a_precision_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
@@ -4344,7 +4345,7 @@ static int ad1984a_precision_init(struct hda_codec *codec)
  * digital-mic (0x17) - Internal mic
  * digital-mic (0x17) - Internal mic
  */
  */
 
 
-static struct hda_verb ad1984a_touchsmart_verbs[] = {
+static const struct hda_verb ad1984a_touchsmart_verbs[] = {
 	/* DACs; unmute as default */
 	/* DACs; unmute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
@@ -4396,7 +4397,7 @@ static struct hda_verb ad1984a_touchsmart_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
+static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
 /*	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
 /*	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
 	{
 	{
@@ -4475,7 +4476,7 @@ static const char * const ad1884a_models[AD1884A_MODELS] = {
 	[AD1984A_PRECISION]	= "precision",
 	[AD1984A_PRECISION]	= "precision",
 };
 };
 
 
-static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
+static const struct snd_pci_quirk ad1884a_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
 	SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
 	SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
 	SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
 	SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
 	SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
@@ -4614,22 +4615,22 @@ static int patch_ad1884a(struct hda_codec *codec)
  * port-G - rear clfe-out (6stack)
  * port-G - rear clfe-out (6stack)
  */
  */
 
 
-static hda_nid_t ad1882_dac_nids[3] = {
+static const hda_nid_t ad1882_dac_nids[3] = {
 	0x04, 0x03, 0x05
 	0x04, 0x03, 0x05
 };
 };
 
 
-static hda_nid_t ad1882_adc_nids[2] = {
+static const hda_nid_t ad1882_adc_nids[2] = {
 	0x08, 0x09,
 	0x08, 0x09,
 };
 };
 
 
-static hda_nid_t ad1882_capsrc_nids[2] = {
+static const hda_nid_t ad1882_capsrc_nids[2] = {
 	0x0c, 0x0d,
 	0x0c, 0x0d,
 };
 };
 
 
 #define AD1882_SPDIF_OUT	0x02
 #define AD1882_SPDIF_OUT	0x02
 
 
 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
-static struct hda_input_mux ad1882_capture_source = {
+static const struct hda_input_mux ad1882_capture_source = {
 	.num_items = 5,
 	.num_items = 5,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x1 },
 		{ "Front Mic", 0x1 },
@@ -4641,7 +4642,7 @@ static struct hda_input_mux ad1882_capture_source = {
 };
 };
 
 
 /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
 /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
-static struct hda_input_mux ad1882a_capture_source = {
+static const struct hda_input_mux ad1882a_capture_source = {
 	.num_items = 5,
 	.num_items = 5,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x1 },
 		{ "Front Mic", 0x1 },
@@ -4652,7 +4653,7 @@ static struct hda_input_mux ad1882a_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new ad1882_base_mixers[] = {
+static const struct snd_kcontrol_new ad1882_base_mixers[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
@@ -4694,7 +4695,7 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
+static const struct snd_kcontrol_new ad1882_loopback_mixers[] = {
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
@@ -4706,7 +4707,7 @@ static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
+static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
@@ -4719,7 +4720,7 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
+static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
@@ -4733,14 +4734,14 @@ static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
+static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb ad1882_ch2_init[] = {
+static const struct hda_verb ad1882_ch2_init[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -4750,7 +4751,7 @@ static struct hda_verb ad1882_ch2_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb ad1882_ch4_init[] = {
+static const struct hda_verb ad1882_ch4_init[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -4760,7 +4761,7 @@ static struct hda_verb ad1882_ch4_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb ad1882_ch6_init[] = {
+static const struct hda_verb ad1882_ch6_init[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -4770,7 +4771,7 @@ static struct hda_verb ad1882_ch6_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode ad1882_modes[3] = {
+static const struct hda_channel_mode ad1882_modes[3] = {
 	{ 2, ad1882_ch2_init },
 	{ 2, ad1882_ch2_init },
 	{ 4, ad1882_ch4_init },
 	{ 4, ad1882_ch4_init },
 	{ 6, ad1882_ch6_init },
 	{ 6, ad1882_ch6_init },
@@ -4779,7 +4780,7 @@ static struct hda_channel_mode ad1882_modes[3] = {
 /*
 /*
  * initialization verbs
  * initialization verbs
  */
  */
-static struct hda_verb ad1882_init_verbs[] = {
+static const struct hda_verb ad1882_init_verbs[] = {
 	/* DACs; mute as default */
 	/* DACs; mute as default */
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -4848,7 +4849,7 @@ static struct hda_verb ad1882_init_verbs[] = {
 };
 };
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list ad1882_loopbacks[] = {
+static const struct hda_amp_list ad1882_loopbacks[] = {
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
 	{ 0x20, HDA_INPUT, 1 }, /* Mic */
 	{ 0x20, HDA_INPUT, 4 }, /* Line */
 	{ 0x20, HDA_INPUT, 4 }, /* Line */
@@ -4945,7 +4946,7 @@ static int patch_ad1882(struct hda_codec *codec)
 /*
 /*
  * patch entries
  * patch entries
  */
  */
-static struct hda_codec_preset snd_hda_preset_analog[] = {
+static const struct hda_codec_preset snd_hda_preset_analog[] = {
 	{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
 	{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
 	{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
 	{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
 	{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
 	{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },

+ 8 - 8
sound/pci/hda/patch_ca0110.c

@@ -134,7 +134,7 @@ static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 /*
 /*
  */
  */
 
 
-static char *dirstr[2] = { "Playback", "Capture" };
+static const char * const dirstr[2] = { "Playback", "Capture" };
 
 
 static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
 static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
 		       int chan, int dir)
 		       int chan, int dir)
@@ -171,7 +171,7 @@ static int ca0110_build_controls(struct hda_codec *codec)
 {
 {
 	struct ca0110_spec *spec = codec->spec;
 	struct ca0110_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	static char *prefix[AUTO_CFG_MAX_OUTS] = {
+	static const char * const prefix[AUTO_CFG_MAX_OUTS] = {
 		"Front", "Surround", NULL, "Side", "Multi"
 		"Front", "Surround", NULL, "Side", "Multi"
 	};
 	};
 	hda_nid_t mutenid;
 	hda_nid_t mutenid;
@@ -259,7 +259,7 @@ static int ca0110_build_controls(struct hda_codec *codec)
 
 
 /*
 /*
  */
  */
-static struct hda_pcm_stream ca0110_pcm_analog_playback = {
+static const struct hda_pcm_stream ca0110_pcm_analog_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.channels_max = 8,
@@ -270,7 +270,7 @@ static struct hda_pcm_stream ca0110_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream ca0110_pcm_analog_capture = {
+static const struct hda_pcm_stream ca0110_pcm_analog_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -280,7 +280,7 @@ static struct hda_pcm_stream ca0110_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream ca0110_pcm_digital_playback = {
+static const struct hda_pcm_stream ca0110_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -291,7 +291,7 @@ static struct hda_pcm_stream ca0110_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream ca0110_pcm_digital_capture = {
+static const struct hda_pcm_stream ca0110_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -389,7 +389,7 @@ static void ca0110_free(struct hda_codec *codec)
 	kfree(codec->spec);
 	kfree(codec->spec);
 }
 }
 
 
-static struct hda_codec_ops ca0110_patch_ops = {
+static const struct hda_codec_ops ca0110_patch_ops = {
 	.build_controls = ca0110_build_controls,
 	.build_controls = ca0110_build_controls,
 	.build_pcms = ca0110_build_pcms,
 	.build_pcms = ca0110_build_pcms,
 	.init = ca0110_init,
 	.init = ca0110_init,
@@ -539,7 +539,7 @@ static int patch_ca0110(struct hda_codec *codec)
 /*
 /*
  * patch entries
  * patch entries
  */
  */
-static struct hda_codec_preset snd_hda_preset_ca0110[] = {
+static const struct hda_codec_preset snd_hda_preset_ca0110[] = {
 	{ .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 },
 	{ .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 },
 	{ .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 },
 	{ .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 },
 	{ .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 },
 	{ .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 },

+ 25 - 27
sound/pci/hda/patch_cirrus.c

@@ -51,7 +51,7 @@ struct cs_spec {
 	unsigned int cur_adc_format;
 	unsigned int cur_adc_format;
 	hda_nid_t dig_in;
 	hda_nid_t dig_in;
 
 
-	struct hda_bind_ctls *capture_bind[2];
+	const struct hda_bind_ctls *capture_bind[2];
 
 
 	unsigned int gpio_mask;
 	unsigned int gpio_mask;
 	unsigned int gpio_dir;
 	unsigned int gpio_dir;
@@ -231,7 +231,7 @@ static int cs_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 
 
 /*
 /*
  */
  */
-static struct hda_pcm_stream cs_pcm_analog_playback = {
+static const struct hda_pcm_stream cs_pcm_analog_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -242,7 +242,7 @@ static struct hda_pcm_stream cs_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream cs_pcm_analog_capture = {
+static const struct hda_pcm_stream cs_pcm_analog_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -252,7 +252,7 @@ static struct hda_pcm_stream cs_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream cs_pcm_digital_playback = {
+static const struct hda_pcm_stream cs_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -264,7 +264,7 @@ static struct hda_pcm_stream cs_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream cs_pcm_digital_capture = {
+static const struct hda_pcm_stream cs_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -331,8 +331,8 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
 	struct cs_spec *spec = codec->spec;
 	struct cs_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	hda_nid_t pin = cfg->inputs[idx].pin;
 	hda_nid_t pin = cfg->inputs[idx].pin;
-	unsigned int val = snd_hda_query_pin_caps(codec, pin);
-	if (!(val & AC_PINCAP_PRES_DETECT))
+	unsigned int val;
+	if (!is_jack_detectable(codec, pin))
 		return 0;
 		return 0;
 	val = snd_hda_codec_get_pincfg(codec, pin);
 	val = snd_hda_codec_get_pincfg(codec, pin);
 	return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT);
 	return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT);
@@ -349,8 +349,7 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
 		hda_nid_t pins[2];
 		hda_nid_t pins[2];
 		unsigned int type;
 		unsigned int type;
 		int j, nums;
 		int j, nums;
-		type = (get_wcaps(codec, nid) & AC_WCAP_TYPE)
-			>> AC_WCAP_TYPE_SHIFT;
+		type = get_wcaps_type(get_wcaps(codec, nid));
 		if (type != AC_WID_AUD_IN)
 		if (type != AC_WID_AUD_IN)
 			continue;
 			continue;
 		nums = snd_hda_get_connections(codec, nid, pins,
 		nums = snd_hda_get_connections(codec, nid, pins,
@@ -559,10 +558,10 @@ static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx,
 	const char *name;
 	const char *name;
 	int err, index;
 	int err, index;
 	struct snd_kcontrol *kctl;
 	struct snd_kcontrol *kctl;
-	static char *speakers[] = {
+	static const char * const speakers[] = {
 		"Front Speaker", "Surround Speaker", "Bass Speaker"
 		"Front Speaker", "Surround Speaker", "Bass Speaker"
 	};
 	};
-	static char *line_outs[] = {
+	static const char * const line_outs[] = {
 		"Front Line-Out", "Surround Line-Out", "Bass Line-Out"
 		"Front Line-Out", "Surround Line-Out", "Bass Line-Out"
 	};
 	};
 
 
@@ -642,7 +641,7 @@ static int build_output(struct hda_codec *codec)
 /*
 /*
  */
  */
 
 
-static struct snd_kcontrol_new cs_capture_ctls[] = {
+static const struct snd_kcontrol_new cs_capture_ctls[] = {
 	HDA_BIND_SW("Capture Switch", 0),
 	HDA_BIND_SW("Capture Switch", 0),
 	HDA_BIND_VOL("Capture Volume", 0),
 	HDA_BIND_VOL("Capture Volume", 0),
 };
 };
@@ -710,7 +709,7 @@ static int cs_capture_source_put(struct snd_kcontrol *kcontrol,
 	return change_cur_input(codec, idx, 0);
 	return change_cur_input(codec, idx, 0);
 }
 }
 
 
-static struct snd_kcontrol_new cs_capture_source = {
+static const struct snd_kcontrol_new cs_capture_source = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Capture Source",
 	.name = "Capture Source",
 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -719,7 +718,7 @@ static struct snd_kcontrol_new cs_capture_source = {
 	.put = cs_capture_source_put,
 	.put = cs_capture_source_put,
 };
 };
 
 
-static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
+static const struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
 					       struct hda_ctl_ops *ops)
 					       struct hda_ctl_ops *ops)
 {
 {
 	struct cs_spec *spec = codec->spec;
 	struct cs_spec *spec = codec->spec;
@@ -847,15 +846,14 @@ static void cs_automute(struct hda_codec *codec)
 {
 {
 	struct cs_spec *spec = codec->spec;
 	struct cs_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	unsigned int caps, hp_present;
+	unsigned int hp_present;
 	hda_nid_t nid;
 	hda_nid_t nid;
 	int i;
 	int i;
 
 
 	hp_present = 0;
 	hp_present = 0;
 	for (i = 0; i < cfg->hp_outs; i++) {
 	for (i = 0; i < cfg->hp_outs; i++) {
 		nid = cfg->hp_pins[i];
 		nid = cfg->hp_pins[i];
-		caps = snd_hda_query_pin_caps(codec, nid);
-		if (!(caps & AC_PINCAP_PRES_DETECT))
+		if (!is_jack_detectable(codec, nid))
 			continue;
 			continue;
 		hp_present = snd_hda_jack_detect(codec, nid);
 		hp_present = snd_hda_jack_detect(codec, nid);
 		if (hp_present)
 		if (hp_present)
@@ -924,7 +922,7 @@ static void init_output(struct hda_codec *codec)
 				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
 				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
 		if (!cfg->speaker_outs)
 		if (!cfg->speaker_outs)
 			continue;
 			continue;
-		if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
+		if (is_jack_detectable(codec, nid)) {
 			snd_hda_codec_write(codec, nid, 0,
 			snd_hda_codec_write(codec, nid, 0,
 					    AC_VERB_SET_UNSOLICITED_ENABLE,
 					    AC_VERB_SET_UNSOLICITED_ENABLE,
 					    AC_USRSP_EN | HP_EVENT);
 					    AC_USRSP_EN | HP_EVENT);
@@ -983,7 +981,7 @@ static void init_input(struct hda_codec *codec)
 	cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
 	cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
 }
 }
 
 
-static struct hda_verb cs_coef_init_verbs[] = {
+static const struct hda_verb cs_coef_init_verbs[] = {
 	{0x11, AC_VERB_SET_PROC_STATE, 1},
 	{0x11, AC_VERB_SET_PROC_STATE, 1},
 	{0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
 	{0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
 	{0x11, AC_VERB_SET_PROC_COEF,
 	{0x11, AC_VERB_SET_PROC_COEF,
@@ -1017,7 +1015,7 @@ static struct hda_verb cs_coef_init_verbs[] = {
  * blocks, which will alleviate the issue.
  * blocks, which will alleviate the issue.
  */
  */
 
 
-static struct hda_verb cs_errata_init_verbs[] = {
+static const struct hda_verb cs_errata_init_verbs[] = {
 	{0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
 	{0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
 	{0x11, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
 	{0x11, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
 
 
@@ -1126,7 +1124,7 @@ static void cs_unsol_event(struct hda_codec *codec, unsigned int res)
 	}
 	}
 }
 }
 
 
-static struct hda_codec_ops cs_patch_ops = {
+static const struct hda_codec_ops cs_patch_ops = {
 	.build_controls = cs_build_controls,
 	.build_controls = cs_build_controls,
 	.build_pcms = cs_build_pcms,
 	.build_pcms = cs_build_pcms,
 	.init = cs_init,
 	.init = cs_init,
@@ -1166,7 +1164,7 @@ static const char * const cs420x_models[CS420X_MODELS] = {
 };
 };
 
 
 
 
-static struct snd_pci_quirk cs420x_cfg_tbl[] = {
+static const struct snd_pci_quirk cs420x_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
 	SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
 	SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
 	SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
 	SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
 	SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
@@ -1180,7 +1178,7 @@ struct cs_pincfg {
 	u32 val;
 	u32 val;
 };
 };
 
 
-static struct cs_pincfg mbp53_pincfgs[] = {
+static const struct cs_pincfg mbp53_pincfgs[] = {
 	{ 0x09, 0x012b4050 },
 	{ 0x09, 0x012b4050 },
 	{ 0x0a, 0x90100141 },
 	{ 0x0a, 0x90100141 },
 	{ 0x0b, 0x90100140 },
 	{ 0x0b, 0x90100140 },
@@ -1194,7 +1192,7 @@ static struct cs_pincfg mbp53_pincfgs[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static struct cs_pincfg mbp55_pincfgs[] = {
+static const struct cs_pincfg mbp55_pincfgs[] = {
 	{ 0x09, 0x012b4030 },
 	{ 0x09, 0x012b4030 },
 	{ 0x0a, 0x90100121 },
 	{ 0x0a, 0x90100121 },
 	{ 0x0b, 0x90100120 },
 	{ 0x0b, 0x90100120 },
@@ -1208,7 +1206,7 @@ static struct cs_pincfg mbp55_pincfgs[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static struct cs_pincfg imac27_pincfgs[] = {
+static const struct cs_pincfg imac27_pincfgs[] = {
 	{ 0x09, 0x012b4050 },
 	{ 0x09, 0x012b4050 },
 	{ 0x0a, 0x90100140 },
 	{ 0x0a, 0x90100140 },
 	{ 0x0b, 0x90100142 },
 	{ 0x0b, 0x90100142 },
@@ -1222,7 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
+static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
 	[CS420X_MBP53] = mbp53_pincfgs,
 	[CS420X_MBP53] = mbp53_pincfgs,
 	[CS420X_MBP55] = mbp55_pincfgs,
 	[CS420X_MBP55] = mbp55_pincfgs,
 	[CS420X_IMAC27] = imac27_pincfgs,
 	[CS420X_IMAC27] = imac27_pincfgs,
@@ -1283,7 +1281,7 @@ static int patch_cs420x(struct hda_codec *codec)
 /*
 /*
  * patch entries
  * patch entries
  */
  */
-static struct hda_codec_preset snd_hda_preset_cirrus[] = {
+static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
 	{ .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
 	{ .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
 	{ .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
 	{ .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
 	{} /* terminator */
 	{} /* terminator */

+ 20 - 20
sound/pci/hda/patch_cmedia.c

@@ -53,7 +53,7 @@ struct cmi_spec {
 	int num_dacs;
 	int num_dacs;
 
 
 	/* capture */
 	/* capture */
-	hda_nid_t *adc_nids;
+	const hda_nid_t *adc_nids;
 	hda_nid_t dig_in_nid;
 	hda_nid_t dig_in_nid;
 
 
 	/* capture source */
 	/* capture source */
@@ -110,7 +110,7 @@ static int cmi_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
  */
  */
 
 
 /* 3-stack / 2 channel */
 /* 3-stack / 2 channel */
-static struct hda_verb cmi9880_ch2_init[] = {
+static const struct hda_verb cmi9880_ch2_init[] = {
 	/* set line-in PIN for input */
 	/* set line-in PIN for input */
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	/* set mic PIN for input, also enable vref */
 	/* set mic PIN for input, also enable vref */
@@ -121,7 +121,7 @@ static struct hda_verb cmi9880_ch2_init[] = {
 };
 };
 
 
 /* 3-stack / 6 channel */
 /* 3-stack / 6 channel */
-static struct hda_verb cmi9880_ch6_init[] = {
+static const struct hda_verb cmi9880_ch6_init[] = {
 	/* set line-in PIN for output */
 	/* set line-in PIN for output */
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	/* set mic PIN for output */
 	/* set mic PIN for output */
@@ -132,7 +132,7 @@ static struct hda_verb cmi9880_ch6_init[] = {
 };
 };
 
 
 /* 3-stack+front / 8 channel */
 /* 3-stack+front / 8 channel */
-static struct hda_verb cmi9880_ch8_init[] = {
+static const struct hda_verb cmi9880_ch8_init[] = {
 	/* set line-in PIN for output */
 	/* set line-in PIN for output */
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	/* set mic PIN for output */
 	/* set mic PIN for output */
@@ -142,7 +142,7 @@ static struct hda_verb cmi9880_ch8_init[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_channel_mode cmi9880_channel_modes[3] = {
+static const struct hda_channel_mode cmi9880_channel_modes[3] = {
 	{ 2, cmi9880_ch2_init },
 	{ 2, cmi9880_ch2_init },
 	{ 6, cmi9880_ch6_init },
 	{ 6, cmi9880_ch6_init },
 	{ 8, cmi9880_ch8_init },
 	{ 8, cmi9880_ch8_init },
@@ -174,7 +174,7 @@ static int cmi_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
 
 
 /*
 /*
  */
  */
-static struct snd_kcontrol_new cmi9880_basic_mixer[] = {
+static const struct snd_kcontrol_new cmi9880_basic_mixer[] = {
 	/* CMI9880 has no playback volumes! */
 	/* CMI9880 has no playback volumes! */
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT),
@@ -205,7 +205,7 @@ static struct snd_kcontrol_new cmi9880_basic_mixer[] = {
 /*
 /*
  * shared I/O pins
  * shared I/O pins
  */
  */
-static struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = {
+static const struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
 		.name = "Channel Mode",
@@ -219,7 +219,7 @@ static struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = {
 /* AUD-in selections:
 /* AUD-in selections:
  * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20
  * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20
  */
  */
-static struct hda_input_mux cmi9880_basic_mux = {
+static const struct hda_input_mux cmi9880_basic_mux = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x5 },
 		{ "Front Mic", 0x5 },
@@ -229,7 +229,7 @@ static struct hda_input_mux cmi9880_basic_mux = {
 	}
 	}
 };
 };
 
 
-static struct hda_input_mux cmi9880_no_line_mux = {
+static const struct hda_input_mux cmi9880_no_line_mux = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x5 },
 		{ "Front Mic", 0x5 },
@@ -239,11 +239,11 @@ static struct hda_input_mux cmi9880_no_line_mux = {
 };
 };
 
 
 /* front, rear, clfe, rear_surr */
 /* front, rear, clfe, rear_surr */
-static hda_nid_t cmi9880_dac_nids[4] = {
+static const hda_nid_t cmi9880_dac_nids[4] = {
 	0x03, 0x04, 0x05, 0x06
 	0x03, 0x04, 0x05, 0x06
 };
 };
 /* ADC0, ADC1 */
 /* ADC0, ADC1 */
-static hda_nid_t cmi9880_adc_nids[2] = {
+static const hda_nid_t cmi9880_adc_nids[2] = {
 	0x08, 0x09
 	0x08, 0x09
 };
 };
 
 
@@ -252,7 +252,7 @@ static hda_nid_t cmi9880_adc_nids[2] = {
 
 
 /*
 /*
  */
  */
-static struct hda_verb cmi9880_basic_init[] = {
+static const struct hda_verb cmi9880_basic_init[] = {
 	/* port-D for line out (rear panel) */
 	/* port-D for line out (rear panel) */
 	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	/* port-E for HP out (front panel) */
 	/* port-E for HP out (front panel) */
@@ -281,7 +281,7 @@ static struct hda_verb cmi9880_basic_init[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static struct hda_verb cmi9880_allout_init[] = {
+static const struct hda_verb cmi9880_allout_init[] = {
 	/* port-D for line out (rear panel) */
 	/* port-D for line out (rear panel) */
 	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	/* port-E for HP out (front panel) */
 	/* port-E for HP out (front panel) */
@@ -528,7 +528,7 @@ static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 
 
 /*
 /*
  */
  */
-static struct hda_pcm_stream cmi9880_pcm_analog_playback = {
+static const struct hda_pcm_stream cmi9880_pcm_analog_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.channels_max = 8,
@@ -540,7 +540,7 @@ static struct hda_pcm_stream cmi9880_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream cmi9880_pcm_analog_capture = {
+static const struct hda_pcm_stream cmi9880_pcm_analog_capture = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -551,7 +551,7 @@ static struct hda_pcm_stream cmi9880_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream cmi9880_pcm_digital_playback = {
+static const struct hda_pcm_stream cmi9880_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -563,7 +563,7 @@ static struct hda_pcm_stream cmi9880_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream cmi9880_pcm_digital_capture = {
+static const struct hda_pcm_stream cmi9880_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -617,14 +617,14 @@ static const char * const cmi9880_models[CMI_MODELS] = {
 	[CMI_AUTO]	= "auto",
 	[CMI_AUTO]	= "auto",
 };
 };
 
 
-static struct snd_pci_quirk cmi9880_cfg_tbl[] = {
+static const struct snd_pci_quirk cmi9880_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG),
 	SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", CMI_FULL_DIG),
 	SND_PCI_QUIRK(0x1854, 0x002b, "LG LS75", CMI_MINIMAL),
 	SND_PCI_QUIRK(0x1854, 0x002b, "LG LS75", CMI_MINIMAL),
 	SND_PCI_QUIRK(0x1854, 0x0032, "LG", CMI_FULL_DIG),
 	SND_PCI_QUIRK(0x1854, 0x0032, "LG", CMI_FULL_DIG),
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static struct hda_codec_ops cmi9880_patch_ops = {
+static const struct hda_codec_ops cmi9880_patch_ops = {
 	.build_controls = cmi9880_build_controls,
 	.build_controls = cmi9880_build_controls,
 	.build_pcms = cmi9880_build_pcms,
 	.build_pcms = cmi9880_build_pcms,
 	.init = cmi9880_init,
 	.init = cmi9880_init,
@@ -745,7 +745,7 @@ static int patch_cmi9880(struct hda_codec *codec)
 /*
 /*
  * patch entries
  * patch entries
  */
  */
-static struct hda_codec_preset snd_hda_preset_cmedia[] = {
+static const struct hda_codec_preset snd_hda_preset_cmedia[] = {
 	{ .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
 	{ .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
  	{ .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
  	{ .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
 	{} /* terminator */
 	{} /* terminator */

+ 808 - 277
sound/pci/hda/patch_conexant.c

@@ -39,6 +39,7 @@
 
 
 #define CONEXANT_HP_EVENT	0x37
 #define CONEXANT_HP_EVENT	0x37
 #define CONEXANT_MIC_EVENT	0x38
 #define CONEXANT_MIC_EVENT	0x38
+#define CONEXANT_LINE_EVENT	0x39
 
 
 /* Conexant 5051 specific */
 /* Conexant 5051 specific */
 
 
@@ -55,9 +56,16 @@ struct pin_dac_pair {
 	int type;
 	int type;
 };
 };
 
 
+struct imux_info {
+	hda_nid_t pin;		/* input pin NID */
+	hda_nid_t adc;		/* connected ADC NID */	
+	hda_nid_t boost;	/* optional boost volume NID */
+	int index;		/* corresponding to autocfg.input */
+};
+
 struct conexant_spec {
 struct conexant_spec {
 
 
-	struct snd_kcontrol_new *mixers[5];
+	const struct snd_kcontrol_new *mixers[5];
 	int num_mixers;
 	int num_mixers;
 	hda_nid_t vmaster_nid;
 	hda_nid_t vmaster_nid;
 
 
@@ -74,14 +82,17 @@ struct conexant_spec {
 					 */
 					 */
 	unsigned int cur_eapd;
 	unsigned int cur_eapd;
 	unsigned int hp_present;
 	unsigned int hp_present;
+	unsigned int line_present;
 	unsigned int auto_mic;
 	unsigned int auto_mic;
-	int auto_mic_ext;		/* autocfg.inputs[] index for ext mic */
+	int auto_mic_ext;		/* imux_pins[] index for ext mic */
+	int auto_mic_dock;		/* imux_pins[] index for dock mic */
+	int auto_mic_int;		/* imux_pins[] index for int mic */
 	unsigned int need_dac_fix;
 	unsigned int need_dac_fix;
 	hda_nid_t slave_dig_outs[2];
 	hda_nid_t slave_dig_outs[2];
 
 
 	/* capture */
 	/* capture */
 	unsigned int num_adc_nids;
 	unsigned int num_adc_nids;
-	hda_nid_t *adc_nids;
+	const hda_nid_t *adc_nids;
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 
 
 	unsigned int cur_adc_idx;
 	unsigned int cur_adc_idx;
@@ -89,9 +100,11 @@ struct conexant_spec {
 	unsigned int cur_adc_stream_tag;
 	unsigned int cur_adc_stream_tag;
 	unsigned int cur_adc_format;
 	unsigned int cur_adc_format;
 
 
+	const struct hda_pcm_stream *capture_stream;
+
 	/* capture source */
 	/* capture source */
 	const struct hda_input_mux *input_mux;
 	const struct hda_input_mux *input_mux;
-	hda_nid_t *capsrc_nids;
+	const hda_nid_t *capsrc_nids;
 	unsigned int cur_mux[3];
 	unsigned int cur_mux[3];
 
 
 	/* channel model */
 	/* channel model */
@@ -106,12 +119,17 @@ struct conexant_spec {
 	/* dynamic controls, init_verbs and input_mux */
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
 	struct auto_pin_cfg autocfg;
 	struct hda_input_mux private_imux;
 	struct hda_input_mux private_imux;
+	struct imux_info imux_info[HDA_MAX_NUM_INPUTS];
+	hda_nid_t private_adc_nids[HDA_MAX_NUM_INPUTS];
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 	struct pin_dac_pair dac_info[8];
 	struct pin_dac_pair dac_info[8];
 	int dac_info_filled;
 	int dac_info_filled;
 
 
 	unsigned int port_d_mode;
 	unsigned int port_d_mode;
 	unsigned int auto_mute:1;	/* used in auto-parser */
 	unsigned int auto_mute:1;	/* used in auto-parser */
+	unsigned int detect_line:1;	/* Line-out detection enabled */
+	unsigned int automute_lines:1;	/* automute line-out as well */
+	unsigned int automute_hp_lo:1;	/* both HP and LO available */
 	unsigned int dell_automute:1;
 	unsigned int dell_automute:1;
 	unsigned int dell_vostro:1;
 	unsigned int dell_vostro:1;
 	unsigned int ideapad:1;
 	unsigned int ideapad:1;
@@ -119,6 +137,8 @@ struct conexant_spec {
 	unsigned int hp_laptop:1;
 	unsigned int hp_laptop:1;
 	unsigned int asus:1;
 	unsigned int asus:1;
 
 
+	unsigned int adc_switching:1;
+
 	unsigned int ext_mic_present;
 	unsigned int ext_mic_present;
 	unsigned int recording;
 	unsigned int recording;
 	void (*capture_prepare)(struct hda_codec *codec);
 	void (*capture_prepare)(struct hda_codec *codec);
@@ -227,7 +247,7 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 
 
 
 
 
 
-static struct hda_pcm_stream conexant_pcm_analog_playback = {
+static const struct hda_pcm_stream conexant_pcm_analog_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -239,7 +259,7 @@ static struct hda_pcm_stream conexant_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream conexant_pcm_analog_capture = {
+static const struct hda_pcm_stream conexant_pcm_analog_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -251,7 +271,7 @@ static struct hda_pcm_stream conexant_pcm_analog_capture = {
 };
 };
 
 
 
 
-static struct hda_pcm_stream conexant_pcm_digital_playback = {
+static const struct hda_pcm_stream conexant_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -263,7 +283,7 @@ static struct hda_pcm_stream conexant_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream conexant_pcm_digital_capture = {
+static const struct hda_pcm_stream conexant_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -294,7 +314,7 @@ static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 	return 0;
 }
 }
 
 
-static struct hda_pcm_stream cx5051_pcm_analog_capture = {
+static const struct hda_pcm_stream cx5051_pcm_analog_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -319,13 +339,19 @@ static int conexant_build_pcms(struct hda_codec *codec)
 		spec->multiout.max_channels;
 		spec->multiout.max_channels;
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
 		spec->multiout.dac_nids[0];
 		spec->multiout.dac_nids[0];
-	if (codec->vendor_id == 0x14f15051)
-		info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-			cx5051_pcm_analog_capture;
-	else
-		info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-			conexant_pcm_analog_capture;
-	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
+	if (spec->capture_stream)
+		info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream;
+	else {
+		if (codec->vendor_id == 0x14f15051)
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+				cx5051_pcm_analog_capture;
+		else {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+				conexant_pcm_analog_capture;
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
+				spec->num_adc_nids;
+		}
+	}
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
 
 
 	if (spec->multiout.dig_out_nid) {
 	if (spec->multiout.dig_out_nid) {
@@ -433,7 +459,7 @@ static void conexant_free(struct hda_codec *codec)
 	kfree(codec->spec);
 	kfree(codec->spec);
 }
 }
 
 
-static struct snd_kcontrol_new cxt_capture_mixers[] = {
+static const struct snd_kcontrol_new cxt_capture_mixers[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Capture Source",
 		.name = "Capture Source",
@@ -446,7 +472,7 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = {
 
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
 /* additional beep mixers; the actual parameters are overwritten at build */
-static struct snd_kcontrol_new cxt_beep_mixer[] = {
+static const struct snd_kcontrol_new cxt_beep_mixer[] = {
 	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
 	{ } /* end */
 	{ } /* end */
@@ -456,12 +482,18 @@ static struct snd_kcontrol_new cxt_beep_mixer[] = {
 static const char * const slave_vols[] = {
 static const char * const slave_vols[] = {
 	"Headphone Playback Volume",
 	"Headphone Playback Volume",
 	"Speaker Playback Volume",
 	"Speaker Playback Volume",
+	"Front Playback Volume",
+	"Surround Playback Volume",
+	"CLFE Playback Volume",
 	NULL
 	NULL
 };
 };
 
 
 static const char * const slave_sws[] = {
 static const char * const slave_sws[] = {
 	"Headphone Playback Switch",
 	"Headphone Playback Switch",
 	"Speaker Playback Switch",
 	"Speaker Playback Switch",
+	"Front Playback Switch",
+	"Surround Playback Switch",
+	"CLFE Playback Switch",
 	NULL
 	NULL
 };
 };
 
 
@@ -521,7 +553,7 @@ static int conexant_build_controls(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 	/* create beep controls if needed */
 	/* create beep controls if needed */
 	if (spec->beep_amp) {
 	if (spec->beep_amp) {
-		struct snd_kcontrol_new *knew;
+		const struct snd_kcontrol_new *knew;
 		for (knew = cxt_beep_mixer; knew->name; knew++) {
 		for (knew = cxt_beep_mixer; knew->name; knew++) {
 			struct snd_kcontrol *kctl;
 			struct snd_kcontrol *kctl;
 			kctl = snd_ctl_new1(knew, codec);
 			kctl = snd_ctl_new1(knew, codec);
@@ -546,7 +578,7 @@ static int conexant_suspend(struct hda_codec *codec, pm_message_t state)
 }
 }
 #endif
 #endif
 
 
-static struct hda_codec_ops conexant_patch_ops = {
+static const struct hda_codec_ops conexant_patch_ops = {
 	.build_controls = conexant_build_controls,
 	.build_controls = conexant_build_controls,
 	.build_pcms = conexant_build_pcms,
 	.build_pcms = conexant_build_pcms,
 	.init = conexant_init,
 	.init = conexant_init,
@@ -564,6 +596,7 @@ static struct hda_codec_ops conexant_patch_ops = {
 #define set_beep_amp(spec, nid, idx, dir) /* NOP */
 #define set_beep_amp(spec, nid, idx, dir) /* NOP */
 #endif
 #endif
 
 
+static int patch_conexant_auto(struct hda_codec *codec);
 /*
 /*
  * EAPD control
  * EAPD control
  * the private value = nid | (invert << 8)
  * the private value = nid | (invert << 8)
@@ -662,16 +695,16 @@ static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol,
 
 
 /* Conexant 5045 specific */
 /* Conexant 5045 specific */
 
 
-static hda_nid_t cxt5045_dac_nids[1] = { 0x19 };
-static hda_nid_t cxt5045_adc_nids[1] = { 0x1a };
-static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a };
+static const hda_nid_t cxt5045_dac_nids[1] = { 0x19 };
+static const hda_nid_t cxt5045_adc_nids[1] = { 0x1a };
+static const hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a };
 #define CXT5045_SPDIF_OUT	0x18
 #define CXT5045_SPDIF_OUT	0x18
 
 
-static struct hda_channel_mode cxt5045_modes[1] = {
+static const struct hda_channel_mode cxt5045_modes[1] = {
 	{ 2, NULL },
 	{ 2, NULL },
 };
 };
 
 
-static struct hda_input_mux cxt5045_capture_source = {
+static const struct hda_input_mux cxt5045_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "IntMic", 0x1 },
 		{ "IntMic", 0x1 },
@@ -679,7 +712,7 @@ static struct hda_input_mux cxt5045_capture_source = {
 	}
 	}
 };
 };
 
 
-static struct hda_input_mux cxt5045_capture_source_benq = {
+static const struct hda_input_mux cxt5045_capture_source_benq = {
 	.num_items = 5,
 	.num_items = 5,
 	.items = {
 	.items = {
 		{ "IntMic", 0x1 },
 		{ "IntMic", 0x1 },
@@ -690,7 +723,7 @@ static struct hda_input_mux cxt5045_capture_source_benq = {
 	}
 	}
 };
 };
 
 
-static struct hda_input_mux cxt5045_capture_source_hp530 = {
+static const struct hda_input_mux cxt5045_capture_source_hp530 = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "ExtMic", 0x1 },
 		{ "ExtMic", 0x1 },
@@ -723,7 +756,7 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 }
 }
 
 
 /* bind volumes of both NID 0x10 and 0x11 */
 /* bind volumes of both NID 0x10 and 0x11 */
-static struct hda_bind_ctls cxt5045_hp_bind_master_vol = {
+static const struct hda_bind_ctls cxt5045_hp_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT),
@@ -735,12 +768,12 @@ static struct hda_bind_ctls cxt5045_hp_bind_master_vol = {
 /* toggle input of built-in and mic jack appropriately */
 /* toggle input of built-in and mic jack appropriately */
 static void cxt5045_hp_automic(struct hda_codec *codec)
 static void cxt5045_hp_automic(struct hda_codec *codec)
 {
 {
-	static struct hda_verb mic_jack_on[] = {
+	static const struct hda_verb mic_jack_on[] = {
 		{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{}
 		{}
 	};
 	};
-	static struct hda_verb mic_jack_off[] = {
+	static const struct hda_verb mic_jack_off[] = {
 		{0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
 		{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
 		{}
 		{}
@@ -784,7 +817,7 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec,
 	}
 	}
 }
 }
 
 
-static struct snd_kcontrol_new cxt5045_mixers[] = {
+static const struct snd_kcontrol_new cxt5045_mixers[] = {
 	HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
@@ -808,7 +841,7 @@ static struct snd_kcontrol_new cxt5045_mixers[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
+static const struct snd_kcontrol_new cxt5045_benq_mixers[] = {
 	HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT),
@@ -825,7 +858,7 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
+static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
 	HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
@@ -849,7 +882,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb cxt5045_init_verbs[] = {
+static const struct hda_verb cxt5045_init_verbs[] = {
 	/* Line in, Mic */
 	/* Line in, Mic */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
@@ -875,7 +908,7 @@ static struct hda_verb cxt5045_init_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5045_benq_init_verbs[] = {
+static const struct hda_verb cxt5045_benq_init_verbs[] = {
 	/* Internal Mic, Mic */
 	/* Internal Mic, Mic */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
@@ -901,13 +934,13 @@ static struct hda_verb cxt5045_benq_init_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5045_hp_sense_init_verbs[] = {
+static const struct hda_verb cxt5045_hp_sense_init_verbs[] = {
 	/* pin sensing on HP jack */
 	/* pin sensing on HP jack */
 	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
 	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5045_mic_sense_init_verbs[] = {
+static const struct hda_verb cxt5045_mic_sense_init_verbs[] = {
 	/* pin sensing on HP jack */
 	/* pin sensing on HP jack */
 	{0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
 	{0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
 	{ } /* end */
 	{ } /* end */
@@ -917,7 +950,7 @@ static struct hda_verb cxt5045_mic_sense_init_verbs[] = {
 /* Test configuration for debugging, modelled after the ALC260 test
 /* Test configuration for debugging, modelled after the ALC260 test
  * configuration.
  * configuration.
  */
  */
-static struct hda_input_mux cxt5045_test_capture_source = {
+static const struct hda_input_mux cxt5045_test_capture_source = {
 	.num_items = 5,
 	.num_items = 5,
 	.items = {
 	.items = {
 		{ "MIXER", 0x0 },
 		{ "MIXER", 0x0 },
@@ -928,7 +961,7 @@ static struct hda_input_mux cxt5045_test_capture_source = {
         },
         },
 };
 };
 
 
-static struct snd_kcontrol_new cxt5045_test_mixer[] = {
+static const struct snd_kcontrol_new cxt5045_test_mixer[] = {
 
 
 	/* Output controls */
 	/* Output controls */
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT),
@@ -978,7 +1011,7 @@ static struct snd_kcontrol_new cxt5045_test_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5045_test_init_verbs[] = {
+static const struct hda_verb cxt5045_test_init_verbs[] = {
 	/* Set connections */
 	/* Set connections */
 	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
 	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
 	{ 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 },
 	{ 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 },
@@ -1047,6 +1080,7 @@ enum {
 #ifdef CONFIG_SND_DEBUG
 #ifdef CONFIG_SND_DEBUG
 	CXT5045_TEST,
 	CXT5045_TEST,
 #endif
 #endif
+	CXT5045_AUTO,
 	CXT5045_MODELS
 	CXT5045_MODELS
 };
 };
 
 
@@ -1059,9 +1093,10 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
 #ifdef CONFIG_SND_DEBUG
 #ifdef CONFIG_SND_DEBUG
 	[CXT5045_TEST]		= "test",
 	[CXT5045_TEST]		= "test",
 #endif
 #endif
+	[CXT5045_AUTO]			= "auto",
 };
 };
 
 
-static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
+static const struct snd_pci_quirk cxt5045_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
 	SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
 			   CXT5045_LAPTOP_HPSENSE),
 			   CXT5045_LAPTOP_HPSENSE),
@@ -1085,6 +1120,16 @@ static int patch_cxt5045(struct hda_codec *codec)
 	struct conexant_spec *spec;
 	struct conexant_spec *spec;
 	int board_config;
 	int board_config;
 
 
+	board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
+						  cxt5045_models,
+						  cxt5045_cfg_tbl);
+#if 0 /* use the old method just for safety */
+	if (board_config < 0)
+		board_config = CXT5045_AUTO;
+#endif
+	if (board_config == CXT5045_AUTO)
+		return patch_conexant_auto(codec);
+
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 	if (!spec)
 		return -ENOMEM;
 		return -ENOMEM;
@@ -1111,9 +1156,6 @@ static int patch_cxt5045(struct hda_codec *codec)
 
 
 	codec->patch_ops = conexant_patch_ops;
 	codec->patch_ops = conexant_patch_ops;
 
 
-	board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
-						  cxt5045_models,
-						  cxt5045_cfg_tbl);
 	switch (board_config) {
 	switch (board_config) {
 	case CXT5045_LAPTOP_HPSENSE:
 	case CXT5045_LAPTOP_HPSENSE:
 		codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
 		codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
@@ -1196,15 +1238,15 @@ static int patch_cxt5045(struct hda_codec *codec)
 /* Conexant 5047 specific */
 /* Conexant 5047 specific */
 #define CXT5047_SPDIF_OUT	0x11
 #define CXT5047_SPDIF_OUT	0x11
 
 
-static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */
-static hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
-static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
+static const hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */
+static const hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
+static const hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
 
 
-static struct hda_channel_mode cxt5047_modes[1] = {
+static const struct hda_channel_mode cxt5047_modes[1] = {
 	{ 2, NULL },
 	{ 2, NULL },
 };
 };
 
 
-static struct hda_input_mux cxt5047_toshiba_capture_source = {
+static const struct hda_input_mux cxt5047_toshiba_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "ExtMic", 0x2 },
 		{ "ExtMic", 0x2 },
@@ -1256,12 +1298,12 @@ static void cxt5047_hp_automute(struct hda_codec *codec)
 /* toggle input of built-in and mic jack appropriately */
 /* toggle input of built-in and mic jack appropriately */
 static void cxt5047_hp_automic(struct hda_codec *codec)
 static void cxt5047_hp_automic(struct hda_codec *codec)
 {
 {
-	static struct hda_verb mic_jack_on[] = {
+	static const struct hda_verb mic_jack_on[] = {
 		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 		{}
 		{}
 	};
 	};
-	static struct hda_verb mic_jack_off[] = {
+	static const struct hda_verb mic_jack_off[] = {
 		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 		{}
 		{}
@@ -1289,7 +1331,7 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec,
 	}
 	}
 }
 }
 
 
-static struct snd_kcontrol_new cxt5047_base_mixers[] = {
+static const struct snd_kcontrol_new cxt5047_base_mixers[] = {
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT),
@@ -1309,19 +1351,19 @@ static struct snd_kcontrol_new cxt5047_base_mixers[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = {
+static const struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = {
 	/* See the note in cxt5047_hp_master_sw_put */
 	/* See the note in cxt5047_hp_master_sw_put */
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT),
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5047_hp_only_mixers[] = {
+static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5047_init_verbs[] = {
+static const struct hda_verb cxt5047_init_verbs[] = {
 	/* Line in, Mic, Built-in Mic */
 	/* Line in, Mic, Built-in Mic */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
@@ -1348,7 +1390,7 @@ static struct hda_verb cxt5047_init_verbs[] = {
 };
 };
 
 
 /* configuration for Toshiba Laptops */
 /* configuration for Toshiba Laptops */
-static struct hda_verb cxt5047_toshiba_init_verbs[] = {
+static const struct hda_verb cxt5047_toshiba_init_verbs[] = {
 	{0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */
 	{0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */
 	{}
 	{}
 };
 };
@@ -1357,7 +1399,7 @@ static struct hda_verb cxt5047_toshiba_init_verbs[] = {
  * configuration.
  * configuration.
  */
  */
 #ifdef CONFIG_SND_DEBUG
 #ifdef CONFIG_SND_DEBUG
-static struct hda_input_mux cxt5047_test_capture_source = {
+static const struct hda_input_mux cxt5047_test_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "LINE1 pin", 0x0 },
 		{ "LINE1 pin", 0x0 },
@@ -1367,7 +1409,7 @@ static struct hda_input_mux cxt5047_test_capture_source = {
         },
         },
 };
 };
 
 
-static struct snd_kcontrol_new cxt5047_test_mixer[] = {
+static const struct snd_kcontrol_new cxt5047_test_mixer[] = {
 
 
 	/* Output only controls */
 	/* Output only controls */
 	HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT),
@@ -1420,7 +1462,7 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5047_test_init_verbs[] = {
+static const struct hda_verb cxt5047_test_init_verbs[] = {
 	/* Enable retasking pins as output, initially without power amp */
 	/* Enable retasking pins as output, initially without power amp */
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -1492,6 +1534,7 @@ enum {
 #ifdef CONFIG_SND_DEBUG
 #ifdef CONFIG_SND_DEBUG
 	CXT5047_TEST,
 	CXT5047_TEST,
 #endif
 #endif
+	CXT5047_AUTO,
 	CXT5047_MODELS
 	CXT5047_MODELS
 };
 };
 
 
@@ -1502,9 +1545,10 @@ static const char * const cxt5047_models[CXT5047_MODELS] = {
 #ifdef CONFIG_SND_DEBUG
 #ifdef CONFIG_SND_DEBUG
 	[CXT5047_TEST]		= "test",
 	[CXT5047_TEST]		= "test",
 #endif
 #endif
+	[CXT5047_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
+static const struct snd_pci_quirk cxt5047_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
 	SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
 			   CXT5047_LAPTOP),
 			   CXT5047_LAPTOP),
@@ -1517,6 +1561,16 @@ static int patch_cxt5047(struct hda_codec *codec)
 	struct conexant_spec *spec;
 	struct conexant_spec *spec;
 	int board_config;
 	int board_config;
 
 
+	board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
+						  cxt5047_models,
+						  cxt5047_cfg_tbl);
+#if 0 /* not enabled as default, as BIOS often broken for this codec */
+	if (board_config < 0)
+		board_config = CXT5047_AUTO;
+#endif
+	if (board_config == CXT5047_AUTO)
+		return patch_conexant_auto(codec);
+
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 	if (!spec)
 		return -ENOMEM;
 		return -ENOMEM;
@@ -1540,9 +1594,6 @@ static int patch_cxt5047(struct hda_codec *codec)
 
 
 	codec->patch_ops = conexant_patch_ops;
 	codec->patch_ops = conexant_patch_ops;
 
 
-	board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
-						  cxt5047_models,
-						  cxt5047_cfg_tbl);
 	switch (board_config) {
 	switch (board_config) {
 	case CXT5047_LAPTOP:
 	case CXT5047_LAPTOP:
 		spec->num_mixers = 2;
 		spec->num_mixers = 2;
@@ -1591,10 +1642,10 @@ static int patch_cxt5047(struct hda_codec *codec)
 }
 }
 
 
 /* Conexant 5051 specific */
 /* Conexant 5051 specific */
-static hda_nid_t cxt5051_dac_nids[1] = { 0x10 };
-static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 };
+static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 };
+static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 };
 
 
-static struct hda_channel_mode cxt5051_modes[1] = {
+static const struct hda_channel_mode cxt5051_modes[1] = {
 	{ 2, NULL },
 	{ 2, NULL },
 };
 };
 
 
@@ -1696,7 +1747,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
 	snd_hda_input_jack_report(codec, nid);
 	snd_hda_input_jack_report(codec, nid);
 }
 }
 
 
-static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_playback_mixers[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1709,7 +1760,7 @@ static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_capture_mixers[] = {
 	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
@@ -1719,7 +1770,7 @@ static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_hp_mixers[] = {
 	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT),
@@ -1727,19 +1778,19 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT),
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5051_f700_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_f700_mixers[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT),
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
+static const struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
 	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
@@ -1747,7 +1798,7 @@ static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb cxt5051_init_verbs[] = {
+static const struct hda_verb cxt5051_init_verbs[] = {
 	/* Line in, Mic */
 	/* Line in, Mic */
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -1776,7 +1827,7 @@ static struct hda_verb cxt5051_init_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
+static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
 	/* Line in, Mic */
 	/* Line in, Mic */
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -1801,7 +1852,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
+static const struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
 	/* Line in, Mic */
 	/* Line in, Mic */
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -1834,7 +1885,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5051_f700_init_verbs[] = {
+static const struct hda_verb cxt5051_f700_init_verbs[] = {
 	/* Line in, Mic */
 	/* Line in, Mic */
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -1869,7 +1920,7 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
 	snd_hda_input_jack_report(codec, nid);
 	snd_hda_input_jack_report(codec, nid);
 }
 }
 
 
-static struct hda_verb cxt5051_ideapad_init_verbs[] = {
+static const struct hda_verb cxt5051_ideapad_init_verbs[] = {
 	/* Subwoofer */
 	/* Subwoofer */
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -1906,6 +1957,7 @@ enum {
 	CXT5051_F700,       /* HP Compaq Presario F700 */
 	CXT5051_F700,       /* HP Compaq Presario F700 */
 	CXT5051_TOSHIBA,	/* Toshiba M300 & co */
 	CXT5051_TOSHIBA,	/* Toshiba M300 & co */
 	CXT5051_IDEAPAD,	/* Lenovo IdeaPad Y430 */
 	CXT5051_IDEAPAD,	/* Lenovo IdeaPad Y430 */
+	CXT5051_AUTO,		/* auto-parser */
 	CXT5051_MODELS
 	CXT5051_MODELS
 };
 };
 
 
@@ -1917,9 +1969,10 @@ static const char *const cxt5051_models[CXT5051_MODELS] = {
 	[CXT5051_F700]          = "hp-700",
 	[CXT5051_F700]          = "hp-700",
 	[CXT5051_TOSHIBA]	= "toshiba",
 	[CXT5051_TOSHIBA]	= "toshiba",
 	[CXT5051_IDEAPAD]	= "ideapad",
 	[CXT5051_IDEAPAD]	= "ideapad",
+	[CXT5051_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
+static const struct snd_pci_quirk cxt5051_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736),
 	SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736),
 	SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP),
 	SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP),
 	SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700),
 	SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700),
@@ -1937,6 +1990,16 @@ static int patch_cxt5051(struct hda_codec *codec)
 	struct conexant_spec *spec;
 	struct conexant_spec *spec;
 	int board_config;
 	int board_config;
 
 
+	board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
+						  cxt5051_models,
+						  cxt5051_cfg_tbl);
+#if 0 /* use the old method just for safety */
+	if (board_config < 0)
+		board_config = CXT5051_AUTO;
+#endif
+	if (board_config == CXT5051_AUTO)
+		return patch_conexant_auto(codec);
+
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 	if (!spec)
 		return -ENOMEM;
 		return -ENOMEM;
@@ -1967,9 +2030,6 @@ static int patch_cxt5051(struct hda_codec *codec)
 
 
 	codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
 	codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
 
 
-	board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
-						  cxt5051_models,
-						  cxt5051_cfg_tbl);
 	spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC;
 	spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC;
 	switch (board_config) {
 	switch (board_config) {
 	case CXT5051_HP:
 	case CXT5051_HP:
@@ -2011,17 +2071,17 @@ static int patch_cxt5051(struct hda_codec *codec)
 
 
 /* Conexant 5066 specific */
 /* Conexant 5066 specific */
 
 
-static hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
-static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
-static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
-static hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
+static const hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
+static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
+static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
+static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
 
 
 /* OLPC's microphone port is DC coupled for use with external sensors,
 /* OLPC's microphone port is DC coupled for use with external sensors,
  * therefore we use a 50% mic bias in order to center the input signal with
  * therefore we use a 50% mic bias in order to center the input signal with
  * the DC input range of the codec. */
  * the DC input range of the codec. */
 #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50
 #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50
 
 
-static struct hda_channel_mode cxt5066_modes[1] = {
+static const struct hda_channel_mode cxt5066_modes[1] = {
 	{ 2, NULL },
 	{ 2, NULL },
 };
 };
 
 
@@ -2176,7 +2236,7 @@ static void cxt5066_vostro_automic(struct hda_codec *codec)
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{}
 		{}
 	};
 	};
-	static struct hda_verb ext_mic_absent[] = {
+	static const struct hda_verb ext_mic_absent[] = {
 		/* enable internal mic, port C */
 		/* enable internal mic, port C */
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 
 
@@ -2209,7 +2269,7 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{}
 		{}
 	};
 	};
-	static struct hda_verb ext_mic_absent[] = {
+	static const struct hda_verb ext_mic_absent[] = {
 		{0x14, AC_VERB_SET_CONNECT_SEL, 2},
 		{0x14, AC_VERB_SET_CONNECT_SEL, 2},
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -2257,7 +2317,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec)
 {
 {
 	unsigned int ext_present, dock_present;
 	unsigned int ext_present, dock_present;
 
 
-	static struct hda_verb ext_mic_present[] = {
+	static const struct hda_verb ext_mic_present[] = {
 		{0x14, AC_VERB_SET_CONNECT_SEL, 0},
 		{0x14, AC_VERB_SET_CONNECT_SEL, 0},
 		{0x17, AC_VERB_SET_CONNECT_SEL, 1},
 		{0x17, AC_VERB_SET_CONNECT_SEL, 1},
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -2265,7 +2325,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec)
 		{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{}
 		{}
 	};
 	};
-	static struct hda_verb dock_mic_present[] = {
+	static const struct hda_verb dock_mic_present[] = {
 		{0x14, AC_VERB_SET_CONNECT_SEL, 0},
 		{0x14, AC_VERB_SET_CONNECT_SEL, 0},
 		{0x17, AC_VERB_SET_CONNECT_SEL, 0},
 		{0x17, AC_VERB_SET_CONNECT_SEL, 0},
 		{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 		{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -2273,7 +2333,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec)
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{}
 		{}
 	};
 	};
-	static struct hda_verb ext_mic_absent[] = {
+	static const struct hda_verb ext_mic_absent[] = {
 		{0x14, AC_VERB_SET_CONNECT_SEL, 2},
 		{0x14, AC_VERB_SET_CONNECT_SEL, 2},
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -2537,7 +2597,7 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
 }
 }
 
 
 static void conexant_check_dig_outs(struct hda_codec *codec,
 static void conexant_check_dig_outs(struct hda_codec *codec,
-				    hda_nid_t *dig_pins,
+				    const hda_nid_t *dig_pins,
 				    int num_pins)
 				    int num_pins)
 {
 {
 	struct conexant_spec *spec = codec->spec;
 	struct conexant_spec *spec = codec->spec;
@@ -2557,7 +2617,7 @@ static void conexant_check_dig_outs(struct hda_codec *codec,
 	}
 	}
 }
 }
 
 
-static struct hda_input_mux cxt5066_capture_source = {
+static const struct hda_input_mux cxt5066_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic B", 0 },
 		{ "Mic B", 0 },
@@ -2567,7 +2627,7 @@ static struct hda_input_mux cxt5066_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_bind_ctls cxt5066_bind_capture_vol_others = {
+static const struct hda_bind_ctls cxt5066_bind_capture_vol_others = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
@@ -2576,7 +2636,7 @@ static struct hda_bind_ctls cxt5066_bind_capture_vol_others = {
 	},
 	},
 };
 };
 
 
-static struct hda_bind_ctls cxt5066_bind_capture_sw_others = {
+static const struct hda_bind_ctls cxt5066_bind_capture_sw_others = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
@@ -2585,12 +2645,12 @@ static struct hda_bind_ctls cxt5066_bind_capture_sw_others = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new cxt5066_mixer_master[] = {
+static const struct snd_kcontrol_new cxt5066_mixer_master[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
+static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Volume",
 		.name = "Master Playback Volume",
@@ -2609,7 +2669,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
+static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "DC Mode Enable Switch",
 		.name = "DC Mode Enable Switch",
@@ -2627,7 +2687,7 @@ static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5066_mixers[] = {
+static const struct snd_kcontrol_new cxt5066_mixers[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
 		.name = "Master Playback Switch",
@@ -2650,7 +2710,7 @@ static struct snd_kcontrol_new cxt5066_mixers[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
+static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Internal Mic Boost Capture Enum",
 		.name = "Internal Mic Boost Capture Enum",
@@ -2662,7 +2722,7 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb cxt5066_init_verbs[] = {
+static const struct hda_verb cxt5066_init_verbs[] = {
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
 	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
 	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
@@ -2717,7 +2777,7 @@ static struct hda_verb cxt5066_init_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5066_init_verbs_olpc[] = {
+static const struct hda_verb cxt5066_init_verbs_olpc[] = {
 	/* Port A: headphones */
 	/* Port A: headphones */
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
 	{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
@@ -2778,7 +2838,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5066_init_verbs_vostro[] = {
+static const struct hda_verb cxt5066_init_verbs_vostro[] = {
 	/* Port A: headphones */
 	/* Port A: headphones */
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
 	{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
 	{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
@@ -2839,7 +2899,7 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5066_init_verbs_ideapad[] = {
+static const struct hda_verb cxt5066_init_verbs_ideapad[] = {
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
 	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
 	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
@@ -2889,7 +2949,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5066_init_verbs_thinkpad[] = {
+static const struct hda_verb cxt5066_init_verbs_thinkpad[] = {
 	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
 	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
 	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
 	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
 
 
@@ -2947,13 +3007,13 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
+static const struct hda_verb cxt5066_init_verbs_portd_lo[] = {
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
 
 
-static struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
+static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x0},
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x0},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
@@ -2997,6 +3057,7 @@ enum {
 	CXT5066_THINKPAD,	/* Lenovo ThinkPad T410s, others? */
 	CXT5066_THINKPAD,	/* Lenovo ThinkPad T410s, others? */
 	CXT5066_ASUS,		/* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */
 	CXT5066_ASUS,		/* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */
 	CXT5066_HP_LAPTOP,      /* HP Laptop */
 	CXT5066_HP_LAPTOP,      /* HP Laptop */
+	CXT5066_AUTO,		/* BIOS auto-parser */
 	CXT5066_MODELS
 	CXT5066_MODELS
 };
 };
 
 
@@ -3009,9 +3070,10 @@ static const char * const cxt5066_models[CXT5066_MODELS] = {
 	[CXT5066_THINKPAD]	= "thinkpad",
 	[CXT5066_THINKPAD]	= "thinkpad",
 	[CXT5066_ASUS]		= "asus",
 	[CXT5066_ASUS]		= "asus",
 	[CXT5066_HP_LAPTOP]	= "hp-laptop",
 	[CXT5066_HP_LAPTOP]	= "hp-laptop",
+	[CXT5066_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
+static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
 	SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
 	SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
 	SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD),
@@ -3046,6 +3108,15 @@ static int patch_cxt5066(struct hda_codec *codec)
 	struct conexant_spec *spec;
 	struct conexant_spec *spec;
 	int board_config;
 	int board_config;
 
 
+	board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
+						  cxt5066_models, cxt5066_cfg_tbl);
+#if 0 /* use the old method just for safety */
+	if (board_config < 0)
+		board_config = CXT5066_AUTO;
+#endif
+	if (board_config == CXT5066_AUTO)
+		return patch_conexant_auto(codec);
+
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 	if (!spec)
 		return -ENOMEM;
 		return -ENOMEM;
@@ -3076,8 +3147,6 @@ static int patch_cxt5066(struct hda_codec *codec)
 
 
 	set_beep_amp(spec, 0x13, 0, HDA_OUTPUT);
 	set_beep_amp(spec, 0x13, 0, HDA_OUTPUT);
 
 
-	board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
-						  cxt5066_models, cxt5066_cfg_tbl);
 	switch (board_config) {
 	switch (board_config) {
 	default:
 	default:
 	case CXT5066_LAPTOP:
 	case CXT5066_LAPTOP:
@@ -3195,7 +3264,45 @@ static int patch_cxt5066(struct hda_codec *codec)
  * Automatic parser for CX20641 & co
  * Automatic parser for CX20641 & co
  */
  */
 
 
-static hda_nid_t cx_auto_adc_nids[] = { 0x14 };
+static int cx_auto_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       unsigned int stream_tag,
+				       unsigned int format,
+				       struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	hda_nid_t adc = spec->imux_info[spec->cur_mux[0]].adc;
+	if (spec->adc_switching) {
+		spec->cur_adc = adc;
+		spec->cur_adc_stream_tag = stream_tag;
+		spec->cur_adc_format = format;
+	}
+	snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format);
+	return 0;
+}
+
+static int cx_auto_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+	spec->cur_adc = 0;
+	return 0;
+}
+
+static const struct hda_pcm_stream cx_auto_pcm_analog_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0, /* fill later */
+	.ops = {
+		.prepare = cx_auto_capture_pcm_prepare,
+		.cleanup = cx_auto_capture_pcm_cleanup
+	},
+};
+
+static const hda_nid_t cx_auto_adc_nids[] = { 0x14 };
 
 
 /* get the connection index of @nid in the widget @mux */
 /* get the connection index of @nid in the widget @mux */
 static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
 static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
@@ -3320,61 +3427,339 @@ static void cx_auto_parse_output(struct hda_codec *codec)
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
 
-	if (cfg->hp_outs > 0)
-		spec->auto_mute = 1;
+	for (i = 0; i < cfg->hp_outs; i++) {
+		if (is_jack_detectable(codec, cfg->hp_pins[i])) {
+			spec->auto_mute = 1;
+			break;
+		}
+	}
+	if (spec->auto_mute && cfg->line_out_pins[0] &&
+	    cfg->line_out_pins[0] != cfg->hp_pins[0] &&
+	    cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
+		for (i = 0; i < cfg->line_outs; i++) {
+			if (is_jack_detectable(codec, cfg->line_out_pins[i])) {
+				spec->detect_line = 1;
+				break;
+			}
+		}
+		spec->automute_lines = spec->detect_line;
+	}
+
 	spec->vmaster_nid = spec->private_dac_nids[0];
 	spec->vmaster_nid = spec->private_dac_nids[0];
 }
 }
 
 
+static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
+			      hda_nid_t *pins, bool on);
+
+static void do_automute(struct hda_codec *codec, int num_pins,
+			hda_nid_t *pins, bool on)
+{
+	int i;
+	for (i = 0; i < num_pins; i++)
+		snd_hda_codec_write(codec, pins[i], 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL,
+				    on ? PIN_OUT : 0);
+	cx_auto_turn_eapd(codec, num_pins, pins, on);
+}
+
+static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
+{
+	int i, present = 0;
+
+	for (i = 0; i < num_pins; i++) {
+		hda_nid_t nid = pins[i];
+		if (!nid || !is_jack_detectable(codec, nid))
+			break;
+		snd_hda_input_jack_report(codec, nid);
+		present |= snd_hda_jack_detect(codec, nid);
+	}
+	return present;
+}
+
 /* auto-mute/unmute speaker and line outs according to headphone jack */
 /* auto-mute/unmute speaker and line outs according to headphone jack */
+static void cx_auto_update_speakers(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int on;
+
+	if (!spec->auto_mute)
+		on = 0;
+	else
+		on = spec->hp_present | spec->line_present;
+	cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
+	do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, !on);
+
+	/* toggle line-out mutes if needed, too */
+	/* if LO is a copy of either HP or Speaker, don't need to handle it */
+	if (cfg->line_out_pins[0] == cfg->hp_pins[0] ||
+	    cfg->line_out_pins[0] == cfg->speaker_pins[0])
+		return;
+	if (!spec->automute_lines || !spec->auto_mute)
+		on = 0;
+	else
+		on = spec->hp_present;
+	do_automute(codec, cfg->line_outs, cfg->line_out_pins, !on);
+}
+
 static void cx_auto_hp_automute(struct hda_codec *codec)
 static void cx_auto_hp_automute(struct hda_codec *codec)
 {
 {
 	struct conexant_spec *spec = codec->spec;
 	struct conexant_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	int i, present;
 
 
 	if (!spec->auto_mute)
 	if (!spec->auto_mute)
 		return;
 		return;
-	present = 0;
-	for (i = 0; i < cfg->hp_outs; i++) {
-		if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) {
-			present = 1;
-			break;
-		}
+	spec->hp_present = detect_jacks(codec, cfg->hp_outs, cfg->hp_pins);
+	cx_auto_update_speakers(codec);
+}
+
+static void cx_auto_line_automute(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+
+	if (!spec->auto_mute || !spec->detect_line)
+		return;
+	spec->line_present = detect_jacks(codec, cfg->line_outs,
+					  cfg->line_out_pins);
+	cx_auto_update_speakers(codec);
+}
+
+static int cx_automute_mode_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	static const char * const texts2[] = {
+		"Disabled", "Enabled"
+	};
+	static const char * const texts3[] = {
+		"Disabled", "Speaker Only", "Line-Out+Speaker"
+	};
+	const char * const *texts;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	if (spec->automute_hp_lo) {
+		uinfo->value.enumerated.items = 3;
+		texts = texts3;
+	} else {
+		uinfo->value.enumerated.items = 2;
+		texts = texts2;
 	}
 	}
-	for (i = 0; i < cfg->line_outs; i++) {
-		snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    present ? 0 : PIN_OUT);
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name,
+	       texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int cx_automute_mode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+	unsigned int val;
+	if (!spec->auto_mute)
+		val = 0;
+	else if (!spec->automute_lines)
+		val = 1;
+	else
+		val = 2;
+	ucontrol->value.enumerated.item[0] = val;
+	return 0;
+}
+
+static int cx_automute_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	switch (ucontrol->value.enumerated.item[0]) {
+	case 0:
+		if (!spec->auto_mute)
+			return 0;
+		spec->auto_mute = 0;
+		break;
+	case 1:
+		if (spec->auto_mute && !spec->automute_lines)
+			return 0;
+		spec->auto_mute = 1;
+		spec->automute_lines = 0;
+		break;
+	case 2:
+		if (!spec->automute_hp_lo)
+			return -EINVAL;
+		if (spec->auto_mute && spec->automute_lines)
+			return 0;
+		spec->auto_mute = 1;
+		spec->automute_lines = 1;
+		break;
+	default:
+		return -EINVAL;
 	}
 	}
-	for (i = 0; !present && i < cfg->line_outs; i++)
-		if (snd_hda_jack_detect(codec, cfg->line_out_pins[i]))
-			present = 1;
-	for (i = 0; i < cfg->speaker_outs; i++) {
-		snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    present ? 0 : PIN_OUT);
+	cx_auto_update_speakers(codec);
+	return 1;
+}
+
+static const struct snd_kcontrol_new cx_automute_mode_enum[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Auto-Mute Mode",
+		.info = cx_automute_mode_info,
+		.get = cx_automute_mode_get,
+		.put = cx_automute_mode_put,
+	},
+	{ }
+};
+
+static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	return snd_hda_input_mux_info(&spec->private_imux, uinfo);
+}
+
+static int cx_auto_mux_enum_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mux[0];
+	return 0;
+}
+
+/* look for the route the given pin from mux and return the index;
+ * if do_select is set, actually select the route.
+ */
+static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,
+				     hda_nid_t pin, hda_nid_t *srcp,
+				     bool do_select, int depth)
+{
+	hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+	int i, nums;
+
+	switch (get_wcaps_type(get_wcaps(codec, mux))) {
+	case AC_WID_AUD_IN:
+	case AC_WID_AUD_SEL:
+	case AC_WID_AUD_MIX:
+		break;
+	default:
+		return -1;
 	}
 	}
+
+	nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+	for (i = 0; i < nums; i++)
+		if (conn[i] == pin) {
+			if (do_select)
+				snd_hda_codec_write(codec, mux, 0,
+						    AC_VERB_SET_CONNECT_SEL, i);
+			if (srcp)
+				*srcp = mux;
+			return i;
+		}
+	depth++;
+	if (depth == 2)
+		return -1;
+	for (i = 0; i < nums; i++) {
+		int ret  = __select_input_connection(codec, conn[i], pin, srcp,
+						     do_select, depth);
+		if (ret >= 0) {
+			if (do_select)
+				snd_hda_codec_write(codec, mux, 0,
+						    AC_VERB_SET_CONNECT_SEL, i);
+			return i;
+		}
+	}
+	return -1;
+}
+
+static void select_input_connection(struct hda_codec *codec, hda_nid_t mux,
+				   hda_nid_t pin)
+{
+	__select_input_connection(codec, mux, pin, NULL, true, 0);
+}
+
+static int get_input_connection(struct hda_codec *codec, hda_nid_t mux,
+				hda_nid_t pin)
+{
+	return __select_input_connection(codec, mux, pin, NULL, false, 0);
+}
+
+static int cx_auto_mux_enum_update(struct hda_codec *codec,
+				   const struct hda_input_mux *imux,
+				   unsigned int idx)
+{
+	struct conexant_spec *spec = codec->spec;
+	hda_nid_t adc;
+
+	if (!imux->num_items)
+		return 0;
+	if (idx >= imux->num_items)
+		idx = imux->num_items - 1;
+	if (spec->cur_mux[0] == idx)
+		return 0;
+	adc = spec->imux_info[idx].adc;
+	select_input_connection(codec, spec->imux_info[idx].adc,
+				spec->imux_info[idx].pin);
+	if (spec->cur_adc && spec->cur_adc != adc) {
+		/* stream is running, let's swap the current ADC */
+		__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+		spec->cur_adc = adc;
+		snd_hda_codec_setup_stream(codec, adc,
+					   spec->cur_adc_stream_tag, 0,
+					   spec->cur_adc_format);
+	}
+	spec->cur_mux[0] = idx;
+	return 1;
+}
+
+static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct conexant_spec *spec = codec->spec;
+
+	return cx_auto_mux_enum_update(codec, &spec->private_imux,
+				       ucontrol->value.enumerated.item[0]);
+}
+
+static const struct snd_kcontrol_new cx_auto_capture_mixers[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = cx_auto_mux_enum_info,
+		.get = cx_auto_mux_enum_get,
+		.put = cx_auto_mux_enum_put
+	},
+	{}
+};
+
+static bool select_automic(struct hda_codec *codec, int idx, bool detect)
+{
+	struct conexant_spec *spec = codec->spec;
+	if (idx < 0)
+		return false;
+	if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin))
+		return false;
+	cx_auto_mux_enum_update(codec, &spec->private_imux, idx);
+	return true;
 }
 }
 
 
 /* automatic switch internal and external mic */
 /* automatic switch internal and external mic */
 static void cx_auto_automic(struct hda_codec *codec)
 static void cx_auto_automic(struct hda_codec *codec)
 {
 {
 	struct conexant_spec *spec = codec->spec;
 	struct conexant_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
-	struct hda_input_mux *imux = &spec->private_imux;
-	int ext_idx = spec->auto_mic_ext;
 
 
 	if (!spec->auto_mic)
 	if (!spec->auto_mic)
 		return;
 		return;
-	if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) {
-		snd_hda_codec_write(codec, spec->adc_nids[0], 0,
-				    AC_VERB_SET_CONNECT_SEL,
-				    imux->items[ext_idx].index);
-	} else {
-		snd_hda_codec_write(codec, spec->adc_nids[0], 0,
-				    AC_VERB_SET_CONNECT_SEL,
-				    imux->items[!ext_idx].index);
-	}
+	if (!select_automic(codec, spec->auto_mic_ext, true))
+		if (!select_automic(codec, spec->auto_mic_dock, true))
+			select_automic(codec, spec->auto_mic_int, false);
 }
 }
 
 
 static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
 static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
@@ -3383,7 +3768,9 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
 	switch (res >> 26) {
 	switch (res >> 26) {
 	case CONEXANT_HP_EVENT:
 	case CONEXANT_HP_EVENT:
 		cx_auto_hp_automute(codec);
 		cx_auto_hp_automute(codec);
-		snd_hda_input_jack_report(codec, nid);
+		break;
+	case CONEXANT_LINE_EVENT:
+		cx_auto_line_automute(codec);
 		break;
 		break;
 	case CONEXANT_MIC_EVENT:
 	case CONEXANT_MIC_EVENT:
 		cx_auto_automic(codec);
 		cx_auto_automic(codec);
@@ -3392,43 +3779,45 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
 	}
 	}
 }
 }
 
 
-/* return true if it's an internal-mic pin */
-static int is_int_mic(struct hda_codec *codec, hda_nid_t pin)
-{
-	unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
-	return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
-		snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT;
-}
-
-/* return true if it's an external-mic pin */
-static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin)
-{
-	unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
-	return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
-		snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL &&
-		(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT);
-}
-
 /* check whether the pin config is suitable for auto-mic switching;
 /* check whether the pin config is suitable for auto-mic switching;
- * auto-mic is enabled only when one int-mic and one-ext mic exist
+ * auto-mic is enabled only when one int-mic and one ext- and/or
+ * one dock-mic exist
  */
  */
 static void cx_auto_check_auto_mic(struct hda_codec *codec)
 static void cx_auto_check_auto_mic(struct hda_codec *codec)
 {
 {
 	struct conexant_spec *spec = codec->spec;
 	struct conexant_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int pset[INPUT_PIN_ATTR_NORMAL + 1];
+	int i;
 
 
-	if (is_ext_mic(codec, cfg->inputs[0].pin) &&
-	    is_int_mic(codec, cfg->inputs[1].pin)) {
-		spec->auto_mic = 1;
-		spec->auto_mic_ext = 1;
-		return;
-	}
-	if (is_int_mic(codec, cfg->inputs[1].pin) &&
-	    is_ext_mic(codec, cfg->inputs[0].pin)) {
-		spec->auto_mic = 1;
-		spec->auto_mic_ext = 0;
-		return;
+	for (i = 0; i < INPUT_PIN_ATTR_NORMAL; i++)
+		pset[i] = -1;
+	for (i = 0; i < spec->private_imux.num_items; i++) {
+		hda_nid_t pin = spec->imux_info[i].pin;
+		unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
+		int type, attr;
+		attr = snd_hda_get_input_pin_attr(def_conf);
+		if (attr == INPUT_PIN_ATTR_UNUSED)
+			return; /* invalid entry */
+		if (attr > INPUT_PIN_ATTR_NORMAL)
+			attr = INPUT_PIN_ATTR_NORMAL;
+		if (attr != INPUT_PIN_ATTR_INT &&
+		    !is_jack_detectable(codec, pin))
+			return; /* non-detectable pin */
+		type = get_defcfg_device(def_conf);
+		if (type != AC_JACK_MIC_IN &&
+		    (attr != INPUT_PIN_ATTR_DOCK || type != AC_JACK_LINE_IN))
+			return; /* no valid input type */
+		if (pset[attr] >= 0)
+			return; /* already occupied */
+		pset[attr] = i;
 	}
 	}
+	if (pset[INPUT_PIN_ATTR_INT] < 0 ||
+	    (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK]))
+		return; /* no input to switch*/
+	spec->auto_mic = 1;
+	spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL];
+	spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK];
+	spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT];
 }
 }
 
 
 static void cx_auto_parse_input(struct hda_codec *codec)
 static void cx_auto_parse_input(struct hda_codec *codec)
@@ -3436,22 +3825,37 @@ static void cx_auto_parse_input(struct hda_codec *codec)
 	struct conexant_spec *spec = codec->spec;
 	struct conexant_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct hda_input_mux *imux;
 	struct hda_input_mux *imux;
-	int i;
+	int i, j;
 
 
 	imux = &spec->private_imux;
 	imux = &spec->private_imux;
 	for (i = 0; i < cfg->num_inputs; i++) {
 	for (i = 0; i < cfg->num_inputs; i++) {
-		int idx = get_connection_index(codec, spec->adc_nids[0],
-					       cfg->inputs[i].pin);
-		if (idx >= 0) {
-			const char *label;
-			label = hda_get_autocfg_input_label(codec, cfg, i);
-			snd_hda_add_imux_item(imux, label, idx, NULL);
+		for (j = 0; j < spec->num_adc_nids; j++) {
+			hda_nid_t adc = spec->adc_nids[j];
+			int idx = get_input_connection(codec, adc,
+						       cfg->inputs[i].pin);
+			if (idx >= 0) {
+				const char *label;
+				label = hda_get_autocfg_input_label(codec, cfg, i);
+				spec->imux_info[imux->num_items].index = i;
+				spec->imux_info[imux->num_items].boost = 0;
+				spec->imux_info[imux->num_items].adc = adc;
+				spec->imux_info[imux->num_items].pin =
+					cfg->inputs[i].pin;
+				snd_hda_add_imux_item(imux, label, idx, NULL);
+				break;
+			}
 		}
 		}
 	}
 	}
-	if (imux->num_items == 2 && cfg->num_inputs == 2)
+	if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items)
 		cx_auto_check_auto_mic(codec);
 		cx_auto_check_auto_mic(codec);
-	if (imux->num_items > 1 && !spec->auto_mic)
-		spec->input_mux = imux;
+	if (imux->num_items > 1 && !spec->auto_mic) {
+		for (i = 1; i < imux->num_items; i++) {
+			if (spec->imux_info[i].adc != spec->imux_info[0].adc) {
+				spec->adc_switching = 1;
+				break;
+			}
+		}
+	}
 }
 }
 
 
 /* get digital-input audio widget corresponding to the given pin */
 /* get digital-input audio widget corresponding to the given pin */
@@ -3517,14 +3921,15 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
-static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins,
-				 hda_nid_t *pins)
+static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
+			      hda_nid_t *pins, bool on)
 {
 {
 	int i;
 	int i;
 	for (i = 0; i < num_pins; i++) {
 	for (i = 0; i < num_pins; i++) {
 		if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
 		if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
 			snd_hda_codec_write(codec, pins[i], 0,
 			snd_hda_codec_write(codec, pins[i], 0,
-					    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+					    AC_VERB_SET_EAPD_BTLENABLE,
+					    on ? 0x02 : 0);
 	}
 	}
 }
 }
 
 
@@ -3537,6 +3942,34 @@ static void select_connection(struct hda_codec *codec, hda_nid_t pin,
 				    AC_VERB_SET_CONNECT_SEL, idx);
 				    AC_VERB_SET_CONNECT_SEL, idx);
 }
 }
 
 
+static void mute_outputs(struct hda_codec *codec, int num_nids,
+			 const hda_nid_t *nids)
+{
+	int i, val;
+
+	for (i = 0; i < num_nids; i++) {
+		hda_nid_t nid = nids[i];
+		if (!(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
+			continue;
+		if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE)
+			val = AMP_OUT_MUTE;
+		else
+			val = AMP_OUT_ZERO;
+		snd_hda_codec_write(codec, nid, 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE, val);
+	}
+}
+
+static void enable_unsol_pins(struct hda_codec *codec, int num_pins,
+			      hda_nid_t *pins, unsigned int tag)
+{
+	int i;
+	for (i = 0; i < num_pins; i++)
+		snd_hda_codec_write(codec, pins[i], 0,
+				    AC_VERB_SET_UNSOLICITED_ENABLE,
+				    AC_USRSP_EN | tag);
+}
+
 static void cx_auto_init_output(struct hda_codec *codec)
 static void cx_auto_init_output(struct hda_codec *codec)
 {
 {
 	struct conexant_spec *spec = codec->spec;
 	struct conexant_spec *spec = codec->spec;
@@ -3544,51 +3977,53 @@ static void cx_auto_init_output(struct hda_codec *codec)
 	hda_nid_t nid;
 	hda_nid_t nid;
 	int i;
 	int i;
 
 
-	for (i = 0; i < spec->multiout.num_dacs; i++)
-		snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0,
-				    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
+	mute_outputs(codec, spec->multiout.num_dacs, spec->multiout.dac_nids);
 	for (i = 0; i < cfg->hp_outs; i++)
 	for (i = 0; i < cfg->hp_outs; i++)
 		snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
 		snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
 				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
 				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
-	if (spec->auto_mute) {
-		for (i = 0; i < cfg->hp_outs; i++) {
-			snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
-				    AC_VERB_SET_UNSOLICITED_ENABLE,
-				    AC_USRSP_EN | CONEXANT_HP_EVENT);
-		}
-		cx_auto_hp_automute(codec);
-	} else {
-		for (i = 0; i < cfg->line_outs; i++)
-			snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-		for (i = 0; i < cfg->speaker_outs; i++)
-			snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-	}
-
+	mute_outputs(codec, cfg->hp_outs, cfg->hp_pins);
+	mute_outputs(codec, cfg->line_outs, cfg->line_out_pins);
+	mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins);
 	for (i = 0; i < spec->dac_info_filled; i++) {
 	for (i = 0; i < spec->dac_info_filled; i++) {
 		nid = spec->dac_info[i].dac;
 		nid = spec->dac_info[i].dac;
 		if (!nid)
 		if (!nid)
 			nid = spec->multiout.dac_nids[0];
 			nid = spec->multiout.dac_nids[0];
 		select_connection(codec, spec->dac_info[i].pin, nid);
 		select_connection(codec, spec->dac_info[i].pin, nid);
 	}
 	}
-
-	/* turn on EAPD */
-	cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins);
-	cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins);
-	cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins);
+	if (spec->auto_mute) {
+		enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins,
+				  CONEXANT_HP_EVENT);
+		spec->hp_present = detect_jacks(codec, cfg->hp_outs,
+						cfg->hp_pins);
+		if (spec->detect_line) {
+			enable_unsol_pins(codec, cfg->line_outs,
+					  cfg->line_out_pins,
+					  CONEXANT_LINE_EVENT);
+			spec->line_present =
+				detect_jacks(codec, cfg->line_outs,
+					     cfg->line_out_pins);
+		}
+	}
+	cx_auto_update_speakers(codec);
 }
 }
 
 
 static void cx_auto_init_input(struct hda_codec *codec)
 static void cx_auto_init_input(struct hda_codec *codec)
 {
 {
 	struct conexant_spec *spec = codec->spec;
 	struct conexant_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	int i;
+	int i, val;
 
 
-	for (i = 0; i < spec->num_adc_nids; i++)
-		snd_hda_codec_write(codec, spec->adc_nids[i], 0,
-				    AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0));
+	for (i = 0; i < spec->num_adc_nids; i++) {
+		hda_nid_t nid = spec->adc_nids[i];
+		if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+			continue;
+		if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE)
+			val = AMP_IN_MUTE(0);
+		else
+			val = AMP_IN_UNMUTE(0);
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    val);
+	}
 
 
 	for (i = 0; i < cfg->num_inputs; i++) {
 	for (i = 0; i < cfg->num_inputs; i++) {
 		unsigned int type;
 		unsigned int type;
@@ -3601,17 +4036,22 @@ static void cx_auto_init_input(struct hda_codec *codec)
 	}
 	}
 
 
 	if (spec->auto_mic) {
 	if (spec->auto_mic) {
-		int ext_idx = spec->auto_mic_ext;
-		snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0,
-				    AC_VERB_SET_UNSOLICITED_ENABLE,
-				    AC_USRSP_EN | CONEXANT_MIC_EVENT);
+		if (spec->auto_mic_ext >= 0) {
+			snd_hda_codec_write(codec,
+				cfg->inputs[spec->auto_mic_ext].pin, 0,
+				AC_VERB_SET_UNSOLICITED_ENABLE,
+				AC_USRSP_EN | CONEXANT_MIC_EVENT);
+		}
+		if (spec->auto_mic_dock >= 0) {
+			snd_hda_codec_write(codec,
+				cfg->inputs[spec->auto_mic_dock].pin, 0,
+				AC_VERB_SET_UNSOLICITED_ENABLE,
+				AC_USRSP_EN | CONEXANT_MIC_EVENT);
+		}
 		cx_auto_automic(codec);
 		cx_auto_automic(codec);
 	} else {
 	} else {
-		for (i = 0; i < spec->num_adc_nids; i++) {
-			snd_hda_codec_write(codec, spec->adc_nids[i], 0,
-					    AC_VERB_SET_CONNECT_SEL,
-					    spec->private_imux.items[0].index);
-		}
+		select_input_connection(codec, spec->imux_info[0].adc,
+					spec->imux_info[0].pin);
 	}
 	}
 }
 }
 
 
@@ -3646,7 +4086,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
 		HDA_CODEC_VOLUME(name, 0, 0, 0),
 		HDA_CODEC_VOLUME(name, 0, 0, 0),
 		HDA_CODEC_MUTE(name, 0, 0, 0),
 		HDA_CODEC_MUTE(name, 0, 0, 0),
 	};
 	};
-	static char *sfx[2] = { "Volume", "Switch" };
+	static const char * const sfx[2] = { "Volume", "Switch" };
 	int i, err;
 	int i, err;
 
 
 	for (i = 0; i < 2; i++) {
 	for (i = 0; i < 2; i++) {
@@ -3674,6 +4114,19 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
 #define cx_auto_add_pb_volume(codec, nid, str, idx)			\
 #define cx_auto_add_pb_volume(codec, nid, str, idx)			\
 	cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
 	cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
 
 
+static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac,
+			     hda_nid_t pin, const char *name, int idx)
+{
+	unsigned int caps;
+	caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+	if (caps & AC_AMPCAP_NUM_STEPS)
+		return cx_auto_add_pb_volume(codec, dac, name, idx);
+	caps = query_amp_caps(codec, pin, HDA_OUTPUT);
+	if (caps & AC_AMPCAP_NUM_STEPS)
+		return cx_auto_add_pb_volume(codec, pin, name, idx);
+	return 0;
+}
+
 static int cx_auto_build_output_controls(struct hda_codec *codec)
 static int cx_auto_build_output_controls(struct hda_codec *codec)
 {
 {
 	struct conexant_spec *spec = codec->spec;
 	struct conexant_spec *spec = codec->spec;
@@ -3682,8 +4135,10 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
 	static const char * const texts[3] = { "Front", "Surround", "CLFE" };
 	static const char * const texts[3] = { "Front", "Surround", "CLFE" };
 
 
 	if (spec->dac_info_filled == 1)
 	if (spec->dac_info_filled == 1)
-		return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac,
-					     "Master", 0);
+		return try_add_pb_volume(codec, spec->dac_info[0].dac,
+					 spec->dac_info[0].pin,
+					 "Master", 0);
+
 	for (i = 0; i < spec->dac_info_filled; i++) {
 	for (i = 0; i < spec->dac_info_filled; i++) {
 		const char *label;
 		const char *label;
 		int idx, type;
 		int idx, type;
@@ -3707,74 +4162,123 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
 			idx = num_spk++;
 			idx = num_spk++;
 			break;
 			break;
 		}
 		}
-		err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac,
-					    label, idx);
+		err = try_add_pb_volume(codec, spec->dac_info[i].dac,
+					spec->dac_info[i].pin,
+					label, idx);
+		if (err < 0)
+			return err;
+	}
+
+	if (spec->auto_mute) {
+		err = snd_hda_add_new_ctls(codec, cx_automute_mode_enum);
 		if (err < 0)
 		if (err < 0)
 			return err;
 			return err;
 	}
 	}
+	
+	return 0;
+}
+
+static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
+				      const char *label, const char *pfx,
+				      int cidx)
+{
+	struct conexant_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i < spec->num_adc_nids; i++) {
+		hda_nid_t adc_nid = spec->adc_nids[i];
+		int idx = get_input_connection(codec, adc_nid, nid);
+		if (idx < 0)
+			continue;
+		return cx_auto_add_volume_idx(codec, label, pfx,
+					      cidx, adc_nid, HDA_INPUT, idx);
+	}
+	return 0;
+}
+
+static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
+				    const char *label, int cidx)
+{
+	struct conexant_spec *spec = codec->spec;
+	hda_nid_t mux, nid;
+	int i, con;
+
+	nid = spec->imux_info[idx].pin;
+	if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+		return cx_auto_add_volume(codec, label, " Boost", cidx,
+					  nid, HDA_INPUT);
+	con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
+					&mux, false, 0);
+	if (con < 0)
+		return 0;
+	for (i = 0; i < idx; i++) {
+		if (spec->imux_info[i].boost == mux)
+			return 0; /* already present */
+	}
+
+	if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) {
+		spec->imux_info[idx].boost = mux;
+		return cx_auto_add_volume(codec, label, " Boost", 0,
+					  mux, HDA_OUTPUT);
+	}
 	return 0;
 	return 0;
 }
 }
 
 
 static int cx_auto_build_input_controls(struct hda_codec *codec)
 static int cx_auto_build_input_controls(struct hda_codec *codec)
 {
 {
 	struct conexant_spec *spec = codec->spec;
 	struct conexant_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
-	static const char *prev_label;
-	int i, err, cidx, conn_len;
-	hda_nid_t conn[HDA_MAX_CONNECTIONS];
-
-	int multi_adc_volume = 0; /* If the ADC nid has several input volumes */
-	int adc_nid = spec->adc_nids[0];
-
-	conn_len = snd_hda_get_connections(codec, adc_nid, conn,
-					   HDA_MAX_CONNECTIONS);
-	if (conn_len < 0)
-		return conn_len;
-
-	multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1;
-	if (!multi_adc_volume) {
-		err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid,
-					 HDA_INPUT);
-		if (err < 0)
-			return err;
+	struct hda_input_mux *imux = &spec->private_imux;
+	const char *prev_label;
+	int input_conn[HDA_MAX_NUM_INPUTS];
+	int i, err, cidx;
+	int multi_connection;
+
+	multi_connection = 0;
+	for (i = 0; i < imux->num_items; i++) {
+		cidx = get_input_connection(codec, spec->imux_info[i].adc,
+					    spec->imux_info[i].pin);
+		input_conn[i] = (spec->imux_info[i].adc << 8) | cidx;
+		if (i > 0 && input_conn[i] != input_conn[0])
+			multi_connection = 1;
 	}
 	}
 
 
 	prev_label = NULL;
 	prev_label = NULL;
 	cidx = 0;
 	cidx = 0;
-	for (i = 0; i < cfg->num_inputs; i++) {
-		hda_nid_t nid = cfg->inputs[i].pin;
+	for (i = 0; i < imux->num_items; i++) {
+		hda_nid_t nid = spec->imux_info[i].pin;
 		const char *label;
 		const char *label;
-		int j;
-		int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP;
-		if (!pin_amp && !multi_adc_volume)
-			continue;
 
 
-		label = hda_get_autocfg_input_label(codec, cfg, i);
+		label = hda_get_autocfg_input_label(codec, &spec->autocfg,
+						    spec->imux_info[i].index);
 		if (label == prev_label)
 		if (label == prev_label)
 			cidx++;
 			cidx++;
 		else
 		else
 			cidx = 0;
 			cidx = 0;
 		prev_label = label;
 		prev_label = label;
 
 
-		if (pin_amp) {
-			err = cx_auto_add_volume(codec, label, " Boost", cidx,
-						 nid, HDA_INPUT);
-			if (err < 0)
-				return err;
-		}
+		err = cx_auto_add_boost_volume(codec, i, label, cidx);
+		if (err < 0)
+			return err;
 
 
-		if (!multi_adc_volume)
-			continue;
-		for (j = 0; j < conn_len; j++) {
-			if (conn[j] == nid) {
-				err = cx_auto_add_volume_idx(codec, label,
-				    " Capture", cidx, adc_nid, HDA_INPUT, j);
-				if (err < 0)
-					return err;
-				break;
-			}
+		if (!multi_connection) {
+			if (i > 0)
+				continue;
+			err = cx_auto_add_capture_volume(codec, nid,
+							 "Capture", "", cidx);
+		} else {
+			err = cx_auto_add_capture_volume(codec, nid,
+							 label, " Capture", cidx);
 		}
 		}
+		if (err < 0)
+			return err;
 	}
 	}
+
+	if (spec->private_imux.num_items > 1 && !spec->auto_mic) {
+		err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3791,7 +4295,29 @@ static int cx_auto_build_controls(struct hda_codec *codec)
 	return conexant_build_controls(codec);
 	return conexant_build_controls(codec);
 }
 }
 
 
-static struct hda_codec_ops cx_auto_patch_ops = {
+static int cx_auto_search_adcs(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	hda_nid_t nid, end_nid;
+
+	end_nid = codec->start_nid + codec->num_nodes;
+	for (nid = codec->start_nid; nid < end_nid; nid++) {
+		unsigned int caps = get_wcaps(codec, nid);
+		if (get_wcaps_type(caps) != AC_WID_AUD_IN)
+			continue;
+		if (caps & AC_WCAP_DIGITAL)
+			continue;
+		if (snd_BUG_ON(spec->num_adc_nids >=
+			       ARRAY_SIZE(spec->private_adc_nids)))
+			break;
+		spec->private_adc_nids[spec->num_adc_nids++] = nid;
+	}
+	spec->adc_nids = spec->private_adc_nids;
+	return 0;
+}
+
+
+static const struct hda_codec_ops cx_auto_patch_ops = {
 	.build_controls = cx_auto_build_controls,
 	.build_controls = cx_auto_build_controls,
 	.build_pcms = conexant_build_pcms,
 	.build_pcms = conexant_build_pcms,
 	.init = cx_auto_init,
 	.init = cx_auto_init,
@@ -3808,19 +4334,24 @@ static int patch_conexant_auto(struct hda_codec *codec)
 	struct conexant_spec *spec;
 	struct conexant_spec *spec;
 	int err;
 	int err;
 
 
+	printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+	       codec->chip_name);
+
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
 	if (!spec)
 		return -ENOMEM;
 		return -ENOMEM;
 	codec->spec = spec;
 	codec->spec = spec;
-	spec->adc_nids = cx_auto_adc_nids;
-	spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids);
-	spec->capsrc_nids = spec->adc_nids;
+	codec->pin_amp_workaround = 1;
+	err = cx_auto_search_adcs(codec);
+	if (err < 0)
+		return err;
 	err = cx_auto_parse_auto_config(codec);
 	err = cx_auto_parse_auto_config(codec);
 	if (err < 0) {
 	if (err < 0) {
 		kfree(codec->spec);
 		kfree(codec->spec);
 		codec->spec = NULL;
 		codec->spec = NULL;
 		return err;
 		return err;
 	}
 	}
+	spec->capture_stream = &cx_auto_pcm_analog_capture;
 	codec->patch_ops = cx_auto_patch_ops;
 	codec->patch_ops = cx_auto_patch_ops;
 	if (spec->beep_amp)
 	if (spec->beep_amp)
 		snd_hda_attach_beep_device(codec, spec->beep_amp);
 		snd_hda_attach_beep_device(codec, spec->beep_amp);
@@ -3830,7 +4361,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
 /*
 /*
  */
  */
 
 
-static struct hda_codec_preset snd_hda_preset_conexant[] = {
+static const struct hda_codec_preset snd_hda_preset_conexant[] = {
 	{ .id = 0x14f15045, .name = "CX20549 (Venice)",
 	{ .id = 0x14f15045, .name = "CX20549 (Venice)",
 	  .patch = patch_cxt5045 },
 	  .patch = patch_cxt5045 },
 	{ .id = 0x14f15047, .name = "CX20551 (Waikiki)",
 	{ .id = 0x14f15047, .name = "CX20551 (Waikiki)",

+ 26 - 13
sound/pci/hda/patch_hdmi.c

@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_local.h"
 
 
@@ -76,7 +77,7 @@ struct hdmi_spec {
 	 * ati/nvhdmi specific
 	 * ati/nvhdmi specific
 	 */
 	 */
 	struct hda_multi_out multiout;
 	struct hda_multi_out multiout;
-	struct hda_pcm_stream *pcm_playback;
+	const struct hda_pcm_stream *pcm_playback;
 
 
 	/* misc flags */
 	/* misc flags */
 	/* PD bit indicates only the update, not the current state */
 	/* PD bit indicates only the update, not the current state */
@@ -720,6 +721,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 				  &spec->sink_eld[index]);
 				  &spec->sink_eld[index]);
 		/* TODO: do real things about ELD */
 		/* TODO: do real things about ELD */
 	}
 	}
+
+	snd_hda_input_jack_report(codec, tag);
 }
 }
 
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -912,6 +915,7 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
 static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 {
 {
 	struct hdmi_spec *spec = codec->spec;
 	struct hdmi_spec *spec = codec->spec;
+	int err;
 
 
 	if (spec->num_pins >= MAX_HDMI_PINS) {
 	if (spec->num_pins >= MAX_HDMI_PINS) {
 		snd_printk(KERN_WARNING
 		snd_printk(KERN_WARNING
@@ -919,6 +923,12 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 		return -E2BIG;
 		return -E2BIG;
 	}
 	}
 
 
+	err = snd_hda_input_jack_add(codec, pin_nid,
+				     SND_JACK_VIDEOOUT, NULL);
+	if (err < 0)
+		return err;
+	snd_hda_input_jack_report(codec, pin_nid);
+
 	hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
 	hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
 
 
 	spec->pin[spec->num_pins] = pin_nid;
 	spec->pin[spec->num_pins] = pin_nid;
@@ -1044,7 +1054,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 	return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
 	return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
 }
 }
 
 
-static struct hda_pcm_stream generic_hdmi_pcm_playback = {
+static const struct hda_pcm_stream generic_hdmi_pcm_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.ops = {
 	.ops = {
@@ -1120,11 +1130,12 @@ static void generic_hdmi_free(struct hda_codec *codec)
 
 
 	for (i = 0; i < spec->num_pins; i++)
 	for (i = 0; i < spec->num_pins; i++)
 		snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
 		snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
+	snd_hda_input_jack_free(codec);
 
 
 	kfree(spec);
 	kfree(spec);
 }
 }
 
 
-static struct hda_codec_ops generic_hdmi_patch_ops = {
+static const struct hda_codec_ops generic_hdmi_patch_ops = {
 	.init			= generic_hdmi_init,
 	.init			= generic_hdmi_init,
 	.free			= generic_hdmi_free,
 	.free			= generic_hdmi_free,
 	.build_pcms		= generic_hdmi_build_pcms,
 	.build_pcms		= generic_hdmi_build_pcms,
@@ -1169,12 +1180,12 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 #define nvhdmi_master_con_nid_7x	0x04
 #define nvhdmi_master_con_nid_7x	0x04
 #define nvhdmi_master_pin_nid_7x	0x05
 #define nvhdmi_master_pin_nid_7x	0x05
 
 
-static hda_nid_t nvhdmi_con_nids_7x[4] = {
+static const hda_nid_t nvhdmi_con_nids_7x[4] = {
 	/*front, rear, clfe, rear_surr */
 	/*front, rear, clfe, rear_surr */
 	0x6, 0x8, 0xa, 0xc,
 	0x6, 0x8, 0xa, 0xc,
 };
 };
 
 
-static struct hda_verb nvhdmi_basic_init_7x[] = {
+static const struct hda_verb nvhdmi_basic_init_7x[] = {
 	/* set audio protect on */
 	/* set audio protect on */
 	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
 	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
 	/* enable digital output on pin widget */
 	/* enable digital output on pin widget */
@@ -1435,7 +1446,7 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
 	return 0;
 	return 0;
 }
 }
 
 
-static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
+static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.channels_max = 8,
@@ -1450,7 +1461,7 @@ static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
+static const struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -1465,14 +1476,14 @@ static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
 	},
 	},
 };
 };
 
 
-static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
+static const struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
 	.build_controls = generic_hdmi_build_controls,
 	.build_controls = generic_hdmi_build_controls,
 	.build_pcms = generic_hdmi_build_pcms,
 	.build_pcms = generic_hdmi_build_pcms,
 	.init = nvhdmi_7x_init,
 	.init = nvhdmi_7x_init,
 	.free = generic_hdmi_free,
 	.free = generic_hdmi_free,
 };
 };
 
 
-static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
+static const struct hda_codec_ops nvhdmi_patch_ops_2ch = {
 	.build_controls = generic_hdmi_build_controls,
 	.build_controls = generic_hdmi_build_controls,
 	.build_pcms = generic_hdmi_build_pcms,
 	.build_pcms = generic_hdmi_build_pcms,
 	.init = nvhdmi_7x_init,
 	.init = nvhdmi_7x_init,
@@ -1568,7 +1579,7 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 	return 0;
 	return 0;
 }
 }
 
 
-static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
+static const struct hda_pcm_stream atihdmi_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -1580,7 +1591,7 @@ static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_verb atihdmi_basic_init[] = {
+static const struct hda_verb atihdmi_basic_init[] = {
 	/* enable digital output on pin widget */
 	/* enable digital output on pin widget */
 	{ 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{} /* terminator */
 	{} /* terminator */
@@ -1599,7 +1610,7 @@ static int atihdmi_init(struct hda_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct hda_codec_ops atihdmi_patch_ops = {
+static const struct hda_codec_ops atihdmi_patch_ops = {
 	.build_controls = generic_hdmi_build_controls,
 	.build_controls = generic_hdmi_build_controls,
 	.build_pcms = generic_hdmi_build_pcms,
 	.build_pcms = generic_hdmi_build_pcms,
 	.init = atihdmi_init,
 	.init = atihdmi_init,
@@ -1634,7 +1645,7 @@ static int patch_atihdmi(struct hda_codec *codec)
 /*
 /*
  * patch entries
  * patch entries
  */
  */
-static struct hda_codec_preset snd_hda_preset_hdmi[] = {
+static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x1002793c, .name = "RS600 HDMI",	.patch = patch_atihdmi },
 { .id = 0x1002793c, .name = "RS600 HDMI",	.patch = patch_atihdmi },
 { .id = 0x10027919, .name = "RS600 HDMI",	.patch = patch_atihdmi },
 { .id = 0x10027919, .name = "RS600 HDMI",	.patch = patch_atihdmi },
 { .id = 0x1002791a, .name = "RS690/780 HDMI",	.patch = patch_atihdmi },
 { .id = 0x1002791a, .name = "RS690/780 HDMI",	.patch = patch_atihdmi },
@@ -1677,6 +1688,7 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x80862803, .name = "Eaglelake HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862803, .name = "Eaglelake HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862804, .name = "IbexPeak HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862804, .name = "IbexPeak HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862805, .name = "CougarPoint HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x80862805, .name = "CougarPoint HDMI",	.patch = patch_generic_hdmi },
+{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi },
 { .id = 0x808629fb, .name = "Crestline HDMI",	.patch = patch_generic_hdmi },
 { .id = 0x808629fb, .name = "Crestline HDMI",	.patch = patch_generic_hdmi },
 {} /* terminator */
 {} /* terminator */
 };
 };
@@ -1722,6 +1734,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862802");
 MODULE_ALIAS("snd-hda-codec-id:80862803");
 MODULE_ALIAS("snd-hda-codec-id:80862803");
 MODULE_ALIAS("snd-hda-codec-id:80862804");
 MODULE_ALIAS("snd-hda-codec-id:80862804");
 MODULE_ALIAS("snd-hda-codec-id:80862805");
 MODULE_ALIAS("snd-hda-codec-id:80862805");
+MODULE_ALIAS("snd-hda-codec-id:80862806");
 MODULE_ALIAS("snd-hda-codec-id:808629fb");
 MODULE_ALIAS("snd-hda-codec-id:808629fb");
 
 
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 1848 - 1873
sound/pci/hda/patch_realtek.c

@@ -299,11 +299,23 @@ struct alc_customize_define {
 
 
 struct alc_fixup;
 struct alc_fixup;
 
 
+struct alc_multi_io {
+	hda_nid_t pin;		/* multi-io widget pin NID */
+	hda_nid_t dac;		/* DAC to be connected */
+	unsigned int ctl_in;	/* cached input-pin control value */
+};
+
+enum {
+	ALC_AUTOMUTE_PIN,	/* change the pin control */
+	ALC_AUTOMUTE_AMP,	/* mute/unmute the pin AMP */
+	ALC_AUTOMUTE_MIXER,	/* mute/unmute mixer widget AMP */
+};
+
 struct alc_spec {
 struct alc_spec {
 	/* codec parameterization */
 	/* codec parameterization */
-	struct snd_kcontrol_new *mixers[5];	/* mixer arrays */
+	const struct snd_kcontrol_new *mixers[5];	/* mixer arrays */
 	unsigned int num_mixers;
 	unsigned int num_mixers;
-	struct snd_kcontrol_new *cap_mixer;	/* capture mixer */
+	const struct snd_kcontrol_new *cap_mixer;	/* capture mixer */
 	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */
 	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */
 
 
 	const struct hda_verb *init_verbs[10];	/* initialization verbs
 	const struct hda_verb *init_verbs[10];	/* initialization verbs
@@ -313,14 +325,14 @@ struct alc_spec {
 	unsigned int num_init_verbs;
 	unsigned int num_init_verbs;
 
 
 	char stream_name_analog[32];	/* analog PCM stream */
 	char stream_name_analog[32];	/* analog PCM stream */
-	struct hda_pcm_stream *stream_analog_playback;
-	struct hda_pcm_stream *stream_analog_capture;
-	struct hda_pcm_stream *stream_analog_alt_playback;
-	struct hda_pcm_stream *stream_analog_alt_capture;
+	const struct hda_pcm_stream *stream_analog_playback;
+	const struct hda_pcm_stream *stream_analog_capture;
+	const struct hda_pcm_stream *stream_analog_alt_playback;
+	const struct hda_pcm_stream *stream_analog_alt_capture;
 
 
 	char stream_name_digital[32];	/* digital PCM stream */
 	char stream_name_digital[32];	/* digital PCM stream */
-	struct hda_pcm_stream *stream_digital_playback;
-	struct hda_pcm_stream *stream_digital_capture;
+	const struct hda_pcm_stream *stream_digital_playback;
+	const struct hda_pcm_stream *stream_digital_capture;
 
 
 	/* playback */
 	/* playback */
 	struct hda_multi_out multiout;	/* playback set-up
 	struct hda_multi_out multiout;	/* playback set-up
@@ -333,8 +345,8 @@ struct alc_spec {
 
 
 	/* capture */
 	/* capture */
 	unsigned int num_adc_nids;
 	unsigned int num_adc_nids;
-	hda_nid_t *adc_nids;
-	hda_nid_t *capsrc_nids;
+	const hda_nid_t *adc_nids;
+	const hda_nid_t *capsrc_nids;
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 
 
 	/* capture setup for dynamic dual-adc switch */
 	/* capture setup for dynamic dual-adc switch */
@@ -348,6 +360,7 @@ struct alc_spec {
 	const struct hda_input_mux *input_mux;
 	const struct hda_input_mux *input_mux;
 	unsigned int cur_mux[3];
 	unsigned int cur_mux[3];
 	struct alc_mic_route ext_mic;
 	struct alc_mic_route ext_mic;
+	struct alc_mic_route dock_mic;
 	struct alc_mic_route int_mic;
 	struct alc_mic_route int_mic;
 
 
 	/* channel model */
 	/* channel model */
@@ -375,17 +388,27 @@ struct alc_spec {
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	void (*power_hook)(struct hda_codec *codec);
 	void (*power_hook)(struct hda_codec *codec);
 #endif
 #endif
+	void (*shutup)(struct hda_codec *codec);
 
 
 	/* for pin sensing */
 	/* for pin sensing */
-	unsigned int sense_updated: 1;
 	unsigned int jack_present: 1;
 	unsigned int jack_present: 1;
-	unsigned int master_sw: 1;
+	unsigned int line_jack_present:1;
+	unsigned int master_mute:1;
 	unsigned int auto_mic:1;
 	unsigned int auto_mic:1;
+	unsigned int automute:1;	/* HP automute enabled */
+	unsigned int detect_line:1;	/* Line-out detection enabled */
+	unsigned int automute_lines:1;	/* automute line-out as well */
+	unsigned int automute_hp_lo:1;	/* both HP and LO available */
 
 
 	/* other flags */
 	/* other flags */
 	unsigned int no_analog :1; /* digital I/O only */
 	unsigned int no_analog :1; /* digital I/O only */
 	unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
 	unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
 	unsigned int single_input_src:1;
 	unsigned int single_input_src:1;
+
+	/* auto-mute control */
+	int automute_mode;
+	hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
+
 	int init_amp;
 	int init_amp;
 	int codec_variant;	/* flag for other variants */
 	int codec_variant;	/* flag for other variants */
 
 
@@ -403,25 +426,29 @@ struct alc_spec {
 	int fixup_id;
 	int fixup_id;
 	const struct alc_fixup *fixup_list;
 	const struct alc_fixup *fixup_list;
 	const char *fixup_name;
 	const char *fixup_name;
+
+	/* multi-io */
+	int multi_ios;
+	struct alc_multi_io multi_io[4];
 };
 };
 
 
 /*
 /*
  * configuration template - to be copied to the spec instance
  * configuration template - to be copied to the spec instance
  */
  */
 struct alc_config_preset {
 struct alc_config_preset {
-	struct snd_kcontrol_new *mixers[5]; /* should be identical size
+	const struct snd_kcontrol_new *mixers[5]; /* should be identical size
 					     * with spec
 					     * with spec
 					     */
 					     */
-	struct snd_kcontrol_new *cap_mixer; /* capture mixer */
+	const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
 	const struct hda_verb *init_verbs[5];
 	const struct hda_verb *init_verbs[5];
 	unsigned int num_dacs;
 	unsigned int num_dacs;
-	hda_nid_t *dac_nids;
+	const hda_nid_t *dac_nids;
 	hda_nid_t dig_out_nid;		/* optional */
 	hda_nid_t dig_out_nid;		/* optional */
 	hda_nid_t hp_nid;		/* optional */
 	hda_nid_t hp_nid;		/* optional */
-	hda_nid_t *slave_dig_outs;
+	const hda_nid_t *slave_dig_outs;
 	unsigned int num_adc_nids;
 	unsigned int num_adc_nids;
-	hda_nid_t *adc_nids;
-	hda_nid_t *capsrc_nids;
+	const hda_nid_t *adc_nids;
+	const hda_nid_t *capsrc_nids;
 	hda_nid_t dig_in_nid;
 	hda_nid_t dig_in_nid;
 	unsigned int num_channel_mode;
 	unsigned int num_channel_mode;
 	const struct hda_channel_mode *channel_mode;
 	const struct hda_channel_mode *channel_mode;
@@ -433,7 +460,7 @@ struct alc_config_preset {
 	void (*setup)(struct hda_codec *);
 	void (*setup)(struct hda_codec *);
 	void (*init_hook)(struct hda_codec *);
 	void (*init_hook)(struct hda_codec *);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-	struct hda_amp_list *loopbacks;
+	const struct hda_amp_list *loopbacks;
 	void (*power_hook)(struct hda_codec *codec);
 	void (*power_hook)(struct hda_codec *codec);
 #endif
 #endif
 };
 };
@@ -560,11 +587,11 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
  * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
  * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
  * March 2006.
  * March 2006.
  */
  */
-static char *alc_pin_mode_names[] = {
+static const char * const alc_pin_mode_names[] = {
 	"Mic 50pc bias", "Mic 80pc bias",
 	"Mic 50pc bias", "Mic 80pc bias",
 	"Line in", "Line out", "Headphone out",
 	"Line in", "Line out", "Headphone out",
 };
 };
-static unsigned char alc_pin_mode_values[] = {
+static const unsigned char alc_pin_mode_values[] = {
 	PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
 	PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
 };
 };
 /* The control can present all 5 options, or it can limit the options based
 /* The control can present all 5 options, or it can limit the options based
@@ -583,7 +610,7 @@ static unsigned char alc_pin_mode_values[] = {
 /* Info about the pin modes supported by the different pin direction modes.
 /* Info about the pin modes supported by the different pin direction modes.
  * For each direction the minimum and maximum values are given.
  * For each direction the minimum and maximum values are given.
  */
  */
-static signed char alc_pin_mode_dir_info[5][2] = {
+static const signed char alc_pin_mode_dir_info[5][2] = {
 	{ 0, 2 },    /* ALC_PIN_DIR_IN */
 	{ 0, 2 },    /* ALC_PIN_DIR_IN */
 	{ 3, 4 },    /* ALC_PIN_DIR_OUT */
 	{ 3, 4 },    /* ALC_PIN_DIR_OUT */
 	{ 0, 4 },    /* ALC_PIN_DIR_INOUT */
 	{ 0, 4 },    /* ALC_PIN_DIR_INOUT */
@@ -900,7 +927,7 @@ static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
 
 
 /*
 /*
  */
  */
-static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
+static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
 {
 {
 	if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
 	if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
 		return;
 		return;
@@ -971,21 +998,21 @@ static void setup_preset(struct hda_codec *codec,
 }
 }
 
 
 /* Enable GPIO mask and set output */
 /* Enable GPIO mask and set output */
-static struct hda_verb alc_gpio1_init_verbs[] = {
+static const struct hda_verb alc_gpio1_init_verbs[] = {
 	{0x01, AC_VERB_SET_GPIO_MASK, 0x01},
 	{0x01, AC_VERB_SET_GPIO_MASK, 0x01},
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc_gpio2_init_verbs[] = {
+static const struct hda_verb alc_gpio2_init_verbs[] = {
 	{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
 	{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x02},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x02},
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc_gpio3_init_verbs[] = {
+static const struct hda_verb alc_gpio3_init_verbs[] = {
 	{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
 	{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x03},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x03},
@@ -1031,6 +1058,7 @@ static int alc_init_jacks(struct hda_codec *codec)
 	int err;
 	int err;
 	unsigned int hp_nid = spec->autocfg.hp_pins[0];
 	unsigned int hp_nid = spec->autocfg.hp_pins[0];
 	unsigned int mic_nid = spec->ext_mic.pin;
 	unsigned int mic_nid = spec->ext_mic.pin;
+	unsigned int dock_nid = spec->dock_mic.pin;
 
 
 	if (hp_nid) {
 	if (hp_nid) {
 		err = snd_hda_input_jack_add(codec, hp_nid,
 		err = snd_hda_input_jack_add(codec, hp_nid,
@@ -1047,46 +1075,116 @@ static int alc_init_jacks(struct hda_codec *codec)
 			return err;
 			return err;
 		snd_hda_input_jack_report(codec, mic_nid);
 		snd_hda_input_jack_report(codec, mic_nid);
 	}
 	}
+	if (dock_nid) {
+		err = snd_hda_input_jack_add(codec, dock_nid,
+					     SND_JACK_MICROPHONE, NULL);
+		if (err < 0)
+			return err;
+		snd_hda_input_jack_report(codec, dock_nid);
+	}
 #endif /* CONFIG_SND_HDA_INPUT_JACK */
 #endif /* CONFIG_SND_HDA_INPUT_JACK */
 	return 0;
 	return 0;
 }
 }
 
 
-static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
+static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
 {
 {
-	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
-	hda_nid_t nid;
-	int i;
+	int i, present = 0;
 
 
-	spec->jack_present = 0;
-	for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
-		nid = spec->autocfg.hp_pins[i];
+	for (i = 0; i < num_pins; i++) {
+		hda_nid_t nid = pins[i];
 		if (!nid)
 		if (!nid)
 			break;
 			break;
 		snd_hda_input_jack_report(codec, nid);
 		snd_hda_input_jack_report(codec, nid);
-		spec->jack_present |= snd_hda_jack_detect(codec, nid);
+		present |= snd_hda_jack_detect(codec, nid);
 	}
 	}
+	return present;
+}
+
+static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
+			bool mute, bool hp_out)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
+	unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
+	int i;
 
 
-	mute = spec->jack_present ? HDA_AMP_MUTE : 0;
-	/* Toggle internal speakers muting */
-	for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
-		nid = spec->autocfg.speaker_pins[i];
+	for (i = 0; i < num_pins; i++) {
+		hda_nid_t nid = pins[i];
 		if (!nid)
 		if (!nid)
 			break;
 			break;
-		if (pinctl) {
+		switch (spec->automute_mode) {
+		case ALC_AUTOMUTE_PIN:
 			snd_hda_codec_write(codec, nid, 0,
 			snd_hda_codec_write(codec, nid, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    spec->jack_present ? 0 : PIN_OUT);
-		} else {
+					    AC_VERB_SET_PIN_WIDGET_CONTROL,
+					    pin_bits);
+			break;
+		case ALC_AUTOMUTE_AMP:
 			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
 			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
+						 HDA_AMP_MUTE, mute_bits);
+			break;
+		case ALC_AUTOMUTE_MIXER:
+			nid = spec->automute_mixer_nid[i];
+			if (!nid)
+				break;
+			snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
+						 HDA_AMP_MUTE, mute_bits);
+			snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
+						 HDA_AMP_MUTE, mute_bits);
+			break;
 		}
 		}
 	}
 	}
 }
 }
 
 
-static void alc_automute_pin(struct hda_codec *codec)
+/* Toggle internal speakers muting */
+static void update_speakers(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int on;
+
+	if (!spec->automute)
+		on = 0;
+	else
+		on = spec->jack_present | spec->line_jack_present;
+	on |= spec->master_mute;
+	do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
+		    spec->autocfg.speaker_pins, on, false);
+
+	/* toggle line-out mutes if needed, too */
+	/* if LO is a copy of either HP or Speaker, don't need to handle it */
+	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
+	    spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
+		return;
+	if (!spec->automute_lines || !spec->automute)
+		on = 0;
+	else
+		on = spec->jack_present;
+	on |= spec->master_mute;
+	do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
+		    spec->autocfg.line_out_pins, on, false);
+}
+
+static void alc_hp_automute(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (!spec->automute)
+		return;
+	spec->jack_present =
+		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
+			     spec->autocfg.hp_pins);
+	update_speakers(codec);
+}
+
+static void alc_line_automute(struct hda_codec *codec)
 {
 {
-	alc_automute_speaker(codec, 1);
+	struct alc_spec *spec = codec->spec;
+
+	if (!spec->automute || !spec->detect_line)
+		return;
+	spec->line_jack_present =
+		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
+			     spec->autocfg.line_out_pins);
+	update_speakers(codec);
 }
 }
 
 
 static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
 static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
@@ -1128,7 +1226,7 @@ static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
 static void alc_mic_automute(struct hda_codec *codec)
 static void alc_mic_automute(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	struct alc_mic_route *dead, *alive;
+	struct alc_mic_route *dead1, *dead2, *alive;
 	unsigned int present, type;
 	unsigned int present, type;
 	hda_nid_t cap_nid;
 	hda_nid_t cap_nid;
 
 
@@ -1146,13 +1244,24 @@ static void alc_mic_automute(struct hda_codec *codec)
 
 
 	cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
 	cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
 
 
+	alive = &spec->int_mic;
+	dead1 = &spec->ext_mic;
+	dead2 = &spec->dock_mic;
+
 	present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
 	present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
 	if (present) {
 	if (present) {
 		alive = &spec->ext_mic;
 		alive = &spec->ext_mic;
-		dead = &spec->int_mic;
-	} else {
-		alive = &spec->int_mic;
-		dead = &spec->ext_mic;
+		dead1 = &spec->int_mic;
+		dead2 = &spec->dock_mic;
+	}
+	if (!present && spec->dock_mic.pin > 0) {
+		present = snd_hda_jack_detect(codec, spec->dock_mic.pin);
+		if (present) {
+			alive = &spec->dock_mic;
+			dead1 = &spec->int_mic;
+			dead2 = &spec->ext_mic;
+		}
+		snd_hda_input_jack_report(codec, spec->dock_mic.pin);
 	}
 	}
 
 
 	type = get_wcaps_type(get_wcaps(codec, cap_nid));
 	type = get_wcaps_type(get_wcaps(codec, cap_nid));
@@ -1161,9 +1270,14 @@ static void alc_mic_automute(struct hda_codec *codec)
 		snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
 		snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
 					 alive->mux_idx,
 					 alive->mux_idx,
 					 HDA_AMP_MUTE, 0);
 					 HDA_AMP_MUTE, 0);
-		snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
-					 dead->mux_idx,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		if (dead1->pin > 0)
+			snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
+						 dead1->mux_idx,
+						 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		if (dead2->pin > 0)
+			snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
+						 dead2->mux_idx,
+						 HDA_AMP_MUTE, HDA_AMP_MUTE);
 	} else {
 	} else {
 		/* MUX style (e.g. ALC880) */
 		/* MUX style (e.g. ALC880) */
 		snd_hda_codec_write_cache(codec, cap_nid, 0,
 		snd_hda_codec_write_cache(codec, cap_nid, 0,
@@ -1184,7 +1298,10 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
 		res >>= 26;
 		res >>= 26;
 	switch (res) {
 	switch (res) {
 	case ALC880_HP_EVENT:
 	case ALC880_HP_EVENT:
-		alc_automute_pin(codec);
+		alc_hp_automute(codec);
+		break;
+	case ALC880_FRONT_EVENT:
+		alc_line_automute(codec);
 		break;
 		break;
 	case ALC880_MIC_EVENT:
 	case ALC880_MIC_EVENT:
 		alc_mic_automute(codec);
 		alc_mic_automute(codec);
@@ -1194,7 +1311,8 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
 
 
 static void alc_inithook(struct hda_codec *codec)
 static void alc_inithook(struct hda_codec *codec)
 {
 {
-	alc_automute_pin(codec);
+	alc_hp_automute(codec);
+	alc_line_automute(codec);
 	alc_mic_automute(codec);
 	alc_mic_automute(codec);
 }
 }
 
 
@@ -1236,6 +1354,43 @@ static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
 				    on ? 2 : 0);
 				    on ? 2 : 0);
 }
 }
 
 
+/* turn on/off EAPD controls of the codec */
+static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
+{
+	/* We currently only handle front, HP */
+	switch (codec->vendor_id) {
+	case 0x10ec0260:
+		set_eapd(codec, 0x0f, on);
+		set_eapd(codec, 0x10, on);
+		break;
+	case 0x10ec0262:
+	case 0x10ec0267:
+	case 0x10ec0268:
+	case 0x10ec0269:
+	case 0x10ec0270:
+	case 0x10ec0272:
+	case 0x10ec0660:
+	case 0x10ec0662:
+	case 0x10ec0663:
+	case 0x10ec0665:
+	case 0x10ec0862:
+	case 0x10ec0889:
+	case 0x10ec0892:
+		set_eapd(codec, 0x14, on);
+		set_eapd(codec, 0x15, on);
+		break;
+	}
+}
+
+/* generic shutup callback;
+ * just turning off EPAD and a little pause for avoiding pop-noise
+ */
+static void alc_eapd_shutup(struct hda_codec *codec)
+{
+	alc_auto_setup_eapd(codec, false);
+	msleep(200);
+}
+
 static void alc_auto_init_amp(struct hda_codec *codec, int type)
 static void alc_auto_init_amp(struct hda_codec *codec, int type)
 {
 {
 	unsigned int tmp;
 	unsigned int tmp;
@@ -1251,27 +1406,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
 		snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
 		snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
 		break;
 		break;
 	case ALC_INIT_DEFAULT:
 	case ALC_INIT_DEFAULT:
-		switch (codec->vendor_id) {
-		case 0x10ec0260:
-			set_eapd(codec, 0x0f, 1);
-			set_eapd(codec, 0x10, 1);
-			break;
-		case 0x10ec0262:
-		case 0x10ec0267:
-		case 0x10ec0268:
-		case 0x10ec0269:
-		case 0x10ec0270:
-		case 0x10ec0272:
-		case 0x10ec0660:
-		case 0x10ec0662:
-		case 0x10ec0663:
-		case 0x10ec0665:
-		case 0x10ec0862:
-		case 0x10ec0889:
-			set_eapd(codec, 0x14, 1);
-			set_eapd(codec, 0x15, 1);
-			break;
-		}
+		alc_auto_setup_eapd(codec, true);
 		switch (codec->vendor_id) {
 		switch (codec->vendor_id) {
 		case 0x10ec0260:
 		case 0x10ec0260:
 			snd_hda_codec_write(codec, 0x1a, 0,
 			snd_hda_codec_write(codec, 0x1a, 0,
@@ -1315,20 +1450,128 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
 	}
 	}
 }
 }
 
 
+static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	static const char * const texts2[] = {
+		"Disabled", "Enabled"
+	};
+	static const char * const texts3[] = {
+		"Disabled", "Speaker Only", "Line-Out+Speaker"
+	};
+	const char * const *texts;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	if (spec->automute_hp_lo) {
+		uinfo->value.enumerated.items = 3;
+		texts = texts3;
+	} else {
+		uinfo->value.enumerated.items = 2;
+		texts = texts2;
+	}
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name,
+	       texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	unsigned int val;
+	if (!spec->automute)
+		val = 0;
+	else if (!spec->automute_lines)
+		val = 1;
+	else
+		val = 2;
+	ucontrol->value.enumerated.item[0] = val;
+	return 0;
+}
+
+static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+
+	switch (ucontrol->value.enumerated.item[0]) {
+	case 0:
+		if (!spec->automute)
+			return 0;
+		spec->automute = 0;
+		break;
+	case 1:
+		if (spec->automute && !spec->automute_lines)
+			return 0;
+		spec->automute = 1;
+		spec->automute_lines = 0;
+		break;
+	case 2:
+		if (!spec->automute_hp_lo)
+			return -EINVAL;
+		if (spec->automute && spec->automute_lines)
+			return 0;
+		spec->automute = 1;
+		spec->automute_lines = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	update_speakers(codec);
+	return 1;
+}
+
+static const struct snd_kcontrol_new alc_automute_mode_enum = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Auto-Mute Mode",
+	.info = alc_automute_mode_info,
+	.get = alc_automute_mode_get,
+	.put = alc_automute_mode_put,
+};
+
+static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec);
+
+static int alc_add_automute_mode_enum(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	struct snd_kcontrol_new *knew;
+
+	knew = alc_kcontrol_new(spec);
+	if (!knew)
+		return -ENOMEM;
+	*knew = alc_automute_mode_enum;
+	knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
+	if (!knew->name)
+		return -ENOMEM;
+	return 0;
+}
+
 static void alc_init_auto_hp(struct hda_codec *codec)
 static void alc_init_auto_hp(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int present = 0;
 	int i;
 	int i;
 
 
-	if (!cfg->hp_pins[0]) {
-		if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-			return;
-	}
+	if (cfg->hp_pins[0])
+		present++;
+	if (cfg->line_out_pins[0])
+		present++;
+	if (cfg->speaker_pins[0])
+		present++;
+	if (present < 2) /* need two different output types */
+		return;
+	if (present == 3)
+		spec->automute_hp_lo = 1; /* both HP and LO automute */
 
 
 	if (!cfg->speaker_pins[0]) {
 	if (!cfg->speaker_pins[0]) {
-		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
-			return;
 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
 		memcpy(cfg->speaker_pins, cfg->line_out_pins,
 		       sizeof(cfg->speaker_pins));
 		       sizeof(cfg->speaker_pins));
 		cfg->speaker_outs = cfg->line_outs;
 		cfg->speaker_outs = cfg->line_outs;
@@ -1341,28 +1584,49 @@ static void alc_init_auto_hp(struct hda_codec *codec)
 	}
 	}
 
 
 	for (i = 0; i < cfg->hp_outs; i++) {
 	for (i = 0; i < cfg->hp_outs; i++) {
+		hda_nid_t nid = cfg->hp_pins[i];
+		if (!is_jack_detectable(codec, nid))
+			continue;
 		snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
 		snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
-			    cfg->hp_pins[i]);
-		snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0,
+			    nid);
+		snd_hda_codec_write_cache(codec, nid, 0,
 				  AC_VERB_SET_UNSOLICITED_ENABLE,
 				  AC_VERB_SET_UNSOLICITED_ENABLE,
 				  AC_USRSP_EN | ALC880_HP_EVENT);
 				  AC_USRSP_EN | ALC880_HP_EVENT);
+		spec->automute = 1;
+		spec->automute_mode = ALC_AUTOMUTE_PIN;
+	}
+	if (spec->automute && cfg->line_out_pins[0] &&
+	    cfg->line_out_pins[0] != cfg->hp_pins[0] &&
+	    cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
+		for (i = 0; i < cfg->line_outs; i++) {
+			hda_nid_t nid = cfg->line_out_pins[i];
+			if (!is_jack_detectable(codec, nid))
+				continue;
+			snd_printdd("realtek: Enable Line-Out auto-muting "
+				    "on NID 0x%x\n", nid);
+			snd_hda_codec_write_cache(codec, nid, 0,
+					AC_VERB_SET_UNSOLICITED_ENABLE,
+					AC_USRSP_EN | ALC880_FRONT_EVENT);
+			spec->detect_line = 1;
+		}
+		spec->automute_lines = spec->detect_line;
+	}
+
+	if (spec->automute) {
+		/* create a control for automute mode */
+		alc_add_automute_mode_enum(codec);
+		spec->unsol_event = alc_sku_unsol_event;
 	}
 	}
-	spec->unsol_event = alc_sku_unsol_event;
 }
 }
 
 
 static void alc_init_auto_mic(struct hda_codec *codec)
 static void alc_init_auto_mic(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	hda_nid_t fixed, ext;
+	hda_nid_t fixed, ext, dock;
 	int i;
 	int i;
 
 
-	/* there must be only two mic inputs exclusively */
-	for (i = 0; i < cfg->num_inputs; i++)
-		if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
-			return;
-
-	fixed = ext = 0;
+	fixed = ext = dock = 0;
 	for (i = 0; i < cfg->num_inputs; i++) {
 	for (i = 0; i < cfg->num_inputs; i++) {
 		hda_nid_t nid = cfg->inputs[i].pin;
 		hda_nid_t nid = cfg->inputs[i].pin;
 		unsigned int defcfg;
 		unsigned int defcfg;
@@ -1371,26 +1635,45 @@ static void alc_init_auto_mic(struct hda_codec *codec)
 		case INPUT_PIN_ATTR_INT:
 		case INPUT_PIN_ATTR_INT:
 			if (fixed)
 			if (fixed)
 				return; /* already occupied */
 				return; /* already occupied */
+			if (cfg->inputs[i].type != AUTO_PIN_MIC)
+				return; /* invalid type */
 			fixed = nid;
 			fixed = nid;
 			break;
 			break;
 		case INPUT_PIN_ATTR_UNUSED:
 		case INPUT_PIN_ATTR_UNUSED:
 			return; /* invalid entry */
 			return; /* invalid entry */
+		case INPUT_PIN_ATTR_DOCK:
+			if (dock)
+				return; /* already occupied */
+			if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+				return; /* invalid type */
+			dock = nid;
+			break;
 		default:
 		default:
 			if (ext)
 			if (ext)
 				return; /* already occupied */
 				return; /* already occupied */
+			if (cfg->inputs[i].type != AUTO_PIN_MIC)
+				return; /* invalid type */
 			ext = nid;
 			ext = nid;
 			break;
 			break;
 		}
 		}
 	}
 	}
+	if (!ext && dock) {
+		ext = dock;
+		dock = 0;
+	}
 	if (!ext || !fixed)
 	if (!ext || !fixed)
 		return;
 		return;
-	if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
+	if (!is_jack_detectable(codec, ext))
+		return; /* no unsol support */
+	if (dock && !is_jack_detectable(codec, dock))
 		return; /* no unsol support */
 		return; /* no unsol support */
-	snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
-		    ext, fixed);
+	snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
+		    ext, fixed, dock);
 	spec->ext_mic.pin = ext;
 	spec->ext_mic.pin = ext;
+	spec->dock_mic.pin = dock;
 	spec->int_mic.pin = fixed;
 	spec->int_mic.pin = fixed;
 	spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
 	spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
+	spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
 	spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
 	spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
 	spec->auto_mic = 1;
 	spec->auto_mic = 1;
 	snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
 	snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
@@ -1583,9 +1866,6 @@ do_sku:
 				return 1;
 				return 1;
 		spec->autocfg.hp_pins[0] = nid;
 		spec->autocfg.hp_pins[0] = nid;
 	}
 	}
-
-	alc_init_auto_hp(codec);
-	alc_init_auto_mic(codec);
 	return 1;
 	return 1;
 }
 }
 
 
@@ -1598,9 +1878,10 @@ static void alc_ssid_check(struct hda_codec *codec,
 		snd_printd("realtek: "
 		snd_printd("realtek: "
 			   "Enable default setup for auto mode as fallback\n");
 			   "Enable default setup for auto mode as fallback\n");
 		spec->init_amp = ALC_INIT_DEFAULT;
 		spec->init_amp = ALC_INIT_DEFAULT;
-		alc_init_auto_hp(codec);
-		alc_init_auto_mic(codec);
 	}
 	}
+
+	alc_init_auto_hp(codec);
+	alc_init_auto_mic(codec);
 }
 }
 
 
 /*
 /*
@@ -1842,7 +2123,7 @@ static void alc_auto_parse_digital(struct hda_codec *codec)
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_verb alc888_4ST_ch2_intel_init[] = {
+static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
 /* Mic-in jack as mic in */
 /* Mic-in jack as mic in */
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -1857,7 +2138,7 @@ static struct hda_verb alc888_4ST_ch2_intel_init[] = {
 /*
 /*
  * 4ch mode
  * 4ch mode
  */
  */
-static struct hda_verb alc888_4ST_ch4_intel_init[] = {
+static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
 /* Mic-in jack as mic in */
 /* Mic-in jack as mic in */
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -1872,7 +2153,7 @@ static struct hda_verb alc888_4ST_ch4_intel_init[] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc888_4ST_ch6_intel_init[] = {
+static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
 /* Mic-in jack as CLFE */
 /* Mic-in jack as CLFE */
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -1887,7 +2168,7 @@ static struct hda_verb alc888_4ST_ch6_intel_init[] = {
 /*
 /*
  * 8ch mode
  * 8ch mode
  */
  */
-static struct hda_verb alc888_4ST_ch8_intel_init[] = {
+static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
 /* Mic-in jack as CLFE */
 /* Mic-in jack as CLFE */
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -1899,7 +2180,7 @@ static struct hda_verb alc888_4ST_ch8_intel_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
+static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
 	{ 2, alc888_4ST_ch2_intel_init },
 	{ 2, alc888_4ST_ch2_intel_init },
 	{ 4, alc888_4ST_ch4_intel_init },
 	{ 4, alc888_4ST_ch4_intel_init },
 	{ 6, alc888_4ST_ch6_intel_init },
 	{ 6, alc888_4ST_ch6_intel_init },
@@ -1910,7 +2191,7 @@ static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
  * ALC888 Fujitsu Siemens Amillo xa3530
  * ALC888 Fujitsu Siemens Amillo xa3530
  */
  */
 
 
-static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
+static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
 /* Front Mic: set to PIN_IN (empty by default) */
 /* Front Mic: set to PIN_IN (empty by default) */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 /* Connect Internal HP to Front */
 /* Connect Internal HP to Front */
@@ -1943,22 +2224,6 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static void alc_automute_amp(struct hda_codec *codec)
-{
-	alc_automute_speaker(codec, 0);
-}
-
-static void alc_automute_amp_unsol_event(struct hda_codec *codec,
-					 unsigned int res)
-{
-	if (codec->vendor_id == 0x10ec0880)
-		res >>= 28;
-	else
-		res >>= 26;
-	if (res == ALC880_HP_EVENT)
-		alc_automute_amp(codec);
-}
-
 static void alc889_automute_setup(struct hda_codec *codec)
 static void alc889_automute_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
@@ -1969,12 +2234,14 @@ static void alc889_automute_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[2] = 0x17;
 	spec->autocfg.speaker_pins[2] = 0x17;
 	spec->autocfg.speaker_pins[3] = 0x19;
 	spec->autocfg.speaker_pins[3] = 0x19;
 	spec->autocfg.speaker_pins[4] = 0x1a;
 	spec->autocfg.speaker_pins[4] = 0x1a;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc889_intel_init_hook(struct hda_codec *codec)
 static void alc889_intel_init_hook(struct hda_codec *codec)
 {
 {
 	alc889_coef_init(codec);
 	alc889_coef_init(codec);
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 }
 }
 
 
 static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
 static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
@@ -1985,13 +2252,15 @@ static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[1] = 0x1b; /* hp */
 	spec->autocfg.hp_pins[1] = 0x1b; /* hp */
 	spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
 	spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
 	spec->autocfg.speaker_pins[1] = 0x15; /* bass */
 	spec->autocfg.speaker_pins[1] = 0x15; /* bass */
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 /*
 /*
  * ALC888 Acer Aspire 4930G model
  * ALC888 Acer Aspire 4930G model
  */
  */
 
 
-static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
+static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
 /* Front Mic: set to PIN_IN (empty by default) */
 /* Front Mic: set to PIN_IN (empty by default) */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 /* Unselect Front Mic by default in input mixer 3 */
 /* Unselect Front Mic by default in input mixer 3 */
@@ -2014,7 +2283,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
  * ALC888 Acer Aspire 6530G model
  * ALC888 Acer Aspire 6530G model
  */
  */
 
 
-static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
+static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
 /* Route to built-in subwoofer as well as speakers */
 /* Route to built-in subwoofer as well as speakers */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -2044,7 +2313,7 @@ static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
  *ALC888 Acer Aspire 7730G model
  *ALC888 Acer Aspire 7730G model
  */
  */
 
 
-static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
+static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
 /* Bias voltage on for external mic port */
 /* Bias voltage on for external mic port */
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
 /* Front Mic: set to PIN_IN (empty by default) */
 /* Front Mic: set to PIN_IN (empty by default) */
@@ -2074,7 +2343,7 @@ static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
  * ALC889 Acer Aspire 8930G model
  * ALC889 Acer Aspire 8930G model
  */
  */
 
 
-static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
+static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
 /* Front Mic: set to PIN_IN (empty by default) */
 /* Front Mic: set to PIN_IN (empty by default) */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 /* Unselect Front Mic by default in input mixer 3 */
 /* Unselect Front Mic by default in input mixer 3 */
@@ -2120,7 +2389,7 @@ static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_input_mux alc888_2_capture_sources[2] = {
+static const struct hda_input_mux alc888_2_capture_sources[2] = {
 	/* Front mic only available on one ADC */
 	/* Front mic only available on one ADC */
 	{
 	{
 		.num_items = 4,
 		.num_items = 4,
@@ -2141,7 +2410,7 @@ static struct hda_input_mux alc888_2_capture_sources[2] = {
 	}
 	}
 };
 };
 
 
-static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
+static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
 	/* Interal mic only available on one ADC */
 	/* Interal mic only available on one ADC */
 	{
 	{
 		.num_items = 5,
 		.num_items = 5,
@@ -2164,7 +2433,7 @@ static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
 	}
 	}
 };
 };
 
 
-static struct hda_input_mux alc889_capture_sources[3] = {
+static const struct hda_input_mux alc889_capture_sources[3] = {
 	/* Digital mic only available on first "ADC" */
 	/* Digital mic only available on first "ADC" */
 	{
 	{
 		.num_items = 5,
 		.num_items = 5,
@@ -2196,7 +2465,7 @@ static struct hda_input_mux alc889_capture_sources[3] = {
 	}
 	}
 };
 };
 
 
-static struct snd_kcontrol_new alc888_base_mixer[] = {
+static const struct snd_kcontrol_new alc888_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2218,7 +2487,7 @@ static struct snd_kcontrol_new alc888_base_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
+static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2240,7 +2509,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
+static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2267,6 +2536,8 @@ static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x17;
 	spec->autocfg.speaker_pins[2] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
 static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
@@ -2277,6 +2548,8 @@ static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x17;
 	spec->autocfg.speaker_pins[2] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
 static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
@@ -2287,6 +2560,8 @@ static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x17;
 	spec->autocfg.speaker_pins[2] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
 static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
@@ -2297,6 +2572,8 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x1b;
 	spec->autocfg.speaker_pins[2] = 0x1b;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 /*
 /*
@@ -2307,12 +2584,12 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
  *                 F-Mic = 0x1b, HP = 0x19
  *                 F-Mic = 0x1b, HP = 0x19
  */
  */
 
 
-static hda_nid_t alc880_dac_nids[4] = {
+static const hda_nid_t alc880_dac_nids[4] = {
 	/* front, rear, clfe, rear_surr */
 	/* front, rear, clfe, rear_surr */
 	0x02, 0x05, 0x04, 0x03
 	0x02, 0x05, 0x04, 0x03
 };
 };
 
 
-static hda_nid_t alc880_adc_nids[3] = {
+static const hda_nid_t alc880_adc_nids[3] = {
 	/* ADC0-2 */
 	/* ADC0-2 */
 	0x07, 0x08, 0x09,
 	0x07, 0x08, 0x09,
 };
 };
@@ -2321,7 +2598,7 @@ static hda_nid_t alc880_adc_nids[3] = {
  * but it shows zero connection in the real implementation on some devices.
  * but it shows zero connection in the real implementation on some devices.
  * Note: this is a 915GAV bug, fixed on 915GLV
  * Note: this is a 915GAV bug, fixed on 915GLV
  */
  */
-static hda_nid_t alc880_adc_nids_alt[2] = {
+static const hda_nid_t alc880_adc_nids_alt[2] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x08, 0x09,
 	0x08, 0x09,
 };
 };
@@ -2329,7 +2606,7 @@ static hda_nid_t alc880_adc_nids_alt[2] = {
 #define ALC880_DIGOUT_NID	0x06
 #define ALC880_DIGOUT_NID	0x06
 #define ALC880_DIGIN_NID	0x0a
 #define ALC880_DIGIN_NID	0x0a
 
 
-static struct hda_input_mux alc880_capture_source = {
+static const struct hda_input_mux alc880_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -2341,7 +2618,7 @@ static struct hda_input_mux alc880_capture_source = {
 
 
 /* channel source setting (2/6 channel selection for 3-stack) */
 /* channel source setting (2/6 channel selection for 3-stack) */
 /* 2ch mode */
 /* 2ch mode */
-static struct hda_verb alc880_threestack_ch2_init[] = {
+static const struct hda_verb alc880_threestack_ch2_init[] = {
 	/* set line-in to input, mute it */
 	/* set line-in to input, mute it */
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -2352,7 +2629,7 @@ static struct hda_verb alc880_threestack_ch2_init[] = {
 };
 };
 
 
 /* 6ch mode */
 /* 6ch mode */
-static struct hda_verb alc880_threestack_ch6_init[] = {
+static const struct hda_verb alc880_threestack_ch6_init[] = {
 	/* set line-in to output, unmute it */
 	/* set line-in to output, unmute it */
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -2362,12 +2639,12 @@ static struct hda_verb alc880_threestack_ch6_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc880_threestack_modes[2] = {
+static const struct hda_channel_mode alc880_threestack_modes[2] = {
 	{ 2, alc880_threestack_ch2_init },
 	{ 2, alc880_threestack_ch2_init },
 	{ 6, alc880_threestack_ch6_init },
 	{ 6, alc880_threestack_ch6_init },
 };
 };
 
 
-static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
+static const struct snd_kcontrol_new alc880_three_stack_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
@@ -2512,14 +2789,14 @@ static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
 	}
 	}
 
 
 #define DEFINE_CAPMIX(num) \
 #define DEFINE_CAPMIX(num) \
-static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
 	_DEFINE_CAPMIX(num),				      \
 	_DEFINE_CAPMIX(num),				      \
 	_DEFINE_CAPSRC(num),				      \
 	_DEFINE_CAPSRC(num),				      \
 	{ } /* end */					      \
 	{ } /* end */					      \
 }
 }
 
 
 #define DEFINE_CAPMIX_NOSRC(num) \
 #define DEFINE_CAPMIX_NOSRC(num) \
-static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
+static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
 	_DEFINE_CAPMIX(num),					    \
 	_DEFINE_CAPMIX(num),					    \
 	{ } /* end */						    \
 	{ } /* end */						    \
 }
 }
@@ -2542,7 +2819,7 @@ DEFINE_CAPMIX_NOSRC(3);
  */
  */
 
 
 /* additional mixers to alc880_three_stack_mixer */
 /* additional mixers to alc880_three_stack_mixer */
-static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
+static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
 	HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
 	{ } /* end */
 	{ } /* end */
@@ -2550,7 +2827,7 @@ static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
 
 
 /* channel source setting (6/8 channel selection for 5-stack) */
 /* channel source setting (6/8 channel selection for 5-stack) */
 /* 6ch mode */
 /* 6ch mode */
-static struct hda_verb alc880_fivestack_ch6_init[] = {
+static const struct hda_verb alc880_fivestack_ch6_init[] = {
 	/* set line-in to input, mute it */
 	/* set line-in to input, mute it */
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -2558,14 +2835,14 @@ static struct hda_verb alc880_fivestack_ch6_init[] = {
 };
 };
 
 
 /* 8ch mode */
 /* 8ch mode */
-static struct hda_verb alc880_fivestack_ch8_init[] = {
+static const struct hda_verb alc880_fivestack_ch8_init[] = {
 	/* set line-in to output, unmute it */
 	/* set line-in to output, unmute it */
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc880_fivestack_modes[2] = {
+static const struct hda_channel_mode alc880_fivestack_modes[2] = {
 	{ 6, alc880_fivestack_ch6_init },
 	{ 6, alc880_fivestack_ch6_init },
 	{ 8, alc880_fivestack_ch8_init },
 	{ 8, alc880_fivestack_ch8_init },
 };
 };
@@ -2580,12 +2857,12 @@ static struct hda_channel_mode alc880_fivestack_modes[2] = {
  *   Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
  *   Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
  */
  */
 
 
-static hda_nid_t alc880_6st_dac_nids[4] = {
+static const hda_nid_t alc880_6st_dac_nids[4] = {
 	/* front, rear, clfe, rear_surr */
 	/* front, rear, clfe, rear_surr */
 	0x02, 0x03, 0x04, 0x05
 	0x02, 0x03, 0x04, 0x05
 };
 };
 
 
-static struct hda_input_mux alc880_6stack_capture_source = {
+static const struct hda_input_mux alc880_6stack_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -2596,11 +2873,11 @@ static struct hda_input_mux alc880_6stack_capture_source = {
 };
 };
 
 
 /* fixed 8-channels */
 /* fixed 8-channels */
-static struct hda_channel_mode alc880_sixstack_modes[1] = {
+static const struct hda_channel_mode alc880_sixstack_modes[1] = {
 	{ 8, NULL },
 	{ 8, NULL },
 };
 };
 
 
-static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
+static const struct snd_kcontrol_new alc880_six_stack_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2655,18 +2932,18 @@ static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
  * haven't setup any initialization verbs for these yet...
  * haven't setup any initialization verbs for these yet...
  */
  */
 
 
-static hda_nid_t alc880_w810_dac_nids[3] = {
+static const hda_nid_t alc880_w810_dac_nids[3] = {
 	/* front, rear/surround, clfe */
 	/* front, rear/surround, clfe */
 	0x02, 0x03, 0x04
 	0x02, 0x03, 0x04
 };
 };
 
 
 /* fixed 6 channels */
 /* fixed 6 channels */
-static struct hda_channel_mode alc880_w810_modes[1] = {
+static const struct hda_channel_mode alc880_w810_modes[1] = {
 	{ 6, NULL }
 	{ 6, NULL }
 };
 };
 
 
 /* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
 /* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
-static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
+static const struct snd_kcontrol_new alc880_w810_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2688,17 +2965,17 @@ static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
  *                 Line = 0x1a
  *                 Line = 0x1a
  */
  */
 
 
-static hda_nid_t alc880_z71v_dac_nids[1] = {
+static const hda_nid_t alc880_z71v_dac_nids[1] = {
 	0x02
 	0x02
 };
 };
 #define ALC880_Z71V_HP_DAC	0x03
 #define ALC880_Z71V_HP_DAC	0x03
 
 
 /* fixed 2 channels */
 /* fixed 2 channels */
-static struct hda_channel_mode alc880_2_jack_modes[1] = {
+static const struct hda_channel_mode alc880_2_jack_modes[1] = {
 	{ 2, NULL }
 	{ 2, NULL }
 };
 };
 
 
-static struct snd_kcontrol_new alc880_z71v_mixer[] = {
+static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2718,12 +2995,12 @@ static struct snd_kcontrol_new alc880_z71v_mixer[] = {
  * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
  * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
  */
  */
 
 
-static hda_nid_t alc880_f1734_dac_nids[1] = {
+static const hda_nid_t alc880_f1734_dac_nids[1] = {
 	0x03
 	0x03
 };
 };
 #define ALC880_F1734_HP_DAC	0x02
 #define ALC880_F1734_HP_DAC	0x02
 
 
-static struct snd_kcontrol_new alc880_f1734_mixer[] = {
+static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2735,7 +3012,7 @@ static struct snd_kcontrol_new alc880_f1734_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_input_mux alc880_f1734_capture_source = {
+static const struct hda_input_mux alc880_f1734_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x1 },
 		{ "Mic", 0x1 },
@@ -2755,7 +3032,7 @@ static struct hda_input_mux alc880_f1734_capture_source = {
 #define alc880_asus_dac_nids	alc880_w810_dac_nids	/* identical with w810 */
 #define alc880_asus_dac_nids	alc880_w810_dac_nids	/* identical with w810 */
 #define alc880_asus_modes	alc880_threestack_modes	/* 2/6 channel mode */
 #define alc880_asus_modes	alc880_threestack_modes	/* 2/6 channel mode */
 
 
-static struct snd_kcontrol_new alc880_asus_mixer[] = {
+static const struct snd_kcontrol_new alc880_asus_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2789,14 +3066,14 @@ static struct snd_kcontrol_new alc880_asus_mixer[] = {
  */
  */
 
 
 /* additional mixers to alc880_asus_mixer */
 /* additional mixers to alc880_asus_mixer */
-static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
+static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
 	HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
 	HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
 	HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
 	HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
 /* TCL S700 */
 /* TCL S700 */
-static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
+static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -2810,7 +3087,7 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
 };
 };
 
 
 /* Uniwill */
 /* Uniwill */
-static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
+static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2837,7 +3114,7 @@ static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
+static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2851,7 +3128,7 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
+static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -2878,7 +3155,6 @@ static const char * const alc_slave_vols[] = {
 	"Speaker Playback Volume",
 	"Speaker Playback Volume",
 	"Mono Playback Volume",
 	"Mono Playback Volume",
 	"Line-Out Playback Volume",
 	"Line-Out Playback Volume",
-	"PCM Playback Volume",
 	NULL,
 	NULL,
 };
 };
 
 
@@ -2893,7 +3169,6 @@ static const char * const alc_slave_sws[] = {
 	"Mono Playback Switch",
 	"Mono Playback Switch",
 	"IEC958 Playback Switch",
 	"IEC958 Playback Switch",
 	"Line-Out Playback Switch",
 	"Line-Out Playback Switch",
-	"PCM Playback Switch",
 	NULL,
 	NULL,
 };
 };
 
 
@@ -2914,7 +3189,7 @@ static void alc_free_kctls(struct hda_codec *codec);
 
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
 /* additional beep mixers; the actual parameters are overwritten at build */
-static struct snd_kcontrol_new alc_beep_mixer[] = {
+static const struct snd_kcontrol_new alc_beep_mixer[] = {
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
 	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
 	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
 	{ } /* end */
 	{ } /* end */
@@ -2925,7 +3200,7 @@ static int alc_build_controls(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	struct snd_kcontrol *kctl = NULL;
 	struct snd_kcontrol *kctl = NULL;
-	struct snd_kcontrol_new *knew;
+	const struct snd_kcontrol_new *knew;
 	int i, j, err;
 	int i, j, err;
 	unsigned int u;
 	unsigned int u;
 	hda_nid_t nid;
 	hda_nid_t nid;
@@ -2962,7 +3237,7 @@ static int alc_build_controls(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 	/* create beep controls if needed */
 	/* create beep controls if needed */
 	if (spec->beep_amp) {
 	if (spec->beep_amp) {
-		struct snd_kcontrol_new *knew;
+		const struct snd_kcontrol_new *knew;
 		for (knew = alc_beep_mixer; knew->name; knew++) {
 		for (knew = alc_beep_mixer; knew->name; knew++) {
 			struct snd_kcontrol *kctl;
 			struct snd_kcontrol *kctl;
 			kctl = snd_ctl_new1(knew, codec);
 			kctl = snd_ctl_new1(knew, codec);
@@ -3001,7 +3276,7 @@ static int alc_build_controls(struct hda_codec *codec)
 		if (!kctl)
 		if (!kctl)
 			kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
 			kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
 		for (i = 0; kctl && i < kctl->count; i++) {
 		for (i = 0; kctl && i < kctl->count; i++) {
-			hda_nid_t *nids = spec->capsrc_nids;
+			const hda_nid_t *nids = spec->capsrc_nids;
 			if (!nids)
 			if (!nids)
 				nids = spec->adc_nids;
 				nids = spec->adc_nids;
 			err = snd_hda_add_nid(codec, kctl, i, nids[i]);
 			err = snd_hda_add_nid(codec, kctl, i, nids[i]);
@@ -3079,7 +3354,7 @@ static int alc_build_controls(struct hda_codec *codec)
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc880_volume_init_verbs[] = {
+static const struct hda_verb alc880_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
 	 */
@@ -3130,7 +3405,7 @@ static struct hda_verb alc880_volume_init_verbs[] = {
  * 3-stack pin configuration:
  * 3-stack pin configuration:
  * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
  * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
  */
  */
-static struct hda_verb alc880_pin_3stack_init_verbs[] = {
+static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
 	/*
 	/*
 	 * preset connection lists of input pins
 	 * preset connection lists of input pins
 	 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
 	 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
@@ -3168,7 +3443,7 @@ static struct hda_verb alc880_pin_3stack_init_verbs[] = {
  * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
  * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
  * line-in/side = 0x1a, f-mic = 0x1b
  * line-in/side = 0x1a, f-mic = 0x1b
  */
  */
-static struct hda_verb alc880_pin_5stack_init_verbs[] = {
+static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
 	/*
 	/*
 	 * preset connection lists of input pins
 	 * preset connection lists of input pins
 	 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
 	 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
@@ -3212,7 +3487,7 @@ static struct hda_verb alc880_pin_5stack_init_verbs[] = {
  * W810 pin configuration:
  * W810 pin configuration:
  * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
  * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
  */
  */
-static struct hda_verb alc880_pin_w810_init_verbs[] = {
+static const struct hda_verb alc880_pin_w810_init_verbs[] = {
 	/* hphone/speaker input selector: front DAC */
 	/* hphone/speaker input selector: front DAC */
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
 
 
@@ -3233,7 +3508,7 @@ static struct hda_verb alc880_pin_w810_init_verbs[] = {
  * Z71V pin configuration:
  * Z71V pin configuration:
  * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
  * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
  */
  */
-static struct hda_verb alc880_pin_z71v_init_verbs[] = {
+static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -3252,7 +3527,7 @@ static struct hda_verb alc880_pin_z71v_init_verbs[] = {
  * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
  * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
  * f-mic = 0x19, line = 0x1a, HP = 0x1b
  * f-mic = 0x19, line = 0x1a, HP = 0x1b
  */
  */
-static struct hda_verb alc880_pin_6stack_init_verbs[] = {
+static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -3282,7 +3557,7 @@ static struct hda_verb alc880_pin_6stack_init_verbs[] = {
  * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
  * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
  * line = 0x1a
  * line = 0x1a
  */
  */
-static struct hda_verb alc880_uniwill_init_verbs[] = {
+static const struct hda_verb alc880_uniwill_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -3320,7 +3595,7 @@ static struct hda_verb alc880_uniwill_init_verbs[] = {
 * Uniwill P53
 * Uniwill P53
 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
  */
  */
-static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
+static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -3349,7 +3624,7 @@ static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc880_beep_init_verbs[] = {
+static const struct hda_verb alc880_beep_init_verbs[] = {
 	{ 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
 	{ 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
 	{ }
 	{ }
 };
 };
@@ -3372,11 +3647,13 @@ static void alc880_uniwill_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x16;
 	spec->autocfg.speaker_pins[0] = 0x16;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc880_uniwill_init_hook(struct hda_codec *codec)
 static void alc880_uniwill_init_hook(struct hda_codec *codec)
 {
 {
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	alc88x_simple_mic_automute(codec);
 	alc88x_simple_mic_automute(codec);
 }
 }
 
 
@@ -3391,7 +3668,7 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec,
 		alc88x_simple_mic_automute(codec);
 		alc88x_simple_mic_automute(codec);
 		break;
 		break;
 	default:
 	default:
-		alc_automute_amp_unsol_event(codec, res);
+		alc_sku_unsol_event(codec, res);
 		break;
 		break;
 	}
 	}
 }
 }
@@ -3402,6 +3679,8 @@ static void alc880_uniwill_p53_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
 static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
@@ -3426,14 +3705,14 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
 	if ((res >> 28) == ALC880_DCVOL_EVENT)
 	if ((res >> 28) == ALC880_DCVOL_EVENT)
 		alc880_uniwill_p53_dcvol_automute(codec);
 		alc880_uniwill_p53_dcvol_automute(codec);
 	else
 	else
-		alc_automute_amp_unsol_event(codec, res);
+		alc_sku_unsol_event(codec, res);
 }
 }
 
 
 /*
 /*
  * F1734 pin configuration:
  * F1734 pin configuration:
  * HP = 0x14, speaker-out = 0x15, mic = 0x18
  * HP = 0x14, speaker-out = 0x15, mic = 0x18
  */
  */
-static struct hda_verb alc880_pin_f1734_init_verbs[] = {
+static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
 	{0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
 	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
 	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -3465,7 +3744,7 @@ static struct hda_verb alc880_pin_f1734_init_verbs[] = {
  * ASUS pin configuration:
  * ASUS pin configuration:
  * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
  * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
  */
  */
-static struct hda_verb alc880_pin_asus_init_verbs[] = {
+static const struct hda_verb alc880_pin_asus_init_verbs[] = {
 	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
 	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
 	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
@@ -3499,7 +3778,7 @@ static struct hda_verb alc880_pin_asus_init_verbs[] = {
 #define alc880_gpio3_init_verbs	alc_gpio3_init_verbs
 #define alc880_gpio3_init_verbs	alc_gpio3_init_verbs
 
 
 /* Clevo m520g init */
 /* Clevo m520g init */
-static struct hda_verb alc880_pin_clevo_init_verbs[] = {
+static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
 	/* headphone output */
 	/* headphone output */
 	{0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
 	/* line-out */
 	/* line-out */
@@ -3527,7 +3806,7 @@ static struct hda_verb alc880_pin_clevo_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
+static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
 	/* change to EAPD mode */
 	/* change to EAPD mode */
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_PROC_COEF,  0x3060},
 	{0x20, AC_VERB_SET_PROC_COEF,  0x3060},
@@ -3565,12 +3844,12 @@ static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
  */
  */
 
 
 /* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
 /* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
-static hda_nid_t alc880_lg_dac_nids[3] = {
+static const hda_nid_t alc880_lg_dac_nids[3] = {
 	0x05, 0x02, 0x03
 	0x05, 0x02, 0x03
 };
 };
 
 
 /* seems analog CD is not working */
 /* seems analog CD is not working */
-static struct hda_input_mux alc880_lg_capture_source = {
+static const struct hda_input_mux alc880_lg_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x1 },
 		{ "Mic", 0x1 },
@@ -3580,34 +3859,34 @@ static struct hda_input_mux alc880_lg_capture_source = {
 };
 };
 
 
 /* 2,4,6 channel modes */
 /* 2,4,6 channel modes */
-static struct hda_verb alc880_lg_ch2_init[] = {
+static const struct hda_verb alc880_lg_ch2_init[] = {
 	/* set line-in and mic-in to input */
 	/* set line-in and mic-in to input */
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc880_lg_ch4_init[] = {
+static const struct hda_verb alc880_lg_ch4_init[] = {
 	/* set line-in to out and mic-in to input */
 	/* set line-in to out and mic-in to input */
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc880_lg_ch6_init[] = {
+static const struct hda_verb alc880_lg_ch6_init[] = {
 	/* set line-in and mic-in to output */
 	/* set line-in and mic-in to output */
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_channel_mode alc880_lg_ch_modes[3] = {
+static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
 	{ 2, alc880_lg_ch2_init },
 	{ 2, alc880_lg_ch2_init },
 	{ 4, alc880_lg_ch4_init },
 	{ 4, alc880_lg_ch4_init },
 	{ 6, alc880_lg_ch6_init },
 	{ 6, alc880_lg_ch6_init },
 };
 };
 
 
-static struct snd_kcontrol_new alc880_lg_mixer[] = {
+static const struct snd_kcontrol_new alc880_lg_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -3632,7 +3911,7 @@ static struct snd_kcontrol_new alc880_lg_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc880_lg_init_verbs[] = {
+static const struct hda_verb alc880_lg_init_verbs[] = {
 	/* set capture source to mic-in */
 	/* set capture source to mic-in */
 	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -3670,6 +3949,8 @@ static void alc880_lg_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x17;
 	spec->autocfg.speaker_pins[0] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 /*
 /*
@@ -3684,7 +3965,7 @@ static void alc880_lg_setup(struct hda_codec *codec)
  *   SPDIF-Out: 0x1e
  *   SPDIF-Out: 0x1e
  */
  */
 
 
-static struct hda_input_mux alc880_lg_lw_capture_source = {
+static const struct hda_input_mux alc880_lg_lw_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -3695,7 +3976,7 @@ static struct hda_input_mux alc880_lg_lw_capture_source = {
 
 
 #define alc880_lg_lw_modes alc880_threestack_modes
 #define alc880_lg_lw_modes alc880_threestack_modes
 
 
-static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
+static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
@@ -3720,7 +4001,7 @@ static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc880_lg_lw_init_verbs[] = {
+static const struct hda_verb alc880_lg_lw_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
 	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
 	{0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
 	{0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
@@ -3754,9 +4035,11 @@ static void alc880_lg_lw_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
+static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -3766,7 +4049,7 @@ static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_input_mux alc880_medion_rim_capture_source = {
+static const struct hda_input_mux alc880_medion_rim_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -3774,7 +4057,7 @@ static struct hda_input_mux alc880_medion_rim_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_verb alc880_medion_rim_init_verbs[] = {
+static const struct hda_verb alc880_medion_rim_init_verbs[] = {
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -3801,7 +4084,7 @@ static struct hda_verb alc880_medion_rim_init_verbs[] = {
 static void alc880_medion_rim_automute(struct hda_codec *codec)
 static void alc880_medion_rim_automute(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	/* toggle EAPD */
 	/* toggle EAPD */
 	if (spec->jack_present)
 	if (spec->jack_present)
 		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
 		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
@@ -3825,10 +4108,12 @@ static void alc880_medion_rim_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x1b;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list alc880_loopbacks[] = {
+static const struct hda_amp_list alc880_loopbacks[] = {
 	{ 0x0b, HDA_INPUT, 0 },
 	{ 0x0b, HDA_INPUT, 0 },
 	{ 0x0b, HDA_INPUT, 1 },
 	{ 0x0b, HDA_INPUT, 1 },
 	{ 0x0b, HDA_INPUT, 2 },
 	{ 0x0b, HDA_INPUT, 2 },
@@ -3837,7 +4122,7 @@ static struct hda_amp_list alc880_loopbacks[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_amp_list alc880_lg_loopbacks[] = {
+static const struct hda_amp_list alc880_lg_loopbacks[] = {
 	{ 0x0b, HDA_INPUT, 1 },
 	{ 0x0b, HDA_INPUT, 1 },
 	{ 0x0b, HDA_INPUT, 6 },
 	{ 0x0b, HDA_INPUT, 6 },
 	{ 0x0b, HDA_INPUT, 7 },
 	{ 0x0b, HDA_INPUT, 7 },
@@ -4009,7 +4294,7 @@ static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 	return 0;
 }
 }
 
 
-static struct hda_pcm_stream dualmic_pcm_analog_capture = {
+static const struct hda_pcm_stream dualmic_pcm_analog_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -4022,7 +4307,7 @@ static struct hda_pcm_stream dualmic_pcm_analog_capture = {
 
 
 /*
 /*
  */
  */
-static struct hda_pcm_stream alc880_pcm_analog_playback = {
+static const struct hda_pcm_stream alc880_pcm_analog_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.channels_max = 8,
@@ -4034,21 +4319,21 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream alc880_pcm_analog_capture = {
+static const struct hda_pcm_stream alc880_pcm_analog_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
 	/* NID is set in alc_build_pcms */
 	/* NID is set in alc_build_pcms */
 };
 };
 
 
-static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
+static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
 	/* NID is set in alc_build_pcms */
 	/* NID is set in alc_build_pcms */
 };
 };
 
 
-static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
+static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
 	.substreams = 2, /* can be overridden */
 	.substreams = 2, /* can be overridden */
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -4059,7 +4344,7 @@ static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream alc880_pcm_digital_playback = {
+static const struct hda_pcm_stream alc880_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -4072,7 +4357,7 @@ static struct hda_pcm_stream alc880_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream alc880_pcm_digital_capture = {
+static const struct hda_pcm_stream alc880_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -4080,7 +4365,7 @@ static struct hda_pcm_stream alc880_pcm_digital_capture = {
 };
 };
 
 
 /* Used by alc_build_pcms to flag that a PCM has no playback stream */
 /* Used by alc_build_pcms to flag that a PCM has no playback stream */
-static struct hda_pcm_stream alc_pcm_null_stream = {
+static const struct hda_pcm_stream alc_pcm_null_stream = {
 	.substreams = 0,
 	.substreams = 0,
 	.channels_min = 0,
 	.channels_min = 0,
 	.channels_max = 0,
 	.channels_max = 0,
@@ -4174,7 +4459,7 @@ static int alc_build_pcms(struct hda_codec *codec)
 				alc_pcm_null_stream;
 				alc_pcm_null_stream;
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
 		}
 		}
-		if (spec->num_adc_nids > 1) {
+		if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) {
 			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
 			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
 				*spec->stream_analog_alt_capture;
 				*spec->stream_analog_alt_capture;
 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
@@ -4193,6 +4478,10 @@ static int alc_build_pcms(struct hda_codec *codec)
 
 
 static inline void alc_shutup(struct hda_codec *codec)
 static inline void alc_shutup(struct hda_codec *codec)
 {
 {
+	struct alc_spec *spec = codec->spec;
+
+	if (spec && spec->shutup)
+		spec->shutup(codec);
 	snd_hda_shutup_pins(codec);
 	snd_hda_shutup_pins(codec);
 }
 }
 
 
@@ -4226,28 +4515,7 @@ static void alc_free(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static void alc_power_eapd(struct hda_codec *codec)
 static void alc_power_eapd(struct hda_codec *codec)
 {
 {
-	/* We currently only handle front, HP */
-	switch (codec->vendor_id) {
-	case 0x10ec0260:
-		set_eapd(codec, 0x0f, 0);
-		set_eapd(codec, 0x10, 0);
-		break;
-	case 0x10ec0262:
-	case 0x10ec0267:
-	case 0x10ec0268:
-	case 0x10ec0269:
-	case 0x10ec0270:
-	case 0x10ec0272:
-	case 0x10ec0660:
-	case 0x10ec0662:
-	case 0x10ec0663:
-	case 0x10ec0665:
-	case 0x10ec0862:
-	case 0x10ec0889:
-		set_eapd(codec, 0x14, 0);
-		set_eapd(codec, 0x15, 0);
-		break;
-	}
+	alc_auto_setup_eapd(codec, false);
 }
 }
 
 
 static int alc_suspend(struct hda_codec *codec, pm_message_t state)
 static int alc_suspend(struct hda_codec *codec, pm_message_t state)
@@ -4263,6 +4531,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state)
 #ifdef SND_HDA_NEEDS_RESUME
 #ifdef SND_HDA_NEEDS_RESUME
 static int alc_resume(struct hda_codec *codec)
 static int alc_resume(struct hda_codec *codec)
 {
 {
+	msleep(150); /* to avoid pop noise */
 	codec->patch_ops.init(codec);
 	codec->patch_ops.init(codec);
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_cache(codec);
 	snd_hda_codec_resume_cache(codec);
@@ -4273,7 +4542,7 @@ static int alc_resume(struct hda_codec *codec)
 
 
 /*
 /*
  */
  */
-static struct hda_codec_ops alc_patch_ops = {
+static const struct hda_codec_ops alc_patch_ops = {
 	.build_controls = alc_build_controls,
 	.build_controls = alc_build_controls,
 	.build_pcms = alc_build_pcms,
 	.build_pcms = alc_build_pcms,
 	.init = alc_init,
 	.init = alc_init,
@@ -4308,11 +4577,11 @@ static int alc_codec_rename(struct hda_codec *codec, const char *name)
  * enum controls.
  * enum controls.
  */
  */
 #ifdef CONFIG_SND_DEBUG
 #ifdef CONFIG_SND_DEBUG
-static hda_nid_t alc880_test_dac_nids[4] = {
+static const hda_nid_t alc880_test_dac_nids[4] = {
 	0x02, 0x03, 0x04, 0x05
 	0x02, 0x03, 0x04, 0x05
 };
 };
 
 
-static struct hda_input_mux alc880_test_capture_source = {
+static const struct hda_input_mux alc880_test_capture_source = {
 	.num_items = 7,
 	.num_items = 7,
 	.items = {
 	.items = {
 		{ "In-1", 0x0 },
 		{ "In-1", 0x0 },
@@ -4325,7 +4594,7 @@ static struct hda_input_mux alc880_test_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_channel_mode alc880_test_modes[4] = {
+static const struct hda_channel_mode alc880_test_modes[4] = {
 	{ 2, NULL },
 	{ 2, NULL },
 	{ 4, NULL },
 	{ 4, NULL },
 	{ 6, NULL },
 	{ 6, NULL },
@@ -4335,7 +4604,7 @@ static struct hda_channel_mode alc880_test_modes[4] = {
 static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
 static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_info *uinfo)
 				 struct snd_ctl_elem_info *uinfo)
 {
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"N/A", "Line Out", "HP Out",
 		"N/A", "Line Out", "HP Out",
 		"In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
 		"In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
 	};
 	};
@@ -4380,7 +4649,7 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
 {
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
 	hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
-	static unsigned int ctls[] = {
+	static const unsigned int ctls[] = {
 		0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
 		0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
 		AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
 		AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
 		AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
 		AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
@@ -4410,7 +4679,7 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
 static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
 static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_info *uinfo)
 				 struct snd_ctl_elem_info *uinfo)
 {
 {
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"Front", "Surround", "CLFE", "Side"
 		"Front", "Surround", "CLFE", "Side"
 	};
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -4471,7 +4740,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
 			.private_value = nid	       \
 			.private_value = nid	       \
 			}
 			}
 
 
-static struct snd_kcontrol_new alc880_test_mixer[] = {
+static const struct snd_kcontrol_new alc880_test_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
@@ -4512,7 +4781,7 @@ static struct snd_kcontrol_new alc880_test_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc880_test_init_verbs[] = {
+static const struct hda_verb alc880_test_init_verbs[] = {
 	/* Unmute inputs of 0x0c - 0x0f */
 	/* Unmute inputs of 0x0c - 0x0f */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -4596,7 +4865,7 @@ static const char * const alc880_models[ALC880_MODEL_LAST] = {
 	[ALC880_AUTO]		= "auto",
 	[ALC880_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk alc880_cfg_tbl[] = {
+static const struct snd_pci_quirk alc880_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
 	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
 	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
 	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
 	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
 	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
@@ -4676,7 +4945,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = {
 /*
 /*
  * ALC880 codec presets
  * ALC880 codec presets
  */
  */
-static struct alc_config_preset alc880_presets[] = {
+static const struct alc_config_preset alc880_presets[] = {
 	[ALC880_3ST] = {
 	[ALC880_3ST] = {
 		.mixers = { alc880_three_stack_mixer },
 		.mixers = { alc880_three_stack_mixer },
 		.init_verbs = { alc880_volume_init_verbs,
 		.init_verbs = { alc880_volume_init_verbs,
@@ -4794,7 +5063,7 @@ static struct alc_config_preset alc880_presets[] = {
 		.input_mux = &alc880_f1734_capture_source,
 		.input_mux = &alc880_f1734_capture_source,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
 		.setup = alc880_uniwill_p53_setup,
 		.setup = alc880_uniwill_p53_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC880_ASUS] = {
 	[ALC880_ASUS] = {
 		.mixers = { alc880_asus_mixer },
 		.mixers = { alc880_asus_mixer },
@@ -4885,7 +5154,7 @@ static struct alc_config_preset alc880_presets[] = {
 		.input_mux = &alc880_capture_source,
 		.input_mux = &alc880_capture_source,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
 		.setup = alc880_uniwill_p53_setup,
 		.setup = alc880_uniwill_p53_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC880_FUJITSU] = {
 	[ALC880_FUJITSU] = {
 		.mixers = { alc880_fujitsu_mixer },
 		.mixers = { alc880_fujitsu_mixer },
@@ -4900,7 +5169,7 @@ static struct alc_config_preset alc880_presets[] = {
 		.input_mux = &alc880_capture_source,
 		.input_mux = &alc880_capture_source,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
 		.unsol_event = alc880_uniwill_p53_unsol_event,
 		.setup = alc880_uniwill_p53_setup,
 		.setup = alc880_uniwill_p53_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC880_CLEVO] = {
 	[ALC880_CLEVO] = {
 		.mixers = { alc880_three_stack_mixer },
 		.mixers = { alc880_three_stack_mixer },
@@ -4925,9 +5194,9 @@ static struct alc_config_preset alc880_presets[] = {
 		.channel_mode = alc880_lg_ch_modes,
 		.channel_mode = alc880_lg_ch_modes,
 		.need_dac_fix = 1,
 		.need_dac_fix = 1,
 		.input_mux = &alc880_lg_capture_source,
 		.input_mux = &alc880_lg_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc880_lg_setup,
 		.setup = alc880_lg_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 		.loopbacks = alc880_lg_loopbacks,
 		.loopbacks = alc880_lg_loopbacks,
 #endif
 #endif
@@ -4942,9 +5211,9 @@ static struct alc_config_preset alc880_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
 		.num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
 		.channel_mode = alc880_lg_lw_modes,
 		.channel_mode = alc880_lg_lw_modes,
 		.input_mux = &alc880_lg_lw_capture_source,
 		.input_mux = &alc880_lg_lw_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc880_lg_lw_setup,
 		.setup = alc880_lg_lw_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC880_MEDION_RIM] = {
 	[ALC880_MEDION_RIM] = {
 		.mixers = { alc880_medion_rim_mixer },
 		.mixers = { alc880_medion_rim_mixer },
@@ -4984,20 +5253,25 @@ enum {
 	ALC_CTL_WIDGET_MUTE,
 	ALC_CTL_WIDGET_MUTE,
 	ALC_CTL_BIND_MUTE,
 	ALC_CTL_BIND_MUTE,
 };
 };
-static struct snd_kcontrol_new alc880_control_templates[] = {
+static const struct snd_kcontrol_new alc880_control_templates[] = {
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	HDA_BIND_MUTE(NULL, 0, 0, 0),
 	HDA_BIND_MUTE(NULL, 0, 0, 0),
 };
 };
 
 
+static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
+{
+	snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
+	return snd_array_new(&spec->kctls);
+}
+
 /* add dynamic controls */
 /* add dynamic controls */
 static int add_control(struct alc_spec *spec, int type, const char *name,
 static int add_control(struct alc_spec *spec, int type, const char *name,
 		       int cidx, unsigned long val)
 		       int cidx, unsigned long val)
 {
 {
 	struct snd_kcontrol_new *knew;
 	struct snd_kcontrol_new *knew;
 
 
-	snd_array_init(&spec->kctls, sizeof(*knew), 32);
-	knew = snd_array_new(&spec->kctls);
+	knew = alc_kcontrol_new(spec);
 	if (!knew)
 	if (!knew)
 		return -ENOMEM;
 		return -ENOMEM;
 	*knew = alc880_control_templates[type];
 	*knew = alc880_control_templates[type];
@@ -5055,7 +5329,7 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
 		nid = cfg->line_out_pins[i];
 		nid = cfg->line_out_pins[i];
 		if (alc880_is_fixed_pin(nid)) {
 		if (alc880_is_fixed_pin(nid)) {
 			int idx = alc880_fixed_pin_idx(nid);
 			int idx = alc880_fixed_pin_idx(nid);
-			spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
+			spec->private_dac_nids[i] = alc880_idx_to_dac(idx);
 			assigned[idx] = 1;
 			assigned[idx] = 1;
 		}
 		}
 	}
 	}
@@ -5067,7 +5341,7 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
 		/* search for an empty channel */
 		/* search for an empty channel */
 		for (j = 0; j < cfg->line_outs; j++) {
 		for (j = 0; j < cfg->line_outs; j++) {
 			if (!assigned[j]) {
 			if (!assigned[j]) {
-				spec->multiout.dac_nids[i] =
+				spec->private_dac_nids[i] =
 					alc880_idx_to_dac(j);
 					alc880_idx_to_dac(j);
 				assigned[j] = 1;
 				assigned[j] = 1;
 				break;
 				break;
@@ -5078,10 +5352,13 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
 	return 0;
 	return 0;
 }
 }
 
 
-static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
+static const char *alc_get_line_out_pfx(struct alc_spec *spec,
 					bool can_be_master)
 					bool can_be_master)
 {
 {
-	if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master)
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+
+	if (cfg->line_outs == 1 && !spec->multi_ios &&
+	    !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
 		return "Master";
 		return "Master";
 
 
 	switch (cfg->line_out_type) {
 	switch (cfg->line_out_type) {
@@ -5092,7 +5369,7 @@ static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
 	case AUTO_PIN_HP_OUT:
 	case AUTO_PIN_HP_OUT:
 		return "Headphone";
 		return "Headphone";
 	default:
 	default:
-		if (cfg->line_outs == 1)
+		if (cfg->line_outs == 1 && !spec->multi_ios)
 			return "PCM";
 			return "PCM";
 		break;
 		break;
 	}
 	}
@@ -5106,11 +5383,15 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
 	static const char * const chname[4] = {
 	static const char * const chname[4] = {
 		"Front", "Surround", NULL /*CLFE*/, "Side"
 		"Front", "Surround", NULL /*CLFE*/, "Side"
 	};
 	};
-	const char *pfx = alc_get_line_out_pfx(cfg, false);
+	const char *pfx = alc_get_line_out_pfx(spec, false);
 	hda_nid_t nid;
 	hda_nid_t nid;
-	int i, err;
+	int i, err, noutputs;
 
 
-	for (i = 0; i < cfg->line_outs; i++) {
+	noutputs = cfg->line_outs;
+	if (spec->multi_ios > 0)
+		noutputs += spec->multi_ios;
+
+	for (i = 0; i < noutputs; i++) {
 		if (!spec->multiout.dac_nids[i])
 		if (!spec->multiout.dac_nids[i])
 			continue;
 			continue;
 		nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
 		nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
@@ -5376,6 +5657,8 @@ static void alc880_auto_init_input_src(struct hda_codec *codec)
 	}
 	}
 }
 }
 
 
+static int alc_auto_add_multi_channel_mode(struct hda_codec *codec);
+
 /* parse the BIOS configuration and set up the alc_spec */
 /* parse the BIOS configuration and set up the alc_spec */
 /* return 1 if successful, 0 if the proper config is not found,
 /* return 1 if successful, 0 if the proper config is not found,
  * or a negative error code
  * or a negative error code
@@ -5384,7 +5667,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	int err;
 	int err;
-	static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
 
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc880_ignore);
 					   alc880_ignore);
@@ -5394,6 +5677,9 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
 		return 0; /* can't find valid BIOS pin config */
 		return 0; /* can't find valid BIOS pin config */
 
 
 	err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
 	err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = alc_auto_add_multi_channel_mode(codec);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 	err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
 	err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
@@ -5467,6 +5753,12 @@ static void fixup_automic_adc(struct hda_codec *codec)
 			spec->capsrc_nids += i;
 			spec->capsrc_nids += i;
 		spec->adc_nids += i;
 		spec->adc_nids += i;
 		spec->num_adc_nids = 1;
 		spec->num_adc_nids = 1;
+		/* optional dock-mic */
+		eidx = get_connection_index(codec, cap, spec->dock_mic.pin);
+		if (eidx < 0)
+			spec->dock_mic.pin = 0;
+		else
+			spec->dock_mic.mux_idx = eidx;
 		return;
 		return;
 	}
 	}
 	snd_printd(KERN_INFO "hda_codec: %s: "
 	snd_printd(KERN_INFO "hda_codec: %s: "
@@ -5494,6 +5786,8 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	int i;
 	int i;
 
 
+	if (!pin)
+		return 0;
 	for (i = 0; i < spec->num_adc_nids; i++) {
 	for (i = 0; i < spec->num_adc_nids; i++) {
 		hda_nid_t cap = spec->capsrc_nids ?
 		hda_nid_t cap = spec->capsrc_nids ?
 			spec->capsrc_nids[i] : spec->adc_nids[i];
 			spec->capsrc_nids[i] : spec->adc_nids[i];
@@ -5534,6 +5828,7 @@ static void fixup_dual_adc_switch(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	init_capsrc_for_pin(codec, spec->ext_mic.pin);
 	init_capsrc_for_pin(codec, spec->ext_mic.pin);
+	init_capsrc_for_pin(codec, spec->dock_mic.pin);
 	init_capsrc_for_pin(codec, spec->int_mic.pin);
 	init_capsrc_for_pin(codec, spec->int_mic.pin);
 }
 }
 
 
@@ -5550,7 +5845,7 @@ static void alc_init_special_input_src(struct hda_codec *codec)
 static void set_capture_mixer(struct hda_codec *codec)
 static void set_capture_mixer(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	static struct snd_kcontrol_new *caps[2][3] = {
+	static const struct snd_kcontrol_new *caps[2][3] = {
 		{ alc_capture_mixer_nosrc1,
 		{ alc_capture_mixer_nosrc1,
 		  alc_capture_mixer_nosrc2,
 		  alc_capture_mixer_nosrc2,
 		  alc_capture_mixer_nosrc3 },
 		  alc_capture_mixer_nosrc3 },
@@ -5576,7 +5871,7 @@ static void set_capture_mixer(struct hda_codec *codec)
 }
 }
 
 
 /* fill adc_nids (and capsrc_nids) containing all active input pins */
 /* fill adc_nids (and capsrc_nids) containing all active input pins */
-static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
+static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids,
 				 int num_nids)
 				 int num_nids)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
@@ -5642,10 +5937,11 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
 #define set_beep_amp(spec, nid, idx, dir) \
 #define set_beep_amp(spec, nid, idx, dir) \
 	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
 	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
 
 
-static struct snd_pci_quirk beep_white_list[] = {
+static const struct snd_pci_quirk beep_white_list[] = {
 	SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
 	SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
 	SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
 	SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
 	SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
 	SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
+	SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
 	SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
 	SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
 	{}
 	{}
 };
 };
@@ -5753,17 +6049,17 @@ static int patch_alc880(struct hda_codec *codec)
  * ALC260 support
  * ALC260 support
  */
  */
 
 
-static hda_nid_t alc260_dac_nids[1] = {
+static const hda_nid_t alc260_dac_nids[1] = {
 	/* front */
 	/* front */
 	0x02,
 	0x02,
 };
 };
 
 
-static hda_nid_t alc260_adc_nids[1] = {
+static const hda_nid_t alc260_adc_nids[1] = {
 	/* ADC0 */
 	/* ADC0 */
 	0x04,
 	0x04,
 };
 };
 
 
-static hda_nid_t alc260_adc_nids_alt[1] = {
+static const hda_nid_t alc260_adc_nids_alt[1] = {
 	/* ADC1 */
 	/* ADC1 */
 	0x05,
 	0x05,
 };
 };
@@ -5771,7 +6067,7 @@ static hda_nid_t alc260_adc_nids_alt[1] = {
 /* NIDs used when simultaneous access to both ADCs makes sense.  Note that
 /* NIDs used when simultaneous access to both ADCs makes sense.  Note that
  * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
  * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
  */
  */
-static hda_nid_t alc260_dual_adc_nids[2] = {
+static const hda_nid_t alc260_dual_adc_nids[2] = {
 	/* ADC0, ADC1 */
 	/* ADC0, ADC1 */
 	0x04, 0x05
 	0x04, 0x05
 };
 };
@@ -5779,7 +6075,7 @@ static hda_nid_t alc260_dual_adc_nids[2] = {
 #define ALC260_DIGOUT_NID	0x03
 #define ALC260_DIGOUT_NID	0x03
 #define ALC260_DIGIN_NID	0x06
 #define ALC260_DIGIN_NID	0x06
 
 
-static struct hda_input_mux alc260_capture_source = {
+static const struct hda_input_mux alc260_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -5795,7 +6091,7 @@ static struct hda_input_mux alc260_capture_source = {
  * recording the mixer output on the second ADC (ADC0 doesn't have a
  * recording the mixer output on the second ADC (ADC0 doesn't have a
  * connection to the mixer output).
  * connection to the mixer output).
  */
  */
-static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
+static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
 	{
 	{
 		.num_items = 3,
 		.num_items = 3,
 		.items = {
 		.items = {
@@ -5819,7 +6115,7 @@ static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
 /* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
 /* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
  * the Fujitsu S702x, but jacks are marked differently.
  * the Fujitsu S702x, but jacks are marked differently.
  */
  */
-static struct hda_input_mux alc260_acer_capture_sources[2] = {
+static const struct hda_input_mux alc260_acer_capture_sources[2] = {
 	{
 	{
 		.num_items = 4,
 		.num_items = 4,
 		.items = {
 		.items = {
@@ -5842,7 +6138,7 @@ static struct hda_input_mux alc260_acer_capture_sources[2] = {
 };
 };
 
 
 /* Maxdata Favorit 100XS */
 /* Maxdata Favorit 100XS */
-static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
+static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
 	{
 	{
 		.num_items = 2,
 		.num_items = 2,
 		.items = {
 		.items = {
@@ -5866,7 +6162,7 @@ static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
  * element which allows changing the channel mode, so the verb list is
  * element which allows changing the channel mode, so the verb list is
  * never used.
  * never used.
  */
  */
-static struct hda_channel_mode alc260_modes[1] = {
+static const struct hda_channel_mode alc260_modes[1] = {
 	{ 2, NULL },
 	{ 2, NULL },
 };
 };
 
 
@@ -5880,7 +6176,7 @@ static struct hda_channel_mode alc260_modes[1] = {
  * acer: acer + capture
  * acer: acer + capture
  */
  */
 
 
-static struct snd_kcontrol_new alc260_base_output_mixer[] = {
+static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
@@ -5890,7 +6186,7 @@ static struct snd_kcontrol_new alc260_base_output_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc260_input_mixer[] = {
+static const struct snd_kcontrol_new alc260_input_mixer[] = {
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 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_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
@@ -5903,21 +6199,14 @@ static struct snd_kcontrol_new alc260_input_mixer[] = {
 };
 };
 
 
 /* update HP, line and mono out pins according to the master switch */
 /* update HP, line and mono out pins according to the master switch */
-static void alc260_hp_master_update(struct hda_codec *codec,
-				    hda_nid_t hp, hda_nid_t line,
-				    hda_nid_t mono)
+static void alc260_hp_master_update(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	unsigned int val = spec->master_sw ? PIN_HP : 0;
-	/* change HP and line-out pins */
-	snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    val);
-	snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    val);
-	/* mono (speaker) depending on the HP jack sense */
-	val = (val && !spec->jack_present) ? PIN_OUT : 0;
-	snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    val);
+
+	/* change HP pins */
+	do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
+		    spec->autocfg.hp_pins, spec->master_mute, true);
+	update_speakers(codec);
 }
 }
 
 
 static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
 static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
@@ -5925,7 +6214,7 @@ static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
 {
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	*ucontrol->value.integer.value = spec->master_sw;
+	*ucontrol->value.integer.value = !spec->master_mute;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -5934,20 +6223,16 @@ static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 {
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	int val = !!*ucontrol->value.integer.value;
-	hda_nid_t hp, line, mono;
+	int val = !*ucontrol->value.integer.value;
 
 
-	if (val == spec->master_sw)
+	if (val == spec->master_mute)
 		return 0;
 		return 0;
-	spec->master_sw = val;
-	hp = (kcontrol->private_value >> 16) & 0xff;
-	line = (kcontrol->private_value >> 8) & 0xff;
-	mono = kcontrol->private_value & 0xff;
-	alc260_hp_master_update(codec, hp, line, mono);
+	spec->master_mute = val;
+	alc260_hp_master_update(codec);
 	return 1;
 	return 1;
 }
 }
 
 
-static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
+static const struct snd_kcontrol_new alc260_hp_output_mixer[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
 		.name = "Master Playback Switch",
@@ -5955,7 +6240,6 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
 		.info = snd_ctl_boolean_mono_info,
 		.info = snd_ctl_boolean_mono_info,
 		.get = alc260_hp_master_sw_get,
 		.get = alc260_hp_master_sw_get,
 		.put = alc260_hp_master_sw_put,
 		.put = alc260_hp_master_sw_put,
-		.private_value = (0x0f << 16) | (0x10 << 8) | 0x11
 	},
 	},
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
@@ -5967,26 +6251,23 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc260_hp_unsol_verbs[] = {
+static const struct hda_verb alc260_hp_unsol_verbs[] = {
 	{0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{},
 	{},
 };
 };
 
 
-static void alc260_hp_automute(struct hda_codec *codec)
+static void alc260_hp_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 
 
-	spec->jack_present = snd_hda_jack_detect(codec, 0x10);
-	alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
-}
-
-static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc260_hp_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x0f;
+	spec->autocfg.speaker_pins[0] = 0x10;
+	spec->autocfg.speaker_pins[1] = 0x11;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 }
 
 
-static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
+static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
 		.name = "Master Playback Switch",
@@ -5994,7 +6275,6 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
 		.info = snd_ctl_boolean_mono_info,
 		.info = snd_ctl_boolean_mono_info,
 		.get = alc260_hp_master_sw_get,
 		.get = alc260_hp_master_sw_get,
 		.put = alc260_hp_master_sw_put,
 		.put = alc260_hp_master_sw_put,
-		.private_value = (0x15 << 16) | (0x10 << 8) | 0x11
 	},
 	},
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
@@ -6007,7 +6287,18 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
+static void alc260_hp_3013_setup(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x10;
+	spec->autocfg.speaker_pins[1] = 0x11;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
+}
+
+static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
@@ -6017,7 +6308,7 @@ static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
 	},
 	},
 };
 };
 
 
-static struct hda_bind_ctls alc260_dc7600_bind_switch = {
+static const struct hda_bind_ctls alc260_dc7600_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
@@ -6026,7 +6317,7 @@ static struct hda_bind_ctls alc260_dc7600_bind_switch = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
+static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
 	HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
 	HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
@@ -6034,49 +6325,27 @@ static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
+static const struct hda_verb alc260_hp_3013_unsol_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{},
 	{},
 };
 };
 
 
-static void alc260_hp_3013_automute(struct hda_codec *codec)
+static void alc260_hp_3012_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 
 
-	spec->jack_present = snd_hda_jack_detect(codec, 0x15);
-	alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
-}
-
-static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc260_hp_3013_automute(codec);
-}
-
-static void alc260_hp_3012_automute(struct hda_codec *codec)
-{
-	unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
-
-	snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    bits);
-	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    bits);
-	snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    bits);
-}
-
-static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc260_hp_3012_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x10;
+	spec->autocfg.speaker_pins[0] = 0x0f;
+	spec->autocfg.speaker_pins[1] = 0x11;
+	spec->autocfg.speaker_pins[2] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 }
 
 
 /* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12,
 /* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12,
  * HP jack = 0x14, CD audio =  0x16, internal speaker = 0x10.
  * HP jack = 0x14, CD audio =  0x16, internal speaker = 0x10.
  */
  */
-static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
+static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
 	ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
 	ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
@@ -6113,7 +6382,7 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
  * controls for such models.  On models without a "mono speaker" the control
  * controls for such models.  On models without a "mono speaker" the control
  * won't do anything.
  * won't do anything.
  */
  */
-static struct snd_kcontrol_new alc260_acer_mixer[] = {
+static const struct snd_kcontrol_new alc260_acer_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
 	ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
 	ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
@@ -6134,7 +6403,7 @@ static struct snd_kcontrol_new alc260_acer_mixer[] = {
 
 
 /* Maxdata Favorit 100XS: one output and one input (0x12) jack
 /* Maxdata Favorit 100XS: one output and one input (0x12) jack
  */
  */
-static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
+static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
 	ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
 	ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
@@ -6147,7 +6416,7 @@ static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
 /* Packard bell V7900  ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
 /* Packard bell V7900  ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
  * Line In jack = 0x14, CD audio =  0x16, pc beep = 0x17.
  * Line In jack = 0x14, CD audio =  0x16, pc beep = 0x17.
  */
  */
-static struct snd_kcontrol_new alc260_will_mixer[] = {
+static const struct snd_kcontrol_new alc260_will_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
@@ -6164,7 +6433,7 @@ static struct snd_kcontrol_new alc260_will_mixer[] = {
 /* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
 /* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
  * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
  * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
  */
  */
-static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
+static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
@@ -6181,7 +6450,7 @@ static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
 /*
 /*
  * initialization verbs
  * initialization verbs
  */
  */
-static struct hda_verb alc260_init_verbs[] = {
+static const struct hda_verb alc260_init_verbs[] = {
 	/* Line In pin widget for input */
 	/* Line In pin widget for input */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	/* CD pin widget for input */
 	/* CD pin widget for input */
@@ -6245,7 +6514,7 @@ static struct hda_verb alc260_init_verbs[] = {
 };
 };
 
 
 #if 0 /* should be identical with alc260_init_verbs? */
 #if 0 /* should be identical with alc260_init_verbs? */
-static struct hda_verb alc260_hp_init_verbs[] = {
+static const struct hda_verb alc260_hp_init_verbs[] = {
 	/* Headphone and output */
 	/* Headphone and output */
 	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
 	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
 	/* mono output */
 	/* mono output */
@@ -6295,7 +6564,7 @@ static struct hda_verb alc260_hp_init_verbs[] = {
 };
 };
 #endif
 #endif
 
 
-static struct hda_verb alc260_hp_3013_init_verbs[] = {
+static const struct hda_verb alc260_hp_3013_init_verbs[] = {
 	/* Line out and output */
 	/* Line out and output */
 	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
 	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
 	/* mono output */
 	/* mono output */
@@ -6348,7 +6617,7 @@ static struct hda_verb alc260_hp_3013_init_verbs[] = {
  * laptops.  ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
  * laptops.  ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
  * audio = 0x16, internal speaker = 0x10.
  * audio = 0x16, internal speaker = 0x10.
  */
  */
-static struct hda_verb alc260_fujitsu_init_verbs[] = {
+static const struct hda_verb alc260_fujitsu_init_verbs[] = {
 	/* Disable all GPIOs */
 	/* Disable all GPIOs */
 	{0x01, AC_VERB_SET_GPIO_MASK, 0},
 	{0x01, AC_VERB_SET_GPIO_MASK, 0},
 	/* Internal speaker is connected to headphone pin */
 	/* Internal speaker is connected to headphone pin */
@@ -6430,7 +6699,7 @@ static struct hda_verb alc260_fujitsu_init_verbs[] = {
 /* Initialisation sequence for ALC260 as configured in Acer TravelMate and
 /* Initialisation sequence for ALC260 as configured in Acer TravelMate and
  * similar laptops (adapted from Fujitsu init verbs).
  * similar laptops (adapted from Fujitsu init verbs).
  */
  */
-static struct hda_verb alc260_acer_init_verbs[] = {
+static const struct hda_verb alc260_acer_init_verbs[] = {
 	/* On TravelMate laptops, GPIO 0 enables the internal speaker and
 	/* On TravelMate laptops, GPIO 0 enables the internal speaker and
 	 * the headphone jack.  Turn this on and rely on the standard mute
 	 * the headphone jack.  Turn this on and rely on the standard mute
 	 * methods whenever the user wants to turn these outputs off.
 	 * methods whenever the user wants to turn these outputs off.
@@ -6518,7 +6787,7 @@ static struct hda_verb alc260_acer_init_verbs[] = {
 /* Initialisation sequence for Maxdata Favorit 100XS
 /* Initialisation sequence for Maxdata Favorit 100XS
  * (adapted from Acer init verbs).
  * (adapted from Acer init verbs).
  */
  */
-static struct hda_verb alc260_favorit100_init_verbs[] = {
+static const struct hda_verb alc260_favorit100_init_verbs[] = {
 	/* GPIO 0 enables the output jack.
 	/* GPIO 0 enables the output jack.
 	 * Turn this on and rely on the standard mute
 	 * Turn this on and rely on the standard mute
 	 * methods whenever the user wants to turn these outputs off.
 	 * methods whenever the user wants to turn these outputs off.
@@ -6598,7 +6867,7 @@ static struct hda_verb alc260_favorit100_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc260_will_verbs[] = {
+static const struct hda_verb alc260_will_verbs[] = {
 	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -6608,7 +6877,7 @@ static struct hda_verb alc260_will_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc260_replacer_672v_verbs[] = {
+static const struct hda_verb alc260_replacer_672v_verbs[] = {
 	{0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
 	{0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
 	{0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
 	{0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
@@ -6650,7 +6919,7 @@ static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
                 alc260_replacer_672v_automute(codec);
                 alc260_replacer_672v_automute(codec);
 }
 }
 
 
-static struct hda_verb alc260_hp_dc7600_verbs[] = {
+static const struct hda_verb alc260_hp_dc7600_verbs[] = {
 	{0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -6668,17 +6937,17 @@ static struct hda_verb alc260_hp_dc7600_verbs[] = {
  * configuration.
  * configuration.
  */
  */
 #ifdef CONFIG_SND_DEBUG
 #ifdef CONFIG_SND_DEBUG
-static hda_nid_t alc260_test_dac_nids[1] = {
+static const hda_nid_t alc260_test_dac_nids[1] = {
 	0x02,
 	0x02,
 };
 };
-static hda_nid_t alc260_test_adc_nids[2] = {
+static const hda_nid_t alc260_test_adc_nids[2] = {
 	0x04, 0x05,
 	0x04, 0x05,
 };
 };
 /* For testing the ALC260, each input MUX needs its own definition since
 /* For testing the ALC260, each input MUX needs its own definition since
  * the signal assignments are different.  This assumes that the first ADC
  * the signal assignments are different.  This assumes that the first ADC
  * is NID 0x04.
  * is NID 0x04.
  */
  */
-static struct hda_input_mux alc260_test_capture_sources[2] = {
+static const struct hda_input_mux alc260_test_capture_sources[2] = {
 	{
 	{
 		.num_items = 7,
 		.num_items = 7,
 		.items = {
 		.items = {
@@ -6705,7 +6974,7 @@ static struct hda_input_mux alc260_test_capture_sources[2] = {
 		},
 		},
         },
         },
 };
 };
-static struct snd_kcontrol_new alc260_test_mixer[] = {
+static const struct snd_kcontrol_new alc260_test_mixer[] = {
 	/* Output driver widgets */
 	/* Output driver widgets */
 	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
 	HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
@@ -6769,7 +7038,7 @@ static struct snd_kcontrol_new alc260_test_mixer[] = {
 
 
 	{ } /* end */
 	{ } /* end */
 };
 };
-static struct hda_verb alc260_test_init_verbs[] = {
+static const struct hda_verb alc260_test_init_verbs[] = {
 	/* Enable all GPIOs as outputs with an initial value of 0 */
 	/* Enable all GPIOs as outputs with an initial value of 0 */
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
 	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
 	{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
@@ -6907,7 +7176,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
 
 
 	spec->multiout.num_dacs = 1;
 	spec->multiout.num_dacs = 1;
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	spec->multiout.dac_nids = spec->private_dac_nids;
-	spec->multiout.dac_nids[0] = 0x02;
+	spec->private_dac_nids[0] = 0x02;
 
 
 	nid = cfg->line_out_pins[0];
 	nid = cfg->line_out_pins[0];
 	if (nid) {
 	if (nid) {
@@ -7005,7 +7274,7 @@ static void alc260_auto_init_analog_input(struct hda_codec *codec)
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc260_volume_init_verbs[] = {
+static const struct hda_verb alc260_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
 	 */
@@ -7050,7 +7319,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	int err;
 	int err;
-	static hda_nid_t alc260_ignore[] = { 0x17, 0 };
+	static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
 
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc260_ignore);
 					   alc260_ignore);
@@ -7095,7 +7364,7 @@ static void alc260_auto_init(struct hda_codec *codec)
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list alc260_loopbacks[] = {
+static const struct hda_amp_list alc260_loopbacks[] = {
 	{ 0x07, HDA_INPUT, 0 },
 	{ 0x07, HDA_INPUT, 0 },
 	{ 0x07, HDA_INPUT, 1 },
 	{ 0x07, HDA_INPUT, 1 },
 	{ 0x07, HDA_INPUT, 2 },
 	{ 0x07, HDA_INPUT, 2 },
@@ -7122,7 +7391,7 @@ static const struct alc_fixup alc260_fixups[] = {
 	},
 	},
 };
 };
 
 
-static struct snd_pci_quirk alc260_fixup_tbl[] = {
+static const struct snd_pci_quirk alc260_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
 	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
 	{}
 	{}
 };
 };
@@ -7146,7 +7415,7 @@ static const char * const alc260_models[ALC260_MODEL_LAST] = {
 	[ALC260_AUTO]		= "auto",
 	[ALC260_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk alc260_cfg_tbl[] = {
+static const struct snd_pci_quirk alc260_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
 	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
 	SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
 	SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
 	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
 	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
@@ -7170,7 +7439,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = {
 	{}
 	{}
 };
 };
 
 
-static struct alc_config_preset alc260_presets[] = {
+static const struct alc_config_preset alc260_presets[] = {
 	[ALC260_BASIC] = {
 	[ALC260_BASIC] = {
 		.mixers = { alc260_base_output_mixer,
 		.mixers = { alc260_base_output_mixer,
 			    alc260_input_mixer },
 			    alc260_input_mixer },
@@ -7195,8 +7464,9 @@ static struct alc_config_preset alc260_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
 		.input_mux = &alc260_capture_source,
-		.unsol_event = alc260_hp_unsol_event,
-		.init_hook = alc260_hp_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc260_hp_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC260_HP_DC7600] = {
 	[ALC260_HP_DC7600] = {
 		.mixers = { alc260_hp_dc7600_mixer,
 		.mixers = { alc260_hp_dc7600_mixer,
@@ -7210,8 +7480,9 @@ static struct alc_config_preset alc260_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
 		.input_mux = &alc260_capture_source,
-		.unsol_event = alc260_hp_3012_unsol_event,
-		.init_hook = alc260_hp_3012_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc260_hp_3012_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC260_HP_3013] = {
 	[ALC260_HP_3013] = {
 		.mixers = { alc260_hp_3013_mixer,
 		.mixers = { alc260_hp_3013_mixer,
@@ -7225,8 +7496,9 @@ static struct alc_config_preset alc260_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
 		.input_mux = &alc260_capture_source,
-		.unsol_event = alc260_hp_3013_unsol_event,
-		.init_hook = alc260_hp_3013_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc260_hp_3013_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC260_FUJITSU_S702X] = {
 	[ALC260_FUJITSU_S702X] = {
 		.mixers = { alc260_fujitsu_mixer },
 		.mixers = { alc260_fujitsu_mixer },
@@ -7384,6 +7656,7 @@ static int patch_alc260(struct hda_codec *codec)
 	codec->patch_ops = alc_patch_ops;
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC260_AUTO)
 	if (board_config == ALC260_AUTO)
 		spec->init_hook = alc260_auto_init;
 		spec->init_hook = alc260_auto_init;
+	spec->shutup = alc_eapd_shutup;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	if (!spec->loopback.amplist)
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc260_loopbacks;
 		spec->loopback.amplist = alc260_loopbacks;
@@ -7411,12 +7684,12 @@ static int patch_alc260(struct hda_codec *codec)
 #define ALC1200_DIGOUT_NID	0x10
 #define ALC1200_DIGOUT_NID	0x10
 
 
 
 
-static struct hda_channel_mode alc882_ch_modes[1] = {
+static const struct hda_channel_mode alc882_ch_modes[1] = {
 	{ 8, NULL }
 	{ 8, NULL }
 };
 };
 
 
 /* DACs */
 /* DACs */
-static hda_nid_t alc882_dac_nids[4] = {
+static const hda_nid_t alc882_dac_nids[4] = {
 	/* front, rear, clfe, rear_surr */
 	/* front, rear, clfe, rear_surr */
 	0x02, 0x03, 0x04, 0x05
 	0x02, 0x03, 0x04, 0x05
 };
 };
@@ -7426,20 +7699,20 @@ static hda_nid_t alc882_dac_nids[4] = {
 #define alc882_adc_nids		alc880_adc_nids
 #define alc882_adc_nids		alc880_adc_nids
 #define alc882_adc_nids_alt	alc880_adc_nids_alt
 #define alc882_adc_nids_alt	alc880_adc_nids_alt
 #define alc883_adc_nids		alc882_adc_nids_alt
 #define alc883_adc_nids		alc882_adc_nids_alt
-static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
-static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
+static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
+static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
 #define alc889_adc_nids		alc880_adc_nids
 #define alc889_adc_nids		alc880_adc_nids
 
 
-static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
-static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
+static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
+static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
 #define alc883_capsrc_nids	alc882_capsrc_nids_alt
 #define alc883_capsrc_nids	alc882_capsrc_nids_alt
-static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
+static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
 #define alc889_capsrc_nids	alc882_capsrc_nids
 #define alc889_capsrc_nids	alc882_capsrc_nids
 
 
 /* input MUX */
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 /* FIXME: should be a matrix-type input source selection */
 
 
-static struct hda_input_mux alc882_capture_source = {
+static const struct hda_input_mux alc882_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -7451,7 +7724,7 @@ static struct hda_input_mux alc882_capture_source = {
 
 
 #define alc883_capture_source	alc882_capture_source
 #define alc883_capture_source	alc882_capture_source
 
 
-static struct hda_input_mux alc889_capture_source = {
+static const struct hda_input_mux alc889_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x0 },
 		{ "Front Mic", 0x0 },
@@ -7460,7 +7733,7 @@ static struct hda_input_mux alc889_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux mb5_capture_source = {
+static const struct hda_input_mux mb5_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x1 },
 		{ "Mic", 0x1 },
@@ -7469,7 +7742,7 @@ static struct hda_input_mux mb5_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux macmini3_capture_source = {
+static const struct hda_input_mux macmini3_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Line", 0x2 },
 		{ "Line", 0x2 },
@@ -7477,7 +7750,7 @@ static struct hda_input_mux macmini3_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc883_3stack_6ch_intel = {
+static const struct hda_input_mux alc883_3stack_6ch_intel = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x1 },
 		{ "Mic", 0x1 },
@@ -7487,7 +7760,7 @@ static struct hda_input_mux alc883_3stack_6ch_intel = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc883_lenovo_101e_capture_source = {
+static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x1 },
 		{ "Mic", 0x1 },
@@ -7495,7 +7768,7 @@ static struct hda_input_mux alc883_lenovo_101e_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
+static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -7505,7 +7778,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
+static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -7513,7 +7786,7 @@ static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc883_lenovo_sky_capture_source = {
+static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -7522,7 +7795,7 @@ static struct hda_input_mux alc883_lenovo_sky_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc883_asus_eee1601_capture_source = {
+static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -7530,7 +7803,7 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc889A_mb31_capture_source = {
+static const struct hda_input_mux alc889A_mb31_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -7541,7 +7814,7 @@ static struct hda_input_mux alc889A_mb31_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc889A_imac91_capture_source = {
+static const struct hda_input_mux alc889A_imac91_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x01 },
 		{ "Mic", 0x01 },
@@ -7552,14 +7825,14 @@ static struct hda_input_mux alc889A_imac91_capture_source = {
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
+static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
 	{ 2, NULL }
 	{ 2, NULL }
 };
 };
 
 
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_verb alc882_3ST_ch2_init[] = {
+static const struct hda_verb alc882_3ST_ch2_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -7570,7 +7843,7 @@ static struct hda_verb alc882_3ST_ch2_init[] = {
 /*
 /*
  * 4ch mode
  * 4ch mode
  */
  */
-static struct hda_verb alc882_3ST_ch4_init[] = {
+static const struct hda_verb alc882_3ST_ch4_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7582,7 +7855,7 @@ static struct hda_verb alc882_3ST_ch4_init[] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc882_3ST_ch6_init[] = {
+static const struct hda_verb alc882_3ST_ch6_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
 	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -7592,7 +7865,7 @@ static struct hda_verb alc882_3ST_ch6_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
+static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
 	{ 2, alc882_3ST_ch2_init },
 	{ 2, alc882_3ST_ch2_init },
 	{ 4, alc882_3ST_ch4_init },
 	{ 4, alc882_3ST_ch4_init },
 	{ 6, alc882_3ST_ch6_init },
 	{ 6, alc882_3ST_ch6_init },
@@ -7603,7 +7876,7 @@ static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
+static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -7615,7 +7888,7 @@ static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
 /*
 /*
  * 4ch mode
  * 4ch mode
  */
  */
-static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
+static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -7628,7 +7901,7 @@ static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
+static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -7639,7 +7912,7 @@ static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
+static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
 	{ 2, alc883_3ST_ch2_clevo_init },
 	{ 2, alc883_3ST_ch2_clevo_init },
 	{ 4, alc883_3ST_ch4_clevo_init },
 	{ 4, alc883_3ST_ch4_clevo_init },
 	{ 6, alc883_3ST_ch6_clevo_init },
 	{ 6, alc883_3ST_ch6_clevo_init },
@@ -7649,7 +7922,7 @@ static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc882_sixstack_ch6_init[] = {
+static const struct hda_verb alc882_sixstack_ch6_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7660,7 +7933,7 @@ static struct hda_verb alc882_sixstack_ch6_init[] = {
 /*
 /*
  * 8ch mode
  * 8ch mode
  */
  */
-static struct hda_verb alc882_sixstack_ch8_init[] = {
+static const struct hda_verb alc882_sixstack_ch8_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7668,7 +7941,7 @@ static struct hda_verb alc882_sixstack_ch8_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc882_sixstack_modes[2] = {
+static const struct hda_channel_mode alc882_sixstack_modes[2] = {
 	{ 6, alc882_sixstack_ch6_init },
 	{ 6, alc882_sixstack_ch6_init },
 	{ 8, alc882_sixstack_ch8_init },
 	{ 8, alc882_sixstack_ch8_init },
 };
 };
@@ -7676,7 +7949,7 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = {
 
 
 /* Macbook Air 2,1 */
 /* Macbook Air 2,1 */
 
 
-static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
+static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
       { 2, NULL },
       { 2, NULL },
 };
 };
 
 
@@ -7687,7 +7960,7 @@ static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_verb alc885_mbp_ch2_init[] = {
+static const struct hda_verb alc885_mbp_ch2_init[] = {
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -7697,7 +7970,7 @@ static struct hda_verb alc885_mbp_ch2_init[] = {
 /*
 /*
  * 4ch mode
  * 4ch mode
  */
  */
-static struct hda_verb alc885_mbp_ch4_init[] = {
+static const struct hda_verb alc885_mbp_ch4_init[] = {
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{ 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
 	{ 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
@@ -7706,7 +7979,7 @@ static struct hda_verb alc885_mbp_ch4_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
+static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
 	{ 2, alc885_mbp_ch2_init },
 	{ 2, alc885_mbp_ch2_init },
 	{ 4, alc885_mbp_ch4_init },
 	{ 4, alc885_mbp_ch4_init },
 };
 };
@@ -7716,7 +7989,7 @@ static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
  * Speakers/Woofer/HP = Front
  * Speakers/Woofer/HP = Front
  * LineIn = Input
  * LineIn = Input
  */
  */
-static struct hda_verb alc885_mb5_ch2_init[] = {
+static const struct hda_verb alc885_mb5_ch2_init[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{ } /* end */
 	{ } /* end */
@@ -7728,14 +8001,14 @@ static struct hda_verb alc885_mb5_ch2_init[] = {
  * Woofer = LFE
  * Woofer = LFE
  * LineIn = Surround
  * LineIn = Surround
  */
  */
-static struct hda_verb alc885_mb5_ch6_init[] = {
+static const struct hda_verb alc885_mb5_ch6_init[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
+static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
 	{ 2, alc885_mb5_ch2_init },
 	{ 2, alc885_mb5_ch2_init },
 	{ 6, alc885_mb5_ch6_init },
 	{ 6, alc885_mb5_ch6_init },
 };
 };
@@ -7745,7 +8018,7 @@ static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_verb alc883_4ST_ch2_init[] = {
+static const struct hda_verb alc883_4ST_ch2_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
@@ -7758,7 +8031,7 @@ static struct hda_verb alc883_4ST_ch2_init[] = {
 /*
 /*
  * 4ch mode
  * 4ch mode
  */
  */
-static struct hda_verb alc883_4ST_ch4_init[] = {
+static const struct hda_verb alc883_4ST_ch4_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
@@ -7772,7 +8045,7 @@ static struct hda_verb alc883_4ST_ch4_init[] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc883_4ST_ch6_init[] = {
+static const struct hda_verb alc883_4ST_ch6_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7787,7 +8060,7 @@ static struct hda_verb alc883_4ST_ch6_init[] = {
 /*
 /*
  * 8ch mode
  * 8ch mode
  */
  */
-static struct hda_verb alc883_4ST_ch8_init[] = {
+static const struct hda_verb alc883_4ST_ch8_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
 	{ 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
@@ -7800,7 +8073,7 @@ static struct hda_verb alc883_4ST_ch8_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
+static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
 	{ 2, alc883_4ST_ch2_init },
 	{ 2, alc883_4ST_ch2_init },
 	{ 4, alc883_4ST_ch4_init },
 	{ 4, alc883_4ST_ch4_init },
 	{ 6, alc883_4ST_ch6_init },
 	{ 6, alc883_4ST_ch6_init },
@@ -7811,7 +8084,7 @@ static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_verb alc883_3ST_ch2_intel_init[] = {
+static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -7822,7 +8095,7 @@ static struct hda_verb alc883_3ST_ch2_intel_init[] = {
 /*
 /*
  * 4ch mode
  * 4ch mode
  */
  */
-static struct hda_verb alc883_3ST_ch4_intel_init[] = {
+static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7834,7 +8107,7 @@ static struct hda_verb alc883_3ST_ch4_intel_init[] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc883_3ST_ch6_intel_init[] = {
+static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -7844,7 +8117,7 @@ static struct hda_verb alc883_3ST_ch6_intel_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
+static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
 	{ 2, alc883_3ST_ch2_intel_init },
 	{ 2, alc883_3ST_ch2_intel_init },
 	{ 4, alc883_3ST_ch4_intel_init },
 	{ 4, alc883_3ST_ch4_intel_init },
 	{ 6, alc883_3ST_ch6_intel_init },
 	{ 6, alc883_3ST_ch6_intel_init },
@@ -7853,7 +8126,7 @@ static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_verb alc889_ch2_intel_init[] = {
+static const struct hda_verb alc889_ch2_intel_init[] = {
 	{ 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
@@ -7866,7 +8139,7 @@ static struct hda_verb alc889_ch2_intel_init[] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc889_ch6_intel_init[] = {
+static const struct hda_verb alc889_ch6_intel_init[] = {
 	{ 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
 	{ 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
 	{ 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -7879,7 +8152,7 @@ static struct hda_verb alc889_ch6_intel_init[] = {
 /*
 /*
  * 8ch mode
  * 8ch mode
  */
  */
-static struct hda_verb alc889_ch8_intel_init[] = {
+static const struct hda_verb alc889_ch8_intel_init[] = {
 	{ 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
 	{ 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
 	{ 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
 	{ 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -7890,7 +8163,7 @@ static struct hda_verb alc889_ch8_intel_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
+static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
 	{ 2, alc889_ch2_intel_init },
 	{ 2, alc889_ch2_intel_init },
 	{ 6, alc889_ch6_intel_init },
 	{ 6, alc889_ch6_intel_init },
 	{ 8, alc889_ch8_intel_init },
 	{ 8, alc889_ch8_intel_init },
@@ -7899,7 +8172,7 @@ static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc883_sixstack_ch6_init[] = {
+static const struct hda_verb alc883_sixstack_ch6_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7910,7 +8183,7 @@ static struct hda_verb alc883_sixstack_ch6_init[] = {
 /*
 /*
  * 8ch mode
  * 8ch mode
  */
  */
-static struct hda_verb alc883_sixstack_ch8_init[] = {
+static const struct hda_verb alc883_sixstack_ch8_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -7918,7 +8191,7 @@ static struct hda_verb alc883_sixstack_ch8_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc883_sixstack_modes[2] = {
+static const struct hda_channel_mode alc883_sixstack_modes[2] = {
 	{ 6, alc883_sixstack_ch6_init },
 	{ 6, alc883_sixstack_ch6_init },
 	{ 8, alc883_sixstack_ch8_init },
 	{ 8, alc883_sixstack_ch8_init },
 };
 };
@@ -7927,7 +8200,7 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = {
 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  */
  */
-static struct snd_kcontrol_new alc882_base_mixer[] = {
+static const struct snd_kcontrol_new alc882_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -7954,14 +8227,14 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
 
 
 /* Macbook Air 2,1 same control for HP and internal Speaker */
 /* Macbook Air 2,1 same control for HP and internal Speaker */
 
 
-static struct snd_kcontrol_new alc885_mba21_mixer[] = {
+static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
      { }
      { }
 };
 };
 
 
 
 
-static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
+static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_BIND_MUTE   ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_BIND_MUTE   ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
@@ -7976,7 +8249,7 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc885_mb5_mixer[] = {
+static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
@@ -7994,7 +8267,7 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
+static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
@@ -8009,14 +8282,14 @@ static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc885_imac91_mixer[] = {
+static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
 
 
-static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
+static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -8029,7 +8302,7 @@ static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc882_targa_mixer[] = {
+static const struct snd_kcontrol_new alc882_targa_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -8049,7 +8322,7 @@ static struct snd_kcontrol_new alc882_targa_mixer[] = {
 /* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
 /* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
  *                 Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
  *                 Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
  */
  */
-static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
+static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -8066,7 +8339,7 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
+static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -8080,7 +8353,7 @@ static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc882_chmode_mixer[] = {
+static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
 		.name = "Channel Mode",
@@ -8091,7 +8364,7 @@ static struct snd_kcontrol_new alc882_chmode_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc882_base_init_verbs[] = {
+static const struct hda_verb alc882_base_init_verbs[] = {
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -8153,7 +8426,7 @@ static struct hda_verb alc882_base_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc882_adc1_init_verbs[] = {
+static const struct hda_verb alc882_adc1_init_verbs[] = {
 	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
 	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
@@ -8165,26 +8438,26 @@ static struct hda_verb alc882_adc1_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc882_eapd_verbs[] = {
+static const struct hda_verb alc882_eapd_verbs[] = {
 	/* change to EAPD mode */
 	/* change to EAPD mode */
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_PROC_COEF, 0x3060},
 	{0x20, AC_VERB_SET_PROC_COEF, 0x3060},
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc889_eapd_verbs[] = {
+static const struct hda_verb alc889_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc_hp15_unsol_verbs[] = {
+static const struct hda_verb alc_hp15_unsol_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc885_init_verbs[] = {
+static const struct hda_verb alc885_init_verbs[] = {
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -8243,7 +8516,7 @@ static struct hda_verb alc885_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc885_init_input_verbs[] = {
+static const struct hda_verb alc885_init_input_verbs[] = {
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
@@ -8252,7 +8525,7 @@ static struct hda_verb alc885_init_input_verbs[] = {
 
 
 
 
 /* Unmute Selector 24h and set the default input to front mic */
 /* Unmute Selector 24h and set the default input to front mic */
-static struct hda_verb alc889_init_input_verbs[] = {
+static const struct hda_verb alc889_init_input_verbs[] = {
 	{0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{ }
 	{ }
@@ -8262,7 +8535,7 @@ static struct hda_verb alc889_init_input_verbs[] = {
 #define alc883_init_verbs	alc882_base_init_verbs
 #define alc883_init_verbs	alc882_base_init_verbs
 
 
 /* Mac Pro test */
 /* Mac Pro test */
-static struct snd_kcontrol_new alc882_macpro_mixer[] = {
+static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
@@ -8275,7 +8548,7 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc882_macpro_init_verbs[] = {
+static const struct hda_verb alc882_macpro_init_verbs[] = {
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -8327,7 +8600,7 @@ static struct hda_verb alc882_macpro_init_verbs[] = {
 };
 };
 
 
 /* Macbook 5,1 */
 /* Macbook 5,1 */
-static struct hda_verb alc885_mb5_init_verbs[] = {
+static const struct hda_verb alc885_mb5_init_verbs[] = {
 	/* DACs */
 	/* DACs */
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -8376,7 +8649,7 @@ static struct hda_verb alc885_mb5_init_verbs[] = {
 };
 };
 
 
 /* Macmini 3,1 */
 /* Macmini 3,1 */
-static struct hda_verb alc885_macmini3_init_verbs[] = {
+static const struct hda_verb alc885_macmini3_init_verbs[] = {
 	/* DACs */
 	/* DACs */
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -8423,7 +8696,7 @@ static struct hda_verb alc885_macmini3_init_verbs[] = {
 };
 };
 
 
 
 
-static struct hda_verb alc885_mba21_init_verbs[] = {
+static const struct hda_verb alc885_mba21_init_verbs[] = {
 	/*Internal and HP Speaker Mixer*/
 	/*Internal and HP Speaker Mixer*/
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -8446,7 +8719,7 @@ static struct hda_verb alc885_mba21_init_verbs[] = {
 
 
 
 
 /* Macbook Pro rev3 */
 /* Macbook Pro rev3 */
-static struct hda_verb alc885_mbp3_init_verbs[] = {
+static const struct hda_verb alc885_mbp3_init_verbs[] = {
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	/* Front mixer: unmute input/output amp left and right (volume = 0) */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -8510,7 +8783,7 @@ static struct hda_verb alc885_mbp3_init_verbs[] = {
 };
 };
 
 
 /* iMac 9,1 */
 /* iMac 9,1 */
-static struct hda_verb alc885_imac91_init_verbs[] = {
+static const struct hda_verb alc885_imac91_init_verbs[] = {
 	/* Internal Speaker Pin (0x0c) */
 	/* Internal Speaker Pin (0x0c) */
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -8565,14 +8838,14 @@ static struct hda_verb alc885_imac91_init_verbs[] = {
 };
 };
 
 
 /* iMac 24 mixer. */
 /* iMac 24 mixer. */
-static struct snd_kcontrol_new alc885_imac24_mixer[] = {
+static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
 /* iMac 24 init verbs. */
 /* iMac 24 init verbs. */
-static struct hda_verb alc885_imac24_init_verbs[] = {
+static const struct hda_verb alc885_imac24_init_verbs[] = {
 	/* Internal speakers: output 0 (0x0c) */
 	/* Internal speakers: output 0 (0x0c) */
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -8600,6 +8873,8 @@ static void alc885_imac24_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x18;
 	spec->autocfg.speaker_pins[0] = 0x18;
 	spec->autocfg.speaker_pins[1] = 0x1a;
 	spec->autocfg.speaker_pins[1] = 0x1a;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 #define alc885_mb5_setup	alc885_imac24_setup
 #define alc885_mb5_setup	alc885_imac24_setup
@@ -8612,6 +8887,8 @@ static void alc885_mba21_setup(struct hda_codec *codec)
 
 
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x18;
        spec->autocfg.speaker_pins[0] = 0x18;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 
 
@@ -8622,6 +8899,8 @@ static void alc885_mbp3_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc885_imac91_setup(struct hda_codec *codec)
 static void alc885_imac91_setup(struct hda_codec *codec)
@@ -8631,9 +8910,11 @@ static void alc885_imac91_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x18;
 	spec->autocfg.speaker_pins[0] = 0x18;
 	spec->autocfg.speaker_pins[1] = 0x1a;
 	spec->autocfg.speaker_pins[1] = 0x1a;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-static struct hda_verb alc882_targa_verbs[] = {
+static const struct hda_verb alc882_targa_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
 
@@ -8652,7 +8933,7 @@ static struct hda_verb alc882_targa_verbs[] = {
 static void alc882_targa_automute(struct hda_codec *codec)
 static void alc882_targa_automute(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
 	snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
 				  spec->jack_present ? 1 : 3);
 				  spec->jack_present ? 1 : 3);
 }
 }
@@ -8663,6 +8944,8 @@ static void alc882_targa_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x1b;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
 static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
@@ -8671,7 +8954,7 @@ static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
 		alc882_targa_automute(codec);
 		alc882_targa_automute(codec);
 }
 }
 
 
-static struct hda_verb alc882_asus_a7j_verbs[] = {
+static const struct hda_verb alc882_asus_a7j_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
 
@@ -8689,7 +8972,7 @@ static struct hda_verb alc882_asus_a7j_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc882_asus_a7m_verbs[] = {
+static const struct hda_verb alc882_asus_a7m_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
 
@@ -8750,13 +9033,13 @@ static void alc885_macpro_init_hook(struct hda_codec *codec)
 static void alc885_imac24_init_hook(struct hda_codec *codec)
 static void alc885_imac24_init_hook(struct hda_codec *codec)
 {
 {
 	alc885_macpro_init_hook(codec);
 	alc885_macpro_init_hook(codec);
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 }
 }
 
 
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc883_auto_init_verbs[] = {
+static const struct hda_verb alc883_auto_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
 	 */
@@ -8796,7 +9079,7 @@ static struct hda_verb alc883_auto_init_verbs[] = {
 };
 };
 
 
 /* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
 /* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
-static struct hda_verb alc889A_mb31_ch2_init[] = {
+static const struct hda_verb alc889A_mb31_ch2_init[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
@@ -8805,7 +9088,7 @@ static struct hda_verb alc889A_mb31_ch2_init[] = {
 };
 };
 
 
 /* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
 /* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
-static struct hda_verb alc889A_mb31_ch4_init[] = {
+static const struct hda_verb alc889A_mb31_ch4_init[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
@@ -8814,7 +9097,7 @@ static struct hda_verb alc889A_mb31_ch4_init[] = {
 };
 };
 
 
 /* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
 /* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
-static struct hda_verb alc889A_mb31_ch5_init[] = {
+static const struct hda_verb alc889A_mb31_ch5_init[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as rear */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as rear */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},    /* Line as input */
@@ -8823,7 +9106,7 @@ static struct hda_verb alc889A_mb31_ch5_init[] = {
 };
 };
 
 
 /* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
 /* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
-static struct hda_verb alc889A_mb31_ch6_init[] = {
+static const struct hda_verb alc889A_mb31_ch6_init[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as front */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},             /* HP as front */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Subwoofer off */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},   /* Subwoofer off */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},   /* Line as output */
@@ -8831,14 +9114,14 @@ static struct hda_verb alc889A_mb31_ch6_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
+static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
 	{ 2, alc889A_mb31_ch2_init },
 	{ 2, alc889A_mb31_ch2_init },
 	{ 4, alc889A_mb31_ch4_init },
 	{ 4, alc889A_mb31_ch4_init },
 	{ 5, alc889A_mb31_ch5_init },
 	{ 5, alc889A_mb31_ch5_init },
 	{ 6, alc889A_mb31_ch6_init },
 	{ 6, alc889A_mb31_ch6_init },
 };
 };
 
 
-static struct hda_verb alc883_medion_eapd_verbs[] = {
+static const struct hda_verb alc883_medion_eapd_verbs[] = {
         /* eanable EAPD on medion laptop */
         /* eanable EAPD on medion laptop */
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_PROC_COEF, 0x3070},
 	{0x20, AC_VERB_SET_PROC_COEF, 0x3070},
@@ -8847,7 +9130,7 @@ static struct hda_verb alc883_medion_eapd_verbs[] = {
 
 
 #define alc883_base_mixer	alc882_base_mixer
 #define alc883_base_mixer	alc882_base_mixer
 
 
-static struct snd_kcontrol_new alc883_mitac_mixer[] = {
+static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
@@ -8864,7 +9147,7 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
+static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -8878,7 +9161,7 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
+static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -8892,7 +9175,7 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
+static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -8909,7 +9192,7 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
+static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -8932,7 +9215,7 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
+static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -8956,7 +9239,7 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
+static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -8980,7 +9263,7 @@ static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
+static const struct snd_kcontrol_new alc883_fivestack_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -9003,7 +9286,7 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_targa_mixer[] = {
+static const struct snd_kcontrol_new alc883_targa_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -9024,7 +9307,7 @@ static struct snd_kcontrol_new alc883_targa_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
+static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -9040,7 +9323,7 @@ static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
+static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
 	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
@@ -9049,7 +9332,7 @@ static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
+static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -9061,7 +9344,7 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
+static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -9074,7 +9357,7 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
+static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -9084,7 +9367,7 @@ static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc883_medion_wim2160_verbs[] = {
+static const struct hda_verb alc883_medion_wim2160_verbs[] = {
 	/* Unmute front mixer */
 	/* Unmute front mixer */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -9108,9 +9391,11 @@ static void alc883_medion_wim2160_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x1a;
 	spec->autocfg.hp_pins[0] = 0x1a;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
+static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -9122,7 +9407,7 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
+static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
@@ -9135,7 +9420,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
+static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
@@ -9160,7 +9445,7 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
+static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
 	/* Output mixers */
 	/* Output mixers */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
@@ -9186,7 +9471,7 @@ static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
+static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -9196,7 +9481,7 @@ static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_bind_ctls alc883_bind_cap_vol = {
+static const struct hda_bind_ctls alc883_bind_cap_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
 		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
@@ -9205,7 +9490,7 @@ static struct hda_bind_ctls alc883_bind_cap_vol = {
 	},
 	},
 };
 };
 
 
-static struct hda_bind_ctls alc883_bind_cap_switch = {
+static const struct hda_bind_ctls alc883_bind_cap_switch = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
 		HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
@@ -9214,7 +9499,7 @@ static struct hda_bind_ctls alc883_bind_cap_switch = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
+static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -9226,7 +9511,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
+static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
 	HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
 	HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
 	HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
 	HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
 	{
 	{
@@ -9241,7 +9526,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc883_chmode_mixer[] = {
+static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
 		.name = "Channel Mode",
@@ -9260,9 +9545,11 @@ static void alc883_mitac_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x17;
 	spec->autocfg.speaker_pins[1] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-static struct hda_verb alc883_mitac_verbs[] = {
+static const struct hda_verb alc883_mitac_verbs[] = {
 	/* HP */
 	/* HP */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -9277,7 +9564,7 @@ static struct hda_verb alc883_mitac_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc883_clevo_m540r_verbs[] = {
+static const struct hda_verb alc883_clevo_m540r_verbs[] = {
 	/* HP */
 	/* HP */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -9293,7 +9580,7 @@ static struct hda_verb alc883_clevo_m540r_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc883_clevo_m720_verbs[] = {
+static const struct hda_verb alc883_clevo_m720_verbs[] = {
 	/* HP */
 	/* HP */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -9308,7 +9595,7 @@ static struct hda_verb alc883_clevo_m720_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
+static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
 	/* HP */
 	/* HP */
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -9322,7 +9609,7 @@ static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc883_targa_verbs[] = {
+static const struct hda_verb alc883_targa_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
 
@@ -9351,14 +9638,14 @@ static struct hda_verb alc883_targa_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc883_lenovo_101e_verbs[] = {
+static const struct hda_verb alc883_lenovo_101e_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
         {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
         {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
+static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
         {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
         {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
         {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
         {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
@@ -9366,7 +9653,7 @@ static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
+static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -9375,7 +9662,7 @@ static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc883_haier_w66_verbs[] = {
+static const struct hda_verb alc883_haier_w66_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
 
@@ -9388,7 +9675,7 @@ static struct hda_verb alc883_haier_w66_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc888_lenovo_sky_verbs[] = {
+static const struct hda_verb alc888_lenovo_sky_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -9400,12 +9687,12 @@ static struct hda_verb alc888_lenovo_sky_verbs[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc888_6st_dell_verbs[] = {
+static const struct hda_verb alc888_6st_dell_verbs[] = {
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc883_vaiott_verbs[] = {
+static const struct hda_verb alc883_vaiott_verbs[] = {
 	/* HP */
 	/* HP */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -9424,9 +9711,11 @@ static void alc888_3st_hp_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x18;
 	spec->autocfg.speaker_pins[2] = 0x18;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-static struct hda_verb alc888_3st_hp_verbs[] = {
+static const struct hda_verb alc888_3st_hp_verbs[] = {
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
 	{0x16, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Rear : output 1 (0x0d) */
 	{0x16, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Rear : output 1 (0x0d) */
 	{0x18, AC_VERB_SET_CONNECT_SEL, 0x02},	/* CLFE : output 2 (0x0e) */
 	{0x18, AC_VERB_SET_CONNECT_SEL, 0x02},	/* CLFE : output 2 (0x0e) */
@@ -9437,7 +9726,7 @@ static struct hda_verb alc888_3st_hp_verbs[] = {
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_verb alc888_3st_hp_2ch_init[] = {
+static const struct hda_verb alc888_3st_hp_2ch_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -9448,7 +9737,7 @@ static struct hda_verb alc888_3st_hp_2ch_init[] = {
 /*
 /*
  * 4ch mode
  * 4ch mode
  */
  */
-static struct hda_verb alc888_3st_hp_4ch_init[] = {
+static const struct hda_verb alc888_3st_hp_4ch_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -9460,7 +9749,7 @@ static struct hda_verb alc888_3st_hp_4ch_init[] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc888_3st_hp_6ch_init[] = {
+static const struct hda_verb alc888_3st_hp_6ch_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
 	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -9470,48 +9759,32 @@ static struct hda_verb alc888_3st_hp_6ch_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc888_3st_hp_modes[3] = {
+static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
 	{ 2, alc888_3st_hp_2ch_init },
 	{ 2, alc888_3st_hp_2ch_init },
 	{ 4, alc888_3st_hp_4ch_init },
 	{ 4, alc888_3st_hp_4ch_init },
 	{ 6, alc888_3st_hp_6ch_init },
 	{ 6, alc888_3st_hp_6ch_init },
 };
 };
 
 
-/* toggle front-jack and RCA according to the hp-jack state */
-static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
+static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
 {
 {
- 	unsigned int present = snd_hda_jack_detect(codec, 0x1b);
+	struct alc_spec *spec = codec->spec;
 
 
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.line_out_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-/* toggle RCA according to the front-jack state */
-static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
-{
- 	unsigned int present = snd_hda_jack_detect(codec, 0x14);
-
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
-					     unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc888_lenovo_ms7195_front_automute(codec);
-	if ((res >> 26) == ALC880_FRONT_EVENT)
-		alc888_lenovo_ms7195_rca_automute(codec);
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 /* toggle speaker-output according to the hp-jack state */
 /* toggle speaker-output according to the hp-jack state */
@@ -9524,11 +9797,13 @@ static void alc883_clevo_m720_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
 static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
 {
 {
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	alc88x_simple_mic_automute(codec);
 	alc88x_simple_mic_automute(codec);
 }
 }
 
 
@@ -9540,7 +9815,7 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
 		alc88x_simple_mic_automute(codec);
 		alc88x_simple_mic_automute(codec);
 		break;
 		break;
 	default:
 	default:
-		alc_automute_amp_unsol_event(codec, res);
+		alc_sku_unsol_event(codec, res);
 		break;
 		break;
 	}
 	}
 }
 }
@@ -9552,6 +9827,8 @@ static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc883_haier_w66_setup(struct hda_codec *codec)
 static void alc883_haier_w66_setup(struct hda_codec *codec)
@@ -9560,33 +9837,21 @@ static void alc883_haier_w66_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
-{
-	int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
-
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
+static void alc883_lenovo_101e_setup(struct hda_codec *codec)
 {
 {
-	int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
-
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
+	struct alc_spec *spec = codec->spec;
 
 
-static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc883_lenovo_101e_all_automute(codec);
-	if ((res >> 26) == ALC880_FRONT_EVENT)
-		alc883_lenovo_101e_ispeaker_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.line_out_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->detect_line = 1;
+	spec->automute_lines = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 /* toggle speaker-output according to the hp-jack state */
 /* toggle speaker-output according to the hp-jack state */
@@ -9597,9 +9862,11 @@ static void alc883_acer_aspire_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[1] = 0x16;
 	spec->autocfg.speaker_pins[1] = 0x16;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-static struct hda_verb alc883_acer_eapd_verbs[] = {
+static const struct hda_verb alc883_acer_eapd_verbs[] = {
 	/* HP Pin: output 0 (0x0c) */
 	/* HP Pin: output 0 (0x0c) */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -9626,6 +9893,8 @@ static void alc888_6st_dell_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[1] = 0x15;
 	spec->autocfg.speaker_pins[1] = 0x15;
 	spec->autocfg.speaker_pins[2] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x16;
 	spec->autocfg.speaker_pins[3] = 0x17;
 	spec->autocfg.speaker_pins[3] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc888_lenovo_sky_setup(struct hda_codec *codec)
 static void alc888_lenovo_sky_setup(struct hda_codec *codec)
@@ -9638,6 +9907,8 @@ static void alc888_lenovo_sky_setup(struct hda_codec *codec)
 	spec->autocfg.speaker_pins[2] = 0x16;
 	spec->autocfg.speaker_pins[2] = 0x16;
 	spec->autocfg.speaker_pins[3] = 0x17;
 	spec->autocfg.speaker_pins[3] = 0x17;
 	spec->autocfg.speaker_pins[4] = 0x1a;
 	spec->autocfg.speaker_pins[4] = 0x1a;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc883_vaiott_setup(struct hda_codec *codec)
 static void alc883_vaiott_setup(struct hda_codec *codec)
@@ -9647,9 +9918,11 @@ static void alc883_vaiott_setup(struct hda_codec *codec)
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x17;
 	spec->autocfg.speaker_pins[1] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-static struct hda_verb alc888_asus_m90v_verbs[] = {
+static const struct hda_verb alc888_asus_m90v_verbs[] = {
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -9672,9 +9945,11 @@ static void alc883_mode2_setup(struct hda_codec *codec)
 	spec->ext_mic.mux_idx = 0;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.mux_idx = 1;
 	spec->int_mic.mux_idx = 1;
 	spec->auto_mic = 1;
 	spec->auto_mic = 1;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-static struct hda_verb alc888_asus_eee1601_verbs[] = {
+static const struct hda_verb alc888_asus_eee1601_verbs[] = {
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -9693,10 +9968,10 @@ static void alc883_eee1601_inithook(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x1b;
-	alc_automute_pin(codec);
+	alc_hp_automute(codec);
 }
 }
 
 
-static struct hda_verb alc889A_mb31_verbs[] = {
+static const struct hda_verb alc889A_mb31_verbs[] = {
 	/* Init rear pin (used as headphone output) */
 	/* Init rear pin (used as headphone output) */
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},    /* Apple Headphones */
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},    /* Apple Headphones */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},           /* Connect to front */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},           /* Connect to front */
@@ -9742,11 +10017,11 @@ static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
 #define alc882_pcm_digital_playback	alc880_pcm_digital_playback
 #define alc882_pcm_digital_playback	alc880_pcm_digital_playback
 #define alc882_pcm_digital_capture	alc880_pcm_digital_capture
 #define alc882_pcm_digital_capture	alc880_pcm_digital_capture
 
 
-static hda_nid_t alc883_slave_dig_outs[] = {
+static const hda_nid_t alc883_slave_dig_outs[] = {
 	ALC1200_DIGOUT_NID, 0,
 	ALC1200_DIGOUT_NID, 0,
 };
 };
 
 
-static hda_nid_t alc1200_slave_dig_outs[] = {
+static const hda_nid_t alc1200_slave_dig_outs[] = {
 	ALC883_DIGOUT_NID, 0,
 	ALC883_DIGOUT_NID, 0,
 };
 };
 
 
@@ -9805,7 +10080,7 @@ static const char * const alc882_models[ALC882_MODEL_LAST] = {
 	[ALC882_AUTO]		= "auto",
 	[ALC882_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk alc882_cfg_tbl[] = {
+static const struct snd_pci_quirk alc882_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
 	SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
 
 
 	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
@@ -9932,7 +10207,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
 };
 };
 
 
 /* codec SSID table for Intel Mac */
 /* codec SSID table for Intel Mac */
-static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
+static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
 	SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
 	SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
 	SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
 	SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
 	SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
@@ -9959,7 +10234,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static struct alc_config_preset alc882_presets[] = {
+static const struct alc_config_preset alc882_presets[] = {
 	[ALC882_3ST_DIG] = {
 	[ALC882_3ST_DIG] = {
 		.mixers = { alc882_base_mixer },
 		.mixers = { alc882_base_mixer },
 		.init_verbs = { alc882_base_init_verbs,
 		.init_verbs = { alc882_base_init_verbs,
@@ -10015,9 +10290,9 @@ static struct alc_config_preset alc882_presets[] = {
 			.channel_mode = alc885_mba21_ch_modes,
 			.channel_mode = alc885_mba21_ch_modes,
 			.num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
 			.num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
 			.input_mux = &alc882_capture_source,
 			.input_mux = &alc882_capture_source,
-			.unsol_event = alc_automute_amp_unsol_event,
+			.unsol_event = alc_sku_unsol_event,
 			.setup = alc885_mba21_setup,
 			.setup = alc885_mba21_setup,
-			.init_hook = alc_automute_amp,
+			.init_hook = alc_hp_automute,
        },
        },
 	[ALC885_MBP3] = {
 	[ALC885_MBP3] = {
 		.mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
 		.mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
@@ -10031,9 +10306,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.input_mux = &alc882_capture_source,
 		.input_mux = &alc882_capture_source,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc885_mbp3_setup,
 		.setup = alc885_mbp3_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC885_MB5] = {
 	[ALC885_MB5] = {
 		.mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
 		.mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
@@ -10046,9 +10321,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.input_mux = &mb5_capture_source,
 		.input_mux = &mb5_capture_source,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc885_mb5_setup,
 		.setup = alc885_mb5_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC885_MACMINI3] = {
 	[ALC885_MACMINI3] = {
 		.mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
 		.mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
@@ -10061,9 +10336,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.input_mux = &macmini3_capture_source,
 		.input_mux = &macmini3_capture_source,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc885_macmini3_setup,
 		.setup = alc885_macmini3_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC885_MACPRO] = {
 	[ALC885_MACPRO] = {
 		.mixers = { alc882_macpro_mixer },
 		.mixers = { alc882_macpro_mixer },
@@ -10087,7 +10362,7 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
 		.channel_mode = alc882_ch_modes,
 		.channel_mode = alc882_ch_modes,
 		.input_mux = &alc882_capture_source,
 		.input_mux = &alc882_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc885_imac24_setup,
 		.setup = alc885_imac24_setup,
 		.init_hook = alc885_imac24_init_hook,
 		.init_hook = alc885_imac24_init_hook,
 	},
 	},
@@ -10102,9 +10377,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.input_mux = &alc889A_imac91_capture_source,
 		.input_mux = &alc889A_imac91_capture_source,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
 		.dig_in_nid = ALC882_DIGIN_NID,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc885_imac91_setup,
 		.setup = alc885_imac91_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC882_TARGA] = {
 	[ALC882_TARGA] = {
 		.mixers = { alc882_targa_mixer, alc882_chmode_mixer },
 		.mixers = { alc882_targa_mixer, alc882_chmode_mixer },
@@ -10120,7 +10395,7 @@ static struct alc_config_preset alc882_presets[] = {
 		.channel_mode = alc882_3ST_6ch_modes,
 		.channel_mode = alc882_3ST_6ch_modes,
 		.need_dac_fix = 1,
 		.need_dac_fix = 1,
 		.input_mux = &alc882_capture_source,
 		.input_mux = &alc882_capture_source,
-		.unsol_event = alc882_targa_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc882_targa_setup,
 		.setup = alc882_targa_setup,
 		.init_hook = alc882_targa_automute,
 		.init_hook = alc882_targa_automute,
 	},
 	},
@@ -10214,8 +10489,8 @@ static struct alc_config_preset alc882_presets[] = {
 		.capsrc_nids = alc889_capsrc_nids,
 		.capsrc_nids = alc889_capsrc_nids,
 		.input_mux = &alc889_capture_source,
 		.input_mux = &alc889_capture_source,
 		.setup = alc889_automute_setup,
 		.setup = alc889_automute_setup,
-		.init_hook = alc_automute_amp,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.init_hook = alc_hp_automute,
+		.unsol_event = alc_sku_unsol_event,
 		.need_dac_fix = 1,
 		.need_dac_fix = 1,
 	},
 	},
 	[ALC889_INTEL] = {
 	[ALC889_INTEL] = {
@@ -10235,7 +10510,7 @@ static struct alc_config_preset alc882_presets[] = {
 		.input_mux = &alc889_capture_source,
 		.input_mux = &alc889_capture_source,
 		.setup = alc889_automute_setup,
 		.setup = alc889_automute_setup,
 		.init_hook = alc889_intel_init_hook,
 		.init_hook = alc889_intel_init_hook,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.need_dac_fix = 1,
 		.need_dac_fix = 1,
 	},
 	},
 	[ALC883_6ST_DIG] = {
 	[ALC883_6ST_DIG] = {
@@ -10324,9 +10599,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_acer_aspire_setup,
 		.setup = alc883_acer_aspire_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC888_ACER_ASPIRE_4930G] = {
 	[ALC888_ACER_ASPIRE_4930G] = {
 		.mixers = { alc888_acer_aspire_4930g_mixer,
 		.mixers = { alc888_acer_aspire_4930g_mixer,
@@ -10346,9 +10621,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_mux_defs =
 		.num_mux_defs =
 			ARRAY_SIZE(alc888_2_capture_sources),
 			ARRAY_SIZE(alc888_2_capture_sources),
 		.input_mux = alc888_2_capture_sources,
 		.input_mux = alc888_2_capture_sources,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_acer_aspire_4930g_setup,
 		.setup = alc888_acer_aspire_4930g_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC888_ACER_ASPIRE_6530G] = {
 	[ALC888_ACER_ASPIRE_6530G] = {
 		.mixers = { alc888_acer_aspire_6530_mixer },
 		.mixers = { alc888_acer_aspire_6530_mixer },
@@ -10365,9 +10640,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_mux_defs =
 		.num_mux_defs =
 			ARRAY_SIZE(alc888_2_capture_sources),
 			ARRAY_SIZE(alc888_2_capture_sources),
 		.input_mux = alc888_acer_aspire_6530_sources,
 		.input_mux = alc888_acer_aspire_6530_sources,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_acer_aspire_6530g_setup,
 		.setup = alc888_acer_aspire_6530g_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC888_ACER_ASPIRE_8930G] = {
 	[ALC888_ACER_ASPIRE_8930G] = {
 		.mixers = { alc889_acer_aspire_8930g_mixer,
 		.mixers = { alc889_acer_aspire_8930g_mixer,
@@ -10388,9 +10663,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_mux_defs =
 		.num_mux_defs =
 			ARRAY_SIZE(alc889_capture_sources),
 			ARRAY_SIZE(alc889_capture_sources),
 		.input_mux = alc889_capture_sources,
 		.input_mux = alc889_capture_sources,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc889_acer_aspire_8930g_setup,
 		.setup = alc889_acer_aspire_8930g_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 		.power_hook = alc_power_eapd,
 		.power_hook = alc_power_eapd,
 #endif
 #endif
@@ -10411,9 +10686,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.need_dac_fix = 1,
 		.need_dac_fix = 1,
 		.const_channel_count = 6,
 		.const_channel_count = 6,
 		.input_mux = &alc883_capture_source,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_acer_aspire_7730g_setup,
 		.setup = alc888_acer_aspire_7730g_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC883_MEDION] = {
 	[ALC883_MEDION] = {
 		.mixers = { alc883_fivestack_mixer,
 		.mixers = { alc883_fivestack_mixer,
@@ -10440,9 +10715,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_medion_wim2160_setup,
 		.setup = alc883_medion_wim2160_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC883_LAPTOP_EAPD] = {
 	[ALC883_LAPTOP_EAPD] = {
 		.mixers = { alc883_base_mixer },
 		.mixers = { alc883_base_mixer },
@@ -10492,8 +10767,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_lenovo_101e_capture_source,
 		.input_mux = &alc883_lenovo_101e_capture_source,
-		.unsol_event = alc883_lenovo_101e_unsol_event,
-		.init_hook = alc883_lenovo_101e_all_automute,
+		.setup = alc883_lenovo_101e_setup,
+		.unsol_event = alc_sku_unsol_event,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC883_LENOVO_NB0763] = {
 	[ALC883_LENOVO_NB0763] = {
 		.mixers = { alc883_lenovo_nb0763_mixer },
 		.mixers = { alc883_lenovo_nb0763_mixer },
@@ -10504,9 +10780,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.channel_mode = alc883_3ST_2ch_modes,
 		.channel_mode = alc883_3ST_2ch_modes,
 		.need_dac_fix = 1,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_lenovo_nb0763_capture_source,
 		.input_mux = &alc883_lenovo_nb0763_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_lenovo_nb0763_setup,
 		.setup = alc883_lenovo_nb0763_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC888_LENOVO_MS7195_DIG] = {
 	[ALC888_LENOVO_MS7195_DIG] = {
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -10518,8 +10794,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.channel_mode = alc883_3ST_6ch_modes,
 		.channel_mode = alc883_3ST_6ch_modes,
 		.need_dac_fix = 1,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_capture_source,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc883_lenovo_ms7195_unsol_event,
-		.init_hook = alc888_lenovo_ms7195_front_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc888_lenovo_ms7195_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC883_HAIER_W66] = {
 	[ALC883_HAIER_W66] = {
 		.mixers = { alc883_targa_2ch_mixer},
 		.mixers = { alc883_targa_2ch_mixer},
@@ -10530,9 +10807,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_haier_w66_setup,
 		.setup = alc883_haier_w66_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC888_3ST_HP] = {
 	[ALC888_3ST_HP] = {
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -10543,9 +10820,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.channel_mode = alc888_3st_hp_modes,
 		.channel_mode = alc888_3st_hp_modes,
 		.need_dac_fix = 1,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_capture_source,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_3st_hp_setup,
 		.setup = alc888_3st_hp_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC888_6ST_DELL] = {
 	[ALC888_6ST_DELL] = {
 		.mixers = { alc883_base_mixer, alc883_chmode_mixer },
 		.mixers = { alc883_base_mixer, alc883_chmode_mixer },
@@ -10557,9 +10834,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
 		.channel_mode = alc883_sixstack_modes,
 		.input_mux = &alc883_capture_source,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_6st_dell_setup,
 		.setup = alc888_6st_dell_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC883_MITAC] = {
 	[ALC883_MITAC] = {
 		.mixers = { alc883_mitac_mixer },
 		.mixers = { alc883_mitac_mixer },
@@ -10569,9 +10846,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_mitac_setup,
 		.setup = alc883_mitac_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC883_FUJITSU_PI2515] = {
 	[ALC883_FUJITSU_PI2515] = {
 		.mixers = { alc883_2ch_fujitsu_pi2515_mixer },
 		.mixers = { alc883_2ch_fujitsu_pi2515_mixer },
@@ -10583,9 +10860,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_fujitsu_pi2515_capture_source,
 		.input_mux = &alc883_fujitsu_pi2515_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_2ch_fujitsu_pi2515_setup,
 		.setup = alc883_2ch_fujitsu_pi2515_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC888_FUJITSU_XA3530] = {
 	[ALC888_FUJITSU_XA3530] = {
 		.mixers = { alc888_base_mixer, alc883_chmode_mixer },
 		.mixers = { alc888_base_mixer, alc883_chmode_mixer },
@@ -10602,9 +10879,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_mux_defs =
 		.num_mux_defs =
 			ARRAY_SIZE(alc888_2_capture_sources),
 			ARRAY_SIZE(alc888_2_capture_sources),
 		.input_mux = alc888_2_capture_sources,
 		.input_mux = alc888_2_capture_sources,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_fujitsu_xa3530_setup,
 		.setup = alc888_fujitsu_xa3530_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC888_LENOVO_SKY] = {
 	[ALC888_LENOVO_SKY] = {
 		.mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
 		.mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
@@ -10616,9 +10893,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.channel_mode = alc883_sixstack_modes,
 		.channel_mode = alc883_sixstack_modes,
 		.need_dac_fix = 1,
 		.need_dac_fix = 1,
 		.input_mux = &alc883_lenovo_sky_capture_source,
 		.input_mux = &alc883_lenovo_sky_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc888_lenovo_sky_setup,
 		.setup = alc888_lenovo_sky_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC888_ASUS_M90V] = {
 	[ALC888_ASUS_M90V] = {
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
 		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
@@ -10686,9 +10963,9 @@ static struct alc_config_preset alc882_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 		.input_mux = &alc883_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc883_vaiott_setup,
 		.setup = alc883_vaiott_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 };
 };
 
 
@@ -10734,7 +11011,7 @@ static const struct alc_fixup alc882_fixups[] = {
 	},
 	},
 };
 };
 
 
-static struct snd_pci_quirk alc882_fixup_tbl[] = {
+static const struct snd_pci_quirk alc882_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
 	SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
 	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
 	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
 	SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
 	SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
@@ -10842,6 +11119,11 @@ static void alc882_auto_init_input_src(struct hda_codec *codec)
 		const struct hda_input_mux *imux;
 		const struct hda_input_mux *imux;
 		int conns, mute, idx, item;
 		int conns, mute, idx, item;
 
 
+		/* mute ADC */
+		snd_hda_codec_write(codec, spec->adc_nids[c], 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_IN_MUTE(0));
+
 		conns = snd_hda_get_connections(codec, nid, conn_list,
 		conns = snd_hda_get_connections(codec, nid, conn_list,
 						ARRAY_SIZE(conn_list));
 						ARRAY_SIZE(conn_list));
 		if (conns < 0)
 		if (conns < 0)
@@ -10921,7 +11203,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
 static int alc882_parse_auto_config(struct hda_codec *codec)
 static int alc882_parse_auto_config(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
 	int err;
 	int err;
 
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
@@ -10932,6 +11214,9 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
 		return 0; /* can't find valid BIOS pin config */
 		return 0; /* can't find valid BIOS pin config */
 
 
 	err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
 	err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = alc_auto_add_multi_channel_mode(codec);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 	err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
 	err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
@@ -11135,14 +11420,14 @@ static int patch_alc882(struct hda_codec *codec)
 #define alc262_modes		alc260_modes
 #define alc262_modes		alc260_modes
 #define alc262_capture_source	alc882_capture_source
 #define alc262_capture_source	alc882_capture_source
 
 
-static hda_nid_t alc262_dmic_adc_nids[1] = {
+static const hda_nid_t alc262_dmic_adc_nids[1] = {
 	/* ADC0 */
 	/* ADC0 */
 	0x09
 	0x09
 };
 };
 
 
-static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
+static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
 
 
-static struct snd_kcontrol_new alc262_base_mixer[] = {
+static const struct snd_kcontrol_new alc262_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -11163,71 +11448,30 @@ static struct snd_kcontrol_new alc262_base_mixer[] = {
 };
 };
 
 
 /* update HP, line and mono-out pins according to the master switch */
 /* update HP, line and mono-out pins according to the master switch */
-static void alc262_hp_master_update(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	int val = spec->master_sw;
-
-	/* HP & line-out */
-	snd_hda_codec_write_cache(codec, 0x1b, 0,
-				  AC_VERB_SET_PIN_WIDGET_CONTROL,
-				  val ? PIN_HP : 0);
-	snd_hda_codec_write_cache(codec, 0x15, 0,
-				  AC_VERB_SET_PIN_WIDGET_CONTROL,
-				  val ? PIN_HP : 0);
-	/* mono (speaker) depending on the HP jack sense */
-	val = val && !spec->jack_present;
-	snd_hda_codec_write_cache(codec, 0x16, 0,
-				  AC_VERB_SET_PIN_WIDGET_CONTROL,
-				  val ? PIN_OUT : 0);
-}
+#define alc262_hp_master_update		alc260_hp_master_update
 
 
-static void alc262_hp_bpc_automute(struct hda_codec *codec)
+static void alc262_hp_bpc_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 
 
-	spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
-	alc262_hp_master_update(codec);
-}
-
-static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc262_hp_bpc_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x16;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 }
 
 
-static void alc262_hp_wildwest_automute(struct hda_codec *codec)
+static void alc262_hp_wildwest_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 
 
-	spec->jack_present = snd_hda_jack_detect(codec, 0x15);
-	alc262_hp_master_update(codec);
-}
-
-static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc262_hp_wildwest_automute(codec);
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x16;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 }
 
 
 #define alc262_hp_master_sw_get		alc260_hp_master_sw_get
 #define alc262_hp_master_sw_get		alc260_hp_master_sw_get
-
-static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	int val = !!*ucontrol->value.integer.value;
-
-	if (val == spec->master_sw)
-		return 0;
-	spec->master_sw = val;
-	alc262_hp_master_update(codec);
-	return 1;
-}
+#define alc262_hp_master_sw_put		alc260_hp_master_sw_put
 
 
 #define ALC262_HP_MASTER_SWITCH					\
 #define ALC262_HP_MASTER_SWITCH					\
 	{							\
 	{							\
@@ -11244,7 +11488,7 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 	}
 	}
 
 
 
 
-static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
+static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
 	ALC262_HP_MASTER_SWITCH,
 	ALC262_HP_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -11268,7 +11512,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
+static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
 	ALC262_HP_MASTER_SWITCH,
 	ALC262_HP_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -11288,7 +11532,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
+static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
 	HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
@@ -11302,9 +11546,11 @@ static void alc262_hp_t5735_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 }
 
 
-static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
+static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
@@ -11315,7 +11561,7 @@ static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc262_hp_t5735_verbs[] = {
+static const struct hda_verb alc262_hp_t5735_verbs[] = {
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 
 
@@ -11323,7 +11569,7 @@ static struct hda_verb alc262_hp_t5735_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
+static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
@@ -11333,7 +11579,7 @@ static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc262_hp_rp5700_verbs[] = {
+static const struct hda_verb alc262_hp_rp5700_verbs[] = {
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -11347,7 +11593,7 @@ static struct hda_verb alc262_hp_rp5700_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_input_mux alc262_hp_rp5700_capture_source = {
+static const struct hda_input_mux alc262_hp_rp5700_capture_source = {
 	.num_items = 1,
 	.num_items = 1,
 	.items = {
 	.items = {
 		{ "Line", 0x1 },
 		{ "Line", 0x1 },
@@ -11355,44 +11601,9 @@ static struct hda_input_mux alc262_hp_rp5700_capture_source = {
 };
 };
 
 
 /* bind hp and internal speaker mute (with plug check) as master switch */
 /* bind hp and internal speaker mute (with plug check) as master switch */
-static void alc262_hippo_master_update(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
-	hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
-	hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
-	unsigned int mute;
-
-	/* HP */
-	mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
-	snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, mute);
-	/* mute internal speaker per jack sense */
-	if (spec->jack_present)
-		mute = HDA_AMP_MUTE;
-	if (line_nid)
-		snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	if (speaker_nid && speaker_nid != line_nid)
-		snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-}
-
+#define alc262_hippo_master_update	alc262_hp_master_update
 #define alc262_hippo_master_sw_get	alc262_hp_master_sw_get
 #define alc262_hippo_master_sw_get	alc262_hp_master_sw_get
-
-static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
-				      struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	int val = !!*ucontrol->value.integer.value;
-
-	if (val == spec->master_sw)
-		return 0;
-	spec->master_sw = val;
-	alc262_hippo_master_update(codec);
-	return 1;
-}
+#define alc262_hippo_master_sw_put	alc262_hp_master_sw_put
 
 
 #define ALC262_HIPPO_MASTER_SWITCH				\
 #define ALC262_HIPPO_MASTER_SWITCH				\
 	{							\
 	{							\
@@ -11409,7 +11620,7 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
 			     (SUBDEV_SPEAKER(0) << 16), \
 			     (SUBDEV_SPEAKER(0) << 16), \
 	}
 	}
 
 
-static struct snd_kcontrol_new alc262_hippo_mixer[] = {
+static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
 	ALC262_HIPPO_MASTER_SWITCH,
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -11426,7 +11637,7 @@ static struct snd_kcontrol_new alc262_hippo_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
+static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	ALC262_HIPPO_MASTER_SWITCH,
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -11443,28 +11654,14 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
 };
 };
 
 
 /* mute/unmute internal speaker according to the hp jack and mute state */
 /* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hippo_automute(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
-
-	spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
-	alc262_hippo_master_update(codec);
-}
-
-static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc262_hippo_automute(codec);
-}
-
 static void alc262_hippo_setup(struct hda_codec *codec)
 static void alc262_hippo_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 
 
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc262_hippo1_setup(struct hda_codec *codec)
 static void alc262_hippo1_setup(struct hda_codec *codec)
@@ -11473,10 +11670,12 @@ static void alc262_hippo1_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 
 
-static struct snd_kcontrol_new alc262_sony_mixer[] = {
+static const struct snd_kcontrol_new alc262_sony_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	ALC262_HIPPO_MASTER_SWITCH,
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -11486,7 +11685,7 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
+static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	ALC262_HIPPO_MASTER_SWITCH,
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -11497,7 +11696,7 @@ static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc262_tyan_mixer[] = {
+static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
 	HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
@@ -11513,7 +11712,7 @@ static struct snd_kcontrol_new alc262_tyan_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc262_tyan_verbs[] = {
+static const struct hda_verb alc262_tyan_verbs[] = {
 	/* Headphone automute */
 	/* Headphone automute */
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -11535,6 +11734,8 @@ static void alc262_tyan_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 
 
@@ -11544,7 +11745,7 @@ static void alc262_tyan_setup(struct hda_codec *codec)
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc262_init_verbs[] = {
+static const struct hda_verb alc262_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
 	 */
@@ -11620,13 +11821,13 @@ static struct hda_verb alc262_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc262_eapd_verbs[] = {
+static const struct hda_verb alc262_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc262_hippo1_unsol_verbs[] = {
+static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
 	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
@@ -11636,7 +11837,7 @@ static struct hda_verb alc262_hippo1_unsol_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc262_sony_unsol_verbs[] = {
+static const struct hda_verb alc262_sony_unsol_verbs[] = {
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},	// Front Mic
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},	// Front Mic
@@ -11646,7 +11847,7 @@ static struct hda_verb alc262_sony_unsol_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
+static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -11655,7 +11856,7 @@ static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc262_toshiba_s06_verbs[] = {
+static const struct hda_verb alc262_toshiba_s06_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -11678,6 +11879,8 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec)
 	spec->int_mic.pin = 0x12;
 	spec->int_mic.pin = 0x12;
 	spec->int_mic.mux_idx = 9;
 	spec->int_mic.mux_idx = 9;
 	spec->auto_mic = 1;
 	spec->auto_mic = 1;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 }
 
 
 /*
 /*
@@ -11687,7 +11890,7 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec)
  *  0x18 = external mic
  *  0x18 = external mic
  */
  */
 
 
-static struct snd_kcontrol_new alc262_nec_mixer[] = {
+static const struct snd_kcontrol_new alc262_nec_mixer[] = {
 	HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
 
 
@@ -11700,7 +11903,7 @@ static struct snd_kcontrol_new alc262_nec_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc262_nec_verbs[] = {
+static const struct hda_verb alc262_nec_verbs[] = {
 	/* Unmute Speaker */
 	/* Unmute Speaker */
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 
 
@@ -11723,7 +11926,7 @@ static struct hda_verb alc262_nec_verbs[] = {
 
 
 #define ALC_HP_EVENT	0x37
 #define ALC_HP_EVENT	0x37
 
 
-static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
+static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
@@ -11731,20 +11934,20 @@ static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
+static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
+static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
 	/* Front Mic pin: input vref at 50% */
 	/* Front Mic pin: input vref at 50% */
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{}
 	{}
 };
 };
 
 
-static struct hda_input_mux alc262_fujitsu_capture_source = {
+static const struct hda_input_mux alc262_fujitsu_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -11753,7 +11956,7 @@ static struct hda_input_mux alc262_fujitsu_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc262_HP_capture_source = {
+static const struct hda_input_mux alc262_HP_capture_source = {
 	.num_items = 5,
 	.num_items = 5,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -11764,7 +11967,7 @@ static struct hda_input_mux alc262_HP_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc262_HP_D7000_capture_source = {
+static const struct hda_input_mux alc262_HP_D7000_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -11774,44 +11977,19 @@ static struct hda_input_mux alc262_HP_D7000_capture_source = {
 	},
 	},
 };
 };
 
 
-/* mute/unmute internal speaker according to the hp jacks and mute state */
-static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
+static void alc262_fujitsu_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
-
-	if (force || !spec->sense_updated) {
-		spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
-				     snd_hda_jack_detect(codec, 0x1b);
-		spec->sense_updated = 1;
-	}
-	/* unmute internal speaker only if both HPs are unplugged and
-	 * master switch is on
-	 */
-	if (spec->jack_present)
-		mute = HDA_AMP_MUTE;
-	else
-		mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, mute);
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) != ALC_HP_EVENT)
-		return;
-	alc262_fujitsu_automute(codec, 1);
-}
 
 
-static void alc262_fujitsu_init_hook(struct hda_codec *codec)
-{
-	alc262_fujitsu_automute(codec, 1);
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.hp_pins[1] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 /* bind volumes of both NID 0x0c and 0x0d */
 /* bind volumes of both NID 0x0c and 0x0d */
-static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
+static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
@@ -11820,78 +11998,15 @@ static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
 	},
 	},
 };
 };
 
 
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
-{
-	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
-
-	if (force || !spec->sense_updated) {
-		spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
-		spec->sense_updated = 1;
-	}
-	if (spec->jack_present) {
-		/* mute internal speaker */
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		/* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-		snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	}
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) != ALC_HP_EVENT)
-		return;
-	alc262_lenovo_3000_automute(codec, 1);
-}
-
-static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
-				  int dir, int idx, long *valp)
-{
-	int i, change = 0;
-
-	for (i = 0; i < 2; i++, valp++)
-		change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
-						   HDA_AMP_MUTE,
-						   *valp ? 0 : HDA_AMP_MUTE);
-	return change;
-}
-
-/* bind hp and internal speaker mute (with plug check) */
-static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
-					 struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	long *valp = ucontrol->value.integer.value;
-	int change;
-
-	change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
-	change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
-	if (change)
-		alc262_fujitsu_automute(codec, 0);
-	return change;
-}
-
-static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
+static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
 		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = alc262_fujitsu_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc262_hp_master_sw_get,
+		.put = alc262_hp_master_sw_put,
 	},
 	},
 	{
 	{
 		.iface = NID_MAPPING,
 		.iface = NID_MAPPING,
@@ -11909,30 +12024,26 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-/* bind hp and internal speaker mute (with plug check) */
-static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
-					 struct snd_ctl_elem_value *ucontrol)
+static void alc262_lenovo_3000_setup(struct hda_codec *codec)
 {
 {
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	long *valp = ucontrol->value.integer.value;
-	int change;
+	struct alc_spec *spec = codec->spec;
 
 
-	change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
-	if (change)
-		alc262_lenovo_3000_automute(codec, 0);
-	return change;
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x16;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
+static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
 		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = alc262_lenovo_3000_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc262_hp_master_sw_get,
+		.put = alc262_hp_master_sw_put,
 	},
 	},
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
@@ -11945,7 +12056,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
+static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
 	ALC262_HIPPO_MASTER_SWITCH,
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -11958,13 +12069,13 @@ static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
 };
 };
 
 
 /* additional init verbs for Benq laptops */
 /* additional init verbs for Benq laptops */
-static struct hda_verb alc262_EAPD_verbs[] = {
+static const struct hda_verb alc262_EAPD_verbs[] = {
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
 	{0x20, AC_VERB_SET_PROC_COEF,  0x3070},
 	{0x20, AC_VERB_SET_PROC_COEF,  0x3070},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
+static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
 
 
@@ -11974,7 +12085,7 @@ static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
 };
 };
 
 
 /* Samsung Q1 Ultra Vista model setup */
 /* Samsung Q1 Ultra Vista model setup */
-static struct snd_kcontrol_new alc262_ultra_mixer[] = {
+static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
@@ -11984,7 +12095,7 @@ static struct snd_kcontrol_new alc262_ultra_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc262_ultra_verbs[] = {
+static const struct hda_verb alc262_ultra_verbs[] = {
 	/* output mixer */
 	/* output mixer */
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
@@ -12047,7 +12158,7 @@ static void alc262_ultra_unsol_event(struct hda_codec *codec,
 	alc262_ultra_automute(codec);
 	alc262_ultra_automute(codec);
 }
 }
 
 
-static struct hda_input_mux alc262_ultra_capture_source = {
+static const struct hda_input_mux alc262_ultra_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x1 },
 		{ "Mic", 0x1 },
@@ -12073,7 +12184,7 @@ static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
 	return ret;
 	return ret;
 }
 }
 
 
-static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
+static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
 	{
 	{
@@ -12148,9 +12259,9 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
 
 
 	spec->multiout.num_dacs = 1;	/* only use one dac */
 	spec->multiout.num_dacs = 1;	/* only use one dac */
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	spec->multiout.dac_nids = spec->private_dac_nids;
-	spec->multiout.dac_nids[0] = 2;
+	spec->private_dac_nids[0] = 2;
 
 
-	pfx = alc_get_line_out_pfx(cfg, true);
+	pfx = alc_get_line_out_pfx(spec, true);
 	if (!pfx)
 	if (!pfx)
 		pfx = "Front";
 		pfx = "Front";
 	for (i = 0; i < 2; i++) {
 	for (i = 0; i < 2; i++) {
@@ -12204,7 +12315,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc262_volume_init_verbs[] = {
+static const struct hda_verb alc262_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
 	 */
@@ -12265,7 +12376,7 @@ static struct hda_verb alc262_volume_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc262_HP_BPC_init_verbs[] = {
+static const struct hda_verb alc262_HP_BPC_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
 	 */
@@ -12369,7 +12480,7 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
+static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
 	 */
@@ -12465,7 +12576,7 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
+static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
 
 
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },	/* Front Speaker */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },	/* Front Speaker */
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
@@ -12501,7 +12612,7 @@ static const struct alc_fixup alc262_fixups[] = {
 	},
 	},
 };
 };
 
 
-static struct snd_pci_quirk alc262_fixup_tbl[] = {
+static const struct snd_pci_quirk alc262_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
 	SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
 	{}
 	{}
 };
 };
@@ -12524,7 +12635,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	int err;
 	int err;
-	static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
 
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc262_ignore);
 					   alc262_ignore);
@@ -12609,7 +12720,7 @@ static const char * const alc262_models[ALC262_MODEL_LAST] = {
 	[ALC262_AUTO]		= "auto",
 	[ALC262_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk alc262_cfg_tbl[] = {
+static const struct snd_pci_quirk alc262_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
 	SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
 	SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
 	SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
@@ -12661,7 +12772,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
 	{}
 	{}
 };
 };
 
 
-static struct alc_config_preset alc262_presets[] = {
+static const struct alc_config_preset alc262_presets[] = {
 	[ALC262_BASIC] = {
 	[ALC262_BASIC] = {
 		.mixers = { alc262_base_mixer },
 		.mixers = { alc262_base_mixer },
 		.init_verbs = { alc262_init_verbs },
 		.init_verbs = { alc262_init_verbs },
@@ -12682,9 +12793,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_hippo_setup,
 		.setup = alc262_hippo_setup,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC262_HIPPO_1] = {
 	[ALC262_HIPPO_1] = {
 		.mixers = { alc262_hippo1_mixer },
 		.mixers = { alc262_hippo1_mixer },
@@ -12696,9 +12807,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_hippo1_setup,
 		.setup = alc262_hippo1_setup,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC262_FUJITSU] = {
 	[ALC262_FUJITSU] = {
 		.mixers = { alc262_fujitsu_mixer },
 		.mixers = { alc262_fujitsu_mixer },
@@ -12711,8 +12822,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_fujitsu_capture_source,
 		.input_mux = &alc262_fujitsu_capture_source,
-		.unsol_event = alc262_fujitsu_unsol_event,
-		.init_hook = alc262_fujitsu_init_hook,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc262_fujitsu_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC262_HP_BPC] = {
 	[ALC262_HP_BPC] = {
 		.mixers = { alc262_HP_BPC_mixer },
 		.mixers = { alc262_HP_BPC_mixer },
@@ -12723,8 +12835,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_HP_capture_source,
 		.input_mux = &alc262_HP_capture_source,
-		.unsol_event = alc262_hp_bpc_unsol_event,
-		.init_hook = alc262_hp_bpc_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc262_hp_bpc_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC262_HP_BPC_D7000_WF] = {
 	[ALC262_HP_BPC_D7000_WF] = {
 		.mixers = { alc262_HP_BPC_WildWest_mixer },
 		.mixers = { alc262_HP_BPC_WildWest_mixer },
@@ -12735,8 +12848,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_HP_D7000_capture_source,
 		.input_mux = &alc262_HP_D7000_capture_source,
-		.unsol_event = alc262_hp_wildwest_unsol_event,
-		.init_hook = alc262_hp_wildwest_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc262_hp_wildwest_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC262_HP_BPC_D7000_WL] = {
 	[ALC262_HP_BPC_D7000_WL] = {
 		.mixers = { alc262_HP_BPC_WildWest_mixer,
 		.mixers = { alc262_HP_BPC_WildWest_mixer,
@@ -12748,8 +12862,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_HP_D7000_capture_source,
 		.input_mux = &alc262_HP_D7000_capture_source,
-		.unsol_event = alc262_hp_wildwest_unsol_event,
-		.init_hook = alc262_hp_wildwest_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc262_hp_wildwest_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC262_HP_TC_T5735] = {
 	[ALC262_HP_TC_T5735] = {
 		.mixers = { alc262_hp_t5735_mixer },
 		.mixers = { alc262_hp_t5735_mixer },
@@ -12792,9 +12907,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_hippo_setup,
 		.setup = alc262_hippo_setup,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC262_BENQ_T31] = {
 	[ALC262_BENQ_T31] = {
 		.mixers = { alc262_benq_t31_mixer },
 		.mixers = { alc262_benq_t31_mixer },
@@ -12806,9 +12921,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_hippo_setup,
 		.setup = alc262_hippo_setup,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC262_ULTRA] = {
 	[ALC262_ULTRA] = {
 		.mixers = { alc262_ultra_mixer },
 		.mixers = { alc262_ultra_mixer },
@@ -12837,7 +12952,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_fujitsu_capture_source,
 		.input_mux = &alc262_fujitsu_capture_source,
-		.unsol_event = alc262_lenovo_3000_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc262_lenovo_3000_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC262_NEC] = {
 	[ALC262_NEC] = {
 		.mixers = { alc262_nec_mixer },
 		.mixers = { alc262_nec_mixer },
@@ -12874,9 +12991,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc262_hippo_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_hippo_setup,
 		.setup = alc262_hippo_setup,
-		.init_hook = alc262_hippo_automute,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC262_TYAN] = {
 	[ALC262_TYAN] = {
 		.mixers = { alc262_tyan_mixer },
 		.mixers = { alc262_tyan_mixer },
@@ -12888,9 +13005,9 @@ static struct alc_config_preset alc262_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.input_mux = &alc262_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc262_tyan_setup,
 		.setup = alc262_tyan_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 };
 };
 
 
@@ -13011,6 +13128,7 @@ static int patch_alc262(struct hda_codec *codec)
 	codec->patch_ops = alc_patch_ops;
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC262_AUTO)
 	if (board_config == ALC262_AUTO)
 		spec->init_hook = alc262_auto_init;
 		spec->init_hook = alc262_auto_init;
+	spec->shutup = alc_eapd_shutup;
 
 
 	alc_init_jacks(codec);
 	alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -13027,24 +13145,24 @@ static int patch_alc262(struct hda_codec *codec)
 #define ALC268_DIGOUT_NID	ALC880_DIGOUT_NID
 #define ALC268_DIGOUT_NID	ALC880_DIGOUT_NID
 #define alc268_modes		alc260_modes
 #define alc268_modes		alc260_modes
 
 
-static hda_nid_t alc268_dac_nids[2] = {
+static const hda_nid_t alc268_dac_nids[2] = {
 	/* front, hp */
 	/* front, hp */
 	0x02, 0x03
 	0x02, 0x03
 };
 };
 
 
-static hda_nid_t alc268_adc_nids[2] = {
+static const hda_nid_t alc268_adc_nids[2] = {
 	/* ADC0-1 */
 	/* ADC0-1 */
 	0x08, 0x07
 	0x08, 0x07
 };
 };
 
 
-static hda_nid_t alc268_adc_nids_alt[1] = {
+static const hda_nid_t alc268_adc_nids_alt[1] = {
 	/* ADC0 */
 	/* ADC0 */
 	0x08
 	0x08
 };
 };
 
 
-static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
+static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
 
 
-static struct snd_kcontrol_new alc268_base_mixer[] = {
+static const struct snd_kcontrol_new alc268_base_mixer[] = {
 	/* output mixer control */
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -13056,7 +13174,7 @@ static struct snd_kcontrol_new alc268_base_mixer[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
+static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
 	/* output mixer control */
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
@@ -13068,7 +13186,7 @@ static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
 };
 };
 
 
 /* bind Beep switches of both NID 0x0f and 0x10 */
 /* bind Beep switches of both NID 0x0f and 0x10 */
-static struct hda_bind_ctls alc268_bind_beep_sw = {
+static const struct hda_bind_ctls alc268_bind_beep_sw = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
 		HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
@@ -13077,27 +13195,27 @@ static struct hda_bind_ctls alc268_bind_beep_sw = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new alc268_beep_mixer[] = {
+static const struct snd_kcontrol_new alc268_beep_mixer[] = {
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
 	HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
 	HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc268_eapd_verbs[] = {
+static const struct hda_verb alc268_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 	{ }
 };
 };
 
 
 /* Toshiba specific */
 /* Toshiba specific */
-static struct hda_verb alc268_toshiba_verbs[] = {
+static const struct hda_verb alc268_toshiba_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
 /* Acer specific */
 /* Acer specific */
 /* bind volumes of both NID 0x02 and 0x03 */
 /* bind volumes of both NID 0x02 and 0x03 */
-static struct hda_bind_ctls alc268_acer_bind_master_vol = {
+static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
@@ -13106,66 +13224,44 @@ static struct hda_bind_ctls alc268_acer_bind_master_vol = {
 	},
 	},
 };
 };
 
 
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc268_acer_automute(struct hda_codec *codec, int force)
+static void alc268_acer_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
 
 
-	if (force || !spec->sense_updated) {
-		spec->jack_present = snd_hda_jack_detect(codec, 0x14);
-		spec->sense_updated = 1;
-	}
-	if (spec->jack_present)
-		mute = HDA_AMP_MUTE; /* mute internal speaker */
-	else /* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, mute);
+	spec->autocfg.hp_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
+#define alc268_acer_master_sw_get	alc262_hp_master_sw_get
+#define alc268_acer_master_sw_put	alc262_hp_master_sw_put
 
 
-/* bind hp and internal speaker mute (with plug check) */
-static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
-				     struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	long *valp = ucontrol->value.integer.value;
-	int change;
-
-	change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
-	if (change)
-		alc268_acer_automute(codec, 0);
-	return change;
-}
-
-static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
+static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
 	/* output mixer control */
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
 		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc268_acer_master_sw_get,
 		.put = alc268_acer_master_sw_put,
 		.put = alc268_acer_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 	},
 	},
 	HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
 	{ }
 	{ }
 };
 };
 
 
-static struct snd_kcontrol_new alc268_acer_mixer[] = {
+static const struct snd_kcontrol_new alc268_acer_mixer[] = {
 	/* output mixer control */
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
 		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc268_acer_master_sw_get,
 		.put = alc268_acer_master_sw_put,
 		.put = alc268_acer_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 	},
 	},
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
@@ -13173,24 +13269,23 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
+static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
 	/* output mixer control */
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
 		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc268_acer_master_sw_get,
 		.put = alc268_acer_master_sw_put,
 		.put = alc268_acer_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 	},
 	},
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc268_acer_aspire_one_verbs[] = {
+static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
@@ -13200,7 +13295,7 @@ static struct hda_verb alc268_acer_aspire_one_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc268_acer_verbs[] = {
+static const struct hda_verb alc268_acer_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -13212,67 +13307,24 @@ static struct hda_verb alc268_acer_verbs[] = {
 };
 };
 
 
 /* unsolicited event for HP jack sensing */
 /* unsolicited event for HP jack sensing */
-#define alc268_toshiba_unsol_event	alc262_hippo_unsol_event
 #define alc268_toshiba_setup		alc262_hippo_setup
 #define alc268_toshiba_setup		alc262_hippo_setup
-#define alc268_toshiba_automute		alc262_hippo_automute
 
 
-static void alc268_acer_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	if ((res >> 26) != ALC880_HP_EVENT)
-		return;
-	alc268_acer_automute(codec, 1);
-}
-
-static void alc268_acer_init_hook(struct hda_codec *codec)
+static void alc268_acer_lc_setup(struct hda_codec *codec)
 {
 {
-	alc268_acer_automute(codec, 1);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0f;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x12;
+	spec->int_mic.mux_idx = 6;
+	spec->auto_mic = 1;
 }
 }
 
 
-/* toggle speaker-output according to the hp-jack state */
-static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x15);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
-				    unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc268_aspire_one_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-static void alc268_acer_lc_setup(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	spec->ext_mic.pin = 0x18;
-	spec->ext_mic.mux_idx = 0;
-	spec->int_mic.pin = 0x12;
-	spec->int_mic.mux_idx = 6;
-	spec->auto_mic = 1;
-}
-
-static void alc268_acer_lc_init_hook(struct hda_codec *codec)
-{
-	alc268_aspire_one_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
-static struct snd_kcontrol_new alc268_dell_mixer[] = {
+static const struct snd_kcontrol_new alc268_dell_mixer[] = {
 	/* output mixer control */
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -13283,7 +13335,7 @@ static struct snd_kcontrol_new alc268_dell_mixer[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc268_dell_verbs[] = {
+static const struct hda_verb alc268_dell_verbs[] = {
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
@@ -13303,9 +13355,11 @@ static void alc268_dell_setup(struct hda_codec *codec)
 	spec->int_mic.pin = 0x19;
 	spec->int_mic.pin = 0x19;
 	spec->int_mic.mux_idx = 1;
 	spec->int_mic.mux_idx = 1;
 	spec->auto_mic = 1;
 	spec->auto_mic = 1;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 }
 
 
-static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
+static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
@@ -13317,7 +13371,7 @@ static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc267_quanta_il1_verbs[] = {
+static const struct hda_verb alc267_quanta_il1_verbs[] = {
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
 	{ }
 	{ }
@@ -13333,12 +13387,14 @@ static void alc267_quanta_il1_setup(struct hda_codec *codec)
 	spec->int_mic.pin = 0x19;
 	spec->int_mic.pin = 0x19;
 	spec->int_mic.mux_idx = 1;
 	spec->int_mic.mux_idx = 1;
 	spec->auto_mic = 1;
 	spec->auto_mic = 1;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
 }
 }
 
 
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc268_base_init_verbs[] = {
+static const struct hda_verb alc268_base_init_verbs[] = {
 	/* Unmute DAC0-1 and set vol = 0 */
 	/* Unmute DAC0-1 and set vol = 0 */
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -13386,7 +13442,7 @@ static struct hda_verb alc268_base_init_verbs[] = {
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc268_volume_init_verbs[] = {
+static const struct hda_verb alc268_volume_init_verbs[] = {
 	/* set output DAC */
 	/* set output DAC */
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -13412,20 +13468,20 @@ static struct hda_verb alc268_volume_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
+static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
+static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
 	_DEFINE_CAPSRC(1),
 	_DEFINE_CAPSRC(1),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc268_capture_mixer[] = {
+static const struct snd_kcontrol_new alc268_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
@@ -13434,7 +13490,7 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_input_mux alc268_capture_source = {
+static const struct hda_input_mux alc268_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -13444,7 +13500,7 @@ static struct hda_input_mux alc268_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc268_acer_capture_source = {
+static const struct hda_input_mux alc268_acer_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -13453,7 +13509,7 @@ static struct hda_input_mux alc268_acer_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc268_acer_dmic_capture_source = {
+static const struct hda_input_mux alc268_acer_dmic_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -13463,7 +13519,7 @@ static struct hda_input_mux alc268_acer_dmic_capture_source = {
 };
 };
 
 
 #ifdef CONFIG_SND_DEBUG
 #ifdef CONFIG_SND_DEBUG
-static struct snd_kcontrol_new alc268_test_mixer[] = {
+static const struct snd_kcontrol_new alc268_test_mixer[] = {
 	/* Volume widgets */
 	/* Volume widgets */
 	HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -13542,7 +13598,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
 						      HDA_OUTPUT));
 						      HDA_OUTPUT));
 		if (err < 0)
 		if (err < 0)
 			return err;
 			return err;
-		spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+		spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
 	}
 	}
 
 
 	if (nid != 0x16)
 	if (nid != 0x16)
@@ -13715,7 +13771,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	int err;
 	int err;
-	static hda_nid_t alc268_ignore[] = { 0 };
+	static const hda_nid_t alc268_ignore[] = { 0 };
 
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc268_ignore);
 					   alc268_ignore);
@@ -13795,7 +13851,7 @@ static const char * const alc268_models[ALC268_MODEL_LAST] = {
 	[ALC268_AUTO]		= "auto",
 	[ALC268_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk alc268_cfg_tbl[] = {
+static const struct snd_pci_quirk alc268_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
 	SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
@@ -13820,7 +13876,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
 };
 };
 
 
 /* Toshiba laptops have no unique PCI SSID but only codec SSID */
 /* Toshiba laptops have no unique PCI SSID but only codec SSID */
-static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
+static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
 	SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
 	SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
 	SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
 	SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
 	SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
@@ -13828,7 +13884,7 @@ static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
 	{}
 	{}
 };
 };
 
 
-static struct alc_config_preset alc268_presets[] = {
+static const struct alc_config_preset alc268_presets[] = {
 	[ALC267_QUANTA_IL1] = {
 	[ALC267_QUANTA_IL1] = {
 		.mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
 		.mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
 			    alc268_capture_nosrc_mixer },
 			    alc268_capture_nosrc_mixer },
@@ -13874,9 +13930,9 @@ static struct alc_config_preset alc268_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_capture_source,
 		.input_mux = &alc268_capture_source,
-		.unsol_event = alc268_toshiba_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc268_toshiba_setup,
 		.setup = alc268_toshiba_setup,
-		.init_hook = alc268_toshiba_automute,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC268_ACER] = {
 	[ALC268_ACER] = {
 		.mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
 		.mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
@@ -13892,8 +13948,9 @@ static struct alc_config_preset alc268_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_acer_capture_source,
 		.input_mux = &alc268_acer_capture_source,
-		.unsol_event = alc268_acer_unsol_event,
-		.init_hook = alc268_acer_init_hook,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc268_acer_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC268_ACER_DMIC] = {
 	[ALC268_ACER_DMIC] = {
 		.mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
 		.mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
@@ -13909,8 +13966,9 @@ static struct alc_config_preset alc268_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_acer_dmic_capture_source,
 		.input_mux = &alc268_acer_dmic_capture_source,
-		.unsol_event = alc268_acer_unsol_event,
-		.init_hook = alc268_acer_init_hook,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc268_acer_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC268_ACER_ASPIRE_ONE] = {
 	[ALC268_ACER_ASPIRE_ONE] = {
 		.mixers = { alc268_acer_aspire_one_mixer,
 		.mixers = { alc268_acer_aspire_one_mixer,
@@ -13926,9 +13984,9 @@ static struct alc_config_preset alc268_presets[] = {
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
 		.channel_mode = alc268_modes,
-		.unsol_event = alc268_acer_lc_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc268_acer_lc_setup,
 		.setup = alc268_acer_lc_setup,
-		.init_hook = alc268_acer_lc_init_hook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC268_DELL] = {
 	[ALC268_DELL] = {
 		.mixers = { alc268_dell_mixer, alc268_beep_mixer,
 		.mixers = { alc268_dell_mixer, alc268_beep_mixer,
@@ -13962,8 +14020,9 @@ static struct alc_config_preset alc268_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
 		.channel_mode = alc268_modes,
 		.input_mux = &alc268_capture_source,
 		.input_mux = &alc268_capture_source,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc268_toshiba_setup,
 		.setup = alc268_toshiba_setup,
-		.init_hook = alc268_toshiba_automute,
+		.init_hook = alc_inithook,
 	},
 	},
 #ifdef CONFIG_SND_DEBUG
 #ifdef CONFIG_SND_DEBUG
 	[ALC268_TEST] = {
 	[ALC268_TEST] = {
@@ -14085,6 +14144,7 @@ static int patch_alc268(struct hda_codec *codec)
 	codec->patch_ops = alc_patch_ops;
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC268_AUTO)
 	if (board_config == ALC268_AUTO)
 		spec->init_hook = alc268_auto_init;
 		spec->init_hook = alc268_auto_init;
+	spec->shutup = alc_eapd_shutup;
 
 
 	alc_init_jacks(codec);
 	alc_init_jacks(codec);
 
 
@@ -14098,32 +14158,32 @@ static int patch_alc268(struct hda_codec *codec)
 
 
 #define alc269_dac_nids		alc260_dac_nids
 #define alc269_dac_nids		alc260_dac_nids
 
 
-static hda_nid_t alc269_adc_nids[1] = {
+static const hda_nid_t alc269_adc_nids[1] = {
 	/* ADC1 */
 	/* ADC1 */
 	0x08,
 	0x08,
 };
 };
 
 
-static hda_nid_t alc269_capsrc_nids[1] = {
+static const hda_nid_t alc269_capsrc_nids[1] = {
 	0x23,
 	0x23,
 };
 };
 
 
-static hda_nid_t alc269vb_adc_nids[1] = {
+static const hda_nid_t alc269vb_adc_nids[1] = {
 	/* ADC1 */
 	/* ADC1 */
 	0x09,
 	0x09,
 };
 };
 
 
-static hda_nid_t alc269vb_capsrc_nids[1] = {
+static const hda_nid_t alc269vb_capsrc_nids[1] = {
 	0x22,
 	0x22,
 };
 };
 
 
-static hda_nid_t alc269_adc_candidates[] = {
+static const hda_nid_t alc269_adc_candidates[] = {
 	0x08, 0x09, 0x07, 0x11,
 	0x08, 0x09, 0x07, 0x11,
 };
 };
 
 
 #define alc269_modes		alc260_modes
 #define alc269_modes		alc260_modes
 #define alc269_capture_source	alc880_lg_lw_capture_source
 #define alc269_capture_source	alc880_lg_lw_capture_source
 
 
-static struct snd_kcontrol_new alc269_base_mixer[] = {
+static const struct snd_kcontrol_new alc269_base_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
@@ -14139,7 +14199,7 @@ static struct snd_kcontrol_new alc269_base_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
+static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
 	/* output mixer control */
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	{
 	{
@@ -14160,7 +14220,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
+static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
 	/* output mixer control */
 	/* output mixer control */
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
 	{
 	{
@@ -14184,7 +14244,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct snd_kcontrol_new alc269_laptop_mixer[] = {
+static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -14192,7 +14252,7 @@ static struct snd_kcontrol_new alc269_laptop_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
+static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
@@ -14200,14 +14260,14 @@ static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc269_asus_mixer[] = {
+static const struct snd_kcontrol_new alc269_asus_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
 /* capture mixer elements */
 /* capture mixer elements */
-static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
+static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
@@ -14215,14 +14275,14 @@ static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
+static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
+static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
@@ -14230,7 +14290,7 @@ static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
+static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
@@ -14240,7 +14300,7 @@ static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
 /* FSC amilo */
 /* FSC amilo */
 #define alc269_fujitsu_mixer	alc269_laptop_mixer
 #define alc269_fujitsu_mixer	alc269_laptop_mixer
 
 
-static struct hda_verb alc269_quanta_fl1_verbs[] = {
+static const struct hda_verb alc269_quanta_fl1_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -14250,7 +14310,7 @@ static struct hda_verb alc269_quanta_fl1_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc269_lifebook_verbs[] = {
+static const struct hda_verb alc269_lifebook_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -14267,15 +14327,7 @@ static struct hda_verb alc269_lifebook_verbs[] = {
 /* toggle speaker-output according to the hp-jack state */
 /* toggle speaker-output according to the hp-jack state */
 static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
 static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
 {
 {
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x15);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
+	alc_hp_automute(codec);
 
 
 	snd_hda_codec_write(codec, 0x20, 0,
 	snd_hda_codec_write(codec, 0x20, 0,
 			AC_VERB_SET_COEF_INDEX, 0x0c);
 			AC_VERB_SET_COEF_INDEX, 0x0c);
@@ -14288,34 +14340,8 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
 			AC_VERB_SET_PROC_COEF, 0x480);
 			AC_VERB_SET_PROC_COEF, 0x480);
 }
 }
 
 
-/* toggle speaker-output according to the hp-jacks state */
-static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	/* Check laptop headphone socket */
-	present = snd_hda_jack_detect(codec, 0x15);
-
-	/* Check port replicator headphone socket */
-	present |= snd_hda_jack_detect(codec, 0x1a);
-
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_COEF_INDEX, 0x0c);
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_PROC_COEF, 0x680);
-
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_COEF_INDEX, 0x0c);
-	snd_hda_codec_write(codec, 0x20, 0,
-			AC_VERB_SET_PROC_COEF, 0x480);
-}
+#define alc269_lifebook_speaker_automute \
+	alc269_quanta_fl1_speaker_automute
 
 
 static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
 static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
 {
 {
@@ -14364,6 +14390,9 @@ static void alc269_quanta_fl1_setup(struct hda_codec *codec)
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x19;
 	spec->int_mic.pin = 0x19;
@@ -14377,13 +14406,24 @@ static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
 	alc_mic_automute(codec);
 	alc_mic_automute(codec);
 }
 }
 
 
+static void alc269_lifebook_setup(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.hp_pins[1] = 0x1a;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
+}
+
 static void alc269_lifebook_init_hook(struct hda_codec *codec)
 static void alc269_lifebook_init_hook(struct hda_codec *codec)
 {
 {
 	alc269_lifebook_speaker_automute(codec);
 	alc269_lifebook_speaker_automute(codec);
 	alc269_lifebook_mic_autoswitch(codec);
 	alc269_lifebook_mic_autoswitch(codec);
 }
 }
 
 
-static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
+static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
 	{0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
@@ -14394,7 +14434,7 @@ static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc269_laptop_amic_init_verbs[] = {
+static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
@@ -14404,7 +14444,7 @@ static struct hda_verb alc269_laptop_amic_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
+static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
 	{0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
@@ -14415,7 +14455,7 @@ static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
+static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
@@ -14426,7 +14466,7 @@ static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc271_acer_dmic_verbs[] = {
+static const struct hda_verb alc271_acer_dmic_verbs[] = {
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
 	{0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
 	{0x20, AC_VERB_SET_PROC_COEF, 0x4000},
 	{0x20, AC_VERB_SET_PROC_COEF, 0x4000},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -14440,42 +14480,14 @@ static struct hda_verb alc271_acer_dmic_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-/* toggle speaker-output according to the hp-jack state */
-static void alc269_speaker_automute(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	unsigned int nid = spec->autocfg.hp_pins[0];
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, nid);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_input_jack_report(codec, nid);
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc269_laptop_unsol_event(struct hda_codec *codec,
-				     unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc269_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
 static void alc269_laptop_amic_setup(struct hda_codec *codec)
 static void alc269_laptop_amic_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x19;
 	spec->int_mic.pin = 0x19;
@@ -14488,6 +14500,9 @@ static void alc269_laptop_dmic_setup(struct hda_codec *codec)
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x12;
 	spec->int_mic.pin = 0x12;
@@ -14500,6 +14515,9 @@ static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x21;
 	spec->autocfg.hp_pins[0] = 0x21;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x19;
 	spec->int_mic.pin = 0x19;
@@ -14512,6 +14530,9 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x21;
 	spec->autocfg.hp_pins[0] = 0x21;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x12;
 	spec->int_mic.pin = 0x12;
@@ -14519,16 +14540,10 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
 	spec->auto_mic = 1;
 	spec->auto_mic = 1;
 }
 }
 
 
-static void alc269_laptop_inithook(struct hda_codec *codec)
-{
-	alc269_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc269_init_verbs[] = {
+static const struct hda_verb alc269_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
 	 */
@@ -14571,7 +14586,7 @@ static struct hda_verb alc269_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc269vb_init_verbs[] = {
+static const struct hda_verb alc269vb_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
 	 */
@@ -14629,7 +14644,7 @@ static struct hda_verb alc269vb_init_verbs[] = {
 #define alc269_pcm_digital_playback	alc880_pcm_digital_playback
 #define alc269_pcm_digital_playback	alc880_pcm_digital_playback
 #define alc269_pcm_digital_capture	alc880_pcm_digital_capture
 #define alc269_pcm_digital_capture	alc880_pcm_digital_capture
 
 
-static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
+static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.channels_max = 8,
@@ -14642,7 +14657,7 @@ static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
+static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -14726,7 +14741,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	int err;
 	int err;
-	static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
 
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc269_ignore);
 					   alc269_ignore);
@@ -14796,7 +14811,6 @@ static void alc269_auto_init(struct hda_codec *codec)
 		alc_inithook(codec);
 		alc_inithook(codec);
 }
 }
 
 
-#ifdef SND_HDA_NEEDS_RESUME
 static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
 static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
 {
 {
 	int val = alc_read_coef_idx(codec, 0x04);
 	int val = alc_read_coef_idx(codec, 0x04);
@@ -14807,25 +14821,17 @@ static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
 	alc_write_coef_idx(codec, 0x04, val);
 	alc_write_coef_idx(codec, 0x04, val);
 }
 }
 
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
+static void alc269_shutup(struct hda_codec *codec)
 {
 {
-	struct alc_spec *spec = codec->spec;
-
 	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
 	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
 		alc269_toggle_power_output(codec, 0);
 		alc269_toggle_power_output(codec, 0);
 	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
 	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
 		alc269_toggle_power_output(codec, 0);
 		alc269_toggle_power_output(codec, 0);
 		msleep(150);
 		msleep(150);
 	}
 	}
-
-	alc_shutup(codec);
-	if (spec && spec->power_hook)
-		spec->power_hook(codec);
-	return 0;
 }
 }
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
 
 
+#ifdef SND_HDA_NEEDS_RESUME
 static int alc269_resume(struct hda_codec *codec)
 static int alc269_resume(struct hda_codec *codec)
 {
 {
 	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
 	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
@@ -14864,7 +14870,7 @@ static void alc269_fixup_hweq(struct hda_codec *codec,
 static void alc271_fixup_dmic(struct hda_codec *codec,
 static void alc271_fixup_dmic(struct hda_codec *codec,
 			      const struct alc_fixup *fix, int action)
 			      const struct alc_fixup *fix, int action)
 {
 {
-	static struct hda_verb verbs[] = {
+	static const struct hda_verb verbs[] = {
 		{0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
 		{0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
 		{0x20, AC_VERB_SET_PROC_COEF, 0x4000},
 		{0x20, AC_VERB_SET_PROC_COEF, 0x4000},
 		{}
 		{}
@@ -14947,7 +14953,7 @@ static const struct alc_fixup alc269_fixups[] = {
 	},
 	},
 };
 };
 
 
-static struct snd_pci_quirk alc269_fixup_tbl[] = {
+static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
 	SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
 	SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
 	SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
 	SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
 	SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
@@ -14978,7 +14984,7 @@ static const char * const alc269_models[ALC269_MODEL_LAST] = {
 	[ALC269_AUTO]			= "auto",
 	[ALC269_AUTO]			= "auto",
 };
 };
 
 
-static struct snd_pci_quirk alc269_cfg_tbl[] = {
+static const struct snd_pci_quirk alc269_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
 	SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
 	SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
 	SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
 	SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
@@ -15036,7 +15042,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = {
 	{}
 	{}
 };
 };
 
 
-static struct alc_config_preset alc269_presets[] = {
+static const struct alc_config_preset alc269_presets[] = {
 	[ALC269_BASIC] = {
 	[ALC269_BASIC] = {
 		.mixers = { alc269_base_mixer },
 		.mixers = { alc269_base_mixer },
 		.init_verbs = { alc269_init_verbs },
 		.init_verbs = { alc269_init_verbs },
@@ -15070,9 +15076,9 @@ static struct alc_config_preset alc269_presets[] = {
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.channel_mode = alc269_modes,
 		.channel_mode = alc269_modes,
-		.unsol_event = alc269_laptop_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc269_laptop_amic_setup,
 		.setup = alc269_laptop_amic_setup,
-		.init_hook = alc269_laptop_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC269_DMIC] = {
 	[ALC269_DMIC] = {
 		.mixers = { alc269_laptop_mixer },
 		.mixers = { alc269_laptop_mixer },
@@ -15084,9 +15090,9 @@ static struct alc_config_preset alc269_presets[] = {
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.channel_mode = alc269_modes,
 		.channel_mode = alc269_modes,
-		.unsol_event = alc269_laptop_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc269_laptop_dmic_setup,
 		.setup = alc269_laptop_dmic_setup,
-		.init_hook = alc269_laptop_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC269VB_AMIC] = {
 	[ALC269VB_AMIC] = {
 		.mixers = { alc269vb_laptop_mixer },
 		.mixers = { alc269vb_laptop_mixer },
@@ -15098,9 +15104,9 @@ static struct alc_config_preset alc269_presets[] = {
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.channel_mode = alc269_modes,
 		.channel_mode = alc269_modes,
-		.unsol_event = alc269_laptop_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc269vb_laptop_amic_setup,
 		.setup = alc269vb_laptop_amic_setup,
-		.init_hook = alc269_laptop_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC269VB_DMIC] = {
 	[ALC269VB_DMIC] = {
 		.mixers = { alc269vb_laptop_mixer },
 		.mixers = { alc269vb_laptop_mixer },
@@ -15112,9 +15118,9 @@ static struct alc_config_preset alc269_presets[] = {
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.channel_mode = alc269_modes,
 		.channel_mode = alc269_modes,
-		.unsol_event = alc269_laptop_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc269vb_laptop_dmic_setup,
 		.setup = alc269vb_laptop_dmic_setup,
-		.init_hook = alc269_laptop_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC269_FUJITSU] = {
 	[ALC269_FUJITSU] = {
 		.mixers = { alc269_fujitsu_mixer },
 		.mixers = { alc269_fujitsu_mixer },
@@ -15126,9 +15132,9 @@ static struct alc_config_preset alc269_presets[] = {
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.num_channel_mode = ARRAY_SIZE(alc269_modes),
 		.channel_mode = alc269_modes,
 		.channel_mode = alc269_modes,
-		.unsol_event = alc269_laptop_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc269_laptop_dmic_setup,
 		.setup = alc269_laptop_dmic_setup,
-		.init_hook = alc269_laptop_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC269_LIFEBOOK] = {
 	[ALC269_LIFEBOOK] = {
 		.mixers = { alc269_lifebook_mixer },
 		.mixers = { alc269_lifebook_mixer },
@@ -15140,6 +15146,7 @@ static struct alc_config_preset alc269_presets[] = {
 		.channel_mode = alc269_modes,
 		.channel_mode = alc269_modes,
 		.input_mux = &alc269_capture_source,
 		.input_mux = &alc269_capture_source,
 		.unsol_event = alc269_lifebook_unsol_event,
 		.unsol_event = alc269_lifebook_unsol_event,
+		.setup = alc269_lifebook_setup,
 		.init_hook = alc269_lifebook_init_hook,
 		.init_hook = alc269_lifebook_init_hook,
 	},
 	},
 	[ALC271_ACER] = {
 	[ALC271_ACER] = {
@@ -15185,14 +15192,21 @@ static int alc269_fill_coef(struct hda_codec *codec)
 		val = alc_read_coef_idx(codec, 0xd);
 		val = alc_read_coef_idx(codec, 0xd);
 		if ((val & 0x0c00) >> 10 != 0x1) {
 		if ((val & 0x0c00) >> 10 != 0x1) {
 			/* Capless ramp up clock control */
 			/* Capless ramp up clock control */
-			alc_write_coef_idx(codec, 0xd, val | 1<<10);
+			alc_write_coef_idx(codec, 0xd, val | (1<<10));
 		}
 		}
 		val = alc_read_coef_idx(codec, 0x17);
 		val = alc_read_coef_idx(codec, 0x17);
 		if ((val & 0x01c0) >> 6 != 0x4) {
 		if ((val & 0x01c0) >> 6 != 0x4) {
 			/* Class D power on reset */
 			/* Class D power on reset */
-			alc_write_coef_idx(codec, 0x17, val | 1<<7);
+			alc_write_coef_idx(codec, 0x17, val | (1<<7));
 		}
 		}
 	}
 	}
+
+	val = alc_read_coef_idx(codec, 0xd); /* Class D */
+	alc_write_coef_idx(codec, 0xd, val | (1<<14));
+
+	val = alc_read_coef_idx(codec, 0x4); /* HP */
+	alc_write_coef_idx(codec, 0x4, val | (1<<11));
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -15313,14 +15327,12 @@ static int patch_alc269(struct hda_codec *codec)
 	spec->vmaster_nid = 0x02;
 	spec->vmaster_nid = 0x02;
 
 
 	codec->patch_ops = alc_patch_ops;
 	codec->patch_ops = alc_patch_ops;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	codec->patch_ops.suspend = alc269_suspend;
-#endif
 #ifdef SND_HDA_NEEDS_RESUME
 #ifdef SND_HDA_NEEDS_RESUME
 	codec->patch_ops.resume = alc269_resume;
 	codec->patch_ops.resume = alc269_resume;
 #endif
 #endif
 	if (board_config == ALC269_AUTO)
 	if (board_config == ALC269_AUTO)
 		spec->init_hook = alc269_auto_init;
 		spec->init_hook = alc269_auto_init;
+	spec->shutup = alc269_shutup;
 
 
 	alc_init_jacks(codec);
 	alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -15341,7 +15353,7 @@ static int patch_alc269(struct hda_codec *codec)
  * set the path ways for 2 channel output
  * set the path ways for 2 channel output
  * need to set the codec line out and mic 1 pin widgets to inputs
  * need to set the codec line out and mic 1 pin widgets to inputs
  */
  */
-static struct hda_verb alc861_threestack_ch2_init[] = {
+static const struct hda_verb alc861_threestack_ch2_init[] = {
 	/* set pin widget 1Ah (line in) for input */
 	/* set pin widget 1Ah (line in) for input */
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
 	/* set pin widget 18h (mic1/2) for input, for mic also enable
 	/* set pin widget 18h (mic1/2) for input, for mic also enable
@@ -15360,7 +15372,7 @@ static struct hda_verb alc861_threestack_ch2_init[] = {
  * 6ch mode
  * 6ch mode
  * need to set the codec line out and mic 1 pin widgets to outputs
  * need to set the codec line out and mic 1 pin widgets to outputs
  */
  */
-static struct hda_verb alc861_threestack_ch6_init[] = {
+static const struct hda_verb alc861_threestack_ch6_init[] = {
 	/* set pin widget 1Ah (line in) for output (Back Surround)*/
 	/* set pin widget 1Ah (line in) for output (Back Surround)*/
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
 	/* set pin widget 18h (mic1) for output (CLFE)*/
 	/* set pin widget 18h (mic1) for output (CLFE)*/
@@ -15377,30 +15389,30 @@ static struct hda_verb alc861_threestack_ch6_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc861_threestack_modes[2] = {
+static const struct hda_channel_mode alc861_threestack_modes[2] = {
 	{ 2, alc861_threestack_ch2_init },
 	{ 2, alc861_threestack_ch2_init },
 	{ 6, alc861_threestack_ch6_init },
 	{ 6, alc861_threestack_ch6_init },
 };
 };
 /* Set mic1 as input and unmute the mixer */
 /* Set mic1 as input and unmute the mixer */
-static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
+static const struct hda_verb alc861_uniwill_m31_ch2_init[] = {
 	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
 	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
 	{ } /* end */
 	{ } /* end */
 };
 };
 /* Set mic1 as output and mute mixer */
 /* Set mic1 as output and mute mixer */
-static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
+static const struct hda_verb alc861_uniwill_m31_ch4_init[] = {
 	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
 	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
+static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
 	{ 2, alc861_uniwill_m31_ch2_init },
 	{ 2, alc861_uniwill_m31_ch2_init },
 	{ 4, alc861_uniwill_m31_ch4_init },
 	{ 4, alc861_uniwill_m31_ch4_init },
 };
 };
 
 
 /* Set mic1 and line-in as input and unmute the mixer */
 /* Set mic1 and line-in as input and unmute the mixer */
-static struct hda_verb alc861_asus_ch2_init[] = {
+static const struct hda_verb alc861_asus_ch2_init[] = {
 	/* set pin widget 1Ah (line in) for input */
 	/* set pin widget 1Ah (line in) for input */
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
 	/* set pin widget 18h (mic1/2) for input, for mic also enable
 	/* set pin widget 18h (mic1/2) for input, for mic also enable
@@ -15416,7 +15428,7 @@ static struct hda_verb alc861_asus_ch2_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 /* Set mic1 nad line-in as output and mute mixer */
 /* Set mic1 nad line-in as output and mute mixer */
-static struct hda_verb alc861_asus_ch6_init[] = {
+static const struct hda_verb alc861_asus_ch6_init[] = {
 	/* set pin widget 1Ah (line in) for output (Back Surround)*/
 	/* set pin widget 1Ah (line in) for output (Back Surround)*/
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
 	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
 	/* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
 	/* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
@@ -15434,14 +15446,14 @@ static struct hda_verb alc861_asus_ch6_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc861_asus_modes[2] = {
+static const struct hda_channel_mode alc861_asus_modes[2] = {
 	{ 2, alc861_asus_ch2_init },
 	{ 2, alc861_asus_ch2_init },
 	{ 6, alc861_asus_ch6_init },
 	{ 6, alc861_asus_ch6_init },
 };
 };
 
 
 /* patch-ALC861 */
 /* patch-ALC861 */
 
 
-static struct snd_kcontrol_new alc861_base_mixer[] = {
+static const struct snd_kcontrol_new alc861_base_mixer[] = {
         /* output mixer control */
         /* output mixer control */
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
@@ -15464,7 +15476,7 @@ static struct snd_kcontrol_new alc861_base_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc861_3ST_mixer[] = {
+static const struct snd_kcontrol_new alc861_3ST_mixer[] = {
         /* output mixer control */
         /* output mixer control */
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
@@ -15495,7 +15507,7 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
+static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
         /* output mixer control */
         /* output mixer control */
 	HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
@@ -15504,7 +15516,7 @@ static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
+static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
         /* output mixer control */
         /* output mixer control */
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
@@ -15535,7 +15547,7 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc861_asus_mixer[] = {
+static const struct snd_kcontrol_new alc861_asus_mixer[] = {
         /* output mixer control */
         /* output mixer control */
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
@@ -15567,7 +15579,7 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = {
 };
 };
 
 
 /* additional mixer */
 /* additional mixer */
-static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
+static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
 	{ }
 	{ }
@@ -15576,7 +15588,7 @@ static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc861_base_init_verbs[] = {
+static const struct hda_verb alc861_base_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
 	 */
@@ -15642,7 +15654,7 @@ static struct hda_verb alc861_base_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc861_threestack_init_verbs[] = {
+static const struct hda_verb alc861_threestack_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
 	 */
@@ -15703,7 +15715,7 @@ static struct hda_verb alc861_threestack_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
+static const struct hda_verb alc861_uniwill_m31_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
 	 */
@@ -15765,7 +15777,7 @@ static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc861_asus_init_verbs[] = {
+static const struct hda_verb alc861_asus_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
 	 */
@@ -15831,7 +15843,7 @@ static struct hda_verb alc861_asus_init_verbs[] = {
 };
 };
 
 
 /* additional init verbs for ASUS laptops */
 /* additional init verbs for ASUS laptops */
-static struct hda_verb alc861_asus_laptop_init_verbs[] = {
+static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
 	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
 	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
 	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
 	{ }
 	{ }
@@ -15840,7 +15852,7 @@ static struct hda_verb alc861_asus_laptop_init_verbs[] = {
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc861_auto_init_verbs[] = {
+static const struct hda_verb alc861_auto_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
 	 */
@@ -15889,7 +15901,7 @@ static struct hda_verb alc861_auto_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc861_toshiba_init_verbs[] = {
+static const struct hda_verb alc861_toshiba_init_verbs[] = {
 	{0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 
 
 	{ }
 	{ }
@@ -15922,26 +15934,26 @@ static void alc861_toshiba_unsol_event(struct hda_codec *codec,
 
 
 #define ALC861_DIGOUT_NID	0x07
 #define ALC861_DIGOUT_NID	0x07
 
 
-static struct hda_channel_mode alc861_8ch_modes[1] = {
+static const struct hda_channel_mode alc861_8ch_modes[1] = {
 	{ 8, NULL }
 	{ 8, NULL }
 };
 };
 
 
-static hda_nid_t alc861_dac_nids[4] = {
+static const hda_nid_t alc861_dac_nids[4] = {
 	/* front, surround, clfe, side */
 	/* front, surround, clfe, side */
 	0x03, 0x06, 0x05, 0x04
 	0x03, 0x06, 0x05, 0x04
 };
 };
 
 
-static hda_nid_t alc660_dac_nids[3] = {
+static const hda_nid_t alc660_dac_nids[3] = {
 	/* front, clfe, surround */
 	/* front, clfe, surround */
 	0x03, 0x05, 0x06
 	0x03, 0x05, 0x06
 };
 };
 
 
-static hda_nid_t alc861_adc_nids[1] = {
+static const hda_nid_t alc861_adc_nids[1] = {
 	/* ADC0-2 */
 	/* ADC0-2 */
 	0x08,
 	0x08,
 };
 };
 
 
-static struct hda_input_mux alc861_capture_source = {
+static const struct hda_input_mux alc861_capture_source = {
 	.num_items = 5,
 	.num_items = 5,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -15991,7 +16003,7 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
 		dac = alc861_look_for_dac(codec, nid);
 		dac = alc861_look_for_dac(codec, nid);
 		if (!dac)
 		if (!dac)
 			continue;
 			continue;
-		spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+		spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -16014,11 +16026,15 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
 	static const char * const chname[4] = {
 	static const char * const chname[4] = {
 		"Front", "Surround", NULL /*CLFE*/, "Side"
 		"Front", "Surround", NULL /*CLFE*/, "Side"
 	};
 	};
-	const char *pfx = alc_get_line_out_pfx(cfg, true);
+	const char *pfx = alc_get_line_out_pfx(spec, true);
 	hda_nid_t nid;
 	hda_nid_t nid;
-	int i, err;
+	int i, err, noutputs;
 
 
-	for (i = 0; i < cfg->line_outs; i++) {
+	noutputs = cfg->line_outs;
+	if (spec->multi_ios > 0)
+		noutputs += spec->multi_ios;
+
+	for (i = 0; i < noutputs; i++) {
 		nid = spec->multiout.dac_nids[i];
 		nid = spec->multiout.dac_nids[i];
 		if (!nid)
 		if (!nid)
 			continue;
 			continue;
@@ -16151,7 +16167,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	int err;
 	int err;
-	static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
 
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc861_ignore);
 					   alc861_ignore);
@@ -16161,6 +16177,9 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
 		return 0; /* can't find valid BIOS pin config */
 		return 0; /* can't find valid BIOS pin config */
 
 
 	err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
 	err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = alc_auto_add_multi_channel_mode(codec);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 	err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
 	err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
@@ -16207,7 +16226,7 @@ static void alc861_auto_init(struct hda_codec *codec)
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list alc861_loopbacks[] = {
+static const struct hda_amp_list alc861_loopbacks[] = {
 	{ 0x15, HDA_INPUT, 0 },
 	{ 0x15, HDA_INPUT, 0 },
 	{ 0x15, HDA_INPUT, 1 },
 	{ 0x15, HDA_INPUT, 1 },
 	{ 0x15, HDA_INPUT, 2 },
 	{ 0x15, HDA_INPUT, 2 },
@@ -16232,7 +16251,7 @@ static const char * const alc861_models[ALC861_MODEL_LAST] = {
 	[ALC861_AUTO]		= "auto",
 	[ALC861_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk alc861_cfg_tbl[] = {
+static const struct snd_pci_quirk alc861_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
 	SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
 	SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
@@ -16256,7 +16275,7 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = {
 	{}
 	{}
 };
 };
 
 
-static struct alc_config_preset alc861_presets[] = {
+static const struct alc_config_preset alc861_presets[] = {
 	[ALC861_3ST] = {
 	[ALC861_3ST] = {
 		.mixers = { alc861_3ST_mixer },
 		.mixers = { alc861_3ST_mixer },
 		.init_verbs = { alc861_threestack_init_verbs },
 		.init_verbs = { alc861_threestack_init_verbs },
@@ -16379,7 +16398,7 @@ static const struct alc_fixup alc861_fixups[] = {
 	},
 	},
 };
 };
 
 
-static struct snd_pci_quirk alc861_fixup_tbl[] = {
+static const struct snd_pci_quirk alc861_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
 	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
 	{}
 	{}
 };
 };
@@ -16472,7 +16491,7 @@ static int patch_alc861(struct hda_codec *codec)
  */
  */
 #define ALC861VD_DIGOUT_NID	0x06
 #define ALC861VD_DIGOUT_NID	0x06
 
 
-static hda_nid_t alc861vd_dac_nids[4] = {
+static const hda_nid_t alc861vd_dac_nids[4] = {
 	/* front, surr, clfe, side surr */
 	/* front, surr, clfe, side surr */
 	0x02, 0x03, 0x04, 0x05
 	0x02, 0x03, 0x04, 0x05
 };
 };
@@ -16484,21 +16503,21 @@ static hda_nid_t alc861vd_dac_nids[4] = {
  * - and it is the same as in 861vd.
  * - and it is the same as in 861vd.
  * adc_nids in ALC660vd are (is) the same as in 861vd
  * adc_nids in ALC660vd are (is) the same as in 861vd
  */
  */
-static hda_nid_t alc660vd_dac_nids[3] = {
+static const hda_nid_t alc660vd_dac_nids[3] = {
 	/* front, rear, clfe, rear_surr */
 	/* front, rear, clfe, rear_surr */
 	0x02, 0x04, 0x03
 	0x02, 0x04, 0x03
 };
 };
 
 
-static hda_nid_t alc861vd_adc_nids[1] = {
+static const hda_nid_t alc861vd_adc_nids[1] = {
 	/* ADC0 */
 	/* ADC0 */
 	0x09,
 	0x09,
 };
 };
 
 
-static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
+static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
 
 
 /* input MUX */
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 /* FIXME: should be a matrix-type input source selection */
-static struct hda_input_mux alc861vd_capture_source = {
+static const struct hda_input_mux alc861vd_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -16508,7 +16527,7 @@ static struct hda_input_mux alc861vd_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc861vd_dallas_capture_source = {
+static const struct hda_input_mux alc861vd_dallas_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -16516,7 +16535,7 @@ static struct hda_input_mux alc861vd_dallas_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc861vd_hp_capture_source = {
+static const struct hda_input_mux alc861vd_hp_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Front Mic", 0x0 },
 		{ "Front Mic", 0x0 },
@@ -16527,14 +16546,14 @@ static struct hda_input_mux alc861vd_hp_capture_source = {
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
+static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
 	{ 2, NULL }
 	{ 2, NULL }
 };
 };
 
 
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc861vd_6stack_ch6_init[] = {
+static const struct hda_verb alc861vd_6stack_ch6_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -16545,7 +16564,7 @@ static struct hda_verb alc861vd_6stack_ch6_init[] = {
 /*
 /*
  * 8ch mode
  * 8ch mode
  */
  */
-static struct hda_verb alc861vd_6stack_ch8_init[] = {
+static const struct hda_verb alc861vd_6stack_ch8_init[] = {
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -16553,12 +16572,12 @@ static struct hda_verb alc861vd_6stack_ch8_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc861vd_6stack_modes[2] = {
+static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
 	{ 6, alc861vd_6stack_ch6_init },
 	{ 6, alc861vd_6stack_ch6_init },
 	{ 8, alc861vd_6stack_ch8_init },
 	{ 8, alc861vd_6stack_ch8_init },
 };
 };
 
 
-static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
 		.name = "Channel Mode",
@@ -16572,7 +16591,7 @@ static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  */
  */
-static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 
 
@@ -16608,7 +16627,7 @@ static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 
 
@@ -16631,7 +16650,7 @@ static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	/*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
 	/*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -16655,7 +16674,7 @@ static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
 /* Pin assignment: Speaker=0x14, HP = 0x15,
 /* Pin assignment: Speaker=0x14, HP = 0x15,
  *                 Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
  *                 Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
  */
  */
-static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -16672,7 +16691,7 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
 /* Pin assignment: Speaker=0x14, Line-out = 0x15,
 /* Pin assignment: Speaker=0x14, Line-out = 0x15,
  *                 Front Mic=0x18, ATAPI Mic = 0x19,
  *                 Front Mic=0x18, ATAPI Mic = 0x19,
  */
  */
-static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
+static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -16688,7 +16707,7 @@ static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc861vd_volume_init_verbs[] = {
+static const struct hda_verb alc861vd_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0 and set the default input to mic-in
 	 * Unmute ADC0 and set the default input to mic-in
 	 */
 	 */
@@ -16738,7 +16757,7 @@ static struct hda_verb alc861vd_volume_init_verbs[] = {
  * 3-stack pin configuration:
  * 3-stack pin configuration:
  * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
  * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
  */
  */
-static struct hda_verb alc861vd_3stack_init_verbs[] = {
+static const struct hda_verb alc861vd_3stack_init_verbs[] = {
 	/*
 	/*
 	 * Set pin mode and muting
 	 * Set pin mode and muting
 	 */
 	 */
@@ -16769,7 +16788,7 @@ static struct hda_verb alc861vd_3stack_init_verbs[] = {
 /*
 /*
  * 6-stack pin configuration:
  * 6-stack pin configuration:
  */
  */
-static struct hda_verb alc861vd_6stack_init_verbs[] = {
+static const struct hda_verb alc861vd_6stack_init_verbs[] = {
 	/*
 	/*
 	 * Set pin mode and muting
 	 * Set pin mode and muting
 	 */
 	 */
@@ -16810,18 +16829,18 @@ static struct hda_verb alc861vd_6stack_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc861vd_eapd_verbs[] = {
+static const struct hda_verb alc861vd_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc660vd_eapd_verbs[] = {
+static const struct hda_verb alc660vd_eapd_verbs[] = {
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
+static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
 	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
@@ -16835,11 +16854,13 @@ static void alc861vd_lenovo_setup(struct hda_codec *codec)
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.hp_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
 static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
 {
 {
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	alc88x_simple_mic_automute(codec);
 	alc88x_simple_mic_automute(codec);
 }
 }
 
 
@@ -16851,12 +16872,12 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
 		alc88x_simple_mic_automute(codec);
 		alc88x_simple_mic_automute(codec);
 		break;
 		break;
 	default:
 	default:
-		alc_automute_amp_unsol_event(codec, res);
+		alc_sku_unsol_event(codec, res);
 		break;
 		break;
 	}
 	}
 }
 }
 
 
-static struct hda_verb alc861vd_dallas_verbs[] = {
+static const struct hda_verb alc861vd_dallas_verbs[] = {
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
@@ -16908,6 +16929,8 @@ static void alc861vd_dallas_setup(struct hda_codec *codec)
 
 
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.hp_pins[0] = 0x15;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -16936,7 +16959,7 @@ static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
 	[ALC861VD_AUTO]		= "auto",
 	[ALC861VD_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
+static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
 	SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
 	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
 	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
 	SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
 	SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
@@ -16955,7 +16978,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
 	{}
 	{}
 };
 };
 
 
-static struct alc_config_preset alc861vd_presets[] = {
+static const struct alc_config_preset alc861vd_presets[] = {
 	[ALC660VD_3ST] = {
 	[ALC660VD_3ST] = {
 		.mixers = { alc861vd_3st_mixer },
 		.mixers = { alc861vd_3st_mixer },
 		.init_verbs = { alc861vd_volume_init_verbs,
 		.init_verbs = { alc861vd_volume_init_verbs,
@@ -17032,9 +17055,9 @@ static struct alc_config_preset alc861vd_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_dallas_capture_source,
 		.input_mux = &alc861vd_dallas_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc861vd_dallas_setup,
 		.setup = alc861vd_dallas_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC861VD_HP] = {
 	[ALC861VD_HP] = {
 		.mixers = { alc861vd_hp_mixer },
 		.mixers = { alc861vd_hp_mixer },
@@ -17045,9 +17068,9 @@ static struct alc_config_preset alc861vd_presets[] = {
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_hp_capture_source,
 		.input_mux = &alc861vd_hp_capture_source,
-		.unsol_event = alc_automute_amp_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc861vd_dallas_setup,
 		.setup = alc861vd_dallas_setup,
-		.init_hook = alc_automute_amp,
+		.init_hook = alc_hp_automute,
 	},
 	},
 	[ALC660VD_ASUS_V1S] = {
 	[ALC660VD_ASUS_V1S] = {
 		.mixers = { alc861vd_lenovo_mixer },
 		.mixers = { alc861vd_lenovo_mixer },
@@ -17146,11 +17169,15 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
 	static const char * const chname[4] = {
 	static const char * const chname[4] = {
 		"Front", "Surround", "CLFE", "Side"
 		"Front", "Surround", "CLFE", "Side"
 	};
 	};
-	const char *pfx = alc_get_line_out_pfx(cfg, true);
+	const char *pfx = alc_get_line_out_pfx(spec, true);
 	hda_nid_t nid_v, nid_s;
 	hda_nid_t nid_v, nid_s;
-	int i, err;
+	int i, err, noutputs;
 
 
-	for (i = 0; i < cfg->line_outs; i++) {
+	noutputs = cfg->line_outs;
+	if (spec->multi_ios > 0)
+		noutputs += spec->multi_ios;
+
+	for (i = 0; i < noutputs; i++) {
 		if (!spec->multiout.dac_nids[i])
 		if (!spec->multiout.dac_nids[i])
 			continue;
 			continue;
 		nid_v = alc861vd_idx_to_mixer_vol(
 		nid_v = alc861vd_idx_to_mixer_vol(
@@ -17263,7 +17290,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	int err;
 	int err;
-	static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
 
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc861vd_ignore);
 					   alc861vd_ignore);
@@ -17273,6 +17300,9 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
 		return 0; /* can't find valid BIOS pin config */
 		return 0; /* can't find valid BIOS pin config */
 
 
 	err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
 	err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = alc_auto_add_multi_channel_mode(codec);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 	err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
 	err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
@@ -17343,7 +17373,7 @@ static const struct alc_fixup alc861vd_fixups[] = {
 	},
 	},
 };
 };
 
 
-static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
+static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
 	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
 	{}
 	{}
 };
 };
@@ -17426,6 +17456,7 @@ static int patch_alc861vd(struct hda_codec *codec)
 
 
 	if (board_config == ALC861VD_AUTO)
 	if (board_config == ALC861VD_AUTO)
 		spec->init_hook = alc861vd_auto_init;
 		spec->init_hook = alc861vd_auto_init;
+	spec->shutup = alc_eapd_shutup;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	if (!spec->loopback.amplist)
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc861vd_loopbacks;
 		spec->loopback.amplist = alc861vd_loopbacks;
@@ -17448,32 +17479,32 @@ static int patch_alc861vd(struct hda_codec *codec)
 #define ALC662_DIGOUT_NID	0x06
 #define ALC662_DIGOUT_NID	0x06
 #define ALC662_DIGIN_NID	0x0a
 #define ALC662_DIGIN_NID	0x0a
 
 
-static hda_nid_t alc662_dac_nids[4] = {
-	/* front, rear, clfe, rear_surr */
+static const hda_nid_t alc662_dac_nids[3] = {
+	/* front, rear, clfe */
 	0x02, 0x03, 0x04
 	0x02, 0x03, 0x04
 };
 };
 
 
-static hda_nid_t alc272_dac_nids[2] = {
+static const hda_nid_t alc272_dac_nids[2] = {
 	0x02, 0x03
 	0x02, 0x03
 };
 };
 
 
-static hda_nid_t alc662_adc_nids[2] = {
+static const hda_nid_t alc662_adc_nids[2] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x09, 0x08
 	0x09, 0x08
 };
 };
 
 
-static hda_nid_t alc272_adc_nids[1] = {
+static const hda_nid_t alc272_adc_nids[1] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x08,
 	0x08,
 };
 };
 
 
-static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
-static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
+static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
+static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
 
 
 
 
 /* input MUX */
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 /* FIXME: should be a matrix-type input source selection */
-static struct hda_input_mux alc662_capture_source = {
+static const struct hda_input_mux alc662_capture_source = {
 	.num_items = 4,
 	.num_items = 4,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -17483,7 +17514,7 @@ static struct hda_input_mux alc662_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc662_lenovo_101e_capture_source = {
+static const struct hda_input_mux alc662_lenovo_101e_capture_source = {
 	.num_items = 2,
 	.num_items = 2,
 	.items = {
 	.items = {
 		{ "Mic", 0x1 },
 		{ "Mic", 0x1 },
@@ -17491,7 +17522,7 @@ static struct hda_input_mux alc662_lenovo_101e_capture_source = {
 	},
 	},
 };
 };
 
 
-static struct hda_input_mux alc663_capture_source = {
+static const struct hda_input_mux alc663_capture_source = {
 	.num_items = 3,
 	.num_items = 3,
 	.items = {
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Mic", 0x0 },
@@ -17501,7 +17532,7 @@ static struct hda_input_mux alc663_capture_source = {
 };
 };
 
 
 #if 0 /* set to 1 for testing other input sources below */
 #if 0 /* set to 1 for testing other input sources below */
-static struct hda_input_mux alc272_nc10_capture_source = {
+static const struct hda_input_mux alc272_nc10_capture_source = {
 	.num_items = 16,
 	.num_items = 16,
 	.items = {
 	.items = {
 		{ "Autoselect Mic", 0x0 },
 		{ "Autoselect Mic", 0x0 },
@@ -17527,14 +17558,14 @@ static struct hda_input_mux alc272_nc10_capture_source = {
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
+static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
 	{ 2, NULL }
 	{ 2, NULL }
 };
 };
 
 
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_verb alc662_3ST_ch2_init[] = {
+static const struct hda_verb alc662_3ST_ch2_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
 	{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -17545,7 +17576,7 @@ static struct hda_verb alc662_3ST_ch2_init[] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc662_3ST_ch6_init[] = {
+static const struct hda_verb alc662_3ST_ch6_init[] = {
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
 	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
 	{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
@@ -17555,7 +17586,7 @@ static struct hda_verb alc662_3ST_ch6_init[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
+static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
 	{ 2, alc662_3ST_ch2_init },
 	{ 2, alc662_3ST_ch2_init },
 	{ 6, alc662_3ST_ch6_init },
 	{ 6, alc662_3ST_ch6_init },
 };
 };
@@ -17563,7 +17594,7 @@ static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
 /*
 /*
  * 2ch mode
  * 2ch mode
  */
  */
-static struct hda_verb alc662_sixstack_ch6_init[] = {
+static const struct hda_verb alc662_sixstack_ch6_init[] = {
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
@@ -17573,14 +17604,14 @@ static struct hda_verb alc662_sixstack_ch6_init[] = {
 /*
 /*
  * 6ch mode
  * 6ch mode
  */
  */
-static struct hda_verb alc662_sixstack_ch8_init[] = {
+static const struct hda_verb alc662_sixstack_ch8_init[] = {
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_channel_mode alc662_5stack_modes[2] = {
+static const struct hda_channel_mode alc662_5stack_modes[2] = {
 	{ 2, alc662_sixstack_ch6_init },
 	{ 2, alc662_sixstack_ch6_init },
 	{ 6, alc662_sixstack_ch8_init },
 	{ 6, alc662_sixstack_ch8_init },
 };
 };
@@ -17589,7 +17620,7 @@ static struct hda_channel_mode alc662_5stack_modes[2] = {
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
  */
  */
 
 
-static struct snd_kcontrol_new alc662_base_mixer[] = {
+static const struct snd_kcontrol_new alc662_base_mixer[] = {
 	/* output mixer control */
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
@@ -17613,7 +17644,7 @@ static struct snd_kcontrol_new alc662_base_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
+static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -17628,7 +17659,7 @@ static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
+static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -17649,7 +17680,7 @@ static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
+static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -17662,7 +17693,7 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
+static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	ALC262_HIPPO_MASTER_SWITCH,
 	ALC262_HIPPO_MASTER_SWITCH,
 
 
@@ -17676,7 +17707,7 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
+static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
 	ALC262_HIPPO_MASTER_SWITCH,
 	ALC262_HIPPO_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -17690,7 +17721,7 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_bind_ctls alc663_asus_bind_master_vol = {
+static const struct hda_bind_ctls alc663_asus_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
@@ -17699,7 +17730,7 @@ static struct hda_bind_ctls alc663_asus_bind_master_vol = {
 	},
 	},
 };
 };
 
 
-static struct hda_bind_ctls alc663_asus_one_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_one_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17708,7 +17739,7 @@ static struct hda_bind_ctls alc663_asus_one_bind_switch = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new alc663_m51va_mixer[] = {
+static const struct snd_kcontrol_new alc663_m51va_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -17716,7 +17747,7 @@ static struct snd_kcontrol_new alc663_m51va_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_tree_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17726,7 +17757,7 @@ static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
+static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -17737,7 +17768,7 @@ static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_bind_ctls alc663_asus_four_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_four_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17747,7 +17778,7 @@ static struct hda_bind_ctls alc663_asus_four_bind_switch = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
+static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -17757,7 +17788,7 @@ static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
+static const struct snd_kcontrol_new alc662_1bjd_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -17768,7 +17799,7 @@ static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
+static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
@@ -17777,7 +17808,7 @@ static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
 	},
 	},
 };
 };
 
 
-static struct hda_bind_ctls alc663_asus_two_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_two_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17786,7 +17817,7 @@ static struct hda_bind_ctls alc663_asus_two_bind_switch = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
+static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume",
 	HDA_BIND_VOL("Master Playback Volume",
 				&alc663_asus_two_bind_master_vol),
 				&alc663_asus_two_bind_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
@@ -17797,7 +17828,7 @@ static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
+static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -17807,7 +17838,7 @@ static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc663_g71v_mixer[] = {
+static const struct snd_kcontrol_new alc663_g71v_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -17821,7 +17852,7 @@ static struct snd_kcontrol_new alc663_g71v_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc663_g50v_mixer[] = {
+static const struct snd_kcontrol_new alc663_g50v_mixer[] = {
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
@@ -17835,7 +17866,7 @@ static struct snd_kcontrol_new alc663_g50v_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17847,7 +17878,7 @@ static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
 	},
 	},
 };
 };
 
 
-static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
+static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 		HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
@@ -17856,7 +17887,7 @@ static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new alc663_mode7_mixer[] = {
+static const struct snd_kcontrol_new alc663_mode7_mixer[] = {
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
 	HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
 	HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
@@ -17869,7 +17900,7 @@ static struct snd_kcontrol_new alc663_mode7_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc663_mode8_mixer[] = {
+static const struct snd_kcontrol_new alc663_mode8_mixer[] = {
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
 	HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
 	HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
 	HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
 	HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
@@ -17881,7 +17912,7 @@ static struct snd_kcontrol_new alc663_mode8_mixer[] = {
 };
 };
 
 
 
 
-static struct snd_kcontrol_new alc662_chmode_mixer[] = {
+static const struct snd_kcontrol_new alc662_chmode_mixer[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Channel Mode",
 		.name = "Channel Mode",
@@ -17892,7 +17923,7 @@ static struct snd_kcontrol_new alc662_chmode_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb alc662_init_verbs[] = {
+static const struct hda_verb alc662_init_verbs[] = {
 	/* ADC: mute amp left and right */
 	/* ADC: mute amp left and right */
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -17938,55 +17969,36 @@ static struct hda_verb alc662_init_verbs[] = {
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
 
-	/* always trun on EAPD */
-	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-
-	{ }
-};
-
-static struct hda_verb alc663_init_verbs[] = {
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc272_init_verbs[] = {
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+static const struct hda_verb alc662_eapd_init_verbs[] = {
+	/* always trun on EAPD */
+	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb alc662_sue_init_verbs[] = {
+static const struct hda_verb alc662_sue_init_verbs[] = {
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
+static const struct hda_verb alc662_eeepc_sue_init_verbs[] = {
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{}
 	{}
 };
 };
 
 
 /* Set Unsolicited Event*/
 /* Set Unsolicited Event*/
-static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
+static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc663_m51va_init_verbs[] = {
+static const struct hda_verb alc663_m51va_init_verbs[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
@@ -17999,7 +18011,7 @@ static struct hda_verb alc663_m51va_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc663_21jd_amic_init_verbs[] = {
+static const struct hda_verb alc663_21jd_amic_init_verbs[] = {
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
@@ -18010,7 +18022,7 @@ static struct hda_verb alc663_21jd_amic_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
+static const struct hda_verb alc662_1bjd_amic_init_verbs[] = {
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -18022,7 +18034,7 @@ static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc663_15jd_amic_init_verbs[] = {
+static const struct hda_verb alc663_15jd_amic_init_verbs[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Headphone */
@@ -18033,7 +18045,7 @@ static struct hda_verb alc663_15jd_amic_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
+static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -18049,7 +18061,7 @@ static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
+static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -18065,7 +18077,7 @@ static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc663_g71v_init_verbs[] = {
+static const struct hda_verb alc663_g71v_init_verbs[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	/* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
 	/* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
 	/* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
 	/* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
@@ -18080,7 +18092,7 @@ static struct hda_verb alc663_g71v_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc663_g50v_init_verbs[] = {
+static const struct hda_verb alc663_g50v_init_verbs[] = {
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Headphone */
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Headphone */
@@ -18090,7 +18102,7 @@ static struct hda_verb alc663_g50v_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc662_ecs_init_verbs[] = {
+static const struct hda_verb alc662_ecs_init_verbs[] = {
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
@@ -18098,7 +18110,7 @@ static struct hda_verb alc662_ecs_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc272_dell_zm1_init_verbs[] = {
+static const struct hda_verb alc272_dell_zm1_init_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -18113,7 +18125,7 @@ static struct hda_verb alc272_dell_zm1_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc272_dell_init_verbs[] = {
+static const struct hda_verb alc272_dell_init_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -18128,7 +18140,7 @@ static struct hda_verb alc272_dell_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc663_mode7_init_verbs[] = {
+static const struct hda_verb alc663_mode7_init_verbs[] = {
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -18147,7 +18159,7 @@ static struct hda_verb alc663_mode7_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb alc663_mode8_init_verbs[] = {
+static const struct hda_verb alc663_mode8_init_verbs[] = {
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -18167,61 +18179,29 @@ static struct hda_verb alc663_mode8_init_verbs[] = {
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
+static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
+static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x14);
-	bits = present ? HDA_AMP_MUTE : 0;
-
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
- 	present = snd_hda_jack_detect(codec, 0x1b);
-	bits = present ? HDA_AMP_MUTE : 0;
-
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static void alc662_lenovo_101e_setup(struct hda_codec *codec)
 {
 {
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc662_lenovo_101e_all_automute(codec);
-	if ((res >> 26) == ALC880_FRONT_EVENT)
-		alc662_lenovo_101e_ispeaker_automute(codec);
-}
+	struct alc_spec *spec = codec->spec;
 
 
-/* unsolicited event for HP jack sensing */
-static void alc662_eeepc_unsol_event(struct hda_codec *codec,
-				     unsigned int res)
-{
-	if ((res >> 26) == ALC880_MIC_EVENT)
-		alc_mic_automute(codec);
-	else
-		alc262_hippo_unsol_event(codec, res);
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.line_out_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x15;
+	spec->automute = 1;
+	spec->detect_line = 1;
+	spec->automute_lines = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc662_eeepc_setup(struct hda_codec *codec)
 static void alc662_eeepc_setup(struct hda_codec *codec)
@@ -18236,199 +18216,124 @@ static void alc662_eeepc_setup(struct hda_codec *codec)
 	spec->auto_mic = 1;
 	spec->auto_mic = 1;
 }
 }
 
 
-static void alc662_eeepc_inithook(struct hda_codec *codec)
-{
-	alc262_hippo_automute(codec);
-	alc_mic_automute(codec);
-}
-
 static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
 static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 
 
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.hp_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[0] = 0x1b;
 	spec->autocfg.speaker_pins[0] = 0x1b;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
-#define alc662_eeepc_ep20_inithook	alc262_hippo_master_update
-
-static void alc663_m51va_speaker_automute(struct hda_codec *codec)
+static void alc663_m51va_setup(struct hda_codec *codec)
 {
 {
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x21);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x12;
+	spec->int_mic.mux_idx = 9;
+	spec->auto_mic = 1;
 }
 }
 
 
-static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
+/* ***************** Mode1 ******************************/
+static void alc663_mode1_setup(struct hda_codec *codec)
 {
 {
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x21);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
 }
 }
 
 
-static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
+/* ***************** Mode2 ******************************/
+static void alc662_mode2_setup(struct hda_codec *codec)
 {
 {
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x15);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
-				 HDA_AMP_MUTE, bits);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
 }
 }
 
 
-static void alc662_f5z_speaker_automute(struct hda_codec *codec)
+/* ***************** Mode3 ******************************/
+static void alc663_mode3_setup(struct hda_codec *codec)
 {
 {
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x1b);
-	bits = present ? 0 : PIN_OUT;
-	snd_hda_codec_write(codec, 0x14, 0,
-			 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
 }
 }
 
 
-static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
+/* ***************** Mode4 ******************************/
+static void alc663_mode4_setup(struct hda_codec *codec)
 {
 {
-	unsigned int present1, present2;
-
-	present1 = snd_hda_jack_detect(codec, 0x21);
-	present2 = snd_hda_jack_detect(codec, 0x15);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x16;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute_mixer_nid[1] = 0x0e;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
+}
 
 
-	if (present1 || present2) {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-	} else {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-	}
-}
-
-static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present1, present2;
-
-	present1 = snd_hda_jack_detect(codec, 0x1b);
-	present2 = snd_hda_jack_detect(codec, 0x15);
-
-	if (present1 || present2) {
-		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
-					 HDA_AMP_MUTE, 0);
-		snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
-					 HDA_AMP_MUTE, 0);
-	}
-}
-
-static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present1, present2;
-
-	present1 = snd_hda_codec_read(codec, 0x1b, 0,
-			AC_VERB_GET_PIN_SENSE, 0)
-			& AC_PINSENSE_PRESENCE;
-	present2 = snd_hda_codec_read(codec, 0x21, 0,
-			AC_VERB_GET_PIN_SENSE, 0)
-			& AC_PINSENSE_PRESENCE;
-
-	if (present1 || present2) {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-		snd_hda_codec_write_cache(codec, 0x17, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-	} else {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-		snd_hda_codec_write_cache(codec, 0x17, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-	}
-}
-
-static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
-{
-	unsigned int present1, present2;
-
-	present1 = snd_hda_codec_read(codec, 0x21, 0,
-			AC_VERB_GET_PIN_SENSE, 0)
-			& AC_PINSENSE_PRESENCE;
-	present2 = snd_hda_codec_read(codec, 0x15, 0,
-			AC_VERB_GET_PIN_SENSE, 0)
-			& AC_PINSENSE_PRESENCE;
-
-	if (present1 || present2) {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-		snd_hda_codec_write_cache(codec, 0x17, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-	} else {
-		snd_hda_codec_write_cache(codec, 0x14, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-		snd_hda_codec_write_cache(codec, 0x17, 0,
-			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-	}
-}
-
-static void alc663_m51va_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_m51va_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-static void alc663_m51va_setup(struct hda_codec *codec)
+/* ***************** Mode5 ******************************/
+static void alc663_mode5_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[1] = 0x16;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute_mixer_nid[1] = 0x0e;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->ext_mic.mux_idx = 0;
-	spec->int_mic.pin = 0x12;
-	spec->int_mic.mux_idx = 9;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
 	spec->auto_mic = 1;
 	spec->auto_mic = 1;
 }
 }
 
 
-static void alc663_m51va_inithook(struct hda_codec *codec)
-{
-	alc663_m51va_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
-/* ***************** Mode1 ******************************/
-#define alc663_mode1_unsol_event	alc663_m51va_unsol_event
-
-static void alc663_mode1_setup(struct hda_codec *codec)
+/* ***************** Mode6 ******************************/
+static void alc663_mode6_setup(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.hp_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute_mixer_nid[0] = 0x0c;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_MIXER;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.pin = 0x18;
 	spec->ext_mic.mux_idx = 0;
 	spec->ext_mic.mux_idx = 0;
 	spec->int_mic.pin = 0x19;
 	spec->int_mic.pin = 0x19;
@@ -18436,229 +18341,60 @@ static void alc663_mode1_setup(struct hda_codec *codec)
 	spec->auto_mic = 1;
 	spec->auto_mic = 1;
 }
 }
 
 
-#define alc663_mode1_inithook		alc663_m51va_inithook
-
-/* ***************** Mode2 ******************************/
-static void alc662_mode2_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc662_f5z_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc662_mode2_setup	alc663_mode1_setup
-
-static void alc662_mode2_inithook(struct hda_codec *codec)
-{
-	alc662_f5z_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-/* ***************** Mode3 ******************************/
-static void alc663_mode3_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_two_hp_m1_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_mode3_setup	alc663_mode1_setup
-
-static void alc663_mode3_inithook(struct hda_codec *codec)
-{
-	alc663_two_hp_m1_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-/* ***************** Mode4 ******************************/
-static void alc663_mode4_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_21jd_two_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_mode4_setup	alc663_mode1_setup
-
-static void alc663_mode4_inithook(struct hda_codec *codec)
-{
-	alc663_21jd_two_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-/* ***************** Mode5 ******************************/
-static void alc663_mode5_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_15jd_two_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_mode5_setup	alc663_mode1_setup
-
-static void alc663_mode5_inithook(struct hda_codec *codec)
-{
-	alc663_15jd_two_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-/* ***************** Mode6 ******************************/
-static void alc663_mode6_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_two_hp_m2_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_mode6_setup	alc663_mode1_setup
-
-static void alc663_mode6_inithook(struct hda_codec *codec)
-{
-	alc663_two_hp_m2_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
 /* ***************** Mode7 ******************************/
 /* ***************** Mode7 ******************************/
-static void alc663_mode7_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_two_hp_m7_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_mode7_setup	alc663_mode1_setup
-
-static void alc663_mode7_inithook(struct hda_codec *codec)
+static void alc663_mode7_setup(struct hda_codec *codec)
 {
 {
-	alc663_two_hp_m7_speaker_automute(codec);
-	alc_mic_automute(codec);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x1b;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x19;
+	spec->int_mic.mux_idx = 1;
+	spec->auto_mic = 1;
 }
 }
 
 
 /* ***************** Mode8 ******************************/
 /* ***************** Mode8 ******************************/
-static void alc663_mode8_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_two_hp_m8_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_mode8_setup	alc663_m51va_setup
-
-static void alc663_mode8_inithook(struct hda_codec *codec)
-{
-	alc663_two_hp_m8_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
-static void alc663_g71v_hp_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x21);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc663_g71v_front_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-	unsigned char bits;
-
-	present = snd_hda_jack_detect(codec, 0x15);
-	bits = present ? HDA_AMP_MUTE : 0;
-	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, bits);
-}
-
-static void alc663_g71v_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
-{
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_g71v_hp_automute(codec);
-		break;
-	case ALC880_FRONT_EVENT:
-		alc663_g71v_front_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
-}
-
-#define alc663_g71v_setup	alc663_m51va_setup
-
-static void alc663_g71v_inithook(struct hda_codec *codec)
+static void alc663_mode8_setup(struct hda_codec *codec)
 {
 {
-	alc663_g71v_front_automute(codec);
-	alc663_g71v_hp_automute(codec);
-	alc_mic_automute(codec);
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.hp_pins[1] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->autocfg.speaker_pins[0] = 0x17;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_PIN;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x12;
+	spec->int_mic.mux_idx = 9;
+	spec->auto_mic = 1;
 }
 }
 
 
-static void alc663_g50v_unsol_event(struct hda_codec *codec,
-					   unsigned int res)
+static void alc663_g71v_setup(struct hda_codec *codec)
 {
 {
-	switch (res >> 26) {
-	case ALC880_HP_EVENT:
-		alc663_m51va_speaker_automute(codec);
-		break;
-	case ALC880_MIC_EVENT:
-		alc_mic_automute(codec);
-		break;
-	}
+	struct alc_spec *spec = codec->spec;
+	spec->autocfg.hp_pins[0] = 0x21;
+	spec->autocfg.line_out_pins[0] = 0x15;
+	spec->autocfg.speaker_pins[0] = 0x14;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
+	spec->detect_line = 1;
+	spec->automute_lines = 1;
+	spec->ext_mic.pin = 0x18;
+	spec->ext_mic.mux_idx = 0;
+	spec->int_mic.pin = 0x12;
+	spec->int_mic.mux_idx = 9;
+	spec->auto_mic = 1;
 }
 }
 
 
 #define alc663_g50v_setup	alc663_m51va_setup
 #define alc663_g50v_setup	alc663_m51va_setup
 
 
-static void alc663_g50v_inithook(struct hda_codec *codec)
-{
-	alc663_m51va_speaker_automute(codec);
-	alc_mic_automute(codec);
-}
-
-static struct snd_kcontrol_new alc662_ecs_mixer[] = {
+static const struct snd_kcontrol_new alc662_ecs_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	ALC262_HIPPO_MASTER_SWITCH,
 	ALC262_HIPPO_MASTER_SWITCH,
 
 
@@ -18672,7 +18408,7 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new alc272_nc10_mixer[] = {
+static const struct snd_kcontrol_new alc272_nc10_mixer[] = {
 	/* Master Playback automatically created from Speaker and Headphone */
 	/* Master Playback automatically created from Speaker and Headphone */
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -18707,7 +18443,7 @@ static const char * const alc662_models[ALC662_MODEL_LAST] = {
 	[ALC662_3ST_2ch_DIG]	= "3stack-dig",
 	[ALC662_3ST_2ch_DIG]	= "3stack-dig",
 	[ALC662_3ST_6ch_DIG]	= "3stack-6ch-dig",
 	[ALC662_3ST_6ch_DIG]	= "3stack-6ch-dig",
 	[ALC662_3ST_6ch]	= "3stack-6ch",
 	[ALC662_3ST_6ch]	= "3stack-6ch",
-	[ALC662_5ST_DIG]	= "6stack-dig",
+	[ALC662_5ST_DIG]	= "5stack-dig",
 	[ALC662_LENOVO_101E]	= "lenovo-101e",
 	[ALC662_LENOVO_101E]	= "lenovo-101e",
 	[ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
 	[ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
 	[ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
 	[ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
@@ -18730,7 +18466,7 @@ static const char * const alc662_models[ALC662_MODEL_LAST] = {
 	[ALC662_AUTO]		= "auto",
 	[ALC662_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk alc662_cfg_tbl[] = {
+static const struct snd_pci_quirk alc662_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
 	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
 	SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
 	SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
 	SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
 	SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
@@ -18812,10 +18548,10 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
 	{}
 	{}
 };
 };
 
 
-static struct alc_config_preset alc662_presets[] = {
+static const struct alc_config_preset alc662_presets[] = {
 	[ALC662_3ST_2ch_DIG] = {
 	[ALC662_3ST_2ch_DIG] = {
 		.mixers = { alc662_3ST_2ch_mixer },
 		.mixers = { alc662_3ST_2ch_mixer },
-		.init_verbs = { alc662_init_verbs },
+		.init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
@@ -18826,7 +18562,7 @@ static struct alc_config_preset alc662_presets[] = {
 	},
 	},
 	[ALC662_3ST_6ch_DIG] = {
 	[ALC662_3ST_6ch_DIG] = {
 		.mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
 		.mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
-		.init_verbs = { alc662_init_verbs },
+		.init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
@@ -18838,7 +18574,7 @@ static struct alc_config_preset alc662_presets[] = {
 	},
 	},
 	[ALC662_3ST_6ch] = {
 	[ALC662_3ST_6ch] = {
 		.mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
 		.mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
-		.init_verbs = { alc662_init_verbs },
+		.init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
@@ -18848,7 +18584,7 @@ static struct alc_config_preset alc662_presets[] = {
 	},
 	},
 	[ALC662_5ST_DIG] = {
 	[ALC662_5ST_DIG] = {
 		.mixers = { alc662_base_mixer, alc662_chmode_mixer },
 		.mixers = { alc662_base_mixer, alc662_chmode_mixer },
-		.init_verbs = { alc662_init_verbs },
+		.init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
@@ -18859,104 +18595,120 @@ static struct alc_config_preset alc662_presets[] = {
 	},
 	},
 	[ALC662_LENOVO_101E] = {
 	[ALC662_LENOVO_101E] = {
 		.mixers = { alc662_lenovo_101e_mixer },
 		.mixers = { alc662_lenovo_101e_mixer },
-		.init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc662_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
 		.input_mux = &alc662_lenovo_101e_capture_source,
 		.input_mux = &alc662_lenovo_101e_capture_source,
-		.unsol_event = alc662_lenovo_101e_unsol_event,
-		.init_hook = alc662_lenovo_101e_all_automute,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc662_lenovo_101e_setup,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC662_ASUS_EEEPC_P701] = {
 	[ALC662_ASUS_EEEPC_P701] = {
 		.mixers = { alc662_eeepc_p701_mixer },
 		.mixers = { alc662_eeepc_p701_mixer },
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc662_eeepc_sue_init_verbs },
 				alc662_eeepc_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc662_eeepc_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc662_eeepc_setup,
 		.setup = alc662_eeepc_setup,
-		.init_hook = alc662_eeepc_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC662_ASUS_EEEPC_EP20] = {
 	[ALC662_ASUS_EEEPC_EP20] = {
 		.mixers = { alc662_eeepc_ep20_mixer,
 		.mixers = { alc662_eeepc_ep20_mixer,
 			    alc662_chmode_mixer },
 			    alc662_chmode_mixer },
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc662_eeepc_ep20_sue_init_verbs },
 				alc662_eeepc_ep20_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.channel_mode = alc662_3ST_6ch_modes,
 		.channel_mode = alc662_3ST_6ch_modes,
 		.input_mux = &alc662_lenovo_101e_capture_source,
 		.input_mux = &alc662_lenovo_101e_capture_source,
-		.unsol_event = alc662_eeepc_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc662_eeepc_ep20_setup,
 		.setup = alc662_eeepc_ep20_setup,
-		.init_hook = alc662_eeepc_ep20_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC662_ECS] = {
 	[ALC662_ECS] = {
 		.mixers = { alc662_ecs_mixer },
 		.mixers = { alc662_ecs_mixer },
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc662_ecs_init_verbs },
 				alc662_ecs_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc662_eeepc_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc662_eeepc_setup,
 		.setup = alc662_eeepc_setup,
-		.init_hook = alc662_eeepc_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_M51VA] = {
 	[ALC663_ASUS_M51VA] = {
 		.mixers = { alc663_m51va_mixer },
 		.mixers = { alc663_m51va_mixer },
-		.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc663_m51va_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_m51va_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_m51va_setup,
 		.setup = alc663_m51va_setup,
-		.init_hook = alc663_m51va_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_G71V] = {
 	[ALC663_ASUS_G71V] = {
 		.mixers = { alc663_g71v_mixer },
 		.mixers = { alc663_g71v_mixer },
-		.init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc663_g71v_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_g71v_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_g71v_setup,
 		.setup = alc663_g71v_setup,
-		.init_hook = alc663_g71v_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_H13] = {
 	[ALC663_ASUS_H13] = {
 		.mixers = { alc663_m51va_mixer },
 		.mixers = { alc663_m51va_mixer },
-		.init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc663_m51va_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_m51va_unsol_event,
-		.init_hook = alc663_m51va_inithook,
+		.setup = alc663_m51va_setup,
+		.unsol_event = alc_sku_unsol_event,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_G50V] = {
 	[ALC663_ASUS_G50V] = {
 		.mixers = { alc663_g50v_mixer },
 		.mixers = { alc663_g50v_mixer },
-		.init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc663_g50v_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.channel_mode = alc662_3ST_6ch_modes,
 		.channel_mode = alc662_3ST_6ch_modes,
 		.input_mux = &alc663_capture_source,
 		.input_mux = &alc663_capture_source,
-		.unsol_event = alc663_g50v_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_g50v_setup,
 		.setup = alc663_g50v_setup,
-		.init_hook = alc663_g50v_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_MODE1] = {
 	[ALC663_ASUS_MODE1] = {
 		.mixers = { alc663_m51va_mixer },
 		.mixers = { alc663_m51va_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_21jd_amic_init_verbs },
 				alc663_21jd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
@@ -18964,28 +18716,30 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode1_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode1_setup,
 		.setup = alc663_mode1_setup,
-		.init_hook = alc663_mode1_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC662_ASUS_MODE2] = {
 	[ALC662_ASUS_MODE2] = {
 		.mixers = { alc662_1bjd_mixer },
 		.mixers = { alc662_1bjd_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc662_1bjd_amic_init_verbs },
 				alc662_1bjd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc662_mode2_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc662_mode2_setup,
 		.setup = alc662_mode2_setup,
-		.init_hook = alc662_mode2_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_MODE3] = {
 	[ALC663_ASUS_MODE3] = {
 		.mixers = { alc663_two_hp_m1_mixer },
 		.mixers = { alc663_two_hp_m1_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_two_hp_amic_m1_init_verbs },
 				alc663_two_hp_amic_m1_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
@@ -18993,14 +18747,15 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode3_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode3_setup,
 		.setup = alc663_mode3_setup,
-		.init_hook = alc663_mode3_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_MODE4] = {
 	[ALC663_ASUS_MODE4] = {
 		.mixers = { alc663_asus_21jd_clfe_mixer },
 		.mixers = { alc663_asus_21jd_clfe_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_21jd_amic_init_verbs},
 				alc663_21jd_amic_init_verbs},
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
@@ -19008,14 +18763,15 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode4_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode4_setup,
 		.setup = alc663_mode4_setup,
-		.init_hook = alc663_mode4_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_MODE5] = {
 	[ALC663_ASUS_MODE5] = {
 		.mixers = { alc663_asus_15jd_clfe_mixer },
 		.mixers = { alc663_asus_15jd_clfe_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_15jd_amic_init_verbs },
 				alc663_15jd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
@@ -19023,14 +18779,15 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode5_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode5_setup,
 		.setup = alc663_mode5_setup,
-		.init_hook = alc663_mode5_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_MODE6] = {
 	[ALC663_ASUS_MODE6] = {
 		.mixers = { alc663_two_hp_m2_mixer },
 		.mixers = { alc663_two_hp_m2_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_two_hp_amic_m2_init_verbs },
 				alc663_two_hp_amic_m2_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
@@ -19038,14 +18795,15 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode6_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode6_setup,
 		.setup = alc663_mode6_setup,
-		.init_hook = alc663_mode6_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_MODE7] = {
 	[ALC663_ASUS_MODE7] = {
 		.mixers = { alc663_mode7_mixer },
 		.mixers = { alc663_mode7_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_mode7_init_verbs },
 				alc663_mode7_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
@@ -19053,14 +18811,15 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode7_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode7_setup,
 		.setup = alc663_mode7_setup,
-		.init_hook = alc663_mode7_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC663_ASUS_MODE8] = {
 	[ALC663_ASUS_MODE8] = {
 		.mixers = { alc663_mode8_mixer },
 		.mixers = { alc663_mode8_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.cap_mixer = alc662_auto_capture_mixer,
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_mode8_init_verbs },
 				alc663_mode8_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.hp_nid = 0x03,
 		.hp_nid = 0x03,
@@ -19068,52 +18827,57 @@ static struct alc_config_preset alc662_presets[] = {
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.dig_out_nid = ALC662_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_mode8_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode8_setup,
 		.setup = alc663_mode8_setup,
-		.init_hook = alc663_mode8_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC272_DELL] = {
 	[ALC272_DELL] = {
 		.mixers = { alc663_m51va_mixer },
 		.mixers = { alc663_m51va_mixer },
 		.cap_mixer = alc272_auto_capture_mixer,
 		.cap_mixer = alc272_auto_capture_mixer,
-		.init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc272_dell_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc272_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc272_dac_nids),
-		.dac_nids = alc662_dac_nids,
+		.dac_nids = alc272_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.adc_nids = alc272_adc_nids,
 		.adc_nids = alc272_adc_nids,
 		.num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
 		.num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
 		.capsrc_nids = alc272_capsrc_nids,
 		.capsrc_nids = alc272_capsrc_nids,
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_m51va_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_m51va_setup,
 		.setup = alc663_m51va_setup,
-		.init_hook = alc663_m51va_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC272_DELL_ZM1] = {
 	[ALC272_DELL_ZM1] = {
 		.mixers = { alc663_m51va_mixer },
 		.mixers = { alc663_m51va_mixer },
 		.cap_mixer = alc662_auto_capture_mixer,
 		.cap_mixer = alc662_auto_capture_mixer,
-		.init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
+				alc272_dell_zm1_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc272_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc272_dac_nids),
-		.dac_nids = alc662_dac_nids,
+		.dac_nids = alc272_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.adc_nids = alc662_adc_nids,
 		.adc_nids = alc662_adc_nids,
 		.num_adc_nids = 1,
 		.num_adc_nids = 1,
 		.capsrc_nids = alc662_capsrc_nids,
 		.capsrc_nids = alc662_capsrc_nids,
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
-		.unsol_event = alc663_m51va_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_m51va_setup,
 		.setup = alc663_m51va_setup,
-		.init_hook = alc663_m51va_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 	[ALC272_SAMSUNG_NC10] = {
 	[ALC272_SAMSUNG_NC10] = {
 		.mixers = { alc272_nc10_mixer },
 		.mixers = { alc272_nc10_mixer },
 		.init_verbs = { alc662_init_verbs,
 		.init_verbs = { alc662_init_verbs,
+				alc662_eapd_init_verbs,
 				alc663_21jd_amic_init_verbs },
 				alc663_21jd_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc272_dac_nids),
 		.num_dacs = ARRAY_SIZE(alc272_dac_nids),
 		.dac_nids = alc272_dac_nids,
 		.dac_nids = alc272_dac_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.channel_mode = alc662_3ST_2ch_modes,
 		/*.input_mux = &alc272_nc10_capture_source,*/
 		/*.input_mux = &alc272_nc10_capture_source,*/
-		.unsol_event = alc663_mode4_unsol_event,
+		.unsol_event = alc_sku_unsol_event,
 		.setup = alc663_mode4_setup,
 		.setup = alc663_mode4_setup,
-		.init_hook = alc663_mode4_inithook,
+		.init_hook = alc_inithook,
 	},
 	},
 };
 };
 
 
@@ -19123,45 +18887,79 @@ static struct alc_config_preset alc662_presets[] = {
  */
  */
 
 
 /* convert from MIX nid to DAC */
 /* convert from MIX nid to DAC */
-static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
-{
-	if (nid == 0x0f)
-		return 0x02;
-	else if (nid >= 0x0c && nid <= 0x0e)
-		return nid - 0x0c + 0x02;
-	else if (nid == 0x26) /* ALC887-VD has this DAC too */
-		return 0x25;
-	else
-		return 0;
+static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
+{
+	hda_nid_t list[5];
+	int i, num;
+
+	num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
+	for (i = 0; i < num; i++) {
+		if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
+			return list[i];
+	}
+	return 0;
+}
+
+/* go down to the selector widget before the mixer */
+static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
+{
+	hda_nid_t srcs[5];
+	int num = snd_hda_get_connections(codec, pin, srcs,
+					  ARRAY_SIZE(srcs));
+	if (num != 1 ||
+	    get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
+		return pin;
+	return srcs[0];
 }
 }
 
 
 /* get MIX nid connected to the given pin targeted to DAC */
 /* get MIX nid connected to the given pin targeted to DAC */
-static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
+static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
 				   hda_nid_t dac)
 				   hda_nid_t dac)
 {
 {
 	hda_nid_t mix[5];
 	hda_nid_t mix[5];
 	int i, num;
 	int i, num;
 
 
+	pin = alc_go_down_to_selector(codec, pin);
 	num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
 	num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
 	for (i = 0; i < num; i++) {
 	for (i = 0; i < num; i++) {
-		if (alc662_mix_to_dac(mix[i]) == dac)
+		if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
 			return mix[i];
 			return mix[i];
 	}
 	}
 	return 0;
 	return 0;
 }
 }
 
 
+/* select the connection from pin to DAC if needed */
+static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
+			       hda_nid_t dac)
+{
+	hda_nid_t mix[5];
+	int i, num;
+
+	pin = alc_go_down_to_selector(codec, pin);
+	num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
+	if (num < 2)
+		return 0;
+	for (i = 0; i < num; i++) {
+		if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
+			snd_hda_codec_update_cache(codec, pin, 0,
+						   AC_VERB_SET_CONNECT_SEL, i);
+			return 0;
+		}
+	}
+	return 0;
+}
+
 /* look for an empty DAC slot */
 /* look for an empty DAC slot */
-static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
+static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	hda_nid_t srcs[5];
 	hda_nid_t srcs[5];
 	int i, j, num;
 	int i, j, num;
 
 
+	pin = alc_go_down_to_selector(codec, pin);
 	num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
 	num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
-	if (num < 0)
-		return 0;
 	for (i = 0; i < num; i++) {
 	for (i = 0; i < num; i++) {
-		hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
+		hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
 		if (!nid)
 		if (!nid)
 			continue;
 			continue;
 		for (j = 0; j < spec->multiout.num_dacs; j++)
 		for (j = 0; j < spec->multiout.num_dacs; j++)
@@ -19183,10 +18981,10 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
 
 
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	for (i = 0; i < cfg->line_outs; i++) {
 	for (i = 0; i < cfg->line_outs; i++) {
-		dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
+		dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]);
 		if (!dac)
 		if (!dac)
 			continue;
 			continue;
-		spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+		spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -19222,15 +19020,23 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
 	static const char * const chname[4] = {
 	static const char * const chname[4] = {
 		"Front", "Surround", NULL /*CLFE*/, "Side"
 		"Front", "Surround", NULL /*CLFE*/, "Side"
 	};
 	};
-	const char *pfx = alc_get_line_out_pfx(cfg, true);
-	hda_nid_t nid, mix;
-	int i, err;
+	const char *pfx = alc_get_line_out_pfx(spec, true);
+	hda_nid_t nid, mix, pin;
+	int i, err, noutputs;
 
 
-	for (i = 0; i < cfg->line_outs; i++) {
+	noutputs = cfg->line_outs;
+	if (spec->multi_ios > 0)
+		noutputs += spec->multi_ios;
+
+	for (i = 0; i < noutputs; i++) {
 		nid = spec->multiout.dac_nids[i];
 		nid = spec->multiout.dac_nids[i];
 		if (!nid)
 		if (!nid)
 			continue;
 			continue;
-		mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
+		if (i >= cfg->line_outs)
+			pin = spec->multi_io[i - 1].pin;
+		else
+			pin = cfg->line_out_pins[i];
+		mix = alc_auto_dac_to_mix(codec, pin, nid);
 		if (!mix)
 		if (!mix)
 			continue;
 			continue;
 		if (!pfx && i == 2) {
 		if (!pfx && i == 2) {
@@ -19276,7 +19082,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
 
 
 	if (!pin)
 	if (!pin)
 		return 0;
 		return 0;
-	nid = alc662_look_for_dac(codec, pin);
+	nid = alc_auto_look_for_dac(codec, pin);
 	if (!nid) {
 	if (!nid) {
 		/* the corresponding DAC is already occupied */
 		/* the corresponding DAC is already occupied */
 		if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
 		if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
@@ -19286,7 +19092,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
 				   HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
 				   HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
 	}
 	}
 
 
-	mix = alc662_dac_to_mix(codec, pin, nid);
+	mix = alc_auto_dac_to_mix(codec, pin, nid);
 	if (!mix)
 	if (!mix)
 		return 0;
 		return 0;
 	err = alc662_add_vol_ctl(spec, pfx, nid, 3);
 	err = alc662_add_vol_ctl(spec, pfx, nid, 3);
@@ -19310,14 +19116,21 @@ static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
 	hda_nid_t srcs[HDA_MAX_CONNECTIONS];
 	hda_nid_t srcs[HDA_MAX_CONNECTIONS];
 
 
 	alc_set_pin_output(codec, nid, pin_type);
 	alc_set_pin_output(codec, nid, pin_type);
-	/* need the manual connection? */
 	num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
 	num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
-	if (num <= 1)
-		return;
 	for (i = 0; i < num; i++) {
 	for (i = 0; i < num; i++) {
-		if (alc662_mix_to_dac(srcs[i]) != dac)
+		if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
 			continue;
 			continue;
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
+		/* need the manual connection? */
+		if (num > 1)
+			snd_hda_codec_write(codec, nid, 0,
+					    AC_VERB_SET_CONNECT_SEL, i);
+		/* unmute mixer widget inputs */
+		snd_hda_codec_write(codec, srcs[i], 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_IN_UNMUTE(0));
+		snd_hda_codec_write(codec, srcs[i], 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_IN_UNMUTE(1));
 		return;
 		return;
 	}
 	}
 }
 }
@@ -19374,11 +19187,164 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec)
 
 
 #define alc662_auto_init_input_src	alc882_auto_init_input_src
 #define alc662_auto_init_input_src	alc882_auto_init_input_src
 
 
+/*
+ * multi-io helper
+ */
+static int alc_auto_fill_multi_ios(struct hda_codec *codec,
+				   unsigned int location)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int type, i, num_pins = 0;
+
+	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
+		for (i = 0; i < cfg->num_inputs; i++) {
+			hda_nid_t nid = cfg->inputs[i].pin;
+			hda_nid_t dac;
+			unsigned int defcfg, caps;
+			if (cfg->inputs[i].type != type)
+				continue;
+			defcfg = snd_hda_codec_get_pincfg(codec, nid);
+			if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
+				continue;
+			if (location && get_defcfg_location(defcfg) != location)
+				continue;
+			caps = snd_hda_query_pin_caps(codec, nid);
+			if (!(caps & AC_PINCAP_OUT))
+				continue;
+			dac = alc_auto_look_for_dac(codec, nid);
+			if (!dac)
+				continue;
+			spec->multi_io[num_pins].pin = nid;
+			spec->multi_io[num_pins].dac = dac;
+			num_pins++;
+			spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
+		}
+	}
+	spec->multiout.num_dacs = 1;
+	if (num_pins < 2)
+		return 0;
+	return num_pins;
+}
+
+static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = spec->multi_ios + 1;
+	if (uinfo->value.enumerated.item > spec->multi_ios)
+		uinfo->value.enumerated.item = spec->multi_ios;
+	sprintf(uinfo->value.enumerated.name, "%dch",
+		(uinfo->value.enumerated.item + 1) * 2);
+	return 0;
+}
+
+static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
+	return 0;
+}
+
+static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
+{
+	struct alc_spec *spec = codec->spec;
+	hda_nid_t nid = spec->multi_io[idx].pin;
+
+	if (!spec->multi_io[idx].ctl_in)
+		spec->multi_io[idx].ctl_in =
+			snd_hda_codec_read(codec, nid, 0,
+					   AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+	if (output) {
+		snd_hda_codec_update_cache(codec, nid, 0,
+					   AC_VERB_SET_PIN_WIDGET_CONTROL,
+					   PIN_OUT);
+		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+						 HDA_AMP_MUTE, 0);
+		alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
+	} else {
+		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+						 HDA_AMP_MUTE, HDA_AMP_MUTE);
+		snd_hda_codec_update_cache(codec, nid, 0,
+					   AC_VERB_SET_PIN_WIDGET_CONTROL,
+					   spec->multi_io[idx].ctl_in);
+	}
+	return 0;
+}
+
+static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	int i, ch;
+
+	ch = ucontrol->value.enumerated.item[0];
+	if (ch < 0 || ch > spec->multi_ios)
+		return -EINVAL;
+	if (ch == (spec->ext_channel_count - 1) / 2)
+		return 0;
+	spec->ext_channel_count = (ch + 1) * 2;
+	for (i = 0; i < spec->multi_ios; i++)
+		alc_set_multi_io(codec, i, i < ch);
+	spec->multiout.max_channels = spec->ext_channel_count;
+	return 1;
+}
+
+static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Channel Mode",
+	.info = alc_auto_ch_mode_info,
+	.get = alc_auto_ch_mode_get,
+	.put = alc_auto_ch_mode_put,
+};
+
+static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	unsigned int location, defcfg;
+	int num_pins;
+
+	if (cfg->line_outs != 1 ||
+	    cfg->line_out_type != AUTO_PIN_LINE_OUT)
+		return 0;
+
+	defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
+	location = get_defcfg_location(defcfg);
+
+	num_pins = alc_auto_fill_multi_ios(codec, location);
+	if (num_pins > 0) {
+		struct snd_kcontrol_new *knew;
+
+		knew = alc_kcontrol_new(spec);
+		if (!knew)
+			return -ENOMEM;
+		*knew = alc_auto_channel_mode_enum;
+		knew->name = kstrdup("Channel Mode", GFP_KERNEL);
+		if (!knew->name)
+			return -ENOMEM;
+
+		spec->multi_ios = num_pins;
+		spec->ext_channel_count = 2;
+		spec->multiout.num_dacs = num_pins + 1;
+	}
+	return 0;
+}
+
 static int alc662_parse_auto_config(struct hda_codec *codec)
 static int alc662_parse_auto_config(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	int err;
 	int err;
-	static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
 
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc662_ignore);
 					   alc662_ignore);
@@ -19388,6 +19354,9 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
 		return 0; /* can't find valid BIOS pin config */
 		return 0; /* can't find valid BIOS pin config */
 
 
 	err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
 	err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = alc_auto_add_multi_channel_mode(codec);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 	err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
 	err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
@@ -19420,14 +19389,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
 	spec->num_mux_defs = 1;
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux[0];
 	spec->input_mux = &spec->private_imux[0];
 
 
-	add_verb(spec, alc662_init_verbs);
-	if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
-	    codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
-		add_verb(spec, alc663_init_verbs);
-
-	if (codec->vendor_id == 0x10ec0272)
-		add_verb(spec, alc272_init_verbs);
-
 	err = alc_auto_add_mic_boost(codec);
 	err = alc_auto_add_mic_boost(codec);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
@@ -19508,7 +19469,7 @@ static const struct alc_fixup alc662_fixups[] = {
 	},
 	},
 };
 };
 
 
-static struct snd_pci_quirk alc662_fixup_tbl[] = {
+static const struct snd_pci_quirk alc662_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
 	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
 	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
@@ -19626,6 +19587,7 @@ static int patch_alc662(struct hda_codec *codec)
 	codec->patch_ops = alc_patch_ops;
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC662_AUTO)
 	if (board_config == ALC662_AUTO)
 		spec->init_hook = alc662_auto_init;
 		spec->init_hook = alc662_auto_init;
+	spec->shutup = alc_eapd_shutup;
 
 
 	alc_init_jacks(codec);
 	alc_init_jacks(codec);
 
 
@@ -19654,6 +19616,15 @@ static int patch_alc888(struct hda_codec *codec)
 	return patch_alc882(codec);
 	return patch_alc882(codec);
 }
 }
 
 
+static int patch_alc899(struct hda_codec *codec)
+{
+	if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) {
+		kfree(codec->chip_name);
+		codec->chip_name = kstrdup("ALC898", GFP_KERNEL);
+	}
+	return patch_alc882(codec);
+}
+
 /*
 /*
  * ALC680 support
  * ALC680 support
  */
  */
@@ -19661,12 +19632,12 @@ static int patch_alc888(struct hda_codec *codec)
 #define ALC680_DIGOUT_NID	ALC880_DIGOUT_NID
 #define ALC680_DIGOUT_NID	ALC880_DIGOUT_NID
 #define alc680_modes		alc260_modes
 #define alc680_modes		alc260_modes
 
 
-static hda_nid_t alc680_dac_nids[3] = {
+static const hda_nid_t alc680_dac_nids[3] = {
 	/* Lout1, Lout2, hp */
 	/* Lout1, Lout2, hp */
 	0x02, 0x03, 0x04
 	0x02, 0x03, 0x04
 };
 };
 
 
-static hda_nid_t alc680_adc_nids[3] = {
+static const hda_nid_t alc680_adc_nids[3] = {
 	/* ADC0-2 */
 	/* ADC0-2 */
 	/* DMIC, MIC, Line-in*/
 	/* DMIC, MIC, Line-in*/
 	0x07, 0x08, 0x09
 	0x07, 0x08, 0x09
@@ -19686,8 +19657,7 @@ static void alc680_rec_autoswitch(struct hda_codec *codec)
 
 
 	for (i = 0; i < cfg->num_inputs; i++) {
 	for (i = 0; i < cfg->num_inputs; i++) {
 		nid = cfg->inputs[i].pin;
 		nid = cfg->inputs[i].pin;
-		if (!(snd_hda_query_pin_caps(codec, nid) &
-		      AC_PINCAP_PRES_DETECT))
+		if (!is_jack_detectable(codec, nid))
 			continue;
 			continue;
 		if (snd_hda_jack_detect(codec, nid)) {
 		if (snd_hda_jack_detect(codec, nid)) {
 			if (cfg->inputs[i].type < type_found) {
 			if (cfg->inputs[i].type < type_found) {
@@ -19734,7 +19704,7 @@ static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 	return 0;
 }
 }
 
 
-static struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
+static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
 	.substreams = 1, /* can be overridden */
 	.substreams = 1, /* can be overridden */
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -19745,7 +19715,7 @@ static struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new alc680_base_mixer[] = {
+static const struct snd_kcontrol_new alc680_base_mixer[] = {
 	/* output mixer control */
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
@@ -19757,7 +19727,7 @@ static struct snd_kcontrol_new alc680_base_mixer[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_bind_ctls alc680_bind_cap_vol = {
+static const struct hda_bind_ctls alc680_bind_cap_vol = {
 	.ops = &snd_hda_bind_vol,
 	.ops = &snd_hda_bind_vol,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
 		HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
@@ -19767,7 +19737,7 @@ static struct hda_bind_ctls alc680_bind_cap_vol = {
 	},
 	},
 };
 };
 
 
-static struct hda_bind_ctls alc680_bind_cap_switch = {
+static const struct hda_bind_ctls alc680_bind_cap_switch = {
 	.ops = &snd_hda_bind_sw,
 	.ops = &snd_hda_bind_sw,
 	.values = {
 	.values = {
 		HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
 		HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
@@ -19777,7 +19747,7 @@ static struct hda_bind_ctls alc680_bind_cap_switch = {
 	},
 	},
 };
 };
 
 
-static struct snd_kcontrol_new alc680_master_capture_mixer[] = {
+static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
 	HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
 	HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
 	HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
 	HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
 	{ } /* end */
 	{ } /* end */
@@ -19786,7 +19756,7 @@ static struct snd_kcontrol_new alc680_master_capture_mixer[] = {
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb alc680_init_verbs[] = {
+static const struct hda_verb alc680_init_verbs[] = {
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -19824,20 +19794,22 @@ static void alc680_base_setup(struct hda_codec *codec)
 	spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
 	spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
 	spec->autocfg.inputs[1].pin = 0x19;
 	spec->autocfg.inputs[1].pin = 0x19;
 	spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
 	spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
+	spec->automute = 1;
+	spec->automute_mode = ALC_AUTOMUTE_AMP;
 }
 }
 
 
 static void alc680_unsol_event(struct hda_codec *codec,
 static void alc680_unsol_event(struct hda_codec *codec,
 					   unsigned int res)
 					   unsigned int res)
 {
 {
 	if ((res >> 26) == ALC880_HP_EVENT)
 	if ((res >> 26) == ALC880_HP_EVENT)
-		alc_automute_amp(codec);
+		alc_hp_automute(codec);
 	if ((res >> 26) == ALC880_MIC_EVENT)
 	if ((res >> 26) == ALC880_MIC_EVENT)
 		alc680_rec_autoswitch(codec);
 		alc680_rec_autoswitch(codec);
 }
 }
 
 
 static void alc680_inithook(struct hda_codec *codec)
 static void alc680_inithook(struct hda_codec *codec)
 {
 {
-	alc_automute_amp(codec);
+	alc_hp_automute(codec);
 	alc680_rec_autoswitch(codec);
 	alc680_rec_autoswitch(codec);
 }
 }
 
 
@@ -19874,7 +19846,7 @@ static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
 
 
 		if (err < 0)
 		if (err < 0)
 			return err;
 			return err;
-		spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+		spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -19960,7 +19932,7 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
 	int err;
 	int err;
-	static hda_nid_t alc680_ignore[] = { 0 };
+	static const hda_nid_t alc680_ignore[] = { 0 };
 
 
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 					   alc680_ignore);
 					   alc680_ignore);
@@ -20018,12 +19990,12 @@ static const char * const alc680_models[ALC680_MODEL_LAST] = {
 	[ALC680_AUTO]		= "auto",
 	[ALC680_AUTO]		= "auto",
 };
 };
 
 
-static struct snd_pci_quirk alc680_cfg_tbl[] = {
+static const struct snd_pci_quirk alc680_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
 	SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
 	{}
 	{}
 };
 };
 
 
-static struct alc_config_preset alc680_presets[] = {
+static const struct alc_config_preset alc680_presets[] = {
 	[ALC680_BASE] = {
 	[ALC680_BASE] = {
 		.mixers = { alc680_base_mixer },
 		.mixers = { alc680_base_mixer },
 		.cap_mixer =  alc680_master_capture_mixer,
 		.cap_mixer =  alc680_master_capture_mixer,
@@ -20104,7 +20076,8 @@ static int patch_alc680(struct hda_codec *codec)
 /*
 /*
  * patch entries
  * patch entries
  */
  */
-static struct hda_codec_preset snd_hda_preset_realtek[] = {
+static const struct hda_codec_preset snd_hda_preset_realtek[] = {
+	{ .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
 	{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
 	{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
 	{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
 	{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
 	{ .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
 	{ .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
@@ -20113,6 +20086,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
 	{ .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
 	{ .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
 	{ .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
 	{ .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
 	{ .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
 	{ .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
+	{ .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
 	{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
 	{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
 	  .patch = patch_alc861 },
 	  .patch = patch_alc861 },
 	{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
 	{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
@@ -20140,6 +20114,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
 	{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
 	{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
 	{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
 	{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
 	{ .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
 	{ .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
+	{ .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 },
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 

+ 6 - 5
sound/pci/hda/patch_si3054.c

@@ -130,7 +130,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol,
 }
 }
 		
 		
 
 
-static struct snd_kcontrol_new si3054_modem_mixer[] = {
+static const struct snd_kcontrol_new si3054_modem_mixer[] = {
 	SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH),
 	SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH),
 	SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID),
 	SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID),
 	{}
 	{}
@@ -181,7 +181,7 @@ static int si3054_pcm_open(struct hda_pcm_stream *hinfo,
 }
 }
 
 
 
 
-static struct hda_pcm_stream si3054_pcm = {
+static const struct hda_pcm_stream si3054_pcm = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 1,
 	.channels_min = 1,
 	.channels_max = 1,
 	.channels_max = 1,
@@ -200,12 +200,13 @@ static int si3054_build_pcms(struct hda_codec *codec)
 {
 {
 	struct si3054_spec *spec = codec->spec;
 	struct si3054_spec *spec = codec->spec;
 	struct hda_pcm *info = &spec->pcm;
 	struct hda_pcm *info = &spec->pcm;
-	si3054_pcm.nid = codec->mfg;
 	codec->num_pcms = 1;
 	codec->num_pcms = 1;
 	codec->pcm_info = info;
 	codec->pcm_info = info;
 	info->name = "Si3054 Modem";
 	info->name = "Si3054 Modem";
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->mfg;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = codec->mfg;
 	info->pcm_type = HDA_PCM_TYPE_MODEM;
 	info->pcm_type = HDA_PCM_TYPE_MODEM;
 	return 0;
 	return 0;
 }
 }
@@ -263,7 +264,7 @@ static void si3054_free(struct hda_codec *codec)
 /*
 /*
  */
  */
 
 
-static struct hda_codec_ops si3054_patch_ops = {
+static const struct hda_codec_ops si3054_patch_ops = {
 	.build_controls = si3054_build_controls,
 	.build_controls = si3054_build_controls,
 	.build_pcms = si3054_build_pcms,
 	.build_pcms = si3054_build_pcms,
 	.init = si3054_init,
 	.init = si3054_init,
@@ -283,7 +284,7 @@ static int patch_si3054(struct hda_codec *codec)
 /*
 /*
  * patch entries
  * patch entries
  */
  */
-static struct hda_codec_preset snd_hda_preset_si3054[] = {
+static const struct hda_codec_preset snd_hda_preset_si3054[] = {
  	{ .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },

+ 214 - 217
sound/pci/hda/patch_sigmatel.c

@@ -217,15 +217,15 @@ struct sigmatel_spec {
 	unsigned int stream_delay;
 	unsigned int stream_delay;
 
 
 	/* analog loopback */
 	/* analog loopback */
-	struct snd_kcontrol_new *aloopback_ctl;
+	const struct snd_kcontrol_new *aloopback_ctl;
 	unsigned char aloopback_mask;
 	unsigned char aloopback_mask;
 	unsigned char aloopback_shift;
 	unsigned char aloopback_shift;
 
 
 	/* power management */
 	/* power management */
 	unsigned int num_pwrs;
 	unsigned int num_pwrs;
-	unsigned int *pwr_mapping;
-	hda_nid_t *pwr_nids;
-	hda_nid_t *dac_list;
+	const unsigned int *pwr_mapping;
+	const hda_nid_t *pwr_nids;
+	const hda_nid_t *dac_list;
 
 
 	/* events */
 	/* events */
 	struct snd_array events;
 	struct snd_array events;
@@ -241,20 +241,20 @@ struct sigmatel_spec {
 	int volume_offset;
 	int volume_offset;
 
 
 	/* capture */
 	/* capture */
-	hda_nid_t *adc_nids;
+	const hda_nid_t *adc_nids;
 	unsigned int num_adcs;
 	unsigned int num_adcs;
-	hda_nid_t *mux_nids;
+	const hda_nid_t *mux_nids;
 	unsigned int num_muxes;
 	unsigned int num_muxes;
-	hda_nid_t *dmic_nids;
+	const hda_nid_t *dmic_nids;
 	unsigned int num_dmics;
 	unsigned int num_dmics;
-	hda_nid_t *dmux_nids;
+	const hda_nid_t *dmux_nids;
 	unsigned int num_dmuxes;
 	unsigned int num_dmuxes;
-	hda_nid_t *smux_nids;
+	const hda_nid_t *smux_nids;
 	unsigned int num_smuxes;
 	unsigned int num_smuxes;
 	unsigned int num_analog_muxes;
 	unsigned int num_analog_muxes;
 
 
-	unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */
-	unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
+	const unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */
+	const unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
 	unsigned int num_caps; /* number of capture volume/switch elements */
 	unsigned int num_caps; /* number of capture volume/switch elements */
 
 
 	struct sigmatel_mic_route ext_mic;
 	struct sigmatel_mic_route ext_mic;
@@ -269,12 +269,12 @@ struct sigmatel_spec {
 	hda_nid_t digbeep_nid;
 	hda_nid_t digbeep_nid;
 
 
 	/* pin widgets */
 	/* pin widgets */
-	hda_nid_t *pin_nids;
+	const hda_nid_t *pin_nids;
 	unsigned int num_pins;
 	unsigned int num_pins;
 
 
 	/* codec specific stuff */
 	/* codec specific stuff */
-	struct hda_verb *init;
-	struct snd_kcontrol_new *mixer;
+	const struct hda_verb *init;
+	const struct snd_kcontrol_new *mixer;
 
 
 	/* capture source */
 	/* capture source */
 	struct hda_input_mux *dinput_mux;
 	struct hda_input_mux *dinput_mux;
@@ -317,52 +317,52 @@ struct sigmatel_spec {
 	hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
 	hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
 };
 };
 
 
-static hda_nid_t stac9200_adc_nids[1] = {
+static const hda_nid_t stac9200_adc_nids[1] = {
         0x03,
         0x03,
 };
 };
 
 
-static hda_nid_t stac9200_mux_nids[1] = {
+static const hda_nid_t stac9200_mux_nids[1] = {
         0x0c,
         0x0c,
 };
 };
 
 
-static hda_nid_t stac9200_dac_nids[1] = {
+static const hda_nid_t stac9200_dac_nids[1] = {
         0x02,
         0x02,
 };
 };
 
 
-static hda_nid_t stac92hd73xx_pwr_nids[8] = {
+static const hda_nid_t stac92hd73xx_pwr_nids[8] = {
 	0x0a, 0x0b, 0x0c, 0xd, 0x0e,
 	0x0a, 0x0b, 0x0c, 0xd, 0x0e,
 	0x0f, 0x10, 0x11
 	0x0f, 0x10, 0x11
 };
 };
 
 
-static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
+static const hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
 	0x26, 0,
 	0x26, 0,
 };
 };
 
 
-static hda_nid_t stac92hd73xx_adc_nids[2] = {
+static const hda_nid_t stac92hd73xx_adc_nids[2] = {
 	0x1a, 0x1b
 	0x1a, 0x1b
 };
 };
 
 
 #define STAC92HD73XX_NUM_DMICS	2
 #define STAC92HD73XX_NUM_DMICS	2
-static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
+static const hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
 	0x13, 0x14, 0
 	0x13, 0x14, 0
 };
 };
 
 
 #define STAC92HD73_DAC_COUNT 5
 #define STAC92HD73_DAC_COUNT 5
 
 
-static hda_nid_t stac92hd73xx_mux_nids[2] = {
+static const hda_nid_t stac92hd73xx_mux_nids[2] = {
 	0x20, 0x21,
 	0x20, 0x21,
 };
 };
 
 
-static hda_nid_t stac92hd73xx_dmux_nids[2] = {
+static const hda_nid_t stac92hd73xx_dmux_nids[2] = {
 	0x20, 0x21,
 	0x20, 0x21,
 };
 };
 
 
-static hda_nid_t stac92hd73xx_smux_nids[2] = {
+static const hda_nid_t stac92hd73xx_smux_nids[2] = {
 	0x22, 0x23,
 	0x22, 0x23,
 };
 };
 
 
 #define STAC92HD73XX_NUM_CAPS	2
 #define STAC92HD73XX_NUM_CAPS	2
-static unsigned long stac92hd73xx_capvols[] = {
+static const unsigned long stac92hd73xx_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
 };
 };
@@ -370,137 +370,141 @@ static unsigned long stac92hd73xx_capvols[] = {
 
 
 #define STAC92HD83_DAC_COUNT 3
 #define STAC92HD83_DAC_COUNT 3
 
 
-static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
+static const hda_nid_t stac92hd83xxx_pwr_nids[4] = {
 	0xa, 0xb, 0xd, 0xe,
 	0xa, 0xb, 0xd, 0xe,
 };
 };
 
 
-static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
+static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
 	0x1e, 0,
 	0x1e, 0,
 };
 };
 
 
-static unsigned int stac92hd83xxx_pwr_mapping[4] = {
+static const unsigned int stac92hd83xxx_pwr_mapping[4] = {
 	0x03, 0x0c, 0x20, 0x40,
 	0x03, 0x0c, 0x20, 0x40,
 };
 };
 
 
-static hda_nid_t stac92hd83xxx_dmic_nids[] = {
+static const hda_nid_t stac92hd83xxx_dmic_nids[] = {
 		0x11, 0x20,
 		0x11, 0x20,
 };
 };
 
 
-static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
+static const hda_nid_t stac92hd71bxx_pwr_nids[3] = {
 	0x0a, 0x0d, 0x0f
 	0x0a, 0x0d, 0x0f
 };
 };
 
 
-static hda_nid_t stac92hd71bxx_adc_nids[2] = {
+static const hda_nid_t stac92hd71bxx_adc_nids[2] = {
 	0x12, 0x13,
 	0x12, 0x13,
 };
 };
 
 
-static hda_nid_t stac92hd71bxx_mux_nids[2] = {
+static const hda_nid_t stac92hd71bxx_mux_nids[2] = {
 	0x1a, 0x1b
 	0x1a, 0x1b
 };
 };
 
 
-static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
+static const hda_nid_t stac92hd71bxx_dmux_nids[2] = {
 	0x1c, 0x1d,
 	0x1c, 0x1d,
 };
 };
 
 
-static hda_nid_t stac92hd71bxx_smux_nids[2] = {
+static const hda_nid_t stac92hd71bxx_smux_nids[2] = {
 	0x24, 0x25,
 	0x24, 0x25,
 };
 };
 
 
 #define STAC92HD71BXX_NUM_DMICS	2
 #define STAC92HD71BXX_NUM_DMICS	2
-static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
+static const hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
 	0x18, 0x19, 0
 	0x18, 0x19, 0
 };
 };
 
 
-static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
+static const hda_nid_t stac92hd71bxx_dmic_5port_nids[STAC92HD71BXX_NUM_DMICS] = {
+	0x18, 0
+};
+
+static const hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
 	0x22, 0
 	0x22, 0
 };
 };
 
 
 #define STAC92HD71BXX_NUM_CAPS		2
 #define STAC92HD71BXX_NUM_CAPS		2
-static unsigned long stac92hd71bxx_capvols[] = {
+static const unsigned long stac92hd71bxx_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 };
 };
 #define stac92hd71bxx_capsws	stac92hd71bxx_capvols
 #define stac92hd71bxx_capsws	stac92hd71bxx_capvols
 
 
-static hda_nid_t stac925x_adc_nids[1] = {
+static const hda_nid_t stac925x_adc_nids[1] = {
         0x03,
         0x03,
 };
 };
 
 
-static hda_nid_t stac925x_mux_nids[1] = {
+static const hda_nid_t stac925x_mux_nids[1] = {
         0x0f,
         0x0f,
 };
 };
 
 
-static hda_nid_t stac925x_dac_nids[1] = {
+static const hda_nid_t stac925x_dac_nids[1] = {
         0x02,
         0x02,
 };
 };
 
 
 #define STAC925X_NUM_DMICS	1
 #define STAC925X_NUM_DMICS	1
-static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
+static const hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
 	0x15, 0
 	0x15, 0
 };
 };
 
 
-static hda_nid_t stac925x_dmux_nids[1] = {
+static const hda_nid_t stac925x_dmux_nids[1] = {
 	0x14,
 	0x14,
 };
 };
 
 
-static unsigned long stac925x_capvols[] = {
+static const unsigned long stac925x_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
 };
 };
-static unsigned long stac925x_capsws[] = {
+static const unsigned long stac925x_capsws[] = {
 	HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 };
 };
 
 
-static hda_nid_t stac922x_adc_nids[2] = {
+static const hda_nid_t stac922x_adc_nids[2] = {
         0x06, 0x07,
         0x06, 0x07,
 };
 };
 
 
-static hda_nid_t stac922x_mux_nids[2] = {
+static const hda_nid_t stac922x_mux_nids[2] = {
         0x12, 0x13,
         0x12, 0x13,
 };
 };
 
 
 #define STAC922X_NUM_CAPS	2
 #define STAC922X_NUM_CAPS	2
-static unsigned long stac922x_capvols[] = {
+static const unsigned long stac922x_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
 };
 };
 #define stac922x_capsws		stac922x_capvols
 #define stac922x_capsws		stac922x_capvols
 
 
-static hda_nid_t stac927x_slave_dig_outs[2] = {
+static const hda_nid_t stac927x_slave_dig_outs[2] = {
 	0x1f, 0,
 	0x1f, 0,
 };
 };
 
 
-static hda_nid_t stac927x_adc_nids[3] = {
+static const hda_nid_t stac927x_adc_nids[3] = {
         0x07, 0x08, 0x09
         0x07, 0x08, 0x09
 };
 };
 
 
-static hda_nid_t stac927x_mux_nids[3] = {
+static const hda_nid_t stac927x_mux_nids[3] = {
         0x15, 0x16, 0x17
         0x15, 0x16, 0x17
 };
 };
 
 
-static hda_nid_t stac927x_smux_nids[1] = {
+static const hda_nid_t stac927x_smux_nids[1] = {
 	0x21,
 	0x21,
 };
 };
 
 
-static hda_nid_t stac927x_dac_nids[6] = {
+static const hda_nid_t stac927x_dac_nids[6] = {
 	0x02, 0x03, 0x04, 0x05, 0x06, 0
 	0x02, 0x03, 0x04, 0x05, 0x06, 0
 };
 };
 
 
-static hda_nid_t stac927x_dmux_nids[1] = {
+static const hda_nid_t stac927x_dmux_nids[1] = {
 	0x1b,
 	0x1b,
 };
 };
 
 
 #define STAC927X_NUM_DMICS 2
 #define STAC927X_NUM_DMICS 2
-static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
+static const hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
 	0x13, 0x14, 0
 	0x13, 0x14, 0
 };
 };
 
 
 #define STAC927X_NUM_CAPS	3
 #define STAC927X_NUM_CAPS	3
-static unsigned long stac927x_capvols[] = {
+static const unsigned long stac927x_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT),
 };
 };
-static unsigned long stac927x_capsws[] = {
+static const unsigned long stac927x_capsws[] = {
 	HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
@@ -511,77 +515,77 @@ static const char * const stac927x_spdif_labels[5] = {
 	"Analog Mux 2", "Analog Mux 3"
 	"Analog Mux 2", "Analog Mux 3"
 };
 };
 
 
-static hda_nid_t stac9205_adc_nids[2] = {
+static const hda_nid_t stac9205_adc_nids[2] = {
         0x12, 0x13
         0x12, 0x13
 };
 };
 
 
-static hda_nid_t stac9205_mux_nids[2] = {
+static const hda_nid_t stac9205_mux_nids[2] = {
         0x19, 0x1a
         0x19, 0x1a
 };
 };
 
 
-static hda_nid_t stac9205_dmux_nids[1] = {
+static const hda_nid_t stac9205_dmux_nids[1] = {
 	0x1d,
 	0x1d,
 };
 };
 
 
-static hda_nid_t stac9205_smux_nids[1] = {
+static const hda_nid_t stac9205_smux_nids[1] = {
 	0x21,
 	0x21,
 };
 };
 
 
 #define STAC9205_NUM_DMICS	2
 #define STAC9205_NUM_DMICS	2
-static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
+static const hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
         0x17, 0x18, 0
         0x17, 0x18, 0
 };
 };
 
 
 #define STAC9205_NUM_CAPS	2
 #define STAC9205_NUM_CAPS	2
-static unsigned long stac9205_capvols[] = {
+static const unsigned long stac9205_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT),
 };
 };
-static unsigned long stac9205_capsws[] = {
+static const unsigned long stac9205_capsws[] = {
 	HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT),
 	HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT),
 };
 };
 
 
-static hda_nid_t stac9200_pin_nids[8] = {
+static const hda_nid_t stac9200_pin_nids[8] = {
 	0x08, 0x09, 0x0d, 0x0e, 
 	0x08, 0x09, 0x0d, 0x0e, 
 	0x0f, 0x10, 0x11, 0x12,
 	0x0f, 0x10, 0x11, 0x12,
 };
 };
 
 
-static hda_nid_t stac925x_pin_nids[8] = {
+static const hda_nid_t stac925x_pin_nids[8] = {
 	0x07, 0x08, 0x0a, 0x0b, 
 	0x07, 0x08, 0x0a, 0x0b, 
 	0x0c, 0x0d, 0x10, 0x11,
 	0x0c, 0x0d, 0x10, 0x11,
 };
 };
 
 
-static hda_nid_t stac922x_pin_nids[10] = {
+static const hda_nid_t stac922x_pin_nids[10] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x15, 0x1b,
 	0x0f, 0x10, 0x11, 0x15, 0x1b,
 };
 };
 
 
-static hda_nid_t stac92hd73xx_pin_nids[13] = {
+static const hda_nid_t stac92hd73xx_pin_nids[13] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x12, 0x13,
 	0x0f, 0x10, 0x11, 0x12, 0x13,
 	0x14, 0x22, 0x23
 	0x14, 0x22, 0x23
 };
 };
 
 
 #define STAC92HD71BXX_NUM_PINS 13
 #define STAC92HD71BXX_NUM_PINS 13
-static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
+static const hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x00,
 	0x0a, 0x0b, 0x0c, 0x0d, 0x00,
 	0x00, 0x14, 0x18, 0x19, 0x1e,
 	0x00, 0x14, 0x18, 0x19, 0x1e,
 	0x1f, 0x20, 0x27
 	0x1f, 0x20, 0x27
 };
 };
-static hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = {
+static const hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x14, 0x18, 0x19, 0x1e,
 	0x0f, 0x14, 0x18, 0x19, 0x1e,
 	0x1f, 0x20, 0x27
 	0x1f, 0x20, 0x27
 };
 };
 
 
-static hda_nid_t stac927x_pin_nids[14] = {
+static const hda_nid_t stac927x_pin_nids[14] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x12, 0x13,
 	0x0f, 0x10, 0x11, 0x12, 0x13,
 	0x14, 0x21, 0x22, 0x23,
 	0x14, 0x21, 0x22, 0x23,
 };
 };
 
 
-static hda_nid_t stac9205_pin_nids[12] = {
+static const hda_nid_t stac9205_pin_nids[12] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x14, 0x16, 0x17, 0x18,
 	0x0f, 0x14, 0x16, 0x17, 0x18,
 	0x21, 0x22,
 	0x21, 0x22,
@@ -841,45 +845,45 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
 	return 1;
 	return 1;
 }
 }
 
 
-static struct hda_verb stac9200_core_init[] = {
+static const struct hda_verb stac9200_core_init[] = {
 	/* set dac0mux for dac converter */
 	/* set dac0mux for dac converter */
 	{ 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{ 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb stac9200_eapd_init[] = {
+static const struct hda_verb stac9200_eapd_init[] = {
 	/* set dac0mux for dac converter */
 	/* set dac0mux for dac converter */
 	{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
 	{0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb dell_eq_core_init[] = {
+static const struct hda_verb dell_eq_core_init[] = {
 	/* set master volume to max value without distortion
 	/* set master volume to max value without distortion
 	 * and direct control */
 	 * and direct control */
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb stac92hd73xx_core_init[] = {
+static const struct hda_verb stac92hd73xx_core_init[] = {
 	/* set master volume and direct control */
 	/* set master volume and direct control */
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb stac92hd83xxx_core_init[] = {
+static const struct hda_verb stac92hd83xxx_core_init[] = {
 	/* power state controls amps */
 	/* power state controls amps */
 	{ 0x01, AC_VERB_SET_EAPD, 1 << 2},
 	{ 0x01, AC_VERB_SET_EAPD, 1 << 2},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb stac92hd71bxx_core_init[] = {
+static const struct hda_verb stac92hd71bxx_core_init[] = {
 	/* set master volume and direct control */
 	/* set master volume and direct control */
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb stac92hd71bxx_unmute_core_init[] = {
+static const struct hda_verb stac92hd71bxx_unmute_core_init[] = {
 	/* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
 	/* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
 	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -887,7 +891,7 @@ static struct hda_verb stac92hd71bxx_unmute_core_init[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb stac925x_core_init[] = {
+static const struct hda_verb stac925x_core_init[] = {
 	/* set dac0mux for dac converter */
 	/* set dac0mux for dac converter */
 	{ 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{ 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
 	/* mute the master volume */
 	/* mute the master volume */
@@ -895,13 +899,13 @@ static struct hda_verb stac925x_core_init[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb stac922x_core_init[] = {
+static const struct hda_verb stac922x_core_init[] = {
 	/* set master volume and direct control */	
 	/* set master volume and direct control */	
 	{ 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{ 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb d965_core_init[] = {
+static const struct hda_verb d965_core_init[] = {
 	/* set master volume and direct control */	
 	/* set master volume and direct control */	
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* unmute node 0x1b */
 	/* unmute node 0x1b */
@@ -911,7 +915,7 @@ static struct hda_verb d965_core_init[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb dell_3st_core_init[] = {
+static const struct hda_verb dell_3st_core_init[] = {
 	/* don't set delta bit */
 	/* don't set delta bit */
 	{0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
 	{0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
 	/* unmute node 0x1b */
 	/* unmute node 0x1b */
@@ -921,7 +925,7 @@ static struct hda_verb dell_3st_core_init[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb stac927x_core_init[] = {
+static const struct hda_verb stac927x_core_init[] = {
 	/* set master volume and direct control */	
 	/* set master volume and direct control */	
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* enable analog pc beep path */
 	/* enable analog pc beep path */
@@ -929,7 +933,7 @@ static struct hda_verb stac927x_core_init[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb stac927x_volknob_core_init[] = {
+static const struct hda_verb stac927x_volknob_core_init[] = {
 	/* don't set delta bit */
 	/* don't set delta bit */
 	{0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
 	{0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
 	/* enable analog pc beep path */
 	/* enable analog pc beep path */
@@ -937,7 +941,7 @@ static struct hda_verb stac927x_volknob_core_init[] = {
 	{}
 	{}
 };
 };
 
 
-static struct hda_verb stac9205_core_init[] = {
+static const struct hda_verb stac9205_core_init[] = {
 	/* set master volume and direct control */	
 	/* set master volume and direct control */	
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	/* enable analog pc beep path */
 	/* enable analog pc beep path */
@@ -977,7 +981,7 @@ static struct hda_verb stac9205_core_init[] = {
 		.private_value = nid, \
 		.private_value = nid, \
 	}
 	}
 
 
-static struct snd_kcontrol_new stac9200_mixer[] = {
+static const struct snd_kcontrol_new stac9200_mixer[] = {
 	HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
@@ -985,38 +989,38 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = {
+static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = {
+static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
+static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
 	{}
 	{}
 };
 };
 
 
 
 
-static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
+static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
 };
 };
 
 
-static struct snd_kcontrol_new stac925x_mixer[] = {
+static const struct snd_kcontrol_new stac925x_mixer[] = {
 	HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new stac9205_loopback[] = {
+static const struct snd_kcontrol_new stac9205_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
 	STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
 	{}
 	{}
 };
 };
 
 
-static struct snd_kcontrol_new stac927x_loopback[] = {
+static const struct snd_kcontrol_new stac927x_loopback[] = {
 	STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
 	STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
 	{}
 	{}
 };
 };
@@ -1182,16 +1186,16 @@ static int stac92xx_build_controls(struct hda_codec *codec)
 	return 0;	
 	return 0;	
 }
 }
 
 
-static unsigned int ref9200_pin_configs[8] = {
+static const unsigned int ref9200_pin_configs[8] = {
 	0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
 	0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
 	0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
 	0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
 };
 };
 
 
-static unsigned int gateway9200_m4_pin_configs[8] = {
+static const unsigned int gateway9200_m4_pin_configs[8] = {
 	0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
 	0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
 	0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
 	0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
 };
 };
-static unsigned int gateway9200_m4_2_pin_configs[8] = {
+static const unsigned int gateway9200_m4_2_pin_configs[8] = {
 	0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
 	0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
 	0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
 	0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
 };
 };
@@ -1202,7 +1206,7 @@ static unsigned int gateway9200_m4_2_pin_configs[8] = {
     102801DE
     102801DE
     102801E8
     102801E8
 */
 */
-static unsigned int dell9200_d21_pin_configs[8] = {
+static const unsigned int dell9200_d21_pin_configs[8] = {
 	0x400001f0, 0x400001f1, 0x02214030, 0x01014010, 
 	0x400001f0, 0x400001f1, 0x02214030, 0x01014010, 
 	0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
 	0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
 };
 };
@@ -1212,7 +1216,7 @@ static unsigned int dell9200_d21_pin_configs[8] = {
     102801C0
     102801C0
     102801C1
     102801C1
 */
 */
-static unsigned int dell9200_d22_pin_configs[8] = {
+static const unsigned int dell9200_d22_pin_configs[8] = {
 	0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, 
 	0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, 
 	0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
 	0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
 };
 };
@@ -1226,7 +1230,7 @@ static unsigned int dell9200_d22_pin_configs[8] = {
     102801DA
     102801DA
     102801E3
     102801E3
 */
 */
-static unsigned int dell9200_d23_pin_configs[8] = {
+static const unsigned int dell9200_d23_pin_configs[8] = {
 	0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, 
 	0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, 
 	0x01813020, 0x01a19021, 0x90100140, 0x400001f2, 
 	0x01813020, 0x01a19021, 0x90100140, 0x400001f2, 
 };
 };
@@ -1237,7 +1241,7 @@ static unsigned int dell9200_d23_pin_configs[8] = {
     102801B5 (Dell Inspiron 630m)
     102801B5 (Dell Inspiron 630m)
     102801D8 (Dell Inspiron 640m)
     102801D8 (Dell Inspiron 640m)
 */
 */
-static unsigned int dell9200_m21_pin_configs[8] = {
+static const unsigned int dell9200_m21_pin_configs[8] = {
 	0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
 	0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
 	0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
 	0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
 };
 };
@@ -1250,7 +1254,7 @@ static unsigned int dell9200_m21_pin_configs[8] = {
     102801D4 
     102801D4 
     102801D6 
     102801D6 
 */
 */
-static unsigned int dell9200_m22_pin_configs[8] = {
+static const unsigned int dell9200_m22_pin_configs[8] = {
 	0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, 
 	0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, 
 	0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
 	0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
 };
 };
@@ -1260,7 +1264,7 @@ static unsigned int dell9200_m22_pin_configs[8] = {
     102801CE (Dell XPS M1710)
     102801CE (Dell XPS M1710)
     102801CF (Dell Precision M90)
     102801CF (Dell Precision M90)
 */
 */
-static unsigned int dell9200_m23_pin_configs[8] = {
+static const unsigned int dell9200_m23_pin_configs[8] = {
 	0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
 	0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
 	0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
 	0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
 };
 };
@@ -1272,7 +1276,7 @@ static unsigned int dell9200_m23_pin_configs[8] = {
     102801CB (Dell Latitude 120L)
     102801CB (Dell Latitude 120L)
     102801D3
     102801D3
 */
 */
-static unsigned int dell9200_m24_pin_configs[8] = {
+static const unsigned int dell9200_m24_pin_configs[8] = {
 	0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, 
 	0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, 
 	0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, 
 	0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, 
 };
 };
@@ -1283,7 +1287,7 @@ static unsigned int dell9200_m24_pin_configs[8] = {
     102801EE
     102801EE
     102801EF
     102801EF
 */
 */
-static unsigned int dell9200_m25_pin_configs[8] = {
+static const unsigned int dell9200_m25_pin_configs[8] = {
 	0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, 
 	0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, 
 	0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
 	0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
 };
 };
@@ -1293,7 +1297,7 @@ static unsigned int dell9200_m25_pin_configs[8] = {
     102801F5 (Dell Inspiron 1501)
     102801F5 (Dell Inspiron 1501)
     102801F6
     102801F6
 */
 */
-static unsigned int dell9200_m26_pin_configs[8] = {
+static const unsigned int dell9200_m26_pin_configs[8] = {
 	0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, 
 	0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, 
 	0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
 	0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
 };
 };
@@ -1302,18 +1306,18 @@ static unsigned int dell9200_m26_pin_configs[8] = {
     STAC 9200-32
     STAC 9200-32
     102801CD (Dell Inspiron E1705/9400)
     102801CD (Dell Inspiron E1705/9400)
 */
 */
-static unsigned int dell9200_m27_pin_configs[8] = {
+static const unsigned int dell9200_m27_pin_configs[8] = {
 	0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
 	0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
 	0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
 	0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
 };
 };
 
 
-static unsigned int oqo9200_pin_configs[8] = {
+static const unsigned int oqo9200_pin_configs[8] = {
 	0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
 	0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
 	0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
 	0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
 };
 };
 
 
 
 
-static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
+static const unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
 	[STAC_REF] = ref9200_pin_configs,
 	[STAC_REF] = ref9200_pin_configs,
 	[STAC_9200_OQO] = oqo9200_pin_configs,
 	[STAC_9200_OQO] = oqo9200_pin_configs,
 	[STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
 	[STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
@@ -1350,7 +1354,7 @@ static const char * const stac9200_models[STAC_9200_MODELS] = {
 	[STAC_9200_PANASONIC] = "panasonic",
 	[STAC_9200_PANASONIC] = "panasonic",
 };
 };
 
 
-static struct snd_pci_quirk stac9200_cfg_tbl[] = {
+static const struct snd_pci_quirk stac9200_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_REF),
 		      "DFI LanParty", STAC_REF),
@@ -1426,47 +1430,47 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static unsigned int ref925x_pin_configs[8] = {
+static const unsigned int ref925x_pin_configs[8] = {
 	0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
 	0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
 	0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
 	0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
 };
 };
 
 
-static unsigned int stac925xM1_pin_configs[8] = {
+static const unsigned int stac925xM1_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 };
 
 
-static unsigned int stac925xM1_2_pin_configs[8] = {
+static const unsigned int stac925xM1_2_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 };
 
 
-static unsigned int stac925xM2_pin_configs[8] = {
+static const unsigned int stac925xM2_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 };
 
 
-static unsigned int stac925xM2_2_pin_configs[8] = {
+static const unsigned int stac925xM2_2_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 };
 
 
-static unsigned int stac925xM3_pin_configs[8] = {
+static const unsigned int stac925xM3_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3,
 };
 };
 
 
-static unsigned int stac925xM5_pin_configs[8] = {
+static const unsigned int stac925xM5_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 };
 
 
-static unsigned int stac925xM6_pin_configs[8] = {
+static const unsigned int stac925xM6_pin_configs[8] = {
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x90330320,
 	0x40a000f0, 0x90100210, 0x400003f1, 0x90330320,
 };
 };
 
 
-static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
+static const unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
 	[STAC_REF] = ref925x_pin_configs,
 	[STAC_REF] = ref925x_pin_configs,
 	[STAC_M1] = stac925xM1_pin_configs,
 	[STAC_M1] = stac925xM1_pin_configs,
 	[STAC_M1_2] = stac925xM1_2_pin_configs,
 	[STAC_M1_2] = stac925xM1_2_pin_configs,
@@ -1489,7 +1493,7 @@ static const char * const stac925x_models[STAC_925x_MODELS] = {
 	[STAC_M6] = "m6",
 	[STAC_M6] = "m6",
 };
 };
 
 
-static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
+static const struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2),
 	SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2),
 	SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5),
 	SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5),
 	SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1),
 	SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1),
@@ -1503,7 +1507,7 @@ static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static struct snd_pci_quirk stac925x_cfg_tbl[] = {
+static const struct snd_pci_quirk stac925x_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
@@ -1515,33 +1519,33 @@ static struct snd_pci_quirk stac925x_cfg_tbl[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static unsigned int ref92hd73xx_pin_configs[13] = {
+static const unsigned int ref92hd73xx_pin_configs[13] = {
 	0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
 	0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
 	0x0181302e, 0x01014010, 0x01014020, 0x01014030,
 	0x0181302e, 0x01014010, 0x01014020, 0x01014030,
 	0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
 	0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
 	0x01452050,
 	0x01452050,
 };
 };
 
 
-static unsigned int dell_m6_pin_configs[13] = {
+static const unsigned int dell_m6_pin_configs[13] = {
 	0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
 	0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
 	0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
 	0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
 	0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
 	0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
 	0x4f0000f0,
 	0x4f0000f0,
 };
 };
 
 
-static unsigned int alienware_m17x_pin_configs[13] = {
+static const unsigned int alienware_m17x_pin_configs[13] = {
 	0x0321101f, 0x0321101f, 0x03a11020, 0x03014020,
 	0x0321101f, 0x0321101f, 0x03a11020, 0x03014020,
 	0x90170110, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0,
 	0x90170110, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0,
 	0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
 	0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
 	0x904601b0,
 	0x904601b0,
 };
 };
 
 
-static unsigned int intel_dg45id_pin_configs[13] = {
+static const unsigned int intel_dg45id_pin_configs[13] = {
 	0x02214230, 0x02A19240, 0x01013214, 0x01014210,
 	0x02214230, 0x02A19240, 0x01013214, 0x01014210,
 	0x01A19250, 0x01011212, 0x01016211
 	0x01A19250, 0x01011212, 0x01016211
 };
 };
 
 
-static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
+static const unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
 	[STAC_92HD73XX_REF]	= ref92hd73xx_pin_configs,
 	[STAC_92HD73XX_REF]	= ref92hd73xx_pin_configs,
 	[STAC_DELL_M6_AMIC]	= dell_m6_pin_configs,
 	[STAC_DELL_M6_AMIC]	= dell_m6_pin_configs,
 	[STAC_DELL_M6_DMIC]	= dell_m6_pin_configs,
 	[STAC_DELL_M6_DMIC]	= dell_m6_pin_configs,
@@ -1563,7 +1567,7 @@ static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
 	[STAC_ALIENWARE_M17X] = "alienware",
 	[STAC_ALIENWARE_M17X] = "alienware",
 };
 };
 
 
-static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
+static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 				"DFI LanParty", STAC_92HD73XX_REF),
 				"DFI LanParty", STAC_92HD73XX_REF),
@@ -1600,11 +1604,11 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe,
 				"Dell Studio XPS 1645", STAC_DELL_M6_BOTH),
 				"Dell Studio XPS 1645", STAC_DELL_M6_BOTH),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413,
-				"Dell Studio 1558", STAC_DELL_M6_BOTH),
+				"Dell Studio 1558", STAC_DELL_M6_DMIC),
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
+static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1,
 		      "Alienware M17x", STAC_ALIENWARE_M17X),
 		      "Alienware M17x", STAC_ALIENWARE_M17X),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
@@ -1612,25 +1616,25 @@ static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static unsigned int ref92hd83xxx_pin_configs[10] = {
+static const unsigned int ref92hd83xxx_pin_configs[10] = {
 	0x02214030, 0x02211010, 0x02a19020, 0x02170130,
 	0x02214030, 0x02211010, 0x02a19020, 0x02170130,
 	0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
 	0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
 	0x01451160, 0x98560170,
 	0x01451160, 0x98560170,
 };
 };
 
 
-static unsigned int dell_s14_pin_configs[10] = {
+static const unsigned int dell_s14_pin_configs[10] = {
 	0x0221403f, 0x0221101f, 0x02a19020, 0x90170110,
 	0x0221403f, 0x0221101f, 0x02a19020, 0x90170110,
 	0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a60160,
 	0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a60160,
 	0x40f000f0, 0x40f000f0,
 	0x40f000f0, 0x40f000f0,
 };
 };
 
 
-static unsigned int hp_dv7_4000_pin_configs[10] = {
+static const unsigned int hp_dv7_4000_pin_configs[10] = {
 	0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
 	0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
 	0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
 	0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
 	0x40f000f0, 0x40f000f0,
 	0x40f000f0, 0x40f000f0,
 };
 };
 
 
-static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
+static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
 	[STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
 	[STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
 	[STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
 	[STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
 	[STAC_DELL_S14] = dell_s14_pin_configs,
 	[STAC_DELL_S14] = dell_s14_pin_configs,
@@ -1646,7 +1650,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
 	[STAC_HP_DV7_4000] = "hp-dv7-4000",
 	[STAC_HP_DV7_4000] = "hp-dv7-4000",
 };
 };
 
 
-static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
+static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_92HD83XXX_REF),
 		      "DFI LanParty", STAC_92HD83XXX_REF),
@@ -1659,35 +1663,35 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = {
+static const unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = {
 	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
 	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
 	0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
 	0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
 	0x90a000f0, 0x01452050, 0x01452050, 0x00000000,
 	0x90a000f0, 0x01452050, 0x01452050, 0x00000000,
 	0x00000000
 	0x00000000
 };
 };
 
 
-static unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = {
+static const unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = {
 	0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
 	0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
 	0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
 	0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
 	0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000,
 	0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000,
 	0x00000000
 	0x00000000
 };
 };
 
 
-static unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = {
+static const unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = {
 	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
 	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
 	0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
 	0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
 	0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
 	0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
 	0x00000000
 	0x00000000
 };
 };
 
 
-static unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = {
+static const unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = {
 	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
 	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
 	0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0,
 	0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0,
 	0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
 	0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
 	0x00000000
 	0x00000000
 };
 };
 
 
-static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
+static const unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
 	[STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
 	[STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
 	[STAC_DELL_M4_1]	= dell_m4_1_pin_configs,
 	[STAC_DELL_M4_1]	= dell_m4_1_pin_configs,
 	[STAC_DELL_M4_2]	= dell_m4_2_pin_configs,
 	[STAC_DELL_M4_2]	= dell_m4_2_pin_configs,
@@ -1712,7 +1716,7 @@ static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
 	[STAC_HP_DV4_1222NR] = "hp-dv4-1222nr",
 	[STAC_HP_DV4_1222NR] = "hp-dv4-1222nr",
 };
 };
 
 
-static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
+static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_92HD71BXX_REF),
 		      "DFI LanParty", STAC_92HD71BXX_REF),
@@ -1769,7 +1773,7 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static unsigned int ref922x_pin_configs[10] = {
+static const unsigned int ref922x_pin_configs[10] = {
 	0x01014010, 0x01016011, 0x01012012, 0x0221401f,
 	0x01014010, 0x01016011, 0x01012012, 0x0221401f,
 	0x01813122, 0x01011014, 0x01441030, 0x01c41030,
 	0x01813122, 0x01011014, 0x01441030, 0x01c41030,
 	0x40000100, 0x40000100,
 	0x40000100, 0x40000100,
@@ -1783,7 +1787,7 @@ static unsigned int ref922x_pin_configs[10] = {
     102801D1
     102801D1
     102801D2
     102801D2
 */
 */
-static unsigned int dell_922x_d81_pin_configs[10] = {
+static const unsigned int dell_922x_d81_pin_configs[10] = {
 	0x02214030, 0x01a19021, 0x01111012, 0x01114010,
 	0x02214030, 0x01a19021, 0x01111012, 0x01114010,
 	0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
 	0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
 	0x01813122, 0x400001f2,
 	0x01813122, 0x400001f2,
@@ -1794,7 +1798,7 @@ static unsigned int dell_922x_d81_pin_configs[10] = {
     102801AC
     102801AC
     102801D0
     102801D0
 */
 */
-static unsigned int dell_922x_d82_pin_configs[10] = {
+static const unsigned int dell_922x_d82_pin_configs[10] = {
 	0x02214030, 0x01a19021, 0x01111012, 0x01114010,
 	0x02214030, 0x01a19021, 0x01111012, 0x01114010,
 	0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
 	0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
 	0x01813122, 0x400001f1,
 	0x01813122, 0x400001f1,
@@ -1804,7 +1808,7 @@ static unsigned int dell_922x_d82_pin_configs[10] = {
     STAC 922X pin configs for
     STAC 922X pin configs for
     102801BF
     102801BF
 */
 */
-static unsigned int dell_922x_m81_pin_configs[10] = {
+static const unsigned int dell_922x_m81_pin_configs[10] = {
 	0x0321101f, 0x01112024, 0x01111222, 0x91174220,
 	0x0321101f, 0x01112024, 0x01111222, 0x91174220,
 	0x03a11050, 0x01116221, 0x90a70330, 0x01452340, 
 	0x03a11050, 0x01116221, 0x90a70330, 0x01452340, 
 	0x40C003f1, 0x405003f0,
 	0x40C003f1, 0x405003f0,
@@ -1814,61 +1818,61 @@ static unsigned int dell_922x_m81_pin_configs[10] = {
     STAC 9221 A1 pin configs for
     STAC 9221 A1 pin configs for
     102801D7 (Dell XPS M1210)
     102801D7 (Dell XPS M1210)
 */
 */
-static unsigned int dell_922x_m82_pin_configs[10] = {
+static const unsigned int dell_922x_m82_pin_configs[10] = {
 	0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, 
 	0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, 
 	0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, 
 	0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, 
 	0x508003f3, 0x405003f4, 
 	0x508003f3, 0x405003f4, 
 };
 };
 
 
-static unsigned int d945gtp3_pin_configs[10] = {
+static const unsigned int d945gtp3_pin_configs[10] = {
 	0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
 	0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
 	0x40000100, 0x40000100, 0x40000100, 0x40000100,
 	0x40000100, 0x40000100, 0x40000100, 0x40000100,
 	0x02a19120, 0x40000100,
 	0x02a19120, 0x40000100,
 };
 };
 
 
-static unsigned int d945gtp5_pin_configs[10] = {
+static const unsigned int d945gtp5_pin_configs[10] = {
 	0x0221401f, 0x01011012, 0x01813024, 0x01014010,
 	0x0221401f, 0x01011012, 0x01813024, 0x01014010,
 	0x01a19021, 0x01016011, 0x01452130, 0x40000100,
 	0x01a19021, 0x01016011, 0x01452130, 0x40000100,
 	0x02a19320, 0x40000100,
 	0x02a19320, 0x40000100,
 };
 };
 
 
-static unsigned int intel_mac_v1_pin_configs[10] = {
+static const unsigned int intel_mac_v1_pin_configs[10] = {
 	0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
 	0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
 	0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
 	0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
 	0x400000fc, 0x400000fb,
 	0x400000fc, 0x400000fb,
 };
 };
 
 
-static unsigned int intel_mac_v2_pin_configs[10] = {
+static const unsigned int intel_mac_v2_pin_configs[10] = {
 	0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
 	0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
 	0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
 	0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
 	0x400000fc, 0x400000fb,
 	0x400000fc, 0x400000fb,
 };
 };
 
 
-static unsigned int intel_mac_v3_pin_configs[10] = {
+static const unsigned int intel_mac_v3_pin_configs[10] = {
 	0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
 	0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
 	0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
 	0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
 	0x400000fc, 0x400000fb,
 	0x400000fc, 0x400000fb,
 };
 };
 
 
-static unsigned int intel_mac_v4_pin_configs[10] = {
+static const unsigned int intel_mac_v4_pin_configs[10] = {
 	0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
 	0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
 	0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
 	0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
 	0x400000fc, 0x400000fb,
 	0x400000fc, 0x400000fb,
 };
 };
 
 
-static unsigned int intel_mac_v5_pin_configs[10] = {
+static const unsigned int intel_mac_v5_pin_configs[10] = {
 	0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
 	0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
 	0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
 	0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
 	0x400000fc, 0x400000fb,
 	0x400000fc, 0x400000fb,
 };
 };
 
 
-static unsigned int ecs202_pin_configs[10] = {
+static const unsigned int ecs202_pin_configs[10] = {
 	0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
 	0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
 	0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
 	0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
 	0x9037012e, 0x40e000f2,
 	0x9037012e, 0x40e000f2,
 };
 };
 
 
-static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
+static const unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
 	[STAC_D945_REF] = ref922x_pin_configs,
 	[STAC_D945_REF] = ref922x_pin_configs,
 	[STAC_D945GTP3] = d945gtp3_pin_configs,
 	[STAC_D945GTP3] = d945gtp3_pin_configs,
 	[STAC_D945GTP5] = d945gtp5_pin_configs,
 	[STAC_D945GTP5] = d945gtp5_pin_configs,
@@ -1917,7 +1921,7 @@ static const char * const stac922x_models[STAC_922X_MODELS] = {
 	[STAC_922X_DELL_M82] = "dell-m82",
 	[STAC_922X_DELL_M82] = "dell-m82",
 };
 };
 
 
-static struct snd_pci_quirk stac922x_cfg_tbl[] = {
+static const struct snd_pci_quirk stac922x_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_D945_REF),
 		      "DFI LanParty", STAC_D945_REF),
@@ -2008,42 +2012,42 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static unsigned int ref927x_pin_configs[14] = {
+static const unsigned int ref927x_pin_configs[14] = {
 	0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
 	0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
 	0x01a19040, 0x01011012, 0x01016011, 0x0101201f, 
 	0x01a19040, 0x01011012, 0x01016011, 0x0101201f, 
 	0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
 	0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
 	0x01c42190, 0x40000100,
 	0x01c42190, 0x40000100,
 };
 };
 
 
-static unsigned int d965_3st_pin_configs[14] = {
+static const unsigned int d965_3st_pin_configs[14] = {
 	0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
 	0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
 	0x01a19021, 0x01813024, 0x40000100, 0x40000100,
 	0x01a19021, 0x01813024, 0x40000100, 0x40000100,
 	0x40000100, 0x40000100, 0x40000100, 0x40000100,
 	0x40000100, 0x40000100, 0x40000100, 0x40000100,
 	0x40000100, 0x40000100
 	0x40000100, 0x40000100
 };
 };
 
 
-static unsigned int d965_5st_pin_configs[14] = {
+static const unsigned int d965_5st_pin_configs[14] = {
 	0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
 	0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
 	0x01a19040, 0x01011012, 0x01016011, 0x40000100,
 	0x01a19040, 0x01011012, 0x01016011, 0x40000100,
 	0x40000100, 0x40000100, 0x40000100, 0x01442070,
 	0x40000100, 0x40000100, 0x40000100, 0x01442070,
 	0x40000100, 0x40000100
 	0x40000100, 0x40000100
 };
 };
 
 
-static unsigned int d965_5st_no_fp_pin_configs[14] = {
+static const unsigned int d965_5st_no_fp_pin_configs[14] = {
 	0x40000100, 0x40000100, 0x0181304e, 0x01014010,
 	0x40000100, 0x40000100, 0x0181304e, 0x01014010,
 	0x01a19040, 0x01011012, 0x01016011, 0x40000100,
 	0x01a19040, 0x01011012, 0x01016011, 0x40000100,
 	0x40000100, 0x40000100, 0x40000100, 0x01442070,
 	0x40000100, 0x40000100, 0x40000100, 0x01442070,
 	0x40000100, 0x40000100
 	0x40000100, 0x40000100
 };
 };
 
 
-static unsigned int dell_3st_pin_configs[14] = {
+static const unsigned int dell_3st_pin_configs[14] = {
 	0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
 	0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
 	0x01111212, 0x01116211, 0x01813050, 0x01112214,
 	0x01111212, 0x01116211, 0x01813050, 0x01112214,
 	0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
 	0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
 	0x40c003fc, 0x40000100
 	0x40c003fc, 0x40000100
 };
 };
 
 
-static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
+static const unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
 	[STAC_D965_REF_NO_JD] = ref927x_pin_configs,
 	[STAC_D965_REF_NO_JD] = ref927x_pin_configs,
 	[STAC_D965_REF]  = ref927x_pin_configs,
 	[STAC_D965_REF]  = ref927x_pin_configs,
 	[STAC_D965_3ST]  = d965_3st_pin_configs,
 	[STAC_D965_3ST]  = d965_3st_pin_configs,
@@ -2066,7 +2070,7 @@ static const char * const stac927x_models[STAC_927X_MODELS] = {
 	[STAC_927X_VOLKNOB]	= "volknob",
 	[STAC_927X_VOLKNOB]	= "volknob",
 };
 };
 
 
-static struct snd_pci_quirk stac927x_cfg_tbl[] = {
+static const struct snd_pci_quirk stac927x_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_D965_REF),
 		      "DFI LanParty", STAC_D965_REF),
@@ -2104,7 +2108,7 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
-static unsigned int ref9205_pin_configs[12] = {
+static const unsigned int ref9205_pin_configs[12] = {
 	0x40000100, 0x40000100, 0x01016011, 0x01014010,
 	0x40000100, 0x40000100, 0x01016011, 0x01014010,
 	0x01813122, 0x01a19021, 0x01019020, 0x40000100,
 	0x01813122, 0x01a19021, 0x01019020, 0x40000100,
 	0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
 	0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
@@ -2121,7 +2125,7 @@ static unsigned int ref9205_pin_configs[12] = {
     10280228 (Dell Vostro 1500)
     10280228 (Dell Vostro 1500)
     10280229 (Dell Vostro 1700)
     10280229 (Dell Vostro 1700)
 */
 */
-static unsigned int dell_9205_m42_pin_configs[12] = {
+static const unsigned int dell_9205_m42_pin_configs[12] = {
 	0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
 	0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
 	0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
 	0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
 	0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
 	0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
@@ -2137,19 +2141,19 @@ static unsigned int dell_9205_m42_pin_configs[12] = {
     10280200
     10280200
     10280201
     10280201
 */
 */
-static unsigned int dell_9205_m43_pin_configs[12] = {
+static const unsigned int dell_9205_m43_pin_configs[12] = {
 	0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
 	0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
 	0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
 	0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
 	0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
 	0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
 };
 };
 
 
-static unsigned int dell_9205_m44_pin_configs[12] = {
+static const unsigned int dell_9205_m44_pin_configs[12] = {
 	0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
 	0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
 	0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
 	0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
 	0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
 	0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
 };
 };
 
 
-static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
+static const unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
 	[STAC_9205_REF] = ref9205_pin_configs,
 	[STAC_9205_REF] = ref9205_pin_configs,
 	[STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
 	[STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
 	[STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
 	[STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
@@ -2166,7 +2170,7 @@ static const char * const stac9205_models[STAC_9205_MODELS] = {
 	[STAC_9205_EAPD] = "eapd",
 	[STAC_9205_EAPD] = "eapd",
 };
 };
 
 
-static struct snd_pci_quirk stac9205_cfg_tbl[] = {
+static const struct snd_pci_quirk stac9205_cfg_tbl[] = {
 	/* SigmaTel reference board */
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_9205_REF),
 		      "DFI LanParty", STAC_9205_REF),
@@ -2214,7 +2218,7 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
 };
 };
 
 
 static void stac92xx_set_config_regs(struct hda_codec *codec,
 static void stac92xx_set_config_regs(struct hda_codec *codec,
-				     unsigned int *pincfgs)
+				     const unsigned int *pincfgs)
 {
 {
 	int i;
 	int i;
 	struct sigmatel_spec *spec = codec->spec;
 	struct sigmatel_spec *spec = codec->spec;
@@ -2334,7 +2338,7 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 	return 0;
 }
 }
 
 
-static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
+static const struct hda_pcm_stream stac92xx_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -2347,14 +2351,14 @@ static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
+static const struct hda_pcm_stream stac92xx_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
 	/* NID is set in stac92xx_build_pcms */
 	/* NID is set in stac92xx_build_pcms */
 };
 };
 
 
-static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
+static const struct hda_pcm_stream stac92xx_pcm_analog_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.channels_max = 8,
@@ -2366,7 +2370,7 @@ static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
+static const struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -2378,7 +2382,7 @@ static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
+static const struct hda_pcm_stream stac92xx_pcm_analog_capture = {
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
 	/* NID + .substreams is set in stac92xx_build_pcms */
 	/* NID + .substreams is set in stac92xx_build_pcms */
@@ -2487,7 +2491,7 @@ static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_info *uinfo)
 				struct snd_ctl_elem_info *uinfo)
 {
 {
 	int i;
 	int i;
-	static char *texts[] = {
+	static const char * const texts[] = {
 		"Mic In", "Line In", "Line Out"
 		"Mic In", "Line In", "Line Out"
 	};
 	};
 
 
@@ -2556,7 +2560,7 @@ static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
 static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol,
 static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_info *uinfo)
 				struct snd_ctl_elem_info *uinfo)
 {
 {
-	static char *texts[2];
+	char *texts[2];
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct sigmatel_spec *spec = codec->spec;
 	struct sigmatel_spec *spec = codec->spec;
 
 
@@ -2687,7 +2691,7 @@ enum {
 	STAC_CTL_WIDGET_DC_BIAS
 	STAC_CTL_WIDGET_DC_BIAS
 };
 };
 
 
-static struct snd_kcontrol_new stac92xx_control_templates[] = {
+static const struct snd_kcontrol_new stac92xx_control_templates[] = {
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0),
@@ -2701,7 +2705,7 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = {
 /* add dynamic controls */
 /* add dynamic controls */
 static struct snd_kcontrol_new *
 static struct snd_kcontrol_new *
 stac_control_new(struct sigmatel_spec *spec,
 stac_control_new(struct sigmatel_spec *spec,
-		 struct snd_kcontrol_new *ktemp,
+		 const struct snd_kcontrol_new *ktemp,
 		 const char *name,
 		 const char *name,
 		 unsigned int subdev)
 		 unsigned int subdev)
 {
 {
@@ -2724,7 +2728,7 @@ stac_control_new(struct sigmatel_spec *spec,
 }
 }
 
 
 static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
 static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
-				     struct snd_kcontrol_new *ktemp,
+				     const struct snd_kcontrol_new *ktemp,
 				     int idx, const char *name,
 				     int idx, const char *name,
 				     unsigned long val)
 				     unsigned long val)
 {
 {
@@ -2754,7 +2758,7 @@ static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
 	return stac92xx_add_control_idx(spec, type, 0, name, val);
 	return stac92xx_add_control_idx(spec, type, 0, name, val);
 }
 }
 
 
-static struct snd_kcontrol_new stac_input_src_temp = {
+static const struct snd_kcontrol_new stac_input_src_temp = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Input Source",
 	.name = "Input Source",
 	.info = stac92xx_mux_enum_info,
 	.info = stac92xx_mux_enum_info,
@@ -3072,7 +3076,8 @@ static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
 		printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
 		printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
 		return 1;
 		return 1;
 	} else {
 	} else {
-		spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
+		snd_BUG_ON(spec->multiout.dac_nids != spec->dac_nids);
+		spec->dac_nids[spec->multiout.num_dacs] = nid;
 		spec->multiout.num_dacs++;
 		spec->multiout.num_dacs++;
 	}
 	}
 	return 0;
 	return 0;
@@ -3109,8 +3114,7 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
 
 
 	for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) {
 	for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) {
 		if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
 		if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
-			wid_caps = get_wcaps(codec, pins[i]);
-			if (wid_caps & AC_WCAP_UNSOL_CAP)
+			if (is_jack_detectable(codec, pins[i]))
 				spec->hp_detect = 1;
 				spec->hp_detect = 1;
 		}
 		}
 		nid = dac_nids[i];
 		nid = dac_nids[i];
@@ -3309,7 +3313,7 @@ static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
 	return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]);
 	return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]);
 }
 }
 
 
-static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
+static const struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.info = stac92xx_dig_beep_switch_info,
 	.info = stac92xx_dig_beep_switch_info,
 	.get = stac92xx_dig_beep_switch_get,
 	.get = stac92xx_dig_beep_switch_get,
@@ -3516,14 +3520,18 @@ static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
 			 hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock)
 			 hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock)
 {
 {
 	unsigned int cfg;
 	unsigned int cfg;
+	unsigned int type;
 
 
 	if (!nid)
 	if (!nid)
 		return 0;
 		return 0;
 	cfg = snd_hda_codec_get_pincfg(codec, nid);
 	cfg = snd_hda_codec_get_pincfg(codec, nid);
+	type = get_defcfg_device(cfg);
 	switch (snd_hda_get_input_pin_attr(cfg)) {
 	switch (snd_hda_get_input_pin_attr(cfg)) {
 	case INPUT_PIN_ATTR_INT:
 	case INPUT_PIN_ATTR_INT:
 		if (*fixed)
 		if (*fixed)
 			return 1; /* already occupied */
 			return 1; /* already occupied */
+		if (type != AC_JACK_MIC_IN)
+			return 1; /* invalid type */
 		*fixed = nid;
 		*fixed = nid;
 		break;
 		break;
 	case INPUT_PIN_ATTR_UNUSED:
 	case INPUT_PIN_ATTR_UNUSED:
@@ -3531,11 +3539,15 @@ static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
 	case INPUT_PIN_ATTR_DOCK:
 	case INPUT_PIN_ATTR_DOCK:
 		if (*dock)
 		if (*dock)
 			return 1; /* already occupied */
 			return 1; /* already occupied */
+		if (type != AC_JACK_MIC_IN && type != AC_JACK_LINE_IN)
+			return 1; /* invalid type */
 		*dock = nid;
 		*dock = nid;
 		break;
 		break;
 	default:
 	default:
 		if (*ext)
 		if (*ext)
 			return 1; /* already occupied */
 			return 1; /* already occupied */
+		if (type != AC_JACK_MIC_IN)
+			return 1; /* invalid type */
 		*ext = nid;
 		*ext = nid;
 		break;
 		break;
 	}
 	}
@@ -3591,10 +3603,6 @@ static int stac_check_auto_mic(struct hda_codec *codec)
 	hda_nid_t fixed, ext, dock;
 	hda_nid_t fixed, ext, dock;
 	int i;
 	int i;
 
 
-	for (i = 0; i < cfg->num_inputs; i++) {
-		if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
-			return 0; /* must be exclusively mics */
-	}
 	fixed = ext = dock = 0;
 	fixed = ext = dock = 0;
 	for (i = 0; i < cfg->num_inputs; i++)
 	for (i = 0; i < cfg->num_inputs; i++)
 		if (check_mic_pin(codec, cfg->inputs[i].pin,
 		if (check_mic_pin(codec, cfg->inputs[i].pin,
@@ -3606,7 +3614,7 @@ static int stac_check_auto_mic(struct hda_codec *codec)
 			return 0;
 			return 0;
 	if (!fixed || (!ext && !dock))
 	if (!fixed || (!ext && !dock))
 		return 0; /* no input to switch */
 		return 0; /* no input to switch */
-	if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
+	if (!is_jack_detectable(codec, ext))
 		return 0; /* no unsol support */
 		return 0; /* no unsol support */
 	if (set_mic_route(codec, &spec->ext_mic, ext) ||
 	if (set_mic_route(codec, &spec->ext_mic, ext) ||
 	    set_mic_route(codec, &spec->int_mic, fixed) ||
 	    set_mic_route(codec, &spec->int_mic, fixed) ||
@@ -3921,13 +3929,11 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
 {
 {
 	struct sigmatel_spec *spec = codec->spec;
 	struct sigmatel_spec *spec = codec->spec;
 	hda_nid_t pin = cfg->hp_pins[0];
 	hda_nid_t pin = cfg->hp_pins[0];
-	unsigned int wid_caps;
 
 
 	if (! pin)
 	if (! pin)
 		return 0;
 		return 0;
 
 
-	wid_caps = get_wcaps(codec, pin);
-	if (wid_caps & AC_WCAP_UNSOL_CAP)
+	if (is_jack_detectable(codec, pin))
 		spec->hp_detect = 1;
 		spec->hp_detect = 1;
 
 
 	return 0;
 	return 0;
@@ -4138,7 +4144,7 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
 	struct sigmatel_event *event;
 	struct sigmatel_event *event;
 	int tag;
 	int tag;
 
 
-	if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
+	if (!is_jack_detectable(codec, nid))
 		return 0;
 		return 0;
 	event = stac_get_event(codec, nid);
 	event = stac_get_event(codec, nid);
 	if (event) {
 	if (event) {
@@ -4171,7 +4177,7 @@ static void stac92xx_power_down(struct hda_codec *codec)
 	struct sigmatel_spec *spec = codec->spec;
 	struct sigmatel_spec *spec = codec->spec;
 
 
 	/* power down inactive DACs */
 	/* power down inactive DACs */
-	hda_nid_t *dac;
+	const hda_nid_t *dac;
 	for (dac = spec->dac_list; *dac; dac++)
 	for (dac = spec->dac_list; *dac; dac++)
 		if (!check_all_dac_nids(spec, *dac))
 		if (!check_all_dac_nids(spec, *dac))
 			snd_hda_codec_write(codec, *dac, 0,
 			snd_hda_codec_write(codec, *dac, 0,
@@ -4644,7 +4650,7 @@ static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
 }
 }
 
 
 static int stac92xx_connected_ports(struct hda_codec *codec,
 static int stac92xx_connected_ports(struct hda_codec *codec,
-					 hda_nid_t *nids, int num_nids)
+				    const hda_nid_t *nids, int num_nids)
 {
 {
 	struct sigmatel_spec *spec = codec->spec;
 	struct sigmatel_spec *spec = codec->spec;
 	int idx, num;
 	int idx, num;
@@ -4968,7 +4974,7 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
 }
 }
 #endif
 #endif
 
 
-static struct hda_codec_ops stac92xx_patch_ops = {
+static const struct hda_codec_ops stac92xx_patch_ops = {
 	.build_controls = stac92xx_build_controls,
 	.build_controls = stac92xx_build_controls,
 	.build_pcms = stac92xx_build_pcms,
 	.build_pcms = stac92xx_build_pcms,
 	.init = stac92xx_init,
 	.init = stac92xx_init,
@@ -5588,7 +5594,7 @@ static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol,
 	return 1;
 	return 1;
 }
 }
 
 
-static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
+static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.info = stac_hp_bass_gpio_info,
 	.info = stac_hp_bass_gpio_info,
 	.get = stac_hp_bass_gpio_get,
 	.get = stac_hp_bass_gpio_get,
@@ -5612,7 +5618,7 @@ static int stac_add_hp_bass_switch(struct hda_codec *codec)
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
 {
 	struct sigmatel_spec *spec;
 	struct sigmatel_spec *spec;
-	struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
+	const struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
 	unsigned int pin_cfg;
 	unsigned int pin_cfg;
 	int err = 0;
 	int err = 0;
 
 
@@ -5705,9 +5711,9 @@ again:
 		unmute_init++;
 		unmute_init++;
 		snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
 		snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
 		snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
 		snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
-		stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
+		spec->dmic_nids = stac92hd71bxx_dmic_5port_nids;
 		spec->num_dmics = stac92xx_connected_ports(codec,
 		spec->num_dmics = stac92xx_connected_ports(codec,
-					stac92hd71bxx_dmic_nids,
+					stac92hd71bxx_dmic_5port_nids,
 					STAC92HD71BXX_NUM_DMICS - 1);
 					STAC92HD71BXX_NUM_DMICS - 1);
 		break;
 		break;
 	case 0x111d7603: /* 6 Port with Analog Mixer */
 	case 0x111d7603: /* 6 Port with Analog Mixer */
@@ -5729,15 +5735,6 @@ again:
 	if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
 	if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
 		snd_hda_sequence_write_cache(codec, unmute_init);
 		snd_hda_sequence_write_cache(codec, unmute_init);
 
 
-	/* Some HP machines seem to have unstable codec communications
-	 * especially with ATI fglrx driver.  For recovering from the
-	 * CORB/RIRB stall, allow the BUS reset and keep always sync
-	 */
-	if (spec->board_config == STAC_HP_DV5) {
-		codec->bus->sync_write = 1;
-		codec->bus->allow_bus_reset = 1;
-	}
-
 	spec->aloopback_ctl = stac92hd71bxx_loopback;
 	spec->aloopback_ctl = stac92hd71bxx_loopback;
 	spec->aloopback_mask = 0x50;
 	spec->aloopback_mask = 0x50;
 	spec->aloopback_shift = 0;
 	spec->aloopback_shift = 0;
@@ -6223,31 +6220,31 @@ static int patch_stac9205(struct hda_codec *codec)
  * STAC9872 hack
  * STAC9872 hack
  */
  */
 
 
-static struct hda_verb stac9872_core_init[] = {
+static const struct hda_verb stac9872_core_init[] = {
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
 	{}
 	{}
 };
 };
 
 
-static hda_nid_t stac9872_pin_nids[] = {
+static const hda_nid_t stac9872_pin_nids[] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
 	0x11, 0x13, 0x14,
 	0x11, 0x13, 0x14,
 };
 };
 
 
-static hda_nid_t stac9872_adc_nids[] = {
+static const hda_nid_t stac9872_adc_nids[] = {
 	0x8 /*,0x6*/
 	0x8 /*,0x6*/
 };
 };
 
 
-static hda_nid_t stac9872_mux_nids[] = {
+static const hda_nid_t stac9872_mux_nids[] = {
 	0x15
 	0x15
 };
 };
 
 
-static unsigned long stac9872_capvols[] = {
+static const unsigned long stac9872_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
 	HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
 };
 };
 #define stac9872_capsws		stac9872_capvols
 #define stac9872_capsws		stac9872_capvols
 
 
-static unsigned int stac9872_vaio_pin_configs[9] = {
+static const unsigned int stac9872_vaio_pin_configs[9] = {
 	0x03211020, 0x411111f0, 0x411111f0, 0x03a15030,
 	0x03211020, 0x411111f0, 0x411111f0, 0x03a15030,
 	0x411111f0, 0x90170110, 0x411111f0, 0x411111f0,
 	0x411111f0, 0x90170110, 0x411111f0, 0x411111f0,
 	0x90a7013e
 	0x90a7013e
@@ -6258,11 +6255,11 @@ static const char * const stac9872_models[STAC_9872_MODELS] = {
 	[STAC_9872_VAIO] = "vaio",
 	[STAC_9872_VAIO] = "vaio",
 };
 };
 
 
-static unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = {
+static const unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = {
 	[STAC_9872_VAIO] = stac9872_vaio_pin_configs,
 	[STAC_9872_VAIO] = stac9872_vaio_pin_configs,
 };
 };
 
 
-static struct snd_pci_quirk stac9872_cfg_tbl[] = {
+static const struct snd_pci_quirk stac9872_cfg_tbl[] = {
 	SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0,
 	SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0,
 			   "Sony VAIO F/S", STAC_9872_VAIO),
 			   "Sony VAIO F/S", STAC_9872_VAIO),
 	{} /* terminator */
 	{} /* terminator */
@@ -6316,7 +6313,7 @@ static int patch_stac9872(struct hda_codec *codec)
 /*
 /*
  * patch entries
  * patch entries
  */
  */
-static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
+static const struct hda_codec_preset snd_hda_preset_sigmatel[] = {
  	{ .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
  	{ .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
  	{ .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
  	{ .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
  	{ .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
  	{ .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },

+ 864 - 662
sound/pci/hda/patch_via.c

@@ -98,24 +98,30 @@ enum VIA_HDA_CODEC {
 	VT1716S,
 	VT1716S,
 	VT2002P,
 	VT2002P,
 	VT1812,
 	VT1812,
+	VT1802,
 	CODEC_TYPES,
 	CODEC_TYPES,
 };
 };
 
 
+#define VT2002P_COMPATIBLE(spec) \
+	((spec)->codec_type == VT2002P ||\
+	 (spec)->codec_type == VT1812 ||\
+	 (spec)->codec_type == VT1802)
+
 struct via_spec {
 struct via_spec {
 	/* codec parameterization */
 	/* codec parameterization */
-	struct snd_kcontrol_new *mixers[6];
+	const struct snd_kcontrol_new *mixers[6];
 	unsigned int num_mixers;
 	unsigned int num_mixers;
 
 
-	struct hda_verb *init_verbs[5];
+	const struct hda_verb *init_verbs[5];
 	unsigned int num_iverbs;
 	unsigned int num_iverbs;
 
 
 	char *stream_name_analog;
 	char *stream_name_analog;
-	struct hda_pcm_stream *stream_analog_playback;
-	struct hda_pcm_stream *stream_analog_capture;
+	const struct hda_pcm_stream *stream_analog_playback;
+	const struct hda_pcm_stream *stream_analog_capture;
 
 
 	char *stream_name_digital;
 	char *stream_name_digital;
-	struct hda_pcm_stream *stream_digital_playback;
-	struct hda_pcm_stream *stream_digital_capture;
+	const struct hda_pcm_stream *stream_digital_playback;
+	const struct hda_pcm_stream *stream_digital_capture;
 
 
 	/* playback */
 	/* playback */
 	struct hda_multi_out multiout;
 	struct hda_multi_out multiout;
@@ -123,7 +129,7 @@ struct via_spec {
 
 
 	/* capture */
 	/* capture */
 	unsigned int num_adc_nids;
 	unsigned int num_adc_nids;
-	hda_nid_t *adc_nids;
+	const hda_nid_t *adc_nids;
 	hda_nid_t mux_nids[3];
 	hda_nid_t mux_nids[3];
 	hda_nid_t dig_in_nid;
 	hda_nid_t dig_in_nid;
 	hda_nid_t dig_in_pin;
 	hda_nid_t dig_in_pin;
@@ -154,6 +160,9 @@ struct via_spec {
 	struct delayed_work vt1708_hp_work;
 	struct delayed_work vt1708_hp_work;
 	int vt1708_jack_detectect;
 	int vt1708_jack_detectect;
 	int vt1708_hp_present;
 	int vt1708_hp_present;
+
+	void (*set_widgets_power_state)(struct hda_codec *codec);
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	struct hda_loopback_check loopback;
 	struct hda_loopback_check loopback;
 #endif
 #endif
@@ -218,17 +227,19 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
 		codec_type = VT1812;
 		codec_type = VT1812;
 	else if (dev_id == 0x0440)
 	else if (dev_id == 0x0440)
 		codec_type = VT1708S;
 		codec_type = VT1708S;
+	else if ((dev_id & 0xfff) == 0x446)
+		codec_type = VT1802;
 	else
 	else
 		codec_type = UNKNOWN;
 		codec_type = UNKNOWN;
 	return codec_type;
 	return codec_type;
 };
 };
 
 
+#define VIA_JACK_EVENT		0x20
 #define VIA_HP_EVENT		0x01
 #define VIA_HP_EVENT		0x01
 #define VIA_GPIO_EVENT		0x02
 #define VIA_GPIO_EVENT		0x02
-#define VIA_JACK_EVENT		0x04
-#define VIA_MONO_EVENT		0x08
-#define VIA_SPEAKER_EVENT	0x10
-#define VIA_BIND_HP_EVENT	0x20
+#define VIA_MONO_EVENT		0x03
+#define VIA_SPEAKER_EVENT	0x04
+#define VIA_BIND_HP_EVENT	0x05
 
 
 enum {
 enum {
 	VIA_CTL_WIDGET_VOL,
 	VIA_CTL_WIDGET_VOL,
@@ -245,7 +256,6 @@ enum {
 };
 };
 
 
 static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
 static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
-static void set_jack_power_state(struct hda_codec *codec);
 static int is_aa_path_mute(struct hda_codec *codec);
 static int is_aa_path_mute(struct hda_codec *codec);
 
 
 static void vt1708_start_hp_work(struct via_spec *spec)
 static void vt1708_start_hp_work(struct via_spec *spec)
@@ -271,6 +281,12 @@ static void vt1708_stop_hp_work(struct via_spec *spec)
 	cancel_delayed_work_sync(&spec->vt1708_hp_work);
 	cancel_delayed_work_sync(&spec->vt1708_hp_work);
 }
 }
 
 
+static void set_widgets_power_state(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	if (spec->set_widgets_power_state)
+		spec->set_widgets_power_state(codec);
+}
 
 
 static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
 static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 				   struct snd_ctl_elem_value *ucontrol)
@@ -278,7 +294,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
 	int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
 	int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 
 
-	set_jack_power_state(codec);
+	set_widgets_power_state(codec);
 	analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
 	analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
 	if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
 	if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
 		if (is_aa_path_mute(codec))
 		if (is_aa_path_mute(codec))
@@ -394,54 +410,54 @@ static int bind_pin_switch_put(struct snd_kcontrol *kcontrol,
 			.put = bind_pin_switch_put,			\
 			.put = bind_pin_switch_put,			\
 			.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
 			.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
 
 
-static struct snd_kcontrol_new via_control_templates[] = {
+static const struct snd_kcontrol_new via_control_templates[] = {
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
 	ANALOG_INPUT_MUTE,
 	ANALOG_INPUT_MUTE,
 	BIND_PIN_MUTE,
 	BIND_PIN_MUTE,
 };
 };
 
 
-static hda_nid_t vt1708_adc_nids[2] = {
+static const hda_nid_t vt1708_adc_nids[2] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x15, 0x27
 	0x15, 0x27
 };
 };
 
 
-static hda_nid_t vt1709_adc_nids[3] = {
+static const hda_nid_t vt1709_adc_nids[3] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x14, 0x15, 0x16
 	0x14, 0x15, 0x16
 };
 };
 
 
-static hda_nid_t vt1708B_adc_nids[2] = {
+static const hda_nid_t vt1708B_adc_nids[2] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x13, 0x14
 	0x13, 0x14
 };
 };
 
 
-static hda_nid_t vt1708S_adc_nids[2] = {
+static const hda_nid_t vt1708S_adc_nids[2] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x13, 0x14
 	0x13, 0x14
 };
 };
 
 
-static hda_nid_t vt1702_adc_nids[3] = {
+static const hda_nid_t vt1702_adc_nids[3] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x12, 0x20, 0x1F
 	0x12, 0x20, 0x1F
 };
 };
 
 
-static hda_nid_t vt1718S_adc_nids[2] = {
+static const hda_nid_t vt1718S_adc_nids[2] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x10, 0x11
 	0x10, 0x11
 };
 };
 
 
-static hda_nid_t vt1716S_adc_nids[2] = {
+static const hda_nid_t vt1716S_adc_nids[2] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x13, 0x14
 	0x13, 0x14
 };
 };
 
 
-static hda_nid_t vt2002P_adc_nids[2] = {
+static const hda_nid_t vt2002P_adc_nids[2] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x10, 0x11
 	0x10, 0x11
 };
 };
 
 
-static hda_nid_t vt1812_adc_nids[2] = {
+static const hda_nid_t vt1812_adc_nids[2] = {
 	/* ADC1-2 */
 	/* ADC1-2 */
 	0x10, 0x11
 	0x10, 0x11
 };
 };
@@ -471,7 +487,7 @@ static int __via_add_control(struct via_spec *spec, int type, const char *name,
 	__via_add_control(spec, type, name, 0, val)
 	__via_add_control(spec, type, name, 0, val)
 
 
 static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
 static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
-						struct snd_kcontrol_new *tmpl)
+				const struct snd_kcontrol_new *tmpl)
 {
 {
 	struct snd_kcontrol_new *knew;
 	struct snd_kcontrol_new *knew;
 
 
@@ -602,482 +618,6 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
 }
 }
 
 
-static void set_jack_power_state(struct hda_codec *codec)
-{
-	struct via_spec *spec = codec->spec;
-	int imux_is_smixer;
-	unsigned int parm;
-
-	if (spec->codec_type == VT1702) {
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
-		/* inputs */
-		/* PW 1/2/5 (14h/15h/18h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x14, &parm);
-		set_pin_power_state(codec, 0x15, &parm);
-		set_pin_power_state(codec, 0x18, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
-		/* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
-		snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* outputs */
-		/* PW 3/4 (16h/17h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x16, &parm);
-		set_pin_power_state(codec, 0x17, &parm);
-		/* MW0 (1ah), AOW 0/1 (10h/1dh) */
-		snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
-				    imux_is_smixer ? AC_PWRST_D0 : parm);
-		snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-	} else if (spec->codec_type == VT1708B_8CH
-		   || spec->codec_type == VT1708B_4CH
-		   || spec->codec_type == VT1708S) {
-		/* SW0 (17h) = stereo mixer */
-		int is_8ch = spec->codec_type != VT1708B_4CH;
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
-			== ((spec->codec_type == VT1708S)  ? 5 : 0);
-		/* inputs */
-		/* PW 1/2/5 (1ah/1bh/1eh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x1a, &parm);
-		set_pin_power_state(codec, 0x1b, &parm);
-		set_pin_power_state(codec, 0x1e, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0;
-		/* SW0 (17h), AIW 0/1 (13h/14h) */
-		snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* outputs */
-		/* PW0 (19h), SW1 (18h), AOW1 (11h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x19, &parm);
-		if (spec->smart51_enabled)
-			parm = AC_PWRST_D0;
-		snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* PW6 (22h), SW2 (26h), AOW2 (24h) */
-		if (is_8ch) {
-			parm = AC_PWRST_D3;
-			set_pin_power_state(codec, 0x22, &parm);
-			if (spec->smart51_enabled)
-				parm = AC_PWRST_D0;
-			snd_hda_codec_write(codec, 0x26, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-			snd_hda_codec_write(codec, 0x24, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-		}
-
-		/* PW 3/4/7 (1ch/1dh/23h) */
-		parm = AC_PWRST_D3;
-		/* force to D0 for internal Speaker */
-		set_pin_power_state(codec, 0x1c, &parm);
-		set_pin_power_state(codec, 0x1d, &parm);
-		if (is_8ch)
-			set_pin_power_state(codec, 0x23, &parm);
-		/* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
-		snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
-				    imux_is_smixer ? AC_PWRST_D0 : parm);
-		snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		if (is_8ch) {
-			snd_hda_codec_write(codec, 0x25, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-			snd_hda_codec_write(codec, 0x27, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-		}
-	}  else if (spec->codec_type == VT1718S) {
-		/* MUX6 (1eh) = stereo mixer */
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
-		/* inputs */
-		/* PW 5/6/7 (29h/2ah/2bh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x29, &parm);
-		set_pin_power_state(codec, 0x2a, &parm);
-		set_pin_power_state(codec, 0x2b, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0;
-		/* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
-		snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* outputs */
-		/* PW3 (27h), MW2 (1ah), AOW3 (bh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x27, &parm);
-		snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* PW2 (26h), AOW2 (ah) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x26, &parm);
-		snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* PW0/1 (24h/25h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x24, &parm);
-		set_pin_power_state(codec, 0x25, &parm);
-		if (!spec->hp_independent_mode) /* check for redirected HP */
-			set_pin_power_state(codec, 0x28, &parm);
-		snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		/* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
-		snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
-				    imux_is_smixer ? AC_PWRST_D0 : parm);
-		if (spec->hp_independent_mode) {
-			/* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
-			parm = AC_PWRST_D3;
-			set_pin_power_state(codec, 0x28, &parm);
-			snd_hda_codec_write(codec, 0x1b, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-			snd_hda_codec_write(codec, 0x34, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-			snd_hda_codec_write(codec, 0xc, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-		}
-	} else if (spec->codec_type == VT1716S) {
-		unsigned int mono_out, present;
-		/* SW0 (17h) = stereo mixer */
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) ==  5;
-		/* inputs */
-		/* PW 1/2/5 (1ah/1bh/1eh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x1a, &parm);
-		set_pin_power_state(codec, 0x1b, &parm);
-		set_pin_power_state(codec, 0x1e, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0;
-		/* SW0 (17h), AIW0(13h) */
-		snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x1e, &parm);
-		/* PW11 (22h) */
-		if (spec->dmic_enabled)
-			set_pin_power_state(codec, 0x22, &parm);
-		else
-			snd_hda_codec_write(
-				codec, 0x22, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-
-		/* SW2(26h), AIW1(14h) */
-		snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* outputs */
-		/* PW0 (19h), SW1 (18h), AOW1 (11h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x19, &parm);
-		/* Smart 5.1 PW2(1bh) */
-		if (spec->smart51_enabled)
-			set_pin_power_state(codec, 0x1b, &parm);
-		snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* PW7 (23h), SW3 (27h), AOW3 (25h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x23, &parm);
-		/* Smart 5.1 PW1(1ah) */
-		if (spec->smart51_enabled)
-			set_pin_power_state(codec, 0x1a, &parm);
-		snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* Smart 5.1 PW5(1eh) */
-		if (spec->smart51_enabled)
-			set_pin_power_state(codec, 0x1e, &parm);
-		snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* Mono out */
-		/* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
-		present = snd_hda_jack_detect(codec, 0x1c);
-		if (present)
-			mono_out = 0;
-		else {
-			present = snd_hda_jack_detect(codec, 0x1d);
-			if (!spec->hp_independent_mode && present)
-				mono_out = 0;
-			else
-				mono_out = 1;
-		}
-		parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
-		snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-		snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE,
-				    parm);
-
-		/* PW 3/4 (1ch/1dh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x1c, &parm);
-		set_pin_power_state(codec, 0x1d, &parm);
-		/* HP Independent Mode, power on AOW3 */
-		if (spec->hp_independent_mode)
-			snd_hda_codec_write(codec, 0x25, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-
-		/* force to D0 for internal Speaker */
-		/* MW0 (16h), AOW0 (10h) */
-		snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
-				    imux_is_smixer ? AC_PWRST_D0 : parm);
-		snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
-				    mono_out ? AC_PWRST_D0 : parm);
-	} else if (spec->codec_type == VT2002P) {
-		unsigned int present;
-		/* MUX9 (1eh) = stereo mixer */
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
-		/* inputs */
-		/* PW 5/6/7 (29h/2ah/2bh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x29, &parm);
-		set_pin_power_state(codec, 0x2a, &parm);
-		set_pin_power_state(codec, 0x2b, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0;
-		/* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
-		snd_hda_codec_write(codec, 0x1e, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x1f, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x10, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x11, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-
-		/* outputs */
-		/* AOW0 (8h)*/
-		snd_hda_codec_write(codec, 0x8, 0,
-				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-
-		/* PW4 (26h), MW4 (1ch), MUX4(37h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x26, &parm);
-		snd_hda_codec_write(codec, 0x1c, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x37,
-				    0, AC_VERB_SET_POWER_STATE, parm);
-
-		/* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x25, &parm);
-		snd_hda_codec_write(codec, 0x19, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x35, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		if (spec->hp_independent_mode)	{
-			snd_hda_codec_write(codec, 0x9, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-		}
-
-		/* Class-D */
-		/* PW0 (24h), MW0(18h), MUX0(34h) */
-		present = snd_hda_jack_detect(codec, 0x25);
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x24, &parm);
-		if (present) {
-			snd_hda_codec_write(
-				codec, 0x18, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-			snd_hda_codec_write(
-				codec, 0x34, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-		} else {
-			snd_hda_codec_write(
-				codec, 0x18, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-			snd_hda_codec_write(
-				codec, 0x34, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-		}
-
-		/* Mono Out */
-		/* PW15 (31h), MW8(17h), MUX8(3bh) */
-		present = snd_hda_jack_detect(codec, 0x26);
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x31, &parm);
-		if (present) {
-			snd_hda_codec_write(
-				codec, 0x17, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-			snd_hda_codec_write(
-				codec, 0x3b, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-		} else {
-			snd_hda_codec_write(
-				codec, 0x17, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-			snd_hda_codec_write(
-				codec, 0x3b, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-		}
-
-		/* MW9 (21h) */
-		if (imux_is_smixer || !is_aa_path_mute(codec))
-			snd_hda_codec_write(
-				codec, 0x21, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-		else
-			snd_hda_codec_write(
-				codec, 0x21, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-	} else if (spec->codec_type == VT1812) {
-		unsigned int present;
-		/* MUX10 (1eh) = stereo mixer */
-		imux_is_smixer = snd_hda_codec_read(
-			codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
-		/* inputs */
-		/* PW 5/6/7 (29h/2ah/2bh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x29, &parm);
-		set_pin_power_state(codec, 0x2a, &parm);
-		set_pin_power_state(codec, 0x2b, &parm);
-		if (imux_is_smixer)
-			parm = AC_PWRST_D0;
-		/* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
-		snd_hda_codec_write(codec, 0x1e, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x1f, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x10, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x11, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-
-		/* outputs */
-		/* AOW0 (8h)*/
-		snd_hda_codec_write(codec, 0x8, 0,
-				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-
-		/* PW4 (28h), MW4 (18h), MUX4(38h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x28, &parm);
-		snd_hda_codec_write(codec, 0x18, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x38, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-
-		/* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x25, &parm);
-		snd_hda_codec_write(codec, 0x15, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x35, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		if (spec->hp_independent_mode)	{
-			snd_hda_codec_write(codec, 0x9, 0,
-					    AC_VERB_SET_POWER_STATE, parm);
-		}
-
-		/* Internal Speaker */
-		/* PW0 (24h), MW0(14h), MUX0(34h) */
-		present = snd_hda_jack_detect(codec, 0x25);
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x24, &parm);
-		if (present) {
-			snd_hda_codec_write(codec, 0x14, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-			snd_hda_codec_write(codec, 0x34, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-		} else {
-			snd_hda_codec_write(codec, 0x14, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D0);
-			snd_hda_codec_write(codec, 0x34, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D0);
-		}
-		/* Mono Out */
-		/* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
-		present = snd_hda_jack_detect(codec, 0x28);
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x31, &parm);
-		if (present) {
-			snd_hda_codec_write(codec, 0x1c, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-			snd_hda_codec_write(codec, 0x3c, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-			snd_hda_codec_write(codec, 0x3e, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D3);
-		} else {
-			snd_hda_codec_write(codec, 0x1c, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D0);
-			snd_hda_codec_write(codec, 0x3c, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D0);
-			snd_hda_codec_write(codec, 0x3e, 0,
-					    AC_VERB_SET_POWER_STATE,
-					    AC_PWRST_D0);
-		}
-
-		/* PW15 (33h), MW15 (1dh), MUX15(3dh) */
-		parm = AC_PWRST_D3;
-		set_pin_power_state(codec, 0x33, &parm);
-		snd_hda_codec_write(codec, 0x1d, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-		snd_hda_codec_write(codec, 0x3d, 0,
-				    AC_VERB_SET_POWER_STATE, parm);
-
-		/* MW9 (21h) */
-		if (imux_is_smixer || !is_aa_path_mute(codec))
-			snd_hda_codec_write(
-				codec, 0x21, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-		else
-			snd_hda_codec_write(
-				codec, 0x21, 0,
-				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-	}
-}
-
 /*
 /*
  * input MUX handling
  * input MUX handling
  */
  */
@@ -1120,7 +660,7 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
 				     spec->mux_nids[adc_idx],
 				     spec->mux_nids[adc_idx],
 				     &spec->cur_mux[adc_idx]);
 				     &spec->cur_mux[adc_idx]);
 	/* update jack power state */
 	/* update jack power state */
-	set_jack_power_state(codec);
+	set_widgets_power_state(codec);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -1168,6 +708,9 @@ static hda_nid_t side_mute_channel(struct via_spec *spec)
 	case VT1709_10CH:	return 0x29;
 	case VT1709_10CH:	return 0x29;
 	case VT1708B_8CH:	/* fall thru */
 	case VT1708B_8CH:	/* fall thru */
 	case VT1708S:		return 0x27;
 	case VT1708S:		return 0x27;
+	case VT2002P:		return 0x19;
+	case VT1802:		return 0x15;
+	case VT1812:		return 0x15;
 	default:		return 0;
 	default:		return 0;
 	}
 	}
 }
 }
@@ -1176,13 +719,22 @@ static int update_side_mute_status(struct hda_codec *codec)
 {
 {
 	/* mute side channel */
 	/* mute side channel */
 	struct via_spec *spec = codec->spec;
 	struct via_spec *spec = codec->spec;
-	unsigned int parm = spec->hp_independent_mode
-		? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
+	unsigned int parm;
 	hda_nid_t sw3 = side_mute_channel(spec);
 	hda_nid_t sw3 = side_mute_channel(spec);
 
 
-	if (sw3)
-		snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-				    parm);
+	if (sw3) {
+		if (VT2002P_COMPATIBLE(spec))
+			parm = spec->hp_independent_mode ?
+			       AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
+		else
+			parm = spec->hp_independent_mode ?
+			       AMP_OUT_MUTE : AMP_OUT_UNMUTE;
+		snd_hda_codec_write(codec, sw3, 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE, parm);
+		if (spec->codec_type == VT1812)
+			snd_hda_codec_write(codec, 0x1d, 0,
+					    AC_VERB_SET_AMP_GAIN_MUTE, parm);
+	}
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1217,19 +769,18 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
 	    || spec->codec_type == VT1702
 	    || spec->codec_type == VT1702
 	    || spec->codec_type == VT1718S
 	    || spec->codec_type == VT1718S
 	    || spec->codec_type == VT1716S
 	    || spec->codec_type == VT1716S
-	    || spec->codec_type == VT2002P
-	    || spec->codec_type == VT1812) {
+	    || VT2002P_COMPATIBLE(spec)) {
 		activate_ctl(codec, "Headphone Playback Volume",
 		activate_ctl(codec, "Headphone Playback Volume",
 			     spec->hp_independent_mode);
 			     spec->hp_independent_mode);
 		activate_ctl(codec, "Headphone Playback Switch",
 		activate_ctl(codec, "Headphone Playback Switch",
 			     spec->hp_independent_mode);
 			     spec->hp_independent_mode);
 	}
 	}
 	/* update jack power state */
 	/* update jack power state */
-	set_jack_power_state(codec);
+	set_widgets_power_state(codec);
 	return 0;
 	return 0;
 }
 }
 
 
-static struct snd_kcontrol_new via_hp_mixer[2] = {
+static const struct snd_kcontrol_new via_hp_mixer[2] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Independent HP",
 		.name = "Independent HP",
@@ -1256,6 +807,7 @@ static int via_hp_build(struct hda_codec *codec)
 		nid = 0x34;
 		nid = 0x34;
 		break;
 		break;
 	case VT2002P:
 	case VT2002P:
+	case VT1802:
 		nid = 0x35;
 		nid = 0x35;
 		break;
 		break;
 	case VT1812:
 	case VT1812:
@@ -1447,11 +999,11 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
 		}
 		}
 	}
 	}
 	spec->smart51_enabled = *ucontrol->value.integer.value;
 	spec->smart51_enabled = *ucontrol->value.integer.value;
-	set_jack_power_state(codec);
+	set_widgets_power_state(codec);
 	return 1;
 	return 1;
 }
 }
 
 
-static struct snd_kcontrol_new via_smart51_mixer[2] = {
+static const struct snd_kcontrol_new via_smart51_mixer[2] = {
 	{
 	{
 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	 .name = "Smart 5.1",
 	 .name = "Smart 5.1",
@@ -1473,6 +1025,11 @@ static int via_smart51_build(struct via_spec *spec)
 	hda_nid_t nid;
 	hda_nid_t nid;
 	int i;
 	int i;
 
 
+	if (!cfg)
+		return 0;
+	if (cfg->line_outs > 2)
+		return 0;
+
 	knew = via_clone_control(spec, &via_smart51_mixer[0]);
 	knew = via_clone_control(spec, &via_smart51_mixer[0]);
 	if (knew == NULL)
 	if (knew == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
@@ -1492,7 +1049,7 @@ static int via_smart51_build(struct via_spec *spec)
 }
 }
 
 
 /* capture mixer elements */
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1708_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1708_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
@@ -1543,6 +1100,7 @@ static int is_aa_path_mute(struct hda_codec *codec)
 		break;
 		break;
 	case VT2002P:
 	case VT2002P:
 	case VT1812:
 	case VT1812:
+	case VT1802:
 		nid_mixer = 0x21;
 		nid_mixer = 0x21;
 		start_idx = 0;
 		start_idx = 0;
 		end_idx = 2;
 		end_idx = 2;
@@ -1607,6 +1165,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
 		break;
 		break;
 	case VT2002P:
 	case VT2002P:
 	case VT1812:
 	case VT1812:
+	case VT1802:
 		verb = 0xf93;
 		verb = 0xf93;
 		parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
 		parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
 		break;
 		break;
@@ -1620,7 +1179,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb vt1708_volume_init_verbs[] = {
+static const struct hda_verb vt1708_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
 	 */
@@ -1650,6 +1209,8 @@ static struct hda_verb vt1708_volume_init_verbs[] = {
 	{0x20, AC_VERB_SET_CONNECT_SEL, 0},
 	{0x20, AC_VERB_SET_CONNECT_SEL, 0},
 	/* PW9 Output enable */
 	/* PW9 Output enable */
 	{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
 	{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* power down jack detect function */
+	{0x1, 0xf81, 0x1},
 	{ }
 	{ }
 };
 };
 
 
@@ -1672,7 +1233,7 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec,
 {
 {
 	struct via_spec *spec = codec->spec;
 	struct via_spec *spec = codec->spec;
 	struct hda_multi_out *mout = &spec->multiout;
 	struct hda_multi_out *mout = &spec->multiout;
-	hda_nid_t *nids = mout->dac_nids;
+	const hda_nid_t *nids = mout->dac_nids;
 	int chs = substream->runtime->channels;
 	int chs = substream->runtime->channels;
 	int i;
 	int i;
 
 
@@ -1741,7 +1302,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
 {
 {
 	struct via_spec *spec = codec->spec;
 	struct via_spec *spec = codec->spec;
 	struct hda_multi_out *mout = &spec->multiout;
 	struct hda_multi_out *mout = &spec->multiout;
-	hda_nid_t *nids = mout->dac_nids;
+	const hda_nid_t *nids = mout->dac_nids;
 
 
 	if (substream->number == 0)
 	if (substream->number == 0)
 		playback_multi_pcm_prep_0(codec, stream_tag, format,
 		playback_multi_pcm_prep_0(codec, stream_tag, format,
@@ -1762,7 +1323,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
 {
 {
 	struct via_spec *spec = codec->spec;
 	struct via_spec *spec = codec->spec;
 	struct hda_multi_out *mout = &spec->multiout;
 	struct hda_multi_out *mout = &spec->multiout;
-	hda_nid_t *nids = mout->dac_nids;
+	const hda_nid_t *nids = mout->dac_nids;
 	int i;
 	int i;
 
 
 	if (substream->number == 0) {
 	if (substream->number == 0) {
@@ -1860,7 +1421,7 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 	return 0;
 	return 0;
 }
 }
 
 
-static struct hda_pcm_stream vt1708_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1708_pcm_analog_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.channels_max = 8,
@@ -1872,7 +1433,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
+static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.channels_max = 8,
@@ -1889,7 +1450,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1708_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1708_pcm_analog_capture = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -1900,7 +1461,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1708_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1708_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -1913,7 +1474,7 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1708_pcm_digital_capture = {
+static const struct hda_pcm_stream vt1708_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -1923,7 +1484,7 @@ static int via_build_controls(struct hda_codec *codec)
 {
 {
 	struct via_spec *spec = codec->spec;
 	struct via_spec *spec = codec->spec;
 	struct snd_kcontrol *kctl;
 	struct snd_kcontrol *kctl;
-	struct snd_kcontrol_new *knew;
+	const struct snd_kcontrol_new *knew;
 	int err, i;
 	int err, i;
 
 
 	for (i = 0; i < spec->num_mixers; i++) {
 	for (i = 0; i < spec->num_mixers; i++) {
@@ -1971,7 +1532,7 @@ static int via_build_controls(struct hda_codec *codec)
 	}
 	}
 
 
 	/* init power states */
 	/* init power states */
-	set_jack_power_state(codec);
+	set_widgets_power_state(codec);
 	analog_low_current_mode(codec, 1);
 	analog_low_current_mode(codec, 1);
 
 
 	via_free_kctls(codec); /* no longer needed */
 	via_free_kctls(codec); /* no longer needed */
@@ -2135,7 +1696,7 @@ static void via_speaker_automute(struct hda_codec *codec)
 	unsigned int hp_present;
 	unsigned int hp_present;
 	struct via_spec *spec = codec->spec;
 	struct via_spec *spec = codec->spec;
 
 
-	if (spec->codec_type != VT2002P && spec->codec_type != VT1812)
+	if (!VT2002P_COMPATIBLE(spec))
 		return;
 		return;
 
 
 	hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
 	hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
@@ -2194,17 +1755,21 @@ static void via_unsol_event(struct hda_codec *codec,
 				  unsigned int res)
 				  unsigned int res)
 {
 {
 	res >>= 26;
 	res >>= 26;
-	if (res & VIA_HP_EVENT)
+
+	if (res & VIA_JACK_EVENT)
+		set_widgets_power_state(codec);
+
+	res &= ~VIA_JACK_EVENT;
+
+	if (res == VIA_HP_EVENT)
 		via_hp_automute(codec);
 		via_hp_automute(codec);
-	if (res & VIA_GPIO_EVENT)
+	else if (res == VIA_GPIO_EVENT)
 		via_gpio_control(codec);
 		via_gpio_control(codec);
-	if (res & VIA_JACK_EVENT)
-		set_jack_power_state(codec);
-	if (res & VIA_MONO_EVENT)
+	else if (res == VIA_MONO_EVENT)
 		via_mono_automute(codec);
 		via_mono_automute(codec);
-	if (res & VIA_SPEAKER_EVENT)
+	else if (res == VIA_SPEAKER_EVENT)
 		via_speaker_automute(codec);
 		via_speaker_automute(codec);
-	if (res & VIA_BIND_HP_EVENT)
+	else if (res == VIA_BIND_HP_EVENT)
 		via_hp_bind_automute(codec);
 		via_hp_bind_automute(codec);
 }
 }
 
 
@@ -2254,7 +1819,7 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 
 
 /*
 /*
  */
  */
-static struct hda_codec_ops via_patch_ops = {
+static const struct hda_codec_ops via_patch_ops = {
 	.build_controls = via_build_controls,
 	.build_controls = via_build_controls,
 	.build_pcms = via_build_pcms,
 	.build_pcms = via_build_pcms,
 	.init = via_init,
 	.init = via_init,
@@ -2284,16 +1849,16 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
 			/* config dac list */
 			/* config dac list */
 			switch (i) {
 			switch (i) {
 			case AUTO_SEQ_FRONT:
 			case AUTO_SEQ_FRONT:
-				spec->multiout.dac_nids[i] = 0x10;
+				spec->private_dac_nids[i] = 0x10;
 				break;
 				break;
 			case AUTO_SEQ_CENLFE:
 			case AUTO_SEQ_CENLFE:
-				spec->multiout.dac_nids[i] = 0x12;
+				spec->private_dac_nids[i] = 0x12;
 				break;
 				break;
 			case AUTO_SEQ_SURROUND:
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x11;
+				spec->private_dac_nids[i] = 0x11;
 				break;
 				break;
 			case AUTO_SEQ_SIDE:
 			case AUTO_SEQ_SIDE:
-				spec->multiout.dac_nids[i] = 0x13;
+				spec->private_dac_nids[i] = 0x13;
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -2437,7 +2002,8 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
 static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
 					    const struct auto_pin_cfg *cfg,
 					    const struct auto_pin_cfg *cfg,
 					    hda_nid_t cap_nid,
 					    hda_nid_t cap_nid,
-					    hda_nid_t pin_idxs[], int num_idxs)
+					    const hda_nid_t pin_idxs[],
+					    int num_idxs)
 {
 {
 	struct via_spec *spec = codec->spec;
 	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
 	struct hda_input_mux *imux = &spec->private_imux[0];
@@ -2483,13 +2049,13 @@ static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
 static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
 static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 						const struct auto_pin_cfg *cfg)
 {
 {
-	static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
+	static const hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 						ARRAY_SIZE(pin_idxs));
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1708_loopbacks[] = {
+static const struct hda_amp_list vt1708_loopbacks[] = {
 	{ 0x17, HDA_INPUT, 1 },
 	{ 0x17, HDA_INPUT, 1 },
 	{ 0x17, HDA_INPUT, 2 },
 	{ 0x17, HDA_INPUT, 2 },
 	{ 0x17, HDA_INPUT, 3 },
 	{ 0x17, HDA_INPUT, 3 },
@@ -2548,7 +2114,7 @@ static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
 	return change;
 	return change;
 }
 }
 
 
-static struct snd_kcontrol_new vt1708_jack_detectect[] = {
+static const struct snd_kcontrol_new vt1708_jack_detectect[] = {
 	{
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Jack Detect",
 		.name = "Jack Detect",
@@ -2623,7 +2189,8 @@ static int via_auto_init(struct hda_codec *codec)
 	via_auto_init_multi_out(codec);
 	via_auto_init_multi_out(codec);
 	via_auto_init_hp_out(codec);
 	via_auto_init_hp_out(codec);
 	via_auto_init_analog_input(codec);
 	via_auto_init_analog_input(codec);
-	if (spec->codec_type == VT2002P || spec->codec_type == VT1812) {
+
+	if (VT2002P_COMPATIBLE(spec)) {
 		via_hp_bind_automute(codec);
 		via_hp_bind_automute(codec);
 	} else {
 	} else {
 		via_hp_automute(codec);
 		via_hp_automute(codec);
@@ -2727,7 +2294,7 @@ static int patch_vt1708(struct hda_codec *codec)
 }
 }
 
 
 /* capture mixer elements */
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1709_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1709_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
@@ -2749,7 +2316,7 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb vt1709_uniwill_init_verbs[] = {
+static const struct hda_verb vt1709_uniwill_init_verbs[] = {
 	{0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
 	{0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{ }
 	{ }
@@ -2758,7 +2325,7 @@ static struct hda_verb vt1709_uniwill_init_verbs[] = {
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
+static const struct hda_verb vt1709_10ch_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
 	 */
@@ -2798,7 +2365,7 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 10,
 	.channels_max = 10,
@@ -2810,7 +2377,7 @@ static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 6,
 	.channels_max = 6,
@@ -2822,7 +2389,7 @@ static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1709_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1709_pcm_analog_capture = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -2833,7 +2400,7 @@ static struct hda_pcm_stream vt1709_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1709_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1709_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -2844,7 +2411,7 @@ static struct hda_pcm_stream vt1709_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1709_pcm_digital_capture = {
+static const struct hda_pcm_stream vt1709_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -2871,26 +2438,26 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
 				switch (i) {
 				switch (i) {
 				case AUTO_SEQ_FRONT:
 				case AUTO_SEQ_FRONT:
 					/* AOW0 */
 					/* AOW0 */
-					spec->multiout.dac_nids[i] = 0x10;
+					spec->private_dac_nids[i] = 0x10;
 					break;
 					break;
 				case AUTO_SEQ_CENLFE:
 				case AUTO_SEQ_CENLFE:
 					/* AOW2 */
 					/* AOW2 */
-					spec->multiout.dac_nids[i] = 0x12;
+					spec->private_dac_nids[i] = 0x12;
 					break;
 					break;
 				case AUTO_SEQ_SURROUND:
 				case AUTO_SEQ_SURROUND:
 					/* AOW3 */
 					/* AOW3 */
-					spec->multiout.dac_nids[i] = 0x11;
+					spec->private_dac_nids[i] = 0x11;
 					break;
 					break;
 				case AUTO_SEQ_SIDE:
 				case AUTO_SEQ_SIDE:
 					/* AOW1 */
 					/* AOW1 */
-					spec->multiout.dac_nids[i] = 0x27;
+					spec->private_dac_nids[i] = 0x27;
 					break;
 					break;
 				default:
 				default:
 					break;
 					break;
 				}
 				}
 			}
 			}
 		}
 		}
-		spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
+		spec->private_dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
 
 
 	} else if (cfg->line_outs == 3) { /* 6 channels */
 	} else if (cfg->line_outs == 3) { /* 6 channels */
 		for (i = 0; i < cfg->line_outs; i++) {
 		for (i = 0; i < cfg->line_outs; i++) {
@@ -2900,15 +2467,15 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
 				switch (i) {
 				switch (i) {
 				case AUTO_SEQ_FRONT:
 				case AUTO_SEQ_FRONT:
 					/* AOW0 */
 					/* AOW0 */
-					spec->multiout.dac_nids[i] = 0x10;
+					spec->private_dac_nids[i] = 0x10;
 					break;
 					break;
 				case AUTO_SEQ_CENLFE:
 				case AUTO_SEQ_CENLFE:
 					/* AOW2 */
 					/* AOW2 */
-					spec->multiout.dac_nids[i] = 0x12;
+					spec->private_dac_nids[i] = 0x12;
 					break;
 					break;
 				case AUTO_SEQ_SURROUND:
 				case AUTO_SEQ_SURROUND:
 					/* AOW1 */
 					/* AOW1 */
-					spec->multiout.dac_nids[i] = 0x11;
+					spec->private_dac_nids[i] = 0x11;
 					break;
 					break;
 				default:
 				default:
 					break;
 					break;
@@ -3056,7 +2623,7 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
 static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 						const struct auto_pin_cfg *cfg)
 {
 {
-	static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
+	static const hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 						ARRAY_SIZE(pin_idxs));
 }
 }
@@ -3106,7 +2673,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1709_loopbacks[] = {
+static const struct hda_amp_list vt1709_loopbacks[] = {
 	{ 0x18, HDA_INPUT, 1 },
 	{ 0x18, HDA_INPUT, 1 },
 	{ 0x18, HDA_INPUT, 2 },
 	{ 0x18, HDA_INPUT, 2 },
 	{ 0x18, HDA_INPUT, 3 },
 	{ 0x18, HDA_INPUT, 3 },
@@ -3167,7 +2734,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
+static const struct hda_verb vt1709_6ch_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 * Unmute ADC0-2 and set the default input to mic-in
 	 */
 	 */
@@ -3257,7 +2824,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
 }
 }
 
 
 /* capture mixer elements */
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1708B_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
@@ -3279,7 +2846,7 @@ static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
 /*
 /*
  * generic initialization of ADC, input mixers and output mixers
  * generic initialization of ADC, input mixers and output mixers
  */
  */
-static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
+static const struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
 	 */
@@ -3314,7 +2881,7 @@ static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
+static const struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
 	 */
@@ -3349,7 +2916,7 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb vt1708B_uniwill_init_verbs[] = {
+static const struct hda_verb vt1708B_uniwill_init_verbs[] = {
 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
@@ -3373,7 +2940,7 @@ static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
 	return 0;
 	return 0;
 }
 }
 
 
-static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.channels_max = 8,
@@ -3386,7 +2953,7 @@ static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 4,
 	.channels_max = 4,
@@ -3398,7 +2965,7 @@ static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1708B_pcm_analog_capture = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -3411,7 +2978,7 @@ static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1708B_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -3424,7 +2991,7 @@ static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
+static const struct hda_pcm_stream vt1708B_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -3447,16 +3014,16 @@ static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
 			/* config dac list */
 			/* config dac list */
 			switch (i) {
 			switch (i) {
 			case AUTO_SEQ_FRONT:
 			case AUTO_SEQ_FRONT:
-				spec->multiout.dac_nids[i] = 0x10;
+				spec->private_dac_nids[i] = 0x10;
 				break;
 				break;
 			case AUTO_SEQ_CENLFE:
 			case AUTO_SEQ_CENLFE:
-				spec->multiout.dac_nids[i] = 0x24;
+				spec->private_dac_nids[i] = 0x24;
 				break;
 				break;
 			case AUTO_SEQ_SURROUND:
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x11;
+				spec->private_dac_nids[i] = 0x11;
 				break;
 				break;
 			case AUTO_SEQ_SIDE:
 			case AUTO_SEQ_SIDE:
-				spec->multiout.dac_nids[i] = 0x25;
+				spec->private_dac_nids[i] = 0x25;
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -3588,7 +3155,7 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
 static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 						const struct auto_pin_cfg *cfg)
 {
 {
-	static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
+	static const hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 						ARRAY_SIZE(pin_idxs));
 }
 }
@@ -3638,7 +3205,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1708B_loopbacks[] = {
+static const struct hda_amp_list vt1708B_loopbacks[] = {
 	{ 0x16, HDA_INPUT, 1 },
 	{ 0x16, HDA_INPUT, 1 },
 	{ 0x16, HDA_INPUT, 2 },
 	{ 0x16, HDA_INPUT, 2 },
 	{ 0x16, HDA_INPUT, 3 },
 	{ 0x16, HDA_INPUT, 3 },
@@ -3646,6 +3213,87 @@ static struct hda_amp_list vt1708B_loopbacks[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 #endif
 #endif
+
+static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int imux_is_smixer;
+	unsigned int parm;
+	int is_8ch = 0;
+	if ((spec->codec_type != VT1708B_4CH) &&
+	    (codec->vendor_id != 0x11064397))
+		is_8ch = 1;
+
+	/* SW0 (17h) = stereo mixer */
+	imux_is_smixer =
+	(snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
+	 == ((spec->codec_type == VT1708S) ? 5 : 0));
+	/* inputs */
+	/* PW 1/2/5 (1ah/1bh/1eh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x1a, &parm);
+	set_pin_power_state(codec, 0x1b, &parm);
+	set_pin_power_state(codec, 0x1e, &parm);
+	if (imux_is_smixer)
+		parm = AC_PWRST_D0;
+	/* SW0 (17h), AIW 0/1 (13h/14h) */
+	snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* PW0 (19h), SW1 (18h), AOW1 (11h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x19, &parm);
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x1b, &parm);
+	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW6 (22h), SW2 (26h), AOW2 (24h) */
+	if (is_8ch) {
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x22, &parm);
+		if (spec->smart51_enabled)
+			set_pin_power_state(codec, 0x1a, &parm);
+		snd_hda_codec_write(codec, 0x26, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x24, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	} else if (codec->vendor_id == 0x11064397) {
+		/* PW7(23h), SW2(27h), AOW2(25h) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x23, &parm);
+		if (spec->smart51_enabled)
+			set_pin_power_state(codec, 0x1a, &parm);
+		snd_hda_codec_write(codec, 0x27, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x25, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	}
+
+	/* PW 3/4/7 (1ch/1dh/23h) */
+	parm = AC_PWRST_D3;
+	/* force to D0 for internal Speaker */
+	set_pin_power_state(codec, 0x1c, &parm);
+	set_pin_power_state(codec, 0x1d, &parm);
+	if (is_8ch)
+		set_pin_power_state(codec, 0x23, &parm);
+
+	/* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
+	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+			    imux_is_smixer ? AC_PWRST_D0 : parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+	if (is_8ch) {
+		snd_hda_codec_write(codec, 0x25, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x27, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	} else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode)
+		snd_hda_codec_write(codec, 0x25, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+}
+
 static int patch_vt1708S(struct hda_codec *codec);
 static int patch_vt1708S(struct hda_codec *codec);
 static int patch_vt1708B_8ch(struct hda_codec *codec)
 static int patch_vt1708B_8ch(struct hda_codec *codec)
 {
 {
@@ -3696,6 +3344,8 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
 	spec->loopback.amplist = vt1708B_loopbacks;
 	spec->loopback.amplist = vt1708B_loopbacks;
 #endif
 #endif
 
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3746,13 +3396,15 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
 	spec->loopback.amplist = vt1708B_loopbacks;
 	spec->loopback.amplist = vt1708B_loopbacks;
 #endif
 #endif
 
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
+
 	return 0;
 	return 0;
 }
 }
 
 
 /* Patch for VT1708S */
 /* Patch for VT1708S */
 
 
 /* capture mixer elements */
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1708S_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
@@ -3775,7 +3427,7 @@ static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb vt1708S_volume_init_verbs[] = {
+static const struct hda_verb vt1708S_volume_init_verbs[] = {
 	/* Unmute ADC0-1 and set the default input to mic-in */
 	/* Unmute ADC0-1 and set the default input to mic-in */
 	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -3801,7 +3453,7 @@ static struct hda_verb vt1708S_volume_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb vt1708S_uniwill_init_verbs[] = {
+static const struct hda_verb vt1708S_uniwill_init_verbs[] = {
 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
@@ -3814,7 +3466,19 @@ static struct hda_verb vt1708S_uniwill_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
+static const struct hda_verb vt1705_uniwill_init_verbs[] = {
+	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
+	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{ }
+};
+
+static const struct hda_pcm_stream vt1708S_pcm_analog_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 8,
 	.channels_max = 8,
@@ -3827,7 +3491,20 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1705_pcm_analog_playback = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 6,
+	.nid = 0x10, /* NID to query formats and rates */
+	.ops = {
+		.open = via_playback_pcm_open,
+		.prepare = via_playback_multi_pcm_prepare,
+		.cleanup = via_playback_multi_pcm_cleanup,
+		.close = via_pcm_open_close
+	},
+};
+
+static const struct hda_pcm_stream vt1708S_pcm_analog_capture = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -3840,7 +3517,7 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1708S_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -3870,16 +3547,19 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
 			/* config dac list */
 			/* config dac list */
 			switch (i) {
 			switch (i) {
 			case AUTO_SEQ_FRONT:
 			case AUTO_SEQ_FRONT:
-				spec->multiout.dac_nids[i] = 0x10;
+				spec->private_dac_nids[i] = 0x10;
 				break;
 				break;
 			case AUTO_SEQ_CENLFE:
 			case AUTO_SEQ_CENLFE:
-				spec->multiout.dac_nids[i] = 0x24;
+				if (spec->codec->vendor_id == 0x11064397)
+					spec->private_dac_nids[i] = 0x25;
+				else
+					spec->private_dac_nids[i] = 0x24;
 				break;
 				break;
 			case AUTO_SEQ_SURROUND:
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x11;
+				spec->private_dac_nids[i] = 0x11;
 				break;
 				break;
 			case AUTO_SEQ_SIDE:
 			case AUTO_SEQ_SIDE:
-				spec->multiout.dac_nids[i] = 0x25;
+				spec->private_dac_nids[i] = 0x25;
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -3888,23 +3568,29 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
 	/* for Smart 5.1, line/mic inputs double as output pins */
 	/* for Smart 5.1, line/mic inputs double as output pins */
 	if (cfg->line_outs == 1) {
 	if (cfg->line_outs == 1) {
 		spec->multiout.num_dacs = 3;
 		spec->multiout.num_dacs = 3;
-		spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11;
-		spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24;
+		spec->private_dac_nids[AUTO_SEQ_SURROUND] = 0x11;
+		if (spec->codec->vendor_id == 0x11064397)
+			spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x25;
+		else
+			spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x24;
 	}
 	}
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 /* add playback controls from the parsed DAC table */
 /* add playback controls from the parsed DAC table */
-static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
+static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec,
 					     const struct auto_pin_cfg *cfg)
 					     const struct auto_pin_cfg *cfg)
 {
 {
+	struct via_spec *spec = codec->spec;
 	char name[32];
 	char name[32];
 	static const char * const chname[4] = {
 	static const char * const chname[4] = {
 		"Front", "Surround", "C/LFE", "Side"
 		"Front", "Surround", "C/LFE", "Side"
 	};
 	};
-	hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
-	hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
+	hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25},
+				     {0x10, 0x11, 0x25, 0} };
+	hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27},
+				      {0x1C, 0x18, 0x27, 0} };
 	hda_nid_t nid, nid_vol, nid_mute;
 	hda_nid_t nid, nid_vol, nid_mute;
 	int i, err;
 	int i, err;
 
 
@@ -3915,8 +3601,15 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
 		if (!nid && i > AUTO_SEQ_CENLFE)
 		if (!nid && i > AUTO_SEQ_CENLFE)
 			continue;
 			continue;
 
 
-		nid_vol = nid_vols[i];
-		nid_mute = nid_mutes[i];
+		if (codec->vendor_id == 0x11064397) {
+			nid_vol = nid_vols[1][i];
+			nid_mute = nid_mutes[1][i];
+		} else {
+			nid_vol = nid_vols[0][i];
+			nid_mute = nid_mutes[0][i];
+		}
+		if (!nid_vol && !nid_mute)
+			continue;
 
 
 		if (i == AUTO_SEQ_CENLFE) {
 		if (i == AUTO_SEQ_CENLFE) {
 			/* Center/LFE */
 			/* Center/LFE */
@@ -4026,7 +3719,7 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
 static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 						const struct auto_pin_cfg *cfg)
 {
 {
-	static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 						ARRAY_SIZE(pin_idxs));
 }
 }
@@ -4070,7 +3763,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
 		return 0; /* can't find valid BIOS pin config */
 		return 0; /* can't find valid BIOS pin config */
 
 
-	err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+	err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 	err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
 	err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
@@ -4097,7 +3790,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1708S_loopbacks[] = {
+static const struct hda_amp_list vt1708S_loopbacks[] = {
 	{ 0x16, HDA_INPUT, 1 },
 	{ 0x16, HDA_INPUT, 1 },
 	{ 0x16, HDA_INPUT, 2 },
 	{ 0x16, HDA_INPUT, 2 },
 	{ 0x16, HDA_INPUT, 3 },
 	{ 0x16, HDA_INPUT, 3 },
@@ -4137,17 +3830,29 @@ static int patch_vt1708S(struct hda_codec *codec)
 	}
 	}
 
 
 	spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
 	spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
-	spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
+	if (codec->vendor_id == 0x11064397)
+		spec->init_verbs[spec->num_iverbs++] =
+			vt1705_uniwill_init_verbs;
+	else
+		spec->init_verbs[spec->num_iverbs++] =
+			vt1708S_uniwill_init_verbs;
 
 
 	if (codec->vendor_id == 0x11060440)
 	if (codec->vendor_id == 0x11060440)
 		spec->stream_name_analog = "VT1818S Analog";
 		spec->stream_name_analog = "VT1818S Analog";
+	else if (codec->vendor_id == 0x11064397)
+		spec->stream_name_analog = "VT1705 Analog";
 	else
 	else
 		spec->stream_name_analog = "VT1708S Analog";
 		spec->stream_name_analog = "VT1708S Analog";
-	spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
+	if (codec->vendor_id == 0x11064397)
+		spec->stream_analog_playback = &vt1705_pcm_analog_playback;
+	else
+		spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
 	spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
 	spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
 
 
 	if (codec->vendor_id == 0x11060440)
 	if (codec->vendor_id == 0x11060440)
 		spec->stream_name_digital = "VT1818S Digital";
 		spec->stream_name_digital = "VT1818S Digital";
+	else if (codec->vendor_id == 0x11064397)
+		spec->stream_name_digital = "VT1705 Digital";
 	else
 	else
 		spec->stream_name_digital = "VT1708S Digital";
 		spec->stream_name_digital = "VT1708S Digital";
 	spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
 	spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
@@ -4185,13 +3890,22 @@ static int patch_vt1708S(struct hda_codec *codec)
 		spec->stream_name_analog = "VT1818S Analog";
 		spec->stream_name_analog = "VT1818S Analog";
 		spec->stream_name_digital = "VT1818S Digital";
 		spec->stream_name_digital = "VT1818S Digital";
 	}
 	}
+	/* correct names for VT1705 */
+	if (codec->vendor_id == 0x11064397)	{
+		kfree(codec->chip_name);
+		codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
+		snprintf(codec->bus->card->mixername,
+			 sizeof(codec->bus->card->mixername),
+			 "%s %s", codec->vendor_name, codec->chip_name);
+	}
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
 	return 0;
 	return 0;
 }
 }
 
 
 /* Patch for VT1702 */
 /* Patch for VT1702 */
 
 
 /* capture mixer elements */
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1702_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1702_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
@@ -4215,7 +3929,7 @@ static struct snd_kcontrol_new vt1702_capture_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb vt1702_volume_init_verbs[] = {
+static const struct hda_verb vt1702_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
 	 */
@@ -4246,7 +3960,7 @@ static struct hda_verb vt1702_volume_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_verb vt1702_uniwill_init_verbs[] = {
+static const struct hda_verb vt1702_uniwill_init_verbs[] = {
 	{0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
 	{0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
@@ -4256,7 +3970,7 @@ static struct hda_verb vt1702_uniwill_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_pcm_stream vt1702_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1702_pcm_analog_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -4269,7 +3983,7 @@ static struct hda_pcm_stream vt1702_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1702_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1702_pcm_analog_capture = {
 	.substreams = 3,
 	.substreams = 3,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -4282,7 +3996,7 @@ static struct hda_pcm_stream vt1702_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1702_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1702_pcm_digital_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -4304,7 +4018,7 @@ static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
 
 
 	if (cfg->line_out_pins[0]) {
 	if (cfg->line_out_pins[0]) {
 		/* config dac list */
 		/* config dac list */
-		spec->multiout.dac_nids[0] = 0x10;
+		spec->private_dac_nids[0] = 0x10;
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -4382,7 +4096,7 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
 static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 						const struct auto_pin_cfg *cfg)
 {
 {
-	static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 						ARRAY_SIZE(pin_idxs));
 }
 }
@@ -4433,7 +4147,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1702_loopbacks[] = {
+static const struct hda_amp_list vt1702_loopbacks[] = {
 	{ 0x1A, HDA_INPUT, 1 },
 	{ 0x1A, HDA_INPUT, 1 },
 	{ 0x1A, HDA_INPUT, 2 },
 	{ 0x1A, HDA_INPUT, 2 },
 	{ 0x1A, HDA_INPUT, 3 },
 	{ 0x1A, HDA_INPUT, 3 },
@@ -4442,6 +4156,37 @@ static struct hda_amp_list vt1702_loopbacks[] = {
 };
 };
 #endif
 #endif
 
 
+static void set_widgets_power_state_vt1702(struct hda_codec *codec)
+{
+	int imux_is_smixer =
+	snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+	unsigned int parm;
+	/* inputs */
+	/* PW 1/2/5 (14h/15h/18h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x14, &parm);
+	set_pin_power_state(codec, 0x15, &parm);
+	set_pin_power_state(codec, 0x18, &parm);
+	if (imux_is_smixer)
+		parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */
+	/* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
+	snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* PW 3/4 (16h/17h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x17, &parm);
+	set_pin_power_state(codec, 0x16, &parm);
+	/* MW0 (1ah), AOW 0/1 (10h/1dh) */
+	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
+			    imux_is_smixer ? AC_PWRST_D0 : parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
+}
+
 static int patch_vt1702(struct hda_codec *codec)
 static int patch_vt1702(struct hda_codec *codec)
 {
 {
 	struct via_spec *spec;
 	struct via_spec *spec;
@@ -4488,13 +4233,14 @@ static int patch_vt1702(struct hda_codec *codec)
 	spec->loopback.amplist = vt1702_loopbacks;
 	spec->loopback.amplist = vt1702_loopbacks;
 #endif
 #endif
 
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1702;
 	return 0;
 	return 0;
 }
 }
 
 
 /* Patch for VT1718S */
 /* Patch for VT1718S */
 
 
 /* capture mixer elements */
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1718S_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1718S_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
@@ -4516,14 +4262,15 @@ static struct snd_kcontrol_new vt1718S_capture_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb vt1718S_volume_init_verbs[] = {
+static const struct hda_verb vt1718S_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
 	 */
 	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
 
-
+	/* Enable MW0 adjust Gain 5 */
+	{0x1, 0xfb2, 0x10},
 	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
 	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
 	 * mixer widget
 	 * mixer widget
 	 */
 	 */
@@ -4532,7 +4279,7 @@ static struct hda_verb vt1718S_volume_init_verbs[] = {
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
 
 
 	/* Setup default input of Front HP to MW9 */
 	/* Setup default input of Front HP to MW9 */
 	{0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
 	{0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
@@ -4563,7 +4310,7 @@ static struct hda_verb vt1718S_volume_init_verbs[] = {
 };
 };
 
 
 
 
-static struct hda_verb vt1718S_uniwill_init_verbs[] = {
+static const struct hda_verb vt1718S_uniwill_init_verbs[] = {
 	{0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
 	{0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 	{0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
@@ -4576,7 +4323,7 @@ static struct hda_verb vt1718S_uniwill_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_pcm_stream vt1718S_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1718S_pcm_analog_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 10,
 	.channels_max = 10,
@@ -4589,7 +4336,7 @@ static struct hda_pcm_stream vt1718S_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1718S_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1718S_pcm_analog_capture = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -4602,7 +4349,7 @@ static struct hda_pcm_stream vt1718S_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1718S_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1718S_pcm_digital_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -4615,7 +4362,7 @@ static struct hda_pcm_stream vt1718S_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1718S_pcm_digital_capture = {
+static const struct hda_pcm_stream vt1718S_pcm_digital_capture = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -4638,16 +4385,16 @@ static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
 			/* config dac list */
 			/* config dac list */
 			switch (i) {
 			switch (i) {
 			case AUTO_SEQ_FRONT:
 			case AUTO_SEQ_FRONT:
-				spec->multiout.dac_nids[i] = 0x8;
+				spec->private_dac_nids[i] = 0x8;
 				break;
 				break;
 			case AUTO_SEQ_CENLFE:
 			case AUTO_SEQ_CENLFE:
-				spec->multiout.dac_nids[i] = 0xa;
+				spec->private_dac_nids[i] = 0xa;
 				break;
 				break;
 			case AUTO_SEQ_SURROUND:
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x9;
+				spec->private_dac_nids[i] = 0x9;
 				break;
 				break;
 			case AUTO_SEQ_SIDE:
 			case AUTO_SEQ_SIDE:
-				spec->multiout.dac_nids[i] = 0xb;
+				spec->private_dac_nids[i] = 0xb;
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -4769,7 +4516,7 @@ static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
 static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 						const struct auto_pin_cfg *cfg)
 {
 {
-	static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 						ARRAY_SIZE(pin_idxs));
 }
 }
@@ -4820,7 +4567,7 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec)
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1718S_loopbacks[] = {
+static const struct hda_amp_list vt1718S_loopbacks[] = {
 	{ 0x21, HDA_INPUT, 1 },
 	{ 0x21, HDA_INPUT, 1 },
 	{ 0x21, HDA_INPUT, 2 },
 	{ 0x21, HDA_INPUT, 2 },
 	{ 0x21, HDA_INPUT, 3 },
 	{ 0x21, HDA_INPUT, 3 },
@@ -4829,6 +4576,72 @@ static struct hda_amp_list vt1718S_loopbacks[] = {
 };
 };
 #endif
 #endif
 
 
+static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int imux_is_smixer;
+	unsigned int parm;
+	/* MUX6 (1eh) = stereo mixer */
+	imux_is_smixer =
+	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+	/* inputs */
+	/* PW 5/6/7 (29h/2ah/2bh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x29, &parm);
+	set_pin_power_state(codec, 0x2a, &parm);
+	set_pin_power_state(codec, 0x2b, &parm);
+	if (imux_is_smixer)
+		parm = AC_PWRST_D0;
+	/* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
+	snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* PW3 (27h), MW2 (1ah), AOW3 (bh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x27, &parm);
+	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW2 (26h), AOW2 (ah) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x26, &parm);
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x2b, &parm);
+	snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW0 (24h), AOW0 (8h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x24, &parm);
+	if (!spec->hp_independent_mode) /* check for redirected HP */
+		set_pin_power_state(codec, 0x28, &parm);
+	snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
+	/* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
+	snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
+			    imux_is_smixer ? AC_PWRST_D0 : parm);
+
+	/* PW1 (25h), AOW1 (9h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x25, &parm);
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x2a, &parm);
+	snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	if (spec->hp_independent_mode) {
+		/* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x28, &parm);
+		snd_hda_codec_write(codec, 0x1b, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x34, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0xc, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	}
+}
+
 static int patch_vt1718S(struct hda_codec *codec)
 static int patch_vt1718S(struct hda_codec *codec)
 {
 {
 	struct via_spec *spec;
 	struct via_spec *spec;
@@ -4890,6 +4703,8 @@ static int patch_vt1718S(struct hda_codec *codec)
 	spec->loopback.amplist = vt1718S_loopbacks;
 	spec->loopback.amplist = vt1718S_loopbacks;
 #endif
 #endif
 
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1718S;
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -4929,13 +4744,12 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
 	snd_hda_codec_write(codec, 0x26, 0,
 	snd_hda_codec_write(codec, 0x26, 0,
 					       AC_VERB_SET_CONNECT_SEL, index);
 					       AC_VERB_SET_CONNECT_SEL, index);
 	spec->dmic_enabled = index;
 	spec->dmic_enabled = index;
-	set_jack_power_state(codec);
-
+	set_widgets_power_state(codec);
 	return 1;
 	return 1;
 }
 }
 
 
 /* capture mixer elements */
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1716S_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1716S_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
@@ -4954,7 +4768,7 @@ static struct snd_kcontrol_new vt1716S_capture_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
+static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
 	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
 	{
 	{
 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -4970,12 +4784,12 @@ static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
 
 
 
 
 /* mono-out mixer elements */
 /* mono-out mixer elements */
-static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
+static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
 	HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb vt1716S_volume_init_verbs[] = {
+static const struct hda_verb vt1716S_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
 	 */
@@ -5024,7 +4838,7 @@ static struct hda_verb vt1716S_volume_init_verbs[] = {
 };
 };
 
 
 
 
-static struct hda_verb vt1716S_uniwill_init_verbs[] = {
+static const struct hda_verb vt1716S_uniwill_init_verbs[] = {
 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
@@ -5037,7 +4851,7 @@ static struct hda_verb vt1716S_uniwill_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_pcm_stream vt1716S_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1716S_pcm_analog_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 6,
 	.channels_max = 6,
@@ -5050,7 +4864,7 @@ static struct hda_pcm_stream vt1716S_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1716S_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1716S_pcm_analog_capture = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -5063,7 +4877,7 @@ static struct hda_pcm_stream vt1716S_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1716S_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1716S_pcm_digital_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -5092,13 +4906,13 @@ static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
 			/* config dac list */
 			/* config dac list */
 			switch (i) {
 			switch (i) {
 			case AUTO_SEQ_FRONT:
 			case AUTO_SEQ_FRONT:
-				spec->multiout.dac_nids[i] = 0x10;
+				spec->private_dac_nids[i] = 0x10;
 				break;
 				break;
 			case AUTO_SEQ_CENLFE:
 			case AUTO_SEQ_CENLFE:
-				spec->multiout.dac_nids[i] = 0x25;
+				spec->private_dac_nids[i] = 0x25;
 				break;
 				break;
 			case AUTO_SEQ_SURROUND:
 			case AUTO_SEQ_SURROUND:
-				spec->multiout.dac_nids[i] = 0x11;
+				spec->private_dac_nids[i] = 0x11;
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -5233,7 +5047,7 @@ static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
 static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 						const struct auto_pin_cfg *cfg)
 {
 {
-	static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 						ARRAY_SIZE(pin_idxs));
 }
 }
@@ -5280,7 +5094,7 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec)
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1716S_loopbacks[] = {
+static const struct hda_amp_list vt1716S_loopbacks[] = {
 	{ 0x16, HDA_INPUT, 1 },
 	{ 0x16, HDA_INPUT, 1 },
 	{ 0x16, HDA_INPUT, 2 },
 	{ 0x16, HDA_INPUT, 2 },
 	{ 0x16, HDA_INPUT, 3 },
 	{ 0x16, HDA_INPUT, 3 },
@@ -5289,6 +5103,99 @@ static struct hda_amp_list vt1716S_loopbacks[] = {
 };
 };
 #endif
 #endif
 
 
+static void set_widgets_power_state_vt1716S(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int imux_is_smixer;
+	unsigned int parm;
+	unsigned int mono_out, present;
+	/* SW0 (17h) = stereo mixer */
+	imux_is_smixer =
+	(snd_hda_codec_read(codec, 0x17, 0,
+			    AC_VERB_GET_CONNECT_SEL, 0x00) ==  5);
+	/* inputs */
+	/* PW 1/2/5 (1ah/1bh/1eh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x1a, &parm);
+	set_pin_power_state(codec, 0x1b, &parm);
+	set_pin_power_state(codec, 0x1e, &parm);
+	if (imux_is_smixer)
+		parm = AC_PWRST_D0;
+	/* SW0 (17h), AIW0(13h) */
+	snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x1e, &parm);
+	/* PW11 (22h) */
+	if (spec->dmic_enabled)
+		set_pin_power_state(codec, 0x22, &parm);
+	else
+		snd_hda_codec_write(codec, 0x22, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+
+	/* SW2(26h), AIW1(14h) */
+	snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* PW0 (19h), SW1 (18h), AOW1 (11h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x19, &parm);
+	/* Smart 5.1 PW2(1bh) */
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x1b, &parm);
+	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW7 (23h), SW3 (27h), AOW3 (25h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x23, &parm);
+	/* Smart 5.1 PW1(1ah) */
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x1a, &parm);
+	snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* Smart 5.1 PW5(1eh) */
+	if (spec->smart51_enabled)
+		set_pin_power_state(codec, 0x1e, &parm);
+	snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* Mono out */
+	/* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
+	present = snd_hda_jack_detect(codec, 0x1c);
+
+	if (present)
+		mono_out = 0;
+	else {
+		present = snd_hda_jack_detect(codec, 0x1d);
+		if (!spec->hp_independent_mode && present)
+			mono_out = 0;
+		else
+			mono_out = 1;
+	}
+	parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
+	snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW 3/4 (1ch/1dh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x1c, &parm);
+	set_pin_power_state(codec, 0x1d, &parm);
+	/* HP Independent Mode, power on AOW3 */
+	if (spec->hp_independent_mode)
+		snd_hda_codec_write(codec, 0x25, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+
+	/* force to D0 for internal Speaker */
+	/* MW0 (16h), AOW0 (10h) */
+	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+			    imux_is_smixer ? AC_PWRST_D0 : parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+			    mono_out ? AC_PWRST_D0 : parm);
+}
+
 static int patch_vt1716S(struct hda_codec *codec)
 static int patch_vt1716S(struct hda_codec *codec)
 {
 {
 	struct via_spec *spec;
 	struct via_spec *spec;
@@ -5343,13 +5250,14 @@ static int patch_vt1716S(struct hda_codec *codec)
 	spec->loopback.amplist = vt1716S_loopbacks;
 	spec->loopback.amplist = vt1716S_loopbacks;
 #endif
 #endif
 
 
+	spec->set_widgets_power_state = set_widgets_power_state_vt1716S;
 	return 0;
 	return 0;
 }
 }
 
 
 /* for vt2002P */
 /* for vt2002P */
 
 
 /* capture mixer elements */
 /* capture mixer elements */
-static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
+static const struct snd_kcontrol_new vt2002P_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
@@ -5372,7 +5280,11 @@ static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb vt2002P_volume_init_verbs[] = {
+static const struct hda_verb vt2002P_volume_init_verbs[] = {
+	/* Class-D speaker related verbs */
+	{0x1, 0xfe0, 0x4},
+	{0x1, 0xfe9, 0x80},
+	{0x1, 0xfe2, 0x22},
 	/*
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
 	 */
@@ -5423,9 +5335,60 @@ static struct hda_verb vt2002P_volume_init_verbs[] = {
 	{0x1, 0xfb8, 0x88},
 	{0x1, 0xfb8, 0x88},
 	{ }
 	{ }
 };
 };
+static const struct hda_verb vt1802_volume_init_verbs[] = {
+	/*
+	 * Unmute ADC0-1 and set the default input to mic-in
+	 */
+	{0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	 * mixer widget
+	 */
+	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+	/* MUX Indices: Mic = 0 */
+	{0x1e, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x1f, AC_VERB_SET_CONNECT_SEL, 0},
+
+	/* PW9 Output enable */
+	{0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+
+	/* Enable Boost Volume backdoor */
+	{0x1, 0xfb9, 0x24},
+
+	/* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+	/* set MUX0/1/4/8 = 0 (AOW0) */
+	{0x34, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x35, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x38, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x3c, AC_VERB_SET_CONNECT_SEL, 0},
+
+	/* set PW0 index=0 (MW0) */
+	{0x24, AC_VERB_SET_CONNECT_SEL, 0},
+
+	/* Enable AOW0 to MW9 */
+	{0x1, 0xfb8, 0x88},
+	{ }
+};
 
 
 
 
-static struct hda_verb vt2002P_uniwill_init_verbs[] = {
+static const struct hda_verb vt2002P_uniwill_init_verbs[] = {
 	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
 	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
 	{0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
 	{0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
@@ -5435,8 +5398,18 @@ static struct hda_verb vt2002P_uniwill_init_verbs[] = {
 	{0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 	{0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 	{ }
 	{ }
 };
 };
+static const struct hda_verb vt1802_uniwill_init_verbs[] = {
+	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
+	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+	{0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
+	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+	{0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+	{ }
+};
 
 
-static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
+static const struct hda_pcm_stream vt2002P_pcm_analog_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -5449,7 +5422,7 @@ static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt2002P_pcm_analog_capture = {
+static const struct hda_pcm_stream vt2002P_pcm_analog_capture = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -5462,7 +5435,7 @@ static struct hda_pcm_stream vt2002P_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt2002P_pcm_digital_playback = {
+static const struct hda_pcm_stream vt2002P_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -5482,7 +5455,7 @@ static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
 	spec->multiout.num_dacs = 1;
 	spec->multiout.num_dacs = 1;
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	if (cfg->line_out_pins[0])
 	if (cfg->line_out_pins[0])
-		spec->multiout.dac_nids[0] = 0x8;
+		spec->private_dac_nids[0] = 0x8;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -5491,10 +5464,15 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
 					     const struct auto_pin_cfg *cfg)
 					     const struct auto_pin_cfg *cfg)
 {
 {
 	int err;
 	int err;
+	hda_nid_t sw_nid;
 
 
 	if (!cfg->line_out_pins[0])
 	if (!cfg->line_out_pins[0])
 		return -1;
 		return -1;
 
 
+	if (spec->codec_type == VT1802)
+		sw_nid = 0x28;
+	else
+		sw_nid = 0x26;
 
 
 	/* Line-Out: PortE */
 	/* Line-Out: PortE */
 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
@@ -5504,7 +5482,7 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
 		return err;
 		return err;
 	err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
 	err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
 			      "Master Front Playback Switch",
 			      "Master Front Playback Switch",
-			      HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT));
+			      HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT));
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 
 
@@ -5544,7 +5522,7 @@ static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec,
 {
 {
 	struct via_spec *spec = codec->spec;
 	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
 	struct hda_input_mux *imux = &spec->private_imux[0];
-	static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
 	int err;
 	int err;
 
 
 	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
 	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
@@ -5605,7 +5583,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec)
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt2002P_loopbacks[] = {
+static const struct hda_amp_list vt2002P_loopbacks[] = {
 	{ 0x21, HDA_INPUT, 0 },
 	{ 0x21, HDA_INPUT, 0 },
 	{ 0x21, HDA_INPUT, 1 },
 	{ 0x21, HDA_INPUT, 1 },
 	{ 0x21, HDA_INPUT, 2 },
 	{ 0x21, HDA_INPUT, 2 },
@@ -5613,6 +5591,116 @@ static struct hda_amp_list vt2002P_loopbacks[] = {
 };
 };
 #endif
 #endif
 
 
+static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int imux_is_smixer;
+	unsigned int parm;
+	unsigned int present;
+	/* MUX9 (1eh) = stereo mixer */
+	imux_is_smixer =
+	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+	/* inputs */
+	/* PW 5/6/7 (29h/2ah/2bh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x29, &parm);
+	set_pin_power_state(codec, 0x2a, &parm);
+	set_pin_power_state(codec, 0x2b, &parm);
+	parm = AC_PWRST_D0;
+	/* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
+	snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* AOW0 (8h)*/
+	snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	if (spec->codec_type == VT1802) {
+		/* PW4 (28h), MW4 (18h), MUX4(38h) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x28, &parm);
+		snd_hda_codec_write(codec, 0x18, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x38, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	} else {
+		/* PW4 (26h), MW4 (1ch), MUX4(37h) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x26, &parm);
+		snd_hda_codec_write(codec, 0x1c, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x37, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	}
+
+	if (spec->codec_type == VT1802) {
+		/* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x25, &parm);
+		snd_hda_codec_write(codec, 0x15, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x35, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	} else {
+		/* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
+		parm = AC_PWRST_D3;
+		set_pin_power_state(codec, 0x25, &parm);
+		snd_hda_codec_write(codec, 0x19, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x35, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	}
+
+	if (spec->hp_independent_mode)
+		snd_hda_codec_write(codec, 0x9, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+	/* Class-D */
+	/* PW0 (24h), MW0(18h/14h), MUX0(34h) */
+	present = snd_hda_jack_detect(codec, 0x25);
+
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x24, &parm);
+	parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
+	if (spec->codec_type == VT1802)
+		snd_hda_codec_write(codec, 0x14, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	else
+		snd_hda_codec_write(codec, 0x18, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* Mono Out */
+	present = snd_hda_jack_detect(codec, 0x26);
+
+	parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
+	if (spec->codec_type == VT1802) {
+		/* PW15 (33h), MW8(1ch), MUX8(3ch) */
+		snd_hda_codec_write(codec, 0x33, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x1c, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x3c, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	} else {
+		/* PW15 (31h), MW8(17h), MUX8(3bh) */
+		snd_hda_codec_write(codec, 0x31, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x17, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+		snd_hda_codec_write(codec, 0x3b, 0,
+				    AC_VERB_SET_POWER_STATE, parm);
+	}
+	/* MW9 (21h) */
+	if (imux_is_smixer || !is_aa_path_mute(codec))
+		snd_hda_codec_write(codec, 0x21, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+	else
+		snd_hda_codec_write(codec, 0x21, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+}
 
 
 /* patch for vt2002P */
 /* patch for vt2002P */
 static int patch_vt2002P(struct hda_codec *codec)
 static int patch_vt2002P(struct hda_codec *codec)
@@ -5635,14 +5723,31 @@ static int patch_vt2002P(struct hda_codec *codec)
 		       "from BIOS.  Using genenic mode...\n");
 		       "from BIOS.  Using genenic mode...\n");
 	}
 	}
 
 
-	spec->init_verbs[spec->num_iverbs++]  = vt2002P_volume_init_verbs;
-	spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs;
+	if (spec->codec_type == VT1802)
+		spec->init_verbs[spec->num_iverbs++]  =
+			vt1802_volume_init_verbs;
+	else
+		spec->init_verbs[spec->num_iverbs++]  =
+			vt2002P_volume_init_verbs;
+
+	if (spec->codec_type == VT1802)
+		spec->init_verbs[spec->num_iverbs++] =
+			vt1802_uniwill_init_verbs;
+	else
+		spec->init_verbs[spec->num_iverbs++] =
+			vt2002P_uniwill_init_verbs;
 
 
-	spec->stream_name_analog = "VT2002P Analog";
+	if (spec->codec_type == VT1802)
+		spec->stream_name_analog = "VT1802 Analog";
+	else
+		spec->stream_name_analog = "VT2002P Analog";
 	spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
 	spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
 	spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
 	spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
 
 
-	spec->stream_name_digital = "VT2002P Digital";
+	if (spec->codec_type == VT1802)
+		spec->stream_name_digital = "VT1802 Digital";
+	else
+		spec->stream_name_digital = "VT2002P Digital";
 	spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
 	spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
 
 
 	if (!spec->adc_nids && spec->input_mux) {
 	if (!spec->adc_nids && spec->input_mux) {
@@ -5664,13 +5769,14 @@ static int patch_vt2002P(struct hda_codec *codec)
 	spec->loopback.amplist = vt2002P_loopbacks;
 	spec->loopback.amplist = vt2002P_loopbacks;
 #endif
 #endif
 
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt2002P;
 	return 0;
 	return 0;
 }
 }
 
 
 /* for vt1812 */
 /* for vt1812 */
 
 
 /* capture mixer elements */
 /* capture mixer elements */
-static struct snd_kcontrol_new vt1812_capture_mixer[] = {
+static const struct snd_kcontrol_new vt1812_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
@@ -5692,7 +5798,7 @@ static struct snd_kcontrol_new vt1812_capture_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
-static struct hda_verb vt1812_volume_init_verbs[] = {
+static const struct hda_verb vt1812_volume_init_verbs[] = {
 	/*
 	/*
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 * Unmute ADC0-1 and set the default input to mic-in
 	 */
 	 */
@@ -5745,7 +5851,7 @@ static struct hda_verb vt1812_volume_init_verbs[] = {
 };
 };
 
 
 
 
-static struct hda_verb vt1812_uniwill_init_verbs[] = {
+static const struct hda_verb vt1812_uniwill_init_verbs[] = {
 	{0x33, AC_VERB_SET_UNSOLICITED_ENABLE,
 	{0x33, AC_VERB_SET_UNSOLICITED_ENABLE,
 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
 	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT },
 	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT },
@@ -5757,7 +5863,7 @@ static struct hda_verb vt1812_uniwill_init_verbs[] = {
 	{ }
 	{ }
 };
 };
 
 
-static struct hda_pcm_stream vt1812_pcm_analog_playback = {
+static const struct hda_pcm_stream vt1812_pcm_analog_playback = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -5770,7 +5876,7 @@ static struct hda_pcm_stream vt1812_pcm_analog_playback = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1812_pcm_analog_capture = {
+static const struct hda_pcm_stream vt1812_pcm_analog_capture = {
 	.substreams = 2,
 	.substreams = 2,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -5783,7 +5889,7 @@ static struct hda_pcm_stream vt1812_pcm_analog_capture = {
 	},
 	},
 };
 };
 
 
-static struct hda_pcm_stream vt1812_pcm_digital_playback = {
+static const struct hda_pcm_stream vt1812_pcm_digital_playback = {
 	.substreams = 1,
 	.substreams = 1,
 	.channels_min = 2,
 	.channels_min = 2,
 	.channels_max = 2,
 	.channels_max = 2,
@@ -5802,7 +5908,7 @@ static int vt1812_auto_fill_dac_nids(struct via_spec *spec,
 	spec->multiout.num_dacs = 1;
 	spec->multiout.num_dacs = 1;
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	spec->multiout.dac_nids = spec->private_dac_nids;
 	if (cfg->line_out_pins[0])
 	if (cfg->line_out_pins[0])
-		spec->multiout.dac_nids[0] = 0x8;
+		spec->private_dac_nids[0] = 0x8;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -5865,7 +5971,7 @@ static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec,
 {
 {
 	struct via_spec *spec = codec->spec;
 	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
 	struct hda_input_mux *imux = &spec->private_imux[0];
-	static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
+	static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
 	int err;
 	int err;
 
 
 	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
 	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
@@ -5927,7 +6033,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec)
 }
 }
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static struct hda_amp_list vt1812_loopbacks[] = {
+static const struct hda_amp_list vt1812_loopbacks[] = {
 	{ 0x21, HDA_INPUT, 0 },
 	{ 0x21, HDA_INPUT, 0 },
 	{ 0x21, HDA_INPUT, 1 },
 	{ 0x21, HDA_INPUT, 1 },
 	{ 0x21, HDA_INPUT, 2 },
 	{ 0x21, HDA_INPUT, 2 },
@@ -5935,6 +6041,97 @@ static struct hda_amp_list vt1812_loopbacks[] = {
 };
 };
 #endif
 #endif
 
 
+static void set_widgets_power_state_vt1812(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int imux_is_smixer =
+	snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+	unsigned int parm;
+	unsigned int present;
+	/* MUX10 (1eh) = stereo mixer */
+	imux_is_smixer =
+	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+	/* inputs */
+	/* PW 5/6/7 (29h/2ah/2bh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x29, &parm);
+	set_pin_power_state(codec, 0x2a, &parm);
+	set_pin_power_state(codec, 0x2b, &parm);
+	parm = AC_PWRST_D0;
+	/* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
+	snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* outputs */
+	/* AOW0 (8h)*/
+	snd_hda_codec_write(codec, 0x8, 0,
+			    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+	/* PW4 (28h), MW4 (18h), MUX4(38h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x28, &parm);
+	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x38, 0, AC_VERB_SET_POWER_STATE, parm);
+
+	/* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x25, &parm);
+	snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x35, 0, AC_VERB_SET_POWER_STATE, parm);
+	if (spec->hp_independent_mode)
+		snd_hda_codec_write(codec, 0x9, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+	/* Internal Speaker */
+	/* PW0 (24h), MW0(14h), MUX0(34h) */
+	present = snd_hda_jack_detect(codec, 0x25);
+
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x24, &parm);
+	if (present) {
+		snd_hda_codec_write(codec, 0x14, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+		snd_hda_codec_write(codec, 0x34, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+	} else {
+		snd_hda_codec_write(codec, 0x14, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+		snd_hda_codec_write(codec, 0x34, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+	}
+
+
+	/* Mono Out */
+	/* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
+	present = snd_hda_jack_detect(codec, 0x28);
+
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x31, &parm);
+	if (present) {
+		snd_hda_codec_write(codec, 0x1c, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+		snd_hda_codec_write(codec, 0x3c, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+		snd_hda_codec_write(codec, 0x3e, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+	} else {
+		snd_hda_codec_write(codec, 0x1c, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+		snd_hda_codec_write(codec, 0x3c, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+		snd_hda_codec_write(codec, 0x3e, 0,
+				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+	}
+
+	/* PW15 (33h), MW15 (1dh), MUX15(3dh) */
+	parm = AC_PWRST_D3;
+	set_pin_power_state(codec, 0x33, &parm);
+	snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
+	snd_hda_codec_write(codec, 0x3d, 0, AC_VERB_SET_POWER_STATE, parm);
+
+}
 
 
 /* patch for vt1812 */
 /* patch for vt1812 */
 static int patch_vt1812(struct hda_codec *codec)
 static int patch_vt1812(struct hda_codec *codec)
@@ -5988,13 +6185,14 @@ static int patch_vt1812(struct hda_codec *codec)
 	spec->loopback.amplist = vt1812_loopbacks;
 	spec->loopback.amplist = vt1812_loopbacks;
 #endif
 #endif
 
 
+	spec->set_widgets_power_state =  set_widgets_power_state_vt1812;
 	return 0;
 	return 0;
 }
 }
 
 
 /*
 /*
  * patch entries
  * patch entries
  */
  */
-static struct hda_codec_preset snd_hda_preset_via[] = {
+static const struct hda_codec_preset snd_hda_preset_via[] = {
 	{ .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
 	{ .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
 	{ .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
 	{ .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
 	{ .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
 	{ .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
@@ -6039,7 +6237,7 @@ static struct hda_codec_preset snd_hda_preset_via[] = {
 	  .patch = patch_vt1708S},
 	  .patch = patch_vt1708S},
 	{ .id = 0x11063397, .name = "VT1708S",
 	{ .id = 0x11063397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
 	  .patch = patch_vt1708S},
-	{ .id = 0x11064397, .name = "VT1708S",
+	{ .id = 0x11064397, .name = "VT1705",
 	  .patch = patch_vt1708S},
 	  .patch = patch_vt1708S},
 	{ .id = 0x11065397, .name = "VT1708S",
 	{ .id = 0x11065397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
 	  .patch = patch_vt1708S},
@@ -6080,6 +6278,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = {
 	{ .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
 	{ .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
 	{ .id = 0x11060440, .name = "VT1818S",
 	{ .id = 0x11060440, .name = "VT1818S",
 	  .patch = patch_vt1708S},
 	  .patch = patch_vt1708S},
+	{ .id = 0x11060446, .name = "VT1802",
+		.patch = patch_vt2002P},
+	{ .id = 0x11068446, .name = "VT1802",
+		.patch = patch_vt2002P},
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 

+ 2 - 2
sound/pci/intel8x0m.c

@@ -235,8 +235,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = {
 	{ PCI_VDEVICE(NVIDIA, 0x0069), DEVICE_NFORCE }, /* NFORCE2 */
 	{ PCI_VDEVICE(NVIDIA, 0x0069), DEVICE_NFORCE }, /* NFORCE2 */
 	{ PCI_VDEVICE(NVIDIA, 0x0089), DEVICE_NFORCE }, /* NFORCE2s */
 	{ PCI_VDEVICE(NVIDIA, 0x0089), DEVICE_NFORCE }, /* NFORCE2s */
 	{ PCI_VDEVICE(NVIDIA, 0x00d9), DEVICE_NFORCE }, /* NFORCE3 */
 	{ PCI_VDEVICE(NVIDIA, 0x00d9), DEVICE_NFORCE }, /* NFORCE3 */
+	{ PCI_VDEVICE(AMD, 0x746e), DEVICE_INTEL },	/* AMD8111 */
 #if 0
 #if 0
-	{ PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL },	/* AMD8111 */
 	{ PCI_VDEVICE(AL, 0x5455), DEVICE_ALI },   /* Ali5455 */
 	{ PCI_VDEVICE(AL, 0x5455), DEVICE_ALI },   /* Ali5455 */
 #endif
 #endif
 	{ 0, }
 	{ 0, }
@@ -1261,9 +1261,9 @@ static struct shortname_table {
 	{ PCI_DEVICE_ID_NVIDIA_MCP2_MODEM, "NVidia nForce2" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP2_MODEM, "NVidia nForce2" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM, "NVidia nForce2s" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM, "NVidia nForce2s" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP3_MODEM, "NVidia nForce3" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP3_MODEM, "NVidia nForce3" },
+	{ 0x746e, "AMD AMD8111" },
 #if 0
 #if 0
 	{ 0x5455, "ALi M5455" },
 	{ 0x5455, "ALi M5455" },
-	{ 0x746d, "AMD AMD8111" },
 #endif
 #endif
 	{ 0 },
 	{ 0 },
 };
 };

+ 4 - 0
sound/pci/lola/Makefile

@@ -0,0 +1,4 @@
+snd-lola-y := lola.o lola_pcm.o lola_clock.o lola_mixer.o
+snd-lola-$(CONFIG_SND_DEBUG) += lola_proc.o
+
+obj-$(CONFIG_SND_LOLA) += snd-lola.o

+ 791 - 0
sound/pci/lola/lola.c

@@ -0,0 +1,791 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include "lola.h"
+
+/* Standard options */
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Digigram Lola driver.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Digigram Lola driver.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Digigram Lola driver.");
+
+/* Lola-specific options */
+
+/* for instance use always max granularity which is compatible
+ * with all sample rates
+ */
+static int granularity[SNDRV_CARDS] = {
+	[0 ... (SNDRV_CARDS - 1)] = LOLA_GRANULARITY_MAX
+};
+
+/* below a sample_rate of 16kHz the analogue audio quality is NOT excellent */
+static int sample_rate_min[SNDRV_CARDS] = {
+	[0 ... (SNDRV_CARDS - 1) ] = 16000
+};
+
+module_param_array(granularity, int, NULL, 0444);
+MODULE_PARM_DESC(granularity, "Granularity value");
+module_param_array(sample_rate_min, int, NULL, 0444);
+MODULE_PARM_DESC(sample_rate_min, "Minimal sample rate");
+
+/*
+ */
+
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Digigram, Lola}}");
+MODULE_DESCRIPTION("Digigram Lola driver");
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+static int debug;
+module_param(debug, int, 0644);
+#define verbose_debug(fmt, args...)			\
+	do { if (debug > 1) printk(KERN_DEBUG SFX fmt, ##args); } while (0)
+#else
+#define verbose_debug(fmt, args...)
+#endif
+
+/*
+ * pseudo-codec read/write via CORB/RIRB
+ */
+
+static int corb_send_verb(struct lola *chip, unsigned int nid,
+			  unsigned int verb, unsigned int data,
+			  unsigned int extdata)
+{
+	unsigned long flags;
+	int ret = -EIO;
+
+	chip->last_cmd_nid = nid;
+	chip->last_verb = verb;
+	chip->last_data = data;
+	chip->last_extdata = extdata;
+	data |= (nid << 20) | (verb << 8);
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) {
+		unsigned int wp = chip->corb.wp + 1;
+		wp %= LOLA_CORB_ENTRIES;
+		chip->corb.wp = wp;
+		chip->corb.buf[wp * 2] = cpu_to_le32(data);
+		chip->corb.buf[wp * 2 + 1] = cpu_to_le32(extdata);
+		lola_writew(chip, BAR0, CORBWP, wp);
+		chip->rirb.cmds++;
+		smp_wmb();
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return ret;
+}
+
+static void lola_queue_unsol_event(struct lola *chip, unsigned int res,
+				   unsigned int res_ex)
+{
+	lola_update_ext_clock_freq(chip, res);
+}
+
+/* retrieve RIRB entry - called from interrupt handler */
+static void lola_update_rirb(struct lola *chip)
+{
+	unsigned int rp, wp;
+	u32 res, res_ex;
+
+	wp = lola_readw(chip, BAR0, RIRBWP);
+	if (wp == chip->rirb.wp)
+		return;
+	chip->rirb.wp = wp;
+
+	while (chip->rirb.rp != wp) {
+		chip->rirb.rp++;
+		chip->rirb.rp %= LOLA_CORB_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 & LOLA_RIRB_EX_UNSOL_EV)
+			lola_queue_unsol_event(chip, res, res_ex);
+		else if (chip->rirb.cmds) {
+			chip->res = res;
+			chip->res_ex = res_ex;
+			smp_wmb();
+			chip->rirb.cmds--;
+		}
+	}
+}
+
+static int rirb_get_response(struct lola *chip, unsigned int *val,
+			     unsigned int *extval)
+{
+	unsigned long timeout;
+
+ again:
+	timeout = jiffies + msecs_to_jiffies(1000);
+	for (;;) {
+		if (chip->polling_mode) {
+			spin_lock_irq(&chip->reg_lock);
+			lola_update_rirb(chip);
+			spin_unlock_irq(&chip->reg_lock);
+		}
+		if (!chip->rirb.cmds) {
+			*val = chip->res;
+			if (extval)
+				*extval = chip->res_ex;
+			verbose_debug("get_response: %x, %x\n",
+				      chip->res, chip->res_ex);
+			if (chip->res_ex & LOLA_RIRB_EX_ERROR) {
+				printk(KERN_WARNING SFX "RIRB ERROR: "
+				       "NID=%x, verb=%x, data=%x, ext=%x\n",
+				       chip->last_cmd_nid,
+				       chip->last_verb, chip->last_data,
+				       chip->last_extdata);
+				return -EIO;
+			}
+			return 0;
+		}
+		if (time_after(jiffies, timeout))
+			break;
+		udelay(20);
+		cond_resched();
+	}
+	printk(KERN_WARNING SFX "RIRB response error\n");
+	if (!chip->polling_mode) {
+		printk(KERN_WARNING SFX "switching to polling mode\n");
+		chip->polling_mode = 1;
+		goto again;
+	}
+	return -EIO;
+}
+
+/* aynchronous write of a codec verb with data */
+int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb,
+		     unsigned int data, unsigned int extdata)
+{
+	verbose_debug("codec_write NID=%x, verb=%x, data=%x, ext=%x\n",
+		      nid, verb, data, extdata);
+	return corb_send_verb(chip, nid, verb, data, extdata);
+}
+
+/* write a codec verb with data and read the returned status */
+int lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb,
+		    unsigned int data, unsigned int extdata,
+		    unsigned int *val, unsigned int *extval)
+{
+	int err;
+
+	verbose_debug("codec_read NID=%x, verb=%x, data=%x, ext=%x\n",
+		      nid, verb, data, extdata);
+	err = corb_send_verb(chip, nid, verb, data, extdata);
+	if (err < 0)
+		return err;
+	err = rirb_get_response(chip, val, extval);
+	return err;
+}
+
+/* flush all pending codec writes */
+int lola_codec_flush(struct lola *chip)
+{
+	unsigned int tmp;
+	return rirb_get_response(chip, &tmp, NULL);
+}
+
+/*
+ * interrupt handler
+ */
+static irqreturn_t lola_interrupt(int irq, void *dev_id)
+{
+	struct lola *chip = dev_id;
+	unsigned int notify_ins, notify_outs, error_ins, error_outs;
+	int handled = 0;
+	int i;
+
+	notify_ins = notify_outs = error_ins = error_outs = 0;
+	spin_lock(&chip->reg_lock);
+	for (;;) {
+		unsigned int status, in_sts, out_sts;
+		unsigned int reg;
+
+		status = lola_readl(chip, BAR1, DINTSTS);
+		if (!status || status == -1)
+			break;
+
+		in_sts = lola_readl(chip, BAR1, DIINTSTS);
+		out_sts = lola_readl(chip, BAR1, DOINTSTS);
+
+		/* clear Input Interrupts */
+		for (i = 0; in_sts && i < chip->pcm[CAPT].num_streams; i++) {
+			if (!(in_sts & (1 << i)))
+				continue;
+			in_sts &= ~(1 << i);
+			reg = lola_dsd_read(chip, i, STS);
+			if (reg & LOLA_DSD_STS_DESE) /* error */
+				error_ins |= (1 << i);
+			if (reg & LOLA_DSD_STS_BCIS) /* notify */
+				notify_ins |= (1 << i);
+			/* clear */
+			lola_dsd_write(chip, i, STS, reg);
+		}
+
+		/* clear Output Interrupts */
+		for (i = 0; out_sts && i < chip->pcm[PLAY].num_streams; i++) {
+			if (!(out_sts & (1 << i)))
+				continue;
+			out_sts &= ~(1 << i);
+			reg = lola_dsd_read(chip, i + MAX_STREAM_IN_COUNT, STS);
+			if (reg & LOLA_DSD_STS_DESE) /* error */
+				error_outs |= (1 << i);
+			if (reg & LOLA_DSD_STS_BCIS) /* notify */
+				notify_outs |= (1 << i);
+			lola_dsd_write(chip, i + MAX_STREAM_IN_COUNT, STS, reg);
+		}
+
+		if (status & LOLA_DINT_CTRL) {
+			unsigned char rbsts; /* ring status is byte access */
+			rbsts = lola_readb(chip, BAR0, RIRBSTS);
+			rbsts &= LOLA_RIRB_INT_MASK;
+			if (rbsts)
+				lola_writeb(chip, BAR0, RIRBSTS, rbsts);
+			rbsts = lola_readb(chip, BAR0, CORBSTS);
+			rbsts &= LOLA_CORB_INT_MASK;
+			if (rbsts)
+				lola_writeb(chip, BAR0, CORBSTS, rbsts);
+
+			lola_update_rirb(chip);
+		}
+
+		if (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)) {
+			/* clear global fifo error interrupt */
+			lola_writel(chip, BAR1, DINTSTS,
+				    (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)));
+		}
+		handled = 1;
+	}
+	spin_unlock(&chip->reg_lock);
+
+	lola_pcm_update(chip, &chip->pcm[CAPT], notify_ins);
+	lola_pcm_update(chip, &chip->pcm[PLAY], notify_outs);
+
+	return IRQ_RETVAL(handled);
+}
+
+
+/*
+ * controller
+ */
+static int reset_controller(struct lola *chip)
+{
+	unsigned int gctl = lola_readl(chip, BAR0, GCTL);
+	unsigned long end_time;
+
+	if (gctl) {
+		/* to be sure */
+		lola_writel(chip, BAR1, BOARD_MODE, 0);
+		return 0;
+	}
+
+	chip->cold_reset = 1;
+	lola_writel(chip, BAR0, GCTL, LOLA_GCTL_RESET);
+	end_time = jiffies + msecs_to_jiffies(200);
+	do {
+		msleep(1);
+		gctl = lola_readl(chip, BAR0, GCTL);
+		if (gctl)
+			break;
+	} while (time_before(jiffies, end_time));
+	if (!gctl) {
+		printk(KERN_ERR SFX "cannot reset controller\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static void lola_irq_enable(struct lola *chip)
+{
+	unsigned int val;
+
+	/* enalbe all I/O streams */
+	val = (1 << chip->pcm[PLAY].num_streams) - 1;
+	lola_writel(chip, BAR1, DOINTCTL, val);
+	val = (1 << chip->pcm[CAPT].num_streams) - 1;
+	lola_writel(chip, BAR1, DIINTCTL, val);
+
+	/* enable global irqs */
+	val = LOLA_DINT_GLOBAL | LOLA_DINT_CTRL | LOLA_DINT_FIFOERR |
+		LOLA_DINT_MUERR;
+	lola_writel(chip, BAR1, DINTCTL, val);
+}
+
+static void lola_irq_disable(struct lola *chip)
+{
+	lola_writel(chip, BAR1, DINTCTL, 0);
+	lola_writel(chip, BAR1, DIINTCTL, 0);
+	lola_writel(chip, BAR1, DOINTCTL, 0);
+}
+
+static int setup_corb_rirb(struct lola *chip)
+{
+	int err;
+	unsigned char tmp;
+	unsigned long end_time;
+
+	err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+				  snd_dma_pci_data(chip->pci),
+				  PAGE_SIZE, &chip->rb);
+	if (err < 0)
+		return err;
+
+	chip->corb.addr = chip->rb.addr;
+	chip->corb.buf = (u32 *)chip->rb.area;
+	chip->rirb.addr = chip->rb.addr + 2048;
+	chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+
+	/* disable ringbuffer DMAs */
+	lola_writeb(chip, BAR0, RIRBCTL, 0);
+	lola_writeb(chip, BAR0, CORBCTL, 0);
+
+	end_time = jiffies + msecs_to_jiffies(200);
+	do {
+		if (!lola_readb(chip, BAR0, RIRBCTL) &&
+		    !lola_readb(chip, BAR0, CORBCTL))
+			break;
+		msleep(1);
+	} while (time_before(jiffies, end_time));
+
+	/* CORB set up */
+	lola_writel(chip, BAR0, CORBLBASE, (u32)chip->corb.addr);
+	lola_writel(chip, BAR0, CORBUBASE, upper_32_bits(chip->corb.addr));
+	/* set the corb size to 256 entries */
+	lola_writeb(chip, BAR0, CORBSIZE, 0x02);
+	/* set the corb write pointer to 0 */
+	lola_writew(chip, BAR0, CORBWP, 0);
+	/* reset the corb hw read pointer */
+	lola_writew(chip, BAR0, CORBRP, LOLA_RBRWP_CLR);
+	/* enable corb dma */
+	lola_writeb(chip, BAR0, CORBCTL, LOLA_RBCTL_DMA_EN);
+	/* clear flags if set */
+	tmp = lola_readb(chip, BAR0, CORBSTS) & LOLA_CORB_INT_MASK;
+	if (tmp)
+		lola_writeb(chip, BAR0, CORBSTS, tmp);
+	chip->corb.wp = 0;
+
+	/* RIRB set up */
+	lola_writel(chip, BAR0, RIRBLBASE, (u32)chip->rirb.addr);
+	lola_writel(chip, BAR0, RIRBUBASE, upper_32_bits(chip->rirb.addr));
+	/* set the rirb size to 256 entries */
+	lola_writeb(chip, BAR0, RIRBSIZE, 0x02);
+	/* reset the rirb hw write pointer */
+	lola_writew(chip, BAR0, RIRBWP, LOLA_RBRWP_CLR);
+	/* set N=1, get RIRB response interrupt for new entry */
+	lola_writew(chip, BAR0, RINTCNT, 1);
+	/* enable rirb dma and response irq */
+	lola_writeb(chip, BAR0, RIRBCTL, LOLA_RBCTL_DMA_EN | LOLA_RBCTL_IRQ_EN);
+	/* clear flags if set */
+	tmp =  lola_readb(chip, BAR0, RIRBSTS) & LOLA_RIRB_INT_MASK;
+	if (tmp)
+		lola_writeb(chip, BAR0, RIRBSTS, tmp);
+	chip->rirb.rp = chip->rirb.cmds = 0;
+
+	return 0;
+}
+
+static void stop_corb_rirb(struct lola *chip)
+{
+	/* disable ringbuffer DMAs */
+	lola_writeb(chip, BAR0, RIRBCTL, 0);
+	lola_writeb(chip, BAR0, CORBCTL, 0);
+}
+
+static void lola_reset_setups(struct lola *chip)
+{
+	/* update the granularity */
+	lola_set_granularity(chip, chip->granularity, true);
+	/* update the sample clock */
+	lola_set_clock_index(chip, chip->clock.cur_index);
+	/* enable unsolicited events of the clock widget */
+	lola_enable_clock_events(chip);
+	/* update the analog gains */
+	lola_setup_all_analog_gains(chip, CAPT, false); /* input, update */
+	/* update SRC configuration if applicable */
+	lola_set_src_config(chip, chip->input_src_mask, false);
+	/* update the analog outputs */
+	lola_setup_all_analog_gains(chip, PLAY, false); /* output, update */
+}
+
+static int lola_parse_tree(struct lola *chip)
+{
+	unsigned int val;
+	int nid, err;
+
+	err = lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read VENDOR_ID\n");
+		return err;
+	}
+	val >>= 16;
+	if (val != 0x1369) {
+		printk(KERN_ERR SFX "Unknown codec vendor 0x%x\n", val);
+		return -EINVAL;
+	}
+
+	err = lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read FUNCTION_TYPE for 0x%x\n", nid);
+		return err;
+	}
+	if (val != 1) {
+		printk(KERN_ERR SFX "Unknown function type %d\n", val);
+		return -EINVAL;
+	}
+
+	err = lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read SPECCAPS\n");
+		return err;
+	}
+	chip->lola_caps = val;
+	chip->pin[CAPT].num_pins = LOLA_AFG_INPUT_PIN_COUNT(chip->lola_caps);
+	chip->pin[PLAY].num_pins = LOLA_AFG_OUTPUT_PIN_COUNT(chip->lola_caps);
+	snd_printdd(SFX "speccaps=0x%x, pins in=%d, out=%d\n",
+		    chip->lola_caps,
+		    chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins);
+
+	if (chip->pin[CAPT].num_pins > MAX_AUDIO_INOUT_COUNT ||
+	    chip->pin[PLAY].num_pins > MAX_AUDIO_INOUT_COUNT) {
+		printk(KERN_ERR SFX "Invalid Lola-spec caps 0x%x\n", val);
+		return -EINVAL;
+	}
+
+	nid = 0x02;
+	err = lola_init_pcm(chip, CAPT, &nid);
+	if (err < 0)
+		return err;
+	err = lola_init_pcm(chip, PLAY, &nid);
+	if (err < 0)
+		return err;
+
+	err = lola_init_pins(chip, CAPT, &nid);
+	if (err < 0)
+		return err;
+	err = lola_init_pins(chip, PLAY, &nid);
+	if (err < 0)
+		return err;
+
+	if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) {
+		err = lola_init_clock_widget(chip, nid);
+		if (err < 0)
+			return err;
+		nid++;
+	}
+	if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) {
+		err = lola_init_mixer_widget(chip, nid);
+		if (err < 0)
+			return err;
+		nid++;
+	}
+
+	/* enable unsolicited events of the clock widget */
+	err = lola_enable_clock_events(chip);
+	if (err < 0)
+		return err;
+
+	/* if last ResetController was not a ColdReset, we don't know
+	 * the state of the card; initialize here again
+	 */
+	if (!chip->cold_reset) {
+		lola_reset_setups(chip);
+		chip->cold_reset = 1;
+	} else {
+		/* set the granularity if it is not the default */
+		if (chip->granularity != LOLA_GRANULARITY_MIN)
+			lola_set_granularity(chip, chip->granularity, true);
+	}
+
+	return 0;
+}
+
+static void lola_stop_hw(struct lola *chip)
+{
+	stop_corb_rirb(chip);
+	lola_irq_disable(chip);
+}
+
+static void lola_free(struct lola *chip)
+{
+	if (chip->initialized)
+		lola_stop_hw(chip);
+	lola_free_pcm(chip);
+	lola_free_mixer(chip);
+	if (chip->irq >= 0)
+		free_irq(chip->irq, (void *)chip);
+	if (chip->bar[0].remap_addr)
+		iounmap(chip->bar[0].remap_addr);
+	if (chip->bar[1].remap_addr)
+		iounmap(chip->bar[1].remap_addr);
+	if (chip->rb.area)
+		snd_dma_free_pages(&chip->rb);
+	pci_release_regions(chip->pci);
+	pci_disable_device(chip->pci);
+	kfree(chip);
+}
+
+static int lola_dev_free(struct snd_device *device)
+{
+	lola_free(device->device_data);
+	return 0;
+}
+
+static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci,
+				 int dev, struct lola **rchip)
+{
+	struct lola *chip;
+	int err;
+	unsigned int dever;
+	static struct snd_device_ops ops = {
+		.dev_free = lola_dev_free,
+	};
+
+	*rchip = NULL;
+
+	err = pci_enable_device(pci);
+	if (err < 0)
+		return err;
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (!chip) {
+		snd_printk(KERN_ERR SFX "cannot allocate chip\n");
+		pci_disable_device(pci);
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&chip->reg_lock);
+	mutex_init(&chip->open_mutex);
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+
+	chip->granularity = granularity[dev];
+	switch (chip->granularity) {
+	case 8:
+		chip->sample_rate_max = 48000;
+		break;
+	case 16:
+		chip->sample_rate_max = 96000;
+		break;
+	case 32:
+		chip->sample_rate_max = 192000;
+		break;
+	default:
+		snd_printk(KERN_WARNING SFX
+			   "Invalid granularity %d, reset to %d\n",
+			   chip->granularity, LOLA_GRANULARITY_MAX);
+		chip->granularity = LOLA_GRANULARITY_MAX;
+		chip->sample_rate_max = 192000;
+		break;
+	}
+	chip->sample_rate_min = sample_rate_min[dev];
+	if (chip->sample_rate_min > chip->sample_rate_max) {
+		snd_printk(KERN_WARNING SFX
+			   "Invalid sample_rate_min %d, reset to 16000\n",
+			   chip->sample_rate_min);
+		chip->sample_rate_min = 16000;
+	}
+
+	err = pci_request_regions(pci, DRVNAME);
+	if (err < 0) {
+		kfree(chip);
+		pci_disable_device(pci);
+		return err;
+	}
+
+	chip->bar[0].addr = pci_resource_start(pci, 0);
+	chip->bar[0].remap_addr = pci_ioremap_bar(pci, 0);
+	chip->bar[1].addr = pci_resource_start(pci, 2);
+	chip->bar[1].remap_addr = pci_ioremap_bar(pci, 2);
+	if (!chip->bar[0].remap_addr || !chip->bar[1].remap_addr) {
+		snd_printk(KERN_ERR SFX "ioremap error\n");
+		err = -ENXIO;
+		goto errout;
+	}
+
+	pci_set_master(pci);
+
+	err = reset_controller(chip);
+	if (err < 0)
+		goto errout;
+
+	if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED,
+			DRVNAME, chip)) {
+		printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
+		err = -EBUSY;
+		goto errout;
+	}
+	chip->irq = pci->irq;
+	synchronize_irq(chip->irq);
+
+	dever = lola_readl(chip, BAR1, DEVER);
+	chip->pcm[CAPT].num_streams = (dever >> 0) & 0x3ff;
+	chip->pcm[PLAY].num_streams = (dever >> 10) & 0x3ff;
+	chip->version = (dever >> 24) & 0xff;
+	snd_printdd(SFX "streams in=%d, out=%d, version=0x%x\n",
+		    chip->pcm[CAPT].num_streams, chip->pcm[PLAY].num_streams,
+		    chip->version);
+
+	/* Test LOLA_BAR1_DEVER */
+	if (chip->pcm[CAPT].num_streams > MAX_STREAM_IN_COUNT ||
+	    chip->pcm[PLAY].num_streams > MAX_STREAM_OUT_COUNT ||
+	    (!chip->pcm[CAPT].num_streams &&
+	     !chip->pcm[PLAY].num_streams)) {
+		printk(KERN_ERR SFX "invalid DEVER = %x\n", dever);
+		err = -EINVAL;
+		goto errout;
+	}
+
+	err = setup_corb_rirb(chip);
+	if (err < 0)
+		goto errout;
+
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+	if (err < 0) {
+		snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
+		goto errout;
+	}
+
+	strcpy(card->driver, "Lola");
+	strlcpy(card->shortname, "Digigram Lola", sizeof(card->shortname));
+	snprintf(card->longname, sizeof(card->longname),
+		 "%s at 0x%lx irq %i",
+		 card->shortname, chip->bar[0].addr, chip->irq);
+	strcpy(card->mixername, card->shortname);
+
+	lola_irq_enable(chip);
+
+	chip->initialized = 1;
+	*rchip = chip;
+	return 0;
+
+ errout:
+	lola_free(chip);
+	return err;
+}
+
+static int __devinit lola_probe(struct pci_dev *pci,
+				const struct pci_device_id *pci_id)
+{
+	static int dev;
+	struct snd_card *card;
+	struct lola *chip;
+	int err;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+	if (err < 0) {
+		snd_printk(KERN_ERR SFX "Error creating card!\n");
+		return err;
+	}
+
+	snd_card_set_dev(card, &pci->dev);
+
+	err = lola_create(card, pci, dev, &chip);
+	if (err < 0)
+		goto out_free;
+	card->private_data = chip;
+
+	err = lola_parse_tree(chip);
+	if (err < 0)
+		goto out_free;
+
+	err = lola_create_pcm(chip);
+	if (err < 0)
+		goto out_free;
+
+	err = lola_create_mixer(chip);
+	if (err < 0)
+		goto out_free;
+
+	lola_proc_debug_new(chip);
+
+	err = snd_card_register(card);
+	if (err < 0)
+		goto out_free;
+
+	pci_set_drvdata(pci, card);
+	dev++;
+	return err;
+out_free:
+	snd_card_free(card);
+	return err;
+}
+
+static void __devexit lola_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+/* PCI IDs */
+static DEFINE_PCI_DEVICE_TABLE(lola_ids) = {
+	{ PCI_VDEVICE(DIGIGRAM, 0x0001) },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, lola_ids);
+
+/* pci_driver definition */
+static struct pci_driver driver = {
+	.name = DRVNAME,
+	.id_table = lola_ids,
+	.probe = lola_probe,
+	.remove = __devexit_p(lola_remove),
+};
+
+static int __init alsa_card_lola_init(void)
+{
+	return pci_register_driver(&driver);
+}
+
+static void __exit alsa_card_lola_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_lola_init)
+module_exit(alsa_card_lola_exit)

+ 527 - 0
sound/pci/lola/lola.h

@@ -0,0 +1,527 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 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 _LOLA_H
+#define _LOLA_H
+
+#define DRVNAME	"snd-lola"
+#define SFX	DRVNAME ": "
+
+/*
+ * Lola HD Audio Registers BAR0
+ */
+#define LOLA_BAR0_GCAP		0x00
+#define LOLA_BAR0_VMIN		0x02
+#define LOLA_BAR0_VMAJ		0x03
+#define LOLA_BAR0_OUTPAY	0x04
+#define LOLA_BAR0_INPAY		0x06
+#define LOLA_BAR0_GCTL		0x08
+#define LOLA_BAR0_WAKEEN	0x0c
+#define LOLA_BAR0_STATESTS	0x0e
+#define LOLA_BAR0_GSTS		0x10
+#define LOLA_BAR0_OUTSTRMPAY	0x18
+#define LOLA_BAR0_INSTRMPAY	0x1a
+#define LOLA_BAR0_INTCTL	0x20
+#define LOLA_BAR0_INTSTS	0x24
+#define LOLA_BAR0_WALCLK	0x30
+#define LOLA_BAR0_SSYNC		0x38
+
+#define LOLA_BAR0_CORBLBASE	0x40
+#define LOLA_BAR0_CORBUBASE	0x44
+#define LOLA_BAR0_CORBWP	0x48	/* no ULONG access */
+#define LOLA_BAR0_CORBRP	0x4a	/* no ULONG access */
+#define LOLA_BAR0_CORBCTL	0x4c	/* no ULONG access */
+#define LOLA_BAR0_CORBSTS	0x4d	/* UCHAR access only */
+#define LOLA_BAR0_CORBSIZE	0x4e	/* no ULONG access */
+
+#define LOLA_BAR0_RIRBLBASE	0x50
+#define LOLA_BAR0_RIRBUBASE	0x54
+#define LOLA_BAR0_RIRBWP	0x58
+#define LOLA_BAR0_RINTCNT	0x5a	/* no ULONG access */
+#define LOLA_BAR0_RIRBCTL	0x5c
+#define LOLA_BAR0_RIRBSTS	0x5d	/* UCHAR access only */
+#define LOLA_BAR0_RIRBSIZE	0x5e	/* no ULONG access */
+
+#define LOLA_BAR0_ICW		0x60
+#define LOLA_BAR0_IRR		0x64
+#define LOLA_BAR0_ICS		0x68
+#define LOLA_BAR0_DPLBASE	0x70
+#define LOLA_BAR0_DPUBASE	0x74
+
+/* stream register offsets from stream base 0x80 */
+#define LOLA_BAR0_SD0_OFFSET	0x80
+#define LOLA_REG0_SD_CTL	0x00
+#define LOLA_REG0_SD_STS	0x03
+#define LOLA_REG0_SD_LPIB	0x04
+#define LOLA_REG0_SD_CBL	0x08
+#define LOLA_REG0_SD_LVI	0x0c
+#define LOLA_REG0_SD_FIFOW	0x0e
+#define LOLA_REG0_SD_FIFOSIZE	0x10
+#define LOLA_REG0_SD_FORMAT	0x12
+#define LOLA_REG0_SD_BDLPL	0x18
+#define LOLA_REG0_SD_BDLPU	0x1c
+
+/*
+ * Lola Digigram Registers BAR1
+ */
+#define LOLA_BAR1_FPGAVER	0x00
+#define LOLA_BAR1_DEVER		0x04
+#define LOLA_BAR1_UCBMV		0x08
+#define LOLA_BAR1_JTAG		0x0c
+#define LOLA_BAR1_UARTRX	0x10
+#define LOLA_BAR1_UARTTX	0x14
+#define LOLA_BAR1_UARTCR	0x18
+#define LOLA_BAR1_NVRAMVER	0x1c
+#define LOLA_BAR1_CTRLSPI	0x20
+#define LOLA_BAR1_DSPI		0x24
+#define LOLA_BAR1_AISPI		0x28
+#define LOLA_BAR1_GRAN		0x2c
+
+#define LOLA_BAR1_DINTCTL	0x80
+#define LOLA_BAR1_DIINTCTL	0x84
+#define LOLA_BAR1_DOINTCTL	0x88
+#define LOLA_BAR1_LRC		0x90
+#define LOLA_BAR1_DINTSTS	0x94
+#define LOLA_BAR1_DIINTSTS	0x98
+#define LOLA_BAR1_DOINTSTS	0x9c
+
+#define LOLA_BAR1_DSD0_OFFSET	0xa0
+#define LOLA_BAR1_DSD_SIZE	0x18
+
+#define LOLA_BAR1_DSDnSTS       0x00
+#define LOLA_BAR1_DSDnLPIB      0x04
+#define LOLA_BAR1_DSDnCTL       0x08
+#define LOLA_BAR1_DSDnLVI       0x0c
+#define LOLA_BAR1_DSDnBDPL      0x10
+#define LOLA_BAR1_DSDnBDPU      0x14
+
+#define LOLA_BAR1_SSYNC		0x03e8
+
+#define LOLA_BAR1_BOARD_CTRL	0x0f00
+#define LOLA_BAR1_BOARD_MODE	0x0f02
+
+#define LOLA_BAR1_SOURCE_GAIN_ENABLE		0x1000
+#define LOLA_BAR1_DEST00_MIX_GAIN_ENABLE	0x1004
+#define LOLA_BAR1_DEST31_MIX_GAIN_ENABLE	0x1080
+#define LOLA_BAR1_SOURCE00_01_GAIN		0x1084
+#define LOLA_BAR1_SOURCE30_31_GAIN		0x10c0
+#define LOLA_BAR1_SOURCE_GAIN(src) \
+	(LOLA_BAR1_SOURCE00_01_GAIN + (src) * 2)
+#define LOLA_BAR1_DEST00_MIX00_01_GAIN		0x10c4
+#define LOLA_BAR1_DEST00_MIX30_31_GAIN		0x1100
+#define LOLA_BAR1_DEST01_MIX00_01_GAIN		0x1104
+#define LOLA_BAR1_DEST01_MIX30_31_GAIN		0x1140
+#define LOLA_BAR1_DEST31_MIX00_01_GAIN		0x1884
+#define LOLA_BAR1_DEST31_MIX30_31_GAIN		0x18c0
+#define LOLA_BAR1_MIX_GAIN(dest, mix) \
+	(LOLA_BAR1_DEST00_MIX00_01_GAIN + (dest) * 0x40 + (mix) * 2)
+#define LOLA_BAR1_ANALOG_CLIP_IN		0x18c4
+#define LOLA_BAR1_PEAKMETERS_SOURCE00_01	0x18c8
+#define LOLA_BAR1_PEAKMETERS_SOURCE30_31	0x1904
+#define LOLA_BAR1_PEAKMETERS_SOURCE(src) \
+	(LOLA_BAR1_PEAKMETERS_SOURCE00_01 + (src) * 2)
+#define LOLA_BAR1_PEAKMETERS_DEST00_01		0x1908
+#define LOLA_BAR1_PEAKMETERS_DEST30_31		0x1944
+#define LOLA_BAR1_PEAKMETERS_DEST(dest) \
+	(LOLA_BAR1_PEAKMETERS_DEST00_01 + (dest) * 2)
+#define LOLA_BAR1_PEAKMETERS_AGC00_01		0x1948
+#define LOLA_BAR1_PEAKMETERS_AGC14_15		0x1964
+#define LOLA_BAR1_PEAKMETERS_AGC(x) \
+	(LOLA_BAR1_PEAKMETERS_AGC00_01 + (x) * 2)
+
+/* GCTL reset bit */
+#define LOLA_GCTL_RESET		(1 << 0)
+/* GCTL unsolicited response enable bit */
+#define LOLA_GCTL_UREN		(1 << 8)
+
+/* CORB/RIRB control, read/write pointer */
+#define LOLA_RBCTL_DMA_EN	0x02	/* enable DMA */
+#define LOLA_RBCTL_IRQ_EN	0x01	/* enable IRQ */
+#define LOLA_RBRWP_CLR		0x8000	/* read/write pointer clear */
+
+#define LOLA_RIRB_EX_UNSOL_EV	0x40000000
+#define LOLA_RIRB_EX_ERROR	0x80000000
+
+/* CORB int mask: CMEI[0] */
+#define LOLA_CORB_INT_CMEI	0x01
+#define LOLA_CORB_INT_MASK	LOLA_CORB_INT_CMEI
+
+/* RIRB int mask: overrun[2], response[0] */
+#define LOLA_RIRB_INT_RESPONSE	0x01
+#define LOLA_RIRB_INT_OVERRUN	0x04
+#define LOLA_RIRB_INT_MASK	(LOLA_RIRB_INT_RESPONSE | LOLA_RIRB_INT_OVERRUN)
+
+/* DINTCTL and DINTSTS */
+#define LOLA_DINT_GLOBAL	0x80000000 /* global interrupt enable bit */
+#define LOLA_DINT_CTRL		0x40000000 /* controller interrupt enable bit */
+#define LOLA_DINT_FIFOERR	0x20000000 /* global fifo error enable bit */
+#define LOLA_DINT_MUERR		0x10000000 /* global microcontroller underrun error */
+
+/* DSDnCTL bits */
+#define LOLA_DSD_CTL_SRST	0x01	/* stream reset bit */
+#define LOLA_DSD_CTL_SRUN	0x02	/* stream DMA start bit */
+#define LOLA_DSD_CTL_IOCE	0x04	/* interrupt on completion enable */
+#define LOLA_DSD_CTL_DEIE	0x10	/* descriptor error interrupt enable */
+#define LOLA_DSD_CTL_VLRCV	0x20	/* valid LRCountValue information in bits 8..31 */
+#define LOLA_LRC_MASK		0xffffff00
+
+/* DSDnSTS */
+#define LOLA_DSD_STS_BCIS	0x04	/* buffer completion interrupt status */
+#define LOLA_DSD_STS_DESE	0x10	/* descriptor error interrupt */
+#define LOLA_DSD_STS_FIFORDY	0x20	/* fifo ready */
+
+#define LOLA_CORB_ENTRIES	256
+
+#define MAX_STREAM_IN_COUNT	16
+#define MAX_STREAM_OUT_COUNT	16
+#define MAX_STREAM_COUNT	16
+#define MAX_PINS		MAX_STREAM_COUNT
+#define MAX_STREAM_BUFFER_COUNT	16
+#define MAX_AUDIO_INOUT_COUNT	16
+
+#define LOLA_CLOCK_TYPE_INTERNAL    0
+#define LOLA_CLOCK_TYPE_AES         1
+#define LOLA_CLOCK_TYPE_AES_SYNC    2
+#define LOLA_CLOCK_TYPE_WORDCLOCK   3
+#define LOLA_CLOCK_TYPE_ETHERSOUND  4
+#define LOLA_CLOCK_TYPE_VIDEO       5
+
+#define LOLA_CLOCK_FORMAT_NONE      0
+#define LOLA_CLOCK_FORMAT_NTSC      1
+#define LOLA_CLOCK_FORMAT_PAL       2
+
+#define MAX_SAMPLE_CLOCK_COUNT  48
+
+/* parameters used with mixer widget's mixer capabilities */
+#define LOLA_PEAK_METER_CAN_AGC_MASK		1
+#define LOLA_PEAK_METER_CAN_ANALOG_CLIP_MASK	2
+
+struct lola_bar {
+	unsigned long addr;
+	void __iomem *remap_addr;
+};
+
+/* CORB/RIRB */
+struct lola_rb {
+	u32 *buf;		/* CORB/RIRB buffer, 8 byte per each entry */
+	dma_addr_t addr;	/* physical address of CORB/RIRB buffer */
+	unsigned short rp, wp;	/* read/write pointers */
+	int cmds;		/* number of pending requests */
+};
+
+/* Pin widget setup */
+struct lola_pin {
+	unsigned int nid;
+	bool is_analog;
+	unsigned int amp_mute;
+	unsigned int amp_step_size;
+	unsigned int amp_num_steps;
+	unsigned int amp_offset;
+	unsigned int max_level;
+	unsigned int config_default_reg;
+	unsigned int fixed_gain_list_len;
+	unsigned int cur_gain_step;
+};
+
+struct lola_pin_array {
+	unsigned int num_pins;
+	unsigned int num_analog_pins;
+	struct lola_pin pins[MAX_PINS];
+};
+
+/* Clock widget setup */
+struct lola_sample_clock {
+	unsigned int type;
+	unsigned int format;
+	unsigned int freq;
+};
+
+struct lola_clock_widget {
+	unsigned int nid;
+	unsigned int items;
+	unsigned int cur_index;
+	unsigned int cur_freq;
+	bool cur_valid;
+	struct lola_sample_clock sample_clock[MAX_SAMPLE_CLOCK_COUNT];
+	unsigned int idx_lookup[MAX_SAMPLE_CLOCK_COUNT];
+};
+
+#define LOLA_MIXER_DIM      32
+struct lola_mixer_array {
+	u32 src_gain_enable;
+	u32 dest_mix_gain_enable[LOLA_MIXER_DIM];
+	u16 src_gain[LOLA_MIXER_DIM];
+	u16 dest_mix_gain[LOLA_MIXER_DIM][LOLA_MIXER_DIM];
+};
+
+/* Mixer widget setup */
+struct lola_mixer_widget {
+	unsigned int nid;
+	unsigned int caps;
+	struct lola_mixer_array __user *array;
+	struct lola_mixer_array *array_saved;
+	unsigned int src_stream_outs;
+	unsigned int src_phys_ins;
+	unsigned int dest_stream_ins;
+	unsigned int dest_phys_outs;
+	unsigned int src_stream_out_ofs;
+	unsigned int dest_phys_out_ofs;
+	unsigned int src_mask;
+	unsigned int dest_mask;
+};
+
+/* Audio stream */
+struct lola_stream {
+	unsigned int nid;	/* audio widget NID */
+	unsigned int index;	/* array index */
+	unsigned int dsd;	/* DSD index */
+	bool can_float;
+	struct snd_pcm_substream *substream; /* assigned PCM substream */
+	struct lola_stream *master;	/* master stream (for multi-channel) */
+
+	/* buffer setup */
+	unsigned int bufsize;
+	unsigned int period_bytes;
+	unsigned int frags;
+
+	/* format + channel setup */
+	unsigned int format_verb;
+
+	/* flags */
+	unsigned int opened:1;
+	unsigned int prepared:1;
+	unsigned int paused:1;
+	unsigned int running:1;
+};
+
+#define PLAY	SNDRV_PCM_STREAM_PLAYBACK
+#define CAPT	SNDRV_PCM_STREAM_CAPTURE
+
+struct lola_pcm {
+	unsigned int num_streams;
+	struct snd_dma_buffer bdl; /* BDL buffer */
+	struct lola_stream streams[MAX_STREAM_COUNT];
+};
+
+/* card instance */
+struct lola {
+	struct snd_card *card;
+	struct pci_dev *pci;
+
+	/* pci resources */
+	struct lola_bar bar[2];
+	int irq;
+
+	/* locks */
+	spinlock_t reg_lock;
+	struct mutex open_mutex;
+
+	/* CORB/RIRB */
+	struct lola_rb corb;
+	struct lola_rb rirb;
+	unsigned int res, res_ex;	/* last read values */
+	/* last command (for debugging) */
+	unsigned int last_cmd_nid, last_verb, last_data, last_extdata;
+
+	/* CORB/RIRB buffers */
+	struct snd_dma_buffer rb;
+
+	/* unsolicited events */
+	unsigned int last_unsol_res;
+
+	/* streams */
+	struct lola_pcm pcm[2];
+
+	/* input src */
+	unsigned int input_src_caps_mask;
+	unsigned int input_src_mask;
+
+	/* pins */
+	struct lola_pin_array pin[2];
+
+	/* clock */
+	struct lola_clock_widget clock;
+	int ref_count_rate;
+	unsigned int sample_rate;
+
+	/* mixer */
+	struct lola_mixer_widget mixer;
+
+	/* hw info */
+	unsigned int version;
+	unsigned int lola_caps;
+
+	/* parameters */
+	unsigned int granularity;
+	unsigned int sample_rate_min;
+	unsigned int sample_rate_max;
+
+	/* flags */
+	unsigned int initialized:1;
+	unsigned int cold_reset:1;
+	unsigned int polling_mode:1;
+
+	/* for debugging */
+	unsigned int debug_res;
+	unsigned int debug_res_ex;
+};
+
+#define BAR0	0
+#define BAR1	1
+
+/* Helper macros */
+#define lola_readl(chip, idx, name) \
+	readl((chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_readw(chip, idx, name) \
+	readw((chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_readb(chip, idx, name) \
+	readb((chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_writel(chip, idx, name, val) \
+	writel((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_writew(chip, idx, name, val) \
+	writew((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+#define lola_writeb(chip, idx, name, val) \
+	writeb((val), (chip)->bar[idx].remap_addr + LOLA_##idx##_##name)
+
+#define lola_dsd_read(chip, dsd, name) \
+	readl((chip)->bar[BAR1].remap_addr + LOLA_BAR1_DSD0_OFFSET + \
+	      (LOLA_BAR1_DSD_SIZE * (dsd)) + LOLA_BAR1_DSDn##name)
+#define lola_dsd_write(chip, dsd, name, val) \
+	writel((val), (chip)->bar[BAR1].remap_addr + LOLA_BAR1_DSD0_OFFSET + \
+	       (LOLA_BAR1_DSD_SIZE * (dsd)) + LOLA_BAR1_DSDn##name)
+
+/* GET verbs HDAudio */
+#define LOLA_VERB_GET_STREAM_FORMAT		0xa00
+#define LOLA_VERB_GET_AMP_GAIN_MUTE		0xb00
+#define LOLA_VERB_PARAMETERS			0xf00
+#define LOLA_VERB_GET_POWER_STATE		0xf05
+#define LOLA_VERB_GET_CONV			0xf06
+#define LOLA_VERB_GET_UNSOLICITED_RESPONSE	0xf08
+#define LOLA_VERB_GET_DIGI_CONVERT_1		0xf0d
+#define LOLA_VERB_GET_CONFIG_DEFAULT		0xf1c
+#define LOLA_VERB_GET_SUBSYSTEM_ID		0xf20
+/* GET verbs Digigram */
+#define LOLA_VERB_GET_FIXED_GAIN		0xfc0
+#define LOLA_VERB_GET_GAIN_SELECT		0xfc1
+#define LOLA_VERB_GET_MAX_LEVEL			0xfc2
+#define LOLA_VERB_GET_CLOCK_LIST		0xfc3
+#define LOLA_VERB_GET_CLOCK_SELECT		0xfc4
+#define LOLA_VERB_GET_CLOCK_STATUS		0xfc5
+
+/* SET verbs HDAudio */
+#define LOLA_VERB_SET_STREAM_FORMAT		0x200
+#define LOLA_VERB_SET_AMP_GAIN_MUTE		0x300
+#define LOLA_VERB_SET_POWER_STATE		0x705
+#define LOLA_VERB_SET_CHANNEL_STREAMID		0x706
+#define LOLA_VERB_SET_UNSOLICITED_ENABLE	0x708
+#define LOLA_VERB_SET_DIGI_CONVERT_1		0x70d
+/* SET verbs Digigram */
+#define LOLA_VERB_SET_GAIN_SELECT		0xf81
+#define LOLA_VERB_SET_CLOCK_SELECT		0xf84
+#define LOLA_VERB_SET_GRANULARITY_STEPS		0xf86
+#define LOLA_VERB_SET_SOURCE_GAIN		0xf87
+#define LOLA_VERB_SET_MIX_GAIN			0xf88
+#define LOLA_VERB_SET_DESTINATION_GAIN		0xf89
+#define LOLA_VERB_SET_SRC			0xf8a
+
+/* Parameter IDs used with LOLA_VERB_PARAMETERS */
+#define LOLA_PAR_VENDOR_ID			0x00
+#define LOLA_PAR_FUNCTION_TYPE			0x05
+#define LOLA_PAR_AUDIO_WIDGET_CAP		0x09
+#define LOLA_PAR_PCM				0x0a
+#define LOLA_PAR_STREAM_FORMATS			0x0b
+#define LOLA_PAR_PIN_CAP			0x0c
+#define LOLA_PAR_AMP_IN_CAP			0x0d
+#define LOLA_PAR_CONNLIST_LEN			0x0e
+#define LOLA_PAR_POWER_STATE			0x0f
+#define LOLA_PAR_GPIO_CAP			0x11
+#define LOLA_PAR_AMP_OUT_CAP			0x12
+#define LOLA_PAR_SPECIFIC_CAPS			0x80
+#define LOLA_PAR_FIXED_GAIN_LIST		0x81
+
+/* extract results of LOLA_PAR_SPECIFIC_CAPS */
+#define LOLA_AFG_MIXER_WIDGET_PRESENT(res)	((res & (1 << 21)) != 0)
+#define LOLA_AFG_CLOCK_WIDGET_PRESENT(res)	((res & (1 << 20)) != 0)
+#define LOLA_AFG_INPUT_PIN_COUNT(res)		((res >> 10) & 0x2ff)
+#define LOLA_AFG_OUTPUT_PIN_COUNT(res)		((res) & 0x2ff)
+
+/* extract results of LOLA_PAR_AMP_IN_CAP / LOLA_PAR_AMP_OUT_CAP */
+#define LOLA_AMP_MUTE_CAPABLE(res)		((res & (1 << 31)) != 0)
+#define LOLA_AMP_STEP_SIZE(res)			((res >> 24) & 0x7f)
+#define LOLA_AMP_NUM_STEPS(res)			((res >> 12) & 0x3ff)
+#define LOLA_AMP_OFFSET(res)			((res) & 0x3ff)
+
+#define LOLA_GRANULARITY_MIN		8
+#define LOLA_GRANULARITY_MAX		32
+#define LOLA_GRANULARITY_STEP		8
+
+/* parameters used with unsolicited command/response */
+#define LOLA_UNSOLICITED_TAG_MASK	0x3f
+#define LOLA_UNSOLICITED_TAG		0x1a
+#define LOLA_UNSOLICITED_ENABLE		0x80
+#define LOLA_UNSOL_RESP_TAG_OFFSET	26
+
+/* count values in the Vendor Specific Mixer Widget's Audio Widget Capabilities */
+#define LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(res)   ((res >> 2) & 0x1f)
+#define LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(res)  ((res >> 7) & 0x1f)
+
+int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb,
+		     unsigned int data, unsigned int extdata);
+int lola_codec_read(struct lola *chip, unsigned int nid, unsigned int verb,
+		    unsigned int data, unsigned int extdata,
+		    unsigned int *val, unsigned int *extval);
+int lola_codec_flush(struct lola *chip);
+#define lola_read_param(chip, nid, param, val) \
+	lola_codec_read(chip, nid, LOLA_VERB_PARAMETERS, param, 0, val, NULL)
+
+/* PCM */
+int lola_create_pcm(struct lola *chip);
+void lola_free_pcm(struct lola *chip);
+int lola_init_pcm(struct lola *chip, int dir, int *nidp);
+void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits);
+
+/* clock */
+int lola_init_clock_widget(struct lola *chip, int nid);
+int lola_set_granularity(struct lola *chip, unsigned int val, bool force);
+int lola_enable_clock_events(struct lola *chip);
+int lola_set_clock_index(struct lola *chip, unsigned int idx);
+int lola_set_clock(struct lola *chip, int idx);
+int lola_set_sample_rate(struct lola *chip, int rate);
+bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val);
+unsigned int lola_sample_rate_convert(unsigned int coded);
+
+/* mixer */
+int lola_init_pins(struct lola *chip, int dir, int *nidp);
+int lola_init_mixer_widget(struct lola *chip, int nid);
+void lola_free_mixer(struct lola *chip);
+int lola_create_mixer(struct lola *chip);
+int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute);
+void lola_save_mixer(struct lola *chip);
+void lola_restore_mixer(struct lola *chip);
+int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update);
+
+/* proc */
+#ifdef CONFIG_SND_DEBUG
+void lola_proc_debug_new(struct lola *chip);
+#else
+#define lola_proc_debug_new(chip)
+#endif
+
+#endif /* _LOLA_H */

+ 323 - 0
sound/pci/lola/lola_clock.c

@@ -0,0 +1,323 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "lola.h"
+
+unsigned int lola_sample_rate_convert(unsigned int coded)
+{
+	unsigned int freq;
+
+	/* base frequency */
+	switch (coded & 0x3) {
+	case 0:     freq = 48000; break;
+	case 1:     freq = 44100; break;
+	case 2:     freq = 32000; break;
+	default:    return 0;   /* error */
+	}
+
+	/* multiplier / devisor */
+	switch (coded & 0x1c) {
+	case (0 << 2):    break;
+	case (4 << 2):    break;
+	case (1 << 2):    freq *= 2; break;
+	case (2 << 2):    freq *= 4; break;
+	case (5 << 2):    freq /= 2; break;
+	case (6 << 2):    freq /= 4; break;
+	default:        return 0;   /* error */
+	}
+
+	/* ajustement */
+	switch (coded & 0x60) {
+	case (0 << 5):    break;
+	case (1 << 5):    freq = (freq * 999) / 1000; break;
+	case (2 << 5):    freq = (freq * 1001) / 1000; break;
+	default:        return 0;   /* error */
+	}
+	return freq;
+}
+
+/*
+ * Granualrity
+ */
+
+#define LOLA_MAXFREQ_AT_GRANULARITY_MIN         48000
+#define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX   96000
+
+static bool check_gran_clock_compatibility(struct lola *chip,
+					   unsigned int val,
+					   unsigned int freq)
+{
+	if (!chip->granularity)
+		return true;
+
+	if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX ||
+	    (val % LOLA_GRANULARITY_STEP) != 0)
+		return false;
+
+	if (val == LOLA_GRANULARITY_MIN) {
+		if (freq > LOLA_MAXFREQ_AT_GRANULARITY_MIN)
+			return false;
+	} else if (val < LOLA_GRANULARITY_MAX) {
+		if (freq > LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX)
+			return false;
+	}
+	return true;
+}
+
+int lola_set_granularity(struct lola *chip, unsigned int val, bool force)
+{
+	int err;
+
+	if (!force) {
+		if (val == chip->granularity)
+			return 0;
+#if 0
+		/* change Gran only if there are no streams allocated ! */
+		if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask)
+			return -EBUSY;
+#endif
+		if (!check_gran_clock_compatibility(chip, val,
+						    chip->clock.cur_freq))
+			return -EINVAL;
+	}
+
+	chip->granularity = val;
+	val /= LOLA_GRANULARITY_STEP;
+
+	/* audio function group */
+	err = lola_codec_write(chip, 1, LOLA_VERB_SET_GRANULARITY_STEPS,
+			       val, 0);
+	if (err < 0)
+		return err;
+	/* this can be a very slow function !!! */
+	usleep_range(400 * val, 20000);
+	return lola_codec_flush(chip);
+}
+
+/*
+ * Clock widget handling
+ */
+
+int __devinit lola_init_clock_widget(struct lola *chip, int nid)
+{
+	unsigned int val;
+	int i, j, nitems, nb_verbs, idx, idx_list;
+	int err;
+
+	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+		return err;
+	}
+
+	if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
+		snd_printdd("No valid clock widget\n");
+		return 0;
+	}
+
+	chip->clock.nid = nid;
+	chip->clock.items = val & 0xff;
+	snd_printdd("clock_list nid=%x, entries=%d\n", nid,
+		    chip->clock.items);
+	if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
+		printk(KERN_ERR SFX "CLOCK_LIST too big: %d\n",
+		       chip->clock.items);
+		return -EINVAL;
+	}
+
+	nitems = chip->clock.items;
+	nb_verbs = (nitems + 3) / 4;
+	idx = 0;
+	idx_list = 0;
+	for (i = 0; i < nb_verbs; i++) {
+		unsigned int res_ex;
+		unsigned short items[4];
+
+		err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
+				      idx, 0, &val, &res_ex);
+		if (err < 0) {
+			printk(KERN_ERR SFX "Can't read CLOCK_LIST\n");
+			return -EINVAL;
+		}
+
+		items[0] = val & 0xfff;
+		items[1] = (val >> 16) & 0xfff;
+		items[2] = res_ex & 0xfff;
+		items[3] = (res_ex >> 16) & 0xfff;
+
+		for (j = 0; j < 4; j++) {
+			unsigned char type = items[j] >> 8;
+			unsigned int freq = items[j] & 0xff;
+			int format = LOLA_CLOCK_FORMAT_NONE;
+			bool add_clock = true;
+			if (type == LOLA_CLOCK_TYPE_INTERNAL) {
+				freq = lola_sample_rate_convert(freq);
+				if (freq < chip->sample_rate_min)
+					add_clock = false;
+				else if (freq == 48000) {
+					chip->clock.cur_index = idx_list;
+					chip->clock.cur_freq = 48000;
+					chip->clock.cur_valid = true;
+				}
+			} else if (type == LOLA_CLOCK_TYPE_VIDEO) {
+				freq = lola_sample_rate_convert(freq);
+				if (freq < chip->sample_rate_min)
+					add_clock = false;
+				/* video clock has a format (0:NTSC, 1:PAL)*/
+				if (items[j] & 0x80)
+					format = LOLA_CLOCK_FORMAT_NTSC;
+				else
+					format = LOLA_CLOCK_FORMAT_PAL;
+			}
+			if (add_clock) {
+				struct lola_sample_clock *sc;
+				sc = &chip->clock.sample_clock[idx_list];
+				sc->type = type;
+				sc->format = format;
+				sc->freq = freq;
+				/* keep the index used with the board */
+				chip->clock.idx_lookup[idx_list] = idx;
+				idx_list++;
+			} else {
+				chip->clock.items--;
+			}
+			if (++idx >= nitems)
+				break;
+		}
+	}
+	return 0;
+}
+
+/* enable unsolicited events of the clock widget */
+int lola_enable_clock_events(struct lola *chip)
+{
+	unsigned int res;
+	int err;
+
+	err = lola_codec_read(chip, chip->clock.nid,
+			      LOLA_VERB_SET_UNSOLICITED_ENABLE,
+			      LOLA_UNSOLICITED_ENABLE | LOLA_UNSOLICITED_TAG,
+			      0, &res, NULL);
+	if (err < 0)
+		return err;
+	if (res) {
+		printk(KERN_WARNING SFX "error in enable_clock_events %d\n",
+		       res);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int lola_set_clock_index(struct lola *chip, unsigned int idx)
+{
+	unsigned int res;
+	int err;
+
+	err = lola_codec_read(chip, chip->clock.nid,
+			      LOLA_VERB_SET_CLOCK_SELECT,
+			      chip->clock.idx_lookup[idx],
+			      0, &res, NULL);
+	if (err < 0)
+		return err;
+	if (res) {
+		printk(KERN_WARNING SFX "error in set_clock %d\n", res);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val)
+{
+	unsigned int tag;
+
+	/* the current EXTERNAL clock information gets updated by interrupt
+	 * with an unsolicited response
+	 */
+	if (!val)
+		return false;
+	tag = (val >> LOLA_UNSOL_RESP_TAG_OFFSET) & LOLA_UNSOLICITED_TAG_MASK;
+	if (tag != LOLA_UNSOLICITED_TAG)
+		return false;
+
+	/* only for current = external clocks */
+	if (chip->clock.sample_clock[chip->clock.cur_index].type !=
+	    LOLA_CLOCK_TYPE_INTERNAL) {
+		chip->clock.cur_freq = lola_sample_rate_convert(val & 0x7f);
+		chip->clock.cur_valid = (val & 0x100) != 0;
+	}
+	return true;
+}
+
+int lola_set_clock(struct lola *chip, int idx)
+{
+	int freq = 0;
+	bool valid = false;
+
+	if (idx == chip->clock.cur_index) {
+		/* current clock is allowed */
+		freq = chip->clock.cur_freq;
+		valid = chip->clock.cur_valid;
+	} else if (chip->clock.sample_clock[idx].type ==
+		   LOLA_CLOCK_TYPE_INTERNAL) {
+		/* internal clocks allowed */
+		freq = chip->clock.sample_clock[idx].freq;
+		valid = true;
+	}
+
+	if (!freq || !valid)
+		return -EINVAL;
+
+	if (!check_gran_clock_compatibility(chip, chip->granularity, freq))
+		return -EINVAL;
+
+	if (idx != chip->clock.cur_index) {
+		int err = lola_set_clock_index(chip, idx);
+		if (err < 0)
+			return err;
+		/* update new settings */
+		chip->clock.cur_index = idx;
+		chip->clock.cur_freq = freq;
+		chip->clock.cur_valid = true;
+	}
+	return 0;
+}
+
+int lola_set_sample_rate(struct lola *chip, int rate)
+{
+	int i;
+
+	if (chip->clock.cur_freq == rate && chip->clock.cur_valid)
+		return 0;
+	/* search for new dwClockIndex */
+	for (i = 0; i < chip->clock.items; i++) {
+		if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL &&
+		    chip->clock.sample_clock[i].freq == rate)
+			break;
+	}
+	if (i >= chip->clock.items)
+		return -EINVAL;
+	return lola_set_clock(chip, i);
+}
+

+ 839 - 0
sound/pci/lola/lola_mixer.c

@@ -0,0 +1,839 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "lola.h"
+
+static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin,
+				   int dir, int nid)
+{
+	unsigned int val;
+	int err;
+
+	pin->nid = nid;
+	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+		return err;
+	}
+	val &= 0x00f00fff; /* test TYPE and bits 0..11 */
+	if (val == 0x00400200)    /* Type = 4, Digital = 1 */
+		pin->is_analog = false;
+	else if (val == 0x0040000a && dir == CAPT) /* Dig=0, InAmp/ovrd */
+		pin->is_analog = true;
+	else if (val == 0x0040000c && dir == PLAY) /* Dig=0, OutAmp/ovrd */
+		pin->is_analog = true;
+	else {
+		printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", val, nid);
+		return -EINVAL;
+	}
+
+	/* analog parameters only following, so continue in case of Digital pin
+	 */
+	if (!pin->is_analog)
+		return 0;
+
+	if (dir == PLAY)
+		err = lola_read_param(chip, nid, LOLA_PAR_AMP_OUT_CAP, &val);
+	else
+		err = lola_read_param(chip, nid, LOLA_PAR_AMP_IN_CAP, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read AMP-caps for 0x%x\n", nid);
+		return err;
+	}
+
+	pin->amp_mute = LOLA_AMP_MUTE_CAPABLE(val);
+	pin->amp_step_size = LOLA_AMP_STEP_SIZE(val);
+	pin->amp_num_steps = LOLA_AMP_NUM_STEPS(val);
+	if (pin->amp_num_steps) {
+		/* zero as mute state */
+		pin->amp_num_steps++;
+		pin->amp_step_size++;
+	}
+	pin->amp_offset = LOLA_AMP_OFFSET(val);
+
+	err = lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val,
+			      NULL);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't get MAX_LEVEL 0x%x\n", nid);
+		return err;
+	}
+	pin->max_level = val & 0x3ff;   /* 10 bits */
+
+	pin->config_default_reg = 0;
+	pin->fixed_gain_list_len = 0;
+	pin->cur_gain_step = 0;
+
+	return 0;
+}
+
+int __devinit lola_init_pins(struct lola *chip, int dir, int *nidp)
+{
+	int i, err, nid;
+	nid = *nidp;
+	for (i = 0; i < chip->pin[dir].num_pins; i++, nid++) {
+		err = lola_init_pin(chip, &chip->pin[dir].pins[i], dir, nid);
+		if (err < 0)
+			return err;
+		if (chip->pin[dir].pins[i].is_analog)
+			chip->pin[dir].num_analog_pins++;
+	}
+	*nidp = nid;
+	return 0;
+}
+
+void lola_free_mixer(struct lola *chip)
+{
+	if (chip->mixer.array_saved)
+		vfree(chip->mixer.array_saved);
+}
+
+int __devinit lola_init_mixer_widget(struct lola *chip, int nid)
+{
+	unsigned int val;
+	int err;
+
+	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+		return err;
+	}
+
+	if ((val & 0xfff00000) != 0x02f00000) { /* test SubType and Type */
+		snd_printdd("No valid mixer widget\n");
+		return 0;
+	}
+
+	chip->mixer.nid = nid;
+	chip->mixer.caps = val;
+	chip->mixer.array = (struct lola_mixer_array __iomem *)
+		(chip->bar[BAR1].remap_addr + LOLA_BAR1_SOURCE_GAIN_ENABLE);
+
+	/* reserve memory to copy mixer data for sleep mode transitions */
+	chip->mixer.array_saved = vmalloc(sizeof(struct lola_mixer_array));
+
+	/* mixer matrix sources are physical input data and play streams */
+	chip->mixer.src_stream_outs = chip->pcm[PLAY].num_streams;
+	chip->mixer.src_phys_ins = chip->pin[CAPT].num_pins;
+
+	/* mixer matrix destinations are record streams and physical output */
+	chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams;
+	chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins;
+
+	/* mixer matrix can have unused areas between PhysIn and
+	 * Play or Record and PhysOut zones
+	 */
+	chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins +
+		LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val);
+	chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins +
+		LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(val);
+
+	/* example : MixerMatrix of LoLa881
+	 * 0-------8------16-------8------16
+	 * |       |       |       |       |
+	 * | INPUT |       | INPUT |       |
+	 * | ->    |unused | ->    |unused |
+	 * | RECORD|       | OUTPUT|       |
+	 * |       |       |       |       |
+	 * 8--------------------------------
+	 * |       |       |       |       |
+	 * |       |       |       |       |
+	 * |unused |unused |unused |unused |
+	 * |       |       |       |       |
+	 * |       |       |       |       |
+	 * 16-------------------------------
+	 * |       |       |       |       |
+	 * | PLAY  |       | PLAY  |       |
+	 * |  ->   |unused | ->    |unused |
+	 * | RECORD|       | OUTPUT|       |
+	 * |       |       |       |       |
+	 * 8--------------------------------
+	 * |       |       |       |       |
+	 * |       |       |       |       |
+	 * |unused |unused |unused |unused |
+	 * |       |       |       |       |
+	 * |       |       |       |       |
+	 * 16-------------------------------
+	 */
+	if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT ||
+	    chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) {
+		printk(KERN_ERR SFX "Invalid mixer widget size\n");
+		return -EINVAL;
+	}
+
+	chip->mixer.src_mask = ((1U << chip->mixer.src_phys_ins) - 1) |
+		(((1U << chip->mixer.src_stream_outs) - 1)
+		 << chip->mixer.src_stream_out_ofs);
+	chip->mixer.dest_mask = ((1U << chip->mixer.dest_stream_ins) - 1) |
+		(((1U << chip->mixer.dest_phys_outs) - 1)
+		 << chip->mixer.dest_phys_out_ofs);
+
+	return 0;
+}
+
+static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id,
+				   unsigned short gain, bool on)
+{
+	unsigned int oldval, val;
+
+	if (!(chip->mixer.src_mask & (1 << id)))
+		return -EINVAL;
+	writew(gain, &chip->mixer.array->src_gain[id]);
+	oldval = val = readl(&chip->mixer.array->src_gain_enable);
+	if (on)
+		val |= (1 << id);
+	else
+		val &= ~(1 << id);
+	writel(val, &chip->mixer.array->src_gain_enable);
+	lola_codec_flush(chip);
+	/* inform micro-controller about the new source gain */
+	return lola_codec_write(chip, chip->mixer.nid,
+				LOLA_VERB_SET_SOURCE_GAIN, id, 0);
+}
+
+#if 0 /* not used */
+static int lola_mixer_set_src_gains(struct lola *chip, unsigned int mask,
+				    unsigned short *gains)
+{
+	int i;
+
+	if ((chip->mixer.src_mask & mask) != mask)
+		return -EINVAL;
+	for (i = 0; i < LOLA_MIXER_DIM; i++) {
+		if (mask & (1 << i)) {
+			writew(*gains, &chip->mixer.array->src_gain[i]);
+			gains++;
+		}
+	}
+	writel(mask, &chip->mixer.array->src_gain_enable);
+	lola_codec_flush(chip);
+	if (chip->mixer.caps & LOLA_PEAK_METER_CAN_AGC_MASK) {
+		/* update for all srcs at once */
+		return lola_codec_write(chip, chip->mixer.nid,
+					LOLA_VERB_SET_SOURCE_GAIN, 0x80, 0);
+	}
+	/* update manually */
+	for (i = 0; i < LOLA_MIXER_DIM; i++) {
+		if (mask & (1 << i)) {
+			lola_codec_write(chip, chip->mixer.nid,
+					 LOLA_VERB_SET_SOURCE_GAIN, i, 0);
+		}
+	}
+	return 0;
+}
+#endif /* not used */
+
+static int lola_mixer_set_mapping_gain(struct lola *chip,
+				       unsigned int src, unsigned int dest,
+				       unsigned short gain, bool on)
+{
+	unsigned int val;
+
+	if (!(chip->mixer.src_mask & (1 << src)) ||
+	    !(chip->mixer.dest_mask & (1 << dest)))
+		return -EINVAL;
+	if (on)
+		writew(gain, &chip->mixer.array->dest_mix_gain[dest][src]);
+	val = readl(&chip->mixer.array->dest_mix_gain_enable[dest]);
+	if (on)
+		val |= (1 << src);
+	else
+		val &= ~(1 << src);
+	writel(val, &chip->mixer.array->dest_mix_gain_enable[dest]);
+	lola_codec_flush(chip);
+	return lola_codec_write(chip, chip->mixer.nid, LOLA_VERB_SET_MIX_GAIN,
+				src, dest);
+}
+
+static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id,
+				     unsigned int mask, unsigned short *gains)
+{
+	int i;
+
+	if (!(chip->mixer.dest_mask & (1 << id)) ||
+	    (chip->mixer.src_mask & mask) != mask)
+		return -EINVAL;
+	for (i = 0; i < LOLA_MIXER_DIM; i++) {
+		if (mask & (1 << i)) {
+			writew(*gains, &chip->mixer.array->dest_mix_gain[id][i]);
+			gains++;
+		}
+	}
+	writel(mask, &chip->mixer.array->dest_mix_gain_enable[id]);
+	lola_codec_flush(chip);
+	/* update for all dests at once */
+	return lola_codec_write(chip, chip->mixer.nid,
+				LOLA_VERB_SET_DESTINATION_GAIN, id, 0);
+}
+
+/*
+ */
+
+static int set_analog_volume(struct lola *chip, int dir,
+			     unsigned int idx, unsigned int val,
+			     bool external_call);
+
+int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute)
+{
+	struct lola_pin *pin;
+	int idx, max_idx;
+
+	pin = chip->pin[dir].pins;
+	max_idx = chip->pin[dir].num_pins;
+	for (idx = 0; idx < max_idx; idx++) {
+		if (pin[idx].is_analog) {
+			unsigned int val = mute ? 0 : pin[idx].cur_gain_step;
+			/* set volume and do not save the value */
+			set_analog_volume(chip, dir, idx, val, false);
+		}
+	}
+	return lola_codec_flush(chip);
+}
+
+void lola_save_mixer(struct lola *chip)
+{
+	/* mute analog output */
+	if (chip->mixer.array_saved) {
+		/* store contents of mixer array */
+		memcpy_fromio(chip->mixer.array_saved, chip->mixer.array,
+			      sizeof(*chip->mixer.array));
+	}
+	lola_setup_all_analog_gains(chip, PLAY, true); /* output mute */
+}
+
+void lola_restore_mixer(struct lola *chip)
+{
+	int i;
+
+	/*lola_reset_setups(chip);*/
+	if (chip->mixer.array_saved) {
+		/* restore contents of mixer array */
+		memcpy_toio(chip->mixer.array, chip->mixer.array_saved,
+			    sizeof(*chip->mixer.array));
+		/* inform micro-controller about all restored values
+		 * and ignore return values
+		 */
+		for (i = 0; i < chip->mixer.src_phys_ins; i++)
+			lola_codec_write(chip, chip->mixer.nid,
+					 LOLA_VERB_SET_SOURCE_GAIN,
+					 i, 0);
+		for (i = 0; i < chip->mixer.src_stream_outs; i++)
+			lola_codec_write(chip, chip->mixer.nid,
+					 LOLA_VERB_SET_SOURCE_GAIN,
+					 chip->mixer.src_stream_out_ofs + i, 0);
+		for (i = 0; i < chip->mixer.dest_stream_ins; i++)
+			lola_codec_write(chip, chip->mixer.nid,
+					 LOLA_VERB_SET_DESTINATION_GAIN,
+					 i, 0);
+		for (i = 0; i < chip->mixer.dest_phys_outs; i++)
+			lola_codec_write(chip, chip->mixer.nid,
+					 LOLA_VERB_SET_DESTINATION_GAIN,
+					 chip->mixer.dest_phys_out_ofs + i, 0);
+		lola_codec_flush(chip);
+	}
+}
+
+/*
+ */
+
+static int set_analog_volume(struct lola *chip, int dir,
+			     unsigned int idx, unsigned int val,
+			     bool external_call)
+{
+	struct lola_pin *pin;
+	int err;
+
+	if (idx >= chip->pin[dir].num_pins)
+		return -EINVAL;
+	pin = &chip->pin[dir].pins[idx];
+	if (!pin->is_analog || pin->amp_num_steps <= val)
+		return -EINVAL;
+	if (external_call && pin->cur_gain_step == val)
+		return 0;
+	if (external_call)
+		lola_codec_flush(chip);
+	err = lola_codec_write(chip, pin->nid,
+			       LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0);
+	if (err < 0)
+		return err;
+	if (external_call)
+		pin->cur_gain_step = val;
+	return 0;
+}
+
+int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update)
+{
+	int ret = 0;
+	int success = 0;
+	int n, err;
+
+	/* SRC can be activated and the dwInputSRCMask is valid? */
+	if ((chip->input_src_caps_mask & src_mask) != src_mask)
+		return -EINVAL;
+	/* handle all even Inputs - SRC is a stereo setting !!! */
+	for (n = 0; n < chip->pin[CAPT].num_pins; n += 2) {
+		unsigned int mask = 3U << n; /* handle the stereo case */
+		unsigned int new_src, src_state;
+		if (!(chip->input_src_caps_mask & mask))
+			continue;
+		/* if one IO needs SRC, both stereo IO will get SRC */
+		new_src = (src_mask & mask) != 0;
+		if (update) {
+			src_state = (chip->input_src_mask & mask) != 0;
+			if (src_state == new_src)
+				continue;   /* nothing to change for this IO */
+		}
+		err = lola_codec_write(chip, chip->pcm[CAPT].streams[n].nid,
+				       LOLA_VERB_SET_SRC, new_src, 0);
+		if (!err)
+			success++;
+		else
+			ret = err;
+	}
+	if (success)
+		ret = lola_codec_flush(chip);
+	if (!ret)
+		chip->input_src_mask = src_mask;
+	return ret;
+}
+
+/*
+ */
+static int init_mixer_values(struct lola *chip)
+{
+	int i;
+
+	/* all src on */
+	lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false);
+
+	/* clear all matrix */
+	memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array));
+	/* set src gain to 0dB */
+	for (i = 0; i < chip->mixer.src_phys_ins; i++)
+		lola_mixer_set_src_gain(chip, i, 336, true); /* 0dB */
+	for (i = 0; i < chip->mixer.src_stream_outs; i++)
+		lola_mixer_set_src_gain(chip,
+					i + chip->mixer.src_stream_out_ofs,
+					336, true); /* 0dB */
+	/* set 1:1 dest gain */
+	for (i = 0; i < chip->mixer.dest_stream_ins; i++) {
+		int src = i % chip->mixer.src_phys_ins;
+		lola_mixer_set_mapping_gain(chip, src, i, 336, true);
+	}
+	for (i = 0; i < chip->mixer.src_stream_outs; i++) {
+		int src = chip->mixer.src_stream_out_ofs + i;
+		int dst = chip->mixer.dest_phys_out_ofs +
+			i % chip->mixer.dest_phys_outs;
+		lola_mixer_set_mapping_gain(chip, src, dst, 336, true);
+	}
+	return 0;
+}
+
+/*
+ * analog mixer control element
+ */
+static int lola_analog_vol_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int dir = kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = chip->pin[dir].num_pins;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = chip->pin[dir].pins[0].amp_num_steps;
+	return 0;
+}
+
+static int lola_analog_vol_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int dir = kcontrol->private_value;
+	int i;
+
+	for (i = 0; i < chip->pin[dir].num_pins; i++)
+		ucontrol->value.integer.value[i] =
+			chip->pin[dir].pins[i].cur_gain_step;
+	return 0;
+}
+
+static int lola_analog_vol_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int dir = kcontrol->private_value;
+	int i, err;
+
+	for (i = 0; i < chip->pin[dir].num_pins; i++) {
+		err = set_analog_volume(chip, dir, i,
+					ucontrol->value.integer.value[i],
+					true);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int lola_analog_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+			       unsigned int size, unsigned int __user *tlv)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int dir = kcontrol->private_value;
+	unsigned int val1, val2;
+	struct lola_pin *pin;
+
+	if (size < 4 * sizeof(unsigned int))
+		return -ENOMEM;
+	pin = &chip->pin[dir].pins[0];
+
+	val2 = pin->amp_step_size * 25;
+	val1 = -1 * (int)pin->amp_offset * (int)val2;
+#ifdef TLV_DB_SCALE_MUTE
+	val2 |= TLV_DB_SCALE_MUTE;
+#endif
+	if (put_user(SNDRV_CTL_TLVT_DB_SCALE, tlv))
+		return -EFAULT;
+	if (put_user(2 * sizeof(unsigned int), tlv + 1))
+		return -EFAULT;
+	if (put_user(val1, tlv + 2))
+		return -EFAULT;
+	if (put_user(val2, tlv + 3))
+		return -EFAULT;
+	return 0;
+}
+
+static struct snd_kcontrol_new lola_analog_mixer __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
+	.info = lola_analog_vol_info,
+	.get = lola_analog_vol_get,
+	.put = lola_analog_vol_put,
+	.tlv.c = lola_analog_vol_tlv,
+};
+
+static int __devinit create_analog_mixer(struct lola *chip, int dir, char *name)
+{
+	if (!chip->pin[dir].num_pins)
+		return 0;
+	/* no analog volumes on digital only adapters */
+	if (chip->pin[dir].num_pins != chip->pin[dir].num_analog_pins)
+		return 0;
+	lola_analog_mixer.name = name;
+	lola_analog_mixer.private_value = dir;
+	return snd_ctl_add(chip->card,
+			   snd_ctl_new1(&lola_analog_mixer, chip));
+}
+
+/*
+ * Hardware sample rate converter on digital input
+ */
+static int lola_input_src_info(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_info *uinfo)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = chip->pin[CAPT].num_pins;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int lola_input_src_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int i;
+
+	for (i = 0; i < chip->pin[CAPT].num_pins; i++)
+		ucontrol->value.integer.value[i] =
+			!!(chip->input_src_mask & (1 << i));
+	return 0;
+}
+
+static int lola_input_src_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	int i;
+	unsigned int mask;
+
+	mask = 0;
+	for (i = 0; i < chip->pin[CAPT].num_pins; i++)
+		if (ucontrol->value.integer.value[i])
+			mask |= 1 << i;
+	return lola_set_src_config(chip, mask, true);
+}
+
+static struct snd_kcontrol_new lola_input_src_mixer __devinitdata = {
+	.name = "Digital SRC Capture Switch",
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.info = lola_input_src_info,
+	.get = lola_input_src_get,
+	.put = lola_input_src_put,
+};
+
+/*
+ * Lola16161 or Lola881 can have Hardware sample rate converters
+ * on its digital input pins
+ */
+static int __devinit create_input_src_mixer(struct lola *chip)
+{
+	if (!chip->input_src_caps_mask)
+		return 0;
+
+	return snd_ctl_add(chip->card,
+			   snd_ctl_new1(&lola_input_src_mixer, chip));
+}
+
+/*
+ * src gain mixer
+ */
+static int lola_src_gain_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *uinfo)
+{
+	unsigned int count = (kcontrol->private_value >> 8) & 0xff;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = count;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 409;
+	return 0;
+}
+
+static int lola_src_gain_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int ofs = kcontrol->private_value & 0xff;
+	unsigned int count = (kcontrol->private_value >> 8) & 0xff;
+	unsigned int mask, i;
+
+	mask = readl(&chip->mixer.array->src_gain_enable);
+	for (i = 0; i < count; i++) {
+		unsigned int idx = ofs + i;
+		unsigned short val;
+		if (!(chip->mixer.src_mask & (1 << idx)))
+			return -EINVAL;
+		if (mask & (1 << idx))
+			val = readw(&chip->mixer.array->src_gain[idx]) + 1;
+		else
+			val = 0;
+		ucontrol->value.integer.value[i] = val;
+	}
+	return 0;
+}
+
+static int lola_src_gain_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int ofs = kcontrol->private_value & 0xff;
+	unsigned int count = (kcontrol->private_value >> 8) & 0xff;
+	int i, err;
+
+	for (i = 0; i < count; i++) {
+		unsigned int idx = ofs + i;
+		unsigned short val = ucontrol->value.integer.value[i];
+		if (val)
+			val--;
+		err = lola_mixer_set_src_gain(chip, idx, val, !!val);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/* raw value: 0 = -84dB, 336 = 0dB, 408=18dB, incremented 1 for mute */
+static const DECLARE_TLV_DB_SCALE(lola_src_gain_tlv, -8425, 25, 1);
+
+static struct snd_kcontrol_new lola_src_gain_mixer __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+	.info = lola_src_gain_info,
+	.get = lola_src_gain_get,
+	.put = lola_src_gain_put,
+	.tlv.p = lola_src_gain_tlv,
+};
+
+static int __devinit create_src_gain_mixer(struct lola *chip,
+					   int num, int ofs, char *name)
+{
+	lola_src_gain_mixer.name = name;
+	lola_src_gain_mixer.private_value = ofs + (num << 8);
+	return snd_ctl_add(chip->card,
+			   snd_ctl_new1(&lola_src_gain_mixer, chip));
+}
+
+/*
+ * destination gain (matrix-like) mixer
+ */
+static int lola_dest_gain_info(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_info *uinfo)
+{
+	unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = src_num;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 433;
+	return 0;
+}
+
+static int lola_dest_gain_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int src_ofs = kcontrol->private_value & 0xff;
+	unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
+	unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff;
+	unsigned int dst, mask, i;
+
+	dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs;
+	mask = readl(&chip->mixer.array->dest_mix_gain_enable[dst]);
+	for (i = 0; i < src_num; i++) {
+		unsigned int src = src_ofs + i;
+		unsigned short val;
+		if (!(chip->mixer.src_mask & (1 << src)))
+			return -EINVAL;
+		if (mask & (1 << dst))
+			val = readw(&chip->mixer.array->dest_mix_gain[dst][src]) + 1;
+		else
+			val = 0;
+		ucontrol->value.integer.value[i] = val;
+	}
+	return 0;
+}
+
+static int lola_dest_gain_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct lola *chip = snd_kcontrol_chip(kcontrol);
+	unsigned int src_ofs = kcontrol->private_value & 0xff;
+	unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
+	unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff;
+	unsigned int dst, mask;
+	unsigned short gains[MAX_STREAM_COUNT];
+	int i, num;
+
+	mask = 0;
+	num = 0;
+	for (i = 0; i < src_num; i++) {
+		unsigned short val = ucontrol->value.integer.value[i];
+		if (val) {
+			gains[num++] = val - 1;
+			mask |= 1 << i;
+		}
+	}
+	mask <<= src_ofs;
+	dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs;
+	return lola_mixer_set_dest_gains(chip, dst, mask, gains);
+}
+
+static const DECLARE_TLV_DB_SCALE(lola_dest_gain_tlv, -8425, 25, 1);
+
+static struct snd_kcontrol_new lola_dest_gain_mixer __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+	.info = lola_dest_gain_info,
+	.get = lola_dest_gain_get,
+	.put = lola_dest_gain_put,
+	.tlv.p = lola_dest_gain_tlv,
+};
+
+static int __devinit create_dest_gain_mixer(struct lola *chip,
+					    int src_num, int src_ofs,
+					    int num, int ofs, char *name)
+{
+	lola_dest_gain_mixer.count = num;
+	lola_dest_gain_mixer.name = name;
+	lola_dest_gain_mixer.private_value =
+		src_ofs + (src_num << 8) + (ofs << 16) + (num << 24);
+	return snd_ctl_add(chip->card,
+			  snd_ctl_new1(&lola_dest_gain_mixer, chip));
+}
+
+/*
+ */
+int __devinit lola_create_mixer(struct lola *chip)
+{
+	int err;
+
+	err = create_analog_mixer(chip, PLAY, "Analog Playback Volume");
+	if (err < 0)
+		return err;
+	err = create_analog_mixer(chip, CAPT, "Analog Capture Volume");
+	if (err < 0)
+		return err;
+	err = create_input_src_mixer(chip);
+	if (err < 0)
+		return err;
+	err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0,
+				    "Line Source Gain Volume");
+	if (err < 0)
+		return err;
+	err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs,
+				    chip->mixer.src_stream_out_ofs,
+				    "Stream Source Gain Volume");
+	if (err < 0)
+		return err;
+	err = create_dest_gain_mixer(chip,
+				     chip->mixer.src_phys_ins, 0,
+				     chip->mixer.dest_stream_ins, 0,
+				     "Line Capture Volume");
+	if (err < 0)
+		return err;
+	err = create_dest_gain_mixer(chip,
+				     chip->mixer.src_stream_outs,
+				     chip->mixer.src_stream_out_ofs,
+				     chip->mixer.dest_stream_ins, 0,
+				     "Stream-Loopback Capture Volume");
+	if (err < 0)
+		return err;
+	err = create_dest_gain_mixer(chip,
+				     chip->mixer.src_phys_ins, 0,
+				     chip->mixer.dest_phys_outs,
+				     chip->mixer.dest_phys_out_ofs,
+				     "Line-Loopback Playback Volume");
+	if (err < 0)
+		return err;
+	err = create_dest_gain_mixer(chip,
+				     chip->mixer.src_stream_outs,
+				     chip->mixer.src_stream_out_ofs,
+				     chip->mixer.dest_phys_outs,
+				     chip->mixer.dest_phys_out_ofs,
+				     "Stream Playback Volume");
+	if (err < 0)
+		return err;
+
+	return init_mixer_values(chip);
+}

+ 706 - 0
sound/pci/lola/lola_pcm.c

@@ -0,0 +1,706 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "lola.h"
+
+#define LOLA_MAX_BDL_ENTRIES	8
+#define LOLA_MAX_BUF_SIZE	(1024*1024*1024)
+#define LOLA_BDL_ENTRY_SIZE	(16 * 16)
+
+static struct lola_pcm *lola_get_pcm(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	return &chip->pcm[substream->stream];
+}
+
+static struct lola_stream *lola_get_stream(struct snd_pcm_substream *substream)
+{
+	struct lola_pcm *pcm = lola_get_pcm(substream);
+	unsigned int idx = substream->number;
+	return &pcm->streams[idx];
+}
+
+static unsigned int lola_get_lrc(struct lola *chip)
+{
+	return lola_readl(chip, BAR1, LRC);
+}
+
+static unsigned int lola_get_tstamp(struct lola *chip, bool quick_no_sync)
+{
+	unsigned int tstamp = lola_get_lrc(chip) >> 8;
+	if (chip->granularity) {
+		unsigned int wait_banks = quick_no_sync ? 0 : 8;
+		tstamp += (wait_banks + 1) * chip->granularity - 1;
+		tstamp -= tstamp % chip->granularity;
+	}
+	return tstamp << 8;
+}
+
+/* clear any pending interrupt status */
+static void lola_stream_clear_pending_irq(struct lola *chip,
+					  struct lola_stream *str)
+{
+	unsigned int val = lola_dsd_read(chip, str->dsd, STS);
+	val &= LOLA_DSD_STS_DESE | LOLA_DSD_STS_BCIS;
+	if (val)
+		lola_dsd_write(chip, str->dsd, STS, val);
+}
+
+static void lola_stream_start(struct lola *chip, struct lola_stream *str,
+			      unsigned int tstamp)
+{
+	lola_stream_clear_pending_irq(chip, str);
+	lola_dsd_write(chip, str->dsd, CTL,
+		       LOLA_DSD_CTL_SRUN |
+		       LOLA_DSD_CTL_IOCE |
+		       LOLA_DSD_CTL_DEIE |
+		       LOLA_DSD_CTL_VLRCV |
+		       tstamp);
+}
+
+static void lola_stream_stop(struct lola *chip, struct lola_stream *str,
+			     unsigned int tstamp)
+{
+	lola_dsd_write(chip, str->dsd, CTL,
+		       LOLA_DSD_CTL_IOCE |
+		       LOLA_DSD_CTL_DEIE |
+		       LOLA_DSD_CTL_VLRCV |
+		       tstamp);
+	lola_stream_clear_pending_irq(chip, str);
+}
+
+static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str)
+{
+	unsigned long end_time = jiffies + msecs_to_jiffies(200);
+	while (time_before(jiffies, end_time)) {
+		unsigned int val;
+		val = lola_dsd_read(chip, str->dsd, CTL);
+		if (!(val & LOLA_DSD_CTL_SRST))
+			return;
+		msleep(1);
+	}
+	printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd);
+}
+
+static int lola_stream_wait_for_fifo(struct lola *chip,
+				     struct lola_stream *str,
+				     bool ready)
+{
+	unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
+	unsigned long end_time = jiffies + msecs_to_jiffies(200);
+	while (time_before(jiffies, end_time)) {
+		unsigned int reg = lola_dsd_read(chip, str->dsd, STS);
+		if ((reg & LOLA_DSD_STS_FIFORDY) == val)
+			return 0;
+		msleep(1);
+	}
+	printk(KERN_WARNING SFX "FIFO not ready (stream %d)\n", str->dsd);
+	return -EIO;
+}
+
+/* sync for FIFO ready/empty for all linked streams;
+ * clear paused flag when FIFO gets ready again
+ */
+static int lola_sync_wait_for_fifo(struct lola *chip,
+				   struct snd_pcm_substream *substream,
+				   bool ready)
+{
+	unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
+	unsigned long end_time = jiffies + msecs_to_jiffies(200);
+	struct snd_pcm_substream *s;
+	int pending = 0;
+
+	while (time_before(jiffies, end_time)) {
+		pending = 0;
+		snd_pcm_group_for_each_entry(s, substream) {
+			struct lola_stream *str;
+			if (s->pcm->card != substream->pcm->card)
+				continue;
+			str = lola_get_stream(s);
+			if (str->prepared && str->paused) {
+				unsigned int reg;
+				reg = lola_dsd_read(chip, str->dsd, STS);
+				if ((reg & LOLA_DSD_STS_FIFORDY) != val) {
+					pending = str->dsd + 1;
+					break;
+				}
+				if (ready)
+					str->paused = 0;
+			}
+		}
+		if (!pending)
+			return 0;
+		msleep(1);
+	}
+	printk(KERN_WARNING SFX "FIFO not ready (pending %d)\n", pending - 1);
+	return -EIO;
+}
+
+/* finish pause - prepare for a new resume */
+static void lola_sync_pause(struct lola *chip,
+			    struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_substream *s;
+
+	lola_sync_wait_for_fifo(chip, substream, false);
+	snd_pcm_group_for_each_entry(s, substream) {
+		struct lola_stream *str;
+		if (s->pcm->card != substream->pcm->card)
+			continue;
+		str = lola_get_stream(s);
+		if (str->paused && str->prepared)
+			lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRUN |
+				       LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
+	}
+	lola_sync_wait_for_fifo(chip, substream, true);
+}
+
+static void lola_stream_reset(struct lola *chip, struct lola_stream *str)
+{
+	if (str->prepared) {
+		if (str->paused)
+			lola_sync_pause(chip, str->substream);
+		str->prepared = 0;
+		lola_dsd_write(chip, str->dsd, CTL,
+			       LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
+		lola_stream_wait_for_fifo(chip, str, false);
+		lola_stream_clear_pending_irq(chip, str);
+		lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST);
+		lola_dsd_write(chip, str->dsd, LVI, 0);
+		lola_dsd_write(chip, str->dsd, BDPU, 0);
+		lola_dsd_write(chip, str->dsd, BDPL, 0);
+		wait_for_srst_clear(chip, str);
+	}
+}
+
+static struct snd_pcm_hardware lola_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),
+	.formats =		(SNDRV_PCM_FMTBIT_S16_LE |
+				 SNDRV_PCM_FMTBIT_S24_LE |
+				 SNDRV_PCM_FMTBIT_S32_LE |
+				 SNDRV_PCM_FMTBIT_FLOAT_LE),
+	.rates =		SNDRV_PCM_RATE_8000_192000,
+	.rate_min =		8000,
+	.rate_max =		192000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	LOLA_MAX_BUF_SIZE,
+	.period_bytes_min =	128,
+	.period_bytes_max =	LOLA_MAX_BUF_SIZE / 2,
+	.periods_min =		2,
+	.periods_max =		LOLA_MAX_BDL_ENTRIES,
+	.fifo_size =		0,
+};
+
+static int lola_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_pcm *pcm = lola_get_pcm(substream);
+	struct lola_stream *str = lola_get_stream(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	mutex_lock(&chip->open_mutex);
+	if (str->opened) {
+		mutex_unlock(&chip->open_mutex);
+		return -EBUSY;
+	}
+	str->substream = substream;
+	str->master = NULL;
+	str->opened = 1;
+	runtime->hw = lola_pcm_hw;
+	runtime->hw.channels_max = pcm->num_streams - str->index;
+	if (chip->sample_rate) {
+		/* sample rate is locked */
+		runtime->hw.rate_min = chip->sample_rate;
+		runtime->hw.rate_max = chip->sample_rate;
+	} else {
+		runtime->hw.rate_min = chip->sample_rate_min;
+		runtime->hw.rate_max = chip->sample_rate_max;
+	}
+	chip->ref_count_rate++;
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	/* period size = multiple of chip->granularity (8, 16 or 32 frames)*/
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+				   chip->granularity);
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+				   chip->granularity);
+	mutex_unlock(&chip->open_mutex);
+	return 0;
+}
+
+static void lola_cleanup_slave_streams(struct lola_pcm *pcm,
+				       struct lola_stream *str)
+{
+	int i;
+	for (i = str->index + 1; i < pcm->num_streams; i++) {
+		struct lola_stream *s = &pcm->streams[i];
+		if (s->master != str)
+			break;
+		s->master = NULL;
+		s->opened = 0;
+	}
+}
+
+static int lola_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_stream *str = lola_get_stream(substream);
+
+	mutex_lock(&chip->open_mutex);
+	if (str->substream == substream) {
+		str->substream = NULL;
+		str->opened = 0;
+	}
+	if (--chip->ref_count_rate == 0) {
+		/* release sample rate */
+		chip->sample_rate = 0;
+	}
+	mutex_unlock(&chip->open_mutex);
+	return 0;
+}
+
+static int lola_pcm_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *hw_params)
+{
+	struct lola_stream *str = lola_get_stream(substream);
+
+	str->bufsize = 0;
+	str->period_bytes = 0;
+	str->format_verb = 0;
+	return snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+}
+
+static int lola_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_pcm *pcm = lola_get_pcm(substream);
+	struct lola_stream *str = lola_get_stream(substream);
+
+	mutex_lock(&chip->open_mutex);
+	lola_stream_reset(chip, str);
+	lola_cleanup_slave_streams(pcm, str);
+	mutex_unlock(&chip->open_mutex);
+	return snd_pcm_lib_free_pages(substream);
+}
+
+/*
+ * set up a BDL entry
+ */
+static int setup_bdle(struct snd_pcm_substream *substream,
+		      struct lola_stream *str, u32 **bdlp,
+		      int ofs, int size)
+{
+	u32 *bdl = *bdlp;
+
+	while (size > 0) {
+		dma_addr_t addr;
+		int chunk;
+
+		if (str->frags >= LOLA_MAX_BDL_ENTRIES)
+			return -EINVAL;
+
+		addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+		/* program the address field of the BDL entry */
+		bdl[0] = cpu_to_le32((u32)addr);
+		bdl[1] = cpu_to_le32(upper_32_bits(addr));
+		/* program the size field of the BDL entry */
+		chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
+		bdl[2] = cpu_to_le32(chunk);
+		/* program the IOC to enable interrupt
+		 * only when the whole fragment is processed
+		 */
+		size -= chunk;
+		bdl[3] = size ? 0 : cpu_to_le32(0x01);
+		bdl += 4;
+		str->frags++;
+		ofs += chunk;
+	}
+	*bdlp = bdl;
+	return ofs;
+}
+
+/*
+ * set up BDL entries
+ */
+static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm,
+			      struct snd_pcm_substream *substream,
+			      struct lola_stream *str)
+{
+	u32 *bdl;
+	int i, ofs, periods, period_bytes;
+
+	period_bytes = str->period_bytes;
+	periods = str->bufsize / period_bytes;
+
+	/* program the initial BDL entries */
+	bdl = (u32 *)(pcm->bdl.area + LOLA_BDL_ENTRY_SIZE * str->index);
+	ofs = 0;
+	str->frags = 0;
+	for (i = 0; i < periods; i++) {
+		ofs = setup_bdle(substream, str, &bdl, ofs, period_bytes);
+		if (ofs < 0)
+			goto error;
+	}
+	return 0;
+
+ error:
+	snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n",
+		   str->bufsize, period_bytes);
+	return -EINVAL;
+}
+
+static unsigned int lola_get_format_verb(struct snd_pcm_substream *substream)
+{
+	unsigned int verb;
+
+	switch (substream->runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		verb = 0x00000000;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		verb = 0x00000200;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		verb = 0x00000300;
+		break;
+	case SNDRV_PCM_FORMAT_FLOAT_LE:
+		verb = 0x00001300;
+		break;
+	default:
+		return 0;
+	}
+	verb |= substream->runtime->channels;
+	return verb;
+}
+
+static int lola_set_stream_config(struct lola *chip,
+				  struct lola_stream *str,
+				  int channels)
+{
+	int i, err;
+	unsigned int verb, val;
+
+	/* set format info for all channels
+	 * (with only one command for the first channel)
+	 */
+	err = lola_codec_read(chip, str->nid, LOLA_VERB_SET_STREAM_FORMAT,
+			      str->format_verb, 0, &val, NULL);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Cannot set stream format 0x%x\n",
+		       str->format_verb);
+		return err;
+	}
+
+	/* update stream - channel config */
+	for (i = 0; i < channels; i++) {
+		verb = (str->index << 6) | i;
+		err = lola_codec_read(chip, str[i].nid,
+				      LOLA_VERB_SET_CHANNEL_STREAMID, 0, verb,
+				      &val, NULL);
+		if (err < 0) {
+			printk(KERN_ERR SFX "Cannot set stream channel %d\n", i);
+			return err;
+		}
+	}
+	return 0;
+}
+
+/*
+ * set up the SD for streaming
+ */
+static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm,
+				 struct lola_stream *str)
+{
+	dma_addr_t bdl;
+
+	if (str->prepared)
+		return -EINVAL;
+
+	/* set up BDL */
+	bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index;
+	lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl);
+	lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl));
+	/* program the stream LVI (last valid index) of the BDL */
+	lola_dsd_write(chip, str->dsd, LVI, str->frags - 1);
+	lola_stream_clear_pending_irq(chip, str);
+
+ 	lola_dsd_write(chip, str->dsd, CTL,
+		       LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE | LOLA_DSD_CTL_SRUN);
+
+	str->prepared = 1;
+
+	return lola_stream_wait_for_fifo(chip, str, true);
+}
+
+static int lola_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_pcm *pcm = lola_get_pcm(substream);
+	struct lola_stream *str = lola_get_stream(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned int bufsize, period_bytes, format_verb;
+	int i, err;
+
+	mutex_lock(&chip->open_mutex);
+	lola_stream_reset(chip, str);
+	lola_cleanup_slave_streams(pcm, str);
+	if (str->index + runtime->channels > pcm->num_streams) {
+		mutex_unlock(&chip->open_mutex);
+		return -EINVAL;
+	}
+	for (i = 1; i < runtime->channels; i++) {
+		str[i].master = str;
+		str[i].opened = 1;
+	}
+	mutex_unlock(&chip->open_mutex);
+
+	bufsize = snd_pcm_lib_buffer_bytes(substream);
+	period_bytes = snd_pcm_lib_period_bytes(substream);
+	format_verb = lola_get_format_verb(substream);
+
+	str->bufsize = bufsize;
+	str->period_bytes = period_bytes;
+	str->format_verb = format_verb;
+
+	err = lola_setup_periods(chip, pcm, substream, str);
+	if (err < 0)
+		return err;
+
+	err = lola_set_sample_rate(chip, runtime->rate);
+	if (err < 0)
+		return err;
+	chip->sample_rate = runtime->rate;	/* sample rate gets locked */
+
+	err = lola_set_stream_config(chip, str, runtime->channels);
+	if (err < 0)
+		return err;
+
+	err = lola_setup_controller(chip, pcm, str);
+	if (err < 0) {
+		lola_stream_reset(chip, str);
+		return err;
+	}
+
+	return 0;
+}
+
+static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_stream *str;
+	struct snd_pcm_substream *s;
+	unsigned int start;
+	unsigned int tstamp;
+	bool sync_streams;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		start = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+		start = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * sample correct synchronization is only needed starting several
+	 * streams. On stop or if only one stream do as quick as possible
+	 */
+	sync_streams = (start && snd_pcm_stream_linked(substream));
+	tstamp = lola_get_tstamp(chip, !sync_streams);
+	spin_lock(&chip->reg_lock);
+	snd_pcm_group_for_each_entry(s, substream) {
+		if (s->pcm->card != substream->pcm->card)
+			continue;
+		str = lola_get_stream(s);
+		if (start)
+			lola_stream_start(chip, str, tstamp);
+		else
+			lola_stream_stop(chip, str, tstamp);
+		str->running = start;
+		str->paused = !start;
+		snd_pcm_trigger_done(s, substream);
+	}
+	spin_unlock(&chip->reg_lock);
+	return 0;
+}
+
+static snd_pcm_uframes_t lola_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct lola *chip = snd_pcm_substream_chip(substream);
+	struct lola_stream *str = lola_get_stream(substream);
+	unsigned int pos = lola_dsd_read(chip, str->dsd, LPIB);
+
+	if (pos >= str->bufsize)
+		pos = 0;
+	return bytes_to_frames(substream->runtime, pos);
+}
+
+void lola_pcm_update(struct lola *chip, struct lola_pcm *pcm, unsigned int bits)
+{
+	int i;
+
+	for (i = 0; bits && i < pcm->num_streams; i++) {
+		if (bits & (1 << i)) {
+			struct lola_stream *str = &pcm->streams[i];
+			if (str->substream && str->running)
+				snd_pcm_period_elapsed(str->substream);
+			bits &= ~(1 << i);
+		}
+	}
+}
+
+static struct snd_pcm_ops lola_pcm_ops = {
+	.open = lola_pcm_open,
+	.close = lola_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = lola_pcm_hw_params,
+	.hw_free = lola_pcm_hw_free,
+	.prepare = lola_pcm_prepare,
+	.trigger = lola_pcm_trigger,
+	.pointer = lola_pcm_pointer,
+	.page = snd_pcm_sgbuf_ops_page,
+};
+
+int __devinit lola_create_pcm(struct lola *chip)
+{
+	struct snd_pcm *pcm;
+	int i, err;
+
+	for (i = 0; i < 2; i++) {
+		err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+					  snd_dma_pci_data(chip->pci),
+					  PAGE_SIZE, &chip->pcm[i].bdl);
+		if (err < 0)
+			return err;
+	}
+
+	err = snd_pcm_new(chip->card, "Digigram Lola", 0,
+			  chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams,
+			  chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams,
+			  &pcm);
+	if (err < 0)
+		return err;
+	strlcpy(pcm->name, "Digigram Lola", sizeof(pcm->name));
+	pcm->private_data = chip;
+	for (i = 0; i < 2; i++) {
+		if (chip->pcm[i].num_streams)
+			snd_pcm_set_ops(pcm, i, &lola_pcm_ops);
+	}
+	/* buffer pre-allocation */
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+					      snd_dma_pci_data(chip->pci),
+					      1024 * 64, 32 * 1024 * 1024);
+	return 0;
+}
+
+void lola_free_pcm(struct lola *chip)
+{
+	snd_dma_free_pages(&chip->pcm[0].bdl);
+	snd_dma_free_pages(&chip->pcm[1].bdl);
+}
+
+/*
+ */
+
+static int lola_init_stream(struct lola *chip, struct lola_stream *str,
+			    int idx, int nid, int dir)
+{
+	unsigned int val;
+	int err;
+
+	str->nid = nid;
+	str->index = idx;
+	str->dsd = idx;
+	if (dir == PLAY)
+		str->dsd += MAX_STREAM_IN_COUNT;
+	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+		return err;
+	}
+	if (dir == PLAY) {
+		/* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) */
+		if ((val & 0x00f00dff) != 0x00000010) {
+			printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n",
+			       val, nid);
+			return -EINVAL;
+		}
+	} else {
+		/* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1)
+		 * (bug : ignore bit8: Conn list = 0/1)
+		 */
+		if ((val & 0x00f00cff) != 0x00100010) {
+			printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n",
+			       val, nid);
+			return -EINVAL;
+		}
+		/* test bit9:DIGITAL and bit12:SRC_PRESENT*/
+		if ((val & 0x00001200) == 0x00001200)
+			chip->input_src_caps_mask |= (1 << idx);
+	}
+
+	err = lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val);
+	if (err < 0) {
+		printk(KERN_ERR SFX "Can't read FORMATS 0x%x\n", nid);
+		return err;
+	}
+	val &= 3;
+	if (val == 3)
+		str->can_float = true;
+	if (!(val & 1)) {
+		printk(KERN_ERR SFX "Invalid formats 0x%x for 0x%x", val, nid);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int __devinit lola_init_pcm(struct lola *chip, int dir, int *nidp)
+{
+	struct lola_pcm *pcm = &chip->pcm[dir];
+	int i, nid, err;
+
+	nid = *nidp;
+	for (i = 0; i < pcm->num_streams; i++, nid++) {
+		err = lola_init_stream(chip, &pcm->streams[i], i, nid, dir);
+		if (err < 0)
+			return err;
+	}
+	*nidp = nid;
+	return 0;
+}

+ 222 - 0
sound/pci/lola/lola_proc.c

@@ -0,0 +1,222 @@
+/*
+ *  Support for Digigram Lola PCI-e boards
+ *
+ *  Copyright (c) 2011 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include "lola.h"
+
+static void print_audio_widget(struct snd_info_buffer *buffer,
+			       struct lola *chip, int nid, const char *name)
+{
+	unsigned int val;
+
+	lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val);
+	lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val);
+	snd_iprintf(buffer, "  Formats: 0x%x\n", val);
+}
+
+static void print_pin_widget(struct snd_info_buffer *buffer,
+			     struct lola *chip, int nid, unsigned int ampcap,
+			     const char *name)
+{
+	unsigned int val;
+
+	lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val);
+	if (val == 0x00400200)
+		return;
+	lola_read_param(chip, nid, ampcap, &val);
+	snd_iprintf(buffer, "  Amp-Caps: 0x%x\n", val);
+	snd_iprintf(buffer, "    mute=%d, step-size=%d, steps=%d, ofs=%d\n",
+		    LOLA_AMP_MUTE_CAPABLE(val),
+		    LOLA_AMP_STEP_SIZE(val),
+		    LOLA_AMP_NUM_STEPS(val),
+		    LOLA_AMP_OFFSET(val));
+	lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val, NULL);
+	snd_iprintf(buffer, "  Max-level: 0x%x\n", val);
+}
+
+static void print_clock_widget(struct snd_info_buffer *buffer,
+			       struct lola *chip, int nid)
+{
+	int i, j, num_clocks;
+	unsigned int val;
+
+	lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	snd_iprintf(buffer, "Node 0x%02x [Clock] wcaps 0x%x\n", nid, val);
+	num_clocks = val & 0xff;
+	for (i = 0; i < num_clocks; i += 4) {
+		unsigned int res_ex;
+		unsigned short items[4];
+		const char *name;
+
+		lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
+				i, 0, &val, &res_ex);
+		items[0] = val & 0xfff;
+		items[1] = (val >> 16) & 0xfff;
+		items[2] = res_ex & 0xfff;
+		items[3] = (res_ex >> 16) & 0xfff;
+		for (j = 0; j < 4; j++) {
+			unsigned char type = items[j] >> 8;
+			unsigned int freq = items[j] & 0xff;
+			if (i + j >= num_clocks)
+				break;
+			if (type == LOLA_CLOCK_TYPE_INTERNAL) {
+				name = "Internal";
+				freq = lola_sample_rate_convert(freq);
+			} else if (type == LOLA_CLOCK_TYPE_VIDEO) {
+				name = "Video";
+				freq = lola_sample_rate_convert(freq);
+			} else {
+				name = "Other";
+			}
+			snd_iprintf(buffer, "  Clock %d: Type %d:%s, freq=%d\n",
+				    i + j, type, name, freq);
+		}
+	}
+}
+
+static void print_mixer_widget(struct snd_info_buffer *buffer,
+			       struct lola *chip, int nid)
+{
+	unsigned int val;
+
+	lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
+	snd_iprintf(buffer, "Node 0x%02x [Mixer] wcaps 0x%x\n", nid, val);
+}
+
+static void lola_proc_codec_read(struct snd_info_entry *entry,
+				 struct snd_info_buffer *buffer)
+{
+	struct lola *chip = entry->private_data;
+	unsigned int val;
+	int i, nid;
+
+	lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val);
+	snd_iprintf(buffer, "Vendor: 0x%08x\n", val);
+	lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val);
+	snd_iprintf(buffer, "Function Type: %d\n", val);
+	lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val);
+	snd_iprintf(buffer, "Specific-Caps: 0x%08x\n", val);
+	snd_iprintf(buffer, "  Pins-In %d, Pins-Out %d\n",
+		    chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins);
+	nid = 2;
+	for (i = 0; i < chip->pcm[CAPT].num_streams; i++, nid++)
+		print_audio_widget(buffer, chip, nid, "[Audio-In]");
+	for (i = 0; i < chip->pcm[PLAY].num_streams; i++, nid++)
+		print_audio_widget(buffer, chip, nid, "[Audio-Out]");
+	for (i = 0; i < chip->pin[CAPT].num_pins; i++, nid++)
+		print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_IN_CAP,
+				 "[Pin-In]");
+	for (i = 0; i < chip->pin[PLAY].num_pins; i++, nid++)
+		print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_OUT_CAP,
+				 "[Pin-Out]");
+	if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) {
+		print_clock_widget(buffer, chip, nid);
+		nid++;
+	}
+	if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) {
+		print_mixer_widget(buffer, chip, nid);
+		nid++;
+	}
+}
+
+/* direct codec access for debugging */
+static void lola_proc_codec_rw_write(struct snd_info_entry *entry,
+				     struct snd_info_buffer *buffer)
+{
+	struct lola *chip = entry->private_data;
+	char line[64];
+	unsigned int id, verb, data, extdata;
+	while (!snd_info_get_line(buffer, line, sizeof(line))) {
+		if (sscanf(line, "%i %i %i %i", &id, &verb, &data, &extdata) != 4)
+			continue;
+		lola_codec_read(chip, id, verb, data, extdata,
+				&chip->debug_res,
+				&chip->debug_res_ex);
+	}
+}
+
+static void lola_proc_codec_rw_read(struct snd_info_entry *entry,
+				    struct snd_info_buffer *buffer)
+{
+	struct lola *chip = entry->private_data;
+	snd_iprintf(buffer, "0x%x 0x%x\n", chip->debug_res, chip->debug_res_ex);
+}
+
+/*
+ * dump some registers
+ */
+static void lola_proc_regs_read(struct snd_info_entry *entry,
+				struct snd_info_buffer *buffer)
+{
+	struct lola *chip = entry->private_data;
+	int i;
+
+	for (i = 0; i < 0x40; i += 4) {
+		snd_iprintf(buffer, "BAR0 %02x: %08x\n", i,
+			    readl(chip->bar[BAR0].remap_addr + i));
+	}
+	snd_iprintf(buffer, "\n");
+	for (i = 0; i < 0x30; i += 4) {
+		snd_iprintf(buffer, "BAR1 %02x: %08x\n", i,
+			    readl(chip->bar[BAR1].remap_addr + i));
+	}
+	snd_iprintf(buffer, "\n");
+	for (i = 0x80; i < 0xa0; i += 4) {
+		snd_iprintf(buffer, "BAR1 %02x: %08x\n", i,
+			    readl(chip->bar[BAR1].remap_addr + i));
+	}
+	snd_iprintf(buffer, "\n");
+	for (i = 0; i < 32; i++) {
+		snd_iprintf(buffer, "DSD %02x STS  %08x\n", i,
+			    lola_dsd_read(chip, i, STS));
+		snd_iprintf(buffer, "DSD %02x LPIB %08x\n", i,
+			    lola_dsd_read(chip, i, LPIB));
+		snd_iprintf(buffer, "DSD %02x CTL  %08x\n", i,
+			    lola_dsd_read(chip, i, CTL));
+		snd_iprintf(buffer, "DSD %02x LVIL %08x\n", i,
+			    lola_dsd_read(chip, i, LVI));
+		snd_iprintf(buffer, "DSD %02x BDPL %08x\n", i,
+			    lola_dsd_read(chip, i, BDPL));
+		snd_iprintf(buffer, "DSD %02x BDPU %08x\n", i,
+			    lola_dsd_read(chip, i, BDPU));
+	}
+}
+
+void __devinit lola_proc_debug_new(struct lola *chip)
+{
+	struct snd_info_entry *entry;
+
+	if (!snd_card_proc_new(chip->card, "codec", &entry))
+		snd_info_set_text_ops(entry, chip, lola_proc_codec_read);
+	if (!snd_card_proc_new(chip->card, "codec_rw", &entry)) {
+		snd_info_set_text_ops(entry, chip, lola_proc_codec_rw_read);
+		entry->mode |= S_IWUSR;
+		entry->c.text.write = lola_proc_codec_rw_write;
+	}
+	if (!snd_card_proc_new(chip->card, "regs", &entry))
+		snd_info_set_text_ops(entry, chip, lola_proc_regs_read);
+}

+ 1 - 1
sound/ppc/tumbler.c

@@ -1000,7 +1000,7 @@ static void device_change_handler(struct work_struct *work)
 				   chip->lineout_sw_ctl);
 				   chip->lineout_sw_ctl);
 		if (mix->anded_reset)
 		if (mix->anded_reset)
 			msleep(10);
 			msleep(10);
-		check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify,
+		check_mute(chip, &mix->amp_mute, !IS_G4DA, mix->auto_mute_notify,
 			   chip->speaker_sw_ctl);
 			   chip->speaker_sw_ctl);
 	} else {
 	} else {
 		/* unmute speaker, mute others */
 		/* unmute speaker, mute others */

+ 1 - 1
sound/soc/atmel/sam9g20_wm8731.c

@@ -184,7 +184,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
 	.codec_dai_name = "wm8731-hifi",
 	.codec_dai_name = "wm8731-hifi",
 	.init = at91sam9g20ek_wm8731_init,
 	.init = at91sam9g20ek_wm8731_init,
 	.platform_name = "atmel-pcm-audio",
 	.platform_name = "atmel-pcm-audio",
-	.codec_name = "wm8731-codec.0-001b",
+	.codec_name = "wm8731.0-001b",
 	.ops = &at91sam9g20ek_ops,
 	.ops = &at91sam9g20ek_ops,
 };
 };
 
 

+ 1 - 1
sound/soc/au1x/db1200.c

@@ -77,7 +77,7 @@ static struct snd_soc_dai_link db1200_i2s_dai = {
 	.codec_dai_name	= "wm8731-hifi",
 	.codec_dai_name	= "wm8731-hifi",
 	.cpu_dai_name	= "au1xpsc_i2s.1",
 	.cpu_dai_name	= "au1xpsc_i2s.1",
 	.platform_name	= "au1xpsc-pcm.1",
 	.platform_name	= "au1xpsc-pcm.1",
-	.codec_name	= "wm8731-codec.0-001b",
+	.codec_name	= "wm8731.0-001b",
 	.ops		= &db1200_i2s_wm8731_ops,
 	.ops		= &db1200_i2s_wm8731_ops,
 };
 };
 
 

+ 10 - 3
sound/soc/blackfin/bf5xx-ac97-pcm.c

@@ -243,6 +243,9 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int ret;
 	int ret;
 
 
@@ -314,6 +317,9 @@ static struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
 
 
 static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
 {
+	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
 	struct snd_dma_buffer *buf = &substream->dma_buffer;
 	struct snd_dma_buffer *buf = &substream->dma_buffer;
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max
@@ -377,6 +383,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 	struct snd_dma_buffer *buf;
 	struct snd_dma_buffer *buf;
 	int stream;
 	int stream;
 #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
+	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
 		sizeof(struct ac97_frame) / 4;
 		sizeof(struct ac97_frame) / 4;
 #endif
 #endif
@@ -405,8 +414,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 	}
 	}
 #endif
 #endif
 	}
 	}
-	if (sport_handle)
-		sport_done(sport_handle);
 }
 }
 
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -458,7 +465,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 
 
 static struct platform_driver bf5xx_pcm_driver = {
 static struct platform_driver bf5xx_pcm_driver = {
 	.driver = {
 	.driver = {
-			.name = "bf5xx-pcm-audio",
+			.name = "bfin-ac97-pcm-audio",
 			.owner = THIS_MODULE,
 			.owner = THIS_MODULE,
 	},
 	},
 
 

+ 53 - 113
sound/soc/blackfin/bf5xx-ac97.c

@@ -41,48 +41,7 @@
  *		anomaly does not affect blackfin sound drivers.
  *		anomaly does not affect blackfin sound drivers.
 */
 */
 
 
-static int *cmd_count;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-#define SPORT_REQ(x) \
-	[x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
-	       P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
-static u16 sport_req[][7] = {
-#ifdef SPORT0_TCR1
-	SPORT_REQ(0),
-#endif
-#ifdef SPORT1_TCR1
-	SPORT_REQ(1),
-#endif
-#ifdef SPORT2_TCR1
-	SPORT_REQ(2),
-#endif
-#ifdef SPORT3_TCR1
-	SPORT_REQ(3),
-#endif
-};
-
-#define SPORT_PARAMS(x) \
-	[x] = { \
-		.dma_rx_chan = CH_SPORT##x##_RX, \
-		.dma_tx_chan = CH_SPORT##x##_TX, \
-		.err_irq     = IRQ_SPORT##x##_ERROR, \
-		.regs        = (struct sport_register *)SPORT##x##_TCR1, \
-	}
-static struct sport_param sport_params[4] = {
-#ifdef SPORT0_TCR1
-	SPORT_PARAMS(0),
-#endif
-#ifdef SPORT1_TCR1
-	SPORT_PARAMS(1),
-#endif
-#ifdef SPORT2_TCR1
-	SPORT_PARAMS(2),
-#endif
-#ifdef SPORT3_TCR1
-	SPORT_PARAMS(3),
-#endif
-};
+static struct sport_device *ac97_sport_handle;
 
 
 void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
 void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
 		size_t count, unsigned int chan_mask)
 		size_t count, unsigned int chan_mask)
@@ -140,7 +99,8 @@ static unsigned int sport_tx_curr_frag(struct sport_device *sport)
 
 
 static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 {
 {
-	struct sport_device *sport = sport_handle;
+	struct sport_device *sport = ac97_sport_handle;
+	int *cmd_count = sport->private_data;
 	int nextfrag = sport_tx_curr_frag(sport);
 	int nextfrag = sport_tx_curr_frag(sport);
 	struct ac97_frame *nextwrite;
 	struct ac97_frame *nextwrite;
 
 
@@ -161,6 +121,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
 static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
 	unsigned short reg)
 	unsigned short reg)
 {
 {
+	struct sport_device *sport_handle = ac97_sport_handle;
 	struct ac97_frame out_frame[2], in_frame[2];
 	struct ac97_frame out_frame[2], in_frame[2];
 
 
 	pr_debug("%s enter 0x%x\n", __func__, reg);
 	pr_debug("%s enter 0x%x\n", __func__, reg);
@@ -185,6 +146,8 @@ static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
 void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 	unsigned short val)
 	unsigned short val)
 {
 {
+	struct sport_device *sport_handle = ac97_sport_handle;
+
 	pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
 	pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
 
 
 	if (sport_handle->tx_run) {
 	if (sport_handle->tx_run) {
@@ -203,28 +166,19 @@ void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 
 
 static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
 static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
 {
 {
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF561) || \
- (defined(BF537_FAMILY) && (CONFIG_SND_BF5XX_SPORT_NUM == 1))
-
-#define CONCAT(a, b, c) a ## b ## c
-#define BFIN_SPORT_RFS(x) CONCAT(P_SPORT, x, _RFS)
-
-	u16 per = BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM);
-	u16 gpio = P_IDENT(BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM));
+	struct sport_device *sport_handle = ac97_sport_handle;
+	u16 gpio = P_IDENT(sport_handle->pin_req[3]);
 
 
 	pr_debug("%s enter\n", __func__);
 	pr_debug("%s enter\n", __func__);
 
 
-	peripheral_free(per);
+	peripheral_free_list(sport_handle->pin_req);
 	gpio_request(gpio, "bf5xx-ac97");
 	gpio_request(gpio, "bf5xx-ac97");
 	gpio_direction_output(gpio, 1);
 	gpio_direction_output(gpio, 1);
 	udelay(2);
 	udelay(2);
 	gpio_set_value(gpio, 0);
 	gpio_set_value(gpio, 0);
 	udelay(1);
 	udelay(1);
 	gpio_free(gpio);
 	gpio_free(gpio);
-	peripheral_request(per, "soc-audio");
-#else
-	pr_info("%s: Not implemented\n", __func__);
-#endif
+	peripheral_request_list(sport_handle->pin_req, "soc-audio");
 }
 }
 
 
 static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
 static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
@@ -306,18 +260,32 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 #define bf5xx_ac97_resume	NULL
 #define bf5xx_ac97_resume	NULL
 #endif
 #endif
 
 
-static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
+static struct snd_soc_dai_driver bfin_ac97_dai = {
+	.ac97_control = 1,
+	.suspend = bf5xx_ac97_suspend,
+	.resume = bf5xx_ac97_resume,
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 2,
+#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
+		.channels_max = 6,
+#else
+		.channels_max = 2,
+#endif
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+
+static int __devinit asoc_bfin_ac97_probe(struct platform_device *pdev)
 {
 {
-	int ret = 0;
-	cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
-	if (cmd_count == NULL)
-		return -ENOMEM;
-
-	if (peripheral_request_list(sport_req[sport_num], "soc-audio")) {
-		pr_err("Requesting Peripherals failed\n");
-		ret =  -EFAULT;
-		goto peripheral_err;
-	}
+	struct sport_device *sport_handle;
+	int ret;
 
 
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	/* Request PB3 as reset pin */
 	/* Request PB3 as reset pin */
@@ -329,12 +297,14 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
 	}
 	}
 	gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
 	gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
 #endif
 #endif
-	sport_handle = sport_init(&sport_params[sport_num], 2, \
-			sizeof(struct ac97_frame), NULL);
+
+	sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
+		PAGE_SIZE);
 	if (!sport_handle) {
 	if (!sport_handle) {
 		ret = -ENODEV;
 		ret = -ENODEV;
 		goto sport_err;
 		goto sport_err;
 	}
 	}
+
 	/*SPORT works in TDM mode to simulate AC97 transfers*/
 	/*SPORT works in TDM mode to simulate AC97 transfers*/
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
 	ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1);
 	ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1);
@@ -361,67 +331,37 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
 		goto sport_config_err;
 		goto sport_config_err;
 	}
 	}
 
 
+	ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+	if (ret) {
+		pr_err("Failed to register DAI: %d\n", ret);
+		goto sport_config_err;
+	}
+
+	ac97_sport_handle = sport_handle;
+
 	return 0;
 	return 0;
 
 
 sport_config_err:
 sport_config_err:
-	kfree(sport_handle);
+	sport_done(sport_handle);
 sport_err:
 sport_err:
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 gpio_err:
 gpio_err:
 #endif
 #endif
-	peripheral_free_list(sport_req[sport_num]);
-peripheral_err:
-	free_page((unsigned long)cmd_count);
-	cmd_count = NULL;
 
 
 	return ret;
 	return ret;
 }
 }
 
 
-static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
+static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
 {
 {
-	free_page((unsigned long)cmd_count);
-	cmd_count = NULL;
-	peripheral_free_list(sport_req[sport_num]);
+	struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+	sport_done(sport_handle);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
 #endif
-	return 0;
-}
-
-struct snd_soc_dai_driver bfin_ac97_dai = {
-	.ac97_control = 1,
-	.probe = bf5xx_ac97_probe,
-	.remove = bf5xx_ac97_remove,
-	.suspend = bf5xx_ac97_suspend,
-	.resume = bf5xx_ac97_resume,
-	.playback = {
-		.stream_name = "AC97 Playback",
-		.channels_min = 2,
-#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
-		.channels_max = 6,
-#else
-		.channels_max = 2,
-#endif
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
-	.capture = {
-		.stream_name = "AC97 Capture",
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
-};
-EXPORT_SYMBOL_GPL(bfin_ac97_dai);
-
-static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
-{
-	return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
-}
 
 
-static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_dai(&pdev->dev);
 	return 0;
 	return 0;
 }
 }
 
 

+ 21 - 21
sound/soc/blackfin/bf5xx-ad1836.c

@@ -29,22 +29,12 @@
 #include <asm/portmux.h>
 #include <asm/portmux.h>
 
 
 #include "../codecs/ad1836.h"
 #include "../codecs/ad1836.h"
-#include "bf5xx-sport.h"
 
 
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm.h"
 #include "bf5xx-tdm.h"
 
 
 static struct snd_soc_card bf5xx_ad1836;
 static struct snd_soc_card bf5xx_ad1836;
 
 
-static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 	struct snd_pcm_hw_params *params)
 {
 {
@@ -75,23 +65,33 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 }
 }
 
 
 static struct snd_soc_ops bf5xx_ad1836_ops = {
 static struct snd_soc_ops bf5xx_ad1836_ops = {
-	.startup = bf5xx_ad1836_startup,
 	.hw_params = bf5xx_ad1836_hw_params,
 	.hw_params = bf5xx_ad1836_hw_params,
 };
 };
 
 
-static struct snd_soc_dai_link bf5xx_ad1836_dai = {
-	.name = "ad1836",
-	.stream_name = "AD1836",
-	.cpu_dai_name = "bf5xx-tdm",
-	.codec_dai_name = "ad1836-hifi",
-	.platform_name = "bf5xx-tdm-pcm-audio",
-	.codec_name = "ad1836-codec.0",
-	.ops = &bf5xx_ad1836_ops,
+static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
+	{
+		.name = "ad1836",
+		.stream_name = "AD1836",
+		.cpu_dai_name = "bfin-tdm.0",
+		.codec_dai_name = "ad1836-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad1836.0",
+		.ops = &bf5xx_ad1836_ops,
+	},
+	{
+		.name = "ad1836",
+		.stream_name = "AD1836",
+		.cpu_dai_name = "bfin-tdm.1",
+		.codec_dai_name = "ad1836-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad1836.0",
+		.ops = &bf5xx_ad1836_ops,
+	},
 };
 };
 
 
 static struct snd_soc_card bf5xx_ad1836 = {
 static struct snd_soc_card bf5xx_ad1836 = {
-	.name = "bf5xx_ad1836",
-	.dai_link = &bf5xx_ad1836_dai,
+	.name = "bfin-ad1836",
+	.dai_link = &bf5xx_ad1836_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 	.num_links = 1,
 };
 };
 
 

+ 35 - 21
sound/soc/blackfin/bf5xx-ad193x.c

@@ -38,30 +38,28 @@
 #include <asm/portmux.h>
 #include <asm/portmux.h>
 
 
 #include "../codecs/ad193x.h"
 #include "../codecs/ad193x.h"
-#include "bf5xx-sport.h"
 
 
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm.h"
 #include "bf5xx-tdm.h"
 
 
 static struct snd_soc_card bf5xx_ad193x;
 static struct snd_soc_card bf5xx_ad193x;
 
 
-static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 	struct snd_pcm_hw_params *params)
 {
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int clk = 0;
 	unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
 	unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
 	int ret = 0;
 	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 48000:
+		clk = 12288000;
+		break;
+	}
+
 	/* set cpu DAI configuration */
 	/* set cpu DAI configuration */
 	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
 	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
 		SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
 		SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
@@ -74,6 +72,12 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
+	/* set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
 	/* set codec DAI slots, 8 channels, all channels are enabled */
 	/* set codec DAI slots, 8 channels, all channels are enabled */
 	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
 	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
 	if (ret < 0)
 	if (ret < 0)
@@ -89,23 +93,33 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 }
 }
 
 
 static struct snd_soc_ops bf5xx_ad193x_ops = {
 static struct snd_soc_ops bf5xx_ad193x_ops = {
-	.startup = bf5xx_ad193x_startup,
 	.hw_params = bf5xx_ad193x_hw_params,
 	.hw_params = bf5xx_ad193x_hw_params,
 };
 };
 
 
-static struct snd_soc_dai_link bf5xx_ad193x_dai = {
-	.name = "ad193x",
-	.stream_name = "AD193X",
-	.cpu_dai_name = "bf5xx-tdm",
-	.codec_dai_name ="ad193x-hifi",
-	.platform_name = "bf5xx-tdm-pcm-audio",
-	.codec_name = "ad193x-codec.5",
-	.ops = &bf5xx_ad193x_ops,
+static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
+	{
+		.name = "ad193x",
+		.stream_name = "AD193X",
+		.cpu_dai_name = "bfin-tdm.0",
+		.codec_dai_name ="ad193x-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad193x.5",
+		.ops = &bf5xx_ad193x_ops,
+	},
+	{
+		.name = "ad193x",
+		.stream_name = "AD193X",
+		.cpu_dai_name = "bfin-tdm.1",
+		.codec_dai_name ="ad193x-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad193x.5",
+		.ops = &bf5xx_ad193x_ops,
+	},
 };
 };
 
 
 static struct snd_soc_card bf5xx_ad193x = {
 static struct snd_soc_card bf5xx_ad193x = {
-	.name = "bf5xx_ad193x",
-	.dai_link = &bf5xx_ad193x_dai,
+	.name = "bfin-ad193x",
+	.dai_link = &bf5xx_ad193x_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 	.num_links = 1,
 };
 };
 
 

+ 20 - 25
sound/soc/blackfin/bf5xx-ad1980.c

@@ -47,39 +47,34 @@
 #include <asm/portmux.h>
 #include <asm/portmux.h>
 
 
 #include "../codecs/ad1980.h"
 #include "../codecs/ad1980.h"
-#include "bf5xx-sport.h"
+
 #include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 #include "bf5xx-ac97.h"
 
 
 static struct snd_soc_card bf5xx_board;
 static struct snd_soc_card bf5xx_board;
 
 
-static int bf5xx_board_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	pr_debug("%s enter\n", __func__);
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
-static struct snd_soc_ops bf5xx_board_ops = {
-	.startup = bf5xx_board_startup,
-};
-
-static struct snd_soc_dai_link bf5xx_board_dai = {
-	.name = "AC97",
-	.stream_name = "AC97 HiFi",
-	.cpu_dai_name = "bfin-ac97",
-	.codec_dai_name = "ad1980-hifi",
-	.platform_name = "bfin-pcm-audio",
-	.codec_name = "ad1980-codec",
-	.ops = &bf5xx_board_ops,
+static struct snd_soc_dai_link bf5xx_board_dai[] = {
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		.cpu_dai_name = "bfin-ac97.0",
+		.codec_dai_name = "ad1980-hifi",
+		.platform_name = "bfin-ac97-pcm-audio",
+		.codec_name = "ad1980",
+	},
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		.cpu_dai_name = "bfin-ac97.1",
+		.codec_dai_name = "ad1980-hifi",
+		.platform_name = "bfin-ac97-pcm-audio",
+		.codec_name = "ad1980",
+	},
 };
 };
 
 
 static struct snd_soc_card bf5xx_board = {
 static struct snd_soc_card bf5xx_board = {
-	.name = "bf5xx-board",
-	.dai_link = &bf5xx_board_dai,
+	.name = "bfin-ad1980",
+	.dai_link = &bf5xx_board_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 	.num_links = 1,
 };
 };
 
 

+ 21 - 21
sound/soc/blackfin/bf5xx-ad73311.c

@@ -145,16 +145,6 @@ static int bf5xx_probe(struct platform_device *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
-static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	pr_debug("%s enter\n", __func__);
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 	struct snd_pcm_hw_params *params)
 {
 {
@@ -176,24 +166,34 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 
 
 
 
 static struct snd_soc_ops bf5xx_ad73311_ops = {
 static struct snd_soc_ops bf5xx_ad73311_ops = {
-	.startup = bf5xx_ad73311_startup,
 	.hw_params = bf5xx_ad73311_hw_params,
 	.hw_params = bf5xx_ad73311_hw_params,
 };
 };
 
 
-static struct snd_soc_dai_link bf5xx_ad73311_dai = {
-	.name = "ad73311",
-	.stream_name = "AD73311",
-	.cpu_dai_name = "bf5xx-i2s",
-	.codec_dai_name = "ad73311-hifi",
-	.platform_name = "bfin-pcm-audio",
-	.codec_name = "ad73311-codec",
-	.ops = &bf5xx_ad73311_ops,
+static struct snd_soc_dai_link bf5xx_ad73311_dai[] = {
+	{
+		.name = "ad73311",
+		.stream_name = "AD73311",
+		.cpu_dai_name = "bfin-i2s.0",
+		.codec_dai_name = "ad73311-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ad73311",
+		.ops = &bf5xx_ad73311_ops,
+	},
+	{
+		.name = "ad73311",
+		.stream_name = "AD73311",
+		.cpu_dai_name = "bfin-i2s.1",
+		.codec_dai_name = "ad73311-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ad73311",
+		.ops = &bf5xx_ad73311_ops,
+	},
 };
 };
 
 
 static struct snd_soc_card bf5xx_ad73311 = {
 static struct snd_soc_card bf5xx_ad73311 = {
-	.name = "bf5xx_ad73311",
+	.name = "bfin-ad73311",
 	.probe = bf5xx_probe,
 	.probe = bf5xx_probe,
-	.dai_link = &bf5xx_ad73311_dai,
+	.dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 	.num_links = 1,
 };
 };
 
 

+ 13 - 10
sound/soc/blackfin/bf5xx-i2s-pcm.c

@@ -148,10 +148,15 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
 	int ret;
 	int ret;
 
 
 	pr_debug("%s enter\n", __func__);
 	pr_debug("%s enter\n", __func__);
+
 	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
 	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
 
 
 	ret = snd_pcm_hw_constraint_integer(runtime, \
 	ret = snd_pcm_hw_constraint_integer(runtime, \
@@ -159,9 +164,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
-	if (sport_handle != NULL)
+	if (sport_handle != NULL) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sport_handle->tx_buf = buf->area;
+		else
+			sport_handle->rx_buf = buf->area;
+
 		runtime->private_data = sport_handle;
 		runtime->private_data = sport_handle;
-	else {
+	} else {
 		pr_err("sport_handle is NULL\n");
 		pr_err("sport_handle is NULL\n");
 		return -1;
 		return -1;
 	}
 	}
@@ -214,11 +224,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 	pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
 	pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
 		buf->area, buf->bytes);
 		buf->area, buf->bytes);
 
 
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-		sport_handle->tx_buf = buf->area;
-	else
-		sport_handle->rx_buf = buf->area;
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -239,8 +244,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		buf->area = NULL;
 		buf->area = NULL;
 	}
 	}
-	if (sport_handle)
-		sport_done(sport_handle);
 }
 }
 
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -292,7 +295,7 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
 
 
 static struct platform_driver bfin_i2s_pcm_driver = {
 static struct platform_driver bfin_i2s_pcm_driver = {
 	.driver = {
 	.driver = {
-			.name = "bfin-pcm-audio",
+			.name = "bfin-i2s-pcm-audio",
 			.owner = THIS_MODULE,
 			.owner = THIS_MODULE,
 	},
 	},
 
 

+ 73 - 99
sound/soc/blackfin/bf5xx-i2s.c

@@ -51,59 +51,24 @@ struct bf5xx_i2s_port {
 	int configured;
 	int configured;
 };
 };
 
 
-static struct bf5xx_i2s_port bf5xx_i2s;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-	{
-		.dma_rx_chan	= CH_SPORT0_RX,
-		.dma_tx_chan	= CH_SPORT0_TX,
-		.err_irq	= IRQ_SPORT0_ERROR,
-		.regs		= (struct sport_register *)SPORT0_TCR1,
-	},
-	{
-		.dma_rx_chan	= CH_SPORT1_RX,
-		.dma_tx_chan	= CH_SPORT1_TX,
-		.err_irq	= IRQ_SPORT1_ERROR,
-		.regs		= (struct sport_register *)SPORT1_TCR1,
-	}
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-		P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-		{P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-		P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 		unsigned int fmt)
 		unsigned int fmt)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 	int ret = 0;
 	int ret = 0;
 
 
 	/* interface format:support I2S,slave mode */
 	/* interface format:support I2S,slave mode */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 	case SND_SOC_DAIFMT_I2S:
-		bf5xx_i2s.tcr1 |= TFSR | TCKFE;
-		bf5xx_i2s.rcr1 |= RFSR | RCKFE;
-		bf5xx_i2s.tcr2 |= TSFSE;
-		bf5xx_i2s.rcr2 |= RSFSE;
+		bf5xx_i2s->tcr1 |= TFSR | TCKFE;
+		bf5xx_i2s->rcr1 |= RFSR | RCKFE;
+		bf5xx_i2s->tcr2 |= TSFSE;
+		bf5xx_i2s->rcr2 |= RSFSE;
 		break;
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
 	case SND_SOC_DAIFMT_DSP_A:
-		bf5xx_i2s.tcr1 |= TFSR;
-		bf5xx_i2s.rcr1 |= RFSR;
+		bf5xx_i2s->tcr1 |= TFSR;
+		bf5xx_i2s->rcr1 |= RFSR;
 		break;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 	case SND_SOC_DAIFMT_LEFT_J:
 		ret = -EINVAL;
 		ret = -EINVAL;
@@ -135,29 +100,35 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 				struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 	int ret = 0;
 	int ret = 0;
 
 
-	bf5xx_i2s.tcr2 &= ~0x1f;
-	bf5xx_i2s.rcr2 &= ~0x1f;
+	bf5xx_i2s->tcr2 &= ~0x1f;
+	bf5xx_i2s->rcr2 &= ~0x1f;
 	switch (params_format(params)) {
 	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		bf5xx_i2s->tcr2 |= 7;
+		bf5xx_i2s->rcr2 |= 7;
+		sport_handle->wdsize = 1;
 	case SNDRV_PCM_FORMAT_S16_LE:
 	case SNDRV_PCM_FORMAT_S16_LE:
-		bf5xx_i2s.tcr2 |= 15;
-		bf5xx_i2s.rcr2 |= 15;
+		bf5xx_i2s->tcr2 |= 15;
+		bf5xx_i2s->rcr2 |= 15;
 		sport_handle->wdsize = 2;
 		sport_handle->wdsize = 2;
 		break;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
 	case SNDRV_PCM_FORMAT_S24_LE:
-		bf5xx_i2s.tcr2 |= 23;
-		bf5xx_i2s.rcr2 |= 23;
+		bf5xx_i2s->tcr2 |= 23;
+		bf5xx_i2s->rcr2 |= 23;
 		sport_handle->wdsize = 3;
 		sport_handle->wdsize = 3;
 		break;
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
 	case SNDRV_PCM_FORMAT_S32_LE:
-		bf5xx_i2s.tcr2 |= 31;
-		bf5xx_i2s.rcr2 |= 31;
+		bf5xx_i2s->tcr2 |= 31;
+		bf5xx_i2s->rcr2 |= 31;
 		sport_handle->wdsize = 4;
 		sport_handle->wdsize = 4;
 		break;
 		break;
 	}
 	}
 
 
-	if (!bf5xx_i2s.configured) {
+	if (!bf5xx_i2s->configured) {
 		/*
 		/*
 		 * TX and RX are not independent,they are enabled at the
 		 * TX and RX are not independent,they are enabled at the
 		 * same time, even if only one side is running. So, we
 		 * same time, even if only one side is running. So, we
@@ -166,16 +137,16 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 		 *
 		 *
 		 * CPU DAI:slave mode.
 		 * CPU DAI:slave mode.
 		 */
 		 */
-		bf5xx_i2s.configured = 1;
-		ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
-				      bf5xx_i2s.rcr2, 0, 0);
+		bf5xx_i2s->configured = 1;
+		ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
+				      bf5xx_i2s->rcr2, 0, 0);
 		if (ret) {
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 			return -EBUSY;
 		}
 		}
 
 
-		ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
-				      bf5xx_i2s.tcr2, 0, 0);
+		ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
+				      bf5xx_i2s->tcr2, 0, 0);
 		if (ret) {
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 			return -EBUSY;
@@ -188,41 +159,19 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
 static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 			       struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+
 	pr_debug("%s enter\n", __func__);
 	pr_debug("%s enter\n", __func__);
 	/* No active stream, SPORT is allowed to be configured again. */
 	/* No active stream, SPORT is allowed to be configured again. */
 	if (!dai->active)
 	if (!dai->active)
-		bf5xx_i2s.configured = 0;
-}
-
-static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
-{
-	pr_debug("%s enter\n", __func__);
-	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-		pr_err("Requesting Peripherals failed\n");
-		return -EFAULT;
-	}
-
-	/* request DMA for SPORT */
-	sport_handle = sport_init(&sport_params[sport_num], 4, \
-			2 * sizeof(u32), NULL);
-	if (!sport_handle) {
-		peripheral_free_list(&sport_req[sport_num][0]);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
-{
-	pr_debug("%s enter\n", __func__);
-	peripheral_free_list(&sport_req[sport_num][0]);
-	return 0;
+		bf5xx_i2s->configured = 0;
 }
 }
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
 
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 
 
@@ -235,19 +184,21 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 
 
 static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 	int ret;
 	int ret;
 
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 
 
-	ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
-				      bf5xx_i2s.rcr2, 0, 0);
+	ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
+				      bf5xx_i2s->rcr2, 0, 0);
 	if (ret) {
 	if (ret) {
 		pr_err("SPORT is busy!\n");
 		pr_err("SPORT is busy!\n");
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 
 
-	ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
-				      bf5xx_i2s.tcr2, 0, 0);
+	ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
+				      bf5xx_i2s->tcr2, 0, 0);
 	if (ret) {
 	if (ret) {
 		pr_err("SPORT is busy!\n");
 		pr_err("SPORT is busy!\n");
 		return -EBUSY;
 		return -EBUSY;
@@ -266,8 +217,11 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
 		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
 		SNDRV_PCM_RATE_96000)
 		SNDRV_PCM_RATE_96000)
 
 
-#define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
-	SNDRV_PCM_FMTBIT_S32_LE)
+#define BF5XX_I2S_FORMATS \
+	(SNDRV_PCM_FMTBIT_S8 | \
+	 SNDRV_PCM_FMTBIT_S16_LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE | \
+	 SNDRV_PCM_FMTBIT_S32_LE)
 
 
 static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 	.shutdown	= bf5xx_i2s_shutdown,
 	.shutdown	= bf5xx_i2s_shutdown,
@@ -276,8 +230,6 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 };
 };
 
 
 static struct snd_soc_dai_driver bf5xx_i2s_dai = {
 static struct snd_soc_dai_driver bf5xx_i2s_dai = {
-	.probe = bf5xx_i2s_probe,
-	.remove = bf5xx_i2s_remove,
 	.suspend = bf5xx_i2s_suspend,
 	.suspend = bf5xx_i2s_suspend,
 	.resume = bf5xx_i2s_resume,
 	.resume = bf5xx_i2s_resume,
 	.playback = {
 	.playback = {
@@ -293,23 +245,45 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = {
 	.ops = &bf5xx_i2s_dai_ops,
 	.ops = &bf5xx_i2s_dai_ops,
 };
 };
 
 
-static int bfin_i2s_drv_probe(struct platform_device *pdev)
+static int __devinit bf5xx_i2s_probe(struct platform_device *pdev)
 {
 {
-	return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+	struct sport_device *sport_handle;
+	int ret;
+
+	/* configure SPORT for I2S */
+	sport_handle = sport_init(pdev, 4, 2 * sizeof(u32),
+		sizeof(struct bf5xx_i2s_port));
+	if (!sport_handle)
+		return -ENODEV;
+
+	/* register with the ASoC layers */
+	ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+	if (ret) {
+		pr_err("Failed to register DAI: %d\n", ret);
+		sport_done(sport_handle);
+		return ret;
+	}
+
+	return 0;
 }
 }
 
 
-static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
+static int __devexit bf5xx_i2s_remove(struct platform_device *pdev)
 {
 {
+	struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
+	pr_debug("%s enter\n", __func__);
+
 	snd_soc_unregister_dai(&pdev->dev);
 	snd_soc_unregister_dai(&pdev->dev);
+	sport_done(sport_handle);
+
 	return 0;
 	return 0;
 }
 }
 
 
 static struct platform_driver bfin_i2s_driver = {
 static struct platform_driver bfin_i2s_driver = {
-	.probe = bfin_i2s_drv_probe,
-	.remove = __devexit_p(bfin_i2s_drv_remove),
-
+	.probe  = bf5xx_i2s_probe,
+	.remove = __devexit_p(bf5xx_i2s_remove),
 	.driver = {
 	.driver = {
-		.name = "bf5xx-i2s",
+		.name = "bfin-i2s",
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 	},
 	},
 };
 };

+ 119 - 40
sound/soc/blackfin/bf5xx-sport.c

@@ -42,8 +42,6 @@
 /* delay between frame sync pulse and first data bit in multichannel mode */
 /* delay between frame sync pulse and first data bit in multichannel mode */
 #define FRAME_DELAY (1<<12)
 #define FRAME_DELAY (1<<12)
 
 
-struct sport_device *sport_handle;
-EXPORT_SYMBOL(sport_handle);
 /* note: multichannel is in units of 8 channels,
 /* note: multichannel is in units of 8 channels,
  * tdm_count is # channels NOT / 8 ! */
  * tdm_count is # channels NOT / 8 ! */
 int sport_set_multichannel(struct sport_device *sport,
 int sport_set_multichannel(struct sport_device *sport,
@@ -798,86 +796,164 @@ int sport_set_err_callback(struct sport_device *sport,
 }
 }
 EXPORT_SYMBOL(sport_set_err_callback);
 EXPORT_SYMBOL(sport_set_err_callback);
 
 
-struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
-		unsigned dummy_count, void *private_data)
+static int sport_config_pdev(struct platform_device *pdev, struct sport_param *param)
 {
 {
-	int ret;
+	/* Extract settings from platform data */
+	struct device *dev = &pdev->dev;
+	struct bfin_snd_platform_data *pdata = dev->platform_data;
+	struct resource *res;
+
+	param->num = pdev->id;
+
+	if (!pdata) {
+		dev_err(dev, "no platform_data\n");
+		return -ENODEV;
+	}
+	param->pin_req = pdata->pin_req;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "no MEM resource\n");
+		return -ENODEV;
+	}
+	param->regs = (struct sport_register *)res->start;
+
+	/* first RX, then TX */
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!res) {
+		dev_err(dev, "no rx DMA resource\n");
+		return -ENODEV;
+	}
+	param->dma_rx_chan = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!res) {
+		dev_err(dev, "no tx DMA resource\n");
+		return -ENODEV;
+	}
+	param->dma_tx_chan = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(dev, "no irq resource\n");
+		return -ENODEV;
+	}
+	param->err_irq = res->start;
+
+	return 0;
+}
+
+struct sport_device *sport_init(struct platform_device *pdev,
+	unsigned int wdsize, unsigned int dummy_count, size_t priv_size)
+{
+	struct device *dev = &pdev->dev;
+	struct sport_param param;
 	struct sport_device *sport;
 	struct sport_device *sport;
-	pr_debug("%s enter\n", __func__);
-	BUG_ON(param == NULL);
-	BUG_ON(wdsize == 0 || dummy_count == 0);
-	sport = kmalloc(sizeof(struct sport_device), GFP_KERNEL);
-	if (!sport) {
-		pr_err("Failed to allocate for sport device\n");
+	int ret;
+
+	dev_dbg(dev, "%s enter\n", __func__);
+
+	param.wdsize = wdsize;
+	param.dummy_count = dummy_count;
+	BUG_ON(param.wdsize == 0 || param.dummy_count == 0);
+
+	ret = sport_config_pdev(pdev, &param);
+	if (ret)
+		return NULL;
+
+	if (peripheral_request_list(param.pin_req, "soc-audio")) {
+		dev_err(dev, "requesting Peripherals failed\n");
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	memset(sport, 0, sizeof(struct sport_device));
-	sport->dma_rx_chan = param->dma_rx_chan;
-	sport->dma_tx_chan = param->dma_tx_chan;
-	sport->err_irq = param->err_irq;
-	sport->regs = param->regs;
-	sport->private_data = private_data;
+	sport = kzalloc(sizeof(*sport), GFP_KERNEL);
+	if (!sport) {
+		dev_err(dev, "failed to allocate for sport device\n");
+		goto __init_err0;
+	}
+
+	sport->num = param.num;
+	sport->dma_rx_chan = param.dma_rx_chan;
+	sport->dma_tx_chan = param.dma_tx_chan;
+	sport->err_irq = param.err_irq;
+	sport->regs = param.regs;
+	sport->pin_req = param.pin_req;
 
 
 	if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) {
 	if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) {
-		pr_err("Failed to request RX dma %d\n", \
-				sport->dma_rx_chan);
+		dev_err(dev, "failed to request RX dma %d\n", sport->dma_rx_chan);
 		goto __init_err1;
 		goto __init_err1;
 	}
 	}
 	if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) {
 	if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) {
-		pr_err("Failed to request RX irq %d\n", \
-				sport->dma_rx_chan);
+		dev_err(dev, "failed to request RX irq %d\n", sport->dma_rx_chan);
 		goto __init_err2;
 		goto __init_err2;
 	}
 	}
 
 
 	if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) {
 	if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) {
-		pr_err("Failed to request TX dma %d\n", \
-				sport->dma_tx_chan);
+		dev_err(dev, "failed to request TX dma %d\n", sport->dma_tx_chan);
 		goto __init_err2;
 		goto __init_err2;
 	}
 	}
 
 
 	if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) {
 	if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) {
-		pr_err("Failed to request TX irq %d\n", \
-				sport->dma_tx_chan);
+		dev_err(dev, "failed to request TX irq %d\n", sport->dma_tx_chan);
 		goto __init_err3;
 		goto __init_err3;
 	}
 	}
 
 
 	if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err",
 	if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err",
 			sport) < 0) {
 			sport) < 0) {
-		pr_err("Failed to request err irq:%d\n", \
-				sport->err_irq);
+		dev_err(dev, "failed to request err irq %d\n", sport->err_irq);
 		goto __init_err3;
 		goto __init_err3;
 	}
 	}
 
 
-	pr_err("dma rx:%d tx:%d, err irq:%d, regs:%p\n",
+	dev_info(dev, "dma rx:%d tx:%d, err irq:%d, regs:%p\n",
 			sport->dma_rx_chan, sport->dma_tx_chan,
 			sport->dma_rx_chan, sport->dma_tx_chan,
 			sport->err_irq, sport->regs);
 			sport->err_irq, sport->regs);
 
 
-	sport->wdsize = wdsize;
-	sport->dummy_count = dummy_count;
+	sport->wdsize = param.wdsize;
+	sport->dummy_count = param.dummy_count;
+
+	sport->private_data = kzalloc(priv_size, GFP_KERNEL);
+	if (!sport->private_data) {
+		dev_err(dev, "could not alloc priv data %zu bytes\n", priv_size);
+		goto __init_err4;
+	}
 
 
 	if (L1_DATA_A_LENGTH)
 	if (L1_DATA_A_LENGTH)
-		sport->dummy_buf = l1_data_sram_zalloc(dummy_count * 2);
+		sport->dummy_buf = l1_data_sram_zalloc(param.dummy_count * 2);
 	else
 	else
-		sport->dummy_buf = kzalloc(dummy_count * 2, GFP_KERNEL);
+		sport->dummy_buf = kzalloc(param.dummy_count * 2, GFP_KERNEL);
 	if (sport->dummy_buf == NULL) {
 	if (sport->dummy_buf == NULL) {
-		pr_err("Failed to allocate dummy buffer\n");
-		goto __error;
+		dev_err(dev, "failed to allocate dummy buffer\n");
+		goto __error1;
 	}
 	}
 
 
 	ret = sport_config_rx_dummy(sport);
 	ret = sport_config_rx_dummy(sport);
 	if (ret) {
 	if (ret) {
-		pr_err("Failed to config rx dummy ring\n");
-		goto __error;
+		dev_err(dev, "failed to config rx dummy ring\n");
+		goto __error2;
 	}
 	}
 	ret = sport_config_tx_dummy(sport);
 	ret = sport_config_tx_dummy(sport);
 	if (ret) {
 	if (ret) {
-		pr_err("Failed to config tx dummy ring\n");
-		goto __error;
+		dev_err(dev, "failed to config tx dummy ring\n");
+		goto __error3;
 	}
 	}
 
 
+	platform_set_drvdata(pdev, sport);
+
 	return sport;
 	return sport;
-__error:
+__error3:
+	if (L1_DATA_A_LENGTH)
+		l1_data_sram_free(sport->dummy_rx_desc);
+	else
+		dma_free_coherent(NULL, 2*sizeof(struct dmasg),
+				sport->dummy_rx_desc, 0);
+__error2:
+	if (L1_DATA_A_LENGTH)
+		l1_data_sram_free(sport->dummy_buf);
+	else
+		kfree(sport->dummy_buf);
+__error1:
+	kfree(sport->private_data);
+__init_err4:
 	free_irq(sport->err_irq, sport);
 	free_irq(sport->err_irq, sport);
 __init_err3:
 __init_err3:
 	free_dma(sport->dma_tx_chan);
 	free_dma(sport->dma_tx_chan);
@@ -885,6 +961,8 @@ __init_err2:
 	free_dma(sport->dma_rx_chan);
 	free_dma(sport->dma_rx_chan);
 __init_err1:
 __init_err1:
 	kfree(sport);
 	kfree(sport);
+__init_err0:
+	peripheral_free_list(param.pin_req);
 	return NULL;
 	return NULL;
 }
 }
 EXPORT_SYMBOL(sport_init);
 EXPORT_SYMBOL(sport_init);
@@ -917,8 +995,9 @@ void sport_done(struct sport_device *sport)
 	free_dma(sport->dma_tx_chan);
 	free_dma(sport->dma_tx_chan);
 	free_irq(sport->err_irq, sport);
 	free_irq(sport->err_irq, sport);
 
 
+	kfree(sport->private_data);
+	peripheral_free_list(sport->pin_req);
 	kfree(sport);
 	kfree(sport);
-		sport = NULL;
 }
 }
 EXPORT_SYMBOL(sport_done);
 EXPORT_SYMBOL(sport_done);
 
 

+ 11 - 5
sound/soc/blackfin/bf5xx-sport.h

@@ -1,5 +1,5 @@
 /*
 /*
- * File:         bf5xx_ac97_sport.h
+ * File:         bf5xx_sport.h
  * Based on:
  * Based on:
  * Author:       Roy Huang <roy.huang@analog.com>
  * Author:       Roy Huang <roy.huang@analog.com>
  *
  *
@@ -33,15 +33,18 @@
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
+#include <linux/platform_device.h>
 #include <asm/dma.h>
 #include <asm/dma.h>
 #include <asm/bfin_sport.h>
 #include <asm/bfin_sport.h>
 
 
 #define DESC_ELEMENT_COUNT 9
 #define DESC_ELEMENT_COUNT 9
 
 
 struct sport_device {
 struct sport_device {
+	int num;
 	int dma_rx_chan;
 	int dma_rx_chan;
 	int dma_tx_chan;
 	int dma_tx_chan;
 	int err_irq;
 	int err_irq;
+	const unsigned short *pin_req;
 	struct sport_register *regs;
 	struct sport_register *regs;
 
 
 	unsigned char *rx_buf;
 	unsigned char *rx_buf;
@@ -103,17 +106,20 @@ struct sport_device {
 	void *private_data;
 	void *private_data;
 };
 };
 
 
-extern struct sport_device *sport_handle;
-
 struct sport_param {
 struct sport_param {
+	int num;
 	int dma_rx_chan;
 	int dma_rx_chan;
 	int dma_tx_chan;
 	int dma_tx_chan;
 	int err_irq;
 	int err_irq;
+	const unsigned short *pin_req;
 	struct sport_register *regs;
 	struct sport_register *regs;
+	unsigned int wdsize;
+	unsigned int dummy_count;
+	void *private_data;
 };
 };
 
 
-struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
-		unsigned dummy_count, void *private_data);
+struct sport_device *sport_init(struct platform_device *pdev,
+	unsigned int wdsize, unsigned int dummy_count, size_t priv_size);
 
 
 void sport_done(struct sport_device *sport);
 void sport_done(struct sport_device *sport);
 
 

+ 21 - 21
sound/soc/blackfin/bf5xx-ssm2602.c

@@ -44,16 +44,6 @@
 
 
 static struct snd_soc_card bf5xx_ssm2602;
 static struct snd_soc_card bf5xx_ssm2602;
 
 
-static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	pr_debug("%s enter\n", __func__);
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 	struct snd_pcm_hw_params *params)
 {
 {
@@ -109,23 +99,33 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 }
 }
 
 
 static struct snd_soc_ops bf5xx_ssm2602_ops = {
 static struct snd_soc_ops bf5xx_ssm2602_ops = {
-	.startup = bf5xx_ssm2602_startup,
 	.hw_params = bf5xx_ssm2602_hw_params,
 	.hw_params = bf5xx_ssm2602_hw_params,
 };
 };
 
 
-static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
-	.name = "ssm2602",
-	.stream_name = "SSM2602",
-	.cpu_dai_name = "bf5xx-i2s",
-	.codec_dai_name = "ssm2602-hifi",
-	.platform_name = "bf5xx-pcm-audio",
-	.codec_name = "ssm2602-codec.0-001b",
-	.ops = &bf5xx_ssm2602_ops,
+static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
+	{
+		.name = "ssm2602",
+		.stream_name = "SSM2602",
+		.cpu_dai_name = "bfin-i2s.0",
+		.codec_dai_name = "ssm2602-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ssm2602.0-001b",
+		.ops = &bf5xx_ssm2602_ops,
+	},
+	{
+		.name = "ssm2602",
+		.stream_name = "SSM2602",
+		.cpu_dai_name = "bfin-i2s.1",
+		.codec_dai_name = "ssm2602-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ssm2602.0-001b",
+		.ops = &bf5xx_ssm2602_ops,
+	},
 };
 };
 
 
 static struct snd_soc_card bf5xx_ssm2602 = {
 static struct snd_soc_card bf5xx_ssm2602 = {
-	.name = "bf5xx_ssm2602",
-	.dai_link = &bf5xx_ssm2602_dai,
+	.name = "bfin-ssm2602",
+	.dai_link = &bf5xx_ssm2602_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 	.num_links = 1,
 };
 };
 
 

+ 13 - 10
sound/soc/blackfin/bf5xx-tdm-pcm.c

@@ -154,7 +154,12 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+
 	int ret = 0;
 	int ret = 0;
 
 
 	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
 	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
@@ -164,9 +169,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
-	if (sport_handle != NULL)
+	if (sport_handle != NULL) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sport_handle->tx_buf = buf->area;
+		else
+			sport_handle->rx_buf = buf->area;
+
 		runtime->private_data = sport_handle;
 		runtime->private_data = sport_handle;
-	else {
+	} else {
 		pr_err("sport_handle is NULL\n");
 		pr_err("sport_handle is NULL\n");
 		ret = -ENODEV;
 		ret = -ENODEV;
 	}
 	}
@@ -249,11 +259,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 	}
 	}
 	buf->bytes = size;
 	buf->bytes = size;
 
 
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-		sport_handle->tx_buf = buf->area;
-	else
-		sport_handle->rx_buf = buf->area;
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -274,8 +279,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		buf->area = NULL;
 		buf->area = NULL;
 	}
 	}
-	if (sport_handle)
-		sport_done(sport_handle);
 }
 }
 
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -326,7 +329,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 
 
 static struct platform_driver bfin_tdm_driver = {
 static struct platform_driver bfin_tdm_driver = {
 	.driver = {
 	.driver = {
-			.name = "bf5xx-tdm-pcm-audio",
+			.name = "bfin-tdm-pcm-audio",
 			.owner = THIS_MODULE,
 			.owner = THIS_MODULE,
 	},
 	},
 
 

+ 38 - 72
sound/soc/blackfin/bf5xx-tdm.c

@@ -46,43 +46,6 @@
 #include "bf5xx-sport.h"
 #include "bf5xx-sport.h"
 #include "bf5xx-tdm.h"
 #include "bf5xx-tdm.h"
 
 
-static struct bf5xx_tdm_port bf5xx_tdm;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-	{
-		.dma_rx_chan    = CH_SPORT0_RX,
-		.dma_tx_chan    = CH_SPORT0_TX,
-		.err_irq        = IRQ_SPORT0_ERROR,
-		.regs           = (struct sport_register *)SPORT0_TCR1,
-	},
-	{
-		.dma_rx_chan    = CH_SPORT1_RX,
-		.dma_tx_chan    = CH_SPORT1_TX,
-		.err_irq        = IRQ_SPORT1_ERROR,
-		.regs           = (struct sport_register *)SPORT1_TCR1,
-	}
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-	P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-	   {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-		   P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 	unsigned int fmt)
 	unsigned int fmt)
 {
 {
@@ -119,14 +82,16 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 	struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
 	int ret = 0;
 	int ret = 0;
 
 
-	bf5xx_tdm.tcr2 &= ~0x1f;
-	bf5xx_tdm.rcr2 &= ~0x1f;
+	bf5xx_tdm->tcr2 &= ~0x1f;
+	bf5xx_tdm->rcr2 &= ~0x1f;
 	switch (params_format(params)) {
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S32_LE:
 	case SNDRV_PCM_FORMAT_S32_LE:
-		bf5xx_tdm.tcr2 |= 31;
-		bf5xx_tdm.rcr2 |= 31;
+		bf5xx_tdm->tcr2 |= 31;
+		bf5xx_tdm->rcr2 |= 31;
 		sport_handle->wdsize = 4;
 		sport_handle->wdsize = 4;
 		break;
 		break;
 		/* at present, we only support 32bit transfer */
 		/* at present, we only support 32bit transfer */
@@ -136,7 +101,7 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 		break;
 		break;
 	}
 	}
 
 
-	if (!bf5xx_tdm.configured) {
+	if (!bf5xx_tdm->configured) {
 		/*
 		/*
 		 * TX and RX are not independent,they are enabled at the
 		 * TX and RX are not independent,they are enabled at the
 		 * same time, even if only one side is running. So, we
 		 * same time, even if only one side is running. So, we
@@ -145,21 +110,21 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 		 *
 		 *
 		 * CPU DAI:slave mode.
 		 * CPU DAI:slave mode.
 		 */
 		 */
-		ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1,
-			bf5xx_tdm.rcr2, 0, 0);
+		ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1,
+			bf5xx_tdm->rcr2, 0, 0);
 		if (ret) {
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 			return -EBUSY;
 		}
 		}
 
 
-		ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1,
-			bf5xx_tdm.tcr2, 0, 0);
+		ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1,
+			bf5xx_tdm->tcr2, 0, 0);
 		if (ret) {
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 			return -EBUSY;
 		}
 		}
 
 
-		bf5xx_tdm.configured = 1;
+		bf5xx_tdm->configured = 1;
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -168,15 +133,20 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
 static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 	struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
+
 	/* No active stream, SPORT is allowed to be configured again. */
 	/* No active stream, SPORT is allowed to be configured again. */
 	if (!dai->active)
 	if (!dai->active)
-		bf5xx_tdm.configured = 0;
+		bf5xx_tdm->configured = 0;
 }
 }
 
 
 static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 		unsigned int tx_num, unsigned int *tx_slot,
 		unsigned int tx_num, unsigned int *tx_slot,
 		unsigned int rx_num, unsigned int *rx_slot)
 		unsigned int rx_num, unsigned int *rx_slot)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
 	int i;
 	int i;
 	unsigned int slot;
 	unsigned int slot;
 	unsigned int tx_mapped = 0, rx_mapped = 0;
 	unsigned int tx_mapped = 0, rx_mapped = 0;
@@ -189,7 +159,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 		slot = tx_slot[i];
 		slot = tx_slot[i];
 		if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
 		if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
 				(!(tx_mapped & (1 << slot)))) {
 				(!(tx_mapped & (1 << slot)))) {
-			bf5xx_tdm.tx_map[i] = slot;
+			bf5xx_tdm->tx_map[i] = slot;
 			tx_mapped |= 1 << slot;
 			tx_mapped |= 1 << slot;
 		} else
 		} else
 			return -EINVAL;
 			return -EINVAL;
@@ -198,7 +168,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 		slot = rx_slot[i];
 		slot = rx_slot[i];
 		if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
 		if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
 				(!(rx_mapped & (1 << slot)))) {
 				(!(rx_mapped & (1 << slot)))) {
-			bf5xx_tdm.rx_map[i] = slot;
+			bf5xx_tdm->rx_map[i] = slot;
 			rx_mapped |= 1 << slot;
 			rx_mapped |= 1 << slot;
 		} else
 		} else
 			return -EINVAL;
 			return -EINVAL;
@@ -212,12 +182,14 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 {
 {
 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
 
-	if (!dai->active)
-		return 0;
-	if (dai->capture_active)
-		sport_rx_stop(sport);
 	if (dai->playback_active)
 	if (dai->playback_active)
 		sport_tx_stop(sport);
 		sport_tx_stop(sport);
+	if (dai->capture_active)
+		sport_rx_stop(sport);
+
+	/* isolate sync/clock pins from codec while sports resume */
+	peripheral_free_list(sport->pin_req);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -226,9 +198,6 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 	int ret;
 	int ret;
 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
 
-	if (!dai->active)
-		return 0;
-
 	ret = sport_set_multichannel(sport, 8, 0xFF, 1);
 	ret = sport_set_multichannel(sport, 8, 0xFF, 1);
 	if (ret) {
 	if (ret) {
 		pr_err("SPORT is busy!\n");
 		pr_err("SPORT is busy!\n");
@@ -247,6 +216,8 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 		ret = -EBUSY;
 		ret = -EBUSY;
 	}
 	}
 
 
+	peripheral_request_list(sport->pin_req, "soc-audio");
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -280,20 +251,14 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = {
 
 
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 {
 {
-	int ret = 0;
-
-	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-		pr_err("Requesting Peripherals failed\n");
-		return -EFAULT;
-	}
+	struct sport_device *sport_handle;
+	int ret;
 
 
-	/* request DMA for SPORT */
-	sport_handle = sport_init(&sport_params[sport_num], 4, \
-		8 * sizeof(u32), NULL);
-	if (!sport_handle) {
-		peripheral_free_list(&sport_req[sport_num][0]);
+	/* configure SPORT for TDM */
+	sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
+		sizeof(struct bf5xx_tdm_port));
+	if (!sport_handle)
 		return -ENODEV;
 		return -ENODEV;
-	}
 
 
 	/* SPORT works in TDM mode */
 	/* SPORT works in TDM mode */
 	ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
 	ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
@@ -323,18 +288,19 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 		goto sport_config_err;
 		goto sport_config_err;
 	}
 	}
 
 
-	sport_handle->private_data = &bf5xx_tdm;
 	return 0;
 	return 0;
 
 
 sport_config_err:
 sport_config_err:
-	peripheral_free_list(&sport_req[sport_num][0]);
+	sport_done(sport_handle);
 	return ret;
 	return ret;
 }
 }
 
 
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 {
 {
-	peripheral_free_list(&sport_req[sport_num][0]);
+	struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
 	snd_soc_unregister_dai(&pdev->dev);
 	snd_soc_unregister_dai(&pdev->dev);
+	sport_done(sport_handle);
 
 
 	return 0;
 	return 0;
 }
 }

+ 1 - 1
sound/soc/codecs/88pm860x-codec.c

@@ -120,7 +120,7 @@
  */
  */
 #define PM860X_DAPM_OUTPUT(wname, wevent)	\
 #define PM860X_DAPM_OUTPUT(wname, wevent)	\
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
-	.shift = 0, .invert = 0, .kcontrols = NULL, \
+	.shift = 0, .invert = 0, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .event = wevent, \
 	.num_kcontrols = 0, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
 
 

+ 18 - 2
sound/soc/codecs/Kconfig

@@ -16,10 +16,11 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_AD1836 if SPI_MASTER
 	select SND_SOC_AD1836 if SPI_MASTER
 	select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_AD1980 if SND_SOC_AC97_BUS
 	select SND_SOC_AD1980 if SND_SOC_AC97_BUS
+	select SND_SOC_AD73311
 	select SND_SOC_ADS117X
 	select SND_SOC_ADS117X
-	select SND_SOC_AD73311 if I2C
 	select SND_SOC_AK4104 if SPI_MASTER
 	select SND_SOC_AK4104 if SPI_MASTER
 	select SND_SOC_AK4535 if I2C
 	select SND_SOC_AK4535 if I2C
+	select SND_SOC_AK4641 if I2C
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4671 if I2C
 	select SND_SOC_AK4671 if I2C
 	select SND_SOC_ALC5623 if I2C
 	select SND_SOC_ALC5623 if I2C
@@ -33,13 +34,14 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_JZ4740_CODEC if SOC_JZ4740
 	select SND_SOC_JZ4740_CODEC if SOC_JZ4740
 	select SND_SOC_LM4857 if I2C
 	select SND_SOC_LM4857 if I2C
 	select SND_SOC_MAX98088 if I2C
 	select SND_SOC_MAX98088 if I2C
+	select SND_SOC_MAX98095 if I2C
 	select SND_SOC_MAX9850 if I2C
 	select SND_SOC_MAX9850 if I2C
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_PCM3008
 	select SND_SOC_PCM3008
 	select SND_SOC_SGTL5000 if I2C
 	select SND_SOC_SGTL5000 if I2C
 	select SND_SOC_SN95031 if INTEL_SCU_IPC
 	select SND_SOC_SN95031 if INTEL_SCU_IPC
 	select SND_SOC_SPDIF
 	select SND_SOC_SPDIF
-	select SND_SOC_SSM2602 if I2C
+	select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -52,6 +54,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_UDA134X
 	select SND_SOC_UDA134X
 	select SND_SOC_UDA1380 if I2C
 	select SND_SOC_UDA1380 if I2C
 	select SND_SOC_WL1273 if MFD_WL1273_CORE
 	select SND_SOC_WL1273 if MFD_WL1273_CORE
+	select SND_SOC_WM1250_EV1 if I2C
 	select SND_SOC_WM2000 if I2C
 	select SND_SOC_WM2000 if I2C
 	select SND_SOC_WM8350 if MFD_WM8350
 	select SND_SOC_WM8350 if MFD_WM8350
 	select SND_SOC_WM8400 if MFD_WM8400
 	select SND_SOC_WM8400 if MFD_WM8400
@@ -72,6 +75,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_WM8900 if I2C
 	select SND_SOC_WM8900 if I2C
 	select SND_SOC_WM8903 if I2C
 	select SND_SOC_WM8903 if I2C
 	select SND_SOC_WM8904 if I2C
 	select SND_SOC_WM8904 if I2C
+	select SND_SOC_WM8915 if I2C
 	select SND_SOC_WM8940 if I2C
 	select SND_SOC_WM8940 if I2C
 	select SND_SOC_WM8955 if I2C
 	select SND_SOC_WM8955 if I2C
 	select SND_SOC_WM8960 if I2C
 	select SND_SOC_WM8960 if I2C
@@ -136,6 +140,9 @@ config SND_SOC_AK4104
 config SND_SOC_AK4535
 config SND_SOC_AK4535
 	tristate
 	tristate
 
 
+config SND_SOC_AK4641
+	tristate
+
 config SND_SOC_AK4642
 config SND_SOC_AK4642
 	tristate
 	tristate
 
 
@@ -187,6 +194,9 @@ config SND_SOC_DMIC
 config SND_SOC_MAX98088
 config SND_SOC_MAX98088
        tristate
        tristate
 
 
+config SND_SOC_MAX98095
+       tristate
+
 config SND_SOC_MAX9850
 config SND_SOC_MAX9850
 	tristate
 	tristate
 
 
@@ -241,6 +251,9 @@ config SND_SOC_UDA1380
 config SND_SOC_WL1273
 config SND_SOC_WL1273
 	tristate
 	tristate
 
 
+config SND_SOC_WM1250_EV1
+	tristate
+
 config SND_SOC_WM8350
 config SND_SOC_WM8350
 	tristate
 	tristate
 
 
@@ -298,6 +311,9 @@ config SND_SOC_WM8903
 config SND_SOC_WM8904
 config SND_SOC_WM8904
 	tristate
 	tristate
 
 
+config SND_SOC_WM8915
+	tristate
+
 config SND_SOC_WM8940
 config SND_SOC_WM8940
         tristate
         tristate
 
 

+ 9 - 1
sound/soc/codecs/Makefile

@@ -7,6 +7,7 @@ snd-soc-ad73311-objs := ad73311.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4535-objs := ak4535.o
+snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cq93vc-objs := cq93vc.o
@@ -19,6 +20,7 @@ snd-soc-dfbmcs320-objs := dfbmcs320.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-l3-objs := l3.o
 snd-soc-l3-objs := l3.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-max98088-objs := max98088.o
+snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-sgtl5000-objs := sgtl5000.o
@@ -37,6 +39,7 @@ snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wl1273-objs := wl1273.o
+snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
 snd-soc-wm8510-objs := wm8510.o
@@ -56,6 +59,7 @@ snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
 snd-soc-wm8904-objs := wm8904.o
+snd-soc-wm8915-objs := wm8915.o
 snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8960-objs := wm8960.o
 snd-soc-wm8960-objs := wm8960.o
@@ -69,7 +73,7 @@ snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8991-objs := wm8991.o
 snd-soc-wm8991-objs := wm8991.o
 snd-soc-wm8993-objs := wm8993.o
 snd-soc-wm8993-objs := wm8993.o
-snd-soc-wm8994-objs := wm8994.o wm8994-tables.o
+snd-soc-wm8994-objs := wm8994.o wm8994-tables.o wm8958-dsp2.o
 snd-soc-wm8995-objs := wm8995.o
 snd-soc-wm8995-objs := wm8995.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9705-objs := wm9705.o
@@ -94,6 +98,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_AK4641)	+= snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
@@ -108,6 +113,7 @@ obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
+obj-$(CONFIG_SND_SOC_MAX98095)	+= snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
@@ -125,6 +131,7 @@ obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
+obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)	+= snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8400)	+= snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
 obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
@@ -144,6 +151,7 @@ obj-$(CONFIG_SND_SOC_WM8804)	+= snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)	+= snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8900)	+= snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)	+= snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8903)	+= snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)	+= snd-soc-wm8904.o
 obj-$(CONFIG_SND_SOC_WM8904)	+= snd-soc-wm8904.o
+obj-$(CONFIG_SND_SOC_WM8915)	+= snd-soc-wm8915.o
 obj-$(CONFIG_SND_SOC_WM8940)	+= snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8940)	+= snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8955)	+= snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8955)	+= snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8960)	+= snd-soc-wm8960.o
 obj-$(CONFIG_SND_SOC_WM8960)	+= snd-soc-wm8960.o

+ 9 - 14
sound/soc/codecs/ad193x.c

@@ -23,8 +23,7 @@
 
 
 /* codec private data */
 /* codec private data */
 struct ad193x_priv {
 struct ad193x_priv {
-	enum snd_soc_control_type bus_type;
-	void *control_data;
+	enum snd_soc_control_type control_type;
 	int sysclk;
 	int sysclk;
 };
 };
 
 
@@ -354,14 +353,12 @@ static int ad193x_probe(struct snd_soc_codec *codec)
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret;
 	int ret;
 
 
-	codec->control_data = ad193x->control_data;
-	if (ad193x->bus_type == SND_SOC_I2C)
-		ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
+	if (ad193x->control_type == SND_SOC_I2C)
+		ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->control_type);
 	else
 	else
-		ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
+		ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->control_type);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(codec->dev, "failed to set cache I/O: %d\n",
-				ret);
+		dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -408,8 +405,7 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	spi_set_drvdata(spi, ad193x);
 	spi_set_drvdata(spi, ad193x);
-	ad193x->control_data = spi;
-	ad193x->bus_type = SND_SOC_SPI;
+	ad193x->control_type = SND_SOC_SPI;
 
 
 	ret = snd_soc_register_codec(&spi->dev,
 	ret = snd_soc_register_codec(&spi->dev,
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
@@ -427,7 +423,7 @@ static int __devexit ad193x_spi_remove(struct spi_device *spi)
 
 
 static struct spi_driver ad193x_spi_driver = {
 static struct spi_driver ad193x_spi_driver = {
 	.driver = {
 	.driver = {
-		.name	= "ad193x-codec",
+		.name	= "ad193x",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 	},
 	},
 	.probe		= ad193x_spi_probe,
 	.probe		= ad193x_spi_probe,
@@ -454,8 +450,7 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	i2c_set_clientdata(client, ad193x);
 	i2c_set_clientdata(client, ad193x);
-	ad193x->control_data = client;
-	ad193x->bus_type = SND_SOC_I2C;
+	ad193x->control_type = SND_SOC_I2C;
 
 
 	ret =  snd_soc_register_codec(&client->dev,
 	ret =  snd_soc_register_codec(&client->dev,
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
@@ -473,7 +468,7 @@ static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 
 
 static struct i2c_driver ad193x_i2c_driver = {
 static struct i2c_driver ad193x_i2c_driver = {
 	.driver = {
 	.driver = {
-		.name = "ad193x-codec",
+		.name = "ad193x",
 	},
 	},
 	.probe    = ad193x_i2c_probe,
 	.probe    = ad193x_i2c_probe,
 	.remove   = __devexit_p(ad193x_i2c_remove),
 	.remove   = __devexit_p(ad193x_i2c_remove),

+ 1 - 1
sound/soc/codecs/ad1980.c

@@ -266,7 +266,7 @@ static int __devexit ad1980_remove(struct platform_device *pdev)
 
 
 static struct platform_driver ad1980_codec_driver = {
 static struct platform_driver ad1980_codec_driver = {
 	.driver = {
 	.driver = {
-			.name = "ad1980-codec",
+			.name = "ad1980",
 			.owner = THIS_MODULE,
 			.owner = THIS_MODULE,
 	},
 	},
 
 

+ 1 - 1
sound/soc/codecs/ad73311.c

@@ -55,7 +55,7 @@ static int __devexit ad73311_remove(struct platform_device *pdev)
 
 
 static struct platform_driver ad73311_codec_driver = {
 static struct platform_driver ad73311_codec_driver = {
 	.driver = {
 	.driver = {
-			.name = "ad73311-codec",
+			.name = "ad73311",
 			.owner = THIS_MODULE,
 			.owner = THIS_MODULE,
 	},
 	},
 
 

+ 5 - 14
sound/soc/codecs/ak4535.c

@@ -230,7 +230,7 @@ static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = {
 	SND_SOC_DAPM_INPUT("AIN"),
 	SND_SOC_DAPM_INPUT("AIN"),
 };
 };
 
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route ak4535_audio_map[] = {
 	/*stereo mixer */
 	/*stereo mixer */
 	{"Stereo Mixer", "Playback Switch", "DAC"},
 	{"Stereo Mixer", "Playback Switch", "DAC"},
 	{"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
 	{"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
@@ -287,17 +287,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Input Mixer", "Aux Capture Switch", "Aux In"},
 	{"Input Mixer", "Aux Capture Switch", "Aux In"},
 };
 };
 
 
-static int ak4535_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, ak4535_dapm_widgets,
-				  ARRAY_SIZE(ak4535_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	int clk_id, unsigned int freq, int dir)
 	int clk_id, unsigned int freq, int dir)
 {
 {
@@ -457,8 +446,6 @@ static int ak4535_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_add_controls(codec, ak4535_snd_controls,
 	snd_soc_add_controls(codec, ak4535_snd_controls,
 				ARRAY_SIZE(ak4535_snd_controls));
 				ARRAY_SIZE(ak4535_snd_controls));
-	ak4535_add_widgets(codec);
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -480,6 +467,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
 	.reg_cache_size = ARRAY_SIZE(ak4535_reg),
 	.reg_cache_size = ARRAY_SIZE(ak4535_reg),
 	.reg_word_size = sizeof(u8),
 	.reg_word_size = sizeof(u8),
 	.reg_cache_default = ak4535_reg,
 	.reg_cache_default = ak4535_reg,
+	.dapm_widgets = ak4535_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
+	.dapm_routes = ak4535_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(ak4535_audio_map),
 };
 };
 
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff