Browse Source

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: (365 commits)
  ALSA: hda - Disable sticky PCM stream assignment for AD codecs
  ALSA: usb - Creative USB X-Fi volume knob support
  ALSA: ca0106: Use card specific dac id for mute controls.
  ALSA: ca0106: Allow different sound cards to use different SPI channel mappings.
  ALSA: ca0106: Create a nice spot for mapping channels to dacs.
  ALSA: ca0106: Move enabling of front dac out of hardcoded setup sequence.
  ALSA: ca0106: Pull out dac powering routine into separate function.
  ALSA: ca0106 - add Sound Blaster 5.1vx info.
  ASoC: tlv320dac33: Use usleep_range for delays
  ALSA: usb-audio: add Novation Launchpad support
  ALSA: hda - Add workarounds for CT-IBG controllers
  ALSA: hda - Fix wrong TLV mute bit for STAC/IDT codecs
  ASoC: tpa6130a2: Error handling for broken chip
  ASoC: max98088: Staticise m98088_eq_band
  ASoC: soc-core: Fix codec->name memory leak
  ALSA: hda - Apply ideapad quirk to Acer laptops with Cxt5066
  ALSA: hda - Add some workarounds for Creative IBG
  ALSA: hda - Fix wrong SPDIF NID assignment for CA0110
  ALSA: hda - Fix codec rename rules for ALC662-compatible codecs
  ALSA: hda - Add alc_init_jacks() call to other codecs
  ...
Linus Torvalds 15 years ago
parent
commit
33081adf8b
100 changed files with 4046 additions and 1677 deletions
  1. 68 14
      Documentation/sound/alsa/ALSA-Configuration.txt
  2. 5 3
      Documentation/sound/alsa/HD-Audio.txt
  3. 13 0
      arch/arm/mach-davinci/devices.c
  4. 40 0
      arch/arm/mach-ep93xx/core.c
  5. 1 0
      arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
  6. 1 0
      arch/arm/mach-ep93xx/include/mach/platform.h
  7. 1 0
      arch/arm/mach-ep93xx/simone.c
  8. 6 0
      arch/arm/mach-kirkwood/common.c
  9. 26 0
      arch/arm/mach-omap1/devices.c
  10. 12 5
      arch/arm/mach-omap2/board-rx51-peripherals.c
  11. 12 0
      arch/arm/mach-omap2/board-zoom-peripherals.c
  12. 1 35
      arch/arm/mach-omap2/board-zoom2.c
  13. 39 0
      arch/arm/mach-omap2/devices.c
  14. 2 0
      arch/arm/mach-omap2/include/mach/board-zoom.h
  15. 25 0
      arch/arm/mach-pxa/devices.c
  16. 6 0
      arch/arm/mach-pxa/devices.h
  17. 4 0
      arch/arm/mach-pxa/pxa27x.c
  18. 5 0
      arch/arm/mach-pxa/pxa3xx.c
  19. 11 0
      arch/arm/mach-pxa/zylonite.c
  20. 18 2
      arch/arm/mach-s3c64xx/dev-audio.c
  21. 1 0
      arch/arm/mach-s3c64xx/mach-smdk6410.c
  22. 7 0
      arch/arm/plat-omap/include/plat/mcbsp.h
  23. 30 4
      arch/arm/plat-s3c24xx/devs.c
  24. 2 0
      arch/arm/plat-samsung/include/plat/devs.h
  25. 6 0
      arch/mips/alchemy/devboards/db1200/platform.c
  26. 1 0
      arch/powerpc/boot/dts/mpc8610_hpcd.dts
  27. 3 0
      arch/powerpc/configs/mpc85xx_defconfig
  28. 3 0
      arch/powerpc/configs/mpc85xx_smp_defconfig
  29. 76 35
      arch/powerpc/include/asm/fsl_guts.h
  30. 209 2
      arch/powerpc/platforms/85xx/p1022_ds.c
  31. 1 1
      arch/sh/kernel/cpu/sh4a/setup-sh7722.c
  32. 2 2
      drivers/input/misc/twl4030-vibra.c
  33. 3 3
      drivers/mfd/twl-core.c
  34. 4 4
      drivers/mfd/twl4030-codec.c
  35. 1 1
      drivers/staging/xgifb/TODO
  36. 3 0
      drivers/video/Kconfig
  37. 83 1
      drivers/video/sh_mobile_hdmi.c
  38. 5 1
      include/linux/i2c/twl.h
  39. 1 1
      include/sound/core.h
  40. 2 0
      include/sound/emu10k1.h
  41. 4 1
      include/sound/jack.h
  42. 50 0
      include/sound/max98088.h
  43. 1 0
      include/sound/pcm.h
  44. 0 3
      include/sound/sh_fsi.h
  45. 63 35
      include/sound/soc-dai.h
  46. 14 4
      include/sound/soc-dapm.h
  47. 0 25
      include/sound/soc-of-simple.h
  48. 148 97
      include/sound/soc.h
  49. 3 1
      include/sound/tlv.h
  50. 42 1
      include/sound/tlv320aic3x.h
  51. 32 0
      include/sound/wm8962.h
  52. 16 0
      include/video/sh_mobile_hdmi.h
  53. 7 2
      sound/core/init.c
  54. 19 15
      sound/core/oss/mixer_oss.c
  55. 1 2
      sound/core/pcm.c
  56. 9 5
      sound/core/pcm_lib.c
  57. 3 1
      sound/core/pcm_native.c
  58. 19 0
      sound/drivers/Kconfig
  59. 2 0
      sound/drivers/Makefile
  60. 1258 0
      sound/drivers/aloop.c
  61. 1 1
      sound/drivers/virmidi.c
  62. 1 1
      sound/i2c/other/ak4xxx-adda.c
  63. 26 10
      sound/isa/Kconfig
  64. 1 3
      sound/isa/Makefile
  65. 1 1
      sound/isa/ad1816a/ad1816a.c
  66. 1 1
      sound/isa/azt2320.c
  67. 10 0
      sound/isa/galaxy/Makefile
  68. 91 0
      sound/isa/galaxy/azt1605.c
  69. 111 0
      sound/isa/galaxy/azt2316.c
  70. 652 0
      sound/isa/galaxy/galaxy.c
  71. 2 2
      sound/isa/gus/gusmax.c
  72. 1 1
      sound/isa/sb/sb8.c
  73. 0 369
      sound/isa/sgalaxy.c
  74. 0 8
      sound/oss/Kconfig
  75. 0 1
      sound/oss/Makefile
  76. 24 24
      sound/oss/au1550_ac97.c
  77. 21 20
      sound/oss/dmasound/dmasound_core.c
  78. 8 7
      sound/oss/msnd_pinnacle.c
  79. 0 325
      sound/oss/sh_dac_audio.c
  80. 22 21
      sound/oss/soundcard.c
  81. 10 10
      sound/oss/swarm_cs4297a.c
  82. 15 15
      sound/oss/vwsnd.c
  83. 11 6
      sound/pci/Kconfig
  84. 1 1
      sound/pci/au88x0/au88x0_mixer.c
  85. 3 2
      sound/pci/ca0106/ca0106.h
  86. 93 43
      sound/pci/ca0106/ca0106_main.c
  87. 70 23
      sound/pci/ca0106/ca0106_mixer.c
  88. 1 1
      sound/pci/emu10k1/emumpu401.c
  89. 6 33
      sound/pci/hda/Kconfig
  90. 3 12
      sound/pci/hda/Makefile
  91. 216 55
      sound/pci/hda/hda_codec.c
  92. 13 0
      sound/pci/hda/hda_codec.h
  93. 0 7
      sound/pci/hda/hda_eld.c
  94. 5 36
      sound/pci/hda/hda_generic.c
  95. 53 48
      sound/pci/hda/hda_intel.c
  96. 40 11
      sound/pci/hda/hda_local.h
  97. 28 20
      sound/pci/hda/patch_analog.c
  98. 0 224
      sound/pci/hda/patch_atihdmi.c
  99. 5 5
      sound/pci/hda/patch_ca0110.c
  100. 70 24
      sound/pci/hda/patch_cirrus.c

+ 68 - 14
Documentation/sound/alsa/ALSA-Configuration.txt

@@ -300,6 +300,74 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
            control correctly. If you have problems regarding this, try
            control correctly. If you have problems regarding this, try
            another ALSA compliant mixer (alsamixer works).
            another ALSA compliant mixer (alsamixer works).
 
 
+  Module snd-azt1605
+  ------------------
+
+    Module for Aztech Sound Galaxy soundcards based on the Aztech AZT1605
+    chipset.
+
+    port	- port # for BASE (0x220,0x240,0x260,0x280)
+    wss_port	- port # for WSS (0x530,0x604,0xe80,0xf40)
+    irq		- IRQ # for WSS (7,9,10,11)
+    dma1	- DMA # for WSS playback (0,1,3)
+    dma2	- DMA # for WSS capture (0,1), -1 = disabled (default)
+    mpu_port	- port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+    mpu_irq	- IRQ # for MPU-401 UART (3,5,7,9), -1 = disabled (default)
+    fm_port	- port # for OPL3 (0x388), -1 = disabled (default)
+
+    This module supports multiple cards. It does not support autoprobe: port,
+    wss_port, irq and dma1 have to be specified. The other values are
+    optional.
+
+    "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+    or the value stored in the card's EEPROM for cards that have an EEPROM and
+    their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+    be choosen freely from the options enumerated above.
+
+    If dma2 is specified and different from dma1, the card will operate in
+    full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+    enable capture since only channels 0 and 1 are available for capture.
+
+    Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+    mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+    Whatever IRQ and DMA channels you pick, be sure to reserve them for
+    legacy ISA in your BIOS.
+
+  Module snd-azt2316
+  ------------------
+
+    Module for Aztech Sound Galaxy soundcards based on the Aztech AZT2316
+    chipset.
+
+    port	- port # for BASE (0x220,0x240,0x260,0x280)
+    wss_port	- port # for WSS (0x530,0x604,0xe80,0xf40)
+    irq		- IRQ # for WSS (7,9,10,11)
+    dma1	- DMA # for WSS playback (0,1,3)
+    dma2	- DMA # for WSS capture (0,1), -1 = disabled (default)
+    mpu_port	- port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+    mpu_irq	- IRQ # for MPU-401 UART (5,7,9,10), -1 = disabled (default)
+    fm_port	- port # for OPL3 (0x388), -1 = disabled (default)
+
+    This module supports multiple cards. It does not support autoprobe: port,
+    wss_port, irq and dma1 have to be specified. The other values are
+    optional.
+
+    "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+    or the value stored in the card's EEPROM for cards that have an EEPROM and
+    their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+    be choosen freely from the options enumerated above.
+
+    If dma2 is specified and different from dma1, the card will operate in
+    full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+    enable capture since only channels 0 and 1 are available for capture.
+
+    Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+    mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+    Whatever IRQ and DMA channels you pick, be sure to reserve them for
+    legacy ISA in your BIOS.
+
   Module snd-aw2
   Module snd-aw2
   --------------
   --------------
 
 
@@ -1641,20 +1709,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
 
     This card is also known as Audio Excel DSP 16 or Zoltrix AV302.
     This card is also known as Audio Excel DSP 16 or Zoltrix AV302.
 
 
-  Module snd-sgalaxy
-  ------------------
-
-    Module for Aztech Sound Galaxy sound card.
-
-    sbport	- Port # for SB16 interface (0x220,0x240)
-    wssport	- Port # for WSS interface (0x530,0xe80,0xf40,0x604)
-    irq		- IRQ # (7,9,10,11)
-    dma1	- DMA #
-
-    This module supports multiple cards.
-
-    The power-management is supported.
-
   Module snd-sscape
   Module snd-sscape
   -----------------
   -----------------
 
 

+ 5 - 3
Documentation/sound/alsa/HD-Audio.txt

@@ -57,9 +57,11 @@ dead.  However, this detection isn't perfect on some devices.  In such
 a case, you can change the default method via `position_fix` option.
 a case, you can change the default method via `position_fix` option.
 
 
 `position_fix=1` means to use LPIB method explicitly.
 `position_fix=1` means to use LPIB method explicitly.
-`position_fix=2` means to use the position-buffer.  0 is the default
-value, the automatic check and fallback to LPIB as described in the
-above.  If you get a problem of repeated sounds, this option might
+`position_fix=2` means to use the position-buffer.
+`position_fix=3` means to use a combination of both methods, needed
+for some VIA and ATI controllers.  0 is the default value for all other
+controllers, the automatic check and fallback to LPIB as described in
+the above.  If you get a problem of repeated sounds, this option might
 help.
 help.
 
 
 In addition to that, every controller is known to be broken regarding
 In addition to that, every controller is known to be broken regarding

+ 13 - 0
arch/arm/mach-davinci/devices.c

@@ -295,6 +295,18 @@ static void davinci_init_wdt(void)
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
+struct platform_device davinci_pcm_device = {
+	.name		= "davinci-pcm-audio",
+	.id		= -1,
+};
+
+static void davinci_init_pcm(void)
+{
+	platform_device_register(&davinci_pcm_device);
+}
+
+/*-------------------------------------------------------------------------*/
+
 struct davinci_timer_instance davinci_timer_instance[2] = {
 struct davinci_timer_instance davinci_timer_instance[2] = {
 	{
 	{
 		.base		= DAVINCI_TIMER0_BASE,
 		.base		= DAVINCI_TIMER0_BASE,
@@ -315,6 +327,7 @@ static int __init davinci_init_devices(void)
 	/* please keep these calls, and their implementations above,
 	/* please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
 	 * in alphabetical order so they're easier to sort through.
 	 */
 	 */
+	davinci_init_pcm();
 	davinci_init_wdt();
 	davinci_init_wdt();
 
 
 	return 0;
 	return 0;

+ 40 - 0
arch/arm/mach-ep93xx/core.c

@@ -776,9 +776,15 @@ static struct platform_device ep93xx_i2s_device = {
 	.resource	= ep93xx_i2s_resource,
 	.resource	= ep93xx_i2s_resource,
 };
 };
 
 
+static struct platform_device ep93xx_pcm_device = {
+	.name		= "ep93xx-pcm-audio",
+	.id		= -1,
+};
+
 void __init ep93xx_register_i2s(void)
 void __init ep93xx_register_i2s(void)
 {
 {
 	platform_device_register(&ep93xx_i2s_device);
 	platform_device_register(&ep93xx_i2s_device);
+	platform_device_register(&ep93xx_pcm_device);
 }
 }
 
 
 #define EP93XX_SYSCON_DEVCFG_I2S_MASK	(EP93XX_SYSCON_DEVCFG_I2SONSSP | \
 #define EP93XX_SYSCON_DEVCFG_I2S_MASK	(EP93XX_SYSCON_DEVCFG_I2SONSSP | \
@@ -826,6 +832,40 @@ void ep93xx_i2s_release(void)
 }
 }
 EXPORT_SYMBOL(ep93xx_i2s_release);
 EXPORT_SYMBOL(ep93xx_i2s_release);
 
 
+/*************************************************************************
+ * EP93xx AC97 audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_ac97_resources[] = {
+	{
+		.start	= EP93XX_AAC_PHYS_BASE,
+		.end	= EP93XX_AAC_PHYS_BASE + 0xb0 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_EP93XX_AACINTR,
+		.end	= IRQ_EP93XX_AACINTR,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ep93xx_ac97_device = {
+	.name		= "ep93xx-ac97",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_ac97_resources),
+	.resource	= ep93xx_ac97_resources,
+};
+
+void __init ep93xx_register_ac97(void)
+{
+	/*
+	 * Make sure that the AC97 pins are not used by I2S.
+	 */
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97);
+
+	platform_device_register(&ep93xx_ac97_device);
+	platform_device_register(&ep93xx_pcm_device);
+}
+
 extern void ep93xx_gpio_init(void);
 extern void ep93xx_gpio_init(void);
 
 
 void __init ep93xx_init_devices(void)
 void __init ep93xx_init_devices(void)

+ 1 - 0
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h

@@ -105,6 +105,7 @@
 #define EP93XX_GPIO_B_INT_STATUS	EP93XX_GPIO_REG(0xbc)
 #define EP93XX_GPIO_B_INT_STATUS	EP93XX_GPIO_REG(0xbc)
 #define EP93XX_GPIO_EEDRIVE		EP93XX_GPIO_REG(0xc8)
 #define EP93XX_GPIO_EEDRIVE		EP93XX_GPIO_REG(0xc8)
 
 
+#define EP93XX_AAC_PHYS_BASE		EP93XX_APB_PHYS(0x00080000)
 #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
 #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
 
 
 #define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
 #define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)

+ 1 - 0
arch/arm/mach-ep93xx/include/mach/platform.h

@@ -61,6 +61,7 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev);
 void ep93xx_register_i2s(void);
 void ep93xx_register_i2s(void);
 int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
 int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
 void ep93xx_i2s_release(void);
 void ep93xx_i2s_release(void);
+void ep93xx_register_ac97(void);
 
 
 void ep93xx_init_devices(void);
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
 extern struct sys_timer ep93xx_timer;

+ 1 - 0
arch/arm/mach-ep93xx/simone.c

@@ -61,6 +61,7 @@ static void __init simone_init_machine(void)
 	ep93xx_register_fb(&simone_fb_info);
 	ep93xx_register_fb(&simone_fb_info);
 	ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
 	ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
 			    ARRAY_SIZE(simone_i2c_board_info));
 			    ARRAY_SIZE(simone_i2c_board_info));
+	ep93xx_register_ac97();
 }
 }
 
 
 MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
 MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")

+ 6 - 0
arch/arm/mach-kirkwood/common.c

@@ -903,10 +903,16 @@ static struct platform_device kirkwood_i2s_device = {
 	},
 	},
 };
 };
 
 
+static struct platform_device kirkwood_pcm_device = {
+	.name		= "kirkwood-pcm-audio",
+	.id		= -1,
+};
+
 void __init kirkwood_audio_init(void)
 void __init kirkwood_audio_init(void)
 {
 {
 	kirkwood_clk_ctrl |= CGC_AUDIO;
 	kirkwood_clk_ctrl |= CGC_AUDIO;
 	platform_device_register(&kirkwood_i2s_device);
 	platform_device_register(&kirkwood_i2s_device);
+	platform_device_register(&kirkwood_pcm_device);
 }
 }
 
 
 /*****************************************************************************
 /*****************************************************************************

+ 26 - 0
arch/arm/mach-omap1/devices.c

@@ -25,6 +25,7 @@
 #include <mach/gpio.h>
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 #include <plat/mmc.h>
 #include <plat/omap7xx.h>
 #include <plat/omap7xx.h>
+#include <plat/mcbsp.h>
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -195,6 +196,30 @@ static inline void omap_init_spi100k(void)
 
 
 static inline void omap_init_sti(void) {}
 static inline void omap_init_sti(void) {}
 
 
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+	.name	= "omap-pcm-audio",
+	.id	= -1,
+};
+
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+
+static void omap_init_audio(void)
+{
+	platform_device_register(&omap_mcbsp1);
+	platform_device_register(&omap_mcbsp2);
+	if (!cpu_is_omap7xx())
+		platform_device_register(&omap_mcbsp3);
+	platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /*
 /*
@@ -227,6 +252,7 @@ static int __init omap1_init_devices(void)
 	omap_init_rtc();
 	omap_init_rtc();
 	omap_init_spi100k();
 	omap_init_spi100k();
 	omap_init_sti();
 	omap_init_sti();
+	omap_init_audio();
 
 
 	return 0;
 	return 0;
 }
 }

+ 12 - 5
arch/arm/mach-omap2/board-rx51-peripherals.c

@@ -23,6 +23,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/gpio_keys.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
+#include <sound/tlv320aic3x.h>
 
 
 #include <plat/mcspi.h>
 #include <plat/mcspi.h>
 #include <plat/board.h>
 #include <plat/board.h>
@@ -689,7 +690,6 @@ static struct twl4030_power_data rx51_t2scripts_data __initdata = {
 };
 };
 
 
 
 
-
 static struct twl4030_platform_data rx51_twldata __initdata = {
 static struct twl4030_platform_data rx51_twldata __initdata = {
 	.irq_base		= TWL4030_IRQ_BASE,
 	.irq_base		= TWL4030_IRQ_BASE,
 	.irq_end		= TWL4030_IRQ_END,
 	.irq_end		= TWL4030_IRQ_END,
@@ -710,10 +710,6 @@ static struct twl4030_platform_data rx51_twldata __initdata = {
 	.vio			= &rx51_vio,
 	.vio			= &rx51_vio,
 };
 };
 
 
-static struct aic3x_pdata rx51_aic3x_data __initdata = {
-	.gpio_reset		= 60,
-};
-
 static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata = {
 static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata = {
 	.id			= TPA6130A2,
 	.id			= TPA6130A2,
 	.power_gpio		= 98,
 	.power_gpio		= 98,
@@ -728,6 +724,17 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
 	},
 	},
 };
 };
 
 
+/* Audio setup data */
+static struct aic3x_setup_data rx51_aic34_setup = {
+	.gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
+	.gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
+};
+
+static struct aic3x_pdata rx51_aic3x_data = {
+	.setup = &rx51_aic34_setup,
+	.gpio_reset = 60,
+};
+
 static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
 static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
 	{
 	{
 		I2C_BOARD_INFO("tlv320aic3x", 0x18),
 		I2C_BOARD_INFO("tlv320aic3x", 0x18),

+ 12 - 0
arch/arm/mach-omap2/board-zoom-peripherals.c

@@ -26,6 +26,8 @@
 #include <plat/common.h>
 #include <plat/common.h>
 #include <plat/usb.h>
 #include <plat/usb.h>
 
 
+#include <mach/board-zoom.h>
+
 #include "mux.h"
 #include "mux.h"
 #include "hsmmc.h"
 #include "hsmmc.h"
 
 
@@ -238,6 +240,11 @@ static int zoom_twl_gpio_setup(struct device *dev,
 	return 0;
 	return 0;
 }
 }
 
 
+/* EXTMUTE callback function */
+void zoom2_set_hs_extmute(int mute)
+{
+	gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
+}
 
 
 static int zoom_batt_table[] = {
 static int zoom_batt_table[] = {
 /* 0 C*/
 /* 0 C*/
@@ -307,6 +314,11 @@ static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
 
 
 static int __init omap_i2c_init(void)
 static int __init omap_i2c_init(void)
 {
 {
+	if (machine_is_omap_zoom2()) {
+		zoom_audio_data.ramp_delay_value = 3;	/* 161 ms */
+		zoom_audio_data.hs_extmute = 1;
+		zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
+	}
 	omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
 	omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
 			ARRAY_SIZE(zoom_i2c_boardinfo));
 			ARRAY_SIZE(zoom_i2c_boardinfo));
 	omap_register_i2c_bus(2, 400, NULL, 0);
 	omap_register_i2c_bus(2, 400, NULL, 0);

+ 1 - 35
arch/arm/mach-omap2/board-zoom2.c

@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
+#include <linux/i2c/twl.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
@@ -34,41 +35,6 @@ static void __init omap_zoom2_init_irq(void)
 	omap_gpio_init();
 	omap_gpio_init();
 }
 }
 
 
-/* REVISIT: These audio entries can be removed once MFD code is merged */
-#if 0
-
-static struct twl4030_madc_platform_data zoom2_madc_data = {
-	.irq_line	= 1,
-};
-
-static struct twl4030_codec_audio_data zoom2_audio_data = {
-	.audio_mclk = 26000000,
-};
-
-static struct twl4030_codec_data zoom2_codec_data = {
-	.audio_mclk = 26000000,
-	.audio = &zoom2_audio_data,
-};
-
-static struct twl4030_platform_data zoom2_twldata = {
-	.irq_base	= TWL4030_IRQ_BASE,
-	.irq_end	= TWL4030_IRQ_END,
-
-	/* platform_data for children goes here */
-	.bci		= &zoom2_bci_data,
-	.madc		= &zoom2_madc_data,
-	.usb		= &zoom2_usb_data,
-	.gpio		= &zoom2_gpio_data,
-	.keypad		= &zoom2_kp_twl4030_data,
-	.codec		= &zoom2_codec_data,
-	.vmmc1          = &zoom2_vmmc1,
-	.vmmc2          = &zoom2_vmmc2,
-	.vsim           = &zoom2_vsim,
-
-};
-
-#endif
-
 #ifdef CONFIG_OMAP_MUX
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
 static struct omap_board_mux board_mux[] __initdata = {
 	/* WLAN IRQ - GPIO 162 */
 	/* WLAN IRQ - GPIO 162 */

+ 39 - 0
arch/arm/mach-omap2/devices.c

@@ -25,6 +25,7 @@
 #include <plat/control.h>
 #include <plat/control.h>
 #include <plat/tc.h>
 #include <plat/tc.h>
 #include <plat/board.h>
 #include <plat/board.h>
+#include <plat/mcbsp.h>
 #include <mach/gpio.h>
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 #include <plat/mmc.h>
 #include <plat/dma.h>
 #include <plat/dma.h>
@@ -235,6 +236,43 @@ static inline void omap_init_mbox(void) { }
 
 
 static inline void omap_init_sti(void) {}
 static inline void omap_init_sti(void) {}
 
 
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+	.name	= "omap-pcm-audio",
+	.id	= -1,
+};
+
+/*
+ * OMAP2420 has 2 McBSP ports
+ * OMAP2430 has 5 McBSP ports
+ * OMAP3 has 5 McBSP ports
+ * OMAP4 has 4 McBSP ports
+ */
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+OMAP_MCBSP_PLATFORM_DEVICE(4);
+OMAP_MCBSP_PLATFORM_DEVICE(5);
+
+static void omap_init_audio(void)
+{
+	platform_device_register(&omap_mcbsp1);
+	platform_device_register(&omap_mcbsp2);
+	if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
+		platform_device_register(&omap_mcbsp3);
+		platform_device_register(&omap_mcbsp4);
+	}
+	if (cpu_is_omap243x() || cpu_is_omap34xx())
+		platform_device_register(&omap_mcbsp5);
+
+	platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
 #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
 #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
 
 
 #include <plat/mcspi.h>
 #include <plat/mcspi.h>
@@ -917,6 +955,7 @@ static int __init omap2_init_devices(void)
 	 * in alphabetical order so they're easier to sort through.
 	 * in alphabetical order so they're easier to sort through.
 	 */
 	 */
 	omap_hsmmc_reset();
 	omap_hsmmc_reset();
+	omap_init_audio();
 	omap_init_camera();
 	omap_init_camera();
 	omap_init_mbox();
 	omap_init_mbox();
 	omap_init_mcspi();
 	omap_init_mcspi();

+ 2 - 0
arch/arm/mach-omap2/include/mach/board-zoom.h

@@ -9,3 +9,5 @@
 extern void __init board_nand_init(struct mtd_partition *, u8 nr_parts, u8 cs);
 extern void __init board_nand_init(struct mtd_partition *, u8 nr_parts, u8 cs);
 extern int __init zoom_debugboard_init(void);
 extern int __init zoom_debugboard_init(void);
 extern void __init zoom_peripherals_init(void);
 extern void __init zoom_peripherals_init(void);
+
+#define ZOOM2_HEADSET_EXTMUTE_GPIO	153

+ 25 - 0
arch/arm/mach-pxa/devices.c

@@ -382,6 +382,31 @@ struct platform_device pxa_device_i2s = {
 	.num_resources	= ARRAY_SIZE(pxai2s_resources),
 	.num_resources	= ARRAY_SIZE(pxai2s_resources),
 };
 };
 
 
+struct platform_device pxa_device_asoc_ssp1 = {
+	.name		= "pxa-ssp-dai",
+	.id		= 0,
+};
+
+struct platform_device pxa_device_asoc_ssp2= {
+	.name		= "pxa-ssp-dai",
+	.id		= 1,
+};
+
+struct platform_device pxa_device_asoc_ssp3 = {
+	.name		= "pxa-ssp-dai",
+	.id		= 2,
+};
+
+struct platform_device pxa_device_asoc_ssp4 = {
+	.name		= "pxa-ssp-dai",
+	.id		= 3,
+};
+
+struct platform_device pxa_device_asoc_platform = {
+	.name		= "pxa-pcm-audio",
+	.id		= -1,
+};
+
 static u64 pxaficp_dmamask = ~(u32)0;
 static u64 pxaficp_dmamask = ~(u32)0;
 
 
 struct platform_device pxa_device_ficp = {
 struct platform_device pxa_device_ficp = {

+ 6 - 0
arch/arm/mach-pxa/devices.h

@@ -39,4 +39,10 @@ extern struct platform_device pxa3xx_device_i2c_power;
 
 
 extern struct platform_device pxa3xx_device_gcu;
 extern struct platform_device pxa3xx_device_gcu;
 
 
+extern struct platform_device pxa_device_asoc_platform;
+extern struct platform_device pxa_device_asoc_ssp1;
+extern struct platform_device pxa_device_asoc_ssp2;
+extern struct platform_device pxa_device_asoc_ssp3;
+extern struct platform_device pxa_device_asoc_ssp4;
+
 void __init pxa_register_device(struct platform_device *dev, void *data);
 void __init pxa_register_device(struct platform_device *dev, void *data);

+ 4 - 0
arch/arm/mach-pxa/pxa27x.c

@@ -385,6 +385,10 @@ static struct platform_device *devices[] __initdata = {
 	&pxa27x_device_udc,
 	&pxa27x_device_udc,
 	&pxa_device_pmu,
 	&pxa_device_pmu,
 	&pxa_device_i2s,
 	&pxa_device_i2s,
+	&pxa_device_asoc_ssp1,
+	&pxa_device_asoc_ssp2,
+	&pxa_device_asoc_ssp3,
+	&pxa_device_asoc_platform,
 	&sa1100_device_rtc,
 	&sa1100_device_rtc,
 	&pxa_device_rtc,
 	&pxa_device_rtc,
 	&pxa27x_device_ssp1,
 	&pxa27x_device_ssp1,

+ 5 - 0
arch/arm/mach-pxa/pxa3xx.c

@@ -593,6 +593,11 @@ static struct platform_device *devices[] __initdata = {
 	&pxa27x_device_udc,
 	&pxa27x_device_udc,
 	&pxa_device_pmu,
 	&pxa_device_pmu,
 	&pxa_device_i2s,
 	&pxa_device_i2s,
+	&pxa_device_asoc_ssp1,
+	&pxa_device_asoc_ssp2,
+	&pxa_device_asoc_ssp3,
+	&pxa_device_asoc_ssp4,
+	&pxa_device_asoc_platform,
 	&sa1100_device_rtc,
 	&sa1100_device_rtc,
 	&pxa_device_rtc,
 	&pxa_device_rtc,
 	&pxa27x_device_ssp1,
 	&pxa27x_device_ssp1,

+ 11 - 0
arch/arm/mach-pxa/zylonite.c

@@ -45,6 +45,16 @@ int wm9713_irq;
 int lcd_id;
 int lcd_id;
 int lcd_orientation;
 int lcd_orientation;
 
 
+struct platform_device pxa_device_wm9713_audio = {
+	.name		= "wm9713-codec",
+	.id		= -1,
+};
+
+static void __init zylonite_init_wm9713_audio(void)
+{
+	platform_device_register(&pxa_device_wm9713_audio);
+}
+
 static struct resource smc91x_resources[] = {
 static struct resource smc91x_resources[] = {
 	[0] = {
 	[0] = {
 		.start	= ZYLONITE_ETH_PHYS + 0x300,
 		.start	= ZYLONITE_ETH_PHYS + 0x300,
@@ -408,6 +418,7 @@ static void __init zylonite_init(void)
 	zylonite_init_nand();
 	zylonite_init_nand();
 	zylonite_init_leds();
 	zylonite_init_leds();
 	zylonite_init_ohci();
 	zylonite_init_ohci();
+	zylonite_init_wm9713_audio();
 }
 }
 
 
 MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
 MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")

+ 18 - 2
arch/arm/mach-s3c64xx/dev-audio.c

@@ -43,8 +43,10 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
 		s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
 		s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
 		s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
 		s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
 		s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
 		s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+		break;
 	default:
 	default:
-		printk(KERN_DEBUG "Invalid I2S Controller number!");
+		printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
+			pdev->id);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
@@ -184,7 +186,8 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
 		s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
 		s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
 		break;
 		break;
 	default:
 	default:
-		printk(KERN_DEBUG "Invalid PCM Controller number!");
+		printk(KERN_DEBUG "Invalid PCM Controller number: %d\n",
+			pdev->id);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
@@ -333,3 +336,16 @@ void __init s3c64xx_ac97_setup_gpio(int num)
 	else
 	else
 		s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
 		s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
 }
 }
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+	.name		  = "s3c24xx-pcm-audio",
+	.id		  = -1,
+	.dev              = {
+		.dma_mask = &s3c_device_audio_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+EXPORT_SYMBOL(s3c_device_pcm);
+

+ 1 - 0
arch/arm/mach-s3c64xx/mach-smdk6410.c

@@ -283,6 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
 	&s3c_device_fb,
 	&s3c_device_fb,
 	&s3c_device_ohci,
 	&s3c_device_ohci,
 	&s3c_device_usb_hsotg,
 	&s3c_device_usb_hsotg,
+	&s3c_device_pcm,
 	&s3c64xx_device_iisv4,
 	&s3c64xx_device_iisv4,
 	&samsung_device_keypad,
 	&samsung_device_keypad,
 
 

+ 7 - 0
arch/arm/plat-omap/include/plat/mcbsp.h

@@ -30,6 +30,13 @@
 #include <mach/hardware.h>
 #include <mach/hardware.h>
 #include <plat/clock.h>
 #include <plat/clock.h>
 
 
+/* macro for building platform_device for McBSP ports */
+#define OMAP_MCBSP_PLATFORM_DEVICE(port_nr)		\
+static struct platform_device omap_mcbsp##port_nr = {	\
+	.name	= "omap-mcbsp-dai",			\
+	.id	= OMAP_MCBSP##port_nr,			\
+}
+
 #define OMAP7XX_MCBSP1_BASE	0xfffb1000
 #define OMAP7XX_MCBSP1_BASE	0xfffb1000
 #define OMAP7XX_MCBSP2_BASE	0xfffb1800
 #define OMAP7XX_MCBSP2_BASE	0xfffb1800
 
 

+ 30 - 4
arch/arm/plat-s3c24xx/devs.c

@@ -247,7 +247,7 @@ static struct resource s3c_iis_resource[] = {
 static u64 s3c_device_iis_dmamask = 0xffffffffUL;
 static u64 s3c_device_iis_dmamask = 0xffffffffUL;
 
 
 struct platform_device s3c_device_iis = {
 struct platform_device s3c_device_iis = {
-	.name		  = "s3c2410-iis",
+	.name		  = "s3c24xx-iis",
 	.id		  = -1,
 	.id		  = -1,
 	.num_resources	  = ARRAY_SIZE(s3c_iis_resource),
 	.num_resources	  = ARRAY_SIZE(s3c_iis_resource),
 	.resource	  = s3c_iis_resource,
 	.resource	  = s3c_iis_resource,
@@ -259,6 +259,21 @@ struct platform_device s3c_device_iis = {
 
 
 EXPORT_SYMBOL(s3c_device_iis);
 EXPORT_SYMBOL(s3c_device_iis);
 
 
+/* ASoC PCM DMA */
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+	.name		  = "s3c24xx-pcm-audio",
+	.id		  = -1,
+	.dev              = {
+		.dma_mask = &s3c_device_audio_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+
+EXPORT_SYMBOL(s3c_device_pcm);
+
 /* RTC */
 /* RTC */
 
 
 static struct resource s3c_rtc_resource[] = {
 static struct resource s3c_rtc_resource[] = {
@@ -481,19 +496,30 @@ static struct resource s3c_ac97_resource[] = {
 	},
 	},
 };
 };
 
 
-static u64 s3c_device_ac97_dmamask = 0xffffffffUL;
-
 struct platform_device s3c_device_ac97 = {
 struct platform_device s3c_device_ac97 = {
 	.name		  = "s3c-ac97",
 	.name		  = "s3c-ac97",
 	.id		  = -1,
 	.id		  = -1,
 	.num_resources	  = ARRAY_SIZE(s3c_ac97_resource),
 	.num_resources	  = ARRAY_SIZE(s3c_ac97_resource),
 	.resource	  = s3c_ac97_resource,
 	.resource	  = s3c_ac97_resource,
 	.dev              = {
 	.dev              = {
-		.dma_mask = &s3c_device_ac97_dmamask,
+		.dma_mask = &s3c_device_audio_dmamask,
 		.coherent_dma_mask = 0xffffffffUL
 		.coherent_dma_mask = 0xffffffffUL
 	}
 	}
 };
 };
 
 
 EXPORT_SYMBOL(s3c_device_ac97);
 EXPORT_SYMBOL(s3c_device_ac97);
 
 
+/* ASoC I2S */
+
+struct platform_device s3c2412_device_iis = {
+	.name		  = "s3c2412-iis",
+	.id		  = -1,
+	.dev              = {
+		.dma_mask = &s3c_device_audio_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+
+EXPORT_SYMBOL(s3c2412_device_iis);
+
 #endif // CONFIG_CPU_S32440
 #endif // CONFIG_CPU_S32440

+ 2 - 0
arch/arm/plat-samsung/include/plat/devs.h

@@ -32,6 +32,8 @@ extern struct platform_device s3c64xx_device_iisv4;
 extern struct platform_device s3c64xx_device_spi0;
 extern struct platform_device s3c64xx_device_spi0;
 extern struct platform_device s3c64xx_device_spi1;
 extern struct platform_device s3c64xx_device_spi1;
 
 
+extern struct platform_device s3c_device_pcm;
+
 extern struct platform_device s3c64xx_device_pcm0;
 extern struct platform_device s3c64xx_device_pcm0;
 extern struct platform_device s3c64xx_device_pcm1;
 extern struct platform_device s3c64xx_device_pcm1;
 
 

+ 6 - 0
arch/mips/alchemy/devboards/db1200/platform.c

@@ -429,6 +429,11 @@ static struct platform_device db1200_audio_dev = {
 	.resource	= au1200_psc1_res,
 	.resource	= au1200_psc1_res,
 };
 };
 
 
+static struct platform_device db1200_stac_dev = {
+	.name		= "ac97-codec",
+	.id		= 1,	/* on PSC1 */
+};
+
 static struct platform_device *db1200_devs[] __initdata = {
 static struct platform_device *db1200_devs[] __initdata = {
 	NULL,		/* PSC0, selected by S6.8 */
 	NULL,		/* PSC0, selected by S6.8 */
 	&db1200_ide_dev,
 	&db1200_ide_dev,
@@ -436,6 +441,7 @@ static struct platform_device *db1200_devs[] __initdata = {
 	&db1200_rtc_dev,
 	&db1200_rtc_dev,
 	&db1200_nand_dev,
 	&db1200_nand_dev,
 	&db1200_audio_dev,
 	&db1200_audio_dev,
+	&db1200_stac_dev,
 };
 };
 
 
 static int __init db1200_dev_init(void)
 static int __init db1200_dev_init(void)

+ 1 - 0
arch/powerpc/boot/dts/mpc8610_hpcd.dts

@@ -286,6 +286,7 @@
 
 
 		ssi@16100 {
 		ssi@16100 {
 			compatible = "fsl,mpc8610-ssi";
 			compatible = "fsl,mpc8610-ssi";
+			status = "disabled";
 			cell-index = <1>;
 			cell-index = <1>;
 			reg = <0x16100 0x100>;
 			reg = <0x16100 0x100>;
 			interrupt-parent = <&mpic>;
 			interrupt-parent = <&mpic>;

+ 3 - 0
arch/powerpc/configs/mpc85xx_defconfig

@@ -124,6 +124,9 @@ CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_SUPPORT_OLD_API is not set

+ 3 - 0
arch/powerpc/configs/mpc85xx_smp_defconfig

@@ -126,6 +126,9 @@ CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_SUPPORT_OLD_API is not set

+ 76 - 35
arch/powerpc/include/asm/immap_86xx.h → arch/powerpc/include/asm/fsl_guts.h

@@ -1,5 +1,5 @@
 /**
 /**
- * MPC86xx Internal Memory Map
+ * Freecale 85xx and 86xx Global Utilties register set
  *
  *
  * Authors: Jeff Brown
  * Authors: Jeff Brown
  *          Timur Tabi <timur@freescale.com>
  *          Timur Tabi <timur@freescale.com>
@@ -10,73 +10,112 @@
  * under  the terms of  the GNU General  Public License as published by the
  * 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
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  * option) any later version.
- *
- * This header file defines structures for various 86xx SOC devices that are
- * used by multiple source files.
  */
  */
 
 
-#ifndef __ASM_POWERPC_IMMAP_86XX_H__
-#define __ASM_POWERPC_IMMAP_86XX_H__
+#ifndef __ASM_POWERPC_FSL_GUTS_H__
+#define __ASM_POWERPC_FSL_GUTS_H__
 #ifdef __KERNEL__
 #ifdef __KERNEL__
 
 
-/* Global Utility Registers */
-struct ccsr_guts {
+/*
+ * These #ifdefs are safe because it's not possible to build a kernel that
+ * runs on e500 and e600 cores.
+ */
+
+#if !defined(CONFIG_PPC_85xx) && !defined(CONFIG_PPC_86xx)
+#error Only 85xx and 86xx SOCs are supported
+#endif
+
+/**
+ * Global Utility Registers.
+ *
+ * Not all registers defined in this structure are available on all chips, so
+ * you are expected to know whether a given register actually exists on your
+ * chip before you access it.
+ *
+ * Also, some registers are similar on different chips but have slightly
+ * different names.  In these cases, one name is chosen to avoid extraneous
+ * #ifdefs.
+ */
+#ifdef CONFIG_PPC_85xx
+struct ccsr_guts_85xx {
+#else
+struct ccsr_guts_86xx {
+#endif
 	__be32	porpllsr;	/* 0x.0000 - POR PLL Ratio Status Register */
 	__be32	porpllsr;	/* 0x.0000 - POR PLL Ratio Status Register */
 	__be32	porbmsr;	/* 0x.0004 - POR Boot Mode Status Register */
 	__be32	porbmsr;	/* 0x.0004 - POR Boot Mode Status Register */
 	__be32	porimpscr;	/* 0x.0008 - POR I/O Impedance Status and Control Register */
 	__be32	porimpscr;	/* 0x.0008 - POR I/O Impedance Status and Control Register */
 	__be32	pordevsr;	/* 0x.000c - POR I/O Device Status Register */
 	__be32	pordevsr;	/* 0x.000c - POR I/O Device Status Register */
 	__be32	pordbgmsr;	/* 0x.0010 - POR Debug Mode Status Register */
 	__be32	pordbgmsr;	/* 0x.0010 - POR Debug Mode Status Register */
-	u8	res1[0x20 - 0x14];
+	__be32	pordevsr2;	/* 0x.0014 - POR device status register 2 */
+	u8	res018[0x20 - 0x18];
 	__be32	porcir;		/* 0x.0020 - POR Configuration Information Register */
 	__be32	porcir;		/* 0x.0020 - POR Configuration Information Register */
-	u8	res2[0x30 - 0x24];
+	u8	res024[0x30 - 0x24];
 	__be32	gpiocr;		/* 0x.0030 - GPIO Control Register */
 	__be32	gpiocr;		/* 0x.0030 - GPIO Control Register */
-	u8	res3[0x40 - 0x34];
+	u8	res034[0x40 - 0x34];
 	__be32	gpoutdr;	/* 0x.0040 - General-Purpose Output Data Register */
 	__be32	gpoutdr;	/* 0x.0040 - General-Purpose Output Data Register */
-	u8	res4[0x50 - 0x44];
+	u8	res044[0x50 - 0x44];
 	__be32	gpindr;		/* 0x.0050 - General-Purpose Input Data Register */
 	__be32	gpindr;		/* 0x.0050 - General-Purpose Input Data Register */
-	u8	res5[0x60 - 0x54];
+	u8	res054[0x60 - 0x54];
 	__be32	pmuxcr;		/* 0x.0060 - Alternate Function Signal Multiplex Control */
 	__be32	pmuxcr;		/* 0x.0060 - Alternate Function Signal Multiplex Control */
-	u8	res6[0x70 - 0x64];
+        __be32  pmuxcr2;	/* 0x.0064 - Alternate function signal multiplex control 2 */
+        __be32  dmuxcr;		/* 0x.0068 - DMA Mux Control Register */
+        u8	res06c[0x70 - 0x6c];
 	__be32	devdisr;	/* 0x.0070 - Device Disable Control */
 	__be32	devdisr;	/* 0x.0070 - Device Disable Control */
 	__be32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
 	__be32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
-	u8	res7[0x80 - 0x78];
+	u8	res078[0x7c - 0x78];
+	__be32  pmjcr;		/* 0x.007c - 4 Power Management Jog Control Register */
 	__be32	powmgtcsr;	/* 0x.0080 - Power Management Status and Control Register */
 	__be32	powmgtcsr;	/* 0x.0080 - Power Management Status and Control Register */
-	u8	res8[0x90 - 0x84];
+	__be32  pmrccr;		/* 0x.0084 - Power Management Reset Counter Configuration Register */
+	__be32  pmpdccr;	/* 0x.0088 - Power Management Power Down Counter Configuration Register */
+	__be32  pmcdr;		/* 0x.008c - 4Power management clock disable register */
 	__be32	mcpsumr;	/* 0x.0090 - Machine Check Summary Register */
 	__be32	mcpsumr;	/* 0x.0090 - Machine Check Summary Register */
 	__be32	rstrscr;	/* 0x.0094 - Reset Request Status and Control Register */
 	__be32	rstrscr;	/* 0x.0094 - Reset Request Status and Control Register */
-	u8	res9[0xA0 - 0x98];
+	__be32  ectrstcr;	/* 0x.0098 - Exception reset control register */
+	__be32  autorstsr;	/* 0x.009c - Automatic reset status register */
 	__be32	pvr;		/* 0x.00a0 - Processor Version Register */
 	__be32	pvr;		/* 0x.00a0 - Processor Version Register */
 	__be32	svr;		/* 0x.00a4 - System Version Register */
 	__be32	svr;		/* 0x.00a4 - System Version Register */
-	u8	res10[0xB0 - 0xA8];
+	u8	res0a8[0xb0 - 0xa8];
 	__be32	rstcr;		/* 0x.00b0 - Reset Control Register */
 	__be32	rstcr;		/* 0x.00b0 - Reset Control Register */
-	u8	res11[0xC0 - 0xB4];
+	u8	res0b4[0xc0 - 0xb4];
+#ifdef CONFIG_PPC_85xx
+	__be32  iovselsr;	/* 0x.00c0 - I/O voltage select status register */
+#else
 	__be32	elbcvselcr;	/* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
 	__be32	elbcvselcr;	/* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
-	u8	res12[0x800 - 0xC4];
+#endif
+	u8	res0c4[0x224 - 0xc4];
+	__be32  iodelay1;	/* 0x.0224 - IO delay control register 1 */
+	__be32  iodelay2;	/* 0x.0228 - IO delay control register 2 */
+	u8	res22c[0x800 - 0x22c];
 	__be32	clkdvdr;	/* 0x.0800 - Clock Divide Register */
 	__be32	clkdvdr;	/* 0x.0800 - Clock Divide Register */
-	u8	res13[0x900 - 0x804];
+	u8	res804[0x900 - 0x804];
 	__be32	ircr;		/* 0x.0900 - Infrared Control Register */
 	__be32	ircr;		/* 0x.0900 - Infrared Control Register */
-	u8	res14[0x908 - 0x904];
+	u8	res904[0x908 - 0x904];
 	__be32	dmacr;		/* 0x.0908 - DMA Control Register */
 	__be32	dmacr;		/* 0x.0908 - DMA Control Register */
-	u8	res15[0x914 - 0x90C];
+	u8	res90c[0x914 - 0x90c];
 	__be32	elbccr;		/* 0x.0914 - eLBC Control Register */
 	__be32	elbccr;		/* 0x.0914 - eLBC Control Register */
-	u8	res16[0xB20 - 0x918];
+	u8	res918[0xb20 - 0x918];
 	__be32	ddr1clkdr;	/* 0x.0b20 - DDR1 Clock Disable Register */
 	__be32	ddr1clkdr;	/* 0x.0b20 - DDR1 Clock Disable Register */
 	__be32	ddr2clkdr;	/* 0x.0b24 - DDR2 Clock Disable Register */
 	__be32	ddr2clkdr;	/* 0x.0b24 - DDR2 Clock Disable Register */
 	__be32	ddrclkdr;	/* 0x.0b28 - DDR Clock Disable Register */
 	__be32	ddrclkdr;	/* 0x.0b28 - DDR Clock Disable Register */
-	u8	res17[0xE00 - 0xB2C];
+	u8	resb2c[0xe00 - 0xb2c];
 	__be32	clkocr;		/* 0x.0e00 - Clock Out Select Register */
 	__be32	clkocr;		/* 0x.0e00 - Clock Out Select Register */
-	u8	res18[0xE10 - 0xE04];
+	u8	rese04[0xe10 - 0xe04];
 	__be32	ddrdllcr;	/* 0x.0e10 - DDR DLL Control Register */
 	__be32	ddrdllcr;	/* 0x.0e10 - DDR DLL Control Register */
-	u8	res19[0xE20 - 0xE14];
+	u8	rese14[0xe20 - 0xe14];
 	__be32	lbcdllcr;	/* 0x.0e20 - LBC DLL Control Register */
 	__be32	lbcdllcr;	/* 0x.0e20 - LBC DLL Control Register */
-	u8	res20[0xF04 - 0xE24];
+	__be32  cpfor;		/* 0x.0e24 - L2 charge pump fuse override register */
+	u8	rese28[0xf04 - 0xe28];
 	__be32	srds1cr0;	/* 0x.0f04 - SerDes1 Control Register 0 */
 	__be32	srds1cr0;	/* 0x.0f04 - SerDes1 Control Register 0 */
 	__be32	srds1cr1;	/* 0x.0f08 - SerDes1 Control Register 0 */
 	__be32	srds1cr1;	/* 0x.0f08 - SerDes1 Control Register 0 */
-	u8	res21[0xF40 - 0xF0C];
-	__be32	srds2cr0;	/* 0x.0f40 - SerDes1 Control Register 0 */
-	__be32	srds2cr1;	/* 0x.0f44 - SerDes1 Control Register 0 */
+	u8	resf0c[0xf2c - 0xf0c];
+	__be32  itcr;		/* 0x.0f2c - Internal transaction control register */
+	u8	resf30[0xf40 - 0xf30];
+	__be32	srds2cr0;	/* 0x.0f40 - SerDes2 Control Register 0 */
+	__be32	srds2cr1;	/* 0x.0f44 - SerDes2 Control Register 0 */
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
+#ifdef CONFIG_PPC_86xx
+
 #define CCSR_GUTS_DMACR_DEV_SSI	0	/* DMA controller/channel set to SSI */
 #define CCSR_GUTS_DMACR_DEV_SSI	0	/* DMA controller/channel set to SSI */
 #define CCSR_GUTS_DMACR_DEV_IR	1	/* DMA controller/channel set to IR */
 #define CCSR_GUTS_DMACR_DEV_IR	1	/* DMA controller/channel set to IR */
 
 
@@ -93,7 +132,7 @@ struct ccsr_guts {
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
  * device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
  */
  */
-static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
+static inline void guts_set_dmacr(struct ccsr_guts_86xx __iomem *guts,
 	unsigned int co, unsigned int ch, unsigned int device)
 	unsigned int co, unsigned int ch, unsigned int device)
 {
 {
 	unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
 	unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
@@ -129,7 +168,7 @@ static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * value: the new value for the bit (0 or 1)
  * value: the new value for the bit (0 or 1)
  */
  */
-static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
+static inline void guts_set_pmuxcr_dma(struct ccsr_guts_86xx __iomem *guts,
 	unsigned int co, unsigned int ch, unsigned int value)
 	unsigned int co, unsigned int ch, unsigned int value)
 {
 {
 	if ((ch == 0) || (ch == 3)) {
 	if ((ch == 0) || (ch == 3)) {
@@ -152,5 +191,7 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
 #define CCSR_GUTS_CLKDVDR_SSICLK_MASK	0x000000FF
 #define CCSR_GUTS_CLKDVDR_SSICLK_MASK	0x000000FF
 #define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
 #define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
 
 
-#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */
-#endif /* __KERNEL__ */
+#endif
+
+#endif
+#endif

+ 209 - 2
arch/powerpc/platforms/85xx/p1022_ds.c

@@ -8,7 +8,6 @@
  * Copyright 2010 Freescale Semiconductor, Inc.
  * Copyright 2010 Freescale Semiconductor, Inc.
  *
  *
  * This file is taken from the Freescale P1022DS BSP, with modifications:
  * This file is taken from the Freescale P1022DS BSP, with modifications:
- * 1) No DIU support (pending rewrite of DIU code)
  * 2) No AMP support
  * 2) No AMP support
  * 3) No PCI endpoint support
  * 3) No PCI endpoint support
  *
  *
@@ -20,12 +19,211 @@
 #include <linux/pci.h>
 #include <linux/pci.h>
 #include <linux/of_platform.h>
 #include <linux/of_platform.h>
 #include <linux/memblock.h>
 #include <linux/memblock.h>
-
+#include <asm/div64.h>
 #include <asm/mpic.h>
 #include <asm/mpic.h>
 #include <asm/swiotlb.h>
 #include <asm/swiotlb.h>
 
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 #include <sysdev/fsl_pci.h>
+#include <asm/fsl_guts.h>
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/*
+ * Board-specific initialization of the DIU.  This code should probably be
+ * executed when the DIU is opened, rather than in arch code, but the DIU
+ * driver does not have a mechanism for this (yet).
+ *
+ * This is especially problematic on the P1022DS because the local bus (eLBC)
+ * and the DIU video signals share the same pins, which means that enabling the
+ * DIU will disable access to NOR flash.
+ */
+
+/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
+#define CLKDVDR_PXCKEN		0x80000000
+#define CLKDVDR_PXCKINV		0x10000000
+#define CLKDVDR_PXCKDLY		0x06000000
+#define CLKDVDR_PXCLK_MASK	0x00FF0000
+
+/* Some ngPIXIS register definitions */
+#define PX_BRDCFG1_DVIEN	0x80
+#define PX_BRDCFG1_DFPEN	0x40
+#define PX_BRDCFG1_BACKLIGHT	0x20
+#define PX_BRDCFG1_DDCEN	0x10
+
+/*
+ * DIU Area Descriptor
+ *
+ * Note that we need to byte-swap the value before it's written to the AD
+ * register.  So even though the registers don't look like they're in the same
+ * bit positions as they are on the MPC8610, the same value is written to the
+ * AD register on the MPC8610 and on the P1022.
+ */
+#define AD_BYTE_F		0x10000000
+#define AD_ALPHA_C_MASK		0x0E000000
+#define AD_ALPHA_C_SHIFT	25
+#define AD_BLUE_C_MASK		0x01800000
+#define AD_BLUE_C_SHIFT		23
+#define AD_GREEN_C_MASK		0x00600000
+#define AD_GREEN_C_SHIFT	21
+#define AD_RED_C_MASK		0x00180000
+#define AD_RED_C_SHIFT		19
+#define AD_PALETTE		0x00040000
+#define AD_PIXEL_S_MASK		0x00030000
+#define AD_PIXEL_S_SHIFT	16
+#define AD_COMP_3_MASK		0x0000F000
+#define AD_COMP_3_SHIFT		12
+#define AD_COMP_2_MASK		0x00000F00
+#define AD_COMP_2_SHIFT		8
+#define AD_COMP_1_MASK		0x000000F0
+#define AD_COMP_1_SHIFT		4
+#define AD_COMP_0_MASK		0x0000000F
+#define AD_COMP_0_SHIFT		0
+
+#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
+	cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
+	(blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
+	(red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
+	(c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
+	(c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
+
+/**
+ * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth
+ *
+ * The Area Descriptor is a 32-bit value that determine which bits in each
+ * pixel are to be used for each color.
+ */
+static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
+	int monitor_port)
+{
+	switch (bits_per_pixel) {
+	case 32:
+		/* 0x88883316 */
+		return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8);
+	case 24:
+		/* 0x88082219 */
+		return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8);
+	case 16:
+		/* 0x65053118 */
+		return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0);
+	default:
+		pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
+		return 0;
+	}
+}
+
+/**
+ * p1022ds_set_gamma_table: update the gamma table, if necessary
+ *
+ * On some boards, the gamma table for some ports may need to be modified.
+ * This is not the case on the P1022DS, so we do nothing.
+*/
+static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+}
+
+/**
+ * p1022ds_set_monitor_port: switch the output to a different monitor port
+ *
+ */
+static void p1022ds_set_monitor_port(int monitor_port)
+{
+	struct device_node *pixis_node;
+	u8 __iomem *brdcfg1;
+
+	pixis_node = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
+	if (!pixis_node) {
+		pr_err("p1022ds: missing ngPIXIS node\n");
+		return;
+	}
+
+	brdcfg1 = of_iomap(pixis_node, 0);
+	if (!brdcfg1) {
+		pr_err("p1022ds: could not map ngPIXIS registers\n");
+		return;
+	}
+	brdcfg1 += 9;	/* BRDCFG1 is at offset 9 in the ngPIXIS */
+
+	switch (monitor_port) {
+	case 0: /* DVI */
+		/* Enable the DVI port, disable the DFP and the backlight */
+		clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
+			     PX_BRDCFG1_DVIEN);
+		break;
+	case 1: /* Single link LVDS */
+		/* Enable the DFP port, disable the DVI and the backlight */
+		clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
+			     PX_BRDCFG1_DFPEN);
+		break;
+	default:
+		pr_err("p1022ds: unsupported monitor port %i\n", monitor_port);
+	}
+}
+
+/**
+ * p1022ds_set_pixel_clock: program the DIU's clock
+ *
+ * @pixclock: the wavelength, in picoseconds, of the clock
+ */
+void p1022ds_set_pixel_clock(unsigned int pixclock)
+{
+	struct device_node *guts_np = NULL;
+	struct ccsr_guts_85xx __iomem *guts;
+	unsigned long freq;
+	u64 temp;
+	u32 pxclk;
+
+	/* Map the global utilities registers. */
+	guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+	if (!guts_np) {
+		pr_err("p1022ds: missing global utilties device node\n");
+		return;
+	}
+
+	guts = of_iomap(guts_np, 0);
+	of_node_put(guts_np);
+	if (!guts) {
+		pr_err("p1022ds: could not map global utilties device\n");
+		return;
+	}
+
+	/* Convert pixclock from a wavelength to a frequency */
+	temp = 1000000000000ULL;
+	do_div(temp, pixclock);
+	freq = temp;
+
+	/* pixclk is the ratio of the platform clock to the pixel clock */
+	pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+
+	/* Disable the pixel clock, and set it to non-inverted and no delay */
+	clrbits32(&guts->clkdvdr,
+		  CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
+
+	/* Enable the clock and set the pxclk */
+	setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
+}
+
+/**
+ * p1022ds_show_monitor_port: show the current monitor
+ *
+ * This function returns a string indicating whether the current monitor is
+ * set to DVI or LVDS.
+ */
+ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf)
+{
+	return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n",
+		monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' ');
+}
+
+/**
+ * p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs
+ */
+int p1022ds_set_sysfs_monitor_port(int val)
+{
+	return val < 2 ? val : 0;
+}
+
+#endif
 
 
 void __init p1022_ds_pic_init(void)
 void __init p1022_ds_pic_init(void)
 {
 {
@@ -92,6 +290,15 @@ static void __init p1022_ds_setup_arch(void)
 	}
 	}
 #endif
 #endif
 
 
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+	diu_ops.get_pixel_format	= p1022ds_get_pixel_format;
+	diu_ops.set_gamma_table		= p1022ds_set_gamma_table;
+	diu_ops.set_monitor_port	= p1022ds_set_monitor_port;
+	diu_ops.set_pixel_clock		= p1022ds_set_pixel_clock;
+	diu_ops.show_monitor_port	= p1022ds_show_monitor_port;
+	diu_ops.set_sysfs_monitor_port	= p1022ds_set_sysfs_monitor_port;
+#endif
+
 #ifdef CONFIG_SMP
 #ifdef CONFIG_SMP
 	mpc85xx_smp_init();
 	mpc85xx_smp_init();
 #endif
 #endif

+ 1 - 1
arch/sh/kernel/cpu/sh4a/setup-sh7722.c

@@ -551,7 +551,7 @@ static struct resource siu_resources[] = {
 };
 };
 
 
 static struct platform_device siu_device = {
 static struct platform_device siu_device = {
-	.name		= "sh_siu",
+	.name		= "siu-pcm-audio",
 	.id		= -1,
 	.id		= -1,
 	.dev = {
 	.dev = {
 		.platform_data	= &siu_platform_data,
 		.platform_data	= &siu_platform_data,

+ 2 - 2
drivers/input/misc/twl4030-vibra.c

@@ -271,7 +271,7 @@ static struct platform_driver twl4030_vibra_driver = {
 	.probe		= twl4030_vibra_probe,
 	.probe		= twl4030_vibra_probe,
 	.remove		= __devexit_p(twl4030_vibra_remove),
 	.remove		= __devexit_p(twl4030_vibra_remove),
 	.driver		= {
 	.driver		= {
-		.name	= "twl4030_codec_vibra",
+		.name	= "twl4030-vibra",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 		.pm	= &twl4030_vibra_pm_ops,
 		.pm	= &twl4030_vibra_pm_ops,
@@ -291,7 +291,7 @@ static void __exit twl4030_vibra_exit(void)
 }
 }
 module_exit(twl4030_vibra_exit);
 module_exit(twl4030_vibra_exit);
 
 
-MODULE_ALIAS("platform:twl4030_codec_vibra");
+MODULE_ALIAS("platform:twl4030-vibra");
 
 
 MODULE_DESCRIPTION("TWL4030 Vibra driver");
 MODULE_DESCRIPTION("TWL4030 Vibra driver");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 3 - 3
drivers/mfd/twl-core.c

@@ -698,17 +698,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
 
 	if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
 	if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
 		sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
 		sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-		child = add_child(sub_chip_id, "twl4030_codec",
+		child = add_child(sub_chip_id, "twl4030-audio",
 				pdata->codec, sizeof(*pdata->codec),
 				pdata->codec, sizeof(*pdata->codec),
 				false, 0, 0);
 				false, 0, 0);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
 
 
-	/* Phoenix*/
+	/* Phoenix codec driver is probed directly atm */
 	if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
 	if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
 		sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
 		sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-		child = add_child(sub_chip_id, "twl6040_codec",
+		child = add_child(sub_chip_id, "twl6040-codec",
 				pdata->codec, sizeof(*pdata->codec),
 				pdata->codec, sizeof(*pdata->codec),
 				false, 0, 0);
 				false, 0, 0);
 		if (IS_ERR(child))
 		if (IS_ERR(child))

+ 4 - 4
drivers/mfd/twl4030-codec.c

@@ -207,14 +207,14 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 
 
 	if (pdata->audio) {
 	if (pdata->audio) {
 		cell = &codec->cells[childs];
 		cell = &codec->cells[childs];
-		cell->name = "twl4030_codec_audio";
+		cell->name = "twl4030-codec";
 		cell->platform_data = pdata->audio;
 		cell->platform_data = pdata->audio;
 		cell->data_size = sizeof(*pdata->audio);
 		cell->data_size = sizeof(*pdata->audio);
 		childs++;
 		childs++;
 	}
 	}
 	if (pdata->vibra) {
 	if (pdata->vibra) {
 		cell = &codec->cells[childs];
 		cell = &codec->cells[childs];
-		cell->name = "twl4030_codec_vibra";
+		cell->name = "twl4030-vibra";
 		cell->platform_data = pdata->vibra;
 		cell->platform_data = pdata->vibra;
 		cell->data_size = sizeof(*pdata->vibra);
 		cell->data_size = sizeof(*pdata->vibra);
 		childs++;
 		childs++;
@@ -249,14 +249,14 @@ static int __devexit twl4030_codec_remove(struct platform_device *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
-MODULE_ALIAS("platform:twl4030_codec");
+MODULE_ALIAS("platform:twl4030-audio");
 
 
 static struct platform_driver twl4030_codec_driver = {
 static struct platform_driver twl4030_codec_driver = {
 	.probe		= twl4030_codec_probe,
 	.probe		= twl4030_codec_probe,
 	.remove		= __devexit_p(twl4030_codec_remove),
 	.remove		= __devexit_p(twl4030_codec_remove),
 	.driver		= {
 	.driver		= {
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
-		.name	= "twl4030_codec",
+		.name	= "twl4030-audio",
 	},
 	},
 };
 };
 
 

+ 1 - 1
drivers/staging/xgifb/TODO

@@ -12,4 +12,4 @@ TODO:
 - get rid of non-linux related stuff
 - get rid of non-linux related stuff
 
 
 Please send patches to:
 Please send patches to:
-Arnaud Patard <apatard@mandriva.com>
+Arnaud Patard <arnaud.patard@rtp-net.org>

+ 3 - 0
drivers/video/Kconfig

@@ -1919,6 +1919,9 @@ config FB_SH_MOBILE_HDMI
 	tristate "SuperH Mobile HDMI controller support"
 	tristate "SuperH Mobile HDMI controller support"
 	depends on FB_SH_MOBILE_LCDC
 	depends on FB_SH_MOBILE_LCDC
 	select FB_MODE_HELPERS
 	select FB_MODE_HELPERS
+	select SOUND
+	select SND
+	select SND_SOC
 	---help---
 	---help---
 	  Driver for the on-chip SH-Mobile HDMI controller.
 	  Driver for the on-chip SH-Mobile HDMI controller.
 
 

+ 83 - 1
drivers/video/sh_mobile_hdmi.c

@@ -22,6 +22,8 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
 
 
 #include <video/sh_mobile_hdmi.h>
 #include <video/sh_mobile_hdmi.h>
 #include <video/sh_mobile_lcdc.h>
 #include <video/sh_mobile_lcdc.h>
@@ -222,6 +224,58 @@ static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg)
 	return ioread8(hdmi->base + reg);
 	return ioread8(hdmi->base + reg);
 }
 }
 
 
+/*
+ *	HDMI sound
+ */
+static unsigned int sh_hdmi_snd_read(struct snd_soc_codec *codec,
+				     unsigned int reg)
+{
+	struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+	return hdmi_read(hdmi, reg);
+}
+
+static int sh_hdmi_snd_write(struct snd_soc_codec *codec,
+			     unsigned int reg,
+			     unsigned int value)
+{
+	struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+	hdmi_write(hdmi, value, reg);
+	return 0;
+}
+
+static struct snd_soc_dai_driver sh_hdmi_dai = {
+	.name = "sh_mobile_hdmi-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  |
+			 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  |
+			 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+			 SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+};
+
+static int sh_hdmi_snd_probe(struct snd_soc_codec *codec)
+{
+	dev_info(codec->dev, "SH Mobile HDMI Audio Codec");
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = {
+	.probe		= sh_hdmi_snd_probe,
+	.read		= sh_hdmi_snd_read,
+	.write		= sh_hdmi_snd_write,
+};
+
+/*
+ *	HDMI video
+ */
+
 /* External video parameter settings */
 /* External video parameter settings */
 static void hdmi_external_video_param(struct sh_hdmi *hdmi)
 static void hdmi_external_video_param(struct sh_hdmi *hdmi)
 {
 {
@@ -318,6 +372,9 @@ static void sh_hdmi_video_config(struct sh_hdmi *hdmi)
  */
  */
 static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
 static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
 {
 {
+	u8 data;
+	struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
+
 	/*
 	/*
 	 * [7:4] L/R data swap control
 	 * [7:4] L/R data swap control
 	 * [3:0] appropriate N[19:16]
 	 * [3:0] appropriate N[19:16]
@@ -335,7 +392,23 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
 	 * [6:5] set required down sampling rate if required
 	 * [6:5] set required down sampling rate if required
 	 * [4:3] set required audio source
 	 * [4:3] set required audio source
 	 */
 	 */
-	hdmi_write(hdmi, 0x00, HDMI_AUDIO_SETTING_1);
+	switch (pdata->flags & HDMI_SND_SRC_MASK) {
+	default:
+		/* fall through */
+	case HDMI_SND_SRC_I2S:
+		data = 0x0 << 3;
+		break;
+	case HDMI_SND_SRC_SPDIF:
+		data = 0x1 << 3;
+		break;
+	case HDMI_SND_SRC_DSD:
+		data = 0x2 << 3;
+		break;
+	case HDMI_SND_SRC_HBR:
+		data = 0x3 << 3;
+		break;
+	}
+	hdmi_write(hdmi, data, HDMI_AUDIO_SETTING_1);
 
 
 	/* [3:0] set sending channel number for channel status */
 	/* [3:0] set sending channel number for channel status */
 	hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2);
 	hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2);
@@ -891,6 +964,11 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
+	ret =  snd_soc_register_codec(&pdev->dev,
+			&soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1);
+	if (ret < 0)
+		goto esndreg;
+
 	hdmi->dev = &pdev->dev;
 	hdmi->dev = &pdev->dev;
 
 
 	hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
 	hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
@@ -976,6 +1054,8 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 erate:
 erate:
 	clk_put(hdmi->hdmi_clk);
 	clk_put(hdmi->hdmi_clk);
 egetclk:
 egetclk:
+	snd_soc_unregister_codec(&pdev->dev);
+esndreg:
 	kfree(hdmi);
 	kfree(hdmi);
 
 
 	return ret;
 	return ret;
@@ -988,6 +1068,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	int irq = platform_get_irq(pdev, 0);
 	int irq = platform_get_irq(pdev, 0);
 
 
+	snd_soc_unregister_codec(&pdev->dev);
+
 	pdata->lcd_chan->board_cfg.display_on = NULL;
 	pdata->lcd_chan->board_cfg.display_on = NULL;
 	pdata->lcd_chan->board_cfg.display_off = NULL;
 	pdata->lcd_chan->board_cfg.display_off = NULL;
 	pdata->lcd_chan->board_cfg.board_data = NULL;
 	pdata->lcd_chan->board_cfg.board_data = NULL;

+ 5 - 1
include/linux/i2c/twl.h

@@ -553,8 +553,12 @@ extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
 extern int twl4030_remove_script(u8 flags);
 extern int twl4030_remove_script(u8 flags);
 
 
 struct twl4030_codec_audio_data {
 struct twl4030_codec_audio_data {
-	unsigned int	audio_mclk;
+	unsigned int audio_mclk; /* not used, will be removed */
+	unsigned int digimic_delay; /* in ms */
 	unsigned int ramp_delay_value;
 	unsigned int ramp_delay_value;
+	unsigned int offset_cncl_path;
+	unsigned int check_defaults:1;
+	unsigned int reset_registers:1;
 	unsigned int hs_extmute:1;
 	unsigned int hs_extmute:1;
 	void (*set_hs_extmute)(int mute);
 	void (*set_hs_extmute)(int mute);
 };
 };

+ 1 - 1
include/sound/core.h

@@ -177,7 +177,7 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state);
 #define snd_power_lock(card)		do { (void)(card); } while (0)
 #define snd_power_lock(card)		do { (void)(card); } while (0)
 #define snd_power_unlock(card)		do { (void)(card); } while (0)
 #define snd_power_unlock(card)		do { (void)(card); } while (0)
 static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
 static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
-#define snd_power_get_state(card)	SNDRV_CTL_POWER_D0
+#define snd_power_get_state(card)	({ (void)(card); SNDRV_CTL_POWER_D0; })
 #define snd_power_change_state(card, state)	do { (void)(card); } while (0)
 #define snd_power_change_state(card, state)	do { (void)(card); } while (0)
 
 
 #endif /* CONFIG_PM */
 #endif /* CONFIG_PM */

+ 2 - 0
include/sound/emu10k1.h

@@ -438,6 +438,8 @@
 #define CCCA_CURRADDR_MASK	0x00ffffff	/* Current address of the selected channel		*/
 #define CCCA_CURRADDR_MASK	0x00ffffff	/* Current address of the selected channel		*/
 #define CCCA_CURRADDR		0x18000008
 #define CCCA_CURRADDR		0x18000008
 
 
+/* undefine CCR to avoid conflict with the definition for SH */
+#undef CCR
 #define CCR			0x09		/* Cache control register				*/
 #define CCR			0x09		/* Cache control register				*/
 #define CCR_CACHEINVALIDSIZE	0x07190009
 #define CCR_CACHEINVALIDSIZE	0x07190009
 #define CCR_CACHEINVALIDSIZE_MASK	0xfe000000	/* Number of invalid samples cache for this channel    	*/
 #define CCR_CACHEINVALIDSIZE_MASK	0xfe000000	/* Number of invalid samples cache for this channel    	*/

+ 4 - 1
include/sound/jack.h

@@ -47,6 +47,9 @@ enum snd_jack_types {
 	SND_JACK_BTN_0		= 0x4000,
 	SND_JACK_BTN_0		= 0x4000,
 	SND_JACK_BTN_1		= 0x2000,
 	SND_JACK_BTN_1		= 0x2000,
 	SND_JACK_BTN_2		= 0x1000,
 	SND_JACK_BTN_2		= 0x1000,
+	SND_JACK_BTN_3		= 0x0800,
+	SND_JACK_BTN_4		= 0x0400,
+	SND_JACK_BTN_5		= 0x0200,
 };
 };
 
 
 struct snd_jack {
 struct snd_jack {
@@ -55,7 +58,7 @@ struct snd_jack {
 	int type;
 	int type;
 	const char *id;
 	const char *id;
 	char name[100];
 	char name[100];
-	unsigned int key[3];   /* Keep in sync with definitions above */
+	unsigned int key[6];   /* Keep in sync with definitions above */
 	void *private_data;
 	void *private_data;
 	void (*private_free)(struct snd_jack *);
 	void (*private_free)(struct snd_jack *);
 };
 };

+ 50 - 0
include/sound/max98088.h

@@ -0,0 +1,50 @@
+/*
+ * Platform data for MAX98088
+ *
+ * Copyright 2010 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_MAX98088_PDATA_H__
+#define __SOUND_MAX98088_PDATA_H__
+
+/* Equalizer filter response configuration */
+struct max98088_eq_cfg {
+       const char *name;
+       unsigned int rate;
+       u16 band1[5];
+       u16 band2[5];
+       u16 band3[5];
+       u16 band4[5];
+       u16 band5[5];
+};
+
+/* codec platform data */
+struct max98088_pdata {
+
+       /* Equalizers for DAI1 and DAI2 */
+       struct max98088_eq_cfg *eq_cfg;
+       unsigned int eq_cfgcnt;
+
+       /* Receiver output can be configured as power amplifier or LINE out */
+       /* Set receiver_mode to:
+        * 0 = amplifier output, or
+        * 1 = LINE level output
+        */
+       unsigned int receiver_mode:1;
+
+       /* 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

+ 1 - 0
include/sound/pcm.h

@@ -278,6 +278,7 @@ struct snd_pcm_runtime {
 	snd_pcm_uframes_t hw_ptr_base;	/* Position at buffer restart */
 	snd_pcm_uframes_t hw_ptr_base;	/* Position at buffer restart */
 	snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
 	snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
 	unsigned long hw_ptr_jiffies;	/* Time when hw_ptr is updated */
 	unsigned long hw_ptr_jiffies;	/* Time when hw_ptr is updated */
+	unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */
 	snd_pcm_sframes_t delay;	/* extra delay; typically FIFO size */
 	snd_pcm_sframes_t delay;	/* extra delay; typically FIFO size */
 
 
 	/* -- HW params -- */
 	/* -- HW params -- */

+ 0 - 3
include/sound/sh_fsi.h

@@ -114,7 +114,4 @@ struct sh_fsi_platform_info {
 	int (*set_rate)(int is_porta, int rate); /* for master mode */
 	int (*set_rate)(int is_porta, int rate); /* for master mode */
 };
 };
 
 
-extern struct snd_soc_dai fsi_soc_dai[2];
-extern struct snd_soc_platform fsi_soc_platform;
-
 #endif /* __SOUND_FSI_H */
 #endif /* __SOUND_FSI_H */

+ 63 - 35
include/sound/soc-dai.h

@@ -91,15 +91,17 @@ struct snd_pcm_substream;
                                SNDRV_PCM_FMTBIT_S32_LE |\
                                SNDRV_PCM_FMTBIT_S32_LE |\
                                SNDRV_PCM_FMTBIT_S32_BE)
                                SNDRV_PCM_FMTBIT_S32_BE)
 
 
-struct snd_soc_dai_ops;
+struct snd_soc_dai_driver;
 struct snd_soc_dai;
 struct snd_soc_dai;
 struct snd_ac97_bus_ops;
 struct snd_ac97_bus_ops;
 
 
 /* Digital Audio Interface registration */
 /* Digital Audio Interface registration */
-int snd_soc_register_dai(struct snd_soc_dai *dai);
-void snd_soc_unregister_dai(struct snd_soc_dai *dai);
-int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count);
-void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count);
+int snd_soc_register_dai(struct device *dev,
+		struct snd_soc_dai_driver *dai_drv);
+void snd_soc_unregister_dai(struct device *dev);
+int snd_soc_register_dais(struct device *dev,
+		struct snd_soc_dai_driver *dai_drv, size_t count);
+void snd_soc_unregister_dais(struct device *dev, size_t count);
 
 
 /* Digital Audio Interface clocking API.*/
 /* Digital Audio Interface clocking API.*/
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -126,16 +128,6 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
 /* Digital Audio Interface mute */
 /* Digital Audio Interface mute */
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
 
 
-/*
- * Digital Audio Interface.
- *
- * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
- * operations and capabilities. Codec and platform drivers will register this
- * structure for every DAI they have.
- *
- * This structure covers the clocking, formating and ALSA operations for each
- * interface.
- */
 struct snd_soc_dai_ops {
 struct snd_soc_dai_ops {
 	/*
 	/*
 	 * DAI clocking configuration, all optional.
 	 * DAI clocking configuration, all optional.
@@ -191,24 +183,24 @@ struct snd_soc_dai_ops {
 };
 };
 
 
 /*
 /*
- * Digital Audio Interface runtime data.
+ * Digital Audio Interface Driver.
  *
  *
- * Holds runtime data for a DAI.
+ * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
+ * operations and capabilities. Codec and platform drivers will register this
+ * structure for every DAI they have.
+ *
+ * This structure covers the clocking, formating and ALSA operations for each
+ * interface.
  */
  */
-struct snd_soc_dai {
+struct snd_soc_dai_driver {
 	/* DAI description */
 	/* DAI description */
-	char *name;
+	const char *name;
 	unsigned int id;
 	unsigned int id;
 	int ac97_control;
 	int ac97_control;
 
 
-	struct device *dev;
-	void *ac97_pdata;	/* platform_data for the ac97 codec */
-
-	/* DAI callbacks */
-	int (*probe)(struct platform_device *pdev,
-		     struct snd_soc_dai *dai);
-	void (*remove)(struct platform_device *pdev,
-		       struct snd_soc_dai *dai);
+	/* DAI driver callbacks */
+	int (*probe)(struct snd_soc_dai *dai);
+	int (*remove)(struct snd_soc_dai *dai);
 	int (*suspend)(struct snd_soc_dai *dai);
 	int (*suspend)(struct snd_soc_dai *dai);
 	int (*resume)(struct snd_soc_dai *dai);
 	int (*resume)(struct snd_soc_dai *dai);
 
 
@@ -219,26 +211,51 @@ struct snd_soc_dai {
 	struct snd_soc_pcm_stream capture;
 	struct snd_soc_pcm_stream capture;
 	struct snd_soc_pcm_stream playback;
 	struct snd_soc_pcm_stream playback;
 	unsigned int symmetric_rates:1;
 	unsigned int symmetric_rates:1;
+};
+
+/*
+ * Digital Audio Interface runtime data.
+ *
+ * Holds runtime data for a DAI.
+ */
+struct snd_soc_dai {
+	const char *name;
+	int id;
+	struct device *dev;
+	void *ac97_pdata;	/* platform_data for the ac97 codec */
+
+	/* driver ops */
+	struct snd_soc_dai_driver *driver;
 
 
 	/* DAI runtime info */
 	/* DAI runtime info */
-	struct snd_soc_codec *codec;
+	unsigned int capture_active:1;		/* stream is in use */
+	unsigned int playback_active:1;		/* stream is in use */
+	unsigned int symmetric_rates:1;
+	struct snd_pcm_runtime *runtime;
 	unsigned int active;
 	unsigned int active;
 	unsigned char pop_wait:1;
 	unsigned char pop_wait:1;
+	unsigned char probed:1;
 
 
-	/* DAI private data */
-	void *private_data;
+	/* DAI DMA data */
+	void *playback_dma_data;
+	void *capture_dma_data;
 
 
-	/* parent platform */
-	struct snd_soc_platform *platform;
+	/* parent platform/codec */
+	union {
+		struct snd_soc_platform *platform;
+		struct snd_soc_codec *codec;
+	};
+	struct snd_soc_card *card;
 
 
 	struct list_head list;
 	struct list_head list;
+	struct list_head card_list;
 };
 };
 
 
 static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
 static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
 					     const struct snd_pcm_substream *ss)
 					     const struct snd_pcm_substream *ss)
 {
 {
 	return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 	return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-		dai->playback.dma_data : dai->capture.dma_data;
+		dai->playback_dma_data : dai->capture_dma_data;
 }
 }
 
 
 static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
 static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
@@ -246,9 +263,20 @@ static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
 					    void *data)
 					    void *data)
 {
 {
 	if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 	if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		dai->playback.dma_data = data;
+		dai->playback_dma_data = data;
 	else
 	else
-		dai->capture.dma_data = data;
+		dai->capture_dma_data = data;
+}
+
+static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai,
+		void *data)
+{
+	dev_set_drvdata(dai->dev, data);
+}
+
+static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
+{
+	return dev_get_drvdata(dai->dev);
 }
 }
 
 
 #endif
 #endif

+ 14 - 4
include/sound/soc-dapm.h

@@ -172,9 +172,19 @@
 #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
 #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
 {	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
 	.reg = wreg, .shift = wshift, .invert = winvert }
 	.reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
+			      wevent, wflags)				\
+{	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
+	.reg = wreg, .shift = wshift, .invert = winvert, \
+	.event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
 {	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
 	.reg = wreg, .shift = wshift, .invert = winvert }
 	.reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
+			     wevent, wflags)				\
+{	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
+	.reg = wreg, .shift = wshift, .invert = winvert, \
+	.event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
 {	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
 	.shift = wshift, .invert = winvert}
 	.shift = wshift, .invert = winvert}
@@ -322,14 +332,14 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
 
 
 /* dapm path setup */
 /* dapm path setup */
 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
-void snd_soc_dapm_free(struct snd_soc_device *socdev);
+void snd_soc_dapm_free(struct snd_soc_codec *codec);
 int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
 int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
 			    const struct snd_soc_dapm_route *route, int num);
 			    const struct snd_soc_dapm_route *route, int num);
 
 
 /* dapm events */
 /* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
-	int event);
-void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+	const char *stream, int event);
+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);

+ 0 - 25
include/sound/soc-of-simple.h

@@ -1,25 +0,0 @@
-/*
- * OF helpers for ALSA SoC
- *
- * Copyright (C) 2008, Secret Lab Technologies Ltd.
- */
-
-#ifndef _INCLUDE_SOC_OF_H_
-#define _INCLUDE_SOC_OF_H_
-
-#if defined(CONFIG_SND_SOC_OF_SIMPLE) || defined(CONFIG_SND_SOC_OF_SIMPLE_MODULE)
-
-#include <linux/of.h>
-#include <sound/soc.h>
-
-int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
-			      void *codec_data, struct snd_soc_dai *dai,
-			      struct device_node *node);
-
-int of_snd_soc_register_platform(struct snd_soc_platform *platform,
-				 struct device_node *node,
-				 struct snd_soc_dai *cpu_dai);
-
-#endif
-
-#endif /* _INCLUDE_SOC_OF_H_ */

+ 148 - 97
include/sound/soc.h

@@ -214,10 +214,10 @@
  * @OFF:     Power Off. No restrictions on transition times.
  * @OFF:     Power Off. No restrictions on transition times.
  */
  */
 enum snd_soc_bias_level {
 enum snd_soc_bias_level {
-	SND_SOC_BIAS_ON,
-	SND_SOC_BIAS_PREPARE,
-	SND_SOC_BIAS_STANDBY,
 	SND_SOC_BIAS_OFF,
 	SND_SOC_BIAS_OFF,
+	SND_SOC_BIAS_STANDBY,
+	SND_SOC_BIAS_PREPARE,
+	SND_SOC_BIAS_ON,
 };
 };
 
 
 struct snd_jack;
 struct snd_jack;
@@ -228,13 +228,17 @@ struct snd_soc_ops;
 struct snd_soc_dai_mode;
 struct snd_soc_dai_mode;
 struct snd_soc_pcm_runtime;
 struct snd_soc_pcm_runtime;
 struct snd_soc_dai;
 struct snd_soc_dai;
+struct snd_soc_dai_driver;
 struct snd_soc_platform;
 struct snd_soc_platform;
 struct snd_soc_dai_link;
 struct snd_soc_dai_link;
+struct snd_soc_platform_driver;
 struct snd_soc_codec;
 struct snd_soc_codec;
+struct snd_soc_codec_driver;
 struct soc_enum;
 struct soc_enum;
 struct snd_soc_ac97_ops;
 struct snd_soc_ac97_ops;
 struct snd_soc_jack;
 struct snd_soc_jack;
 struct snd_soc_jack_pin;
 struct snd_soc_jack_pin;
+
 #ifdef CONFIG_GPIOLIB
 #ifdef CONFIG_GPIOLIB
 struct snd_soc_jack_gpio;
 struct snd_soc_jack_gpio;
 #endif
 #endif
@@ -249,19 +253,18 @@ enum snd_soc_control_type {
 	SND_SOC_SPI,
 	SND_SOC_SPI,
 };
 };
 
 
-int snd_soc_register_platform(struct snd_soc_platform *platform);
-void snd_soc_unregister_platform(struct snd_soc_platform *platform);
-int snd_soc_register_codec(struct snd_soc_codec *codec);
-void snd_soc_unregister_codec(struct snd_soc_codec *codec);
+int snd_soc_register_platform(struct device *dev,
+		struct snd_soc_platform_driver *platform_drv);
+void snd_soc_unregister_platform(struct device *dev);
+int snd_soc_register_codec(struct device *dev,
+		struct snd_soc_codec_driver *codec_drv,
+		struct snd_soc_dai_driver *dai_drv, int num_dai);
+void snd_soc_unregister_codec(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, 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);
 
 
-/* pcm <-> DAI connect */
-void snd_soc_free_pcms(struct snd_soc_device *socdev);
-int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
-
 /* 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);
 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -273,7 +276,7 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
 	const struct snd_pcm_hardware *hw);
 	const struct snd_pcm_hardware *hw);
 
 
 /* Jack reporting */
 /* Jack reporting */
-int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
 		     struct snd_soc_jack *jack);
 		     struct snd_soc_jack *jack);
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
@@ -382,7 +385,7 @@ struct snd_soc_jack_gpio {
 	int invert;
 	int invert;
 	int debounce_time;
 	int debounce_time;
 	struct snd_soc_jack *jack;
 	struct snd_soc_jack *jack;
-	struct work_struct work;
+	struct delayed_work work;
 
 
 	int (*jack_status_check)(void);
 	int (*jack_status_check)(void);
 };
 };
@@ -390,7 +393,7 @@ struct snd_soc_jack_gpio {
 
 
 struct snd_soc_jack {
 struct snd_soc_jack {
 	struct snd_jack *jack;
 	struct snd_jack *jack;
-	struct snd_soc_card *card;
+	struct snd_soc_codec *codec;
 	struct list_head pins;
 	struct list_head pins;
 	int status;
 	int status;
 	struct blocking_notifier_head notifier;
 	struct blocking_notifier_head notifier;
@@ -398,15 +401,13 @@ struct snd_soc_jack {
 
 
 /* SoC PCM stream information */
 /* SoC PCM stream information */
 struct snd_soc_pcm_stream {
 struct snd_soc_pcm_stream {
-	char *stream_name;
+	const char *stream_name;
 	u64 formats;			/* SNDRV_PCM_FMTBIT_* */
 	u64 formats;			/* SNDRV_PCM_FMTBIT_* */
 	unsigned int rates;		/* SNDRV_PCM_RATE_* */
 	unsigned int rates;		/* SNDRV_PCM_RATE_* */
 	unsigned int rate_min;		/* min rate */
 	unsigned int rate_min;		/* min rate */
 	unsigned int rate_max;		/* max rate */
 	unsigned int rate_max;		/* max rate */
 	unsigned int channels_min;	/* min channels */
 	unsigned int channels_min;	/* min channels */
 	unsigned int channels_max;	/* max channels */
 	unsigned int channels_max;	/* max channels */
-	unsigned int active;		/* stream is in use */
-	void *dma_data;			/* used by platform code */
 };
 };
 
 
 /* SoC audio ops */
 /* SoC audio ops */
@@ -419,44 +420,36 @@ struct snd_soc_ops {
 	int (*trigger)(struct snd_pcm_substream *, int);
 	int (*trigger)(struct snd_pcm_substream *, int);
 };
 };
 
 
-/* SoC Audio Codec */
+/* SoC Audio Codec device */
 struct snd_soc_codec {
 struct snd_soc_codec {
-	char *name;
-	struct module *owner;
-	struct mutex mutex;
+	const char *name;
+	int id;
 	struct device *dev;
 	struct device *dev;
-	struct snd_soc_device *socdev;
+	struct snd_soc_codec_driver *driver;
 
 
+	struct mutex mutex;
+	struct snd_soc_card *card;
 	struct list_head list;
 	struct list_head list;
-
-	/* callbacks */
-	int (*set_bias_level)(struct snd_soc_codec *,
-			      enum snd_soc_bias_level level);
+	struct list_head card_list;
+	int num_dai;
 
 
 	/* runtime */
 	/* runtime */
-	struct snd_card *card;
 	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
 	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
 	unsigned int active;
 	unsigned int active;
-	unsigned int pcm_devs;
-	void *drvdata;
+	unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
+	unsigned int cache_only:1;  /* Suppress writes to hardware */
+	unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
+	unsigned int suspended:1; /* Codec is in suspend PM state */
+	unsigned int probed:1; /* Codec has been probed */
+	unsigned int ac97_registered:1; /* Codec has been AC97 registered */
+	unsigned int ac97_created:1; /* Codec has been created by SoC */
+	unsigned int sysfs_registered:1; /* codec has been sysfs registered */
 
 
 	/* codec IO */
 	/* codec IO */
 	void *control_data; /* codec control (i2c/3wire) data */
 	void *control_data; /* codec control (i2c/3wire) data */
-	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
-	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
-	int (*display_register)(struct snd_soc_codec *, char *,
-				size_t, unsigned int);
-	int (*volatile_register)(unsigned int);
-	int (*readable_register)(unsigned int);
 	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);
 	void *reg_cache;
 	void *reg_cache;
-	short reg_cache_size;
-	short reg_cache_step;
-
-	unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
-	unsigned int cache_only:1;  /* Suppress writes to hardware */
-	unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
 
 
 	/* dapm */
 	/* dapm */
 	u32 pop_time;
 	u32 pop_time;
@@ -466,10 +459,6 @@ struct snd_soc_codec {
 	enum snd_soc_bias_level suspend_bias_level;
 	enum snd_soc_bias_level suspend_bias_level;
 	struct delayed_work delayed_work;
 	struct delayed_work delayed_work;
 
 
-	/* codec DAI's */
-	struct snd_soc_dai *dai;
-	unsigned int num_dai;
-
 #ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_codec_root;
 	struct dentry *debugfs_codec_root;
 	struct dentry *debugfs_reg;
 	struct dentry *debugfs_reg;
@@ -478,23 +467,40 @@ struct snd_soc_codec {
 #endif
 #endif
 };
 };
 
 
-/* codec device */
-struct snd_soc_codec_device {
-	int (*probe)(struct platform_device *pdev);
-	int (*remove)(struct platform_device *pdev);
-	int (*suspend)(struct platform_device *pdev, pm_message_t state);
-	int (*resume)(struct platform_device *pdev);
+/* codec driver */
+struct snd_soc_codec_driver {
+
+	/* driver ops */
+	int (*probe)(struct snd_soc_codec *);
+	int (*remove)(struct snd_soc_codec *);
+	int (*suspend)(struct snd_soc_codec *,
+			pm_message_t state);
+	int (*resume)(struct snd_soc_codec *);
+
+	/* codec IO */
+	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+	int (*display_register)(struct snd_soc_codec *, char *,
+				size_t, unsigned int);
+	int (*volatile_register)(unsigned int);
+	int (*readable_register)(unsigned int);
+	short reg_cache_size;
+	short reg_cache_step;
+	short reg_word_size;
+	const void *reg_cache_default;
+
+	/* codec bias level */
+	int (*set_bias_level)(struct snd_soc_codec *,
+			      enum snd_soc_bias_level level);
 };
 };
 
 
 /* SoC platform interface */
 /* SoC platform interface */
-struct snd_soc_platform {
-	char *name;
-	struct list_head list;
+struct snd_soc_platform_driver {
 
 
-	int (*probe)(struct platform_device *pdev);
-	int (*remove)(struct platform_device *pdev);
-	int (*suspend)(struct snd_soc_dai_link *dai_link);
-	int (*resume)(struct snd_soc_dai_link *dai_link);
+	int (*probe)(struct snd_soc_platform *);
+	int (*remove)(struct snd_soc_platform *);
+	int (*suspend)(struct snd_soc_dai *dai);
+	int (*resume)(struct snd_soc_dai *dai);
 
 
 	/* pcm creation and destruction */
 	/* pcm creation and destruction */
 	int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
 	int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
@@ -509,23 +515,31 @@ struct snd_soc_platform {
 		struct snd_soc_dai *);
 		struct snd_soc_dai *);
 
 
 	/* platform stream ops */
 	/* platform stream ops */
-	struct snd_pcm_ops *pcm_ops;
+	struct snd_pcm_ops *ops;
 };
 };
 
 
-/* SoC machine DAI configuration, glues a codec and cpu DAI together */
-struct snd_soc_dai_link  {
-	char *name;			/* Codec name */
-	char *stream_name;		/* Stream name */
+struct snd_soc_platform {
+	const char *name;
+	int id;
+	struct device *dev;
+	struct snd_soc_platform_driver *driver;
 
 
-	/* DAI */
-	struct snd_soc_dai *codec_dai;
-	struct snd_soc_dai *cpu_dai;
+	unsigned int suspended:1; /* platform is suspended */
+	unsigned int probed:1;
 
 
-	/* machine stream operations */
-	struct snd_soc_ops *ops;
+	struct snd_soc_card *card;
+	struct list_head list;
+	struct list_head card_list;
+};
 
 
-	/* codec/machine specific init - e.g. add machine controls */
-	int (*init)(struct snd_soc_codec *codec);
+struct snd_soc_dai_link {
+	/* config - must be set by machine driver */
+	const char *name;			/* Codec name */
+	const char *stream_name;		/* Stream name */
+	const char *codec_name;		/* for multi-codec */
+	const char *platform_name;	/* for multi-platform */
+	const char *cpu_dai_name;
+	const char *codec_dai_name;
 
 
 	/* Keep DAI active over suspend */
 	/* Keep DAI active over suspend */
 	unsigned int ignore_suspend:1;
 	unsigned int ignore_suspend:1;
@@ -533,21 +547,24 @@ struct snd_soc_dai_link  {
 	/* Symmetry requirements */
 	/* Symmetry requirements */
 	unsigned int symmetric_rates:1;
 	unsigned int symmetric_rates:1;
 
 
-	/* Symmetry data - only valid if symmetry is being enforced */
-	unsigned int rate;
+	/* codec/machine specific init - e.g. add machine controls */
+	int (*init)(struct snd_soc_pcm_runtime *rtd);
 
 
-	/* DAI pcm */
-	struct snd_pcm *pcm;
+	/* machine stream operations */
+	struct snd_soc_ops *ops;
 };
 };
 
 
 /* SoC card */
 /* SoC card */
 struct snd_soc_card {
 struct snd_soc_card {
-	char *name;
+	const char *name;
 	struct device *dev;
 	struct device *dev;
+	struct snd_card *snd_card;
+	struct module *owner;
 
 
 	struct list_head list;
 	struct list_head list;
+	struct mutex mutex;
 
 
-	int instantiated;
+	bool instantiated;
 
 
 	int (*probe)(struct platform_device *pdev);
 	int (*probe)(struct platform_device *pdev);
 	int (*remove)(struct platform_device *pdev);
 	int (*remove)(struct platform_device *pdev);
@@ -568,28 +585,38 @@ struct snd_soc_card {
 	/* CPU <--> Codec DAI links  */
 	/* CPU <--> Codec DAI links  */
 	struct snd_soc_dai_link *dai_link;
 	struct snd_soc_dai_link *dai_link;
 	int num_links;
 	int num_links;
+	struct snd_soc_pcm_runtime *rtd;
+	int num_rtd;
 
 
-	struct snd_soc_device *socdev;
-
-	struct snd_soc_codec *codec;
-
-	struct snd_soc_platform *platform;
-	struct delayed_work delayed_work;
 	struct work_struct deferred_resume_work;
 	struct work_struct deferred_resume_work;
+
+	/* lists of probed devices belonging to this card */
+	struct list_head codec_dev_list;
+	struct list_head platform_dev_list;
+	struct list_head dai_dev_list;
 };
 };
 
 
-/* SoC Device - the audio subsystem */
-struct snd_soc_device {
-	struct device *dev;
+/* SoC machine DAI configuration, glues a codec and cpu DAI together */
+struct snd_soc_pcm_runtime  {
+	struct device dev;
 	struct snd_soc_card *card;
 	struct snd_soc_card *card;
-	struct snd_soc_codec_device *codec_dev;
-	void *codec_data;
-};
+	struct snd_soc_dai_link *dai_link;
+
+	unsigned int complete:1;
+	unsigned int dev_registered:1;
+
+	/* Symmetry data - only valid if symmetry is being enforced */
+	unsigned int rate;
+	long pmdown_time;
 
 
-/* runtime channel data */
-struct snd_soc_pcm_runtime {
-	struct snd_soc_dai_link *dai;
-	struct snd_soc_device *socdev;
+	/* runtime devices */
+	struct snd_pcm *pcm;
+	struct snd_soc_codec *codec;
+	struct snd_soc_platform *platform;
+	struct snd_soc_dai *codec_dai;
+	struct snd_soc_dai *cpu_dai;
+
+	struct delayed_work delayed_work;
 };
 };
 
 
 /* mixer control */
 /* mixer control */
@@ -615,24 +642,48 @@ struct soc_enum {
 static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
 static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
 					unsigned int reg)
 					unsigned int reg)
 {
 {
-	return codec->read(codec, reg);
+	return codec->driver->read(codec, reg);
 }
 }
 
 
 static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
 static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
 					 unsigned int reg, unsigned int val)
 					 unsigned int reg, unsigned int val)
 {
 {
-	return codec->write(codec, reg, val);
+	return codec->driver->write(codec, reg, val);
 }
 }
 
 
+/* device driver data */
+
 static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
 static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
-					     void *data)
+		void *data)
 {
 {
-	codec->drvdata = data;
+	dev_set_drvdata(codec->dev, data);
 }
 }
 
 
 static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
 static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
 {
 {
-	return codec->drvdata;
+	return dev_get_drvdata(codec->dev);
+}
+
+static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform,
+		void *data)
+{
+	dev_set_drvdata(platform->dev, data);
+}
+
+static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform)
+{
+	return dev_get_drvdata(platform->dev);
+}
+
+static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
+		void *data)
+{
+	dev_set_drvdata(&rtd->dev, data);
+}
+
+static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd)
+{
+	return dev_get_drvdata(&rtd->dev);
 }
 }
 
 
 #include <sound/soc-dai.h>
 #include <sound/soc-dai.h>

+ 3 - 1
include/sound/tlv.h

@@ -38,9 +38,11 @@
 #define SNDRV_CTL_TLVT_DB_MINMAX 4	/* dB scale with min/max */
 #define SNDRV_CTL_TLVT_DB_MINMAX 4	/* dB scale with min/max */
 #define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5	/* dB scale with min/max with mute */
 #define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5	/* dB scale with min/max with mute */
 
 
+#define TLV_DB_SCALE_MASK	0xffff
+#define TLV_DB_SCALE_MUTE	0x10000
 #define TLV_DB_SCALE_ITEM(min, step, mute)			\
 #define TLV_DB_SCALE_ITEM(min, step, mute)			\
 	SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int),	\
 	SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int),	\
-	(min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0)
+	(min), ((step) & TLV_DB_SCALE_MASK) | ((mute) ? TLV_DB_SCALE_MUTE : 0)
 #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
 #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
 	unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
 	unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
 
 

+ 42 - 1
include/sound/tlv320aic3x.h

@@ -10,8 +10,49 @@
 #ifndef __TLV320AIC3x_H__
 #ifndef __TLV320AIC3x_H__
 #define __TLV320AIC3x_H__
 #define __TLV320AIC3x_H__
 
 
+/* GPIO API */
+enum {
+	AIC3X_GPIO1_FUNC_DISABLED		= 0,
+	AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC	= 1,
+	AIC3X_GPIO1_FUNC_CLOCK_MUX		= 2,
+	AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2		= 3,
+	AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4		= 4,
+	AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8		= 5,
+	AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ	= 6,
+	AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ		= 7,
+	AIC3X_GPIO1_FUNC_INPUT			= 8,
+	AIC3X_GPIO1_FUNC_OUTPUT			= 9,
+	AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK	= 10,
+	AIC3X_GPIO1_FUNC_AUDIO_WORDCLK		= 11,
+	AIC3X_GPIO1_FUNC_BUTTON_IRQ		= 12,
+	AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ	= 13,
+	AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ	= 14,
+	AIC3X_GPIO1_FUNC_ALL_IRQ		= 16
+};
+
+enum {
+	AIC3X_GPIO2_FUNC_DISABLED		= 0,
+	AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ	= 2,
+	AIC3X_GPIO2_FUNC_INPUT			= 3,
+	AIC3X_GPIO2_FUNC_OUTPUT			= 4,
+	AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT	= 5,
+	AIC3X_GPIO2_FUNC_AUDIO_BITCLK		= 8,
+	AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
+	AIC3X_GPIO2_FUNC_ALL_IRQ		= 10,
+	AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
+	AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
+	AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ	= 13,
+	AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ		= 14,
+	AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ	= 15
+};
+
+struct aic3x_setup_data {
+	unsigned int gpio_func[2];
+};
+
 struct aic3x_pdata {
 struct aic3x_pdata {
 	int gpio_reset; /* < 0 if not used */
 	int gpio_reset; /* < 0 if not used */
+	struct aic3x_setup_data *setup;
 };
 };
 
 
-#endif
+#endif

+ 32 - 0
include/sound/wm8962.h

@@ -0,0 +1,32 @@
+/*
+ * wm8962.h  --  WM8962 Soc Audio driver platform data
+ *
+ * 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 _WM8962_PDATA_H
+#define _WM8962_PDATA_H
+
+#define WM8962_MAX_GPIO 6
+
+/* Use to set GPIO default values to zero */
+#define WM8962_GPIO_SET 0x10000
+
+struct wm8962_pdata {
+	int gpio_base;
+	u32 gpio_init[WM8962_MAX_GPIO];
+
+	/* Setup for microphone detection, raw value to be written to
+	 * R48(0x30) - only microphone related bits will be updated.
+	 * Detection may be enabled here for use with signals brought
+	 * out on the GPIOs. */
+	u32 mic_cfg;
+
+	bool irq_active_low;
+
+	bool spk_mono;   /* Speaker outputs tied together as mono */
+};
+
+#endif

+ 16 - 0
include/video/sh_mobile_hdmi.h

@@ -14,9 +14,25 @@
 struct sh_mobile_lcdc_chan_cfg;
 struct sh_mobile_lcdc_chan_cfg;
 struct device;
 struct device;
 
 
+/*
+ * flags format
+ *
+ * 0x0000000A
+ *
+ * A: Audio source select
+ */
+
+/* Audio source select */
+#define HDMI_SND_SRC_MASK	(0xF << 0)
+#define HDMI_SND_SRC_I2S	(0 << 0) /* default */
+#define HDMI_SND_SRC_SPDIF	(1 << 0)
+#define HDMI_SND_SRC_DSD	(2 << 0)
+#define HDMI_SND_SRC_HBR	(3 << 0)
+
 struct sh_mobile_hdmi_info {
 struct sh_mobile_hdmi_info {
 	struct sh_mobile_lcdc_chan_cfg	*lcd_chan;
 	struct sh_mobile_lcdc_chan_cfg	*lcd_chan;
 	struct device			*lcd_dev;
 	struct device			*lcd_dev;
+	unsigned int			 flags;
 };
 };
 
 
 #endif
 #endif

+ 7 - 2
sound/core/init.c

@@ -604,11 +604,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
 		return -EEXIST;
 		return -EEXIST;
 	}
 	}
 	for (idx = 0; idx < snd_ecards_limit; idx++) {
 	for (idx = 0; idx < snd_ecards_limit; idx++) {
-		if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1))
-			goto __exist;
+		if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) {
+			if (card == snd_cards[idx])
+				goto __ok;
+			else
+				goto __exist;
+		}
 	}
 	}
 	strcpy(card->id, buf1);
 	strcpy(card->id, buf1);
 	snd_info_card_id_change(card);
 	snd_info_card_id_change(card);
+__ok:
 	mutex_unlock(&snd_card_mutex);
 	mutex_unlock(&snd_card_mutex);
 
 
 	return count;
 	return count;

+ 19 - 15
sound/core/oss/mixer_oss.c

@@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file)
 	struct snd_mixer_oss_file *fmixer;
 	struct snd_mixer_oss_file *fmixer;
 
 
 	if (file->private_data) {
 	if (file->private_data) {
-		fmixer = (struct snd_mixer_oss_file *) file->private_data;
+		fmixer = file->private_data;
 		module_put(fmixer->card->module);
 		module_put(fmixer->card->module);
 		snd_card_file_remove(fmixer->card, file);
 		snd_card_file_remove(fmixer->card, file);
 		kfree(fmixer);
 		kfree(fmixer);
@@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int
 
 
 static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 {
-	return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg);
+	return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
 }
 }
 
 
 int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
 int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
@@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
 				     struct snd_mixer_oss_slot *pslot,
 				     struct snd_mixer_oss_slot *pslot,
 				     int *left, int *right)
 				     int *left, int *right)
 {
 {
-	struct slot *slot = (struct slot *)pslot->private_data;
+	struct slot *slot = pslot->private_data;
 	
 	
 	*left = *right = 100;
 	*left = *right = 100;
 	if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
 	if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
@@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
 	if (numid == ID_UNKNOWN)
 	if (numid == ID_UNKNOWN)
 		return;
 		return;
 	down_read(&card->controls_rwsem);
 	down_read(&card->controls_rwsem);
-	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL)
+	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
+		up_read(&card->controls_rwsem);
 		return;
 		return;
+	}
 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 	if (uinfo == NULL || uctl == NULL)
 	if (uinfo == NULL || uctl == NULL)
@@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
 		return;
 		return;
 	down_read(&card->controls_rwsem);
 	down_read(&card->controls_rwsem);
 	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
 	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
-		up_read(&fmixer->card->controls_rwsem);
+		up_read(&card->controls_rwsem);
 		return;
 		return;
 	}
 	}
 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
@@ -691,7 +693,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
 				     struct snd_mixer_oss_slot *pslot,
 				     struct snd_mixer_oss_slot *pslot,
 				     int left, int right)
 				     int left, int right)
 {
 {
-	struct slot *slot = (struct slot *)pslot->private_data;
+	struct slot *slot = pslot->private_data;
 	
 	
 	if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
 	if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
 		snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
 		snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
@@ -740,7 +742,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
 					struct snd_mixer_oss_slot *pslot,
 					struct snd_mixer_oss_slot *pslot,
 					int *active)
 					int *active)
 {
 {
-	struct slot *slot = (struct slot *)pslot->private_data;
+	struct slot *slot = pslot->private_data;
 	int left, right;
 	int left, right;
 	
 	
 	left = right = 1;
 	left = right = 1;
@@ -753,7 +755,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
 					   struct snd_mixer_oss_slot *pslot,
 					   struct snd_mixer_oss_slot *pslot,
 					   int *active)
 					   int *active)
 {
 {
-	struct slot *slot = (struct slot *)pslot->private_data;
+	struct slot *slot = pslot->private_data;
 	int left, right;
 	int left, right;
 	
 	
 	left = right = 1;
 	left = right = 1;
@@ -766,7 +768,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
 					struct snd_mixer_oss_slot *pslot,
 					struct snd_mixer_oss_slot *pslot,
 					int active)
 					int active)
 {
 {
-	struct slot *slot = (struct slot *)pslot->private_data;
+	struct slot *slot = pslot->private_data;
 	
 	
 	snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
 	snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
 	return 0;
 	return 0;
@@ -776,7 +778,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
 					   struct snd_mixer_oss_slot *pslot,
 					   struct snd_mixer_oss_slot *pslot,
 					   int active)
 					   int active)
 {
 {
-	struct slot *slot = (struct slot *)pslot->private_data;
+	struct slot *slot = pslot->private_data;
 	
 	
 	snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
 	snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
 	return 0;
 	return 0;
@@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 	if (uinfo == NULL || uctl == NULL) {
 	if (uinfo == NULL || uctl == NULL) {
 		err = -ENOMEM;
 		err = -ENOMEM;
-		goto __unlock;
+		goto __free_only;
 	}
 	}
 	down_read(&card->controls_rwsem);
 	down_read(&card->controls_rwsem);
 	kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
 	kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
@@ -813,7 +815,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
 		if (!(mixer->mask_recsrc & (1 << idx)))
 		if (!(mixer->mask_recsrc & (1 << idx)))
 			continue;
 			continue;
 		pslot = &mixer->slots[idx];
 		pslot = &mixer->slots[idx];
-		slot = (struct slot *)pslot->private_data;
+		slot = pslot->private_data;
 		if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
 		if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
 			continue;
 			continue;
 		if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
 		if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
 	err = 0;
 	err = 0;
       __unlock:
       __unlock:
      	up_read(&card->controls_rwsem);
      	up_read(&card->controls_rwsem);
+      __free_only:
       	kfree(uctl);
       	kfree(uctl);
       	kfree(uinfo);
       	kfree(uinfo);
       	return err;
       	return err;
@@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 	if (uinfo == NULL || uctl == NULL) {
 	if (uinfo == NULL || uctl == NULL) {
 		err = -ENOMEM;
 		err = -ENOMEM;
-		goto __unlock;
+		goto __free_only;
 	}
 	}
 	down_read(&card->controls_rwsem);
 	down_read(&card->controls_rwsem);
 	kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
 	kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
@@ -861,7 +864,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
 		if (!(mixer->mask_recsrc & (1 << idx)))
 		if (!(mixer->mask_recsrc & (1 << idx)))
 			continue;
 			continue;
 		pslot = &mixer->slots[idx];
 		pslot = &mixer->slots[idx];
-		slot = (struct slot *)pslot->private_data;
+		slot = pslot->private_data;
 		if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
 		if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
 			continue;
 			continue;
 		if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
 		if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
 	err = 0;
 	err = 0;
       __unlock:
       __unlock:
 	up_read(&card->controls_rwsem);
 	up_read(&card->controls_rwsem);
+      __free_only:
 	kfree(uctl);
 	kfree(uctl);
 	kfree(uinfo);
 	kfree(uinfo);
 	return err;
 	return err;
@@ -925,7 +929,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl
 
 
 static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
 static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
 {
 {
-	struct slot *p = (struct slot *)chn->private_data;
+	struct slot *p = chn->private_data;
 	if (p) {
 	if (p) {
 		if (p->allocated && p->assigned) {
 		if (p->allocated && p->assigned) {
 			kfree(p->assigned->name);
 			kfree(p->assigned->name);

+ 1 - 2
sound/core/pcm.c

@@ -364,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
 static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
 static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
 					     struct snd_info_buffer *buffer)
 					     struct snd_info_buffer *buffer)
 {
 {
-	snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data,
-			       buffer);
+	snd_pcm_proc_info_read(entry->private_data, buffer);
 }
 }
 
 
 static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
 static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,

+ 9 - 5
sound/core/pcm_lib.c

@@ -334,11 +334,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 		/* delta = "expected next hw_ptr" for in_interrupt != 0 */
 		/* delta = "expected next hw_ptr" for in_interrupt != 0 */
 		delta = runtime->hw_ptr_interrupt + runtime->period_size;
 		delta = runtime->hw_ptr_interrupt + runtime->period_size;
 		if (delta > new_hw_ptr) {
 		if (delta > new_hw_ptr) {
-			hw_base += runtime->buffer_size;
-			if (hw_base >= runtime->boundary)
-				hw_base = 0;
-			new_hw_ptr = hw_base + pos;
-			goto __delta;
+			/* check for double acknowledged interrupts */
+			hdelta = jiffies - runtime->hw_ptr_jiffies;
+			if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
+				hw_base += runtime->buffer_size;
+				if (hw_base >= runtime->boundary)
+					hw_base = 0;
+				new_hw_ptr = hw_base + pos;
+				goto __delta;
+			}
 		}
 		}
 	}
 	}
 	/* new_hw_ptr might be lower than old_hw_ptr in case when */
 	/* new_hw_ptr might be lower than old_hw_ptr in case when */

+ 3 - 1
sound/core/pcm_native.c

@@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
 
 
 #ifdef RULES_DEBUG
 #ifdef RULES_DEBUG
 #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
 #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
-char *snd_pcm_hw_param_names[] = {
+static const char * const snd_pcm_hw_param_names[] = {
 	HW_PARAM(ACCESS),
 	HW_PARAM(ACCESS),
 	HW_PARAM(FORMAT),
 	HW_PARAM(FORMAT),
 	HW_PARAM(SUBFORMAT),
 	HW_PARAM(SUBFORMAT),
@@ -864,6 +864,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_trigger_tstamp(substream);
 	snd_pcm_trigger_tstamp(substream);
 	runtime->hw_ptr_jiffies = jiffies;
 	runtime->hw_ptr_jiffies = jiffies;
+	runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / 
+							    runtime->rate;
 	runtime->status->state = state;
 	runtime->status->state = state;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	    runtime->silence_size > 0)
 	    runtime->silence_size > 0)

+ 19 - 0
sound/drivers/Kconfig

@@ -74,6 +74,25 @@ config SND_DUMMY
 	  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-dummy.
 	  will be called snd-dummy.
 
 
+config SND_ALOOP
+        tristate "Generic loopback driver (PCM)"
+        select SND_PCM
+        help
+          Say 'Y' or 'M' to include support for the PCM loopback device.
+	  This module returns played samples back to the user space using
+	  the standard ALSA PCM device. The devices are routed 0->1 and
+          1->0, where first number is the playback PCM device and second
+	  number is the capture device. Module creates two PCM devices and
+	  configured number of substreams (see the pcm_substreams module
+          parameter).
+
+	  The looback device allow time sychronization with an external
+	  timing source using the time shift universal control (+-20%
+	  of system time).
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-aloop.
+
 config SND_VIRMIDI
 config SND_VIRMIDI
 	tristate "Virtual MIDI soundcard"
 	tristate "Virtual MIDI soundcard"
 	depends on SND_SEQUENCER
 	depends on SND_SEQUENCER

+ 2 - 0
sound/drivers/Makefile

@@ -4,6 +4,7 @@
 #
 #
 
 
 snd-dummy-objs := dummy.o
 snd-dummy-objs := dummy.o
+snd-aloop-objs := aloop.o
 snd-mtpav-objs := mtpav.o
 snd-mtpav-objs := mtpav.o
 snd-mts64-objs := mts64.o
 snd-mts64-objs := mts64.o
 snd-portman2x4-objs := portman2x4.o
 snd-portman2x4-objs := portman2x4.o
@@ -13,6 +14,7 @@ snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o
 
 
 # Toplevel Module Dependency
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
 obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
+obj-$(CONFIG_SND_ALOOP) += snd-aloop.o
 obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
 obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
 obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
 obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
 obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
 obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o

+ 1258 - 0
sound/drivers/aloop.c

@@ -0,0 +1,1258 @@
+/*
+ *  Loopback soundcard
+ *
+ *  Original code:
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *
+ *  More accurate positioning and full-duplex support:
+ *  Copyright (c) Ahmet İnan <ainan at mathematik.uni-freiburg.de>
+ *
+ *  Major (almost complete) rewrite:
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *  A next major update in 2010 (separate timers for playback and capture):
+ *  Copyright (c) Jaroslav Kysela <perex@perex.cz>
+ *
+ *   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/init.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
+MODULE_DESCRIPTION("A loopback soundcard");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}");
+
+#define MAX_PCM_SUBSTREAMS	8
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
+static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
+static int pcm_notify[SNDRV_CARDS];
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for loopback soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for loopback soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable this loopback soundcard.");
+module_param_array(pcm_substreams, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
+module_param_array(pcm_notify, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
+
+#define NO_PITCH 100000
+
+struct loopback_pcm;
+
+struct loopback_cable {
+	spinlock_t lock;
+	struct loopback_pcm *streams[2];
+	struct snd_pcm_hardware hw;
+	/* flags */
+	unsigned int valid;
+	unsigned int running;
+	unsigned int pause;
+};
+
+struct loopback_setup {
+	unsigned int notify: 1;
+	unsigned int rate_shift;
+	unsigned int format;
+	unsigned int rate;
+	unsigned int channels;
+	struct snd_ctl_elem_id active_id;
+	struct snd_ctl_elem_id format_id;
+	struct snd_ctl_elem_id rate_id;
+	struct snd_ctl_elem_id channels_id;
+};
+
+struct loopback {
+	struct snd_card *card;
+	struct mutex cable_lock;
+	struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2];
+	struct snd_pcm *pcm[2];
+	struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2];
+};
+
+struct loopback_pcm {
+	struct loopback *loopback;
+	struct snd_pcm_substream *substream;
+	struct loopback_cable *cable;
+	unsigned int pcm_buffer_size;
+	unsigned int buf_pos;	/* position in buffer */
+	unsigned int silent_size;
+	/* PCM parameters */
+	unsigned int pcm_period_size;
+	unsigned int pcm_bps;		/* bytes per second */
+	unsigned int pcm_salign;	/* bytes per sample * channels */
+	unsigned int pcm_rate_shift;	/* rate shift value */
+	/* flags */
+	unsigned int period_update_pending :1;
+	/* timer stuff */
+	unsigned int irq_pos;		/* fractional IRQ position */
+	unsigned int period_size_frac;
+	unsigned long last_jiffies;
+	struct timer_list timer;
+};
+
+static struct platform_device *devices[SNDRV_CARDS];
+
+static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x)
+{
+	if (dpcm->pcm_rate_shift == NO_PITCH) {
+		x /= HZ;
+	} else {
+		x = div_u64(NO_PITCH * (unsigned long long)x,
+			    HZ * (unsigned long long)dpcm->pcm_rate_shift);
+	}
+	return x - (x % dpcm->pcm_salign);
+}
+
+static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x)
+{
+	if (dpcm->pcm_rate_shift == NO_PITCH) {	/* no pitch */
+		return x * HZ;
+	} else {
+		x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ,
+			    NO_PITCH);
+	}
+	return x;
+}
+
+static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm)
+{
+	int device = dpcm->substream->pstr->pcm->device;
+	
+	if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		device ^= 1;
+	return &dpcm->loopback->setup[dpcm->substream->number][device];
+}
+
+static inline unsigned int get_notify(struct loopback_pcm *dpcm)
+{
+	return get_setup(dpcm)->notify;
+}
+
+static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm)
+{
+	return get_setup(dpcm)->rate_shift;
+}
+
+static void loopback_timer_start(struct loopback_pcm *dpcm)
+{
+	unsigned long tick;
+	unsigned int rate_shift = get_rate_shift(dpcm);
+
+	if (rate_shift != dpcm->pcm_rate_shift) {
+		dpcm->pcm_rate_shift = rate_shift;
+		dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
+	}
+	if (dpcm->period_size_frac <= dpcm->irq_pos) {
+		dpcm->irq_pos %= dpcm->period_size_frac;
+		dpcm->period_update_pending = 1;
+	}
+	tick = dpcm->period_size_frac - dpcm->irq_pos;
+	tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
+	dpcm->timer.expires = jiffies + tick;
+	add_timer(&dpcm->timer);
+}
+
+static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
+{
+	del_timer(&dpcm->timer);
+	dpcm->timer.expires = 0;
+}
+
+#define CABLE_VALID_PLAYBACK	(1 << SNDRV_PCM_STREAM_PLAYBACK)
+#define CABLE_VALID_CAPTURE	(1 << SNDRV_PCM_STREAM_CAPTURE)
+#define CABLE_VALID_BOTH	(CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
+
+static int loopback_check_format(struct loopback_cable *cable, int stream)
+{
+	struct snd_pcm_runtime *runtime, *cruntime;
+	struct loopback_setup *setup;
+	struct snd_card *card;
+	int check;
+
+	if (cable->valid != CABLE_VALID_BOTH) {
+		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+			goto __notify;
+		return 0;
+	}
+	runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+							substream->runtime;
+	cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+							substream->runtime;
+	check = runtime->format != cruntime->format ||
+		runtime->rate != cruntime->rate ||
+		runtime->channels != cruntime->channels;
+	if (!check)
+		return 0;
+	if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+		return -EIO;
+	} else {
+		snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+					substream, SNDRV_PCM_STATE_DRAINING);
+	      __notify:
+		runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+							substream->runtime;
+		setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]);
+		card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card;
+		if (setup->format != runtime->format) {
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+							&setup->format_id);
+			setup->format = runtime->format;
+		}
+		if (setup->rate != runtime->rate) {
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+							&setup->rate_id);
+			setup->rate = runtime->rate;
+		}
+		if (setup->channels != runtime->channels) {
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+							&setup->channels_id);
+			setup->channels = runtime->channels;
+		}
+	}
+	return 0;
+}
+
+static void loopback_active_notify(struct loopback_pcm *dpcm)
+{
+	snd_ctl_notify(dpcm->loopback->card,
+		       SNDRV_CTL_EVENT_MASK_VALUE,
+		       &get_setup(dpcm)->active_id);
+}
+
+static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct loopback_pcm *dpcm = runtime->private_data;
+	struct loopback_cable *cable = dpcm->cable;
+	int err, stream = 1 << substream->stream;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		err = loopback_check_format(cable, substream->stream);
+		if (err < 0)
+			return err;
+		dpcm->last_jiffies = jiffies;
+		dpcm->pcm_rate_shift = 0;
+		spin_lock(&cable->lock);	
+		cable->running |= stream;
+		cable->pause &= ~stream;
+		spin_unlock(&cable->lock);
+		loopback_timer_start(dpcm);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			loopback_active_notify(dpcm);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		spin_lock(&cable->lock);	
+		cable->running &= ~stream;
+		cable->pause &= ~stream;
+		spin_unlock(&cable->lock);
+		loopback_timer_stop(dpcm);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			loopback_active_notify(dpcm);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		spin_lock(&cable->lock);	
+		cable->pause |= stream;
+		spin_unlock(&cable->lock);
+		loopback_timer_stop(dpcm);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		spin_lock(&cable->lock);
+		dpcm->last_jiffies = jiffies;
+		cable->pause &= ~stream;
+		spin_unlock(&cable->lock);
+		loopback_timer_start(dpcm);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void params_change_substream(struct loopback_pcm *dpcm,
+				    struct snd_pcm_runtime *runtime)
+{
+	struct snd_pcm_runtime *dst_runtime;
+
+	if (dpcm == NULL || dpcm->substream == NULL)
+		return;
+	dst_runtime = dpcm->substream->runtime;
+	if (dst_runtime == NULL)
+		return;
+	dst_runtime->hw = dpcm->cable->hw;
+}
+
+static void params_change(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct loopback_pcm *dpcm = runtime->private_data;
+	struct loopback_cable *cable = dpcm->cable;
+
+	cable->hw.formats = (1ULL << runtime->format);
+	cable->hw.rate_min = runtime->rate;
+	cable->hw.rate_max = runtime->rate;
+	cable->hw.channels_min = runtime->channels;
+	cable->hw.channels_max = runtime->channels;
+	params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+				runtime);
+	params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+				runtime);
+}
+
+static int loopback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct loopback_pcm *dpcm = runtime->private_data;
+	struct loopback_cable *cable = dpcm->cable;
+	int bps, salign;
+
+	salign = (snd_pcm_format_width(runtime->format) *
+						runtime->channels) / 8;
+	bps = salign * runtime->rate;
+	if (bps <= 0 || salign <= 0)
+		return -EINVAL;
+
+	dpcm->buf_pos = 0;
+	dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size);
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		/* clear capture buffer */
+		dpcm->silent_size = dpcm->pcm_buffer_size;
+		snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
+					   runtime->buffer_size * runtime->channels);
+	}
+
+	dpcm->irq_pos = 0;
+	dpcm->period_update_pending = 0;
+	dpcm->pcm_bps = bps;
+	dpcm->pcm_salign = salign;
+	dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size);
+
+	mutex_lock(&dpcm->loopback->cable_lock);
+	if (!(cable->valid & ~(1 << substream->stream)) ||
+            (get_setup(dpcm)->notify &&
+	     substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
+		params_change(substream);
+	cable->valid |= 1 << substream->stream;
+	mutex_unlock(&dpcm->loopback->cable_lock);
+
+	return 0;
+}
+
+static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes)
+{
+	struct snd_pcm_runtime *runtime = dpcm->substream->runtime;
+	char *dst = runtime->dma_area;
+	unsigned int dst_off = dpcm->buf_pos;
+
+	if (dpcm->silent_size >= dpcm->pcm_buffer_size)
+		return;
+	if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size)
+		bytes = dpcm->pcm_buffer_size - dpcm->silent_size;
+
+	for (;;) {
+		unsigned int size = bytes;
+		if (dst_off + size > dpcm->pcm_buffer_size)
+			size = dpcm->pcm_buffer_size - dst_off;
+		snd_pcm_format_set_silence(runtime->format, dst + dst_off,
+					   bytes_to_frames(runtime, size) *
+					   	runtime->channels);
+		dpcm->silent_size += size;
+		bytes -= size;
+		if (!bytes)
+			break;
+		dst_off = 0;
+	}
+}
+
+static void copy_play_buf(struct loopback_pcm *play,
+			  struct loopback_pcm *capt,
+			  unsigned int bytes)
+{
+	struct snd_pcm_runtime *runtime = play->substream->runtime;
+	char *src = runtime->dma_area;
+	char *dst = capt->substream->runtime->dma_area;
+	unsigned int src_off = play->buf_pos;
+	unsigned int dst_off = capt->buf_pos;
+	unsigned int clear_bytes = 0;
+
+	/* check if playback is draining, trim the capture copy size
+	 * when our pointer is at the end of playback ring buffer */
+	if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
+	    snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { 
+	    	snd_pcm_uframes_t appl_ptr, appl_ptr1, diff;
+		appl_ptr = appl_ptr1 = runtime->control->appl_ptr;
+		appl_ptr1 -= appl_ptr1 % runtime->buffer_size;
+		appl_ptr1 += play->buf_pos / play->pcm_salign;
+		if (appl_ptr < appl_ptr1)
+			appl_ptr1 -= runtime->buffer_size;
+		diff = (appl_ptr - appl_ptr1) * play->pcm_salign;
+		if (diff < bytes) {
+			clear_bytes = bytes - diff;
+			bytes = diff;
+		}
+	}
+
+	for (;;) {
+		unsigned int size = bytes;
+		if (src_off + size > play->pcm_buffer_size)
+			size = play->pcm_buffer_size - src_off;
+		if (dst_off + size > capt->pcm_buffer_size)
+			size = capt->pcm_buffer_size - dst_off;
+		memcpy(dst + dst_off, src + src_off, size);
+		capt->silent_size = 0;
+		bytes -= size;
+		if (!bytes)
+			break;
+		src_off = (src_off + size) % play->pcm_buffer_size;
+		dst_off = (dst_off + size) % capt->pcm_buffer_size;
+	}
+
+	if (clear_bytes > 0) {
+		clear_capture_buf(capt, clear_bytes);
+		capt->silent_size = 0;
+	}
+}
+
+#define BYTEPOS_UPDATE_POSONLY	0
+#define BYTEPOS_UPDATE_CLEAR	1
+#define BYTEPOS_UPDATE_COPY	2
+
+static void loopback_bytepos_update(struct loopback_pcm *dpcm,
+				    unsigned int delta,
+				    unsigned int cmd)
+{
+	unsigned int count;
+	unsigned long last_pos;
+
+	last_pos = byte_pos(dpcm, dpcm->irq_pos);
+	dpcm->irq_pos += delta * dpcm->pcm_bps;
+	count = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
+	if (!count)
+		return;
+	if (cmd == BYTEPOS_UPDATE_CLEAR)
+		clear_capture_buf(dpcm, count);
+	else if (cmd == BYTEPOS_UPDATE_COPY)
+		copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+			      dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+			      count);
+	dpcm->buf_pos += count;
+	dpcm->buf_pos %= dpcm->pcm_buffer_size;
+	if (dpcm->irq_pos >= dpcm->period_size_frac) {
+		dpcm->irq_pos %= dpcm->period_size_frac;
+		dpcm->period_update_pending = 1;
+	}
+}
+
+static unsigned int loopback_pos_update(struct loopback_cable *cable)
+{
+	struct loopback_pcm *dpcm_play =
+			cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
+	struct loopback_pcm *dpcm_capt =
+			cable->streams[SNDRV_PCM_STREAM_CAPTURE];
+	unsigned long delta_play = 0, delta_capt = 0;
+	unsigned int running;
+
+	spin_lock(&cable->lock);	
+	running = cable->running ^ cable->pause;
+	if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
+		delta_play = jiffies - dpcm_play->last_jiffies;
+		dpcm_play->last_jiffies += delta_play;
+	}
+
+	if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
+		delta_capt = jiffies - dpcm_capt->last_jiffies;
+		dpcm_capt->last_jiffies += delta_capt;
+	}
+
+	if (delta_play == 0 && delta_capt == 0) {
+		spin_unlock(&cable->lock);
+		return running;
+	}
+		
+	if (delta_play > delta_capt) {
+		loopback_bytepos_update(dpcm_play, delta_play - delta_capt,
+					BYTEPOS_UPDATE_POSONLY);
+		delta_play = delta_capt;
+	} else if (delta_play < delta_capt) {
+		loopback_bytepos_update(dpcm_capt, delta_capt - delta_play,
+					BYTEPOS_UPDATE_CLEAR);
+		delta_capt = delta_play;
+	}
+
+	if (delta_play == 0 && delta_capt == 0) {
+		spin_unlock(&cable->lock);
+		return running;
+	}
+	/* note delta_capt == delta_play at this moment */
+	loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY);
+	loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY);
+	spin_unlock(&cable->lock);
+	return running;
+}
+
+static void loopback_timer_function(unsigned long data)
+{
+	struct loopback_pcm *dpcm = (struct loopback_pcm *)data;
+	unsigned int running;
+
+	running = loopback_pos_update(dpcm->cable);
+	if (running & (1 << dpcm->substream->stream)) {
+		loopback_timer_start(dpcm);
+		if (dpcm->period_update_pending) {
+			dpcm->period_update_pending = 0;
+			snd_pcm_period_elapsed(dpcm->substream);
+		}
+	}
+}
+
+static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct loopback_pcm *dpcm = runtime->private_data;
+
+	loopback_pos_update(dpcm->cable);
+	return bytes_to_frames(runtime, dpcm->buf_pos);
+}
+
+static struct snd_pcm_hardware loopback_pcm_hardware =
+{
+	.info =		(SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+			 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
+	.formats =	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+			 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
+			 SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
+	.rates =	SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+	.rate_min =		8000,
+	.rate_max =		192000,
+	.channels_min =		1,
+	.channels_max =		32,
+	.buffer_bytes_max =	2 * 1024 * 1024,
+	.period_bytes_min =	64,
+	/* note check overflow in frac_pos() using pcm_rate_shift before
+	   changing period_bytes_max value */
+	.period_bytes_max =	1024 * 1024,
+	.periods_min =		1,
+	.periods_max =		1024,
+	.fifo_size =		0,
+};
+
+static void loopback_runtime_free(struct snd_pcm_runtime *runtime)
+{
+	struct loopback_pcm *dpcm = runtime->private_data;
+	kfree(dpcm);
+}
+
+static int loopback_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params)
+{
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+}
+
+static int loopback_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct loopback_pcm *dpcm = runtime->private_data;
+	struct loopback_cable *cable = dpcm->cable;
+
+	mutex_lock(&dpcm->loopback->cable_lock);
+	cable->valid &= ~(1 << substream->stream);
+	mutex_unlock(&dpcm->loopback->cable_lock);
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static unsigned int get_cable_index(struct snd_pcm_substream *substream)
+{
+	if (!substream->pcm->device)
+		return substream->stream;
+	else
+		return !substream->stream;
+}
+
+static int rule_format(struct snd_pcm_hw_params *params,
+		       struct snd_pcm_hw_rule *rule)
+{
+
+	struct snd_pcm_hardware *hw = rule->private;
+	struct snd_mask *maskp = hw_param_mask(params, rule->var);
+
+	maskp->bits[0] &= (u_int32_t)hw->formats;
+	maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
+	memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
+	if (! maskp->bits[0] && ! maskp->bits[1])
+		return -EINVAL;
+	return 0;
+}
+
+static int rule_rate(struct snd_pcm_hw_params *params,
+		     struct snd_pcm_hw_rule *rule)
+{
+	struct snd_pcm_hardware *hw = rule->private;
+	struct snd_interval t;
+
+        t.min = hw->rate_min;
+        t.max = hw->rate_max;
+        t.openmin = t.openmax = 0;
+        t.integer = 0;
+	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
+static int rule_channels(struct snd_pcm_hw_params *params,
+			 struct snd_pcm_hw_rule *rule)
+{
+	struct snd_pcm_hardware *hw = rule->private;
+	struct snd_interval t;
+
+        t.min = hw->channels_min;
+        t.max = hw->channels_max;
+        t.openmin = t.openmax = 0;
+        t.integer = 0;
+	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
+static int loopback_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct loopback *loopback = substream->private_data;
+	struct loopback_pcm *dpcm;
+	struct loopback_cable *cable;
+	int err = 0;
+	int dev = get_cable_index(substream);
+
+	mutex_lock(&loopback->cable_lock);
+	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
+	if (!dpcm) {
+		err = -ENOMEM;
+		goto unlock;
+	}
+	dpcm->loopback = loopback;
+	dpcm->substream = substream;
+	setup_timer(&dpcm->timer, loopback_timer_function,
+		    (unsigned long)dpcm);
+
+	cable = loopback->cables[substream->number][dev];
+	if (!cable) {
+		cable = kzalloc(sizeof(*cable), GFP_KERNEL);
+		if (!cable) {
+			kfree(dpcm);
+			err = -ENOMEM;
+			goto unlock;
+		}
+		spin_lock_init(&cable->lock);
+		cable->hw = loopback_pcm_hardware;
+		loopback->cables[substream->number][dev] = cable;
+	}
+	dpcm->cable = cable;
+	cable->streams[substream->stream] = dpcm;
+
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+	/* use dynamic rules based on actual runtime->hw values */
+	/* note that the default rules created in the PCM midlevel code */
+	/* are cached -> they do not reflect the actual state */
+	err = snd_pcm_hw_rule_add(runtime, 0,
+				  SNDRV_PCM_HW_PARAM_FORMAT,
+				  rule_format, &runtime->hw,
+				  SNDRV_PCM_HW_PARAM_FORMAT, -1);
+	if (err < 0)
+		goto unlock;
+	err = snd_pcm_hw_rule_add(runtime, 0,
+				  SNDRV_PCM_HW_PARAM_RATE,
+				  rule_rate, &runtime->hw,
+				  SNDRV_PCM_HW_PARAM_RATE, -1);
+	if (err < 0)
+		goto unlock;
+	err = snd_pcm_hw_rule_add(runtime, 0,
+				  SNDRV_PCM_HW_PARAM_CHANNELS,
+				  rule_channels, &runtime->hw,
+				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+	if (err < 0)
+		goto unlock;
+
+	runtime->private_data = dpcm;
+	runtime->private_free = loopback_runtime_free;
+	if (get_notify(dpcm))
+		runtime->hw = loopback_pcm_hardware;
+	else
+		runtime->hw = cable->hw;
+ unlock:
+	mutex_unlock(&loopback->cable_lock);
+	return err;
+}
+
+static int loopback_close(struct snd_pcm_substream *substream)
+{
+	struct loopback *loopback = substream->private_data;
+	struct loopback_pcm *dpcm = substream->runtime->private_data;
+	struct loopback_cable *cable;
+	int dev = get_cable_index(substream);
+
+	loopback_timer_stop(dpcm);
+	mutex_lock(&loopback->cable_lock);
+	cable = loopback->cables[substream->number][dev];
+	if (cable->streams[!substream->stream]) {
+		/* other stream is still alive */
+		cable->streams[substream->stream] = NULL;
+	} else {
+		/* free the cable */
+		loopback->cables[substream->number][dev] = NULL;
+		kfree(cable);
+	}
+	mutex_unlock(&loopback->cable_lock);
+	return 0;
+}
+
+static struct snd_pcm_ops loopback_playback_ops = {
+	.open =		loopback_open,
+	.close =	loopback_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	loopback_hw_params,
+	.hw_free =	loopback_hw_free,
+	.prepare =	loopback_prepare,
+	.trigger =	loopback_trigger,
+	.pointer =	loopback_pointer,
+};
+
+static struct snd_pcm_ops loopback_capture_ops = {
+	.open =		loopback_open,
+	.close =	loopback_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	loopback_hw_params,
+	.hw_free =	loopback_hw_free,
+	.prepare =	loopback_prepare,
+	.trigger =	loopback_trigger,
+	.pointer =	loopback_pointer,
+};
+
+static int __devinit loopback_pcm_new(struct loopback *loopback,
+				      int device, int substreams)
+{
+	struct snd_pcm *pcm;
+	int err;
+
+	err = snd_pcm_new(loopback->card, "Loopback PCM", device,
+			  substreams, substreams, &pcm);
+	if (err < 0)
+		return err;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops);
+
+	pcm->private_data = loopback;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "Loopback PCM");
+
+	loopback->pcm[device] = pcm;
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+			snd_dma_continuous_data(GFP_KERNEL),
+			0, 2 * 1024 * 1024);
+	return 0;
+}
+
+static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol,   
+				    struct snd_ctl_elem_info *uinfo) 
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 80000;
+	uinfo->value.integer.max = 120000;
+	uinfo->value.integer.step = 1;
+	return 0;
+}                                  
+
+static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+	
+	ucontrol->value.integer.value[0] =
+		loopback->setup[kcontrol->id.subdevice]
+			       [kcontrol->id.device].rate_shift;
+	return 0;
+}
+
+static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+	int change = 0;
+
+	val = ucontrol->value.integer.value[0];
+	if (val < 80000)
+		val = 80000;
+	if (val > 120000)
+		val = 120000;	
+	mutex_lock(&loopback->cable_lock);
+	if (val != loopback->setup[kcontrol->id.subdevice]
+				  [kcontrol->id.device].rate_shift) {
+		loopback->setup[kcontrol->id.subdevice]
+			       [kcontrol->id.device].rate_shift = val;
+		change = 1;
+	}
+	mutex_unlock(&loopback->cable_lock);
+	return change;
+}
+
+static int loopback_notify_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+	
+	ucontrol->value.integer.value[0] =
+		loopback->setup[kcontrol->id.subdevice]
+			       [kcontrol->id.device].notify;
+	return 0;
+}
+
+static int loopback_notify_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+	int change = 0;
+
+	val = ucontrol->value.integer.value[0] ? 1 : 0;
+	if (val != loopback->setup[kcontrol->id.subdevice]
+				[kcontrol->id.device].notify) {
+		loopback->setup[kcontrol->id.subdevice]
+			[kcontrol->id.device].notify = val;
+		change = 1;
+	}
+	return change;
+}
+
+static int loopback_active_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+	struct loopback_cable *cable = loopback->cables
+			[kcontrol->id.subdevice][kcontrol->id.device ^ 1];
+	unsigned int val = 0;
+
+	if (cable != NULL)
+		val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
+									1 : 0;
+	ucontrol->value.integer.value[0] = val;
+	return 0;
+}
+
+static int loopback_format_info(struct snd_kcontrol *kcontrol,   
+				struct snd_ctl_elem_info *uinfo) 
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST;
+	uinfo->value.integer.step = 1;
+	return 0;
+}                                  
+
+static int loopback_format_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+	
+	ucontrol->value.integer.value[0] =
+		loopback->setup[kcontrol->id.subdevice]
+			       [kcontrol->id.device].format;
+	return 0;
+}
+
+static int loopback_rate_info(struct snd_kcontrol *kcontrol,   
+			      struct snd_ctl_elem_info *uinfo) 
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 192000;
+	uinfo->value.integer.step = 1;
+	return 0;
+}                                  
+
+static int loopback_rate_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+	
+	ucontrol->value.integer.value[0] =
+		loopback->setup[kcontrol->id.subdevice]
+			       [kcontrol->id.device].rate;
+	return 0;
+}
+
+static int loopback_channels_info(struct snd_kcontrol *kcontrol,   
+				  struct snd_ctl_elem_info *uinfo) 
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 1;
+	uinfo->value.integer.max = 1024;
+	uinfo->value.integer.step = 1;
+	return 0;
+}                                  
+
+static int loopback_channels_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+	
+	ucontrol->value.integer.value[0] =
+		loopback->setup[kcontrol->id.subdevice]
+			       [kcontrol->id.device].channels;
+	return 0;
+}
+
+static struct snd_kcontrol_new loopback_controls[]  __devinitdata = {
+{
+	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         "PCM Rate Shift 100000",
+	.info =         loopback_rate_shift_info,
+	.get =          loopback_rate_shift_get,
+	.put =          loopback_rate_shift_put,
+},
+{
+	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         "PCM Notify",
+	.info =         snd_ctl_boolean_mono_info,
+	.get =          loopback_notify_get,
+	.put =          loopback_notify_put,
+},
+#define ACTIVE_IDX 2
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         "PCM Slave Active",
+	.info =         snd_ctl_boolean_mono_info,
+	.get =          loopback_active_get,
+},
+#define FORMAT_IDX 3
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         "PCM Slave Format",
+	.info =         loopback_format_info,
+	.get =          loopback_format_get
+},
+#define RATE_IDX 4
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         "PCM Slave Rate",
+	.info =         loopback_rate_info,
+	.get =          loopback_rate_get
+},
+#define CHANNELS_IDX 5
+{
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         "PCM Slave Channels",
+	.info =         loopback_channels_info,
+	.get =          loopback_channels_get
+}
+};
+
+static int __devinit loopback_mixer_new(struct loopback *loopback, int notify)
+{
+	struct snd_card *card = loopback->card;
+	struct snd_pcm *pcm;
+	struct snd_kcontrol *kctl;
+	struct loopback_setup *setup;
+	int err, dev, substr, substr_count, idx;
+
+	strcpy(card->mixername, "Loopback Mixer");
+	for (dev = 0; dev < 2; dev++) {
+		pcm = loopback->pcm[dev];
+		substr_count =
+		    pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count;
+		for (substr = 0; substr < substr_count; substr++) {
+			setup = &loopback->setup[substr][dev];
+			setup->notify = notify;
+			setup->rate_shift = NO_PITCH;
+			setup->format = SNDRV_PCM_FORMAT_S16_LE;
+			setup->rate = 48000;
+			setup->channels = 2;
+			for (idx = 0; idx < ARRAY_SIZE(loopback_controls);
+									idx++) {
+				kctl = snd_ctl_new1(&loopback_controls[idx],
+						    loopback);
+				if (!kctl)
+					return -ENOMEM;
+				kctl->id.device = dev;
+				kctl->id.subdevice = substr;
+				switch (idx) {
+				case ACTIVE_IDX:
+					setup->active_id = kctl->id;
+					break;
+				case FORMAT_IDX:
+					setup->format_id = kctl->id;
+					break;
+				case RATE_IDX:
+					setup->rate_id = kctl->id;
+					break;
+				case CHANNELS_IDX:
+					setup->channels_id = kctl->id;
+					break;
+				default:
+					break;
+				}
+				err = snd_ctl_add(card, kctl);
+				if (err < 0)
+					return err;
+			}
+		}
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void print_dpcm_info(struct snd_info_buffer *buffer,
+			    struct loopback_pcm *dpcm,
+			    const char *id)
+{
+	snd_iprintf(buffer, "  %s\n", id);
+	if (dpcm == NULL) {
+		snd_iprintf(buffer, "    inactive\n");
+		return;
+	}
+	snd_iprintf(buffer, "    buffer_size:\t%u\n", dpcm->pcm_buffer_size);
+	snd_iprintf(buffer, "    buffer_pos:\t\t%u\n", dpcm->buf_pos);
+	snd_iprintf(buffer, "    silent_size:\t%u\n", dpcm->silent_size);
+	snd_iprintf(buffer, "    period_size:\t%u\n", dpcm->pcm_period_size);
+	snd_iprintf(buffer, "    bytes_per_sec:\t%u\n", dpcm->pcm_bps);
+	snd_iprintf(buffer, "    sample_align:\t%u\n", dpcm->pcm_salign);
+	snd_iprintf(buffer, "    rate_shift:\t\t%u\n", dpcm->pcm_rate_shift);
+	snd_iprintf(buffer, "    update_pending:\t%u\n",
+						dpcm->period_update_pending);
+	snd_iprintf(buffer, "    irq_pos:\t\t%u\n", dpcm->irq_pos);
+	snd_iprintf(buffer, "    period_frac:\t%u\n", dpcm->period_size_frac);
+	snd_iprintf(buffer, "    last_jiffies:\t%lu (%lu)\n",
+					dpcm->last_jiffies, jiffies);
+	snd_iprintf(buffer, "    timer_expires:\t%lu\n", dpcm->timer.expires);
+}
+
+static void print_substream_info(struct snd_info_buffer *buffer,
+				 struct loopback *loopback,
+				 int sub,
+				 int num)
+{
+	struct loopback_cable *cable = loopback->cables[sub][num];
+
+	snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub);
+	if (cable == NULL) {
+		snd_iprintf(buffer, "  inactive\n");
+		return;
+	}
+	snd_iprintf(buffer, "  valid: %u\n", cable->valid);
+	snd_iprintf(buffer, "  running: %u\n", cable->running);
+	snd_iprintf(buffer, "  pause: %u\n", cable->pause);
+	print_dpcm_info(buffer, cable->streams[0], "Playback");
+	print_dpcm_info(buffer, cable->streams[1], "Capture");
+}
+
+static void print_cable_info(struct snd_info_entry *entry,
+			     struct snd_info_buffer *buffer)
+{
+	struct loopback *loopback = entry->private_data;
+	int sub, num;
+
+	mutex_lock(&loopback->cable_lock);
+	num = entry->name[strlen(entry->name)-1];
+	num = num == '0' ? 0 : 1;
+	for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++)
+		print_substream_info(buffer, loopback, sub, num);
+	mutex_unlock(&loopback->cable_lock);
+}
+
+static int __devinit loopback_proc_new(struct loopback *loopback, int cidx)
+{
+	char name[32];
+	struct snd_info_entry *entry;
+	int err;
+
+	snprintf(name, sizeof(name), "cable#%d", cidx);
+	err = snd_card_proc_new(loopback->card, name, &entry);
+	if (err < 0)
+		return err;
+
+	snd_info_set_text_ops(entry, loopback, print_cable_info);
+	return 0;
+}
+
+#else /* !CONFIG_PROC_FS */
+
+#define loopback_proc_new(loopback, cidx) do { } while (0)
+
+#endif
+
+static int __devinit loopback_probe(struct platform_device *devptr)
+{
+	struct snd_card *card;
+	struct loopback *loopback;
+	int dev = devptr->id;
+	int err;
+
+	err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+			      sizeof(struct loopback), &card);
+	if (err < 0)
+		return err;
+	loopback = card->private_data;
+
+	if (pcm_substreams[dev] < 1)
+		pcm_substreams[dev] = 1;
+	if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
+		pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
+	
+	loopback->card = card;
+	mutex_init(&loopback->cable_lock);
+
+	err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]);
+	if (err < 0)
+		goto __nodev;
+	err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]);
+	if (err < 0)
+		goto __nodev;
+	err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0);
+	if (err < 0)
+		goto __nodev;
+	loopback_proc_new(loopback, 0);
+	loopback_proc_new(loopback, 1);
+	strcpy(card->driver, "Loopback");
+	strcpy(card->shortname, "Loopback");
+	sprintf(card->longname, "Loopback %i", dev + 1);
+	err = snd_card_register(card);
+	if (!err) {
+		platform_set_drvdata(devptr, card);
+		return 0;
+	}
+      __nodev:
+	snd_card_free(card);
+	return err;
+}
+
+static int __devexit loopback_remove(struct platform_device *devptr)
+{
+	snd_card_free(platform_get_drvdata(devptr));
+	platform_set_drvdata(devptr, NULL);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int loopback_suspend(struct platform_device *pdev,
+				pm_message_t state)
+{
+	struct snd_card *card = platform_get_drvdata(pdev);
+	struct loopback *loopback = card->private_data;
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+	snd_pcm_suspend_all(loopback->pcm[0]);
+	snd_pcm_suspend_all(loopback->pcm[1]);
+	return 0;
+}
+	
+static int loopback_resume(struct platform_device *pdev)
+{
+	struct snd_card *card = platform_get_drvdata(pdev);
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	return 0;
+}
+#endif
+
+#define SND_LOOPBACK_DRIVER	"snd_aloop"
+
+static struct platform_driver loopback_driver = {
+	.probe		= loopback_probe,
+	.remove		= __devexit_p(loopback_remove),
+#ifdef CONFIG_PM
+	.suspend	= loopback_suspend,
+	.resume		= loopback_resume,
+#endif
+	.driver		= {
+		.name	= SND_LOOPBACK_DRIVER
+	},
+};
+
+static void loopback_unregister_all(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(devices); ++i)
+		platform_device_unregister(devices[i]);
+	platform_driver_unregister(&loopback_driver);
+}
+
+static int __init alsa_card_loopback_init(void)
+{
+	int i, err, cards;
+
+	err = platform_driver_register(&loopback_driver);
+	if (err < 0)
+		return err;
+
+
+	cards = 0;
+	for (i = 0; i < SNDRV_CARDS; i++) {
+		struct platform_device *device;
+		if (!enable[i])
+			continue;
+		device = platform_device_register_simple(SND_LOOPBACK_DRIVER,
+							 i, NULL, 0);
+		if (IS_ERR(device))
+			continue;
+		if (!platform_get_drvdata(device)) {
+			platform_device_unregister(device);
+			continue;
+		}
+		devices[i] = device;
+		cards++;
+	}
+	if (!cards) {
+#ifdef MODULE
+		printk(KERN_ERR "aloop: No loopback enabled\n");
+#endif
+		loopback_unregister_all();
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void __exit alsa_card_loopback_exit(void)
+{
+	loopback_unregister_all();
+}
+
+module_init(alsa_card_loopback_init)
+module_exit(alsa_card_loopback_exit)

+ 1 - 1
sound/drivers/virmidi.c

@@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr)
 			      sizeof(struct snd_card_virmidi), &card);
 			      sizeof(struct snd_card_virmidi), &card);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
-	vmidi = (struct snd_card_virmidi *)card->private_data;
+	vmidi = card->private_data;
 	vmidi->card = card;
 	vmidi->card = card;
 
 
 	if (midi_devs[dev] > MAX_MIDI_DEVICES) {
 	if (midi_devs[dev] > MAX_MIDI_DEVICES) {

+ 1 - 1
sound/i2c/other/ak4xxx-adda.c

@@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
 static void proc_regs_read(struct snd_info_entry *entry,
 static void proc_regs_read(struct snd_info_entry *entry,
 		struct snd_info_buffer *buffer)
 		struct snd_info_buffer *buffer)
 {
 {
-	struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data;
+	struct snd_akm4xxx *ak = entry->private_data;
 	int reg, val, chip;
 	int reg, val, chip;
 	for (chip = 0; chip < ak->num_chips; chip++) {
 	for (chip = 0; chip < ak->num_chips; chip++) {
 		for (reg = 0; reg < ak->total_regs; reg++) {
 		for (reg = 0; reg < ak->total_regs; reg++) {

+ 26 - 10
sound/isa/Kconfig

@@ -77,6 +77,32 @@ config SND_ALS100
 	  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-als100.
 	  will be called snd-als100.
 
 
+config SND_AZT1605
+	tristate "Aztech AZT1605 Driver"
+	depends on SND
+	select SND_WSS_LIB
+	select SND_MPU401_UART
+	select SND_OPL3_LIB
+	help
+	  Say Y here to include support for Aztech Sound Galaxy cards
+	  based on the AZT1605 chipset.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-azt1605.
+
+config SND_AZT2316
+	tristate "Aztech AZT2316 Driver"
+	depends on SND
+	select SND_WSS_LIB
+	select SND_MPU401_UART
+	select SND_OPL3_LIB
+	help
+	  Say Y here to include support for Aztech Sound Galaxy cards
+	  based on the AZT2316 chipset.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-azt2316.
+
 config SND_AZT2320
 config SND_AZT2320
 	tristate "Aztech Systems AZT2320"
 	tristate "Aztech Systems AZT2320"
 	depends on PNP
 	depends on PNP
@@ -351,16 +377,6 @@ config SND_SB16_CSP
 	  coprocessor can do variable tasks like various compression and
 	  coprocessor can do variable tasks like various compression and
 	  decompression algorithms.
 	  decompression algorithms.
 
 
-config SND_SGALAXY
-	tristate "Aztech Sound Galaxy"
-	select SND_WSS_LIB
-	help
-	  Say Y here to include support for Aztech Sound Galaxy
-	  soundcards.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-sgalaxy.
-
 config SND_SSCAPE
 config SND_SSCAPE
 	tristate "Ensoniq SoundScape driver"
 	tristate "Ensoniq SoundScape driver"
 	select SND_MPU401_UART
 	select SND_MPU401_UART

+ 1 - 3
sound/isa/Makefile

@@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o
 snd-es18xx-objs := es18xx.o
 snd-es18xx-objs := es18xx.o
 snd-opl3sa2-objs := opl3sa2.o
 snd-opl3sa2-objs := opl3sa2.o
 snd-sc6000-objs := sc6000.o
 snd-sc6000-objs := sc6000.o
-snd-sgalaxy-objs := sgalaxy.o
 snd-sscape-objs := sscape.o
 snd-sscape-objs := sscape.o
 
 
 # Toplevel Module Dependency
 # Toplevel Module Dependency
@@ -21,8 +20,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
 obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
 obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
 obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
 obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
-obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
 obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
 obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
 
 
-obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \
+obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \
 		     sb/ wavefront/ wss/
 		     sb/ wavefront/ wss/

+ 1 - 1
sound/isa/ad1816a/ad1816a.c

@@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
 				sizeof(struct snd_card_ad1816a), &card);
 				sizeof(struct snd_card_ad1816a), &card);
 	if (error < 0)
 	if (error < 0)
 		return error;
 		return error;
-	acard = (struct snd_card_ad1816a *)card->private_data;
+	acard = card->private_data;
 
 
 	if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
 	if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
 		snd_card_free(card);
 		snd_card_free(card);

+ 1 - 1
sound/isa/azt2320.c

@@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev,
 				sizeof(struct snd_card_azt2320), &card);
 				sizeof(struct snd_card_azt2320), &card);
 	if (error < 0)
 	if (error < 0)
 		return error;
 		return error;
-	acard = (struct snd_card_azt2320 *)card->private_data;
+	acard = card->private_data;
 
 
 	if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
 	if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
 		snd_card_free(card);
 		snd_card_free(card);

+ 10 - 0
sound/isa/galaxy/Makefile

@@ -0,0 +1,10 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-azt1605-objs := azt1605.o
+snd-azt2316-objs := azt2316.o
+
+obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o
+obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o

+ 91 - 0
sound/isa/galaxy/azt1605.c

@@ -0,0 +1,91 @@
+/*
+ * Aztech AZT1605 Driver
+ * Copyright (C) 2007,2010  Rene Herman
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT1605
+
+#define CRD_NAME "Aztech AZT1605"
+#define DRV_NAME "AZT1605"
+#define DEV_NAME "azt1605"
+
+#define GALAXY_DSP_MAJOR		2
+#define GALAXY_DSP_MINOR		1
+
+#define GALAXY_CONFIG_SIZE		3
+
+/*
+ * 24-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220		(0 << 0)
+#define GALAXY_CONFIG_SBA_240		(1 << 0)
+#define GALAXY_CONFIG_SBA_260		(2 << 0)
+#define GALAXY_CONFIG_SBA_280		(3 << 0)
+#define GALAXY_CONFIG_SBA_MASK		GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_MPUA_300		(0 << 2)
+#define GALAXY_CONFIG_MPUA_330		(1 << 2)
+
+#define GALAXY_CONFIG_MPU_ENABLE	(1 << 3)
+
+#define GALAXY_CONFIG_GAME_ENABLE	(1 << 4)
+
+#define GALAXY_CONFIG_CD_PANASONIC	(1 << 5)
+#define GALAXY_CONFIG_CD_MITSUMI	(1 << 6)
+#define GALAXY_CONFIG_CD_MASK		(\
+	GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI)
+
+#define GALAXY_CONFIG_UNUSED		(1 << 7)
+#define GALAXY_CONFIG_UNUSED_MASK	GALAXY_CONFIG_UNUSED
+
+#define GALAXY_CONFIG_SBIRQ_2		(1 << 8)
+#define GALAXY_CONFIG_SBIRQ_3		(1 << 9)
+#define GALAXY_CONFIG_SBIRQ_5		(1 << 10)
+#define GALAXY_CONFIG_SBIRQ_7		(1 << 11)
+
+#define GALAXY_CONFIG_MPUIRQ_2		(1 << 12)
+#define GALAXY_CONFIG_MPUIRQ_3		(1 << 13)
+#define GALAXY_CONFIG_MPUIRQ_5		(1 << 14)
+#define GALAXY_CONFIG_MPUIRQ_7		(1 << 15)
+
+#define GALAXY_CONFIG_WSSA_530		(0 << 16)
+#define GALAXY_CONFIG_WSSA_604		(1 << 16)
+#define GALAXY_CONFIG_WSSA_E80		(2 << 16)
+#define GALAXY_CONFIG_WSSA_F40		(3 << 16)
+
+#define GALAXY_CONFIG_WSS_ENABLE	(1 << 18)
+
+#define GALAXY_CONFIG_CDIRQ_11		(1 << 19)
+#define GALAXY_CONFIG_CDIRQ_12		(1 << 20)
+#define GALAXY_CONFIG_CDIRQ_15		(1 << 21)
+#define GALAXY_CONFIG_CDIRQ_MASK	(\
+	GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\
+	GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_CDDMA_DISABLE	(0 << 22)
+#define GALAXY_CONFIG_CDDMA_0		(1 << 22)
+#define GALAXY_CONFIG_CDDMA_1		(2 << 22)
+#define GALAXY_CONFIG_CDDMA_3		(3 << 22)
+#define GALAXY_CONFIG_CDDMA_MASK	GALAXY_CONFIG_CDDMA_3
+
+#define GALAXY_CONFIG_MASK		(\
+	GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\
+	GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\
+	GALAXY_CONFIG_CDDMA_MASK)
+
+#include "galaxy.c"

+ 111 - 0
sound/isa/galaxy/azt2316.c

@@ -0,0 +1,111 @@
+/*
+ * Aztech AZT2316 Driver
+ * Copyright (C) 2007,2010  Rene Herman
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT2316
+
+#define CRD_NAME "Aztech AZT2316"
+#define DRV_NAME "AZT2316"
+#define DEV_NAME "azt2316"
+
+#define GALAXY_DSP_MAJOR		3
+#define GALAXY_DSP_MINOR		1
+
+#define GALAXY_CONFIG_SIZE		4
+
+/*
+ * 32-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220		(0 << 0)
+#define GALAXY_CONFIG_SBA_240		(1 << 0)
+#define GALAXY_CONFIG_SBA_260		(2 << 0)
+#define GALAXY_CONFIG_SBA_280		(3 << 0)
+#define GALAXY_CONFIG_SBA_MASK		GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_SBIRQ_2		(1 << 2)
+#define GALAXY_CONFIG_SBIRQ_5		(1 << 3)
+#define GALAXY_CONFIG_SBIRQ_7		(1 << 4)
+#define GALAXY_CONFIG_SBIRQ_10		(1 << 5)
+
+#define GALAXY_CONFIG_SBDMA_DISABLE	(0 << 6)
+#define GALAXY_CONFIG_SBDMA_0		(1 << 6)
+#define GALAXY_CONFIG_SBDMA_1		(2 << 6)
+#define GALAXY_CONFIG_SBDMA_3		(3 << 6)
+
+#define GALAXY_CONFIG_WSSA_530		(0 << 8)
+#define GALAXY_CONFIG_WSSA_604		(1 << 8)
+#define GALAXY_CONFIG_WSSA_E80		(2 << 8)
+#define GALAXY_CONFIG_WSSA_F40		(3 << 8)
+
+#define GALAXY_CONFIG_WSS_ENABLE	(1 << 10)
+
+#define GALAXY_CONFIG_GAME_ENABLE	(1 << 11)
+
+#define GALAXY_CONFIG_MPUA_300		(0 << 12)
+#define GALAXY_CONFIG_MPUA_330		(1 << 12)
+
+#define GALAXY_CONFIG_MPU_ENABLE	(1 << 13)
+
+#define GALAXY_CONFIG_CDA_310		(0 << 14)
+#define GALAXY_CONFIG_CDA_320		(1 << 14)
+#define GALAXY_CONFIG_CDA_340		(2 << 14)
+#define GALAXY_CONFIG_CDA_350		(3 << 14)
+#define GALAXY_CONFIG_CDA_MASK		GALAXY_CONFIG_CDA_350
+
+#define GALAXY_CONFIG_CD_DISABLE	(0 << 16)
+#define GALAXY_CONFIG_CD_PANASONIC	(1 << 16)
+#define GALAXY_CONFIG_CD_SONY		(2 << 16)
+#define GALAXY_CONFIG_CD_MITSUMI	(3 << 16)
+#define GALAXY_CONFIG_CD_AZTECH		(4 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_5	(5 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_6	(6 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_7	(7 << 16)
+#define GALAXY_CONFIG_CD_MASK		GALAXY_CONFIG_CD_UNUSED_7
+
+#define GALAXY_CONFIG_CDDMA8_DISABLE	(0 << 20)
+#define GALAXY_CONFIG_CDDMA8_0		(1 << 20)
+#define GALAXY_CONFIG_CDDMA8_1		(2 << 20)
+#define GALAXY_CONFIG_CDDMA8_3		(3 << 20)
+#define GALAXY_CONFIG_CDDMA8_MASK	GALAXY_CONFIG_CDDMA8_3
+
+#define GALAXY_CONFIG_CDDMA16_DISABLE	(0 << 22)
+#define GALAXY_CONFIG_CDDMA16_5		(1 << 22)
+#define GALAXY_CONFIG_CDDMA16_6		(2 << 22)
+#define GALAXY_CONFIG_CDDMA16_7		(3 << 22)
+#define GALAXY_CONFIG_CDDMA16_MASK	GALAXY_CONFIG_CDDMA16_7
+
+#define GALAXY_CONFIG_MPUIRQ_2		(1 << 24)
+#define GALAXY_CONFIG_MPUIRQ_5		(1 << 25)
+#define GALAXY_CONFIG_MPUIRQ_7		(1 << 26)
+#define GALAXY_CONFIG_MPUIRQ_10		(1 << 27)
+
+#define GALAXY_CONFIG_CDIRQ_5		(1 << 28)
+#define GALAXY_CONFIG_CDIRQ_11		(1 << 29)
+#define GALAXY_CONFIG_CDIRQ_12		(1 << 30)
+#define GALAXY_CONFIG_CDIRQ_15		(1 << 31)
+#define GALAXY_CONFIG_CDIRQ_MASK	(\
+	GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\
+	GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_MASK		(\
+	GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\
+	GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\
+	GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK)
+
+#include "galaxy.c"

+ 652 - 0
sound/isa/galaxy/galaxy.c

@@ -0,0 +1,652 @@
+/*
+ * Aztech AZT1605/AZT2316 Driver
+ * Copyright (C) 2007,2010  Rene Herman
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/isa.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <asm/processor.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/wss.h>
+#include <sound/mpu401.h>
+#include <sound/opl3.h>
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+module_param_array(wss_port, long, NULL, 0444);
+MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
+module_param_array(mpu_port, long, NULL, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
+module_param_array(fm_port, long, NULL, 0444);
+MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
+module_param_array(mpu_irq, int, NULL, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
+module_param_array(dma1, int, NULL, 0444);
+MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
+
+/*
+ * Generic SB DSP support routines
+ */
+
+#define DSP_PORT_RESET		0x6
+#define DSP_PORT_READ		0xa
+#define DSP_PORT_COMMAND	0xc
+#define DSP_PORT_STATUS		0xc
+#define DSP_PORT_DATA_AVAIL	0xe
+
+#define DSP_SIGNATURE		0xaa
+
+#define DSP_COMMAND_GET_VERSION	0xe1
+
+static int __devinit dsp_get_byte(void __iomem *port, u8 *val)
+{
+	int loops = 1000;
+
+	while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
+		if (!loops--)
+			return -EIO;
+		cpu_relax();
+	}
+	*val = ioread8(port + DSP_PORT_READ);
+	return 0;
+}
+
+static int __devinit dsp_reset(void __iomem *port)
+{
+	u8 val;
+
+	iowrite8(1, port + DSP_PORT_RESET);
+	udelay(10);
+	iowrite8(0, port + DSP_PORT_RESET);
+
+	if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int __devinit dsp_command(void __iomem *port, u8 cmd)
+{
+	int loops = 1000;
+
+	while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
+		if (!loops--)
+			return -EIO;
+		cpu_relax();
+	}
+	iowrite8(cmd, port + DSP_PORT_COMMAND);
+	return 0;
+}
+
+static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
+{
+	int err;
+
+	err = dsp_command(port, DSP_COMMAND_GET_VERSION);
+	if (err < 0)
+		return err;
+
+	err = dsp_get_byte(port, major);
+	if (err < 0)
+		return err;
+
+	err = dsp_get_byte(port, minor);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/*
+ * Generic WSS support routines
+ */
+
+#define WSS_CONFIG_DMA_0	(1 << 0)
+#define WSS_CONFIG_DMA_1	(2 << 0)
+#define WSS_CONFIG_DMA_3	(3 << 0)
+#define WSS_CONFIG_DUPLEX	(1 << 2)
+#define WSS_CONFIG_IRQ_7	(1 << 3)
+#define WSS_CONFIG_IRQ_9	(2 << 3)
+#define WSS_CONFIG_IRQ_10	(3 << 3)
+#define WSS_CONFIG_IRQ_11	(4 << 3)
+
+#define WSS_PORT_CONFIG		0
+#define WSS_PORT_SIGNATURE	3
+
+#define WSS_SIGNATURE		4
+
+static int __devinit wss_detect(void __iomem *wss_port)
+{
+	if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
+		return -ENODEV;
+
+	return 0;
+}
+
+static void wss_set_config(void __iomem *wss_port, u8 wss_config)
+{
+	iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
+}
+
+/*
+ * Aztech Sound Galaxy specifics
+ */
+
+#define GALAXY_PORT_CONFIG	1024
+#define CONFIG_PORT_SET		4
+
+#define DSP_COMMAND_GALAXY_8	8
+#define GALAXY_COMMAND_GET_TYPE	5
+
+#define DSP_COMMAND_GALAXY_9	9
+#define GALAXY_COMMAND_WSSMODE	0
+#define GALAXY_COMMAND_SB8MODE	1
+
+#define GALAXY_MODE_WSS		GALAXY_COMMAND_WSSMODE
+#define GALAXY_MODE_SB8		GALAXY_COMMAND_SB8MODE
+
+struct snd_galaxy {
+	void __iomem *port;
+	void __iomem *config_port;
+	void __iomem *wss_port;
+	u32 config;
+	struct resource *res_port;
+	struct resource *res_config_port;
+	struct resource *res_wss_port;
+};
+
+static u32 config[SNDRV_CARDS];
+static u8 wss_config[SNDRV_CARDS];
+
+static int __devinit snd_galaxy_match(struct device *dev, unsigned int n)
+{
+	if (!enable[n])
+		return 0;
+
+	switch (port[n]) {
+	case SNDRV_AUTO_PORT:
+		dev_err(dev, "please specify port\n");
+		return 0;
+	case 0x220:
+		config[n] |= GALAXY_CONFIG_SBA_220;
+		break;
+	case 0x240:
+		config[n] |= GALAXY_CONFIG_SBA_240;
+		break;
+	case 0x260:
+		config[n] |= GALAXY_CONFIG_SBA_260;
+		break;
+	case 0x280:
+		config[n] |= GALAXY_CONFIG_SBA_280;
+		break;
+	default:
+		dev_err(dev, "invalid port %#lx\n", port[n]);
+		return 0;
+	}
+
+	switch (wss_port[n]) {
+	case SNDRV_AUTO_PORT:
+		dev_err(dev,  "please specify wss_port\n");
+		return 0;
+	case 0x530:
+		config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
+		break;
+	case 0x604:
+		config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
+		break;
+	case 0xe80:
+		config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
+		break;
+	case 0xf40:
+		config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
+		break;
+	default:
+		dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
+		return 0;
+	}
+
+	switch (irq[n]) {
+	case SNDRV_AUTO_IRQ:
+		dev_err(dev,  "please specify irq\n");
+		return 0;
+	case 7:
+		wss_config[n] |= WSS_CONFIG_IRQ_7;
+		break;
+	case 2:
+		irq[n] = 9;
+	case 9:
+		wss_config[n] |= WSS_CONFIG_IRQ_9;
+		break;
+	case 10:
+		wss_config[n] |= WSS_CONFIG_IRQ_10;
+		break;
+	case 11:
+		wss_config[n] |= WSS_CONFIG_IRQ_11;
+		break;
+	default:
+		dev_err(dev, "invalid IRQ %d\n", irq[n]);
+		return 0;
+	}
+
+	switch (dma1[n]) {
+	case SNDRV_AUTO_DMA:
+		dev_err(dev,  "please specify dma1\n");
+		return 0;
+	case 0:
+		wss_config[n] |= WSS_CONFIG_DMA_0;
+		break;
+	case 1:
+		wss_config[n] |= WSS_CONFIG_DMA_1;
+		break;
+	case 3:
+		wss_config[n] |= WSS_CONFIG_DMA_3;
+		break;
+	default:
+		dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
+		return 0;
+	}
+
+	if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
+		dma2[n] = -1;
+		goto mpu;
+	}
+
+	wss_config[n] |= WSS_CONFIG_DUPLEX;
+	switch (dma2[n]) {
+	case 0:
+		break;
+	case 1:
+		if (dma1[n] == 0)
+			break;
+	default:
+		dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
+		return 0;
+	}
+
+mpu:
+	switch (mpu_port[n]) {
+	case SNDRV_AUTO_PORT:
+		dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
+		mpu_port[n] = -1;
+		goto fm;
+	case 0x300:
+		config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
+		break;
+	case 0x330:
+		config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
+		break;
+	default:
+		dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
+		return 0;
+	}
+
+	switch (mpu_irq[n]) {
+	case SNDRV_AUTO_IRQ:
+		dev_warn(dev, "mpu_irq not specified: using polling mode\n");
+		mpu_irq[n] = -1;
+		break;
+	case 2:
+		mpu_irq[n] = 9;
+	case 9:
+		config[n] |= GALAXY_CONFIG_MPUIRQ_2;
+		break;
+#ifdef AZT1605
+	case 3:
+		config[n] |= GALAXY_CONFIG_MPUIRQ_3;
+		break;
+#endif
+	case 5:
+		config[n] |= GALAXY_CONFIG_MPUIRQ_5;
+		break;
+	case 7:
+		config[n] |= GALAXY_CONFIG_MPUIRQ_7;
+		break;
+#ifdef AZT2316
+	case 10:
+		config[n] |= GALAXY_CONFIG_MPUIRQ_10;
+		break;
+#endif
+	default:
+		dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
+		return 0;
+	}
+
+	if (mpu_irq[n] == irq[n]) {
+		dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
+		return 0;
+	}
+
+fm:
+	switch (fm_port[n]) {
+	case SNDRV_AUTO_PORT:
+		dev_warn(dev, "fm_port not specified: not using OPL3\n");
+		fm_port[n] = -1;
+		break;
+	case 0x388:
+		break;
+	default:
+		dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
+		return 0;
+	}
+
+	config[n] |= GALAXY_CONFIG_GAME_ENABLE;
+	return 1;
+}
+
+static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type)
+{
+	u8 major;
+	u8 minor;
+	int err;
+
+	err = dsp_reset(galaxy->port);
+	if (err < 0)
+		return err;
+
+	err = dsp_get_version(galaxy->port, &major, &minor);
+	if (err < 0)
+		return err;
+
+	if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
+		return -ENODEV;
+
+	err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
+	if (err < 0)
+		return err;
+
+	err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
+	if (err < 0)
+		return err;
+
+	err = dsp_get_byte(galaxy->port, type);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
+{
+	int err;
+
+	err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
+	if (err < 0)
+		return err;
+
+	err = dsp_command(galaxy->port, mode);
+	if (err < 0)
+		return err;
+
+#ifdef AZT1605
+	/*
+	 * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
+	 */
+	err = dsp_reset(galaxy->port);
+	if (err < 0)
+		return err;
+#endif
+
+	return 0;
+}
+
+static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
+{
+	u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
+	int i;
+
+	iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
+	for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
+		iowrite8(config, galaxy->config_port + i);
+		config >>= 8;
+	}
+	iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
+	msleep(10);
+}
+
+static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config)
+{
+	int i;
+
+	for (i = GALAXY_CONFIG_SIZE; i; i--) {
+		u8 tmp = ioread8(galaxy->config_port + i - 1);
+		galaxy->config = (galaxy->config << 8) | tmp;
+	}
+	config |= galaxy->config & GALAXY_CONFIG_MASK;
+	galaxy_set_config(galaxy, config);
+}
+
+static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
+{
+	int err;
+
+	err = wss_detect(galaxy->wss_port);
+	if (err < 0)
+		return err;
+
+	wss_set_config(galaxy->wss_port, wss_config);
+
+	err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static void snd_galaxy_free(struct snd_card *card)
+{
+	struct snd_galaxy *galaxy = card->private_data;
+
+	if (galaxy->wss_port) {
+		wss_set_config(galaxy->wss_port, 0);
+		ioport_unmap(galaxy->wss_port);
+		release_and_free_resource(galaxy->res_wss_port);
+	}
+	if (galaxy->config_port) {
+		galaxy_set_config(galaxy, galaxy->config);
+		ioport_unmap(galaxy->config_port);
+		release_and_free_resource(galaxy->res_config_port);
+	}
+	if (galaxy->port) {
+		ioport_unmap(galaxy->port);
+		release_and_free_resource(galaxy->res_port);
+	}
+}
+
+static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n)
+{
+	struct snd_galaxy *galaxy;
+	struct snd_wss *chip;
+	struct snd_card *card;
+	u8 type;
+	int err;
+
+	err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy,
+			      &card);
+	if (err < 0)
+		return err;
+
+	snd_card_set_dev(card, dev);
+
+	card->private_free = snd_galaxy_free;
+	galaxy = card->private_data;
+
+	galaxy->res_port = request_region(port[n], 16, DRV_NAME);
+	if (!galaxy->res_port) {
+		dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
+			port[n] + 15);
+		err = -EBUSY;
+		goto error;
+	}
+	galaxy->port = ioport_map(port[n], 16);
+
+	err = galaxy_init(galaxy, &type);
+	if (err < 0) {
+		dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
+		goto error;
+	}
+	dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
+
+	galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG,
+						 16, DRV_NAME);
+	if (!galaxy->res_config_port) {
+		dev_err(dev, "could not grab ports %#lx-%#lx\n",
+			port[n] + GALAXY_PORT_CONFIG,
+			port[n] + GALAXY_PORT_CONFIG + 15);
+		err = -EBUSY;
+		goto error;
+	}
+	galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16);
+
+	galaxy_config(galaxy, config[n]);
+
+	galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME);
+	if (!galaxy->res_wss_port)  {
+		dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
+			wss_port[n] + 3);
+		err = -EBUSY;
+		goto error;
+	}
+	galaxy->wss_port = ioport_map(wss_port[n], 4);
+
+	err = galaxy_wss_config(galaxy, wss_config[n]);
+	if (err < 0) {
+		dev_err(dev, "could not configure WSS\n");
+		goto error;
+	}
+
+	strcpy(card->driver, DRV_NAME);
+	strcpy(card->shortname, DRV_NAME);
+	sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
+		card->shortname, port[n], wss_port[n], irq[n], dma1[n],
+		dma2[n]);
+
+	err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
+			     dma2[n], WSS_HW_DETECT, 0, &chip);
+	if (err < 0)
+		goto error;
+
+	err = snd_wss_pcm(chip, 0, NULL);
+	if (err < 0)
+		goto error;
+
+	err = snd_wss_mixer(chip);
+	if (err < 0)
+		goto error;
+
+	err = snd_wss_timer(chip, 0, NULL);
+	if (err < 0)
+		goto error;
+
+	if (mpu_port[n] >= 0) {
+		err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+					  mpu_port[n], 0, mpu_irq[n],
+					  IRQF_DISABLED, NULL);
+		if (err < 0)
+			goto error;
+	}
+
+	if (fm_port[n] >= 0) {
+		struct snd_opl3 *opl3;
+
+		err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
+				      OPL3_HW_AUTO, 0, &opl3);
+		if (err < 0) {
+			dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
+			goto error;
+		}
+		err = snd_opl3_timer_new(opl3, 1, 2);
+		if (err < 0)
+			goto error;
+
+		err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+		if (err < 0)
+			goto error;
+	}
+
+	err = snd_card_register(card);
+	if (err < 0)
+		goto error;
+
+	dev_set_drvdata(dev, card);
+	return 0;
+
+error:
+	snd_card_free(card);
+	return err;
+}
+
+static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n)
+{
+	snd_card_free(dev_get_drvdata(dev));
+	dev_set_drvdata(dev, NULL);
+	return 0;
+}
+
+static struct isa_driver snd_galaxy_driver = {
+	.match		= snd_galaxy_match,
+	.probe		= snd_galaxy_probe,
+	.remove		= __devexit_p(snd_galaxy_remove),
+
+	.driver		= {
+		.name	= DEV_NAME
+	}
+};
+
+static int __init alsa_card_galaxy_init(void)
+{
+	return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS);
+}
+
+static void __exit alsa_card_galaxy_exit(void)
+{
+	isa_unregister_driver(&snd_galaxy_driver);
+}
+
+module_init(alsa_card_galaxy_init);
+module_exit(alsa_card_galaxy_exit);

+ 2 - 2
sound/isa/gus/gusmax.c

@@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip)
 
 
 static void snd_gusmax_free(struct snd_card *card)
 static void snd_gusmax_free(struct snd_card *card)
 {
 {
-	struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data;
+	struct snd_gusmax *maxcard = card->private_data;
 	
 	
 	if (maxcard == NULL)
 	if (maxcard == NULL)
 		return;
 		return;
@@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 	card->private_free = snd_gusmax_free;
 	card->private_free = snd_gusmax_free;
-	maxcard = (struct snd_gusmax *)card->private_data;
+	maxcard = card->private_data;
 	maxcard->card = card;
 	maxcard->card = card;
 	maxcard->irq = -1;
 	maxcard->irq = -1;
 	
 	

+ 1 - 1
sound/isa/sb/sb8.c

@@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
 
 
 static void snd_sb8_free(struct snd_card *card)
 static void snd_sb8_free(struct snd_card *card)
 {
 {
-	struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data;
+	struct snd_sb8 *acard = card->private_data;
 
 
 	if (acard == NULL)
 	if (acard == NULL)
 		return;
 		return;

+ 0 - 369
sound/isa/sgalaxy.c

@@ -1,369 +0,0 @@
-/*
- *  Driver for Aztech Sound Galaxy cards
- *  Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk.
- *
- *  I don't have documentation for this card, I based this driver on the
- *  driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.c)
- *
- *   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/init.h>
-#include <linux/err.h>
-#include <linux/isa.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <asm/dma.h>
-#include <sound/core.h>
-#include <sound/sb.h>
-#include <sound/wss.h>
-#include <sound/control.h>
-#define SNDRV_LEGACY_FIND_FREE_IRQ
-#define SNDRV_LEGACY_FIND_FREE_DMA
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>");
-MODULE_DESCRIPTION("Aztech Sound Galaxy");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
-static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240 */
-static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x530,0xe80,0xf40,0x604 */
-static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 7,9,10,11 */
-static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3 */
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard.");
-module_param_array(sbport, long, NULL, 0444);
-MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver.");
-module_param_array(wssport, long, NULL, 0444);
-MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver.");
-module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver.");
-
-#define SGALAXY_AUXC_LEFT 18
-#define SGALAXY_AUXC_RIGHT 19
-
-#define PFX	"sgalaxy: "
-
-/*
-
- */
-
-#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x )
-
-/* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */
-/* short time we actually need it.. */
-
-static int snd_sgalaxy_sbdsp_reset(unsigned long port)
-{
-	int i;
-
-	outb(1, SBP1(port, RESET));
-	udelay(10);
-	outb(0, SBP1(port, RESET));
-	udelay(30);
-	for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++);
-	if (inb(SBP1(port, READ)) != 0xaa) {
-		snd_printd("sb_reset: failed at 0x%lx!!!\n", port);
-		return -ENODEV;
-	}
-	return 0;
-}
-
-static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port,
-					       unsigned char val)
-{
-	int i;
-       	
-	for (i = 10000; i; i--)
-		if ((inb(SBP1(port, STATUS)) & 0x80) == 0) {
-			outb(val, SBP1(port, COMMAND));
-			return 1;
-		}
-
-	return 0;
-}
-
-static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id)
-{
-	return IRQ_NONE;
-}
-
-static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
-{
-	static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 
-				       0x10, 0x18, 0x20, -1, -1, -1, -1};
-	static int dma_bits[] = {1, 2, 0, 3};
-	int tmp, tmp1;
-
-	if ((tmp = inb(port + 3)) == 0xff)
-	{
-		snd_printdd("I/O address dead (0x%lx)\n", port);
-		return 0;
-	}
-#if 0
-	snd_printdd("WSS signature = 0x%x\n", tmp);
-#endif
-
-        if ((tmp & 0x3f) != 0x04 &&
-            (tmp & 0x3f) != 0x0f &&
-            (tmp & 0x3f) != 0x00) {
-		snd_printdd("No WSS signature detected on port 0x%lx\n",
-			    port + 3);
-		return 0;
-	}
-
-#if 0
-	snd_printdd(PFX "setting up IRQ/DMA for WSS\n");
-#endif
-
-        /* initialize IRQ for WSS codec */
-        tmp = interrupt_bits[irq % 16];
-        if (tmp < 0)
-                return -EINVAL;
-
-	if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) {
-		snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq);
-		return -EIO;
-	}
-
-        outb(tmp | 0x40, port);
-        tmp1 = dma_bits[dma % 4];
-        outb(tmp | tmp1, port);
-
-	free_irq(irq, NULL);
-
-	return 0;
-}
-
-static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma)
-{
-#if 0
-	snd_printdd(PFX "switching to WSS mode\n");
-#endif
-
-	/* switch to WSS mode */
-	snd_sgalaxy_sbdsp_reset(sbport[dev]);
-
-	snd_sgalaxy_sbdsp_command(sbport[dev], 9);
-	snd_sgalaxy_sbdsp_command(sbport[dev], 0);
-
-	udelay(400);
-	return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
-}
-
-static struct snd_kcontrol_new snd_sgalaxy_controls[] = {
-WSS_DOUBLE("Aux Playback Switch", 0,
-		SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Playback Volume", 0,
-		SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
-};
-
-static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip)
-{
-	struct snd_card *card = chip->card;
-	struct snd_ctl_elem_id id1, id2;
-	unsigned int idx;
-	int err;
-
-	memset(&id1, 0, sizeof(id1));
-	memset(&id2, 0, sizeof(id2));
-	id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-	/* reassign AUX0 to LINE */
-	strcpy(id1.name, "Aux Playback Switch");
-	strcpy(id2.name, "Line Playback Switch");
-	if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-		return err;
-	strcpy(id1.name, "Aux Playback Volume");
-	strcpy(id2.name, "Line Playback Volume");
-	if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-		return err;
-	/* reassign AUX1 to FM */
-	strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
-	strcpy(id2.name, "FM Playback Switch");
-	if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-		return err;
-	strcpy(id1.name, "Aux Playback Volume");
-	strcpy(id2.name, "FM Playback Volume");
-	if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-		return err;
-	/* build AUX2 input */
-	for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
-		err = snd_ctl_add(card,
-				snd_ctl_new1(&snd_sgalaxy_controls[idx], chip));
-		if (err < 0)
-			return err;
-	}
-	return 0;
-}
-
-static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev)
-{
-	if (!enable[dev])
-		return 0;
-	if (sbport[dev] == SNDRV_AUTO_PORT) {
-		snd_printk(KERN_ERR PFX "specify SB port\n");
-		return 0;
-	}
-	if (wssport[dev] == SNDRV_AUTO_PORT) {
-		snd_printk(KERN_ERR PFX "specify WSS port\n");
-		return 0;
-	}
-	return 1;
-}
-
-static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
-{
-	static int possible_irqs[] = {7, 9, 10, 11, -1};
-	static int possible_dmas[] = {1, 3, 0, -1};
-	int err, xirq, xdma1;
-	struct snd_card *card;
-	struct snd_wss *chip;
-
-	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
-	if (err < 0)
-		return err;
-
-	xirq = irq[dev];
-	if (xirq == SNDRV_AUTO_IRQ) {
-		if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
-			snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
-			err = -EBUSY;
-			goto _err;
-		}
-	}
-	xdma1 = dma1[dev];
-        if (xdma1 == SNDRV_AUTO_DMA) {
-		if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
-			snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
-			err = -EBUSY;
-			goto _err;
-		}
-	}
-
-	if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
-		goto _err;
-
-	err = snd_wss_create(card, wssport[dev] + 4, -1,
-			     xirq, xdma1, -1,
-			     WSS_HW_DETECT, 0, &chip);
-	if (err < 0)
-		goto _err;
-	card->private_data = chip;
-
-	err = snd_wss_pcm(chip, 0, NULL);
-	if (err < 0) {
-		snd_printdd(PFX "error creating new WSS PCM device\n");
-		goto _err;
-	}
-	err = snd_wss_mixer(chip);
-	if (err < 0) {
-		snd_printdd(PFX "error creating new WSS mixer\n");
-		goto _err;
-	}
-	if ((err = snd_sgalaxy_mixer(chip)) < 0) {
-		snd_printdd(PFX "the mixer rewrite failed\n");
-		goto _err;
-	}
-
-	strcpy(card->driver, "Sound Galaxy");
-	strcpy(card->shortname, "Sound Galaxy");
-	sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
-		wssport[dev], xirq, xdma1);
-
-	snd_card_set_dev(card, devptr);
-
-	if ((err = snd_card_register(card)) < 0)
-		goto _err;
-
-	dev_set_drvdata(devptr, card);
-	return 0;
-
- _err:
-	snd_card_free(card);
-	return err;
-}
-
-static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev)
-{
-	snd_card_free(dev_get_drvdata(devptr));
-	dev_set_drvdata(devptr, NULL);
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n,
-			       pm_message_t state)
-{
-	struct snd_card *card = dev_get_drvdata(pdev);
-	struct snd_wss *chip = card->private_data;
-
-	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-	chip->suspend(chip);
-	return 0;
-}
-
-static int snd_sgalaxy_resume(struct device *pdev, unsigned int n)
-{
-	struct snd_card *card = dev_get_drvdata(pdev);
-	struct snd_wss *chip = card->private_data;
-
-	chip->resume(chip);
-	snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
-	snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
-
-	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-	return 0;
-}
-#endif
-
-#define DEV_NAME "sgalaxy"
-
-static struct isa_driver snd_sgalaxy_driver = {
-	.match		= snd_sgalaxy_match,
-	.probe		= snd_sgalaxy_probe,
-	.remove		= __devexit_p(snd_sgalaxy_remove),
-#ifdef CONFIG_PM
-	.suspend	= snd_sgalaxy_suspend,
-	.resume		= snd_sgalaxy_resume,
-#endif
-	.driver		= {
-		.name	= DEV_NAME
-	},
-};
-
-static int __init alsa_card_sgalaxy_init(void)
-{
-	return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS);
-}
-
-static void __exit alsa_card_sgalaxy_exit(void)
-{
-	isa_unregister_driver(&snd_sgalaxy_driver);
-}
-
-module_init(alsa_card_sgalaxy_init)
-module_exit(alsa_card_sgalaxy_exit)

+ 0 - 8
sound/oss/Kconfig

@@ -545,11 +545,3 @@ config SOUND_KAHLUA
 
 
 endif	# SOUND_OSS
 endif	# SOUND_OSS
 
 
-config SOUND_SH_DAC_AUDIO
-	tristate "SuperH DAC audio support"
-	depends on CPU_SH3 && HIGH_RES_TIMERS
-
-config SOUND_SH_DAC_AUDIO_CHANNEL
-	int "DAC channel"
-	default "1"
-	depends on SOUND_SH_DAC_AUDIO

+ 0 - 1
sound/oss/Makefile

@@ -9,7 +9,6 @@ obj-$(CONFIG_SOUND_OSS)		+= sound.o
 
 
 # Please leave it as is, cause the link order is significant !
 # Please leave it as is, cause the link order is significant !
 
 
-obj-$(CONFIG_SOUND_SH_DAC_AUDIO)	+= sh_dac_audio.o
 obj-$(CONFIG_SOUND_AEDSP16)	+= aedsp16.o
 obj-$(CONFIG_SOUND_AEDSP16)	+= aedsp16.o
 obj-$(CONFIG_SOUND_PSS)		+= pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_PSS)		+= pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)	+= trix.o ad1848.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_TRIX)	+= trix.o ad1848.o sb_lib.o uart401.o

+ 24 - 24
sound/oss/au1550_ac97.c

@@ -43,7 +43,6 @@
 #include <linux/sound.h>
 #include <linux/sound.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/soundcard.h>
 #include <linux/soundcard.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -77,6 +76,7 @@
 /* Boot options
 /* Boot options
  * 0 = no VRA, 1 = use VRA if codec supports it
  * 0 = no VRA, 1 = use VRA if codec supports it
  */
  */
+static DEFINE_MUTEX(au1550_ac97_mutex);
 static int      vra = 1;
 static int      vra = 1;
 module_param(vra, bool, 0);
 module_param(vra, bool, 0);
 MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
 MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
@@ -171,7 +171,7 @@ au1550_delay(int msec)
 static u16
 static u16
 rdcodec(struct ac97_codec *codec, u8 addr)
 rdcodec(struct ac97_codec *codec, u8 addr)
 {
 {
-	struct au1550_state *s = (struct au1550_state *)codec->private_data;
+	struct au1550_state *s = codec->private_data;
 	unsigned long   flags;
 	unsigned long   flags;
 	u32             cmd, val;
 	u32             cmd, val;
 	u16             data;
 	u16             data;
@@ -239,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr)
 static void
 static void
 wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
 wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
 {
 {
-	struct au1550_state *s = (struct au1550_state *)codec->private_data;
+	struct au1550_state *s = codec->private_data;
 	unsigned long   flags;
 	unsigned long   flags;
 	u32             cmd, val;
 	u32             cmd, val;
 	int             i;
 	int             i;
@@ -798,9 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin)
 static int
 static int
 au1550_open_mixdev(struct inode *inode, struct file *file)
 au1550_open_mixdev(struct inode *inode, struct file *file)
 {
 {
-	lock_kernel();
+	mutex_lock(&au1550_ac97_mutex);
 	file->private_data = &au1550_state;
 	file->private_data = &au1550_state;
-	unlock_kernel();
+	mutex_unlock(&au1550_ac97_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -820,13 +820,13 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
 static long
 static long
 au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
 au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
 {
 {
-	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct au1550_state *s = file->private_data;
 	struct ac97_codec *codec = s->codec;
 	struct ac97_codec *codec = s->codec;
 	int ret;
 	int ret;
 
 
-	lock_kernel();
+	mutex_lock(&au1550_ac97_mutex);
 	ret = mixdev_ioctl(codec, cmd, arg);
 	ret = mixdev_ioctl(codec, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&au1550_ac97_mutex);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -1031,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
 static ssize_t
 static ssize_t
 au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 {
-	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct au1550_state *s = file->private_data;
 	struct dmabuf  *db = &s->dma_adc;
 	struct dmabuf  *db = &s->dma_adc;
 	DECLARE_WAITQUEUE(wait, current);
 	DECLARE_WAITQUEUE(wait, current);
 	ssize_t         ret;
 	ssize_t         ret;
@@ -1111,7 +1111,7 @@ au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 static ssize_t
 static ssize_t
 au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
 au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
 {
 {
-	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct au1550_state *s = file->private_data;
 	struct dmabuf  *db = &s->dma_dac;
 	struct dmabuf  *db = &s->dma_dac;
 	DECLARE_WAITQUEUE(wait, current);
 	DECLARE_WAITQUEUE(wait, current);
 	ssize_t         ret = 0;
 	ssize_t         ret = 0;
@@ -1211,7 +1211,7 @@ au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
 static unsigned int
 static unsigned int
 au1550_poll(struct file *file, struct poll_table_struct *wait)
 au1550_poll(struct file *file, struct poll_table_struct *wait)
 {
 {
-	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct au1550_state *s = file->private_data;
 	unsigned long   flags;
 	unsigned long   flags;
 	unsigned int    mask = 0;
 	unsigned int    mask = 0;
 
 
@@ -1250,12 +1250,12 @@ au1550_poll(struct file *file, struct poll_table_struct *wait)
 static int
 static int
 au1550_mmap(struct file *file, struct vm_area_struct *vma)
 au1550_mmap(struct file *file, struct vm_area_struct *vma)
 {
 {
-	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct au1550_state *s = file->private_data;
 	struct dmabuf  *db;
 	struct dmabuf  *db;
 	unsigned long   size;
 	unsigned long   size;
 	int ret = 0;
 	int ret = 0;
 
 
-	lock_kernel();
+	mutex_lock(&au1550_ac97_mutex);
 	mutex_lock(&s->sem);
 	mutex_lock(&s->sem);
 	if (vma->vm_flags & VM_WRITE)
 	if (vma->vm_flags & VM_WRITE)
 		db = &s->dma_dac;
 		db = &s->dma_dac;
@@ -1283,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma)
 	db->mapped = 1;
 	db->mapped = 1;
 out:
 out:
 	mutex_unlock(&s->sem);
 	mutex_unlock(&s->sem);
-	unlock_kernel();
+	mutex_unlock(&au1550_ac97_mutex);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -1342,7 +1342,7 @@ dma_count_done(struct dmabuf *db)
 static int
 static int
 au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 {
-	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct au1550_state *s = file->private_data;
 	unsigned long   flags;
 	unsigned long   flags;
 	audio_buf_info  abinfo;
 	audio_buf_info  abinfo;
 	count_info      cinfo;
 	count_info      cinfo;
@@ -1781,9 +1781,9 @@ au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 {
 	int ret;
 	int ret;
 
 
-	lock_kernel();
+	mutex_lock(&au1550_ac97_mutex);
 	ret = au1550_ioctl(file, cmd, arg);
 	ret = au1550_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&au1550_ac97_mutex);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -1804,7 +1804,7 @@ au1550_open(struct inode *inode, struct file *file)
 #endif
 #endif
 
 
 	file->private_data = s;
 	file->private_data = s;
-	lock_kernel();
+	mutex_lock(&au1550_ac97_mutex);
 	/* wait for device to become free */
 	/* wait for device to become free */
 	mutex_lock(&s->open_mutex);
 	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 	while (s->open_mode & file->f_mode) {
@@ -1861,21 +1861,21 @@ au1550_open(struct inode *inode, struct file *file)
 out:
 out:
 	mutex_unlock(&s->open_mutex);
 	mutex_unlock(&s->open_mutex);
 out2:
 out2:
-	unlock_kernel();
+	mutex_unlock(&au1550_ac97_mutex);
 	return ret;
 	return ret;
 }
 }
 
 
 static int
 static int
 au1550_release(struct inode *inode, struct file *file)
 au1550_release(struct inode *inode, struct file *file)
 {
 {
-	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct au1550_state *s = file->private_data;
 
 
-	lock_kernel();
+	mutex_lock(&au1550_ac97_mutex);
 
 
 	if (file->f_mode & FMODE_WRITE) {
 	if (file->f_mode & FMODE_WRITE) {
-		unlock_kernel();
+		mutex_unlock(&au1550_ac97_mutex);
 		drain_dac(s, file->f_flags & O_NONBLOCK);
 		drain_dac(s, file->f_flags & O_NONBLOCK);
-		lock_kernel();
+		mutex_lock(&au1550_ac97_mutex);
 	}
 	}
 
 
 	mutex_lock(&s->open_mutex);
 	mutex_lock(&s->open_mutex);
@@ -1892,7 +1892,7 @@ au1550_release(struct inode *inode, struct file *file)
 	s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
 	s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
 	mutex_unlock(&s->open_mutex);
 	mutex_unlock(&s->open_mutex);
 	wake_up(&s->open_wait);
 	wake_up(&s->open_wait);
-	unlock_kernel();
+	mutex_unlock(&au1550_ac97_mutex);
 	return 0;
 	return 0;
 }
 }
 
 

+ 21 - 20
sound/oss/dmasound/dmasound_core.c

@@ -181,7 +181,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/soundcard.h>
 #include <linux/soundcard.h>
 #include <linux/poll.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 
 
@@ -194,6 +194,7 @@
      *  Declarations
      *  Declarations
      */
      */
 
 
+static DEFINE_MUTEX(dmasound_core_mutex);
 int dmasound_catchRadius = 0;
 int dmasound_catchRadius = 0;
 module_param(dmasound_catchRadius, int, 0);
 module_param(dmasound_catchRadius, int, 0);
 
 
@@ -323,22 +324,22 @@ static struct {
 
 
 static int mixer_open(struct inode *inode, struct file *file)
 static int mixer_open(struct inode *inode, struct file *file)
 {
 {
-	lock_kernel();
+	mutex_lock(&dmasound_core_mutex);
 	if (!try_module_get(dmasound.mach.owner)) {
 	if (!try_module_get(dmasound.mach.owner)) {
-		unlock_kernel();
+		mutex_unlock(&dmasound_core_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 	mixer.busy = 1;
 	mixer.busy = 1;
-	unlock_kernel();
+	mutex_unlock(&dmasound_core_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
 static int mixer_release(struct inode *inode, struct file *file)
 static int mixer_release(struct inode *inode, struct file *file)
 {
 {
-	lock_kernel();
+	mutex_lock(&dmasound_core_mutex);
 	mixer.busy = 0;
 	mixer.busy = 0;
 	module_put(dmasound.mach.owner);
 	module_put(dmasound.mach.owner);
-	unlock_kernel();
+	mutex_unlock(&dmasound_core_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -370,9 +371,9 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
 {
 {
 	int ret;
 	int ret;
 
 
-	lock_kernel();
+	mutex_lock(&dmasound_core_mutex);
 	ret = mixer_ioctl(file, cmd, arg);
 	ret = mixer_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&dmasound_core_mutex);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -752,9 +753,9 @@ static int sq_open(struct inode *inode, struct file *file)
 {
 {
 	int rc;
 	int rc;
 
 
-	lock_kernel();
+	mutex_lock(&dmasound_core_mutex);
 	if (!try_module_get(dmasound.mach.owner)) {
 	if (!try_module_get(dmasound.mach.owner)) {
-		unlock_kernel();
+		mutex_unlock(&dmasound_core_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -799,11 +800,11 @@ static int sq_open(struct inode *inode, struct file *file)
 		sound_set_format(AFMT_MU_LAW);
 		sound_set_format(AFMT_MU_LAW);
 	}
 	}
 #endif
 #endif
-	unlock_kernel();
+	mutex_unlock(&dmasound_core_mutex);
 	return 0;
 	return 0;
  out:
  out:
 	module_put(dmasound.mach.owner);
 	module_put(dmasound.mach.owner);
-	unlock_kernel();
+	mutex_unlock(&dmasound_core_mutex);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -869,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file)
 {
 {
 	int rc = 0;
 	int rc = 0;
 
 
-	lock_kernel();
+	mutex_lock(&dmasound_core_mutex);
 
 
 	if (file->f_mode & FMODE_WRITE) {
 	if (file->f_mode & FMODE_WRITE) {
 		if (write_sq.busy)
 		if (write_sq.busy)
@@ -900,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file)
 	write_sq_wake_up(file); /* checks f_mode */
 	write_sq_wake_up(file); /* checks f_mode */
 #endif /* blocking open() */
 #endif /* blocking open() */
 
 
-	unlock_kernel();
+	mutex_unlock(&dmasound_core_mutex);
 
 
 	return rc;
 	return rc;
 }
 }
@@ -1141,9 +1142,9 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
 {
 {
 	int ret;
 	int ret;
 
 
-	lock_kernel();
+	mutex_lock(&dmasound_core_mutex);
 	ret = sq_ioctl(file, cmd, arg);
 	ret = sq_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&dmasound_core_mutex);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -1257,7 +1258,7 @@ static int state_open(struct inode *inode, struct file *file)
 	int len = 0;
 	int len = 0;
 	int ret;
 	int ret;
 
 
-	lock_kernel();
+	mutex_lock(&dmasound_core_mutex);
 	ret = -EBUSY;
 	ret = -EBUSY;
 	if (state.busy)
 	if (state.busy)
 		goto out;
 		goto out;
@@ -1329,16 +1330,16 @@ printk("dmasound: stat buffer used %d bytes\n", len) ;
 	state.len = len;
 	state.len = len;
 	ret = 0;
 	ret = 0;
 out:
 out:
-	unlock_kernel();
+	mutex_unlock(&dmasound_core_mutex);
 	return ret;
 	return ret;
 }
 }
 
 
 static int state_release(struct inode *inode, struct file *file)
 static int state_release(struct inode *inode, struct file *file)
 {
 {
-	lock_kernel();
+	mutex_lock(&dmasound_core_mutex);
 	state.busy = 0;
 	state.busy = 0;
 	module_put(dmasound.mach.owner);
 	module_put(dmasound.mach.owner);
-	unlock_kernel();
+	mutex_unlock(&dmasound_core_mutex);
 	return 0;
 	return 0;
 }
 }
 
 

+ 8 - 7
sound/oss/msnd_pinnacle.c

@@ -39,7 +39,7 @@
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/gfp.h>
 #include <linux/gfp.h>
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/io.h>
@@ -79,6 +79,7 @@
 					 dev.rec_sample_rate /		\
 					 dev.rec_sample_rate /		\
 					 dev.rec_channels)
 					 dev.rec_channels)
 
 
+static DEFINE_MUTEX(msnd_pinnacle_mutex);
 static multisound_dev_t			dev;
 static multisound_dev_t			dev;
 
 
 #ifndef HAVE_DSPCODEH
 #ifndef HAVE_DSPCODEH
@@ -651,12 +652,12 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 
 	ret = -EINVAL;
 	ret = -EINVAL;
 
 
-	lock_kernel();
+	mutex_lock(&msnd_pinnacle_mutex);
 	if (minor == dev.dsp_minor)
 	if (minor == dev.dsp_minor)
 		ret = dsp_ioctl(file, cmd, arg);
 		ret = dsp_ioctl(file, cmd, arg);
 	else if (minor == dev.mixer_minor)
 	else if (minor == dev.mixer_minor)
 		ret = mixer_ioctl(cmd, arg);
 		ret = mixer_ioctl(cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&msnd_pinnacle_mutex);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -761,7 +762,7 @@ static int dev_open(struct inode *inode, struct file *file)
 	int minor = iminor(inode);
 	int minor = iminor(inode);
 	int err = 0;
 	int err = 0;
 
 
-	lock_kernel();
+	mutex_lock(&msnd_pinnacle_mutex);
 	if (minor == dev.dsp_minor) {
 	if (minor == dev.dsp_minor) {
 		if ((file->f_mode & FMODE_WRITE &&
 		if ((file->f_mode & FMODE_WRITE &&
 		     test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
 		     test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
@@ -791,7 +792,7 @@ static int dev_open(struct inode *inode, struct file *file)
 	} else
 	} else
 		err = -EINVAL;
 		err = -EINVAL;
 out:
 out:
-	unlock_kernel();
+	mutex_unlock(&msnd_pinnacle_mutex);
 	return err;
 	return err;
 }
 }
 
 
@@ -800,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file)
 	int minor = iminor(inode);
 	int minor = iminor(inode);
 	int err = 0;
 	int err = 0;
 
 
-	lock_kernel();
+	mutex_lock(&msnd_pinnacle_mutex);
 	if (minor == dev.dsp_minor)
 	if (minor == dev.dsp_minor)
 		err = dsp_release(file);
 		err = dsp_release(file);
 	else if (minor == dev.mixer_minor) {
 	else if (minor == dev.mixer_minor) {
 		/* nothing */
 		/* nothing */
 	} else
 	} else
 		err = -EINVAL;
 		err = -EINVAL;
-	unlock_kernel();
+	mutex_unlock(&msnd_pinnacle_mutex);
 	return err;
 	return err;
 }
 }
 
 

+ 0 - 325
sound/oss/sh_dac_audio.c

@@ -1,325 +0,0 @@
-/*
- * sound/oss/sh_dac_audio.c
- *
- * SH DAC based sound :(
- *
- *  Copyright (C) 2004,2005  Andriy Skulysh
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/linkage.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/sound.h>
-#include <linux/smp_lock.h>
-#include <linux/soundcard.h>
-#include <linux/interrupt.h>
-#include <linux/hrtimer.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/clock.h>
-#include <cpu/dac.h>
-#include <asm/machvec.h>
-#include <mach/hp6xx.h>
-#include <asm/hd64461.h>
-
-#define MODNAME "sh_dac_audio"
-
-#define BUFFER_SIZE 48000
-
-static int rate;
-static int empty;
-static char *data_buffer, *buffer_begin, *buffer_end;
-static int in_use, device_major;
-static struct hrtimer hrtimer;
-static ktime_t wakeups_per_second;
-
-static void dac_audio_start_timer(void)
-{
-	hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
-}
-
-static void dac_audio_stop_timer(void)
-{
-	hrtimer_cancel(&hrtimer);
-}
-
-static void dac_audio_reset(void)
-{
-	dac_audio_stop_timer();
-	buffer_begin = buffer_end = data_buffer;
-	empty = 1;
-}
-
-static void dac_audio_sync(void)
-{
-	while (!empty)
-		schedule();
-}
-
-static void dac_audio_start(void)
-{
-	if (mach_is_hp6xx()) {
-		u16 v = __raw_readw(HD64461_GPADR);
-		v &= ~HD64461_GPADR_SPEAKER;
-		__raw_writew(v, HD64461_GPADR);
-	}
-
-	sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-static void dac_audio_stop(void)
-{
-	dac_audio_stop_timer();
-
-	if (mach_is_hp6xx()) {
-		u16 v = __raw_readw(HD64461_GPADR);
-		v |= HD64461_GPADR_SPEAKER;
-		__raw_writew(v, HD64461_GPADR);
-	}
-
-	sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-	sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-
-static void dac_audio_set_rate(void)
-{
-	wakeups_per_second = ktime_set(0, 1000000000 / rate);
-}
-
-static int dac_audio_ioctl(struct file *file,
-			   unsigned int cmd, unsigned long arg)
-{
-	int val;
-
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, (int *)arg);
-
-	case SNDCTL_DSP_SYNC:
-		dac_audio_sync();
-		return 0;
-
-	case SNDCTL_DSP_RESET:
-		dac_audio_reset();
-		return 0;
-
-	case SNDCTL_DSP_GETFMTS:
-		return put_user(AFMT_U8, (int *)arg);
-
-	case SNDCTL_DSP_SETFMT:
-		return put_user(AFMT_U8, (int *)arg);
-
-	case SNDCTL_DSP_NONBLOCK:
-		spin_lock(&file->f_lock);
-		file->f_flags |= O_NONBLOCK;
-		spin_unlock(&file->f_lock);
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return 0;
-
-	case SOUND_PCM_WRITE_RATE:
-		val = *(int *)arg;
-		if (val > 0) {
-			rate = val;
-			dac_audio_set_rate();
-		}
-		return put_user(rate, (int *)arg);
-
-	case SNDCTL_DSP_STEREO:
-		return put_user(0, (int *)arg);
-
-	case SOUND_PCM_WRITE_CHANNELS:
-		return put_user(1, (int *)arg);
-
-	case SNDCTL_DSP_SETDUPLEX:
-		return -EINVAL;
-
-	case SNDCTL_DSP_PROFILE:
-		return -EINVAL;
-
-	case SNDCTL_DSP_GETBLKSIZE:
-		return put_user(BUFFER_SIZE, (int *)arg);
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		return 0;
-
-	default:
-		printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n",
-		       cmd);
-		return -EINVAL;
-	}
-	return -EINVAL;
-}
-
-static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
-{
-	int ret;
-
-	lock_kernel();
-	ret = dac_audio_ioctl(file, cmd, arg);
-	unlock_kernel();
-
-	return ret;
-}
-
-static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
-			       loff_t * ppos)
-{
-	int free;
-	int nbytes;
-
-	if (!count) {
-		dac_audio_sync();
-		return 0;
-	}
-
-	free = buffer_begin - buffer_end;
-
-	if (free < 0)
-		free += BUFFER_SIZE;
-	if ((free == 0) && (empty))
-		free = BUFFER_SIZE;
-	if (count > free)
-		count = free;
-	if (buffer_begin > buffer_end) {
-		if (copy_from_user((void *)buffer_end, buf, count))
-			return -EFAULT;
-
-		buffer_end += count;
-	} else {
-		nbytes = data_buffer + BUFFER_SIZE - buffer_end;
-		if (nbytes > count) {
-			if (copy_from_user((void *)buffer_end, buf, count))
-				return -EFAULT;
-			buffer_end += count;
-		} else {
-			if (copy_from_user((void *)buffer_end, buf, nbytes))
-				return -EFAULT;
-			if (copy_from_user
-			    ((void *)data_buffer, buf + nbytes, count - nbytes))
-				return -EFAULT;
-			buffer_end = data_buffer + count - nbytes;
-		}
-	}
-
-	if (empty) {
-		empty = 0;
-		dac_audio_start_timer();
-	}
-
-	return count;
-}
-
-static ssize_t dac_audio_read(struct file *file, char *buf, size_t count,
-			      loff_t * ppos)
-{
-	return -EINVAL;
-}
-
-static int dac_audio_open(struct inode *inode, struct file *file)
-{
-	if (file->f_mode & FMODE_READ)
-		return -ENODEV;
-
-	lock_kernel();
-	if (in_use) {
-		unlock_kernel();
-		return -EBUSY;
-	}
-
-	in_use = 1;
-
-	dac_audio_start();
-	unlock_kernel();
-	return 0;
-}
-
-static int dac_audio_release(struct inode *inode, struct file *file)
-{
-	dac_audio_sync();
-	dac_audio_stop();
-	in_use = 0;
-
-	return 0;
-}
-
-const struct file_operations dac_audio_fops = {
-      .read =		dac_audio_read,
-      .write =		dac_audio_write,
-      .unlocked_ioctl =	dac_audio_unlocked_ioctl,
-      .open =		dac_audio_open,
-      .release =	dac_audio_release,
-};
-
-static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
-{
-	if (!empty) {
-		sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-		buffer_begin++;
-
-		if (buffer_begin == data_buffer + BUFFER_SIZE)
-			buffer_begin = data_buffer;
-		if (buffer_begin == buffer_end)
-			empty = 1;
-	}
-
-	if (!empty)
-		hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
-
-	return HRTIMER_NORESTART;
-}
-
-static int __init dac_audio_init(void)
-{
-	if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) {
-		printk(KERN_ERR "Cannot register dsp device");
-		return device_major;
-	}
-
-	in_use = 0;
-
-	data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-	if (data_buffer == NULL)
-		return -ENOMEM;
-
-	dac_audio_reset();
-	rate = 8000;
-	dac_audio_set_rate();
-
-	/* Today: High Resolution Timer driven DAC playback.
-	 * The timer callback gets called once per sample. Ouch.
-	 *
-	 * Future: A much better approach would be to use the
-	 * SH7720 CMT+DMAC+DAC hardware combination like this:
-	 * - Program sample rate using CMT0 or CMT1
-	 * - Program DMAC to use CMT for timing and output to DAC
-	 * - Play sound using DMAC, let CPU sleep.
-	 * - While at it, rewrite this driver to use ALSA.
-	 */
-
-	hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	hrtimer.function = sh_dac_audio_timer;
-
-	return 0;
-}
-
-static void __exit dac_audio_exit(void)
-{
-	unregister_sound_dsp(device_major);
-	kfree((void *)data_buffer);
-}
-
-module_init(dac_audio_init);
-module_exit(dac_audio_exit);
-
-MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
-MODULE_DESCRIPTION("SH DAC sound driver");
-MODULE_LICENSE("GPL");

+ 22 - 21
sound/oss/soundcard.c

@@ -40,7 +40,7 @@
 #include <linux/major.h>
 #include <linux/major.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/device.h>
 #include <linux/device.h>
@@ -56,6 +56,7 @@
  * Table for permanently allocated memory (used when unloading the module)
  * Table for permanently allocated memory (used when unloading the module)
  */
  */
 void *          sound_mem_blocks[MAX_MEM_BLOCKS];
 void *          sound_mem_blocks[MAX_MEM_BLOCKS];
+static DEFINE_MUTEX(soundcard_mutex);
 int             sound_nblocks = 0;
 int             sound_nblocks = 0;
 
 
 /* Persistent DMA buffers */
 /* Persistent DMA buffers */
@@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
 	 *	big one anyway, we might as well bandage here..
 	 *	big one anyway, we might as well bandage here..
 	 */
 	 */
 	 
 	 
-	lock_kernel();
+	mutex_lock(&soundcard_mutex);
 	
 	
 	DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
 	DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
 	switch (dev & 0x0f) {
 	switch (dev & 0x0f) {
@@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
 	case SND_DEV_MIDIN:
 	case SND_DEV_MIDIN:
 		ret = MIDIbuf_read(dev, file, buf, count);
 		ret = MIDIbuf_read(dev, file, buf, count);
 	}
 	}
-	unlock_kernel();
+	mutex_unlock(&soundcard_mutex);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
 	int dev = iminor(file->f_path.dentry->d_inode);
 	int dev = iminor(file->f_path.dentry->d_inode);
 	int ret = -EINVAL;
 	int ret = -EINVAL;
 	
 	
-	lock_kernel();
+	mutex_lock(&soundcard_mutex);
 	DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
 	DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
 	switch (dev & 0x0f) {
 	switch (dev & 0x0f) {
 	case SND_DEV_SEQ:
 	case SND_DEV_SEQ:
@@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
 		ret =  MIDIbuf_write(dev, file, buf, count);
 		ret =  MIDIbuf_write(dev, file, buf, count);
 		break;
 		break;
 	}
 	}
-	unlock_kernel();
+	mutex_unlock(&soundcard_mutex);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -210,7 +211,7 @@ static int sound_open(struct inode *inode, struct file *file)
 		printk(KERN_ERR "Invalid minor device %d\n", dev);
 		printk(KERN_ERR "Invalid minor device %d\n", dev);
 		return -ENXIO;
 		return -ENXIO;
 	}
 	}
-	lock_kernel();
+	mutex_lock(&soundcard_mutex);
 	switch (dev & 0x0f) {
 	switch (dev & 0x0f) {
 	case SND_DEV_CTL:
 	case SND_DEV_CTL:
 		dev >>= 4;
 		dev >>= 4;
@@ -247,15 +248,15 @@ static int sound_open(struct inode *inode, struct file *file)
 		retval = -ENXIO;
 		retval = -ENXIO;
 	}
 	}
 
 
-	unlock_kernel();
-	return 0;
+	mutex_unlock(&soundcard_mutex);
+	return retval;
 }
 }
 
 
 static int sound_release(struct inode *inode, struct file *file)
 static int sound_release(struct inode *inode, struct file *file)
 {
 {
 	int dev = iminor(inode);
 	int dev = iminor(inode);
 
 
-	lock_kernel();
+	mutex_lock(&soundcard_mutex);
 	DEB(printk("sound_release(dev=%d)\n", dev));
 	DEB(printk("sound_release(dev=%d)\n", dev));
 	switch (dev & 0x0f) {
 	switch (dev & 0x0f) {
 	case SND_DEV_CTL:
 	case SND_DEV_CTL:
@@ -280,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file)
 	default:
 	default:
 		printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
 		printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
 	}
 	}
-	unlock_kernel();
+	mutex_unlock(&soundcard_mutex);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -354,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	if (cmd == OSS_GETVERSION)
 	if (cmd == OSS_GETVERSION)
 		return __put_user(SOUND_VERSION, (int __user *)p);
 		return __put_user(SOUND_VERSION, (int __user *)p);
 	
 	
-	lock_kernel();
+	mutex_lock(&soundcard_mutex);
 	if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 &&   /* Mixer ioctl */
 	if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 &&   /* Mixer ioctl */
 	    (dev & 0x0f) != SND_DEV_CTL) {              
 	    (dev & 0x0f) != SND_DEV_CTL) {              
 		dtype = dev & 0x0f;
 		dtype = dev & 0x0f;
@@ -369,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 			ret = sound_mixer_ioctl(dev >> 4, cmd, p);
 			ret = sound_mixer_ioctl(dev >> 4, cmd, p);
 			break;
 			break;
 		}
 		}
-		unlock_kernel();
+		mutex_unlock(&soundcard_mutex);
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -399,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		break;
 		break;
 
 
 	}
 	}
-	unlock_kernel();
+	mutex_unlock(&soundcard_mutex);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -439,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
 		printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
 		printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
-	lock_kernel();
+	mutex_lock(&soundcard_mutex);
 	if (vma->vm_flags & VM_WRITE)	/* Map write and read/write to the output buf */
 	if (vma->vm_flags & VM_WRITE)	/* Map write and read/write to the output buf */
 		dmap = audio_devs[dev]->dmap_out;
 		dmap = audio_devs[dev]->dmap_out;
 	else if (vma->vm_flags & VM_READ)
 	else if (vma->vm_flags & VM_READ)
 		dmap = audio_devs[dev]->dmap_in;
 		dmap = audio_devs[dev]->dmap_in;
 	else {
 	else {
 		printk(KERN_ERR "Sound: Undefined mmap() access\n");
 		printk(KERN_ERR "Sound: Undefined mmap() access\n");
-		unlock_kernel();
+		mutex_unlock(&soundcard_mutex);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	if (dmap == NULL) {
 	if (dmap == NULL) {
 		printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
 		printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
-		unlock_kernel();
+		mutex_unlock(&soundcard_mutex);
 		return -EIO;
 		return -EIO;
 	}
 	}
 	if (dmap->raw_buf == NULL) {
 	if (dmap->raw_buf == NULL) {
 		printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
 		printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
-		unlock_kernel();
+		mutex_unlock(&soundcard_mutex);
 		return -EIO;
 		return -EIO;
 	}
 	}
 	if (dmap->mapping_flags) {
 	if (dmap->mapping_flags) {
 		printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
 		printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
-		unlock_kernel();
+		mutex_unlock(&soundcard_mutex);
 		return -EIO;
 		return -EIO;
 	}
 	}
 	if (vma->vm_pgoff != 0) {
 	if (vma->vm_pgoff != 0) {
 		printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
 		printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
-		unlock_kernel();
+		mutex_unlock(&soundcard_mutex);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	size = vma->vm_end - vma->vm_start;
 	size = vma->vm_end - vma->vm_start;
@@ -478,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
 	if (remap_pfn_range(vma, vma->vm_start,
 	if (remap_pfn_range(vma, vma->vm_start,
 			virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT,
 			virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT,
 			vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
 			vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
-		unlock_kernel();
+		mutex_unlock(&soundcard_mutex);
 		return -EAGAIN;
 		return -EAGAIN;
 	}
 	}
 
 
@@ -490,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
 	memset(dmap->raw_buf,
 	memset(dmap->raw_buf,
 	       dmap->neutral_byte,
 	       dmap->neutral_byte,
 	       dmap->bytes_in_use);
 	       dmap->bytes_in_use);
-	unlock_kernel();
+	mutex_unlock(&soundcard_mutex);
 	return 0;
 	return 0;
 }
 }
 
 

+ 10 - 10
sound/oss/swarm_cs4297a.c

@@ -68,7 +68,6 @@
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/sound.h>
 #include <linux/sound.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/soundcard.h>
 #include <linux/soundcard.h>
 #include <linux/ac97_codec.h>
 #include <linux/ac97_codec.h>
 #include <linux/pci.h>
 #include <linux/pci.h>
@@ -94,6 +93,7 @@
 
 
 struct cs4297a_state;
 struct cs4297a_state;
 
 
+static DEFINE_MUTEX(swarm_cs4297a_mutex);
 static void stop_dac(struct cs4297a_state *s);
 static void stop_dac(struct cs4297a_state *s);
 static void stop_adc(struct cs4297a_state *s);
 static void stop_adc(struct cs4297a_state *s);
 static void start_dac(struct cs4297a_state *s);
 static void start_dac(struct cs4297a_state *s);
@@ -1535,7 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
 	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
 	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
 		  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
 		  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
 
 
-	lock_kernel();
+	mutex_lock(&swarm_cs4297a_mutex);
 	list_for_each(entry, &cs4297a_devs)
 	list_for_each(entry, &cs4297a_devs)
 	{
 	{
 		s = list_entry(entry, struct cs4297a_state, list);
 		s = list_entry(entry, struct cs4297a_state, list);
@@ -1547,7 +1547,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
 		CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
 		CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
 			printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
 			printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
 
 
-		unlock_kernel();
+		mutex_unlock(&swarm_cs4297a_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 	VALIDATE_STATE(s);
 	VALIDATE_STATE(s);
@@ -1555,7 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
 
 
 	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
 	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
 		  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
 		  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
-	unlock_kernel();
+	mutex_unlock(&swarm_cs4297a_mutex);
 
 
 	return nonseekable_open(inode, file);
 	return nonseekable_open(inode, file);
 }
 }
@@ -1575,10 +1575,10 @@ static int cs4297a_ioctl_mixdev(struct file *file,
 			       unsigned int cmd, unsigned long arg)
 			       unsigned int cmd, unsigned long arg)
 {
 {
 	int ret;
 	int ret;
-	lock_kernel();
+	mutex_lock(&swarm_cs4297a_mutex);
 	ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
 	ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
 			   arg);
 			   arg);
-	unlock_kernel();
+	mutex_unlock(&swarm_cs4297a_mutex);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -2350,9 +2350,9 @@ static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
 {
 {
 	int ret;
 	int ret;
 
 
-	lock_kernel();
+	mutex_lock(&swarm_cs4297a_mutex);
 	ret = cs4297a_ioctl(file, cmd, arg);
 	ret = cs4297a_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&swarm_cs4297a_mutex);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -2509,9 +2509,9 @@ static int cs4297a_open(struct inode *inode, struct file *file)
 {
 {
 	int ret;
 	int ret;
 
 
-	lock_kernel();
+	mutex_lock(&swarm_cs4297a_mutex);
 	ret = cs4297a_open(inode, file);
 	ret = cs4297a_open(inode, file);
-	unlock_kernel();
+	mutex_unlock(&swarm_cs4297a_mutex);
 
 
 	return ret;
 	return ret;
 }
 }

+ 15 - 15
sound/oss/vwsnd.c

@@ -145,7 +145,6 @@
 #include <linux/init.h>
 #include <linux/init.h>
 
 
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
@@ -160,6 +159,7 @@
 
 
 #ifdef VWSND_DEBUG
 #ifdef VWSND_DEBUG
 
 
+static DEFINE_MUTEX(vwsnd_mutex);
 static int shut_up = 1;
 static int shut_up = 1;
 
 
 /*
 /*
@@ -2891,11 +2891,11 @@ static long vwsnd_audio_ioctl(struct file *file,
 	vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
 	vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
 	int ret;
 	int ret;
 
 
-	lock_kernel();
+	mutex_lock(&vwsnd_mutex);
 	mutex_lock(&devc->io_mutex);
 	mutex_lock(&devc->io_mutex);
 	ret = vwsnd_audio_do_ioctl(file, cmd, arg);
 	ret = vwsnd_audio_do_ioctl(file, cmd, arg);
 	mutex_unlock(&devc->io_mutex);
 	mutex_unlock(&devc->io_mutex);
-	unlock_kernel();
+	mutex_unlock(&vwsnd_mutex);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -2922,7 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
 
 	DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
 	DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
 
 
-	lock_kernel();
+	mutex_lock(&vwsnd_mutex);
 	INC_USE_COUNT;
 	INC_USE_COUNT;
 	for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
 	for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
 		if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
 		if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
@@ -2930,7 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
 
 	if (devc == NULL) {
 	if (devc == NULL) {
 		DEC_USE_COUNT;
 		DEC_USE_COUNT;
-		unlock_kernel();
+		mutex_unlock(&vwsnd_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -2939,13 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 		mutex_unlock(&devc->open_mutex);
 		mutex_unlock(&devc->open_mutex);
 		if (file->f_flags & O_NONBLOCK) {
 		if (file->f_flags & O_NONBLOCK) {
 			DEC_USE_COUNT;
 			DEC_USE_COUNT;
-			unlock_kernel();
+			mutex_unlock(&vwsnd_mutex);
 			return -EBUSY;
 			return -EBUSY;
 		}
 		}
 		interruptible_sleep_on(&devc->open_wait);
 		interruptible_sleep_on(&devc->open_wait);
 		if (signal_pending(current)) {
 		if (signal_pending(current)) {
 			DEC_USE_COUNT;
 			DEC_USE_COUNT;
-			unlock_kernel();
+			mutex_unlock(&vwsnd_mutex);
 			return -ERESTARTSYS;
 			return -ERESTARTSYS;
 		}
 		}
 		mutex_lock(&devc->open_mutex);
 		mutex_lock(&devc->open_mutex);
@@ -2998,7 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
 
 	file->private_data = devc;
 	file->private_data = devc;
 	DBGRV();
 	DBGRV();
-	unlock_kernel();
+	mutex_unlock(&vwsnd_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3012,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
 	vwsnd_port_t *wport = NULL, *rport = NULL;
 	vwsnd_port_t *wport = NULL, *rport = NULL;
 	int err = 0;
 	int err = 0;
 
 
-	lock_kernel();
+	mutex_lock(&vwsnd_mutex);
 	mutex_lock(&devc->io_mutex);
 	mutex_lock(&devc->io_mutex);
 	{
 	{
 		DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
 		DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
@@ -3040,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
 	wake_up(&devc->open_wait);
 	wake_up(&devc->open_wait);
 	DEC_USE_COUNT;
 	DEC_USE_COUNT;
 	DBGR();
 	DBGR();
-	unlock_kernel();
+	mutex_unlock(&vwsnd_mutex);
 	return err;
 	return err;
 }
 }
 
 
@@ -3068,18 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file)
 	DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
 	DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
 
 
 	INC_USE_COUNT;
 	INC_USE_COUNT;
-	lock_kernel();
+	mutex_lock(&vwsnd_mutex);
 	for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
 	for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
 		if (devc->mixer_minor == iminor(inode))
 		if (devc->mixer_minor == iminor(inode))
 			break;
 			break;
 
 
 	if (devc == NULL) {
 	if (devc == NULL) {
 		DEC_USE_COUNT;
 		DEC_USE_COUNT;
-		unlock_kernel();
+		mutex_unlock(&vwsnd_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 	file->private_data = devc;
 	file->private_data = devc;
-	unlock_kernel();
+	mutex_unlock(&vwsnd_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3223,7 +3223,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
 
 
 	DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
 	DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
 
 
-	lock_kernel();
+	mutex_lock(&vwsnd_mutex);
 	mutex_lock(&devc->mix_mutex);
 	mutex_lock(&devc->mix_mutex);
 	{
 	{
 		if ((cmd & ~nrmask) == MIXER_READ(0))
 		if ((cmd & ~nrmask) == MIXER_READ(0))
@@ -3234,7 +3234,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
 			retval = -EINVAL;
 			retval = -EINVAL;
 	}
 	}
 	mutex_unlock(&devc->mix_mutex);
 	mutex_unlock(&devc->mix_mutex);
-	unlock_kernel();
+	mutex_unlock(&vwsnd_mutex);
 	return retval;
 	return retval;
 }
 }
 
 

+ 11 - 6
sound/pci/Kconfig

@@ -207,12 +207,12 @@ config SND_CMIPCI
 
 
 config SND_OXYGEN_LIB
 config SND_OXYGEN_LIB
         tristate
         tristate
-	select SND_PCM
-	select SND_MPU401_UART
 
 
 config SND_OXYGEN
 config SND_OXYGEN
 	tristate "C-Media 8788 (Oxygen)"
 	tristate "C-Media 8788 (Oxygen)"
 	select SND_OXYGEN_LIB
 	select SND_OXYGEN_LIB
+	select SND_PCM
+	select SND_MPU401_UART
 	help
 	help
 	  Say Y here to include support for sound cards based on the
 	  Say Y here to include support for sound cards based on the
 	  C-Media CMI8788 (Oxygen HD Audio) chip:
 	  C-Media CMI8788 (Oxygen HD Audio) chip:
@@ -581,6 +581,8 @@ config SND_HDSPM
 config SND_HIFIER
 config SND_HIFIER
 	tristate "TempoTec HiFier Fantasia"
 	tristate "TempoTec HiFier Fantasia"
 	select SND_OXYGEN_LIB
 	select SND_OXYGEN_LIB
+	select SND_PCM
+	select SND_MPU401_UART
 	help
 	help
 	  Say Y here to include support for the MediaTek/TempoTec HiFier
 	  Say Y here to include support for the MediaTek/TempoTec HiFier
 	  Fantasia sound card.
 	  Fantasia sound card.
@@ -815,14 +817,17 @@ config SND_VIA82XX_MODEM
 	  will be called snd-via82xx-modem.
 	  will be called snd-via82xx-modem.
 
 
 config SND_VIRTUOSO
 config SND_VIRTUOSO
-	tristate "Asus Virtuoso 100/200 (Xonar)"
+	tristate "Asus Virtuoso 66/100/200 (Xonar)"
 	select SND_OXYGEN_LIB
 	select SND_OXYGEN_LIB
+	select SND_PCM
+	select SND_MPU401_UART
+	select SND_JACK if INPUT=y || INPUT=SND
 	help
 	help
 	  Say Y here to include support for sound cards based on the
 	  Say Y here to include support for sound cards based on the
-	  Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
+	  Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
 	  Essence ST (Deluxe), and Essence STX.
 	  Essence ST (Deluxe), and Essence STX.
-	  Support for the DS is experimental.
-	  Support for the HDAV1.3 (Deluxe) is very experimental.
+	  Support for the HDAV1.3 (Deluxe) is incomplete; for the
+	  HDAV1.3 Slim and Xense, missing.
 
 
 	  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-virtuoso.
 	  will be called snd-virtuoso.

+ 1 - 1
sound/pci/au88x0/au88x0_mixer.c

@@ -23,7 +23,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex)
 	if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
 	if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
 		return err;
 		return err;
 	memset(&ac97, 0, sizeof(ac97));
 	memset(&ac97, 0, sizeof(ac97));
-	// Intialize AC97 codec stuff.
+	// Initialize AC97 codec stuff.
 	ac97.private_data = vortex;
 	ac97.private_data = vortex;
 	ac97.scaps = AC97_SCAP_NO_SPDIF;
 	ac97.scaps = AC97_SCAP_NO_SPDIF;
 	err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
 	err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);

+ 3 - 2
sound/pci/ca0106/ca0106.h

@@ -670,8 +670,9 @@ struct snd_ca0106_details {
 			   gpio_type = 2 -> shared side-out/line-in. */
 			   gpio_type = 2 -> shared side-out/line-in. */
 	int i2c_adc;	/* with i2c_adc=1, the driver adds some capture volume
 	int i2c_adc;	/* with i2c_adc=1, the driver adds some capture volume
 			   controls, phone, mic, line-in and aux. */
 			   controls, phone, mic, line-in and aux. */
-	int spi_dac;	/* spi_dac=1 adds the mute switch for each analog
-			   output, front, rear, etc. */
+	u16 spi_dac;	/* spi_dac = 0 -> no spi interface for DACs
+			   spi_dac = 0x<front><rear><center-lfe><side>
+			   -> specifies DAC id for each channel pair. */
 };
 };
 
 
 // definition of the chip-specific record
 // definition of the chip-specific record

+ 93 - 43
sound/pci/ca0106/ca0106_main.c

@@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
 	   .name   = "Audigy SE [SB0570]",
 	   .name   = "Audigy SE [SB0570]",
 	   .gpio_type = 1,
 	   .gpio_type = 1,
 	   .i2c_adc = 1,
 	   .i2c_adc = 1,
-	   .spi_dac = 1 } ,
+	   .spi_dac = 0x4021 } ,
 	 /* New Audigy LS. Has a different DAC. */
 	 /* New Audigy LS. Has a different DAC. */
 	 /* SB0570:
 	 /* SB0570:
 	  * CTRL:CA0106-DAT
 	  * CTRL:CA0106-DAT
@@ -238,7 +238,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
 	   .name   = "Audigy SE OEM [SB0570a]",
 	   .name   = "Audigy SE OEM [SB0570a]",
 	   .gpio_type = 1,
 	   .gpio_type = 1,
 	   .i2c_adc = 1,
 	   .i2c_adc = 1,
-	   .spi_dac = 1 } ,
+	   .spi_dac = 0x4021 } ,
+	/* Sound Blaster 5.1vx
+	 * Tested: Playback on front, rear, center/lfe speakers
+	 * Not-Tested: Capture
+	 */
+	{ .serial = 0x10041102,
+	  .name   = "Sound Blaster 5.1vx [SB1070]",
+	  .gpio_type = 1,
+	  .i2c_adc = 0,
+	  .spi_dac = 0x0124
+	 } ,
 	 /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
 	 /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
 	 /* SB0438
 	 /* SB0438
 	  * CTRL:CA0106-DAT
 	  * CTRL:CA0106-DAT
@@ -254,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
 	   .name   = "MSI K8N Diamond MB",
 	   .name   = "MSI K8N Diamond MB",
 	   .gpio_type = 2,
 	   .gpio_type = 2,
 	   .i2c_adc = 1,
 	   .i2c_adc = 1,
-	   .spi_dac = 1 } ,
+	   .spi_dac = 0x4021 } ,
 	/* Giga-byte GA-G1975X mobo
 	/* Giga-byte GA-G1975X mobo
 	 * Novell bnc#395807
 	 * Novell bnc#395807
 	 */
 	 */
@@ -483,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime)
 }
 }
 
 
 static const int spi_dacd_reg[] = {
 static const int spi_dacd_reg[] = {
-	[PCM_FRONT_CHANNEL]	= SPI_DACD4_REG,
-	[PCM_REAR_CHANNEL]	= SPI_DACD0_REG,
-	[PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG,
-	[PCM_UNKNOWN_CHANNEL]	= SPI_DACD1_REG,
+	SPI_DACD0_REG,
+	SPI_DACD1_REG,
+	SPI_DACD2_REG,
+	0,
+	SPI_DACD4_REG,
 };
 };
 static const int spi_dacd_bit[] = {
 static const int spi_dacd_bit[] = {
-	[PCM_FRONT_CHANNEL]	= SPI_DACD4_BIT,
-	[PCM_REAR_CHANNEL]	= SPI_DACD0_BIT,
-	[PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT,
-	[PCM_UNKNOWN_CHANNEL]	= SPI_DACD1_BIT,
+	SPI_DACD0_BIT,
+	SPI_DACD1_BIT,
+	SPI_DACD2_BIT,
+	0,
+	SPI_DACD4_BIT,
 };
 };
 
 
 static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
 static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
@@ -504,6 +516,45 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
 	}
 	}
 }
 }
 
 
+static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
+				  int channel_id)
+{
+	switch (channel_id) {
+	case PCM_FRONT_CHANNEL:
+		return (details->spi_dac & 0xf000) >> (4 * 3);
+	case PCM_REAR_CHANNEL:
+		return (details->spi_dac & 0x0f00) >> (4 * 2);
+	case PCM_CENTER_LFE_CHANNEL:
+		return (details->spi_dac & 0x00f0) >> (4 * 1);
+	case PCM_UNKNOWN_CHANNEL:
+		return (details->spi_dac & 0x000f) >> (4 * 0);
+	default:
+		snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n",
+			   channel_id);
+	}
+	return 0;
+}
+
+static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
+				    int power)
+{
+	if (chip->details->spi_dac) {
+		const int dac = snd_ca0106_channel_dac(chip->details,
+						       channel_id);
+		const int reg = spi_dacd_reg[dac];
+		const int bit = spi_dacd_bit[dac];
+
+		if (power)
+			/* Power up */
+			chip->spi_dac_reg[reg] &= ~bit;
+		else
+			/* Power down */
+			chip->spi_dac_reg[reg] |= bit;
+		return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+	}
+	return 0;
+}
+
 /* open_playback callback */
 /* open_playback callback */
 static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
 static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
 						int channel_id)
 						int channel_id)
@@ -543,12 +594,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
                 return err;
                 return err;
 	snd_pcm_set_sync(substream);
 	snd_pcm_set_sync(substream);
 
 
-	if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) {
-		const int reg = spi_dacd_reg[channel_id];
-
-		/* Power up dac */
-		chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id];
-		err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+	/* Front channel dac should already be on */
+	if (channel_id != PCM_FRONT_CHANNEL) {
+		err = snd_ca0106_pcm_power_dac(chip, channel_id, 1);
 		if (err < 0)
 		if (err < 0)
 			return err;
 			return err;
 	}
 	}
@@ -568,13 +616,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream)
 
 
 	restore_spdif_bits(chip, epcm->channel_id);
 	restore_spdif_bits(chip, epcm->channel_id);
 
 
-	if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
-		const int reg = spi_dacd_reg[epcm->channel_id];
-
-		/* Power down DAC */
-		chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id];
-		snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+	/* Front channel dac should stay on */
+	if (epcm->channel_id != PCM_FRONT_CHANNEL) {
+		int err;
+		err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0);
+		if (err < 0)
+			return err;
 	}
 	}
+
 	/* FIXME: maybe zero others */
 	/* FIXME: maybe zero others */
 	return 0;
 	return 0;
 }
 }
@@ -1002,29 +1051,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
 	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
 	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_ca0106_pcm *epcm = runtime->private_data;
 	struct snd_ca0106_pcm *epcm = runtime->private_data;
-	snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
+	unsigned int ptr, prev_ptr;
 	int channel = epcm->channel_id;
 	int channel = epcm->channel_id;
+	int timeout = 10;
 
 
 	if (!epcm->running)
 	if (!epcm->running)
 		return 0;
 		return 0;
 
 
-	ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
-	ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
-	ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
-	if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
-	ptr2 = bytes_to_frames(runtime, ptr1);
-	ptr2+= (ptr4 >> 3) * runtime->period_size;
-	ptr=ptr2;
-        if (ptr >= runtime->buffer_size)
-		ptr -= runtime->buffer_size;
-	/*
-	printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
-	       "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
-	       ptr1, ptr2, ptr, (int)runtime->buffer_size,
-	       (int)runtime->period_size, (int)runtime->frame_bits,
-	       (int)runtime->rate);
-	*/
-	return ptr;
+	prev_ptr = -1;
+	do {
+		ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
+		ptr = (ptr >> 3) * runtime->period_size;
+		ptr += bytes_to_frames(runtime,
+			snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
+		if (ptr >= runtime->buffer_size)
+			ptr -= runtime->buffer_size;
+		if (prev_ptr == ptr)
+			return ptr;
+		prev_ptr = ptr;
+	} while (--timeout);
+	snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
+	return 0;
 }
 }
 
 
 /* pointer_capture callback */
 /* pointer_capture callback */
@@ -1362,7 +1409,7 @@ static unsigned int spi_dac_init[] = {
 	SPI_REG(12,		0x00),
 	SPI_REG(12,		0x00),
 	SPI_REG(SPI_LDA4_REG,	SPI_DA_BIT_0dB),
 	SPI_REG(SPI_LDA4_REG,	SPI_DA_BIT_0dB),
 	SPI_REG(SPI_RDA4_REG,	SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
 	SPI_REG(SPI_RDA4_REG,	SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
-	SPI_REG(SPI_DACD4_REG,	0x00),
+	SPI_REG(SPI_DACD4_REG,	SPI_DACD4_BIT),
 };
 };
 
 
 static unsigned int i2c_adc_init[][2] = {
 static unsigned int i2c_adc_init[][2] = {
@@ -1541,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
 		/* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
 		/* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
 	}
 	}
 
 
-	if (chip->details->spi_dac == 1) {
+	if (chip->details->spi_dac) {
 		/* The SB0570 use SPI to control DAC. */
 		/* The SB0570 use SPI to control DAC. */
 		int size, n;
 		int size, n;
 
 
@@ -1553,6 +1600,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
 			if (reg < ARRAY_SIZE(chip->spi_dac_reg))
 			if (reg < ARRAY_SIZE(chip->spi_dac_reg))
 				chip->spi_dac_reg[reg] = spi_dac_init[n];
 				chip->spi_dac_reg[reg] = spi_dac_init[n];
 		}
 		}
+
+		/* Enable front dac only */
+		snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1);
 	}
 	}
 }
 }
 
 

+ 70 - 23
sound/pci/ca0106/ca0106_mixer.c

@@ -676,28 +676,65 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata =
         I2C_VOLUME("Aux Capture Volume", 3),
         I2C_VOLUME("Aux Capture Volume", 3),
 };
 };
 
 
-#define SPI_SWITCH(xname,reg,bit) \
-{								\
-	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
-	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
-	.info	= spi_mute_info,				\
-	.get	= spi_mute_get,					\
-	.put	= spi_mute_put,					\
-	.private_value = (reg<<SPI_REG_SHIFT) | (bit)		\
-}
-
-static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[]
-__devinitdata = {
-	SPI_SWITCH("Analog Front Playback Switch",
-		   SPI_DMUTE4_REG, SPI_DMUTE4_BIT),
-	SPI_SWITCH("Analog Rear Playback Switch",
-		   SPI_DMUTE0_REG, SPI_DMUTE0_BIT),
-	SPI_SWITCH("Analog Center/LFE Playback Switch",
-		   SPI_DMUTE2_REG, SPI_DMUTE2_BIT),
-	SPI_SWITCH("Analog Side Playback Switch",
-		   SPI_DMUTE1_REG, SPI_DMUTE1_BIT),
+static const int spi_dmute_reg[] = {
+	SPI_DMUTE0_REG,
+	SPI_DMUTE1_REG,
+	SPI_DMUTE2_REG,
+	0,
+	SPI_DMUTE4_REG,
+};
+static const int spi_dmute_bit[] = {
+	SPI_DMUTE0_BIT,
+	SPI_DMUTE1_BIT,
+	SPI_DMUTE2_BIT,
+	0,
+	SPI_DMUTE4_BIT,
 };
 };
 
 
+static struct snd_kcontrol_new __devinit
+snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details,
+			      int channel_id)
+{
+	struct snd_kcontrol_new spi_switch = {0};
+	int reg, bit;
+	int dac_id;
+
+	spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	spi_switch.info = spi_mute_info;
+	spi_switch.get = spi_mute_get;
+	spi_switch.put = spi_mute_put;
+
+	switch (channel_id) {
+	case PCM_FRONT_CHANNEL:
+		spi_switch.name = "Analog Front Playback Switch";
+		dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
+		break;
+	case PCM_REAR_CHANNEL:
+		spi_switch.name = "Analog Rear Playback Switch";
+		dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
+		break;
+	case PCM_CENTER_LFE_CHANNEL:
+		spi_switch.name = "Analog Center/LFE Playback Switch";
+		dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
+		break;
+	case PCM_UNKNOWN_CHANNEL:
+		spi_switch.name = "Analog Side Playback Switch";
+		dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
+		break;
+	default:
+		/* Unused channel */
+		spi_switch.name = NULL;
+		dac_id = 0;
+	}
+	reg = spi_dmute_reg[dac_id];
+	bit = spi_dmute_bit[dac_id];
+
+	spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
+
+	return spi_switch;
+}
+
 static int __devinit remove_ctl(struct snd_card *card, const char *name)
 static int __devinit remove_ctl(struct snd_card *card, const char *name)
 {
 {
 	struct snd_ctl_elem_id id;
 	struct snd_ctl_elem_id id;
@@ -832,8 +869,18 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
 		if (err < 0)
 		if (err < 0)
 			return err;
 			return err;
 	}
 	}
-	if (emu->details->spi_dac == 1)
-		ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls);
+	if (emu->details->spi_dac) {
+		int i;
+		for (i = 0;; i++) {
+			struct snd_kcontrol_new ctl;
+			ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
+			if (!ctl.name)
+				break;
+			err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
+			if (err < 0)
+				return err;
+		}
+	}
 
 
 	/* Create virtual master controls */
 	/* Create virtual master controls */
 	vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
 	vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
@@ -845,7 +892,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
 		return err;
 		return err;
 	add_slaves(card, vmaster, slave_vols);
 	add_slaves(card, vmaster, slave_vols);
 
 
-	if (emu->details->spi_dac == 1) {
+	if (emu->details->spi_dac) {
 		vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
 		vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
 						      NULL);
 						      NULL);
 		if (!vmaster)
 		if (!vmaster)

+ 1 - 1
sound/pci/emu10k1/emumpu401.c

@@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input =
 
 
 static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
 static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
 {
 {
-	struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data;
+	struct snd_emu10k1_midi *midi = rmidi->private_data;
 	midi->interrupt = NULL;
 	midi->interrupt = NULL;
 	midi->rmidi = NULL;
 	midi->rmidi = NULL;
 }
 }

+ 6 - 33
sound/pci/hda/Kconfig

@@ -119,47 +119,20 @@ config SND_HDA_CODEC_VIA
 	  snd-hda-codec-via.
 	  snd-hda-codec-via.
 	  This module is automatically loaded at probing.
 	  This module is automatically loaded at probing.
 
 
-config SND_HDA_CODEC_ATIHDMI
-	bool "Build ATI HDMI HD-audio codec support"
-	default y
-	help
-	  Say Y here to include ATI HDMI HD-audio codec support in
-	  snd-hda-intel driver, such as ATI RS600 HDMI.
-
-	  When the HD-audio driver is built as a module, the codec
-	  support code is also built as another module,
-	  snd-hda-codec-atihdmi.
-	  This module is automatically loaded at probing.
-
-config SND_HDA_CODEC_NVHDMI
-	bool "Build NVIDIA HDMI HD-audio codec support"
-	default y
-	help
-	  Say Y here to include NVIDIA HDMI HD-audio codec support in
-	  snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
-
-	  When the HD-audio driver is built as a module, the codec
-	  support code is also built as another module,
-	  snd-hda-codec-nvhdmi.
-	  This module is automatically loaded at probing.
-
-config SND_HDA_CODEC_INTELHDMI
-	bool "Build INTEL HDMI HD-audio codec support"
+config SND_HDA_CODEC_HDMI
+	bool "Build HDMI/DisplayPort HD-audio codec support"
 	select SND_DYNAMIC_MINORS
 	select SND_DYNAMIC_MINORS
 	default y
 	default y
 	help
 	help
-	  Say Y here to include INTEL HDMI HD-audio codec support in
-	  snd-hda-intel driver, such as Eaglelake integrated HDMI.
+	  Say Y here to include HDMI and DisplayPort HD-audio codec
+	  support in snd-hda-intel driver.  This includes all AMD/ATI,
+	  Intel and Nvidia HDMI/DisplayPort codecs.
 
 
 	  When the HD-audio driver is built as a module, the codec
 	  When the HD-audio driver is built as a module, the codec
 	  support code is also built as another module,
 	  support code is also built as another module,
-	  snd-hda-codec-intelhdmi.
+	  snd-hda-codec-hdmi.
 	  This module is automatically loaded at probing.
 	  This module is automatically loaded at probing.
 
 
-config SND_HDA_ELD
-	def_bool y
-	depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI
-
 config SND_HDA_CODEC_CIRRUS
 config SND_HDA_CODEC_CIRRUS
 	bool "Build Cirrus Logic codec support"
 	bool "Build Cirrus Logic codec support"
 	depends on SND_HDA_INTEL
 	depends on SND_HDA_INTEL

+ 3 - 12
sound/pci/hda/Makefile

@@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o
 snd-hda-codec-y := hda_codec.o
 snd-hda-codec-y := hda_codec.o
 snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
 snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
-snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
 snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
 
 
@@ -12,13 +11,11 @@ snd-hda-codec-cmedia-objs :=	patch_cmedia.o
 snd-hda-codec-analog-objs :=	patch_analog.o
 snd-hda-codec-analog-objs :=	patch_analog.o
 snd-hda-codec-idt-objs :=	patch_sigmatel.o
 snd-hda-codec-idt-objs :=	patch_sigmatel.o
 snd-hda-codec-si3054-objs :=	patch_si3054.o
 snd-hda-codec-si3054-objs :=	patch_si3054.o
-snd-hda-codec-atihdmi-objs :=	patch_atihdmi.o
 snd-hda-codec-cirrus-objs :=	patch_cirrus.o
 snd-hda-codec-cirrus-objs :=	patch_cirrus.o
 snd-hda-codec-ca0110-objs :=	patch_ca0110.o
 snd-hda-codec-ca0110-objs :=	patch_ca0110.o
 snd-hda-codec-conexant-objs :=	patch_conexant.o
 snd-hda-codec-conexant-objs :=	patch_conexant.o
 snd-hda-codec-via-objs :=	patch_via.o
 snd-hda-codec-via-objs :=	patch_via.o
-snd-hda-codec-nvhdmi-objs :=	patch_nvhdmi.o
-snd-hda-codec-intelhdmi-objs :=	patch_intelhdmi.o
+snd-hda-codec-hdmi-objs :=	patch_hdmi.o hda_eld.o
 
 
 # common driver
 # common driver
 obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
 obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
@@ -39,9 +36,6 @@ endif
 ifdef CONFIG_SND_HDA_CODEC_SI3054
 ifdef CONFIG_SND_HDA_CODEC_SI3054
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
 endif
 endif
-ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
-endif
 ifdef CONFIG_SND_HDA_CODEC_CIRRUS
 ifdef CONFIG_SND_HDA_CODEC_CIRRUS
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
 endif
 endif
@@ -54,11 +48,8 @@ endif
 ifdef CONFIG_SND_HDA_CODEC_VIA
 ifdef CONFIG_SND_HDA_CODEC_VIA
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
 endif
 endif
-ifdef CONFIG_SND_HDA_CODEC_NVHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o
+ifdef CONFIG_SND_HDA_CODEC_HDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o
 endif
 endif
 
 
 # this must be the last entry after codec drivers;
 # this must be the last entry after codec drivers;

+ 216 - 55
sound/pci/hda/hda_codec.c

@@ -1216,6 +1216,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 	struct hda_codec *c;
 	struct hda_codec *c;
 	struct hda_cvt_setup *p;
 	struct hda_cvt_setup *p;
 	unsigned int oldval, newval;
 	unsigned int oldval, newval;
+	int type;
 	int i;
 	int i;
 
 
 	if (!nid)
 	if (!nid)
@@ -1254,10 +1255,12 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 	p->dirty = 0;
 	p->dirty = 0;
 
 
 	/* make other inactive cvts with the same stream-tag dirty */
 	/* make other inactive cvts with the same stream-tag dirty */
+	type = get_wcaps_type(get_wcaps(codec, nid));
 	list_for_each_entry(c, &codec->bus->codec_list, list) {
 	list_for_each_entry(c, &codec->bus->codec_list, list) {
 		for (i = 0; i < c->cvt_setups.used; i++) {
 		for (i = 0; i < c->cvt_setups.used; i++) {
 			p = snd_array_elem(&c->cvt_setups, i);
 			p = snd_array_elem(&c->cvt_setups, i);
-			if (!p->active && p->stream_tag == stream_tag)
+			if (!p->active && p->stream_tag == stream_tag &&
+			    get_wcaps_type(get_wcaps(codec, p->nid)) == type)
 				p->dirty = 1;
 				p->dirty = 1;
 		}
 		}
 	}
 	}
@@ -1281,6 +1284,9 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
 	if (!nid)
 	if (!nid)
 		return;
 		return;
 
 
+	if (codec->no_sticky_stream)
+		do_now = 1;
+
 	snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
 	snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
 	p = get_hda_cvt_setup(codec, nid);
 	p = get_hda_cvt_setup(codec, nid);
 	if (p) {
 	if (p) {
@@ -1831,6 +1837,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 	hda_nid_t nid = get_amp_nid(kcontrol);
 	hda_nid_t nid = get_amp_nid(kcontrol);
 	int dir = get_amp_direction(kcontrol);
 	int dir = get_amp_direction(kcontrol);
 	unsigned int ofs = get_amp_offset(kcontrol);
 	unsigned int ofs = get_amp_offset(kcontrol);
+	bool min_mute = get_amp_min_mute(kcontrol);
 	u32 caps, val1, val2;
 	u32 caps, val1, val2;
 
 
 	if (size < 4 * sizeof(unsigned int))
 	if (size < 4 * sizeof(unsigned int))
@@ -1841,6 +1848,8 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 	val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
 	val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
 	val1 += ofs;
 	val1 += ofs;
 	val1 = ((int)val1) * ((int)val2);
 	val1 = ((int)val1) * ((int)val2);
+	if (min_mute)
+		val2 |= TLV_DB_SCALE_MUTE;
 	if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
 	if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
 		return -EFAULT;
 		return -EFAULT;
 	if (put_user(2 * sizeof(unsigned int), _tlv + 1))
 	if (put_user(2 * sizeof(unsigned int), _tlv + 1))
@@ -2228,10 +2237,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
 		change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
 		change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
 						   HDA_AMP_MUTE,
 						   HDA_AMP_MUTE,
 						   *valp ? 0 : HDA_AMP_MUTE);
 						   *valp ? 0 : HDA_AMP_MUTE);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-	if (codec->patch_ops.check_power_status)
-		codec->patch_ops.check_power_status(codec, nid);
-#endif
+	hda_call_check_power_status(codec, nid);
 	snd_hda_power_down(codec);
 	snd_hda_power_down(codec);
 	return change;
 	return change;
 }
 }
@@ -4372,6 +4378,34 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
 }
 }
 
 
 
 
+/* add the found input-pin to the cfg->inputs[] table */
+static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
+				   int type)
+{
+	if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
+		cfg->inputs[cfg->num_inputs].pin = nid;
+		cfg->inputs[cfg->num_inputs].type = type;
+		cfg->num_inputs++;
+	}
+}
+
+/* sort inputs in the order of AUTO_PIN_* type */
+static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
+{
+	int i, j;
+
+	for (i = 0; i < cfg->num_inputs; i++) {
+		for (j = i + 1; j < cfg->num_inputs; j++) {
+			if (cfg->inputs[i].type > cfg->inputs[j].type) {
+				struct auto_pin_cfg_item tmp;
+				tmp = cfg->inputs[i];
+				cfg->inputs[i] = cfg->inputs[j];
+				cfg->inputs[j] = tmp;
+			}
+		}
+	}
+}
+
 /*
 /*
  * Parse all pin widgets and store the useful pin nids to cfg
  * Parse all pin widgets and store the useful pin nids to cfg
  *
  *
@@ -4385,7 +4419,7 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
  * output, i.e. to line_out_pins[0].  So, line_outs is always positive
  * output, i.e. to line_out_pins[0].  So, line_outs is always positive
  * if any analog output exists.
  * if any analog output exists.
  *
  *
- * The analog input pins are assigned to input_pins array.
+ * The analog input pins are assigned to inputs array.
  * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
  * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
  * respectively.
  * respectively.
  */
  */
@@ -4398,6 +4432,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 	short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
 	short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
 	short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
 	short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
 	short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
 	short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
+	int i;
 
 
 	memset(cfg, 0, sizeof(*cfg));
 	memset(cfg, 0, sizeof(*cfg));
 
 
@@ -4468,33 +4503,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 			sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
 			sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
 			cfg->hp_outs++;
 			cfg->hp_outs++;
 			break;
 			break;
-		case AC_JACK_MIC_IN: {
-			int preferred, alt;
-			if (loc == AC_JACK_LOC_FRONT ||
-			    (loc & 0x30) == AC_JACK_LOC_INTERNAL) {
-				preferred = AUTO_PIN_FRONT_MIC;
-				alt = AUTO_PIN_MIC;
-			} else {
-				preferred = AUTO_PIN_MIC;
-				alt = AUTO_PIN_FRONT_MIC;
-			}
-			if (!cfg->input_pins[preferred])
-				cfg->input_pins[preferred] = nid;
-			else if (!cfg->input_pins[alt])
-				cfg->input_pins[alt] = nid;
+		case AC_JACK_MIC_IN:
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
 			break;
 			break;
-		}
 		case AC_JACK_LINE_IN:
 		case AC_JACK_LINE_IN:
-			if (loc == AC_JACK_LOC_FRONT)
-				cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
-			else
-				cfg->input_pins[AUTO_PIN_LINE] = nid;
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
 			break;
 			break;
 		case AC_JACK_CD:
 		case AC_JACK_CD:
-			cfg->input_pins[AUTO_PIN_CD] = nid;
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
 			break;
 			break;
 		case AC_JACK_AUX:
 		case AC_JACK_AUX:
-			cfg->input_pins[AUTO_PIN_AUX] = nid;
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
 			break;
 			break;
 		case AC_JACK_SPDIF_OUT:
 		case AC_JACK_SPDIF_OUT:
 		case AC_JACK_DIG_OTHER_OUT:
 		case AC_JACK_DIG_OTHER_OUT:
@@ -4539,6 +4558,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 			memmove(sequences_hp + i, sequences_hp + i + 1,
 			memmove(sequences_hp + i, sequences_hp + i + 1,
 				sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
 				sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
 		}
 		}
+		memset(cfg->hp_pins + cfg->hp_outs, 0,
+		       sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
 	}
 	}
 
 
 	/* sort by sequence */
 	/* sort by sequence */
@@ -4549,21 +4570,6 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 	sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
 	sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
 			      cfg->hp_outs);
 			      cfg->hp_outs);
 
 
-	/* if we have only one mic, make it AUTO_PIN_MIC */
-	if (!cfg->input_pins[AUTO_PIN_MIC] &&
-	    cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
-		cfg->input_pins[AUTO_PIN_MIC] =
-			cfg->input_pins[AUTO_PIN_FRONT_MIC];
-		cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0;
-	}
-	/* ditto for line-in */
-	if (!cfg->input_pins[AUTO_PIN_LINE] &&
-	    cfg->input_pins[AUTO_PIN_FRONT_LINE]) {
-		cfg->input_pins[AUTO_PIN_LINE] =
-			cfg->input_pins[AUTO_PIN_FRONT_LINE];
-		cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0;
-	}
-
 	/*
 	/*
 	 * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
 	 * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
 	 * as a primary output
 	 * as a primary output
@@ -4602,6 +4608,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 		break;
 		break;
 	}
 	}
 
 
+	sort_autocfg_input_pins(cfg);
+
 	/*
 	/*
 	 * debug prints of the parsed results
 	 * debug prints of the parsed results
 	 */
 	 */
@@ -4621,14 +4629,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 	if (cfg->dig_outs)
 	if (cfg->dig_outs)
 		snd_printd("   dig-out=0x%x/0x%x\n",
 		snd_printd("   dig-out=0x%x/0x%x\n",
 			   cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
 			   cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
-	snd_printd("   inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
-		   " cd=0x%x, aux=0x%x\n",
-		   cfg->input_pins[AUTO_PIN_MIC],
-		   cfg->input_pins[AUTO_PIN_FRONT_MIC],
-		   cfg->input_pins[AUTO_PIN_LINE],
-		   cfg->input_pins[AUTO_PIN_FRONT_LINE],
-		   cfg->input_pins[AUTO_PIN_CD],
-		   cfg->input_pins[AUTO_PIN_AUX]);
+	snd_printd("   inputs:");
+	for (i = 0; i < cfg->num_inputs; i++) {
+		snd_printdd(" %s=0x%x",
+			    hda_get_autocfg_input_label(codec, cfg, i),
+			    cfg->inputs[i].pin);
+	}
+	snd_printd("\n");
 	if (cfg->dig_in_pin)
 	if (cfg->dig_in_pin)
 		snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
 		snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
 
 
@@ -4636,11 +4643,165 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 }
 }
 EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
 EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
 
 
-/* labels for input pins */
-const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {
-	"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
-};
-EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
+int snd_hda_get_input_pin_attr(unsigned int def_conf)
+{
+	unsigned int loc = get_defcfg_location(def_conf);
+	unsigned int conn = get_defcfg_connect(def_conf);
+	if (conn == AC_JACK_PORT_NONE)
+		return INPUT_PIN_ATTR_UNUSED;
+	/* Windows may claim the internal mic to be BOTH, too */
+	if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
+		return INPUT_PIN_ATTR_INT;
+	if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
+		return INPUT_PIN_ATTR_INT;
+	if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
+		return INPUT_PIN_ATTR_DOCK;
+	if (loc == AC_JACK_LOC_REAR)
+		return INPUT_PIN_ATTR_REAR;
+	if (loc == AC_JACK_LOC_FRONT)
+		return INPUT_PIN_ATTR_FRONT;
+	return INPUT_PIN_ATTR_NORMAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
+
+/**
+ * hda_get_input_pin_label - Give a label for the given input pin
+ *
+ * When check_location is true, the function checks the pin location
+ * for mic and line-in pins, and set an appropriate prefix like "Front",
+ * "Rear", "Internal".
+ */
+
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+					int check_location)
+{
+	unsigned int def_conf;
+	static const char *mic_names[] = {
+		"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
+	};
+	int attr;
+
+	def_conf = snd_hda_codec_get_pincfg(codec, pin);
+
+	switch (get_defcfg_device(def_conf)) {
+	case AC_JACK_MIC_IN:
+		if (!check_location)
+			return "Mic";
+		attr = snd_hda_get_input_pin_attr(def_conf);
+		if (!attr)
+			return "None";
+		return mic_names[attr - 1];
+	case AC_JACK_LINE_IN:
+		if (!check_location)
+			return "Line";
+		attr = snd_hda_get_input_pin_attr(def_conf);
+		if (!attr)
+			return "None";
+		if (attr == INPUT_PIN_ATTR_DOCK)
+			return "Dock Line";
+		return "Line";
+	case AC_JACK_AUX:
+		return "Aux";
+	case AC_JACK_CD:
+		return "CD";
+	case AC_JACK_SPDIF_IN:
+		return "SPDIF In";
+	case AC_JACK_DIG_OTHER_IN:
+		return "Digital In";
+	default:
+		return "Misc";
+	}
+}
+EXPORT_SYMBOL_HDA(hda_get_input_pin_label);
+
+/* Check whether the location prefix needs to be added to the label.
+ * If all mic-jacks are in the same location (e.g. rear panel), we don't
+ * have to put "Front" prefix to each label.  In such a case, returns false.
+ */
+static int check_mic_location_need(struct hda_codec *codec,
+				   const struct auto_pin_cfg *cfg,
+				   int input)
+{
+	unsigned int defc;
+	int i, attr, attr2;
+
+	defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
+	attr = snd_hda_get_input_pin_attr(defc);
+	/* for internal or docking mics, we need locations */
+	if (attr <= INPUT_PIN_ATTR_NORMAL)
+		return 1;
+
+	attr = 0;
+	for (i = 0; i < cfg->num_inputs; i++) {
+		defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
+		attr2 = snd_hda_get_input_pin_attr(defc);
+		if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
+			if (attr && attr != attr2)
+				return 1; /* different locations found */
+			attr = attr2;
+		}
+	}
+	return 0;
+}
+
+/**
+ * hda_get_autocfg_input_label - Get a label for the given input
+ *
+ * Get a label for the given input pin defined by the autocfg item.
+ * Unlike hda_get_input_pin_label(), this function checks all inputs
+ * defined in autocfg and avoids the redundant mic/line prefix as much as
+ * possible.
+ */
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+					const struct auto_pin_cfg *cfg,
+					int input)
+{
+	int type = cfg->inputs[input].type;
+	int has_multiple_pins = 0;
+
+	if ((input > 0 && cfg->inputs[input - 1].type == type) ||
+	    (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
+		has_multiple_pins = 1;
+	if (has_multiple_pins && type == AUTO_PIN_MIC)
+		has_multiple_pins &= check_mic_location_need(codec, cfg, input);
+	return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+				       has_multiple_pins);
+}
+EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
+
+/**
+ * snd_hda_add_imux_item - Add an item to input_mux
+ *
+ * When the same label is used already in the existing items, the number
+ * suffix is appended to the label.  This label index number is stored
+ * to type_idx when non-NULL pointer is given.
+ */
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+			  int index, int *type_idx)
+{
+	int i, label_idx = 0;
+	if (imux->num_items >= HDA_MAX_NUM_INPUTS) {
+		snd_printd(KERN_ERR "hda_codec: Too many imux items!\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < imux->num_items; i++) {
+		if (!strncmp(label, imux->items[i].label, strlen(label)))
+			label_idx++;
+	}
+	if (type_idx)
+		*type_idx = label_idx;
+	if (label_idx > 0)
+		snprintf(imux->items[imux->num_items].label,
+			 sizeof(imux->items[imux->num_items].label),
+			 "%s %d", label, label_idx);
+	else
+		strlcpy(imux->items[imux->num_items].label, label,
+			sizeof(imux->items[imux->num_items].label));
+	imux->items[imux->num_items].index = index;
+	imux->num_items++;
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
 
 
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM

+ 13 - 0
sound/pci/hda/hda_codec.h

@@ -850,6 +850,7 @@ struct hda_codec {
 	unsigned int pin_amp_workaround:1; /* pin out-amp takes index
 	unsigned int pin_amp_workaround:1; /* pin out-amp takes index
 					    * (e.g. Conexant codecs)
 					    * (e.g. Conexant codecs)
 					    */
 					    */
+	unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
 	unsigned int pins_shutup:1;	/* pins are shut up */
 	unsigned int pins_shutup:1;	/* pins are shut up */
 	unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
 	unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -989,6 +990,18 @@ int snd_hda_suspend(struct hda_bus *bus);
 int snd_hda_resume(struct hda_bus *bus);
 int snd_hda_resume(struct hda_bus *bus);
 #endif
 #endif
 
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static inline
+int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
+{
+	if (codec->patch_ops.check_power_status)
+		return codec->patch_ops.check_power_status(codec, nid);
+	return 0;
+}
+#else	
+#define hda_call_check_power_status(codec, nid)		0
+#endif
+
 /*
 /*
  * get widget information
  * get widget information
  */
  */

+ 0 - 7
sound/pci/hda/hda_eld.c

@@ -332,7 +332,6 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
 	return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
 	return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
 						 AC_DIPSIZE_ELD_BUF);
 						 AC_DIPSIZE_ELD_BUF);
 }
 }
-EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size);
 
 
 int snd_hdmi_get_eld(struct hdmi_eld *eld,
 int snd_hdmi_get_eld(struct hdmi_eld *eld,
 		     struct hda_codec *codec, hda_nid_t nid)
 		     struct hda_codec *codec, hda_nid_t nid)
@@ -368,7 +367,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
 	kfree(buf);
 	kfree(buf);
 	return ret;
 	return ret;
 }
 }
-EXPORT_SYMBOL_HDA(snd_hdmi_get_eld);
 
 
 static void hdmi_show_short_audio_desc(struct cea_sad *a)
 static void hdmi_show_short_audio_desc(struct cea_sad *a)
 {
 {
@@ -407,7 +405,6 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
 	}
 	}
 	buf[j] = '\0';	/* necessary when j == 0 */
 	buf[j] = '\0';	/* necessary when j == 0 */
 }
 }
-EXPORT_SYMBOL_HDA(snd_print_channel_allocation);
 
 
 void snd_hdmi_show_eld(struct hdmi_eld *e)
 void snd_hdmi_show_eld(struct hdmi_eld *e)
 {
 {
@@ -426,7 +423,6 @@ void snd_hdmi_show_eld(struct hdmi_eld *e)
 	for (i = 0; i < e->sad_count; i++)
 	for (i = 0; i < e->sad_count; i++)
 		hdmi_show_short_audio_desc(e->sad + i);
 		hdmi_show_short_audio_desc(e->sad + i);
 }
 }
-EXPORT_SYMBOL_HDA(snd_hdmi_show_eld);
 
 
 #ifdef CONFIG_PROC_FS
 #ifdef CONFIG_PROC_FS
 
 
@@ -585,7 +581,6 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new);
 
 
 void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
 void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
 {
 {
@@ -594,7 +589,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
 		eld->proc_entry = NULL;
 		eld->proc_entry = NULL;
 	}
 	}
 }
 }
-EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free);
 
 
 #endif /* CONFIG_PROC_FS */
 #endif /* CONFIG_PROC_FS */
 
 
@@ -645,4 +639,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
 	pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
 	pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
 	pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
 	pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
 }
 }
-EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info);

+ 5 - 36
sound/pci/hda/hda_generic.c

@@ -61,7 +61,6 @@ struct hda_gspec {
 	struct hda_gnode *cap_vol_node;	/* Node for capture volume */
 	struct hda_gnode *cap_vol_node;	/* Node for capture volume */
 	unsigned int cur_cap_src;	/* current capture source */
 	unsigned int cur_cap_src;	/* current capture source */
 	struct hda_input_mux input_mux;
 	struct hda_input_mux input_mux;
-	char cap_labels[HDA_MAX_NUM_INPUTS][16];
 
 
 	unsigned int def_amp_in_caps;
 	unsigned int def_amp_in_caps;
 	unsigned int def_amp_out_caps;
 	unsigned int def_amp_out_caps;
@@ -506,11 +505,10 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
  * returns 0 if not found, 1 if found, or a negative error code.
  * returns 0 if not found, 1 if found, or a negative error code.
  */
  */
 static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
 static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
-			       struct hda_gnode *node)
+			       struct hda_gnode *node, int idx)
 {
 {
 	int i, err;
 	int i, err;
 	unsigned int pinctl;
 	unsigned int pinctl;
-	char *label;
 	const char *type;
 	const char *type;
 
 
 	if (node->checked)
 	if (node->checked)
@@ -523,7 +521,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
 			child = hda_get_node(spec, node->conn_list[i]);
 			child = hda_get_node(spec, node->conn_list[i]);
 			if (! child)
 			if (! child)
 				continue;
 				continue;
-			err = parse_adc_sub_nodes(codec, spec, child);
+			err = parse_adc_sub_nodes(codec, spec, child, idx);
 			if (err < 0)
 			if (err < 0)
 				return err;
 				return err;
 			if (err > 0) {
 			if (err > 0) {
@@ -564,9 +562,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
 			return 0;
 			return 0;
 		type = "Input";
 		type = "Input";
 	}
 	}
-	label = spec->cap_labels[spec->input_mux.num_items];
-	strcpy(label, type);
-	spec->input_mux.items[spec->input_mux.num_items].label = label;
+	snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL);
 
 
 	/* unmute the PIN external input */
 	/* unmute the PIN external input */
 	unmute_input(codec, node, 0); /* index = 0? */
 	unmute_input(codec, node, 0); /* index = 0? */
@@ -577,29 +573,6 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
 	return 1; /* found */
 	return 1; /* found */
 }
 }
 
 
-/* add a capture source element */
-static void add_cap_src(struct hda_gspec *spec, int idx)
-{
-	struct hda_input_mux_item *csrc;
-	char *buf;
-	int num, ocap;
-
-	num = spec->input_mux.num_items;
-	csrc = &spec->input_mux.items[num];
-	buf = spec->cap_labels[num];
-	for (ocap = 0; ocap < num; ocap++) {
-		if (! strcmp(buf, spec->cap_labels[ocap])) {
-			/* same label already exists,
-			 * put the index number to be unique
-			 */
-			sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
-			break;
-		}
-	}
-	csrc->index = idx;
-	spec->input_mux.num_items++;
-}
-
 /*
 /*
  * parse input
  * parse input
  */
  */
@@ -624,22 +597,18 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
 	for (i = 0; i < adc_node->nconns; i++) {
 	for (i = 0; i < adc_node->nconns; i++) {
 		node = hda_get_node(spec, adc_node->conn_list[i]);
 		node = hda_get_node(spec, adc_node->conn_list[i]);
 		if (node && node->type == AC_WID_PIN) {
 		if (node && node->type == AC_WID_PIN) {
-			err = parse_adc_sub_nodes(codec, spec, node);
+			err = parse_adc_sub_nodes(codec, spec, node, i);
 			if (err < 0)
 			if (err < 0)
 				return err;
 				return err;
-			else if (err > 0)
-				add_cap_src(spec, i);
 		}
 		}
 	}
 	}
 	/* ... then check the rests, more complicated connections */
 	/* ... then check the rests, more complicated connections */
 	for (i = 0; i < adc_node->nconns; i++) {
 	for (i = 0; i < adc_node->nconns; i++) {
 		node = hda_get_node(spec, adc_node->conn_list[i]);
 		node = hda_get_node(spec, adc_node->conn_list[i]);
 		if (node && node->type != AC_WID_PIN) {
 		if (node && node->type != AC_WID_PIN) {
-			err = parse_adc_sub_nodes(codec, spec, node);
+			err = parse_adc_sub_nodes(codec, spec, node, i);
 			if (err < 0)
 			if (err < 0)
 				return err;
 				return err;
-			else if (err > 0)
-				add_cap_src(spec, i);
 		}
 		}
 	}
 	}
 
 

+ 53 - 48
sound/pci/hda/hda_intel.c

@@ -78,8 +78,8 @@ MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
 module_param_array(model, charp, NULL, 0444);
 module_param_array(model, charp, NULL, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
 MODULE_PARM_DESC(model, "Use the given board model.");
 module_param_array(position_fix, int, NULL, 0444);
 module_param_array(position_fix, int, NULL, 0444);
-MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
-		 "(0 = auto, 1 = none, 2 = POSBUF).");
+MODULE_PARM_DESC(position_fix, "DMA pointer read method."
+		 "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
 module_param_array(bdl_pos_adj, int, NULL, 0644);
 module_param_array(bdl_pos_adj, int, NULL, 0644);
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
 module_param_array(probe_mask, int, NULL, 0444);
@@ -305,6 +305,7 @@ enum {
 	POS_FIX_AUTO,
 	POS_FIX_AUTO,
 	POS_FIX_LPIB,
 	POS_FIX_LPIB,
 	POS_FIX_POSBUF,
 	POS_FIX_POSBUF,
+	POS_FIX_VIACOMBO,
 };
 };
 
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
 /* Defines for ATI HD Audio support in SB450 south bridge */
@@ -433,7 +434,6 @@ struct azx {
 	unsigned int polling_mode :1;
 	unsigned int polling_mode :1;
 	unsigned int msi :1;
 	unsigned int msi :1;
 	unsigned int irq_pending_warned :1;
 	unsigned int irq_pending_warned :1;
-	unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
 	unsigned int probing :1; /* codec probing phase */
 	unsigned int probing :1; /* codec probing phase */
 
 
 	/* for debugging */
 	/* for debugging */
@@ -458,6 +458,7 @@ enum {
 	AZX_DRIVER_ULI,
 	AZX_DRIVER_ULI,
 	AZX_DRIVER_NVIDIA,
 	AZX_DRIVER_NVIDIA,
 	AZX_DRIVER_TERA,
 	AZX_DRIVER_TERA,
+	AZX_DRIVER_CTX,
 	AZX_DRIVER_GENERIC,
 	AZX_DRIVER_GENERIC,
 	AZX_NUM_DRIVERS, /* keep this as last entry */
 	AZX_NUM_DRIVERS, /* keep this as last entry */
 };
 };
@@ -473,6 +474,7 @@ static char *driver_short_names[] __devinitdata = {
 	[AZX_DRIVER_ULI] = "HDA ULI M5461",
 	[AZX_DRIVER_ULI] = "HDA ULI M5461",
 	[AZX_DRIVER_NVIDIA] = "HDA NVidia",
 	[AZX_DRIVER_NVIDIA] = "HDA NVidia",
 	[AZX_DRIVER_TERA] = "HDA Teradici", 
 	[AZX_DRIVER_TERA] = "HDA Teradici", 
+	[AZX_DRIVER_CTX] = "HDA Creative", 
 	[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 	[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 };
 
 
@@ -563,7 +565,10 @@ static void azx_init_cmd_io(struct azx *chip)
 	/* reset the rirb hw write pointer */
 	/* reset the rirb hw write pointer */
 	azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
 	azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
 	/* set N=1, get RIRB response interrupt for new entry */
 	/* set N=1, get RIRB response interrupt for new entry */
-	azx_writew(chip, RINTCNT, 1);
+	if (chip->driver_type == AZX_DRIVER_CTX)
+		azx_writew(chip, RINTCNT, 0xc0);
+	else
+		azx_writew(chip, RINTCNT, 1);
 	/* enable rirb dma and response irq */
 	/* enable rirb dma and response irq */
 	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
 	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
 	spin_unlock_irq(&chip->reg_lock);
 	spin_unlock_irq(&chip->reg_lock);
@@ -1136,8 +1141,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
 	/* clear rirb int */
 	/* clear rirb int */
 	status = azx_readb(chip, RIRBSTS);
 	status = azx_readb(chip, RIRBSTS);
 	if (status & RIRB_INT_MASK) {
 	if (status & RIRB_INT_MASK) {
-		if (status & RIRB_INT_RESPONSE)
+		if (status & RIRB_INT_RESPONSE) {
+			if (chip->driver_type == AZX_DRIVER_CTX)
+				udelay(80);
 			azx_update_rirb(chip);
 			azx_update_rirb(chip);
+		}
 		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
 		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
 	}
 	}
 
 
@@ -1309,11 +1317,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
 	azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
 	azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
 
 
 	/* enable the position buffer */
 	/* enable the position buffer */
-	if (chip->position_fix[0] == POS_FIX_POSBUF ||
-	    chip->position_fix[0] == POS_FIX_AUTO ||
-	    chip->position_fix[1] == POS_FIX_POSBUF ||
-	    chip->position_fix[1] == POS_FIX_AUTO ||
-	    chip->via_dmapos_patch) {
+	if (chip->position_fix[0] != POS_FIX_LPIB ||
+	    chip->position_fix[1] != POS_FIX_LPIB) {
 		if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
 		if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
 			azx_writel(chip, DPLBASE,
 			azx_writel(chip, DPLBASE,
 				(u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
 				(u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
@@ -1647,7 +1652,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 	struct azx_dev *azx_dev = get_azx_dev(substream);
 	struct azx_dev *azx_dev = get_azx_dev(substream);
 	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
 	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	unsigned int bufsize, period_bytes, format_val;
+	unsigned int bufsize, period_bytes, format_val, stream_tag;
 	int err;
 	int err;
 
 
 	azx_stream_reset(chip, azx_dev);
 	azx_stream_reset(chip, azx_dev);
@@ -1689,7 +1694,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 	else
 	else
 		azx_dev->fifo_size = 0;
 		azx_dev->fifo_size = 0;
 
 
-	return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag,
+	stream_tag = azx_dev->stream_tag;
+	/* CA-IBG chips need the playback stream starting from 1 */
+	if (chip->driver_type == AZX_DRIVER_CTX &&
+	    stream_tag > chip->capture_streams)
+		stream_tag -= chip->capture_streams;
+	return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
 				     azx_dev->format_val, substream);
 				     azx_dev->format_val, substream);
 }
 }
 
 
@@ -1852,20 +1862,21 @@ static unsigned int azx_get_position(struct azx *chip,
 				     struct azx_dev *azx_dev)
 				     struct azx_dev *azx_dev)
 {
 {
 	unsigned int pos;
 	unsigned int pos;
+	int stream = azx_dev->substream->stream;
 
 
-	if (chip->via_dmapos_patch)
+	switch (chip->position_fix[stream]) {
+	case POS_FIX_LPIB:
+		/* read LPIB */
+		pos = azx_sd_readl(azx_dev, SD_LPIB);
+		break;
+	case POS_FIX_VIACOMBO:
 		pos = azx_via_get_position(chip, azx_dev);
 		pos = azx_via_get_position(chip, azx_dev);
-	else {
-		int stream = azx_dev->substream->stream;
-		if (chip->position_fix[stream] == POS_FIX_POSBUF ||
-		    chip->position_fix[stream] == POS_FIX_AUTO) {
-			/* use the position buffer */
-			pos = le32_to_cpu(*azx_dev->posbuf);
-		} else {
-			/* read LPIB */
-			pos = azx_sd_readl(azx_dev, SD_LPIB);
-		}
+		break;
+	default:
+		/* use the position buffer */
+		pos = le32_to_cpu(*azx_dev->posbuf);
 	}
 	}
+
 	if (pos >= azx_dev->bufsize)
 	if (pos >= azx_dev->bufsize)
 		pos = 0;
 		pos = 0;
 	return pos;
 	return pos;
@@ -2313,19 +2324,10 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
 	switch (fix) {
 	switch (fix) {
 	case POS_FIX_LPIB:
 	case POS_FIX_LPIB:
 	case POS_FIX_POSBUF:
 	case POS_FIX_POSBUF:
+	case POS_FIX_VIACOMBO:
 		return fix;
 		return fix;
 	}
 	}
 
 
-	/* Check VIA/ATI HD Audio Controller exist */
-	switch (chip->driver_type) {
-	case AZX_DRIVER_VIA:
-	case AZX_DRIVER_ATI:
-		chip->via_dmapos_patch = 1;
-		/* Use link position directly, avoid any transfer problem. */
-		return POS_FIX_LPIB;
-	}
-	chip->via_dmapos_patch = 0;
-
 	q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
 	q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
 	if (q) {
 	if (q) {
 		printk(KERN_INFO
 		printk(KERN_INFO
@@ -2334,6 +2336,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
 		       q->value, q->subvendor, q->subdevice);
 		       q->value, q->subvendor, q->subdevice);
 		return q->value;
 		return q->value;
 	}
 	}
+
+	/* Check VIA/ATI HD Audio Controller exist */
+	switch (chip->driver_type) {
+	case AZX_DRIVER_VIA:
+	case AZX_DRIVER_ATI:
+		/* Use link position directly, avoid any transfer problem. */
+		return POS_FIX_VIACOMBO;
+	}
+
 	return POS_FIX_AUTO;
 	return POS_FIX_AUTO;
 }
 }
 
 
@@ -2735,25 +2746,17 @@ static void __devexit azx_remove(struct pci_dev *pci)
 
 
 /* PCI IDs */
 /* PCI IDs */
 static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
 static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
-	/* ICH 6..10 */
-	{ PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH },
-	{ PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
-	{ PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
-	{ PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
-	{ PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH },
-	{ PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
-	{ PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
-	{ PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
-	{ PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
-	/* PCH */
-	{ PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
-	{ PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH },
 	/* CPT */
 	/* CPT */
 	{ 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 },
 	/* SCH */
 	/* SCH */
 	{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
 	{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
+	/* Generic Intel */
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
+	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+	  .class_mask = 0xffffff,
+	  .driver_data = AZX_DRIVER_ICH },
 	/* ATI SB 450/600 */
 	/* ATI SB 450/600 */
 	{ PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
 	{ PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
 	{ PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
 	{ PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
@@ -2794,11 +2797,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
 	{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 	  .class_mask = 0xffffff,
 	  .class_mask = 0xffffff,
-	  .driver_data = AZX_DRIVER_GENERIC },
+	  .driver_data = AZX_DRIVER_CTX },
 #else
 #else
 	/* this entry seems still valid -- i.e. without emu20kx chip */
 	/* this entry seems still valid -- i.e. without emu20kx chip */
-	{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
+	{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX },
 #endif
 #endif
+	/* Vortex86MX */
+	{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
 	/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
 	/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
 	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
 	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,

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

@@ -38,10 +38,11 @@
  */
  */
 #define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs)		\
 #define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs)		\
 	((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
 	((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
+#define HDA_AMP_VAL_MIN_MUTE (1<<29)
 #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
 #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
 	HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
 	HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
 /* mono volume with index (index=0,1,...) (channel=1,2) */
 /* mono volume with index (index=0,1,...) (channel=1,2) */
-#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
+#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, dir, flags) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
 	  .subdevice = HDA_SUBDEV_AMP_FLAG, \
 	  .subdevice = HDA_SUBDEV_AMP_FLAG, \
 	  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
 	  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
@@ -51,16 +52,20 @@
 	  .get = snd_hda_mixer_amp_volume_get, \
 	  .get = snd_hda_mixer_amp_volume_get, \
 	  .put = snd_hda_mixer_amp_volume_put, \
 	  .put = snd_hda_mixer_amp_volume_put, \
 	  .tlv = { .c = snd_hda_mixer_amp_tlv },		\
 	  .tlv = { .c = snd_hda_mixer_amp_tlv },		\
-	  .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
+	  .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, dir) | flags }
 /* stereo volume with index */
 /* stereo volume with index */
 #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
 #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
-	HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
+	HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction, 0)
 /* mono volume */
 /* mono volume */
 #define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
 #define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
-	HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction)
+	HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction, 0)
 /* stereo volume */
 /* stereo volume */
 #define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
 #define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
 	HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
 	HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
+/* stereo volume with min=mute */
+#define HDA_CODEC_VOLUME_MIN_MUTE(xname, nid, xindex, direction) \
+	HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, 3, xindex, direction, \
+				  HDA_AMP_VAL_MIN_MUTE)
 /* mono mute switch with index (index=0,1,...) (channel=1,2) */
 /* mono mute switch with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
 #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
@@ -215,7 +220,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
  */
  */
 #define HDA_MAX_NUM_INPUTS	16
 #define HDA_MAX_NUM_INPUTS	16
 struct hda_input_mux_item {
 struct hda_input_mux_item {
-	const char *label;
+	char label[32];
 	unsigned int index;
 	unsigned int index;
 };
 };
 struct hda_input_mux {
 struct hda_input_mux {
@@ -366,9 +371,7 @@ struct hda_bus_unsolicited {
 
 
 enum {
 enum {
 	AUTO_PIN_MIC,
 	AUTO_PIN_MIC,
-	AUTO_PIN_FRONT_MIC,
-	AUTO_PIN_LINE,
-	AUTO_PIN_FRONT_LINE,
+	AUTO_PIN_LINE_IN,
 	AUTO_PIN_CD,
 	AUTO_PIN_CD,
 	AUTO_PIN_AUX,
 	AUTO_PIN_AUX,
 	AUTO_PIN_LAST
 	AUTO_PIN_LAST
@@ -380,9 +383,33 @@ enum {
 	AUTO_PIN_HP_OUT
 	AUTO_PIN_HP_OUT
 };
 };
 
 
-extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST];
-
 #define AUTO_CFG_MAX_OUTS	5
 #define AUTO_CFG_MAX_OUTS	5
+#define AUTO_CFG_MAX_INS	8
+
+struct auto_pin_cfg_item {
+	hda_nid_t pin;
+	int type;
+};
+
+struct auto_pin_cfg;
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+				    int check_location);
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+					const struct auto_pin_cfg *cfg,
+					int input);
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+			  int index, int *type_index_ret);
+
+enum {
+	INPUT_PIN_ATTR_UNUSED,	/* pin not connected */
+	INPUT_PIN_ATTR_INT,	/* internal mic/line-in */
+	INPUT_PIN_ATTR_DOCK,	/* docking mic/line-in */
+	INPUT_PIN_ATTR_NORMAL,	/* mic/line-in jack */
+	INPUT_PIN_ATTR_FRONT,	/* mic/line-in jack in front */
+	INPUT_PIN_ATTR_REAR,	/* mic/line-in jack in rear */
+};
+
+int snd_hda_get_input_pin_attr(unsigned int def_conf);
 
 
 struct auto_pin_cfg {
 struct auto_pin_cfg {
 	int line_outs;
 	int line_outs;
@@ -393,7 +420,8 @@ struct auto_pin_cfg {
 	int hp_outs;
 	int hp_outs;
 	int line_out_type;	/* AUTO_PIN_XXX_OUT */
 	int line_out_type;	/* AUTO_PIN_XXX_OUT */
 	hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
 	hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
-	hda_nid_t input_pins[AUTO_PIN_LAST];
+	int num_inputs;
+	struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
 	int dig_outs;
 	int dig_outs;
 	hda_nid_t dig_out_pins[2];
 	hda_nid_t dig_out_pins[2];
 	hda_nid_t dig_in_pin;
 	hda_nid_t dig_in_pin;
@@ -558,6 +586,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 #define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
 #define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
 #define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
 #define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
 #define get_amp_offset(kc)	(((kc)->private_value >> 23) & 0x3f)
 #define get_amp_offset(kc)	(((kc)->private_value >> 23) & 0x3f)
+#define get_amp_min_mute(kc)	(((kc)->private_value >> 29) & 0x1)
 
 
 /*
 /*
  * CEA Short Audio Descriptor data
  * CEA Short Audio Descriptor data

+ 28 - 20
sound/pci/hda/patch_analog.c

@@ -1276,6 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec)
 	spec->multiout.no_share_stream = 1;
 	spec->multiout.no_share_stream = 1;
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
+	codec->no_sticky_stream = 1;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1463,6 +1464,7 @@ static int patch_ad1983(struct hda_codec *codec)
 	codec->patch_ops = ad198x_patch_ops;
 	codec->patch_ops = ad198x_patch_ops;
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
+	codec->no_sticky_stream = 1;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1917,6 +1919,7 @@ static int patch_ad1981(struct hda_codec *codec)
 	}
 	}
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
+	codec->no_sticky_stream = 1;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2880,7 +2883,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
 
 
 /* create input playback/capture controls for the given pin */
 /* create input playback/capture controls for the given pin */
 static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
 static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
-			    const char *ctlname, int boost)
+			    const char *ctlname, int ctlidx, int boost)
 {
 {
 	char name[32];
 	char name[32];
 	int err, idx;
 	int err, idx;
@@ -2909,25 +2912,27 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
 }
 }
 
 
 /* create playback/capture controls for input pins */
 /* create playback/capture controls for input pins */
-static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,
+static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 						const struct auto_pin_cfg *cfg)
 {
 {
+	struct ad198x_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux;
 	struct hda_input_mux *imux = &spec->private_imux;
-	int i, err;
-
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		err = new_analog_input(spec, cfg->input_pins[i],
-				       auto_pin_cfg_labels[i],
-				       i <= AUTO_PIN_FRONT_MIC);
+	int i, err, type, type_idx;
+
+	for (i = 0; i < cfg->num_inputs; i++) {
+		const char *label;
+		type = cfg->inputs[i].type;
+		label = hda_get_autocfg_input_label(codec, cfg, i);
+		snd_hda_add_imux_item(imux, label,
+				      ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
+				      &type_idx);
+		err = new_analog_input(spec, cfg->inputs[i].pin,
+				       label, type_idx,
+				       type == AUTO_PIN_MIC);
 		if (err < 0)
 		if (err < 0)
 			return err;
 			return err;
-		imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
-		imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
-		imux->num_items++;
 	}
 	}
-	imux->items[imux->num_items].label = "Mix";
-	imux->items[imux->num_items].index = 9;
-	imux->num_items++;
+	snd_hda_add_imux_item(imux, "Mix", 9, NULL);
 
 
 	if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
 	if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
 			       "Analog Mix Playback Volume",
 			       "Analog Mix Playback Volume",
@@ -2994,12 +2999,11 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec)
 static void ad1988_auto_init_analog_input(struct hda_codec *codec)
 static void ad1988_auto_init_analog_input(struct hda_codec *codec)
 {
 {
 	struct ad198x_spec *spec = codec->spec;
 	struct ad198x_spec *spec = codec->spec;
+	const struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i, idx;
 	int i, idx;
 
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[i];
-		if (! nid)
-			continue;
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
 		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);
@@ -3009,7 +3013,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_FRONT_MIC ? PIN_VREF80 : PIN_IN);
+				    i == 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);
@@ -3040,7 +3044,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
 						"Speaker")) < 0 ||
 						"Speaker")) < 0 ||
 	    (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
 	    (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
 						"Headphone")) < 0 ||
 						"Headphone")) < 0 ||
-	    (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
+	    (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
 		return err;
 		return err;
 
 
 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
@@ -3235,6 +3239,7 @@ static int patch_ad1988(struct hda_codec *codec)
 	spec->vmaster_nid = 0x04;
 	spec->vmaster_nid = 0x04;
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
+	codec->no_sticky_stream = 1;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -3449,6 +3454,7 @@ static int patch_ad1884(struct hda_codec *codec)
 	codec->patch_ops = ad198x_patch_ops;
 	codec->patch_ops = ad198x_patch_ops;
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
+	codec->no_sticky_stream = 1;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -4422,6 +4428,7 @@ static int patch_ad1884a(struct hda_codec *codec)
 	}
 	}
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
+	codec->no_sticky_stream = 1;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -4761,6 +4768,7 @@ static int patch_ad1882(struct hda_codec *codec)
 	}
 	}
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
+	codec->no_sticky_stream = 1;
 
 
 	return 0;
 	return 0;
 }
 }

+ 0 - 224
sound/pci/hda/patch_atihdmi.c

@@ -1,224 +0,0 @@
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for ATI HDMI codecs
- *
- * Copyright (c) 2006 ATI Technologies Inc.
- *
- *
- *  This driver is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This driver is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "hda_codec.h"
-#include "hda_local.h"
-
-struct atihdmi_spec {
-	struct hda_multi_out multiout;
-
-	struct hda_pcm pcm_rec;
-};
-
-#define CVT_NID		0x02	/* audio converter */
-#define PIN_NID		0x03	/* HDMI output pin */
-
-static struct hda_verb atihdmi_basic_init[] = {
-	/* enable digital output on pin widget */
-	{ 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{} /* terminator */
-};
-
-/*
- * Controls
- */
-static int atihdmi_build_controls(struct hda_codec *codec)
-{
-	struct atihdmi_spec *spec = codec->spec;
-	int err;
-
-	err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-static int atihdmi_init(struct hda_codec *codec)
-{
-	snd_hda_sequence_write(codec, atihdmi_basic_init);
-	/* SI codec requires to unmute the pin */
-	if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
-		snd_hda_codec_write(codec, PIN_NID, 0,
-				    AC_VERB_SET_AMP_GAIN_MUTE,
-				    AMP_OUT_UNMUTE);
-	return 0;
-}
-
-/*
- * Digital out
- */
-static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-				     struct hda_codec *codec,
-				     struct snd_pcm_substream *substream)
-{
-	struct atihdmi_spec *spec = codec->spec;
-	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-				      struct hda_codec *codec,
-				      struct snd_pcm_substream *substream)
-{
-	struct atihdmi_spec *spec = codec->spec;
-	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-					    struct hda_codec *codec,
-					    unsigned int stream_tag,
-					    unsigned int format,
-					    struct snd_pcm_substream *substream)
-{
-	struct atihdmi_spec *spec = codec->spec;
-	int chans = substream->runtime->channels;
-	int i, err;
-
-	err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-					    format, substream);
-	if (err < 0)
-		return err;
-	snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT,
-			    chans - 1);
-	/* FIXME: XXX */
-	for (i = 0; i < chans; i++) {
-		snd_hda_codec_write(codec, CVT_NID, 0,
-				    AC_VERB_SET_HDMI_CHAN_SLOT,
-				    (i << 4) | i);
-	}
-	return 0;
-}
-
-static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-	.nid = CVT_NID, /* NID to query formats and rates and setup streams */
-	.ops = {
-		.open = atihdmi_dig_playback_pcm_open,
-		.close = atihdmi_dig_playback_pcm_close,
-		.prepare = atihdmi_dig_playback_pcm_prepare
-	},
-};
-
-static int atihdmi_build_pcms(struct hda_codec *codec)
-{
-	struct atihdmi_spec *spec = codec->spec;
-	struct hda_pcm *info = &spec->pcm_rec;
-	unsigned int chans;
-
-	codec->num_pcms = 1;
-	codec->pcm_info = info;
-
-	info->name = "ATI HDMI";
-	info->pcm_type = HDA_PCM_TYPE_HDMI;
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
-
-	/* FIXME: we must check ELD and change the PCM parameters dynamically
-	 */
-	chans = get_wcaps(codec, CVT_NID);
-	chans = get_wcaps_channels(chans);
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
-
-	return 0;
-}
-
-static void atihdmi_free(struct hda_codec *codec)
-{
-	kfree(codec->spec);
-}
-
-static struct hda_codec_ops atihdmi_patch_ops = {
-	.build_controls = atihdmi_build_controls,
-	.build_pcms = atihdmi_build_pcms,
-	.init = atihdmi_init,
-	.free = atihdmi_free,
-};
-
-static int patch_atihdmi(struct hda_codec *codec)
-{
-	struct atihdmi_spec *spec;
-
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
-
-	codec->spec = spec;
-
-	spec->multiout.num_dacs = 0;	  /* no analog */
-	spec->multiout.max_channels = 2;
-	/* NID for copying analog to digital,
-	 * seems to be unused in pure-digital
-	 * case.
-	 */
-	spec->multiout.dig_out_nid = CVT_NID;
-
-	codec->patch_ops = atihdmi_patch_ops;
-
-	return 0;
-}
-
-/*
- * patch entries
- */
-static struct hda_codec_preset snd_hda_preset_atihdmi[] = {
-	{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
-	{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x17e80047, .name = "Chrontel HDMI",  .patch = patch_atihdmi },
-	{} /* terminator */
-};
-
-MODULE_ALIAS("snd-hda-codec-id:1002793c");
-MODULE_ALIAS("snd-hda-codec-id:10027919");
-MODULE_ALIAS("snd-hda-codec-id:1002791a");
-MODULE_ALIAS("snd-hda-codec-id:1002aa01");
-MODULE_ALIAS("snd-hda-codec-id:10951390");
-MODULE_ALIAS("snd-hda-codec-id:17e80047");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ATI HDMI HD-audio codec");
-
-static struct hda_codec_preset_list atihdmi_list = {
-	.preset = snd_hda_preset_atihdmi,
-	.owner = THIS_MODULE,
-};
-
-static int __init patch_atihdmi_init(void)
-{
-	return snd_hda_add_codec_preset(&atihdmi_list);
-}
-
-static void __exit patch_atihdmi_exit(void)
-{
-	snd_hda_delete_codec_preset(&atihdmi_list);
-}
-
-module_init(patch_atihdmi_init)
-module_exit(patch_atihdmi_exit)

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

@@ -468,13 +468,13 @@ static void parse_input(struct hda_codec *codec)
 			spec->dig_in = nid;
 			spec->dig_in = nid;
 			continue;
 			continue;
 		}
 		}
-		for (j = 0; j < AUTO_PIN_LAST; j++)
-			if (cfg->input_pins[j] == pin)
+		for (j = 0; j < cfg->num_inputs; j++)
+			if (cfg->inputs[j].pin == pin)
 				break;
 				break;
-		if (j >= AUTO_PIN_LAST)
+		if (j >= cfg->num_inputs)
 			continue;
 			continue;
 		spec->input_pins[n] = pin;
 		spec->input_pins[n] = pin;
-		spec->input_labels[n] = auto_pin_cfg_labels[j];
+		spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1);
 		spec->adcs[n] = nid;
 		spec->adcs[n] = nid;
 		n++;
 		n++;
 	}
 	}
@@ -489,7 +489,7 @@ static void parse_digital(struct hda_codec *codec)
 	if (cfg->dig_outs &&
 	if (cfg->dig_outs &&
 	    snd_hda_get_connections(codec, cfg->dig_out_pins[0],
 	    snd_hda_get_connections(codec, cfg->dig_out_pins[0],
 				    &spec->dig_out, 1) == 1)
 				    &spec->dig_out, 1) == 1)
-		spec->multiout.dig_out_nid = cfg->dig_out_pins[0];
+		spec->multiout.dig_out_nid = spec->dig_out;
 }
 }
 
 
 static int ca0110_parse_auto_config(struct hda_codec *codec)
 static int ca0110_parse_auto_config(struct hda_codec *codec)

+ 70 - 24
sound/pci/hda/patch_cirrus.c

@@ -65,6 +65,7 @@ struct cs_spec {
 
 
 /* available models */
 /* available models */
 enum {
 enum {
+	CS420X_MBP53,
 	CS420X_MBP55,
 	CS420X_MBP55,
 	CS420X_IMAC27,
 	CS420X_IMAC27,
 	CS420X_AUTO,
 	CS420X_AUTO,
@@ -329,12 +330,12 @@ 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->input_pins[idx];
+	hda_nid_t pin = cfg->inputs[idx].pin;
 	unsigned int val = snd_hda_query_pin_caps(codec, pin);
 	unsigned int val = snd_hda_query_pin_caps(codec, pin);
 	if (!(val & AC_PINCAP_PRES_DETECT))
 	if (!(val & AC_PINCAP_PRES_DETECT))
 		return 0;
 		return 0;
 	val = snd_hda_codec_get_pincfg(codec, pin);
 	val = snd_hda_codec_get_pincfg(codec, pin);
-	return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX);
+	return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT);
 }
 }
 
 
 static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
 static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
@@ -424,10 +425,8 @@ static int parse_input(struct hda_codec *codec)
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i;
 	int i;
 
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t pin = cfg->input_pins[i];
-		if (!pin)
-			continue;
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t pin = cfg->inputs[i].pin;
 		spec->input_idx[spec->num_inputs] = i;
 		spec->input_idx[spec->num_inputs] = i;
 		spec->capsrc_idx[i] = spec->num_inputs++;
 		spec->capsrc_idx[i] = spec->num_inputs++;
 		spec->cur_input = i;
 		spec->cur_input = i;
@@ -438,16 +437,17 @@ static int parse_input(struct hda_codec *codec)
 
 
 	/* check whether the automatic mic switch is available */
 	/* check whether the automatic mic switch is available */
 	if (spec->num_inputs == 2 &&
 	if (spec->num_inputs == 2 &&
-	    spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) {
-		if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) {
-			if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+	    cfg->inputs[0].type == AUTO_PIN_MIC &&
+	    cfg->inputs[1].type == AUTO_PIN_MIC) {
+		if (is_ext_mic(codec, cfg->inputs[0].pin)) {
+			if (!is_ext_mic(codec, cfg->inputs[1].pin)) {
 				spec->mic_detect = 1;
 				spec->mic_detect = 1;
-				spec->automic_idx = AUTO_PIN_FRONT_MIC;
+				spec->automic_idx = 0;
 			}
 			}
 		} else {
 		} else {
-			if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+			if (is_ext_mic(codec, cfg->inputs[1].pin)) {
 				spec->mic_detect = 1;
 				spec->mic_detect = 1;
-				spec->automic_idx = AUTO_PIN_MIC;
+				spec->automic_idx = 1;
 			}
 			}
 		}
 		}
 	}
 	}
@@ -674,6 +674,7 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
 {
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct cs_spec *spec = codec->spec;
 	struct cs_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
 	unsigned int idx;
 	unsigned int idx;
 
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -682,7 +683,8 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
 	if (uinfo->value.enumerated.item >= spec->num_inputs)
 	if (uinfo->value.enumerated.item >= spec->num_inputs)
 		uinfo->value.enumerated.item = spec->num_inputs - 1;
 		uinfo->value.enumerated.item = spec->num_inputs - 1;
 	idx = spec->input_idx[uinfo->value.enumerated.item];
 	idx = spec->input_idx[uinfo->value.enumerated.item];
-	strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]);
+	strcpy(uinfo->value.enumerated.name,
+	       hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1));
 	return 0;
 	return 0;
 }
 }
 
 
@@ -740,6 +742,27 @@ static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
 	return bind;
 	return bind;
 }
 }
 
 
+/* add a (input-boost) volume control to the given input pin */
+static int add_input_volume_control(struct hda_codec *codec,
+				    struct auto_pin_cfg *cfg,
+				    int item)
+{
+	hda_nid_t pin = cfg->inputs[item].pin;
+	u32 caps;
+	const char *label;
+	struct snd_kcontrol *kctl;
+		
+	if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP))
+		return 0;
+	caps = query_amp_caps(codec, pin, HDA_INPUT);
+	caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+	if (caps <= 1)
+		return 0;
+	label = hda_get_autocfg_input_label(codec, cfg, item);
+	return add_volume(codec, label, 0,
+			  HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl);
+}
+
 static int build_input(struct hda_codec *codec)
 static int build_input(struct hda_codec *codec)
 {
 {
 	struct cs_spec *spec = codec->spec;
 	struct cs_spec *spec = codec->spec;
@@ -779,6 +802,12 @@ static int build_input(struct hda_codec *codec)
 			return err;
 			return err;
 	}
 	}
 
 
+	for (i = 0; i < spec->num_inputs; i++) {
+		err = add_input_volume_control(codec, &spec->autocfg, i);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -838,7 +867,8 @@ static void cs_automute(struct hda_codec *codec)
 				    AC_VERB_SET_PIN_WIDGET_CONTROL,
 				    AC_VERB_SET_PIN_WIDGET_CONTROL,
 				    hp_present ? 0 : PIN_OUT);
 				    hp_present ? 0 : PIN_OUT);
 	}
 	}
-	if (spec->board_config == CS420X_MBP55 ||
+	if (spec->board_config == CS420X_MBP53 ||
+	    spec->board_config == CS420X_MBP55 ||
 	    spec->board_config == CS420X_IMAC27) {
 	    spec->board_config == CS420X_IMAC27) {
 		unsigned int gpio = hp_present ? 0x02 : 0x08;
 		unsigned int gpio = hp_present ? 0x02 : 0x08;
 		snd_hda_codec_write(codec, 0x01, 0,
 		snd_hda_codec_write(codec, 0x01, 0,
@@ -853,15 +883,12 @@ static void cs_automic(struct hda_codec *codec)
 	hda_nid_t nid;
 	hda_nid_t nid;
 	unsigned int present;
 	unsigned int present;
 	
 	
-	nid = cfg->input_pins[spec->automic_idx];
+	nid = cfg->inputs[spec->automic_idx].pin;
 	present = snd_hda_jack_detect(codec, nid);
 	present = snd_hda_jack_detect(codec, nid);
 	if (present)
 	if (present)
 		change_cur_input(codec, spec->automic_idx, 0);
 		change_cur_input(codec, spec->automic_idx, 0);
-	else {
-		unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ?
-			AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC;
-		change_cur_input(codec, imic, 0);
-	}
+	else
+		change_cur_input(codec, !spec->automic_idx, 0);
 }
 }
 
 
 /*
 /*
@@ -918,14 +945,14 @@ static void init_input(struct hda_codec *codec)
 	unsigned int coef;
 	unsigned int coef;
 	int i;
 	int i;
 
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
+	for (i = 0; i < cfg->num_inputs; i++) {
 		unsigned int ctl;
 		unsigned int ctl;
-		hda_nid_t pin = cfg->input_pins[i];
-		if (!pin || !spec->adc_nid[i])
+		hda_nid_t pin = cfg->inputs[i].pin;
+		if (!spec->adc_nid[i])
 			continue;
 			continue;
 		/* set appropriate pin control and mute first */
 		/* set appropriate pin control and mute first */
 		ctl = PIN_IN;
 		ctl = PIN_IN;
-		if (i <= AUTO_PIN_FRONT_MIC) {
+		if (cfg->inputs[i].type == AUTO_PIN_MIC) {
 			unsigned int caps = snd_hda_query_pin_caps(codec, pin);
 			unsigned int caps = snd_hda_query_pin_caps(codec, pin);
 			caps >>= AC_PINCAP_VREF_SHIFT;
 			caps >>= AC_PINCAP_VREF_SHIFT;
 			if (caps & AC_PINCAP_VREF_80)
 			if (caps & AC_PINCAP_VREF_80)
@@ -1130,6 +1157,7 @@ static int cs_parse_auto_config(struct hda_codec *codec)
 }
 }
 
 
 static const char *cs420x_models[CS420X_MODELS] = {
 static const char *cs420x_models[CS420X_MODELS] = {
+	[CS420X_MBP53] = "mbp53",
 	[CS420X_MBP55] = "mbp55",
 	[CS420X_MBP55] = "mbp55",
 	[CS420X_IMAC27] = "imac27",
 	[CS420X_IMAC27] = "imac27",
 	[CS420X_AUTO] = "auto",
 	[CS420X_AUTO] = "auto",
@@ -1137,7 +1165,9 @@ static const char *cs420x_models[CS420X_MODELS] = {
 
 
 
 
 static struct snd_pci_quirk cs420x_cfg_tbl[] = {
 static struct snd_pci_quirk cs420x_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
 	SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
 	SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
+	SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
 	SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
 	SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
 	{} /* terminator */
 	{} /* terminator */
 };
 };
@@ -1147,6 +1177,20 @@ struct cs_pincfg {
 	u32 val;
 	u32 val;
 };
 };
 
 
+static struct cs_pincfg mbp53_pincfgs[] = {
+	{ 0x09, 0x012b4050 },
+	{ 0x0a, 0x90100141 },
+	{ 0x0b, 0x90100140 },
+	{ 0x0c, 0x018b3020 },
+	{ 0x0d, 0x90a00110 },
+	{ 0x0e, 0x400000f0 },
+	{ 0x0f, 0x01cbe030 },
+	{ 0x10, 0x014be060 },
+	{ 0x12, 0x400000f0 },
+	{ 0x15, 0x400000f0 },
+	{} /* terminator */
+};
+
 static struct cs_pincfg mbp55_pincfgs[] = {
 static struct cs_pincfg mbp55_pincfgs[] = {
 	{ 0x09, 0x012b4030 },
 	{ 0x09, 0x012b4030 },
 	{ 0x0a, 0x90100121 },
 	{ 0x0a, 0x90100121 },
@@ -1176,6 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = {
 };
 };
 
 
 static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
 static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
+	[CS420X_MBP53] = mbp53_pincfgs,
 	[CS420X_MBP55] = mbp55_pincfgs,
 	[CS420X_MBP55] = mbp55_pincfgs,
 	[CS420X_IMAC27] = imac27_pincfgs,
 	[CS420X_IMAC27] = imac27_pincfgs,
 };
 };
@@ -1208,6 +1253,7 @@ static int patch_cs420x(struct hda_codec *codec)
 
 
 	switch (spec->board_config) {
 	switch (spec->board_config) {
 	case CS420X_IMAC27:
 	case CS420X_IMAC27:
+	case CS420X_MBP53:
 	case CS420X_MBP55:
 	case CS420X_MBP55:
 		/* GPIO1 = headphones */
 		/* GPIO1 = headphones */
 		/* GPIO3 = speakers */
 		/* GPIO3 = speakers */

Some files were not shown because too many files changed in this diff