Prechádzať zdrojové kódy

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: (250 commits)
  ALSA: hda: Storage class should be before const qualifier
  ASoC: tpa6130a2: Remove CPVSS and HPVdd supplies
  ASoC: tpa6130a2: Define output pins with SND_SOC_DAPM_OUTPUT
  ASoC: sdp4430 - add sdp4430 pcm ops to DAI.
  ASoC: TWL6040: Enable earphone path in codec
  ASoC: SDP4430: Add support for Earphone speaker
  ASoC: SDP4430: Add sdp4430 machine driver
  ASoC: tlv320dac33: Avoid powering off while in BIAS_OFF
  ASoC: tlv320dac33: Use dev_dbg in dac33_hard_power function
  ALSA: sound/pci/asihpi: Use kzalloc
  ALSA: hdmi - dont fail on extra nodes
  ALSA: intelhdmi - add id for the CougarPoint chipset
  ALSA: intelhdmi - user friendly codec name
  ALSA: intelhdmi - add dependency on SND_DYNAMIC_MINORS
  ALSA: asihpi: incorrect range check
  ALSA: asihpi: testing the wrong variable
  ALSA: es1688: add pedantic range checks
  ARM: McBSP: Add support for omap4 in McBSP driver
  ARM: McBSP: Fix request for irq in OMAP4
  OMAP: McBSP: Add 32-bit mode support
  ...
Linus Torvalds 15 rokov pred
rodič
commit
7f06a8b26a
100 zmenil súbory, kde vykonal 22016 pridanie a 1033 odobranie
  1. 17 10
      Documentation/DocBook/writing-an-alsa-driver.tmpl
  2. 18 13
      Documentation/sound/alsa/ALSA-Configuration.txt
  3. 3 1
      Documentation/sound/alsa/HD-Audio.txt
  4. 4 0
      arch/arm/mach-davinci/board-dm365-evm.c
  5. 4 8
      arch/arm/mach-omap2/mcbsp.c
  6. 0 3
      arch/arm/mach-s3c2412/dma.c
  7. 6 0
      arch/arm/plat-omap/include/plat/mcbsp.h
  8. 74 15
      arch/arm/plat-omap/mcbsp.c
  9. 12 0
      drivers/gpio/wm8994-gpio.c
  10. 6 2
      drivers/mfd/Kconfig
  11. 2 1
      drivers/mfd/Makefile
  12. 190 0
      drivers/mfd/davinci_voicecodec.c
  13. 2 2
      drivers/mfd/twl-core.c
  14. 30 0
      drivers/mfd/wm831x-irq.c
  15. 40 3
      drivers/mfd/wm8994-core.c
  16. 310 0
      drivers/mfd/wm8994-irq.c
  17. 3 3
      include/linux/i2c/twl.h
  18. 126 0
      include/linux/mfd/davinci_voicecodec.h
  19. 2 0
      include/linux/mfd/wm8350/audio.h
  20. 52 1
      include/linux/mfd/wm8994/core.h
  21. 1 0
      include/linux/mfd/wm8994/pdata.h
  22. 378 0
      include/linux/usb/audio-v2.h
  23. 173 54
      include/linux/usb/audio.h
  24. 10 10
      include/sound/asound.h
  25. 6 5
      include/sound/es1688.h
  26. 12 12
      include/sound/info.h
  27. 8 0
      include/sound/jack.h
  28. 6 1
      include/sound/soc-dai.h
  29. 5 3
      include/sound/soc-dapm.h
  30. 46 15
      include/sound/soc.h
  31. 17 0
      include/sound/tlv320aic3x.h
  32. 1 0
      include/sound/tlv320dac33-plat.h
  33. 1 0
      include/sound/uda134x.h
  34. 1 1
      include/sound/version.h
  35. 249 0
      include/sound/wm8903.h
  36. 108 2
      include/sound/wm8904.h
  37. 24 0
      include/sound/wm8960.h
  38. 28 0
      include/sound/wm9090.h
  39. 1 1
      sound/atmel/Kconfig
  40. 266 89
      sound/atmel/ac97c.c
  41. 5 0
      sound/core/control.c
  42. 43 31
      sound/core/info.c
  43. 65 6
      sound/core/jack.c
  44. 5 0
      sound/core/oss/mixer_oss.c
  45. 5 0
      sound/core/oss/pcm_oss.c
  46. 32 17
      sound/core/pcm_native.c
  47. 5 0
      sound/core/rawmidi.c
  48. 6 0
      sound/core/seq/seq_clientmgr.c
  49. 38 35
      sound/core/sound.c
  50. 6 0
      sound/core/timer.c
  51. 25 58
      sound/drivers/opl4/opl4_proc.c
  52. 12 6
      sound/i2c/i2c.c
  53. 2 14
      sound/isa/Kconfig
  54. 190 35
      sound/isa/es1688/es1688.c
  55. 16 31
      sound/isa/es1688/es1688_lib.c
  56. 8 40
      sound/isa/gus/gus_mem_proc.c
  57. 14 12
      sound/isa/gus/gusextreme.c
  58. 0 2
      sound/isa/sb/Makefile
  59. 0 248
      sound/isa/sb/es968.c
  60. 32 0
      sound/pci/Kconfig
  61. 1 0
      sound/pci/Makefile
  62. 5 0
      sound/pci/asihpi/Makefile
  63. 3002 0
      sound/pci/asihpi/asihpi.c
  64. 2001 0
      sound/pci/asihpi/hpi.h
  65. 1840 0
      sound/pci/asihpi/hpi6000.c
  66. 70 0
      sound/pci/asihpi/hpi6000.h
  67. 2331 0
      sound/pci/asihpi/hpi6205.c
  68. 93 0
      sound/pci/asihpi/hpi6205.h
  69. 1641 0
      sound/pci/asihpi/hpi_internal.h
  70. 643 0
      sound/pci/asihpi/hpicmn.c
  71. 64 0
      sound/pci/asihpi/hpicmn.h
  72. 225 0
      sound/pci/asihpi/hpidebug.c
  73. 385 0
      sound/pci/asihpi/hpidebug.h
  74. 172 0
      sound/pci/asihpi/hpidspcd.c
  75. 104 0
      sound/pci/asihpi/hpidspcd.h
  76. 3864 0
      sound/pci/asihpi/hpifunc.c
  77. 130 0
      sound/pci/asihpi/hpimsginit.c
  78. 40 0
      sound/pci/asihpi/hpimsginit.h
  79. 907 0
      sound/pci/asihpi/hpimsgx.c
  80. 36 0
      sound/pci/asihpi/hpimsgx.h
  81. 484 0
      sound/pci/asihpi/hpioctl.c
  82. 38 0
      sound/pci/asihpi/hpioctl.h
  83. 114 0
      sound/pci/asihpi/hpios.c
  84. 178 0
      sound/pci/asihpi/hpios.h
  85. 37 0
      sound/pci/asihpi/hpipcida.h
  86. 14 26
      sound/pci/cs4281.c
  87. 7 12
      sound/pci/cs46xx/cs46xx_lib.c
  88. 24 27
      sound/pci/emu10k1/emuproc.c
  89. 119 10
      sound/pci/es1968.c
  90. 1 0
      sound/pci/hda/Kconfig
  91. 63 13
      sound/pci/hda/hda_codec.c
  92. 3 0
      sound/pci/hda/hda_codec.h
  93. 63 46
      sound/pci/hda/hda_intel.c
  94. 17 4
      sound/pci/hda/patch_analog.c
  95. 152 5
      sound/pci/hda/patch_conexant.c
  96. 4 6
      sound/pci/hda/patch_hdmi.c
  97. 12 9
      sound/pci/hda/patch_intelhdmi.c
  98. 184 54
      sound/pci/hda/patch_realtek.c
  99. 64 25
      sound/pci/ice1712/aureon.c
  100. 133 6
      sound/pci/maestro3.c

+ 17 - 10
Documentation/DocBook/writing-an-alsa-driver.tmpl

@@ -5518,34 +5518,41 @@ struct _snd_pcm_runtime {
 ]]>
 ]]>
         </programlisting>
         </programlisting>
       </informalexample>
       </informalexample>
+
+      For the raw data, <structfield>size</structfield> field must be
+      set properly.  This specifies the maximum size of the proc file access.
     </para>
     </para>
 
 
     <para>
     <para>
-      The callback is much more complicated than the text-file
-      version. You need to use a low-level I/O functions such as
+      The read/write callbacks of raw mode are more direct than the text mode.
+      You need to use a low-level I/O functions such as
       <function>copy_from/to_user()</function> to transfer the
       <function>copy_from/to_user()</function> to transfer the
       data.
       data.
 
 
       <informalexample>
       <informalexample>
         <programlisting>
         <programlisting>
 <![CDATA[
 <![CDATA[
-  static long my_file_io_read(struct snd_info_entry *entry,
+  static ssize_t my_file_io_read(struct snd_info_entry *entry,
                               void *file_private_data,
                               void *file_private_data,
                               struct file *file,
                               struct file *file,
                               char *buf,
                               char *buf,
-                              unsigned long count,
-                              unsigned long pos)
+                              size_t count,
+                              loff_t pos)
   {
   {
-          long size = count;
-          if (pos + size > local_max_size)
-                  size = local_max_size - pos;
-          if (copy_to_user(buf, local_data + pos, size))
+          if (copy_to_user(buf, local_data + pos, count))
                   return -EFAULT;
                   return -EFAULT;
-          return size;
+          return count;
   }
   }
 ]]>
 ]]>
         </programlisting>
         </programlisting>
       </informalexample>
       </informalexample>
+
+      If the size of the info entry has been set up properly,
+      <structfield>count</structfield> and <structfield>pos</structfield> are
+      guaranteed to fit within 0 and the given size.
+      You don't have to check the range in the callbacks unless any
+      other condition is required.
+
     </para>
     </para>
 
 
   </chapter>
   </chapter>

+ 18 - 13
Documentation/sound/alsa/ALSA-Configuration.txt

@@ -227,6 +227,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
 
     The power-management is supported.
     The power-management is supported.
 
 
+  Module snd-asihpi
+  -----------------
+
+    Module for AudioScience ASI soundcards
+
+    enable_hpi_hwdep	- enable HPI hwdep for AudioScience soundcard
+
+    This module supports multiple cards.
+    The driver requires the firmware loader support on kernel.
+
   Module snd-atiixp
   Module snd-atiixp
   -----------------
   -----------------
 
 
@@ -622,28 +632,23 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     
     
     The power-management is supported.
     The power-management is supported.
 
 
-  Module snd-es968
-  ----------------
-
-    Module for sound cards based on ESS ES968 chip (PnP only).
-
-    This module supports multiple cards, PnP and autoprobe.
-    
-    The power-management is supported.
-
   Module snd-es1688
   Module snd-es1688
   -----------------
   -----------------
 
 
     Module for ESS AudioDrive ES-1688 and ES-688 sound cards.
     Module for ESS AudioDrive ES-1688 and ES-688 sound cards.
 
 
-    port	- port # for ES-1688 chip (0x220,0x240,0x260)
-    fm_port	- port # for OPL3 (option; share the same port as default)
+    isapnp	- ISA PnP detection - 0 = disable, 1 = enable (default)
     mpu_port	- port # for MPU-401 port (0x300,0x310,0x320,0x330), -1 = disable (default)
     mpu_port	- port # for MPU-401 port (0x300,0x310,0x320,0x330), -1 = disable (default)
-    irq		- IRQ # for ES-1688 chip (5,7,9,10)
     mpu_irq	- IRQ # for MPU-401 port (5,7,9,10)
     mpu_irq	- IRQ # for MPU-401 port (5,7,9,10)
+    fm_port	- port # for OPL3 (option; share the same port as default)
+
+    with isapnp=0, the following additional options are available:
+    port	- port # for ES-1688 chip (0x220,0x240,0x260)
+    irq		- IRQ # for ES-1688 chip (5,7,9,10)
     dma8	- DMA # for ES-1688 chip (0,1,3)
     dma8	- DMA # for ES-1688 chip (0,1,3)
 
 
-    This module supports multiple cards and autoprobe (without MPU-401 port).
+    This module supports multiple cards and autoprobe (without MPU-401 port)
+    and PnP with the ES968 chip.
 
 
   Module snd-es18xx
   Module snd-es18xx
   -----------------
   -----------------

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

@@ -204,7 +204,6 @@ generic parser regardless of the codec.  Usually the codec-specific
 parser is much better than the generic parser (as now).  Thus this
 parser is much better than the generic parser (as now).  Thus this
 option is more about the debugging purpose.
 option is more about the debugging purpose.
 
 
-
 Speaker and Headphone Output
 Speaker and Headphone Output
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 One of the most frequent (and obvious) bugs with HD-audio is the
 One of the most frequent (and obvious) bugs with HD-audio is the
@@ -600,6 +599,9 @@ probing, the proc file is available, so you can get the raw codec
 information before modified by the driver.  Of course, the driver
 information before modified by the driver.  Of course, the driver
 isn't usable with `probe_only=1`.  But you can continue the
 isn't usable with `probe_only=1`.  But you can continue the
 configuration via hwdep sysfs file if hda-reconfig option is enabled.
 configuration via hwdep sysfs file if hda-reconfig option is enabled.
+Using `probe_only` mask 2 skips the reset of HDA codecs (use
+`probe_only=3` as module option). The hwdep interface can be used
+to determine the BIOS codec initialization.
 
 
 
 
 hda-verb
 hda-verb

+ 4 - 0
arch/arm/mach-davinci/board-dm365-evm.c

@@ -600,7 +600,11 @@ static __init void dm365_evm_init(void)
 	/* maybe setup mmc1/etc ... _after_ mmc0 */
 	/* maybe setup mmc1/etc ... _after_ mmc0 */
 	evm_init_cpld();
 	evm_init_cpld();
 
 
+#ifdef CONFIG_SND_DM365_AIC3X_CODEC
 	dm365_init_asp(&dm365_evm_snd_data);
 	dm365_init_asp(&dm365_evm_snd_data);
+#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
+	dm365_init_vc(&dm365_evm_snd_data);
+#endif
 	dm365_init_rtc();
 	dm365_init_rtc();
 	dm365_init_ks(&dm365evm_ks_data);
 	dm365_init_ks(&dm365evm_ks_data);
 
 

+ 4 - 8
arch/arm/mach-omap2/mcbsp.c

@@ -187,32 +187,28 @@ static struct omap_mcbsp_platform_data omap44xx_mcbsp_pdata[] = {
 		.phys_base      = OMAP44XX_MCBSP1_BASE,
 		.phys_base      = OMAP44XX_MCBSP1_BASE,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP1_RX,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP1_RX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP1_TX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP1_TX,
-		.rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
-		.tx_irq         = INT_24XX_MCBSP1_IRQ_TX,
+		.tx_irq         = OMAP44XX_IRQ_MCBSP1,
 		.ops            = &omap2_mcbsp_ops,
 		.ops            = &omap2_mcbsp_ops,
 	},
 	},
 	{
 	{
 		.phys_base      = OMAP44XX_MCBSP2_BASE,
 		.phys_base      = OMAP44XX_MCBSP2_BASE,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP2_RX,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP2_RX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP2_TX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP2_TX,
-		.rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
-		.tx_irq         = INT_24XX_MCBSP2_IRQ_TX,
+		.tx_irq         = OMAP44XX_IRQ_MCBSP2,
 		.ops            = &omap2_mcbsp_ops,
 		.ops            = &omap2_mcbsp_ops,
 	},
 	},
 	{
 	{
 		.phys_base      = OMAP44XX_MCBSP3_BASE,
 		.phys_base      = OMAP44XX_MCBSP3_BASE,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP3_RX,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP3_RX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP3_TX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP3_TX,
-		.rx_irq         = INT_24XX_MCBSP3_IRQ_RX,
-		.tx_irq         = INT_24XX_MCBSP3_IRQ_TX,
+		.tx_irq         = OMAP44XX_IRQ_MCBSP3,
 		.ops            = &omap2_mcbsp_ops,
 		.ops            = &omap2_mcbsp_ops,
 	},
 	},
 	{
 	{
 		.phys_base      = OMAP44XX_MCBSP4_BASE,
 		.phys_base      = OMAP44XX_MCBSP4_BASE,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP4_RX,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP4_RX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP4_TX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP4_TX,
-		.rx_irq         = INT_24XX_MCBSP4_IRQ_RX,
-		.tx_irq         = INT_24XX_MCBSP4_IRQ_TX,
+		.tx_irq         = OMAP44XX_IRQ_MCBSP4,
 		.ops            = &omap2_mcbsp_ops,
 		.ops            = &omap2_mcbsp_ops,
 	},
 	},
 };
 };

+ 0 - 3
arch/arm/mach-s3c2412/dma.c

@@ -30,7 +30,6 @@
 #include <mach/regs-mem.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
 #include <mach/regs-sdi.h>
-#include <plat/regs-s3c2412-iis.h>
 #include <plat/regs-iis.h>
 #include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 #include <plat/regs-spi.h>
 
 
@@ -119,13 +118,11 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
 		.name		= "i2s-sdi",
 		.name		= "i2s-sdi",
 		.channels	= MAP(S3C2412_DMAREQSEL_I2SRX),
 		.channels	= MAP(S3C2412_DMAREQSEL_I2SRX),
 		.channels_rx	= MAP(S3C2412_DMAREQSEL_I2SRX),
 		.channels_rx	= MAP(S3C2412_DMAREQSEL_I2SRX),
-		.hw_addr.from	= S3C2410_PA_IIS + S3C2412_IISRXD,
 	},
 	},
 	[DMACH_I2S_OUT] = {
 	[DMACH_I2S_OUT] = {
 		.name		= "i2s-sdo",
 		.name		= "i2s-sdo",
 		.channels	= MAP(S3C2412_DMAREQSEL_I2STX),
 		.channels	= MAP(S3C2412_DMAREQSEL_I2STX),
 		.channels_rx	= MAP(S3C2412_DMAREQSEL_I2STX),
 		.channels_rx	= MAP(S3C2412_DMAREQSEL_I2STX),
-		.hw_addr.to	= S3C2410_PA_IIS + S3C2412_IISTXD,
 	},
 	},
 	[DMACH_USB_EP1] = {
 	[DMACH_USB_EP1] = {
 		.name		= "usb-ep1",
 		.name		= "usb-ep1",

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

@@ -149,6 +149,8 @@
 #define OMAP_MCBSP_REG_WAKEUPEN	0xA8
 #define OMAP_MCBSP_REG_WAKEUPEN	0xA8
 #define OMAP_MCBSP_REG_XCCR	0xAC
 #define OMAP_MCBSP_REG_XCCR	0xAC
 #define OMAP_MCBSP_REG_RCCR	0xB0
 #define OMAP_MCBSP_REG_RCCR	0xB0
+#define OMAP_MCBSP_REG_XBUFFSTAT	0xB4
+#define OMAP_MCBSP_REG_RBUFFSTAT	0xB8
 #define OMAP_MCBSP_REG_SSELCR	0xBC
 #define OMAP_MCBSP_REG_SSELCR	0xBC
 
 
 #define OMAP_ST_REG_REV		0x00
 #define OMAP_ST_REG_REV		0x00
@@ -471,6 +473,8 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold);
 void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold);
 void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold);
 u16 omap_mcbsp_get_max_tx_threshold(unsigned int id);
 u16 omap_mcbsp_get_max_tx_threshold(unsigned int id);
 u16 omap_mcbsp_get_max_rx_threshold(unsigned int id);
 u16 omap_mcbsp_get_max_rx_threshold(unsigned int id);
+u16 omap_mcbsp_get_tx_delay(unsigned int id);
+u16 omap_mcbsp_get_rx_delay(unsigned int id);
 int omap_mcbsp_get_dma_op_mode(unsigned int id);
 int omap_mcbsp_get_dma_op_mode(unsigned int id);
 #else
 #else
 static inline void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
 static inline void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
@@ -479,6 +483,8 @@ static inline void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
 { }
 { }
 static inline u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) { return 0; }
 static inline u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) { return 0; }
 static inline u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) { return 0; }
 static inline u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) { return 0; }
+static inline u16 omap_mcbsp_get_tx_delay(unsigned int id) { return 0; }
+static inline u16 omap_mcbsp_get_rx_delay(unsigned int id) { return 0; }
 static inline int omap_mcbsp_get_dma_op_mode(unsigned int id) { return 0; }
 static inline int omap_mcbsp_get_dma_op_mode(unsigned int id) { return 0; }
 #endif
 #endif
 int omap_mcbsp_request(unsigned int id);
 int omap_mcbsp_request(unsigned int id);

+ 74 - 15
arch/arm/plat-omap/mcbsp.c

@@ -489,7 +489,7 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
 {
 {
 	struct omap_mcbsp *mcbsp;
 	struct omap_mcbsp *mcbsp;
 
 
-	if (!cpu_is_omap34xx())
+	if (!cpu_is_omap34xx() && !cpu_is_omap44xx())
 		return;
 		return;
 
 
 	if (!omap_mcbsp_check_valid_id(id)) {
 	if (!omap_mcbsp_check_valid_id(id)) {
@@ -511,7 +511,7 @@ void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
 {
 {
 	struct omap_mcbsp *mcbsp;
 	struct omap_mcbsp *mcbsp;
 
 
-	if (!cpu_is_omap34xx())
+	if (!cpu_is_omap34xx() && !cpu_is_omap44xx())
 		return;
 		return;
 
 
 	if (!omap_mcbsp_check_valid_id(id)) {
 	if (!omap_mcbsp_check_valid_id(id)) {
@@ -560,6 +560,61 @@ u16 omap_mcbsp_get_max_rx_threshold(unsigned int id)
 }
 }
 EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold);
 EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold);
 
 
+#define MCBSP2_FIFO_SIZE	0x500 /* 1024 + 256 locations */
+#define MCBSP1345_FIFO_SIZE	0x80  /* 128 locations */
+/*
+ * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
+ */
+u16 omap_mcbsp_get_tx_delay(unsigned int id)
+{
+	struct omap_mcbsp *mcbsp;
+	u16 buffstat;
+
+	if (!omap_mcbsp_check_valid_id(id)) {
+		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+		return -ENODEV;
+	}
+	mcbsp = id_to_mcbsp_ptr(id);
+
+	/* Returns the number of free locations in the buffer */
+	buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
+
+	/* Number of slots are different in McBSP ports */
+	if (mcbsp->id == 2)
+		return MCBSP2_FIFO_SIZE - buffstat;
+	else
+		return MCBSP1345_FIFO_SIZE - buffstat;
+}
+EXPORT_SYMBOL(omap_mcbsp_get_tx_delay);
+
+/*
+ * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
+ * to reach the threshold value (when the DMA will be triggered to read it)
+ */
+u16 omap_mcbsp_get_rx_delay(unsigned int id)
+{
+	struct omap_mcbsp *mcbsp;
+	u16 buffstat, threshold;
+
+	if (!omap_mcbsp_check_valid_id(id)) {
+		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+		return -ENODEV;
+	}
+	mcbsp = id_to_mcbsp_ptr(id);
+
+	/* Returns the number of used locations in the buffer */
+	buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
+	/* RX threshold */
+	threshold = MCBSP_READ(mcbsp, THRSH1);
+
+	/* Return the number of location till we reach the threshold limit */
+	if (threshold <= buffstat)
+		return 0;
+	else
+		return threshold - buffstat;
+}
+EXPORT_SYMBOL(omap_mcbsp_get_rx_delay);
+
 /*
 /*
  * omap_mcbsp_get_dma_op_mode just return the current configured
  * omap_mcbsp_get_dma_op_mode just return the current configured
  * operating mode for the mcbsp channel
  * operating mode for the mcbsp channel
@@ -587,7 +642,7 @@ static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp)
 	 * Enable wakup behavior, smart idle and all wakeups
 	 * Enable wakup behavior, smart idle and all wakeups
 	 * REVISIT: some wakeups may be unnecessary
 	 * REVISIT: some wakeups may be unnecessary
 	 */
 	 */
-	if (cpu_is_omap34xx()) {
+	if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		u16 syscon;
 		u16 syscon;
 
 
 		syscon = MCBSP_READ(mcbsp, SYSCON);
 		syscon = MCBSP_READ(mcbsp, SYSCON);
@@ -610,7 +665,7 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp)
 	/*
 	/*
 	 * Disable wakup behavior, smart idle and all wakeups
 	 * Disable wakup behavior, smart idle and all wakeups
 	 */
 	 */
-	if (cpu_is_omap34xx()) {
+	if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		u16 syscon;
 		u16 syscon;
 
 
 		syscon = MCBSP_READ(mcbsp, SYSCON);
 		syscon = MCBSP_READ(mcbsp, SYSCON);
@@ -724,14 +779,17 @@ int omap_mcbsp_request(unsigned int id)
 			goto err_clk_disable;
 			goto err_clk_disable;
 		}
 		}
 
 
-		init_completion(&mcbsp->rx_irq_completion);
-		err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler,
+		if (mcbsp->rx_irq) {
+			init_completion(&mcbsp->rx_irq_completion);
+			err = request_irq(mcbsp->rx_irq,
+					omap_mcbsp_rx_irq_handler,
 					0, "McBSP", (void *)mcbsp);
 					0, "McBSP", (void *)mcbsp);
-		if (err != 0) {
-			dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
-					"for McBSP%d\n", mcbsp->rx_irq,
-					mcbsp->id);
-			goto err_free_irq;
+			if (err != 0) {
+				dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
+						"for McBSP%d\n", mcbsp->rx_irq,
+						mcbsp->id);
+				goto err_free_irq;
+			}
 		}
 		}
 	}
 	}
 
 
@@ -781,7 +839,8 @@ void omap_mcbsp_free(unsigned int id)
 
 
 	if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) {
 	if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) {
 		/* Free IRQs */
 		/* Free IRQs */
-		free_irq(mcbsp->rx_irq, (void *)mcbsp);
+		if (mcbsp->rx_irq)
+			free_irq(mcbsp->rx_irq, (void *)mcbsp);
 		free_irq(mcbsp->tx_irq, (void *)mcbsp);
 		free_irq(mcbsp->tx_irq, (void *)mcbsp);
 	}
 	}
 
 
@@ -855,7 +914,7 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx)
 		MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
 		MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
 	}
 	}
 
 
-	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+	if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		/* Release the transmitter and receiver */
 		/* Release the transmitter and receiver */
 		w = MCBSP_READ_CACHE(mcbsp, XCCR);
 		w = MCBSP_READ_CACHE(mcbsp, XCCR);
 		w &= ~(tx ? XDISABLE : 0);
 		w &= ~(tx ? XDISABLE : 0);
@@ -885,7 +944,7 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx)
 
 
 	/* Reset transmitter */
 	/* Reset transmitter */
 	tx &= 1;
 	tx &= 1;
-	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+	if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		w = MCBSP_READ_CACHE(mcbsp, XCCR);
 		w = MCBSP_READ_CACHE(mcbsp, XCCR);
 		w |= (tx ? XDISABLE : 0);
 		w |= (tx ? XDISABLE : 0);
 		MCBSP_WRITE(mcbsp, XCCR, w);
 		MCBSP_WRITE(mcbsp, XCCR, w);
@@ -895,7 +954,7 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx)
 
 
 	/* Reset receiver */
 	/* Reset receiver */
 	rx &= 1;
 	rx &= 1;
-	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+	if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		w = MCBSP_READ_CACHE(mcbsp, RCCR);
 		w = MCBSP_READ_CACHE(mcbsp, RCCR);
 		w |= (rx ? RDISABLE : 0);
 		w |= (rx ? RDISABLE : 0);
 		MCBSP_WRITE(mcbsp, RCCR, w);
 		MCBSP_WRITE(mcbsp, RCCR, w);

+ 12 - 0
drivers/gpio/wm8994-gpio.c

@@ -81,6 +81,18 @@ static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 	wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value);
 	wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value);
 }
 }
 
 
+static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+	struct wm8994 *wm8994 = wm8994_gpio->wm8994;
+
+	if (!wm8994->irq_base)
+		return -EINVAL;
+
+	return wm8994->irq_base + offset;
+}
+
+
 #ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_DEBUG_FS
 static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
 {

+ 6 - 2
drivers/mfd/Kconfig

@@ -53,6 +53,10 @@ config MFD_SH_MOBILE_SDHI
 	  This driver supports the SDHI hardware block found in many
 	  This driver supports the SDHI hardware block found in many
 	  SuperH Mobile SoCs.
 	  SuperH Mobile SoCs.
 
 
+config MFD_DAVINCI_VOICECODEC
+	tristate
+	select MFD_CORE
+
 config MFD_DM355EVM_MSP
 config MFD_DM355EVM_MSP
 	bool "DaVinci DM355 EVM microcontroller"
 	bool "DaVinci DM355 EVM microcontroller"
 	depends on I2C && MACH_DAVINCI_DM355_EVM
 	depends on I2C && MACH_DAVINCI_DM355_EVM
@@ -297,9 +301,9 @@ config MFD_WM8350_I2C
 	  selected to enable support for the functionality of the chip.
 	  selected to enable support for the functionality of the chip.
 
 
 config MFD_WM8994
 config MFD_WM8994
-	tristate "Support Wolfson Microelectronics WM8994"
+	bool "Support Wolfson Microelectronics WM8994"
 	select MFD_CORE
 	select MFD_CORE
-	depends on I2C
+	depends on I2C=y && GENERIC_HARDIRQS
 	help
 	help
 	  The WM8994 is a highly integrated hi-fi CODEC designed for
 	  The WM8994 is a highly integrated hi-fi CODEC designed for
 	  smartphone applicatiosn.  As well as audio functionality it
 	  smartphone applicatiosn.  As well as audio functionality it

+ 2 - 1
drivers/mfd/Makefile

@@ -12,6 +12,7 @@ obj-$(CONFIG_HTC_EGPIO)		+= htc-egpio.o
 obj-$(CONFIG_HTC_PASIC3)	+= htc-pasic3.o
 obj-$(CONFIG_HTC_PASIC3)	+= htc-pasic3.o
 obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
 obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
 
 
+obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)	+= davinci_voicecodec.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
 
 
 obj-$(CONFIG_MFD_T7L66XB)	+= t7l66xb.o tmio_core.o
 obj-$(CONFIG_MFD_T7L66XB)	+= t7l66xb.o tmio_core.o
@@ -25,7 +26,7 @@ wm8350-objs			:= wm8350-core.o wm8350-regmap.o wm8350-gpio.o
 wm8350-objs			+= wm8350-irq.o
 wm8350-objs			+= wm8350-irq.o
 obj-$(CONFIG_MFD_WM8350)	+= wm8350.o
 obj-$(CONFIG_MFD_WM8350)	+= wm8350.o
 obj-$(CONFIG_MFD_WM8350_I2C)	+= wm8350-i2c.o
 obj-$(CONFIG_MFD_WM8350_I2C)	+= wm8350-i2c.o
-obj-$(CONFIG_MFD_WM8994)	+= wm8994-core.o
+obj-$(CONFIG_MFD_WM8994)	+= wm8994-core.o wm8994-irq.o
 
 
 obj-$(CONFIG_TPS65010)		+= tps65010.o
 obj-$(CONFIG_TPS65010)		+= tps65010.o
 obj-$(CONFIG_MENELAUS)		+= menelaus.o
 obj-$(CONFIG_MENELAUS)		+= menelaus.o

+ 190 - 0
drivers/mfd/davinci_voicecodec.c

@@ -0,0 +1,190 @@
+/*
+ * DaVinci Voice Codec Core Interface for TI platforms
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc
+ *
+ * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <sound/pcm.h>
+
+#include <linux/mfd/davinci_voicecodec.h>
+
+u32 davinci_vc_read(struct davinci_vc *davinci_vc, int reg)
+{
+	return __raw_readl(davinci_vc->base + reg);
+}
+
+void davinci_vc_write(struct davinci_vc *davinci_vc,
+					   int reg, u32 val)
+{
+	__raw_writel(val, davinci_vc->base + reg);
+}
+
+static int __init davinci_vc_probe(struct platform_device *pdev)
+{
+	struct davinci_vc *davinci_vc;
+	struct resource *res, *mem;
+	struct mfd_cell *cell = NULL;
+	int ret;
+
+	davinci_vc = kzalloc(sizeof(struct davinci_vc), GFP_KERNEL);
+	if (!davinci_vc) {
+		dev_dbg(&pdev->dev,
+			    "could not allocate memory for private data\n");
+		return -ENOMEM;
+	}
+
+	davinci_vc->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(davinci_vc->clk)) {
+		dev_dbg(&pdev->dev,
+			    "could not get the clock for voice codec\n");
+		ret = -ENODEV;
+		goto fail1;
+	}
+	clk_enable(davinci_vc->clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no mem resource\n");
+		ret = -ENODEV;
+		goto fail2;
+	}
+
+	davinci_vc->pbase = res->start;
+	davinci_vc->base_size = resource_size(res);
+
+	mem = request_mem_region(davinci_vc->pbase, davinci_vc->base_size,
+				 pdev->name);
+	if (!mem) {
+		dev_err(&pdev->dev, "VCIF region already claimed\n");
+		ret = -EBUSY;
+		goto fail2;
+	}
+
+	davinci_vc->base = ioremap(davinci_vc->pbase, davinci_vc->base_size);
+	if (!davinci_vc->base) {
+		dev_err(&pdev->dev, "can't ioremap mem resource.\n");
+		ret = -ENOMEM;
+		goto fail3;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no DMA resource\n");
+		return -ENXIO;
+	}
+
+	davinci_vc->davinci_vcif.dma_tx_channel = res->start;
+	davinci_vc->davinci_vcif.dma_tx_addr =
+		(dma_addr_t)(io_v2p(davinci_vc->base) + DAVINCI_VC_WFIFO);
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "no DMA resource\n");
+		return -ENXIO;
+	}
+
+	davinci_vc->davinci_vcif.dma_rx_channel = res->start;
+	davinci_vc->davinci_vcif.dma_rx_addr =
+		(dma_addr_t)(io_v2p(davinci_vc->base) + DAVINCI_VC_RFIFO);
+
+	davinci_vc->dev = &pdev->dev;
+	davinci_vc->pdev = pdev;
+
+	/* Voice codec interface client */
+	cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
+	cell->name = "davinci_vcif";
+	cell->driver_data = davinci_vc;
+
+	/* Voice codec CQ93VC client */
+	cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
+	cell->name = "cq93vc";
+	cell->driver_data = davinci_vc;
+
+	ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
+			      DAVINCI_VC_CELLS, NULL, 0);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "fail to register client devices\n");
+		goto fail4;
+	}
+
+	return 0;
+
+fail4:
+	iounmap(davinci_vc->base);
+fail3:
+	release_mem_region(davinci_vc->pbase, davinci_vc->base_size);
+fail2:
+	clk_disable(davinci_vc->clk);
+	clk_put(davinci_vc->clk);
+	davinci_vc->clk = NULL;
+fail1:
+	kfree(davinci_vc);
+
+	return ret;
+}
+
+static int __devexit davinci_vc_remove(struct platform_device *pdev)
+{
+	struct davinci_vc *davinci_vc = platform_get_drvdata(pdev);
+
+	mfd_remove_devices(&pdev->dev);
+
+	iounmap(davinci_vc->base);
+	release_mem_region(davinci_vc->pbase, davinci_vc->base_size);
+
+	clk_disable(davinci_vc->clk);
+	clk_put(davinci_vc->clk);
+	davinci_vc->clk = NULL;
+
+	kfree(davinci_vc);
+
+	return 0;
+}
+
+static struct platform_driver davinci_vc_driver = {
+	.driver	= {
+		.name = "davinci_voicecodec",
+		.owner = THIS_MODULE,
+	},
+	.remove	= __devexit_p(davinci_vc_remove),
+};
+
+static int __init davinci_vc_init(void)
+{
+	return platform_driver_probe(&davinci_vc_driver, davinci_vc_probe);
+}
+module_init(davinci_vc_init);
+
+static void __exit davinci_vc_exit(void)
+{
+	platform_driver_unregister(&davinci_vc_driver);
+}
+module_exit(davinci_vc_exit);
+
+MODULE_AUTHOR("Miguel Aguilar");
+MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface");
+MODULE_LICENSE("GPL");

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

@@ -109,7 +109,7 @@
 #endif
 #endif
 
 
 #if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\
 #if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\
-	defined(CONFIG_SND_SOC_TWL6030) || defined(CONFIG_SND_SOC_TWL6030_MODULE)
+	defined(CONFIG_SND_SOC_TWL6040) || defined(CONFIG_SND_SOC_TWL6040_MODULE)
 #define twl_has_codec()	true
 #define twl_has_codec()	true
 #else
 #else
 #define twl_has_codec()	false
 #define twl_has_codec()	false
@@ -708,7 +708,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 	/* Phoenix*/
 	/* Phoenix*/
 	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, "twl6030_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))

+ 30 - 0
drivers/mfd/wm831x-irq.c

@@ -21,6 +21,7 @@
 
 
 #include <linux/mfd/wm831x/core.h>
 #include <linux/mfd/wm831x/core.h>
 #include <linux/mfd/wm831x/pdata.h>
 #include <linux/mfd/wm831x/pdata.h>
+#include <linux/mfd/wm831x/gpio.h>
 #include <linux/mfd/wm831x/irq.h>
 #include <linux/mfd/wm831x/irq.h>
 
 
 #include <linux/delay.h>
 #include <linux/delay.h>
@@ -388,12 +389,41 @@ static void wm831x_irq_mask(unsigned int irq)
 	wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
 	wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
 }
 }
 
 
+static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
+{
+	struct wm831x *wm831x = get_irq_chip_data(irq);
+	int val;
+
+	irq = irq - wm831x->irq_base;
+
+	if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11)
+		return -EINVAL;
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_BOTH:
+		val = WM831X_GPN_INT_MODE;
+		break;
+	case IRQ_TYPE_EDGE_RISING:
+		val = WM831X_GPN_POL;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		val = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + irq,
+			       WM831X_GPN_INT_MODE | WM831X_GPN_POL, val);
+}
+
 static struct irq_chip wm831x_irq_chip = {
 static struct irq_chip wm831x_irq_chip = {
 	.name = "wm831x",
 	.name = "wm831x",
 	.bus_lock = wm831x_irq_lock,
 	.bus_lock = wm831x_irq_lock,
 	.bus_sync_unlock = wm831x_irq_sync_unlock,
 	.bus_sync_unlock = wm831x_irq_sync_unlock,
 	.mask = wm831x_irq_mask,
 	.mask = wm831x_irq_mask,
 	.unmask = wm831x_irq_unmask,
 	.unmask = wm831x_irq_unmask,
+	.set_type = wm831x_irq_set_type,
 };
 };
 
 
 /* The processing of the primary interrupt occurs in a thread so that
 /* The processing of the primary interrupt occurs in a thread so that

+ 40 - 3
drivers/mfd/wm8994-core.c

@@ -173,9 +173,34 @@ static struct mfd_cell wm8994_regulator_devs[] = {
 	{ .name = "wm8994-ldo", .id = 2 },
 	{ .name = "wm8994-ldo", .id = 2 },
 };
 };
 
 
+static struct resource wm8994_codec_resources[] = {
+	{
+		.start = WM8994_IRQ_TEMP_SHUT,
+		.end   = WM8994_IRQ_TEMP_WARN,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource wm8994_gpio_resources[] = {
+	{
+		.start = WM8994_IRQ_GPIO(1),
+		.end   = WM8994_IRQ_GPIO(11),
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
 static struct mfd_cell wm8994_devs[] = {
 static struct mfd_cell wm8994_devs[] = {
-	{ .name = "wm8994-codec" },
-	{ .name = "wm8994-gpio" },
+	{
+		.name = "wm8994-codec",
+		.num_resources = ARRAY_SIZE(wm8994_codec_resources),
+		.resources = wm8994_codec_resources,
+	},
+
+	{
+		.name = "wm8994-gpio",
+		.num_resources = ARRAY_SIZE(wm8994_gpio_resources),
+		.resources = wm8994_gpio_resources,
+	},
 };
 };
 
 
 /*
 /*
@@ -236,6 +261,11 @@ static int wm8994_device_resume(struct device *dev)
 		return ret;
 		return ret;
 	}
 	}
 
 
+	ret = wm8994_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK,
+			   WM8994_NUM_IRQ_REGS * 2, &wm8994->irq_masks_cur);
+	if (ret < 0)
+		dev_err(dev, "Failed to restore interrupt masks: %d\n", ret);
+
 	ret = wm8994_write(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
 	ret = wm8994_write(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
 			   &wm8994->ldo_regs);
 			   &wm8994->ldo_regs);
 	if (ret < 0)
 	if (ret < 0)
@@ -348,6 +378,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
 
 
 
 
 	if (pdata) {
 	if (pdata) {
+		wm8994->irq_base = pdata->irq_base;
 		wm8994->gpio_base = pdata->gpio_base;
 		wm8994->gpio_base = pdata->gpio_base;
 
 
 		/* GPIO configuration is only applied if it's non-zero */
 		/* GPIO configuration is only applied if it's non-zero */
@@ -375,16 +406,20 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
 					WM8994_LDO1_DISCH, 0);
 					WM8994_LDO1_DISCH, 0);
 	}
 	}
 
 
+	wm8994_irq_init(wm8994);
+
 	ret = mfd_add_devices(wm8994->dev, -1,
 	ret = mfd_add_devices(wm8994->dev, -1,
 			      wm8994_devs, ARRAY_SIZE(wm8994_devs),
 			      wm8994_devs, ARRAY_SIZE(wm8994_devs),
 			      NULL, 0);
 			      NULL, 0);
 	if (ret != 0) {
 	if (ret != 0) {
 		dev_err(wm8994->dev, "Failed to add children: %d\n", ret);
 		dev_err(wm8994->dev, "Failed to add children: %d\n", ret);
-		goto err_enable;
+		goto err_irq;
 	}
 	}
 
 
 	return 0;
 	return 0;
 
 
+err_irq:
+	wm8994_irq_exit(wm8994);
 err_enable:
 err_enable:
 	regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
 	regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
 			       wm8994->supplies);
 			       wm8994->supplies);
@@ -401,6 +436,7 @@ err:
 static void wm8994_device_exit(struct wm8994 *wm8994)
 static void wm8994_device_exit(struct wm8994 *wm8994)
 {
 {
 	mfd_remove_devices(wm8994->dev);
 	mfd_remove_devices(wm8994->dev);
+	wm8994_irq_exit(wm8994);
 	regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
 	regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
 			       wm8994->supplies);
 			       wm8994->supplies);
 	regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
 	regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
@@ -469,6 +505,7 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
 	wm8994->control_data = i2c;
 	wm8994->control_data = i2c;
 	wm8994->read_dev = wm8994_i2c_read_device;
 	wm8994->read_dev = wm8994_i2c_read_device;
 	wm8994->write_dev = wm8994_i2c_write_device;
 	wm8994->write_dev = wm8994_i2c_write_device;
+	wm8994->irq = i2c->irq;
 
 
 	return wm8994_device_init(wm8994, id->driver_data, i2c->irq);
 	return wm8994_device_init(wm8994, id->driver_data, i2c->irq);
 }
 }

+ 310 - 0
drivers/mfd/wm8994-irq.c

@@ -0,0 +1,310 @@
+/*
+ * wm8994-irq.c  --  Interrupt controller support for Wolfson WM8994
+ *
+ * Copyright 2010 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/interrupt.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+
+#include <linux/delay.h>
+
+struct wm8994_irq_data {
+	int reg;
+	int mask;
+};
+
+static struct wm8994_irq_data wm8994_irqs[] = {
+	[WM8994_IRQ_TEMP_SHUT] = {
+		.reg = 2,
+		.mask = WM8994_TEMP_SHUT_EINT,
+	},
+	[WM8994_IRQ_MIC1_DET] = {
+		.reg = 2,
+		.mask = WM8994_MIC1_DET_EINT,
+	},
+	[WM8994_IRQ_MIC1_SHRT] = {
+		.reg = 2,
+		.mask = WM8994_MIC1_SHRT_EINT,
+	},
+	[WM8994_IRQ_MIC2_DET] = {
+		.reg = 2,
+		.mask = WM8994_MIC2_DET_EINT,
+	},
+	[WM8994_IRQ_MIC2_SHRT] = {
+		.reg = 2,
+		.mask = WM8994_MIC2_SHRT_EINT,
+	},
+	[WM8994_IRQ_FLL1_LOCK] = {
+		.reg = 2,
+		.mask = WM8994_FLL1_LOCK_EINT,
+	},
+	[WM8994_IRQ_FLL2_LOCK] = {
+		.reg = 2,
+		.mask = WM8994_FLL2_LOCK_EINT,
+	},
+	[WM8994_IRQ_SRC1_LOCK] = {
+		.reg = 2,
+		.mask = WM8994_SRC1_LOCK_EINT,
+	},
+	[WM8994_IRQ_SRC2_LOCK] = {
+		.reg = 2,
+		.mask = WM8994_SRC2_LOCK_EINT,
+	},
+	[WM8994_IRQ_AIF1DRC1_SIG_DET] = {
+		.reg = 2,
+		.mask = WM8994_AIF1DRC1_SIG_DET,
+	},
+	[WM8994_IRQ_AIF1DRC2_SIG_DET] = {
+		.reg = 2,
+		.mask = WM8994_AIF1DRC2_SIG_DET_EINT,
+	},
+	[WM8994_IRQ_AIF2DRC_SIG_DET] = {
+		.reg = 2,
+		.mask = WM8994_AIF2DRC_SIG_DET_EINT,
+	},
+	[WM8994_IRQ_FIFOS_ERR] = {
+		.reg = 2,
+		.mask = WM8994_FIFOS_ERR_EINT,
+	},
+	[WM8994_IRQ_WSEQ_DONE] = {
+		.reg = 2,
+		.mask = WM8994_WSEQ_DONE_EINT,
+	},
+	[WM8994_IRQ_DCS_DONE] = {
+		.reg = 2,
+		.mask = WM8994_DCS_DONE_EINT,
+	},
+	[WM8994_IRQ_TEMP_WARN] = {
+		.reg = 2,
+		.mask = WM8994_TEMP_WARN_EINT,
+	},
+	[WM8994_IRQ_GPIO(1)] = {
+		.reg = 1,
+		.mask = WM8994_GP1_EINT,
+	},
+	[WM8994_IRQ_GPIO(2)] = {
+		.reg = 1,
+		.mask = WM8994_GP2_EINT,
+	},
+	[WM8994_IRQ_GPIO(3)] = {
+		.reg = 1,
+		.mask = WM8994_GP3_EINT,
+	},
+	[WM8994_IRQ_GPIO(4)] = {
+		.reg = 1,
+		.mask = WM8994_GP4_EINT,
+	},
+	[WM8994_IRQ_GPIO(5)] = {
+		.reg = 1,
+		.mask = WM8994_GP5_EINT,
+	},
+	[WM8994_IRQ_GPIO(6)] = {
+		.reg = 1,
+		.mask = WM8994_GP6_EINT,
+	},
+	[WM8994_IRQ_GPIO(7)] = {
+		.reg = 1,
+		.mask = WM8994_GP7_EINT,
+	},
+	[WM8994_IRQ_GPIO(8)] = {
+		.reg = 1,
+		.mask = WM8994_GP8_EINT,
+	},
+	[WM8994_IRQ_GPIO(9)] = {
+		.reg = 1,
+		.mask = WM8994_GP8_EINT,
+	},
+	[WM8994_IRQ_GPIO(10)] = {
+		.reg = 1,
+		.mask = WM8994_GP10_EINT,
+	},
+	[WM8994_IRQ_GPIO(11)] = {
+		.reg = 1,
+		.mask = WM8994_GP11_EINT,
+	},
+};
+
+static inline int irq_data_to_status_reg(struct wm8994_irq_data *irq_data)
+{
+	return WM8994_INTERRUPT_STATUS_1 - 1 + irq_data->reg;
+}
+
+static inline int irq_data_to_mask_reg(struct wm8994_irq_data *irq_data)
+{
+	return WM8994_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
+}
+
+static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994,
+							int irq)
+{
+	return &wm8994_irqs[irq - wm8994->irq_base];
+}
+
+static void wm8994_irq_lock(unsigned int irq)
+{
+	struct wm8994 *wm8994 = get_irq_chip_data(irq);
+
+	mutex_lock(&wm8994->irq_lock);
+}
+
+static void wm8994_irq_sync_unlock(unsigned int irq)
+{
+	struct wm8994 *wm8994 = get_irq_chip_data(irq);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
+		/* If there's been a change in the mask write it back
+		 * to the hardware. */
+		if (wm8994->irq_masks_cur[i] != wm8994->irq_masks_cache[i]) {
+			wm8994->irq_masks_cache[i] = wm8994->irq_masks_cur[i];
+			wm8994_reg_write(wm8994,
+					 WM8994_INTERRUPT_STATUS_1_MASK + i,
+					 wm8994->irq_masks_cur[i]);
+		}
+	}
+
+	mutex_unlock(&wm8994->irq_lock);
+}
+
+static void wm8994_irq_unmask(unsigned int irq)
+{
+	struct wm8994 *wm8994 = get_irq_chip_data(irq);
+	struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
+
+	wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
+}
+
+static void wm8994_irq_mask(unsigned int irq)
+{
+	struct wm8994 *wm8994 = get_irq_chip_data(irq);
+	struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
+
+	wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
+}
+
+static struct irq_chip wm8994_irq_chip = {
+	.name = "wm8994",
+	.bus_lock = wm8994_irq_lock,
+	.bus_sync_unlock = wm8994_irq_sync_unlock,
+	.mask = wm8994_irq_mask,
+	.unmask = wm8994_irq_unmask,
+};
+
+/* The processing of the primary interrupt occurs in a thread so that
+ * we can interact with the device over I2C or SPI. */
+static irqreturn_t wm8994_irq_thread(int irq, void *data)
+{
+	struct wm8994 *wm8994 = data;
+	unsigned int i;
+	u16 status[WM8994_NUM_IRQ_REGS];
+	int ret;
+
+	ret = wm8994_bulk_read(wm8994, WM8994_INTERRUPT_STATUS_1,
+			       WM8994_NUM_IRQ_REGS, status);
+	if (ret < 0) {
+		dev_err(wm8994->dev, "Failed to read interrupt status: %d\n",
+			ret);
+		return IRQ_NONE;
+	}
+
+	/* Apply masking */
+	for (i = 0; i < WM8994_NUM_IRQ_REGS; i++)
+		status[i] &= ~wm8994->irq_masks_cur[i];
+
+	/* Report */
+	for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
+		if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask)
+			handle_nested_irq(wm8994->irq_base + i);
+	}
+
+	/* Ack any unmasked IRQs */
+	for (i = 0; i < ARRAY_SIZE(status); i++) {
+		if (status[i])
+			wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1 + i,
+					 status[i]);
+	}
+
+	return IRQ_HANDLED;
+}
+
+int wm8994_irq_init(struct wm8994 *wm8994)
+{
+	int i, cur_irq, ret;
+
+	mutex_init(&wm8994->irq_lock);
+
+	/* Mask the individual interrupt sources */
+	for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
+		wm8994->irq_masks_cur[i] = 0xffff;
+		wm8994->irq_masks_cache[i] = 0xffff;
+		wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK + i,
+				 0xffff);
+	}
+
+	if (!wm8994->irq) {
+		dev_warn(wm8994->dev,
+			 "No interrupt specified, no interrupts\n");
+		wm8994->irq_base = 0;
+		return 0;
+	}
+
+	if (!wm8994->irq_base) {
+		dev_err(wm8994->dev,
+			"No interrupt base specified, no interrupts\n");
+		return 0;
+	}
+
+	/* Register them with genirq */
+	for (cur_irq = wm8994->irq_base;
+	     cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base;
+	     cur_irq++) {
+		set_irq_chip_data(cur_irq, wm8994);
+		set_irq_chip_and_handler(cur_irq, &wm8994_irq_chip,
+					 handle_edge_irq);
+		set_irq_nested_thread(cur_irq, 1);
+
+		/* ARM needs us to explicitly flag the IRQ as valid
+		 * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+		set_irq_flags(cur_irq, IRQF_VALID);
+#else
+		set_irq_noprobe(cur_irq);
+#endif
+	}
+
+	ret = request_threaded_irq(wm8994->irq, NULL, wm8994_irq_thread,
+				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   "wm8994", wm8994);
+	if (ret != 0) {
+		dev_err(wm8994->dev, "Failed to request IRQ %d: %d\n",
+			wm8994->irq, ret);
+		return ret;
+	}
+
+	/* Enable top level interrupt if it was masked */
+	wm8994_reg_write(wm8994, WM8994_INTERRUPT_CONTROL, 0);
+
+	return 0;
+}
+
+void wm8994_irq_exit(struct wm8994 *wm8994)
+{
+	if (wm8994->irq)
+		free_irq(wm8994->irq, wm8994);
+}

+ 3 - 3
include/linux/i2c/twl.h

@@ -569,9 +569,9 @@ struct twl4030_codec_data {
 	struct twl4030_codec_audio_data		*audio;
 	struct twl4030_codec_audio_data		*audio;
 	struct twl4030_codec_vibra_data		*vibra;
 	struct twl4030_codec_vibra_data		*vibra;
 
 
-	/* twl6030 */
-	int audpwron_gpio;      /* audio power-on gpio */
-	int naudint_irq;        /* audio interrupt */
+	/* twl6040 */
+	int audpwron_gpio;	/* audio power-on gpio */
+	int naudint_irq;	/* audio interrupt */
 };
 };
 
 
 struct twl4030_platform_data {
 struct twl4030_platform_data {

+ 126 - 0
include/linux/mfd/davinci_voicecodec.h

@@ -0,0 +1,126 @@
+/*
+ * DaVinci Voice Codec Core Interface for TI platforms
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc
+ *
+ * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __LINUX_MFD_DAVINCI_VOICECODEC_H_
+#define __LINUX_MFD_DAVINIC_VOICECODEC_H_
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+
+#include <mach/edma.h>
+
+/*
+ * Register values.
+ */
+#define DAVINCI_VC_PID			0x00
+#define DAVINCI_VC_CTRL			0x04
+#define DAVINCI_VC_INTEN		0x08
+#define DAVINCI_VC_INTSTATUS		0x0c
+#define DAVINCI_VC_INTCLR		0x10
+#define DAVINCI_VC_EMUL_CTRL		0x14
+#define DAVINCI_VC_RFIFO		0x20
+#define DAVINCI_VC_WFIFO		0x24
+#define DAVINCI_VC_FIFOSTAT		0x28
+#define DAVINCI_VC_TST_CTRL		0x2C
+#define DAVINCI_VC_REG05		0x94
+#define DAVINCI_VC_REG09		0xA4
+#define DAVINCI_VC_REG12		0xB0
+
+/* DAVINCI_VC_CTRL bit fields */
+#define DAVINCI_VC_CTRL_MASK		0x5500
+#define DAVINCI_VC_CTRL_RSTADC		BIT(0)
+#define DAVINCI_VC_CTRL_RSTDAC		BIT(1)
+#define DAVINCI_VC_CTRL_RD_BITS_8	BIT(4)
+#define DAVINCI_VC_CTRL_RD_UNSIGNED	BIT(5)
+#define DAVINCI_VC_CTRL_WD_BITS_8	BIT(6)
+#define DAVINCI_VC_CTRL_WD_UNSIGNED	BIT(7)
+#define DAVINCI_VC_CTRL_RFIFOEN		BIT(8)
+#define DAVINCI_VC_CTRL_RFIFOCL		BIT(9)
+#define DAVINCI_VC_CTRL_RFIFOMD_WORD_1	BIT(10)
+#define DAVINCI_VC_CTRL_WFIFOEN		BIT(12)
+#define DAVINCI_VC_CTRL_WFIFOCL		BIT(13)
+#define DAVINCI_VC_CTRL_WFIFOMD_WORD_1	BIT(14)
+
+/* DAVINCI_VC_INT bit fields */
+#define DAVINCI_VC_INT_MASK		0x3F
+#define DAVINCI_VC_INT_RDRDY_MASK	BIT(0)
+#define DAVINCI_VC_INT_RERROVF_MASK	BIT(1)
+#define DAVINCI_VC_INT_RERRUDR_MASK	BIT(2)
+#define DAVINCI_VC_INT_WDREQ_MASK	BIT(3)
+#define DAVINCI_VC_INT_WERROVF_MASKBIT	BIT(4)
+#define DAVINCI_VC_INT_WERRUDR_MASK	BIT(5)
+
+/* DAVINCI_VC_REG05 bit fields */
+#define DAVINCI_VC_REG05_PGA_GAIN	0x07
+
+/* DAVINCI_VC_REG09 bit fields */
+#define DAVINCI_VC_REG09_MUTE		0x40
+#define DAVINCI_VC_REG09_DIG_ATTEN	0x3F
+
+/* DAVINCI_VC_REG12 bit fields */
+#define DAVINCI_VC_REG12_POWER_ALL_ON	0xFD
+#define DAVINCI_VC_REG12_POWER_ALL_OFF	0x00
+
+#define DAVINCI_VC_CELLS		2
+
+enum davinci_vc_cells {
+	DAVINCI_VC_VCIF_CELL,
+	DAVINCI_VC_CQ93VC_CELL,
+};
+
+struct davinci_vcif {
+	struct platform_device	*pdev;
+	u32 dma_tx_channel;
+	u32 dma_rx_channel;
+	dma_addr_t dma_tx_addr;
+	dma_addr_t dma_rx_addr;
+};
+
+struct cq93vc {
+	struct platform_device *pdev;
+	struct snd_soc_codec *codec;
+	u32 sysclk;
+};
+
+struct davinci_vc;
+
+struct davinci_vc {
+	/* Device data */
+	struct device *dev;
+	struct platform_device *pdev;
+	struct clk *clk;
+
+	/* Memory resources */
+	void __iomem *base;
+	resource_size_t pbase;
+	size_t base_size;
+
+	/* MFD cells */
+	struct mfd_cell cells[DAVINCI_VC_CELLS];
+
+	/* Client devices */
+	struct davinci_vcif davinci_vcif;
+	struct cq93vc cq93vc;
+};
+
+#endif

+ 2 - 0
include/linux/mfd/wm8350/audio.h

@@ -492,6 +492,8 @@
  */
  */
 #define WM8350_JACK_L_LVL			0x0800
 #define WM8350_JACK_L_LVL			0x0800
 #define WM8350_JACK_R_LVL                       0x0400
 #define WM8350_JACK_R_LVL                       0x0400
+#define WM8350_JACK_MICSCD_LVL			0x0200
+#define WM8350_JACK_MICSD_LVL			0x0100
 
 
 /*
 /*
  * WM8350 Platform setup
  * WM8350 Platform setup

+ 52 - 1
include/linux/mfd/wm8994/core.h

@@ -15,14 +15,38 @@
 #ifndef __MFD_WM8994_CORE_H__
 #ifndef __MFD_WM8994_CORE_H__
 #define __MFD_WM8994_CORE_H__
 #define __MFD_WM8994_CORE_H__
 
 
+#include <linux/interrupt.h>
+
 struct regulator_dev;
 struct regulator_dev;
 struct regulator_bulk_data;
 struct regulator_bulk_data;
 
 
 #define WM8994_NUM_GPIO_REGS 11
 #define WM8994_NUM_GPIO_REGS 11
-#define WM8994_NUM_LDO_REGS 2
+#define WM8994_NUM_LDO_REGS   2
+#define WM8994_NUM_IRQ_REGS   2
+
+#define WM8994_IRQ_TEMP_SHUT		0
+#define WM8994_IRQ_MIC1_DET		1
+#define WM8994_IRQ_MIC1_SHRT		2
+#define WM8994_IRQ_MIC2_DET		3
+#define WM8994_IRQ_MIC2_SHRT		4
+#define WM8994_IRQ_FLL1_LOCK		5
+#define WM8994_IRQ_FLL2_LOCK		6
+#define WM8994_IRQ_SRC1_LOCK		7
+#define WM8994_IRQ_SRC2_LOCK		8
+#define WM8994_IRQ_AIF1DRC1_SIG_DET	9
+#define WM8994_IRQ_AIF1DRC2_SIG_DET	10
+#define WM8994_IRQ_AIF2DRC_SIG_DET	11
+#define WM8994_IRQ_FIFOS_ERR		12
+#define WM8994_IRQ_WSEQ_DONE		13
+#define WM8994_IRQ_DCS_DONE		14
+#define WM8994_IRQ_TEMP_WARN		15
+
+/* GPIOs in the chip are numbered from 1-11 */
+#define WM8994_IRQ_GPIO(x) (x + WM8994_IRQ_TEMP_WARN)
 
 
 struct wm8994 {
 struct wm8994 {
 	struct mutex io_lock;
 	struct mutex io_lock;
+	struct mutex irq_lock;
 
 
 	struct device *dev;
 	struct device *dev;
 	int (*read_dev)(struct wm8994 *wm8994, unsigned short reg,
 	int (*read_dev)(struct wm8994 *wm8994, unsigned short reg,
@@ -33,6 +57,11 @@ struct wm8994 {
 	void *control_data;
 	void *control_data;
 
 
 	int gpio_base;
 	int gpio_base;
+	int irq_base;
+
+	int irq;
+	u16 irq_masks_cur[WM8994_NUM_IRQ_REGS];
+	u16 irq_masks_cache[WM8994_NUM_IRQ_REGS];
 
 
 	/* Used over suspend/resume */
 	/* Used over suspend/resume */
 	u16 ldo_regs[WM8994_NUM_LDO_REGS];
 	u16 ldo_regs[WM8994_NUM_LDO_REGS];
@@ -51,4 +80,26 @@ int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg,
 int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
 int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
 		     int count, u16 *buf);
 		     int count, u16 *buf);
 
 
+
+/* Helper to save on boilerplate */
+static inline int wm8994_request_irq(struct wm8994 *wm8994, int irq,
+				     irq_handler_t handler, const char *name,
+				     void *data)
+{
+	if (!wm8994->irq_base)
+		return -EINVAL;
+	return request_threaded_irq(wm8994->irq_base + irq, NULL, handler,
+				    IRQF_TRIGGER_RISING, name,
+				    data);
+}
+static inline void wm8994_free_irq(struct wm8994 *wm8994, int irq, void *data)
+{
+	if (!wm8994->irq_base)
+		return;
+	free_irq(wm8994->irq_base + irq, data);
+}
+
+int wm8994_irq_init(struct wm8994 *wm8994);
+void wm8994_irq_exit(struct wm8994 *wm8994);
+
 #endif
 #endif

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

@@ -70,6 +70,7 @@ struct wm8994_pdata {
 
 
 	struct wm8994_ldo_pdata ldo[WM8994_NUM_LDO];
 	struct wm8994_ldo_pdata ldo[WM8994_NUM_LDO];
 
 
+	int irq_base;  /** Base IRQ number for WM8994, required for IRQs */
 
 
         int num_drc_cfgs;
         int num_drc_cfgs;
         struct wm8994_drc_cfg *drc_cfgs;
         struct wm8994_drc_cfg *drc_cfgs;

+ 378 - 0
include/linux/usb/audio-v2.h

@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2010 Daniel Mack <daniel@caiaq.de>
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License ("GPL") version 2, as published by the Free Software Foundation.
+ *
+ * This file holds USB constants and structures defined
+ * by the USB Device Class Definition for Audio Devices in version 2.0.
+ * Comments below reference relevant sections of the documents contained
+ * in http://www.usb.org/developers/devclass_docs/Audio2.0_final.zip
+ */
+
+#ifndef __LINUX_USB_AUDIO_V2_H
+#define __LINUX_USB_AUDIO_V2_H
+
+#include <linux/types.h>
+
+/* v1.0 and v2.0 of this standard have many things in common. For the rest
+ * of the definitions, please refer to audio.h */
+
+/* 4.7.2.1 Clock Source Descriptor */
+
+struct uac_clock_source_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bClockID;
+	__u8 bmAttributes;
+	__u8 bmControls;
+	__u8 bAssocTerminal;
+	__u8 iClockSource;
+} __attribute__((packed));
+
+/* 4.7.2.2 Clock Source Descriptor */
+
+struct uac_clock_selector_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bClockID;
+	__u8 bNrInPins;
+	__u8 bmControls;
+	__u8 baCSourceID[];
+} __attribute__((packed));
+
+/* 4.7.2.4 Input terminal descriptor */
+
+struct uac2_input_terminal_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bTerminalID;
+	__u16 wTerminalType;
+	__u8 bAssocTerminal;
+	__u8 bCSourceID;
+	__u8 bNrChannels;
+	__u32 bmChannelConfig;
+	__u8 iChannelNames;
+	__u16 bmControls;
+	__u8 iTerminal;
+} __attribute__((packed));
+
+/* 4.7.2.5 Output terminal descriptor */
+
+struct uac2_output_terminal_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bTerminalID;
+	__u16 wTerminalType;
+	__u8 bAssocTerminal;
+	__u8 bSourceID;
+	__u8 bCSourceID;
+	__u16 bmControls;
+	__u8 iTerminal;
+} __attribute__((packed));
+
+
+
+/* 4.7.2.8 Feature Unit Descriptor */
+
+struct uac2_feature_unit_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bUnitID;
+	__u8 bSourceID;
+	/* bmaControls is actually u32,
+	 * but u8 is needed for the hybrid parser */
+	__u8 bmaControls[0]; /* variable length */
+} __attribute__((packed));
+
+/* 4.9.2 Class-Specific AS Interface Descriptor */
+
+struct uac_as_header_descriptor_v2 {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bTerminalLink;
+	__u8 bmControls;
+	__u8 bFormatType;
+	__u32 bmFormats;
+	__u8 bNrChannels;
+	__u32 bmChannelConfig;
+	__u8 iChannelNames;
+} __attribute__((packed));
+
+/* 6.1 Interrupt Data Message */
+
+#define UAC2_INTERRUPT_DATA_MSG_VENDOR	(1 << 0)
+#define UAC2_INTERRUPT_DATA_MSG_EP	(1 << 1)
+
+struct uac2_interrupt_data_msg {
+	__u8 bInfo;
+	__u8 bAttribute;
+	__le16 wValue;
+	__le16 wIndex;
+} __attribute__((packed));
+
+/* A.7 Audio Function Category Codes */
+#define UAC2_FUNCTION_SUBCLASS_UNDEFINED	0x00
+#define UAC2_FUNCTION_DESKTOP_SPEAKER		0x01
+#define UAC2_FUNCTION_HOME_THEATER		0x02
+#define UAC2_FUNCTION_MICROPHONE		0x03
+#define UAC2_FUNCTION_HEADSET			0x04
+#define UAC2_FUNCTION_TELEPHONE			0x05
+#define UAC2_FUNCTION_CONVERTER			0x06
+#define UAC2_FUNCTION_SOUND_RECORDER		0x07
+#define UAC2_FUNCTION_IO_BOX			0x08
+#define UAC2_FUNCTION_MUSICAL_INSTRUMENT	0x09
+#define UAC2_FUNCTION_PRO_AUDIO			0x0a
+#define UAC2_FUNCTION_AUDIO_VIDEO		0x0b
+#define UAC2_FUNCTION_CONTROL_PANEL		0x0c
+#define UAC2_FUNCTION_OTHER			0xff
+
+/* A.9 Audio Class-Specific AC Interface Descriptor Subtypes */
+/* see audio.h for the rest, which is identical to v1 */
+#define UAC2_EFFECT_UNIT			0x07
+#define UAC2_PROCESSING_UNIT_V2		0x08
+#define UAC2_EXTENSION_UNIT_V2		0x09
+#define UAC2_CLOCK_SOURCE		0x0a
+#define UAC2_CLOCK_SELECTOR		0x0b
+#define UAC2_CLOCK_MULTIPLIER		0x0c
+#define UAC2_SAMPLE_RATE_CONVERTER	0x0d
+
+/* A.10 Audio Class-Specific AS Interface Descriptor Subtypes */
+/* see audio.h for the rest, which is identical to v1 */
+#define UAC2_ENCODER			0x03
+#define UAC2_DECODER			0x04
+
+/* A.11 Effect Unit Effect Types */
+#define UAC2_EFFECT_UNDEFINED		0x00
+#define UAC2_EFFECT_PARAM_EQ		0x01
+#define UAC2_EFFECT_REVERB		0x02
+#define UAC2_EFFECT_MOD_DELAY		0x03
+#define UAC2_EFFECT_DYN_RANGE_COMP	0x04
+
+/* A.12 Processing Unit Process Types */
+#define UAC2_PROCESS_UNDEFINED		0x00
+#define UAC2_PROCESS_UP_DOWNMIX		0x01
+#define UAC2_PROCESS_DOLBY_PROLOCIC	0x02
+#define UAC2_PROCESS_STEREO_EXTENDER	0x03
+
+/* A.14 Audio Class-Specific Request Codes */
+#define UAC2_CS_CUR			0x01
+#define UAC2_CS_RANGE			0x02
+#define UAC2_CS_MEM			0x03
+
+/* A.15 Encoder Type Codes */
+#define UAC2_ENCODER_UNDEFINED		0x00
+#define UAC2_ENCODER_OTHER		0x01
+#define UAC2_ENCODER_MPEG		0x02
+#define UAC2_ENCODER_AC3		0x03
+#define UAC2_ENCODER_WMA		0x04
+#define UAC2_ENCODER_DTS		0x05
+
+/* A.16 Decoder Type Codes */
+#define UAC2_DECODER_UNDEFINED		0x00
+#define UAC2_DECODER_OTHER		0x01
+#define UAC2_DECODER_MPEG		0x02
+#define UAC2_DECODER_AC3		0x03
+#define UAC2_DECODER_WMA		0x04
+#define UAC2_DECODER_DTS		0x05
+
+/* A.17.1 Clock Source Control Selectors */
+#define UAC2_CS_UNDEFINED		0x00
+#define UAC2_CS_CONTROL_SAM_FREQ	0x01
+#define UAC2_CS_CONTROL_CLOCK_VALID	0x02
+
+/* A.17.2 Clock Selector Control Selectors */
+#define UAC2_CX_UNDEFINED		0x00
+#define UAC2_CX_CLOCK_SELECTOR		0x01
+
+/* A.17.3 Clock Multiplier Control Selectors */
+#define UAC2_CM_UNDEFINED		0x00
+#define UAC2_CM_NUMERATOR		0x01
+#define UAC2_CM_DENOMINTATOR		0x02
+
+/* A.17.4 Terminal Control Selectors */
+#define UAC2_TE_UNDEFINED		0x00
+#define UAC2_TE_COPY_PROTECT		0x01
+#define UAC2_TE_CONNECTOR		0x02
+#define UAC2_TE_OVERLOAD		0x03
+#define UAC2_TE_CLUSTER			0x04
+#define UAC2_TE_UNDERFLOW		0x05
+#define UAC2_TE_OVERFLOW		0x06
+#define UAC2_TE_LATENCY			0x07
+
+/* A.17.5 Mixer Control Selectors */
+#define UAC2_MU_UNDEFINED		0x00
+#define UAC2_MU_MIXER			0x01
+#define UAC2_MU_CLUSTER			0x02
+#define UAC2_MU_UNDERFLOW		0x03
+#define UAC2_MU_OVERFLOW		0x04
+#define UAC2_MU_LATENCY			0x05
+
+/* A.17.6 Selector Control Selectors */
+#define UAC2_SU_UNDEFINED		0x00
+#define UAC2_SU_SELECTOR		0x01
+#define UAC2_SU_LATENCY			0x02
+
+/* A.17.7 Feature Unit Control Selectors */
+/* see audio.h for the rest, which is identical to v1 */
+#define UAC2_FU_INPUT_GAIN		0x0b
+#define UAC2_FU_INPUT_GAIN_PAD		0x0c
+#define UAC2_FU_PHASE_INVERTER		0x0d
+#define UAC2_FU_UNDERFLOW		0x0e
+#define UAC2_FU_OVERFLOW		0x0f
+#define UAC2_FU_LATENCY			0x10
+
+/* A.17.8.1 Parametric Equalizer Section Effect Unit Control Selectors */
+#define UAC2_PE_UNDEFINED		0x00
+#define UAC2_PE_ENABLE			0x01
+#define UAC2_PE_CENTERFREQ		0x02
+#define UAC2_PE_QFACTOR			0x03
+#define UAC2_PE_GAIN			0x04
+#define UAC2_PE_UNDERFLOW		0x05
+#define UAC2_PE_OVERFLOW		0x06
+#define UAC2_PE_LATENCY			0x07
+
+/* A.17.8.2 Reverberation Effect Unit Control Selectors */
+#define UAC2_RV_UNDEFINED		0x00
+#define UAC2_RV_ENABLE			0x01
+#define UAC2_RV_TYPE			0x02
+#define UAC2_RV_LEVEL			0x03
+#define UAC2_RV_TIME			0x04
+#define UAC2_RV_FEEDBACK		0x05
+#define UAC2_RV_PREDELAY		0x06
+#define UAC2_RV_DENSITY			0x07
+#define UAC2_RV_HIFREQ_ROLLOFF		0x08
+#define UAC2_RV_UNDERFLOW		0x09
+#define UAC2_RV_OVERFLOW		0x0a
+#define UAC2_RV_LATENCY			0x0b
+
+/* A.17.8.3 Modulation Delay Effect Control Selectors */
+#define UAC2_MD_UNDEFINED		0x00
+#define UAC2_MD_ENABLE			0x01
+#define UAC2_MD_BALANCE			0x02
+#define UAC2_MD_RATE			0x03
+#define UAC2_MD_DEPTH			0x04
+#define UAC2_MD_TIME			0x05
+#define UAC2_MD_FEEDBACK		0x06
+#define UAC2_MD_UNDERFLOW		0x07
+#define UAC2_MD_OVERFLOW		0x08
+#define UAC2_MD_LATENCY			0x09
+
+/* A.17.8.4 Dynamic Range Compressor Effect Unit Control Selectors */
+#define UAC2_DR_UNDEFINED		0x00
+#define UAC2_DR_ENABLE			0x01
+#define UAC2_DR_COMPRESSION_RATE	0x02
+#define UAC2_DR_MAXAMPL			0x03
+#define UAC2_DR_THRESHOLD		0x04
+#define UAC2_DR_ATTACK_TIME		0x05
+#define UAC2_DR_RELEASE_TIME		0x06
+#define UAC2_DR_UNDEFLOW		0x07
+#define UAC2_DR_OVERFLOW		0x08
+#define UAC2_DR_LATENCY			0x09
+
+/* A.17.9.1 Up/Down-mix Processing Unit Control Selectors */
+#define UAC2_UD_UNDEFINED		0x00
+#define UAC2_UD_ENABLE			0x01
+#define UAC2_UD_MODE_SELECT		0x02
+#define UAC2_UD_CLUSTER			0x03
+#define UAC2_UD_UNDERFLOW		0x04
+#define UAC2_UD_OVERFLOW		0x05
+#define UAC2_UD_LATENCY			0x06
+
+/* A.17.9.2 Dolby Prologic[tm] Processing Unit Control Selectors */
+#define UAC2_DP_UNDEFINED		0x00
+#define UAC2_DP_ENABLE			0x01
+#define UAC2_DP_MODE_SELECT		0x02
+#define UAC2_DP_CLUSTER			0x03
+#define UAC2_DP_UNDERFFLOW		0x04
+#define UAC2_DP_OVERFLOW		0x05
+#define UAC2_DP_LATENCY			0x06
+
+/* A.17.9.3 Stereo Expander Processing Unit Control Selectors */
+#define UAC2_ST_EXT_UNDEFINED		0x00
+#define UAC2_ST_EXT_ENABLE		0x01
+#define UAC2_ST_EXT_WIDTH		0x02
+#define UAC2_ST_EXT_UNDEFLOW		0x03
+#define UAC2_ST_EXT_OVERFLOW		0x04
+#define UAC2_ST_EXT_LATENCY		0x05
+
+/* A.17.10 Extension Unit Control Selectors */
+#define UAC2_XU_UNDEFINED		0x00
+#define UAC2_XU_ENABLE			0x01
+#define UAC2_XU_CLUSTER			0x02
+#define UAC2_XU_UNDERFLOW		0x03
+#define UAC2_XU_OVERFLOW		0x04
+#define UAC2_XU_LATENCY			0x05
+
+/* A.17.11 AudioStreaming Interface Control Selectors */
+#define UAC2_AS_UNDEFINED		0x00
+#define UAC2_AS_ACT_ALT_SETTING		0x01
+#define UAC2_AS_VAL_ALT_SETTINGS	0x02
+#define UAC2_AS_AUDIO_DATA_FORMAT	0x03
+
+/* A.17.12 Encoder Control Selectors */
+#define UAC2_EN_UNDEFINED		0x00
+#define UAC2_EN_BIT_RATE		0x01
+#define UAC2_EN_QUALITY			0x02
+#define UAC2_EN_VBR			0x03
+#define UAC2_EN_TYPE			0x04
+#define UAC2_EN_UNDERFLOW		0x05
+#define UAC2_EN_OVERFLOW		0x06
+#define UAC2_EN_ENCODER_ERROR		0x07
+#define UAC2_EN_PARAM1			0x08
+#define UAC2_EN_PARAM2			0x09
+#define UAC2_EN_PARAM3			0x0a
+#define UAC2_EN_PARAM4			0x0b
+#define UAC2_EN_PARAM5			0x0c
+#define UAC2_EN_PARAM6			0x0d
+#define UAC2_EN_PARAM7			0x0e
+#define UAC2_EN_PARAM8			0x0f
+
+/* A.17.13.1 MPEG Decoder Control Selectors */
+#define UAC2_MPEG_UNDEFINED		0x00
+#define UAC2_MPEG_DUAL_CHANNEL		0x01
+#define UAC2_MPEG_SECOND_STEREO		0x02
+#define UAC2_MPEG_MULTILINGUAL		0x03
+#define UAC2_MPEG_DYN_RANGE		0x04
+#define UAC2_MPEG_SCALING		0x05
+#define UAC2_MPEG_HILO_SCALING		0x06
+#define UAC2_MPEG_UNDERFLOW		0x07
+#define UAC2_MPEG_OVERFLOW		0x08
+#define UAC2_MPEG_DECODER_ERROR		0x09
+
+/* A17.13.2 AC3 Decoder Control Selectors */
+#define UAC2_AC3_UNDEFINED		0x00
+#define UAC2_AC3_MODE			0x01
+#define UAC2_AC3_DYN_RANGE		0x02
+#define UAC2_AC3_SCALING		0x03
+#define UAC2_AC3_HILO_SCALING		0x04
+#define UAC2_AC3_UNDERFLOW		0x05
+#define UAC2_AC3_OVERFLOW		0x06
+#define UAC2_AC3_DECODER_ERROR		0x07
+
+/* A17.13.3 WMA Decoder Control Selectors */
+#define UAC2_WMA_UNDEFINED		0x00
+#define UAC2_WMA_UNDERFLOW		0x01
+#define UAC2_WMA_OVERFLOW		0x02
+#define UAC2_WMA_DECODER_ERROR		0x03
+
+/* A17.13.4 DTS Decoder Control Selectors */
+#define UAC2_DTS_UNDEFINED		0x00
+#define UAC2_DTS_UNDERFLOW		0x01
+#define UAC2_DTS_OVERFLOW		0x02
+#define UAC2_DTS_DECODER_ERROR		0x03
+
+/* A17.14 Endpoint Control Selectors */
+#define UAC2_EP_CS_UNDEFINED		0x00
+#define UAC2_EP_CS_PITCH		0x01
+#define UAC2_EP_CS_DATA_OVERRUN		0x02
+#define UAC2_EP_CS_DATA_UNDERRUN	0x03
+
+#endif /* __LINUX_USB_AUDIO_V2_H */
+

+ 173 - 54
include/linux/usb/audio.h

@@ -13,6 +13,9 @@
  * Comments below reference relevant sections of that document:
  * Comments below reference relevant sections of that document:
  *
  *
  * http://www.usb.org/developers/devclass_docs/audio10.pdf
  * http://www.usb.org/developers/devclass_docs/audio10.pdf
+ *
+ * Types and defines in this file are either specific to version 1.0 of
+ * this standard or common for newer versions.
  */
  */
 
 
 #ifndef __LINUX_USB_AUDIO_H
 #ifndef __LINUX_USB_AUDIO_H
@@ -20,14 +23,15 @@
 
 
 #include <linux/types.h>
 #include <linux/types.h>
 
 
+/* bInterfaceProtocol values to denote the version of the standard used */
+#define UAC_VERSION_1			0x00
+#define UAC_VERSION_2			0x20
+
 /* A.2 Audio Interface Subclass Codes */
 /* A.2 Audio Interface Subclass Codes */
 #define USB_SUBCLASS_AUDIOCONTROL	0x01
 #define USB_SUBCLASS_AUDIOCONTROL	0x01
 #define USB_SUBCLASS_AUDIOSTREAMING	0x02
 #define USB_SUBCLASS_AUDIOSTREAMING	0x02
 #define USB_SUBCLASS_MIDISTREAMING	0x03
 #define USB_SUBCLASS_MIDISTREAMING	0x03
 
 
-#define UAC_VERSION_1			0x00
-#define UAC_VERSION_2			0x20
-
 /* A.5 Audio Class-Specific AC Interface Descriptor Subtypes */
 /* A.5 Audio Class-Specific AC Interface Descriptor Subtypes */
 #define UAC_HEADER			0x01
 #define UAC_HEADER			0x01
 #define UAC_INPUT_TERMINAL		0x02
 #define UAC_INPUT_TERMINAL		0x02
@@ -38,15 +42,6 @@
 #define UAC_PROCESSING_UNIT_V1		0x07
 #define UAC_PROCESSING_UNIT_V1		0x07
 #define UAC_EXTENSION_UNIT_V1		0x08
 #define UAC_EXTENSION_UNIT_V1		0x08
 
 
-/* UAC v2.0 types */
-#define UAC_EFFECT_UNIT			0x07
-#define UAC_PROCESSING_UNIT_V2		0x08
-#define UAC_EXTENSION_UNIT_V2		0x09
-#define UAC_CLOCK_SOURCE		0x0a
-#define UAC_CLOCK_SELECTOR		0x0b
-#define UAC_CLOCK_MULTIPLIER		0x0c
-#define UAC_SAMPLE_RATE_CONVERTER	0x0d
-
 /* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */
 /* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */
 #define UAC_AS_GENERAL			0x01
 #define UAC_AS_GENERAL			0x01
 #define UAC_FORMAT_TYPE			0x02
 #define UAC_FORMAT_TYPE			0x02
@@ -78,10 +73,6 @@
 
 
 #define UAC_GET_STAT			0xff
 #define UAC_GET_STAT			0xff
 
 
-/* Audio class v2.0 handles all the parameter calls differently */
-#define UAC2_CS_CUR			0x01
-#define UAC2_CS_RANGE			0x02
-
 /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */
 /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */
 #define UAC_MS_HEADER			0x01
 #define UAC_MS_HEADER			0x01
 #define UAC_MIDI_IN_JACK		0x02
 #define UAC_MIDI_IN_JACK		0x02
@@ -190,6 +181,156 @@ struct uac_feature_unit_descriptor_##ch {			\
 	__u8  iFeature;						\
 	__u8  iFeature;						\
 } __attribute__ ((packed))
 } __attribute__ ((packed))
 
 
+/* 4.3.2.3 Mixer Unit Descriptor */
+struct uac_mixer_unit_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bUnitID;
+	__u8 bNrInPins;
+	__u8 baSourceID[];
+} __attribute__ ((packed));
+
+static inline __u8 uac_mixer_unit_bNrChannels(struct uac_mixer_unit_descriptor *desc)
+{
+	return desc->baSourceID[desc->bNrInPins];
+}
+
+static inline __u32 uac_mixer_unit_wChannelConfig(struct uac_mixer_unit_descriptor *desc,
+						  int protocol)
+{
+	if (protocol == UAC_VERSION_1)
+		return (desc->baSourceID[desc->bNrInPins + 2] << 8) |
+			desc->baSourceID[desc->bNrInPins + 1];
+	else
+		return  (desc->baSourceID[desc->bNrInPins + 4] << 24) |
+			(desc->baSourceID[desc->bNrInPins + 3] << 16) |
+			(desc->baSourceID[desc->bNrInPins + 2] << 8)  |
+			(desc->baSourceID[desc->bNrInPins + 1]);
+}
+
+static inline __u8 uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor *desc,
+						int protocol)
+{
+	return (protocol == UAC_VERSION_1) ?
+		desc->baSourceID[desc->bNrInPins + 3] :
+		desc->baSourceID[desc->bNrInPins + 5];
+}
+
+static inline __u8 *uac_mixer_unit_bmControls(struct uac_mixer_unit_descriptor *desc,
+					      int protocol)
+{
+	return (protocol == UAC_VERSION_1) ?
+		&desc->baSourceID[desc->bNrInPins + 4] :
+		&desc->baSourceID[desc->bNrInPins + 6];
+}
+
+static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor *desc)
+{
+	__u8 *raw = (__u8 *) desc;
+	return raw[desc->bLength - 1];
+}
+
+/* 4.3.2.4 Selector Unit Descriptor */
+struct uac_selector_unit_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bUintID;
+	__u8 bNrInPins;
+	__u8 baSourceID[];
+} __attribute__ ((packed));
+
+static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc)
+{
+	__u8 *raw = (__u8 *) desc;
+	return raw[9 + desc->bLength - 1];
+}
+
+/* 4.3.2.5 Feature Unit Descriptor */
+struct uac_feature_unit_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bUnitID;
+	__u8 bSourceID;
+	__u8 bControlSize;
+	__u8 bmaControls[0]; /* variable length */
+} __attribute__((packed));
+
+static inline __u8 uac_feature_unit_iFeature(struct uac_feature_unit_descriptor *desc)
+{
+	__u8 *raw = (__u8 *) desc;
+	return raw[desc->bLength - 1];
+}
+
+/* 4.3.2.6 Processing Unit Descriptors */
+struct uac_processing_unit_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bUnitID;
+	__u16 wProcessType;
+	__u8 bNrInPins;
+	__u8 baSourceID[];
+} __attribute__ ((packed));
+
+static inline __u8 uac_processing_unit_bNrChannels(struct uac_processing_unit_descriptor *desc)
+{
+	return desc->baSourceID[desc->bNrInPins];
+}
+
+static inline __u32 uac_processing_unit_wChannelConfig(struct uac_processing_unit_descriptor *desc,
+						       int protocol)
+{
+	if (protocol == UAC_VERSION_1)
+		return (desc->baSourceID[desc->bNrInPins + 2] << 8) |
+			desc->baSourceID[desc->bNrInPins + 1];
+	else
+		return  (desc->baSourceID[desc->bNrInPins + 4] << 24) |
+			(desc->baSourceID[desc->bNrInPins + 3] << 16) |
+			(desc->baSourceID[desc->bNrInPins + 2] << 8)  |
+			(desc->baSourceID[desc->bNrInPins + 1]);
+}
+
+static inline __u8 uac_processing_unit_iChannelNames(struct uac_processing_unit_descriptor *desc,
+						     int protocol)
+{
+	return (protocol == UAC_VERSION_1) ?
+		desc->baSourceID[desc->bNrInPins + 3] :
+		desc->baSourceID[desc->bNrInPins + 5];
+}
+
+static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_descriptor *desc,
+						    int protocol)
+{
+	return (protocol == UAC_VERSION_1) ?
+		desc->baSourceID[desc->bNrInPins + 4] :
+		desc->baSourceID[desc->bNrInPins + 6];
+}
+
+static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc,
+						   int protocol)
+{
+	return (protocol == UAC_VERSION_1) ?
+		&desc->baSourceID[desc->bNrInPins + 5] :
+		&desc->baSourceID[desc->bNrInPins + 7];
+}
+
+static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc,
+						   int protocol)
+{
+	__u8 control_size = uac_processing_unit_bControlSize(desc, protocol);
+	return desc->baSourceID[desc->bNrInPins + control_size];
+}
+
+static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc,
+						 int protocol)
+{
+	__u8 control_size = uac_processing_unit_bControlSize(desc, protocol);
+	return &desc->baSourceID[desc->bNrInPins + control_size + 1];
+}
+
 /* 4.5.2 Class-Specific AS Interface Descriptor */
 /* 4.5.2 Class-Specific AS Interface Descriptor */
 struct uac_as_header_descriptor_v1 {
 struct uac_as_header_descriptor_v1 {
 	__u8  bLength;			/* in bytes: 7 */
 	__u8  bLength;			/* in bytes: 7 */
@@ -200,19 +341,6 @@ struct uac_as_header_descriptor_v1 {
 	__le16 wFormatTag;		/* The Audio Data Format */
 	__le16 wFormatTag;		/* The Audio Data Format */
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
-struct uac_as_header_descriptor_v2 {
-	__u8 bLength;
-	__u8 bDescriptorType;
-	__u8 bDescriptorSubtype;
-	__u8 bTerminalLink;
-	__u8 bmControls;
-	__u8 bFormatType;
-	__u32 bmFormats;
-	__u8 bNrChannels;
-	__u32 bmChannelConfig;
-	__u8 iChannelNames;
-} __attribute__((packed));
-
 #define UAC_DT_AS_HEADER_SIZE		7
 #define UAC_DT_AS_HEADER_SIZE		7
 
 
 /* Formats - A.1.1 Audio Data Format Type I Codes */
 /* Formats - A.1.1 Audio Data Format Type I Codes */
@@ -277,7 +405,6 @@ struct uac_format_type_i_ext_descriptor {
 	__u8 bSideBandProtocol;
 	__u8 bSideBandProtocol;
 } __attribute__((packed));
 } __attribute__((packed));
 
 
-
 /* Formats - Audio Data Format Type I Codes */
 /* Formats - Audio Data Format Type I Codes */
 
 
 #define UAC_FORMAT_TYPE_II_MPEG	0x1001
 #define UAC_FORMAT_TYPE_II_MPEG	0x1001
@@ -329,38 +456,15 @@ struct uac_iso_endpoint_descriptor {
 	__u8  bmAttributes;
 	__u8  bmAttributes;
 	__u8  bLockDelayUnits;
 	__u8  bLockDelayUnits;
 	__le16 wLockDelay;
 	__le16 wLockDelay;
-};
+} __attribute__((packed));
 #define UAC_ISO_ENDPOINT_DESC_SIZE	7
 #define UAC_ISO_ENDPOINT_DESC_SIZE	7
 
 
 #define UAC_EP_CS_ATTR_SAMPLE_RATE	0x01
 #define UAC_EP_CS_ATTR_SAMPLE_RATE	0x01
 #define UAC_EP_CS_ATTR_PITCH_CONTROL	0x02
 #define UAC_EP_CS_ATTR_PITCH_CONTROL	0x02
 #define UAC_EP_CS_ATTR_FILL_MAX		0x80
 #define UAC_EP_CS_ATTR_FILL_MAX		0x80
 
 
-/* Audio class v2.0: CLOCK_SOURCE descriptor */
-
-struct uac_clock_source_descriptor {
-	__u8 bLength;
-	__u8 bDescriptorType;
-	__u8 bDescriptorSubtype;
-	__u8 bClockID;
-	__u8 bmAttributes;
-	__u8 bmControls;
-	__u8 bAssocTerminal;
-	__u8 iClockSource;
-} __attribute__((packed));
-
 /* A.10.2 Feature Unit Control Selectors */
 /* A.10.2 Feature Unit Control Selectors */
 
 
-struct uac_feature_unit_descriptor {
-	__u8 bLength;
-	__u8 bDescriptorType;
-	__u8 bDescriptorSubtype;
-	__u8 bUnitID;
-	__u8 bSourceID;
-	__u8 bControlSize;
-	__u8 controls[0]; /* variable length */
-} __attribute__((packed));
-
 #define UAC_FU_CONTROL_UNDEFINED	0x00
 #define UAC_FU_CONTROL_UNDEFINED	0x00
 #define UAC_MUTE_CONTROL		0x01
 #define UAC_MUTE_CONTROL		0x01
 #define UAC_VOLUME_CONTROL		0x02
 #define UAC_VOLUME_CONTROL		0x02
@@ -384,6 +488,21 @@ struct uac_feature_unit_descriptor {
 #define UAC_FU_BASS_BOOST	(1 << (UAC_BASS_BOOST_CONTROL - 1))
 #define UAC_FU_BASS_BOOST	(1 << (UAC_BASS_BOOST_CONTROL - 1))
 #define UAC_FU_LOUDNESS		(1 << (UAC_LOUDNESS_CONTROL - 1))
 #define UAC_FU_LOUDNESS		(1 << (UAC_LOUDNESS_CONTROL - 1))
 
 
+/* status word format (3.7.1.1) */
+
+#define UAC1_STATUS_TYPE_ORIG_MASK		0x0f
+#define UAC1_STATUS_TYPE_ORIG_AUDIO_CONTROL_IF	0x0
+#define UAC1_STATUS_TYPE_ORIG_AUDIO_STREAM_IF	0x1
+#define UAC1_STATUS_TYPE_ORIG_AUDIO_STREAM_EP	0x2
+
+#define UAC1_STATUS_TYPE_IRQ_PENDING		(1 << 7)
+#define UAC1_STATUS_TYPE_MEM_CHANGED		(1 << 6)
+
+struct uac1_status_word {
+	__u8 bStatusType;
+	__u8 bOriginator;
+} __attribute__((packed));
+
 #ifdef __KERNEL__
 #ifdef __KERNEL__
 
 
 struct usb_audio_control {
 struct usb_audio_control {

+ 10 - 10
include/sound/asound.h

@@ -574,7 +574,7 @@ enum {
 #define SNDRV_TIMER_FLG_SLAVE		(1<<0)	/* cannot be controlled */
 #define SNDRV_TIMER_FLG_SLAVE		(1<<0)	/* cannot be controlled */
 
 
 struct snd_timer_id {
 struct snd_timer_id {
-	int dev_class;	
+	int dev_class;
 	int dev_sclass;
 	int dev_sclass;
 	int card;
 	int card;
 	int device;
 	int device;
@@ -762,7 +762,7 @@ struct snd_ctl_elem_id {
 	snd_ctl_elem_iface_t iface;	/* interface identifier */
 	snd_ctl_elem_iface_t iface;	/* interface identifier */
 	unsigned int device;		/* device/client number */
 	unsigned int device;		/* device/client number */
 	unsigned int subdevice;		/* subdevice (substream) number */
 	unsigned int subdevice;		/* subdevice (substream) number */
-        unsigned char name[44];		/* ASCII name of item */
+	unsigned char name[44];		/* ASCII name of item */
 	unsigned int index;		/* index of item */
 	unsigned int index;		/* index of item */
 };
 };
 
 
@@ -809,7 +809,7 @@ struct snd_ctl_elem_info {
 struct snd_ctl_elem_value {
 struct snd_ctl_elem_value {
 	struct snd_ctl_elem_id id;	/* W: element ID */
 	struct snd_ctl_elem_id id;	/* W: element ID */
 	unsigned int indirect: 1;	/* W: indirect access - obsoleted */
 	unsigned int indirect: 1;	/* W: indirect access - obsoleted */
-        union {
+	union {
 		union {
 		union {
 			long value[128];
 			long value[128];
 			long *value_ptr;	/* obsoleted */
 			long *value_ptr;	/* obsoleted */
@@ -827,15 +827,15 @@ struct snd_ctl_elem_value {
 			unsigned char *data_ptr;	/* obsoleted */
 			unsigned char *data_ptr;	/* obsoleted */
 		} bytes;
 		} bytes;
 		struct snd_aes_iec958 iec958;
 		struct snd_aes_iec958 iec958;
-        } value;                /* RO */
+	} value;		/* RO */
 	struct timespec tstamp;
 	struct timespec tstamp;
-        unsigned char reserved[128-sizeof(struct timespec)];
+	unsigned char reserved[128-sizeof(struct timespec)];
 };
 };
 
 
 struct snd_ctl_tlv {
 struct snd_ctl_tlv {
-        unsigned int numid;	/* control element numeric identification */
-        unsigned int length;	/* in bytes aligned to 4 */
-        unsigned int tlv[0];	/* first TLV */
+	unsigned int numid;	/* control element numeric identification */
+	unsigned int length;	/* in bytes aligned to 4 */
+	unsigned int tlv[0];	/* first TLV */
 };
 };
 
 
 #define SNDRV_CTL_IOCTL_PVERSION	_IOR('U', 0x00, int)
 #define SNDRV_CTL_IOCTL_PVERSION	_IOR('U', 0x00, int)
@@ -886,8 +886,8 @@ struct snd_ctl_event {
 			unsigned int mask;
 			unsigned int mask;
 			struct snd_ctl_elem_id id;
 			struct snd_ctl_elem_id id;
 		} elem;
 		} elem;
-                unsigned char data8[60];
-        } data;
+		unsigned char data8[60];
+	} data;
 };
 };
 
 
 /*
 /*

+ 6 - 5
include/sound/es1688.h

@@ -44,7 +44,6 @@ struct snd_es1688 {
 	unsigned char pad;
 	unsigned char pad;
 	unsigned int dma_size;
 	unsigned int dma_size;
 
 
-	struct snd_card *card;
 	struct snd_pcm *pcm;
 	struct snd_pcm *pcm;
 	struct snd_pcm_substream *playback_substream;
 	struct snd_pcm_substream *playback_substream;
 	struct snd_pcm_substream *capture_substream;
 	struct snd_pcm_substream *capture_substream;
@@ -108,14 +107,16 @@ struct snd_es1688 {
 void snd_es1688_mixer_write(struct snd_es1688 *chip, unsigned char reg, unsigned char data);
 void snd_es1688_mixer_write(struct snd_es1688 *chip, unsigned char reg, unsigned char data);
 
 
 int snd_es1688_create(struct snd_card *card,
 int snd_es1688_create(struct snd_card *card,
+		      struct snd_es1688 *chip,
 		      unsigned long port,
 		      unsigned long port,
 		      unsigned long mpu_port,
 		      unsigned long mpu_port,
 		      int irq,
 		      int irq,
 		      int mpu_irq,
 		      int mpu_irq,
 		      int dma8,
 		      int dma8,
-		      unsigned short hardware,
-		      struct snd_es1688 ** rchip);
-int snd_es1688_pcm(struct snd_es1688 *chip, int device, struct snd_pcm ** rpcm);
-int snd_es1688_mixer(struct snd_es1688 *chip);
+		      unsigned short hardware);
+int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device,
+		   struct snd_pcm **rpcm);
+int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip);
+int snd_es1688_reset(struct snd_es1688 *chip);
 
 
 #endif /* __SOUND_ES1688_H */
 #endif /* __SOUND_ES1688_H */

+ 12 - 12
include/sound/info.h

@@ -51,18 +51,18 @@ struct snd_info_entry_ops {
 		    unsigned short mode, void **file_private_data);
 		    unsigned short mode, void **file_private_data);
 	int (*release)(struct snd_info_entry *entry,
 	int (*release)(struct snd_info_entry *entry,
 		       unsigned short mode, void *file_private_data);
 		       unsigned short mode, void *file_private_data);
-	long (*read)(struct snd_info_entry *entry, void *file_private_data,
-		     struct file *file, char __user *buf,
-		     unsigned long count, unsigned long pos);
-	long (*write)(struct snd_info_entry *entry, void *file_private_data,
-		      struct file *file, const char __user *buf,
-		      unsigned long count, unsigned long pos);
-	long long (*llseek)(struct snd_info_entry *entry,
-			    void *file_private_data, struct file *file,
-			    long long offset, int orig);
-	unsigned int(*poll)(struct snd_info_entry *entry,
-			    void *file_private_data, struct file *file,
-			    poll_table *wait);
+	ssize_t (*read)(struct snd_info_entry *entry, void *file_private_data,
+			struct file *file, char __user *buf,
+			size_t count, loff_t pos);
+	ssize_t (*write)(struct snd_info_entry *entry, void *file_private_data,
+			 struct file *file, const char __user *buf,
+			 size_t count, loff_t pos);
+	loff_t (*llseek)(struct snd_info_entry *entry,
+			 void *file_private_data, struct file *file,
+			 loff_t offset, int orig);
+	unsigned int (*poll)(struct snd_info_entry *entry,
+			     void *file_private_data, struct file *file,
+			     poll_table *wait);
 	int (*ioctl)(struct snd_info_entry *entry, void *file_private_data,
 	int (*ioctl)(struct snd_info_entry *entry, void *file_private_data,
 		     struct file *file, unsigned int cmd, unsigned long arg);
 		     struct file *file, unsigned int cmd, unsigned long arg);
 	int (*mmap)(struct snd_info_entry *entry, void *file_private_data,
 	int (*mmap)(struct snd_info_entry *entry, void *file_private_data,

+ 8 - 0
include/sound/jack.h

@@ -42,6 +42,11 @@ enum snd_jack_types {
 	SND_JACK_MECHANICAL	= 0x0008, /* If detected separately */
 	SND_JACK_MECHANICAL	= 0x0008, /* If detected separately */
 	SND_JACK_VIDEOOUT	= 0x0010,
 	SND_JACK_VIDEOOUT	= 0x0010,
 	SND_JACK_AVOUT		= SND_JACK_LINEOUT | SND_JACK_VIDEOOUT,
 	SND_JACK_AVOUT		= SND_JACK_LINEOUT | SND_JACK_VIDEOOUT,
+
+	/* Kept separate from switches to facilitate implementation */
+	SND_JACK_BTN_0		= 0x4000,
+	SND_JACK_BTN_1		= 0x2000,
+	SND_JACK_BTN_2		= 0x1000,
 };
 };
 
 
 struct snd_jack {
 struct snd_jack {
@@ -50,6 +55,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 */
 	void *private_data;
 	void *private_data;
 	void (*private_free)(struct snd_jack *);
 	void (*private_free)(struct snd_jack *);
 };
 };
@@ -59,6 +65,8 @@ struct snd_jack {
 int snd_jack_new(struct snd_card *card, const char *id, int type,
 int snd_jack_new(struct snd_card *card, const char *id, int type,
 		 struct snd_jack **jack);
 		 struct snd_jack **jack);
 void snd_jack_set_parent(struct snd_jack *jack, struct device *parent);
 void snd_jack_set_parent(struct snd_jack *jack, struct device *parent);
+int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type,
+		     int keytype);
 
 
 void snd_jack_report(struct snd_jack *jack, int status);
 void snd_jack_report(struct snd_jack *jack, int status);
 
 

+ 6 - 1
include/sound/soc-dai.h

@@ -182,6 +182,12 @@ struct snd_soc_dai_ops {
 		struct snd_soc_dai *);
 		struct snd_soc_dai *);
 	int (*trigger)(struct snd_pcm_substream *, int,
 	int (*trigger)(struct snd_pcm_substream *, int,
 		struct snd_soc_dai *);
 		struct snd_soc_dai *);
+	/*
+	 * For hardware based FIFO caused delay reporting.
+	 * Optional.
+	 */
+	snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
+		struct snd_soc_dai *);
 };
 };
 
 
 /*
 /*
@@ -215,7 +221,6 @@ struct snd_soc_dai {
 	unsigned int symmetric_rates:1;
 	unsigned int symmetric_rates:1;
 
 
 	/* DAI runtime info */
 	/* DAI runtime info */
-	struct snd_pcm_runtime *runtime;
 	struct snd_soc_codec *codec;
 	struct snd_soc_codec *codec;
 	unsigned int active;
 	unsigned int active;
 	unsigned char pop_wait:1;
 	unsigned char pop_wait:1;

+ 5 - 3
include/sound/soc-dapm.h

@@ -339,6 +339,9 @@ int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin);
 int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin);
 int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin);
 int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin);
 int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin);
 int snd_soc_dapm_sync(struct snd_soc_codec *codec);
 int snd_soc_dapm_sync(struct snd_soc_codec *codec);
+int snd_soc_dapm_force_enable_pin(struct snd_soc_codec *codec,
+				  const char *pin);
+int snd_soc_dapm_ignore_suspend(struct snd_soc_codec *codec, const char *pin);
 
 
 /* dapm widget types */
 /* dapm widget types */
 enum snd_soc_dapm_type {
 enum snd_soc_dapm_type {
@@ -425,9 +428,8 @@ struct snd_soc_dapm_widget {
 	unsigned char connected:1;		/* connected codec pin */
 	unsigned char connected:1;		/* connected codec pin */
 	unsigned char new:1;			/* cnew complete */
 	unsigned char new:1;			/* cnew complete */
 	unsigned char ext:1;			/* has external widgets */
 	unsigned char ext:1;			/* has external widgets */
-	unsigned char muted:1;			/* muted for pop reduction */
-	unsigned char suspend:1;		/* was active before suspend */
-	unsigned char pmdown:1;			/* waiting for timeout */
+	unsigned char force:1;			/* force state */
+	unsigned char ignore_suspend:1;         /* kept enabled over suspend */
 
 
 	int (*power_check)(struct snd_soc_dapm_widget *w);
 	int (*power_check)(struct snd_soc_dapm_widget *w);
 
 

+ 46 - 15
include/sound/soc.h

@@ -15,6 +15,7 @@
 
 
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
 #include <linux/types.h>
+#include <linux/notifier.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -29,10 +30,10 @@
 #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
 #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
 	((unsigned long)&(struct soc_mixer_control) \
 	((unsigned long)&(struct soc_mixer_control) \
 	{.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \
 	{.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \
-	.invert = xinvert})
+	.platform_max = xmax, .invert = xinvert})
 #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
 #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
 	((unsigned long)&(struct soc_mixer_control) \
 	((unsigned long)&(struct soc_mixer_control) \
-	{.reg = xreg, .max = xmax, .invert = xinvert})
+	{.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert})
 #define SOC_SINGLE(xname, reg, shift, max, invert) \
 #define SOC_SINGLE(xname, reg, shift, max, invert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
@@ -52,14 +53,14 @@
 	.put = snd_soc_put_volsw, \
 	.put = snd_soc_put_volsw, \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 		{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
 		{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
-		 .max = xmax, .invert = xinvert} }
+		 .max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
 #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 	.info = snd_soc_info_volsw_2r, \
 	.info = snd_soc_info_volsw_2r, \
 	.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
 	.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 		{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
 		{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
-		.max = xmax, .invert = xinvert} }
+		.max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \
 #define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@@ -69,7 +70,7 @@
 	.put = snd_soc_put_volsw, \
 	.put = snd_soc_put_volsw, \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 		{.reg = xreg, .shift = shift_left, .rshift = shift_right,\
 		{.reg = xreg, .shift = shift_left, .rshift = shift_right,\
-		 .max = xmax, .invert = xinvert} }
+		 .max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
 #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@@ -79,7 +80,7 @@
 	.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
 	.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 		{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
 		{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
-		.max = xmax, .invert = xinvert} }
+		.max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
 #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
 {	.iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 {	.iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
@@ -88,7 +89,8 @@
 	.info   = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
 	.info   = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
 	.put    = snd_soc_put_volsw_s8, \
 	.put    = snd_soc_put_volsw_s8, \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
-		{.reg = xreg, .min = xmin, .max = xmax} }
+		{.reg = xreg, .min = xmin, .max = xmax, \
+		 .platform_max = xmax} }
 #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \
 #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \
 {	.reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
 {	.reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
 	.max = xmax, .texts = xtexts }
 	.max = xmax, .texts = xtexts }
@@ -125,7 +127,7 @@
 	.get = xhandler_get, .put = xhandler_put, \
 	.get = xhandler_get, .put = xhandler_put, \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 		{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
 		{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
-		 .max = xmax, .invert = xinvert} }
+		 .max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
 #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
 	 xhandler_get, xhandler_put, tlv_array) \
 	 xhandler_get, xhandler_put, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -145,7 +147,7 @@
 	.get = xhandler_get, .put = xhandler_put, \
 	.get = xhandler_get, .put = xhandler_put, \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 		{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
 		{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
-		.max = xmax, .invert = xinvert} }
+		.max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\
 #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\
 	 xhandler_get, xhandler_put, tlv_array) \
 	 xhandler_get, xhandler_put, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
@@ -156,7 +158,7 @@
 	.get = xhandler_get, .put = xhandler_put, \
 	.get = xhandler_get, .put = xhandler_put, \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 	.private_value = (unsigned long)&(struct soc_mixer_control) \
 		{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
 		{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
-		.max = xmax, .invert = xinvert} }
+		.max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
 #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_bool_ext, \
 	.info = snd_soc_info_bool_ext, \
@@ -212,6 +214,7 @@ 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_platform;
 struct snd_soc_platform;
+struct snd_soc_dai_link;
 struct snd_soc_codec;
 struct snd_soc_codec;
 struct soc_enum;
 struct soc_enum;
 struct snd_soc_ac97_ops;
 struct snd_soc_ac97_ops;
@@ -260,6 +263,10 @@ int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
 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,
 			  struct snd_soc_jack_pin *pins);
 			  struct snd_soc_jack_pin *pins);
+void snd_soc_jack_notifier_register(struct snd_soc_jack *jack,
+				    struct notifier_block *nb);
+void snd_soc_jack_notifier_unregister(struct snd_soc_jack *jack,
+				      struct notifier_block *nb);
 #ifdef CONFIG_GPIOLIB
 #ifdef CONFIG_GPIOLIB
 int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
 int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
 			struct snd_soc_jack_gpio *gpios);
 			struct snd_soc_jack_gpio *gpios);
@@ -320,6 +327,8 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
 	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
 int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
 	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_limit_volume(struct snd_soc_codec *codec,
+	const char *name, int max);
 
 
 /**
 /**
  * struct snd_soc_jack_pin - Describes a pin to update based on jack detection
  * struct snd_soc_jack_pin - Describes a pin to update based on jack detection
@@ -363,6 +372,7 @@ struct snd_soc_jack {
 	struct snd_soc_card *card;
 	struct snd_soc_card *card;
 	struct list_head pins;
 	struct list_head pins;
 	int status;
 	int status;
+	struct blocking_notifier_head notifier;
 };
 };
 
 
 /* SoC PCM stream information */
 /* SoC PCM stream information */
@@ -374,7 +384,7 @@ struct snd_soc_pcm_stream {
 	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:1;		/* stream is in use */
+	unsigned int active;		/* stream is in use */
 	void *dma_data;			/* used by platform code */
 	void *dma_data;			/* used by platform code */
 };
 };
 
 
@@ -407,7 +417,7 @@ struct snd_soc_codec {
 	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;
 	unsigned int pcm_devs;
-	void *private_data;
+	void *drvdata;
 
 
 	/* codec IO */
 	/* codec IO */
 	void *control_data; /* codec control (i2c/3wire) data */
 	void *control_data; /* codec control (i2c/3wire) data */
@@ -462,14 +472,21 @@ struct snd_soc_platform {
 
 
 	int (*probe)(struct platform_device *pdev);
 	int (*probe)(struct platform_device *pdev);
 	int (*remove)(struct platform_device *pdev);
 	int (*remove)(struct platform_device *pdev);
-	int (*suspend)(struct snd_soc_dai *dai);
-	int (*resume)(struct snd_soc_dai *dai);
+	int (*suspend)(struct snd_soc_dai_link *dai_link);
+	int (*resume)(struct snd_soc_dai_link *dai_link);
 
 
 	/* 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 *,
 		struct snd_pcm *);
 		struct snd_pcm *);
 	void (*pcm_free)(struct snd_pcm *);
 	void (*pcm_free)(struct snd_pcm *);
 
 
+	/*
+	 * For platform caused delay reporting.
+	 * Optional.
+	 */
+	snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
+		struct snd_soc_dai *);
+
 	/* platform stream ops */
 	/* platform stream ops */
 	struct snd_pcm_ops *pcm_ops;
 	struct snd_pcm_ops *pcm_ops;
 };
 };
@@ -489,6 +506,9 @@ struct snd_soc_dai_link  {
 	/* codec/machine specific init - e.g. add machine controls */
 	/* codec/machine specific init - e.g. add machine controls */
 	int (*init)(struct snd_soc_codec *codec);
 	int (*init)(struct snd_soc_codec *codec);
 
 
+	/* Keep DAI active over suspend */
+	unsigned int ignore_suspend:1;
+
 	/* Symmetry requirements */
 	/* Symmetry requirements */
 	unsigned int symmetric_rates:1;
 	unsigned int symmetric_rates:1;
 
 
@@ -553,7 +573,7 @@ struct snd_soc_pcm_runtime {
 
 
 /* mixer control */
 /* mixer control */
 struct soc_mixer_control {
 struct soc_mixer_control {
-	int min, max;
+	int min, max, platform_max;
 	unsigned int reg, rreg, shift, rshift, invert;
 	unsigned int reg, rreg, shift, rshift, invert;
 };
 };
 
 
@@ -583,6 +603,17 @@ static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
 	return codec->write(codec, reg, val);
 	return codec->write(codec, reg, val);
 }
 }
 
 
+static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
+					     void *data)
+{
+	codec->drvdata = data;
+}
+
+static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
+{
+	return codec->drvdata;
+}
+
 #include <sound/soc-dai.h>
 #include <sound/soc-dai.h>
 
 
 #endif
 #endif

+ 17 - 0
include/sound/tlv320aic3x.h

@@ -0,0 +1,17 @@
+/*
+ * Platform data for Texas Instruments TLV320AIC3x codec
+ *
+ * Author: Jarkko Nikula <jhnikula@gmail.com>
+ *
+ * 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 __TLV320AIC3x_H__
+#define __TLV320AIC3x_H__
+
+struct aic3x_pdata {
+	int gpio_reset; /* < 0 if not used */
+};
+
+#endif

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

@@ -15,6 +15,7 @@
 
 
 struct tlv320dac33_platform_data {
 struct tlv320dac33_platform_data {
 	int power_gpio;
 	int power_gpio;
+	int keep_bclk;	/* Keep the BCLK running in FIFO modes */
 	u8 burst_bclkdiv;
 	u8 burst_bclkdiv;
 };
 };
 
 

+ 1 - 0
include/sound/uda134x.h

@@ -21,6 +21,7 @@ struct uda134x_platform_data {
 #define UDA134X_UDA1340 1
 #define UDA134X_UDA1340 1
 #define UDA134X_UDA1341 2
 #define UDA134X_UDA1341 2
 #define UDA134X_UDA1344 3
 #define UDA134X_UDA1344 3
+#define UDA134X_UDA1345 4
 };
 };
 
 
 #endif /* _UDA134X_H */
 #endif /* _UDA134X_H */

+ 1 - 1
include/sound/version.h

@@ -1,3 +1,3 @@
 /* include/version.h */
 /* include/version.h */
-#define CONFIG_SND_VERSION "1.0.22.1"
+#define CONFIG_SND_VERSION "1.0.23"
 #define CONFIG_SND_DATE ""
 #define CONFIG_SND_DATE ""

+ 249 - 0
include/sound/wm8903.h

@@ -0,0 +1,249 @@
+/*
+ * linux/sound/wm8903.h -- Platform data for WM8903
+ *
+ * Copyright 2010 Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_WM8903_H
+#define __LINUX_SND_WM8903_H
+
+/* Used to enable configuration of a GPIO to all zeros */
+#define WM8903_GPIO_NO_CONFIG 0x8000
+
+/*
+ * R6 (0x06) - Mic Bias Control 0
+ */
+#define WM8903_MICDET_HYST_ENA                  0x0080  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_HYST_ENA_MASK             0x0080  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_HYST_ENA_SHIFT                 7  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_HYST_ENA_WIDTH                 1  /* MICDET_HYST_ENA */
+#define WM8903_MICDET_THR_MASK                  0x0070  /* MICDET_THR - [6:4] */
+#define WM8903_MICDET_THR_SHIFT                      4  /* MICDET_THR - [6:4] */
+#define WM8903_MICDET_THR_WIDTH                      3  /* MICDET_THR - [6:4] */
+#define WM8903_MICSHORT_THR_MASK                0x000C  /* MICSHORT_THR - [3:2] */
+#define WM8903_MICSHORT_THR_SHIFT                    2  /* MICSHORT_THR - [3:2] */
+#define WM8903_MICSHORT_THR_WIDTH                    2  /* MICSHORT_THR - [3:2] */
+#define WM8903_MICDET_ENA                       0x0002  /* MICDET_ENA */
+#define WM8903_MICDET_ENA_MASK                  0x0002  /* MICDET_ENA */
+#define WM8903_MICDET_ENA_SHIFT                      1  /* MICDET_ENA */
+#define WM8903_MICDET_ENA_WIDTH                      1  /* MICDET_ENA */
+#define WM8903_MICBIAS_ENA                      0x0001  /* MICBIAS_ENA */
+#define WM8903_MICBIAS_ENA_MASK                 0x0001  /* MICBIAS_ENA */
+#define WM8903_MICBIAS_ENA_SHIFT                     0  /* MICBIAS_ENA */
+#define WM8903_MICBIAS_ENA_WIDTH                     1  /* MICBIAS_ENA */
+
+/*
+ * R116 (0x74) - GPIO Control 1
+ */
+#define WM8903_GP1_FN_MASK                      0x1F00  /* GP1_FN - [12:8] */
+#define WM8903_GP1_FN_SHIFT                          8  /* GP1_FN - [12:8] */
+#define WM8903_GP1_FN_WIDTH                          5  /* GP1_FN - [12:8] */
+#define WM8903_GP1_DIR                          0x0080  /* GP1_DIR */
+#define WM8903_GP1_DIR_MASK                     0x0080  /* GP1_DIR */
+#define WM8903_GP1_DIR_SHIFT                         7  /* GP1_DIR */
+#define WM8903_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM8903_GP1_OP_CFG                       0x0040  /* GP1_OP_CFG */
+#define WM8903_GP1_OP_CFG_MASK                  0x0040  /* GP1_OP_CFG */
+#define WM8903_GP1_OP_CFG_SHIFT                      6  /* GP1_OP_CFG */
+#define WM8903_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM8903_GP1_IP_CFG                       0x0020  /* GP1_IP_CFG */
+#define WM8903_GP1_IP_CFG_MASK                  0x0020  /* GP1_IP_CFG */
+#define WM8903_GP1_IP_CFG_SHIFT                      5  /* GP1_IP_CFG */
+#define WM8903_GP1_IP_CFG_WIDTH                      1  /* GP1_IP_CFG */
+#define WM8903_GP1_LVL                          0x0010  /* GP1_LVL */
+#define WM8903_GP1_LVL_MASK                     0x0010  /* GP1_LVL */
+#define WM8903_GP1_LVL_SHIFT                         4  /* GP1_LVL */
+#define WM8903_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM8903_GP1_PD                           0x0008  /* GP1_PD */
+#define WM8903_GP1_PD_MASK                      0x0008  /* GP1_PD */
+#define WM8903_GP1_PD_SHIFT                          3  /* GP1_PD */
+#define WM8903_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM8903_GP1_PU                           0x0004  /* GP1_PU */
+#define WM8903_GP1_PU_MASK                      0x0004  /* GP1_PU */
+#define WM8903_GP1_PU_SHIFT                          2  /* GP1_PU */
+#define WM8903_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM8903_GP1_INTMODE                      0x0002  /* GP1_INTMODE */
+#define WM8903_GP1_INTMODE_MASK                 0x0002  /* GP1_INTMODE */
+#define WM8903_GP1_INTMODE_SHIFT                     1  /* GP1_INTMODE */
+#define WM8903_GP1_INTMODE_WIDTH                     1  /* GP1_INTMODE */
+#define WM8903_GP1_DB                           0x0001  /* GP1_DB */
+#define WM8903_GP1_DB_MASK                      0x0001  /* GP1_DB */
+#define WM8903_GP1_DB_SHIFT                          0  /* GP1_DB */
+#define WM8903_GP1_DB_WIDTH                          1  /* GP1_DB */
+
+/*
+ * R117 (0x75) - GPIO Control 2
+ */
+#define WM8903_GP2_FN_MASK                      0x1F00  /* GP2_FN - [12:8] */
+#define WM8903_GP2_FN_SHIFT                          8  /* GP2_FN - [12:8] */
+#define WM8903_GP2_FN_WIDTH                          5  /* GP2_FN - [12:8] */
+#define WM8903_GP2_DIR                          0x0080  /* GP2_DIR */
+#define WM8903_GP2_DIR_MASK                     0x0080  /* GP2_DIR */
+#define WM8903_GP2_DIR_SHIFT                         7  /* GP2_DIR */
+#define WM8903_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM8903_GP2_OP_CFG                       0x0040  /* GP2_OP_CFG */
+#define WM8903_GP2_OP_CFG_MASK                  0x0040  /* GP2_OP_CFG */
+#define WM8903_GP2_OP_CFG_SHIFT                      6  /* GP2_OP_CFG */
+#define WM8903_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM8903_GP2_IP_CFG                       0x0020  /* GP2_IP_CFG */
+#define WM8903_GP2_IP_CFG_MASK                  0x0020  /* GP2_IP_CFG */
+#define WM8903_GP2_IP_CFG_SHIFT                      5  /* GP2_IP_CFG */
+#define WM8903_GP2_IP_CFG_WIDTH                      1  /* GP2_IP_CFG */
+#define WM8903_GP2_LVL                          0x0010  /* GP2_LVL */
+#define WM8903_GP2_LVL_MASK                     0x0010  /* GP2_LVL */
+#define WM8903_GP2_LVL_SHIFT                         4  /* GP2_LVL */
+#define WM8903_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8903_GP2_PD                           0x0008  /* GP2_PD */
+#define WM8903_GP2_PD_MASK                      0x0008  /* GP2_PD */
+#define WM8903_GP2_PD_SHIFT                          3  /* GP2_PD */
+#define WM8903_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM8903_GP2_PU                           0x0004  /* GP2_PU */
+#define WM8903_GP2_PU_MASK                      0x0004  /* GP2_PU */
+#define WM8903_GP2_PU_SHIFT                          2  /* GP2_PU */
+#define WM8903_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM8903_GP2_INTMODE                      0x0002  /* GP2_INTMODE */
+#define WM8903_GP2_INTMODE_MASK                 0x0002  /* GP2_INTMODE */
+#define WM8903_GP2_INTMODE_SHIFT                     1  /* GP2_INTMODE */
+#define WM8903_GP2_INTMODE_WIDTH                     1  /* GP2_INTMODE */
+#define WM8903_GP2_DB                           0x0001  /* GP2_DB */
+#define WM8903_GP2_DB_MASK                      0x0001  /* GP2_DB */
+#define WM8903_GP2_DB_SHIFT                          0  /* GP2_DB */
+#define WM8903_GP2_DB_WIDTH                          1  /* GP2_DB */
+
+/*
+ * R118 (0x76) - GPIO Control 3
+ */
+#define WM8903_GP3_FN_MASK                      0x1F00  /* GP3_FN - [12:8] */
+#define WM8903_GP3_FN_SHIFT                          8  /* GP3_FN - [12:8] */
+#define WM8903_GP3_FN_WIDTH                          5  /* GP3_FN - [12:8] */
+#define WM8903_GP3_DIR                          0x0080  /* GP3_DIR */
+#define WM8903_GP3_DIR_MASK                     0x0080  /* GP3_DIR */
+#define WM8903_GP3_DIR_SHIFT                         7  /* GP3_DIR */
+#define WM8903_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM8903_GP3_OP_CFG                       0x0040  /* GP3_OP_CFG */
+#define WM8903_GP3_OP_CFG_MASK                  0x0040  /* GP3_OP_CFG */
+#define WM8903_GP3_OP_CFG_SHIFT                      6  /* GP3_OP_CFG */
+#define WM8903_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM8903_GP3_IP_CFG                       0x0020  /* GP3_IP_CFG */
+#define WM8903_GP3_IP_CFG_MASK                  0x0020  /* GP3_IP_CFG */
+#define WM8903_GP3_IP_CFG_SHIFT                      5  /* GP3_IP_CFG */
+#define WM8903_GP3_IP_CFG_WIDTH                      1  /* GP3_IP_CFG */
+#define WM8903_GP3_LVL                          0x0010  /* GP3_LVL */
+#define WM8903_GP3_LVL_MASK                     0x0010  /* GP3_LVL */
+#define WM8903_GP3_LVL_SHIFT                         4  /* GP3_LVL */
+#define WM8903_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8903_GP3_PD                           0x0008  /* GP3_PD */
+#define WM8903_GP3_PD_MASK                      0x0008  /* GP3_PD */
+#define WM8903_GP3_PD_SHIFT                          3  /* GP3_PD */
+#define WM8903_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM8903_GP3_PU                           0x0004  /* GP3_PU */
+#define WM8903_GP3_PU_MASK                      0x0004  /* GP3_PU */
+#define WM8903_GP3_PU_SHIFT                          2  /* GP3_PU */
+#define WM8903_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM8903_GP3_INTMODE                      0x0002  /* GP3_INTMODE */
+#define WM8903_GP3_INTMODE_MASK                 0x0002  /* GP3_INTMODE */
+#define WM8903_GP3_INTMODE_SHIFT                     1  /* GP3_INTMODE */
+#define WM8903_GP3_INTMODE_WIDTH                     1  /* GP3_INTMODE */
+#define WM8903_GP3_DB                           0x0001  /* GP3_DB */
+#define WM8903_GP3_DB_MASK                      0x0001  /* GP3_DB */
+#define WM8903_GP3_DB_SHIFT                          0  /* GP3_DB */
+#define WM8903_GP3_DB_WIDTH                          1  /* GP3_DB */
+
+/*
+ * R119 (0x77) - GPIO Control 4
+ */
+#define WM8903_GP4_FN_MASK                      0x1F00  /* GP4_FN - [12:8] */
+#define WM8903_GP4_FN_SHIFT                          8  /* GP4_FN - [12:8] */
+#define WM8903_GP4_FN_WIDTH                          5  /* GP4_FN - [12:8] */
+#define WM8903_GP4_DIR                          0x0080  /* GP4_DIR */
+#define WM8903_GP4_DIR_MASK                     0x0080  /* GP4_DIR */
+#define WM8903_GP4_DIR_SHIFT                         7  /* GP4_DIR */
+#define WM8903_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM8903_GP4_OP_CFG                       0x0040  /* GP4_OP_CFG */
+#define WM8903_GP4_OP_CFG_MASK                  0x0040  /* GP4_OP_CFG */
+#define WM8903_GP4_OP_CFG_SHIFT                      6  /* GP4_OP_CFG */
+#define WM8903_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM8903_GP4_IP_CFG                       0x0020  /* GP4_IP_CFG */
+#define WM8903_GP4_IP_CFG_MASK                  0x0020  /* GP4_IP_CFG */
+#define WM8903_GP4_IP_CFG_SHIFT                      5  /* GP4_IP_CFG */
+#define WM8903_GP4_IP_CFG_WIDTH                      1  /* GP4_IP_CFG */
+#define WM8903_GP4_LVL                          0x0010  /* GP4_LVL */
+#define WM8903_GP4_LVL_MASK                     0x0010  /* GP4_LVL */
+#define WM8903_GP4_LVL_SHIFT                         4  /* GP4_LVL */
+#define WM8903_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM8903_GP4_PD                           0x0008  /* GP4_PD */
+#define WM8903_GP4_PD_MASK                      0x0008  /* GP4_PD */
+#define WM8903_GP4_PD_SHIFT                          3  /* GP4_PD */
+#define WM8903_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM8903_GP4_PU                           0x0004  /* GP4_PU */
+#define WM8903_GP4_PU_MASK                      0x0004  /* GP4_PU */
+#define WM8903_GP4_PU_SHIFT                          2  /* GP4_PU */
+#define WM8903_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM8903_GP4_INTMODE                      0x0002  /* GP4_INTMODE */
+#define WM8903_GP4_INTMODE_MASK                 0x0002  /* GP4_INTMODE */
+#define WM8903_GP4_INTMODE_SHIFT                     1  /* GP4_INTMODE */
+#define WM8903_GP4_INTMODE_WIDTH                     1  /* GP4_INTMODE */
+#define WM8903_GP4_DB                           0x0001  /* GP4_DB */
+#define WM8903_GP4_DB_MASK                      0x0001  /* GP4_DB */
+#define WM8903_GP4_DB_SHIFT                          0  /* GP4_DB */
+#define WM8903_GP4_DB_WIDTH                          1  /* GP4_DB */
+
+/*
+ * R120 (0x78) - GPIO Control 5
+ */
+#define WM8903_GP5_FN_MASK                      0x1F00  /* GP5_FN - [12:8] */
+#define WM8903_GP5_FN_SHIFT                          8  /* GP5_FN - [12:8] */
+#define WM8903_GP5_FN_WIDTH                          5  /* GP5_FN - [12:8] */
+#define WM8903_GP5_DIR                          0x0080  /* GP5_DIR */
+#define WM8903_GP5_DIR_MASK                     0x0080  /* GP5_DIR */
+#define WM8903_GP5_DIR_SHIFT                         7  /* GP5_DIR */
+#define WM8903_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8903_GP5_OP_CFG                       0x0040  /* GP5_OP_CFG */
+#define WM8903_GP5_OP_CFG_MASK                  0x0040  /* GP5_OP_CFG */
+#define WM8903_GP5_OP_CFG_SHIFT                      6  /* GP5_OP_CFG */
+#define WM8903_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8903_GP5_IP_CFG                       0x0020  /* GP5_IP_CFG */
+#define WM8903_GP5_IP_CFG_MASK                  0x0020  /* GP5_IP_CFG */
+#define WM8903_GP5_IP_CFG_SHIFT                      5  /* GP5_IP_CFG */
+#define WM8903_GP5_IP_CFG_WIDTH                      1  /* GP5_IP_CFG */
+#define WM8903_GP5_LVL                          0x0010  /* GP5_LVL */
+#define WM8903_GP5_LVL_MASK                     0x0010  /* GP5_LVL */
+#define WM8903_GP5_LVL_SHIFT                         4  /* GP5_LVL */
+#define WM8903_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8903_GP5_PD                           0x0008  /* GP5_PD */
+#define WM8903_GP5_PD_MASK                      0x0008  /* GP5_PD */
+#define WM8903_GP5_PD_SHIFT                          3  /* GP5_PD */
+#define WM8903_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8903_GP5_PU                           0x0004  /* GP5_PU */
+#define WM8903_GP5_PU_MASK                      0x0004  /* GP5_PU */
+#define WM8903_GP5_PU_SHIFT                          2  /* GP5_PU */
+#define WM8903_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8903_GP5_INTMODE                      0x0002  /* GP5_INTMODE */
+#define WM8903_GP5_INTMODE_MASK                 0x0002  /* GP5_INTMODE */
+#define WM8903_GP5_INTMODE_SHIFT                     1  /* GP5_INTMODE */
+#define WM8903_GP5_INTMODE_WIDTH                     1  /* GP5_INTMODE */
+#define WM8903_GP5_DB                           0x0001  /* GP5_DB */
+#define WM8903_GP5_DB_MASK                      0x0001  /* GP5_DB */
+#define WM8903_GP5_DB_SHIFT                          0  /* GP5_DB */
+#define WM8903_GP5_DB_WIDTH                          1  /* GP5_DB */
+
+struct wm8903_platform_data {
+	bool irq_active_low;   /* Set if IRQ active low, default high */
+
+        /* Default register value for R6 (Mic bias), used to configure
+	 * microphone detection.  In conjunction with gpio_cfg this
+	 * can be used to route the microphone status signals out onto
+	 * the GPIOs for use with snd_soc_jack_add_gpios().
+	 */
+	u16 micdet_cfg;
+
+	int micdet_delay;      /* Delay after microphone detection (ms) */
+
+	u32 gpio_cfg[5];       /* Default register values for GPIO pin mux */
+};
+
+#endif

+ 108 - 2
include/sound/wm8904.h

@@ -15,8 +15,111 @@
 #ifndef __MFD_WM8994_PDATA_H__
 #ifndef __MFD_WM8994_PDATA_H__
 #define __MFD_WM8994_PDATA_H__
 #define __MFD_WM8994_PDATA_H__
 
 
-#define WM8904_DRC_REGS 4
-#define WM8904_EQ_REGS  25
+/* Used to enable configuration of a GPIO to all zeros */
+#define WM8904_GPIO_NO_CONFIG 0x8000
+
+/*
+ * R6 (0x06) - Mic Bias Control 0
+ */
+#define WM8904_MICDET_THR_MASK                  0x0070  /* MICDET_THR - [6:4] */
+#define WM8904_MICDET_THR_SHIFT                      4  /* MICDET_THR - [6:4] */
+#define WM8904_MICDET_THR_WIDTH                      3  /* MICDET_THR - [6:4] */
+#define WM8904_MICSHORT_THR_MASK                0x000C  /* MICSHORT_THR - [3:2] */
+#define WM8904_MICSHORT_THR_SHIFT                    2  /* MICSHORT_THR - [3:2] */
+#define WM8904_MICSHORT_THR_WIDTH                    2  /* MICSHORT_THR - [3:2] */
+#define WM8904_MICDET_ENA                       0x0002  /* MICDET_ENA */
+#define WM8904_MICDET_ENA_MASK                  0x0002  /* MICDET_ENA */
+#define WM8904_MICDET_ENA_SHIFT                      1  /* MICDET_ENA */
+#define WM8904_MICDET_ENA_WIDTH                      1  /* MICDET_ENA */
+#define WM8904_MICBIAS_ENA                      0x0001  /* MICBIAS_ENA */
+#define WM8904_MICBIAS_ENA_MASK                 0x0001  /* MICBIAS_ENA */
+#define WM8904_MICBIAS_ENA_SHIFT                     0  /* MICBIAS_ENA */
+#define WM8904_MICBIAS_ENA_WIDTH                     1  /* MICBIAS_ENA */
+
+/*
+ * R7 (0x07) - Mic Bias Control 1
+ */
+#define WM8904_MIC_DET_FILTER_ENA               0x8000  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_DET_FILTER_ENA_MASK          0x8000  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_DET_FILTER_ENA_SHIFT             15  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_DET_FILTER_ENA_WIDTH              1  /* MIC_DET_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA             0x4000  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA_MASK        0x4000  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA_SHIFT           14  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MIC_SHORT_FILTER_ENA_WIDTH            1  /* MIC_SHORT_FILTER_ENA */
+#define WM8904_MICBIAS_SEL_MASK                 0x0007  /* MICBIAS_SEL - [2:0] */
+#define WM8904_MICBIAS_SEL_SHIFT                     0  /* MICBIAS_SEL - [2:0] */
+#define WM8904_MICBIAS_SEL_WIDTH                     3  /* MICBIAS_SEL - [2:0] */
+
+
+/*
+ * R121 (0x79) - GPIO Control 1
+ */
+#define WM8904_GPIO1_PU                         0x0020  /* GPIO1_PU */
+#define WM8904_GPIO1_PU_MASK                    0x0020  /* GPIO1_PU */
+#define WM8904_GPIO1_PU_SHIFT                        5  /* GPIO1_PU */
+#define WM8904_GPIO1_PU_WIDTH                        1  /* GPIO1_PU */
+#define WM8904_GPIO1_PD                         0x0010  /* GPIO1_PD */
+#define WM8904_GPIO1_PD_MASK                    0x0010  /* GPIO1_PD */
+#define WM8904_GPIO1_PD_SHIFT                        4  /* GPIO1_PD */
+#define WM8904_GPIO1_PD_WIDTH                        1  /* GPIO1_PD */
+#define WM8904_GPIO1_SEL_MASK                   0x000F  /* GPIO1_SEL - [3:0] */
+#define WM8904_GPIO1_SEL_SHIFT                       0  /* GPIO1_SEL - [3:0] */
+#define WM8904_GPIO1_SEL_WIDTH                       4  /* GPIO1_SEL - [3:0] */
+
+/*
+ * R122 (0x7A) - GPIO Control 2
+ */
+#define WM8904_GPIO2_PU                         0x0020  /* GPIO2_PU */
+#define WM8904_GPIO2_PU_MASK                    0x0020  /* GPIO2_PU */
+#define WM8904_GPIO2_PU_SHIFT                        5  /* GPIO2_PU */
+#define WM8904_GPIO2_PU_WIDTH                        1  /* GPIO2_PU */
+#define WM8904_GPIO2_PD                         0x0010  /* GPIO2_PD */
+#define WM8904_GPIO2_PD_MASK                    0x0010  /* GPIO2_PD */
+#define WM8904_GPIO2_PD_SHIFT                        4  /* GPIO2_PD */
+#define WM8904_GPIO2_PD_WIDTH                        1  /* GPIO2_PD */
+#define WM8904_GPIO2_SEL_MASK                   0x000F  /* GPIO2_SEL - [3:0] */
+#define WM8904_GPIO2_SEL_SHIFT                       0  /* GPIO2_SEL - [3:0] */
+#define WM8904_GPIO2_SEL_WIDTH                       4  /* GPIO2_SEL - [3:0] */
+
+/*
+ * R123 (0x7B) - GPIO Control 3
+ */
+#define WM8904_GPIO3_PU                         0x0020  /* GPIO3_PU */
+#define WM8904_GPIO3_PU_MASK                    0x0020  /* GPIO3_PU */
+#define WM8904_GPIO3_PU_SHIFT                        5  /* GPIO3_PU */
+#define WM8904_GPIO3_PU_WIDTH                        1  /* GPIO3_PU */
+#define WM8904_GPIO3_PD                         0x0010  /* GPIO3_PD */
+#define WM8904_GPIO3_PD_MASK                    0x0010  /* GPIO3_PD */
+#define WM8904_GPIO3_PD_SHIFT                        4  /* GPIO3_PD */
+#define WM8904_GPIO3_PD_WIDTH                        1  /* GPIO3_PD */
+#define WM8904_GPIO3_SEL_MASK                   0x000F  /* GPIO3_SEL - [3:0] */
+#define WM8904_GPIO3_SEL_SHIFT                       0  /* GPIO3_SEL - [3:0] */
+#define WM8904_GPIO3_SEL_WIDTH                       4  /* GPIO3_SEL - [3:0] */
+
+/*
+ * R124 (0x7C) - GPIO Control 4
+ */
+#define WM8904_GPI7_ENA                         0x0200  /* GPI7_ENA */
+#define WM8904_GPI7_ENA_MASK                    0x0200  /* GPI7_ENA */
+#define WM8904_GPI7_ENA_SHIFT                        9  /* GPI7_ENA */
+#define WM8904_GPI7_ENA_WIDTH                        1  /* GPI7_ENA */
+#define WM8904_GPI8_ENA                         0x0100  /* GPI8_ENA */
+#define WM8904_GPI8_ENA_MASK                    0x0100  /* GPI8_ENA */
+#define WM8904_GPI8_ENA_SHIFT                        8  /* GPI8_ENA */
+#define WM8904_GPI8_ENA_WIDTH                        1  /* GPI8_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA               0x0080  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA_MASK          0x0080  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA_SHIFT              7  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_MODE_ENA_WIDTH              1  /* GPIO_BCLK_MODE_ENA */
+#define WM8904_GPIO_BCLK_SEL_MASK               0x000F  /* GPIO_BCLK_SEL - [3:0] */
+#define WM8904_GPIO_BCLK_SEL_SHIFT                   0  /* GPIO_BCLK_SEL - [3:0] */
+#define WM8904_GPIO_BCLK_SEL_WIDTH                   4  /* GPIO_BCLK_SEL - [3:0] */
+
+#define WM8904_MIC_REGS  2
+#define WM8904_GPIO_REGS 4
+#define WM8904_DRC_REGS  4
+#define WM8904_EQ_REGS   25
 
 
 /**
 /**
  * DRC configurations are specified with a label and a set of register
  * DRC configurations are specified with a label and a set of register
@@ -52,6 +155,9 @@ struct wm8904_pdata {
 
 
 	int num_retune_mobile_cfgs;
 	int num_retune_mobile_cfgs;
 	struct wm8904_retune_mobile_cfg *retune_mobile_cfgs;
 	struct wm8904_retune_mobile_cfg *retune_mobile_cfgs;
+
+	u32 gpio_cfg[WM8904_GPIO_REGS];
+	u32 mic_cfg[WM8904_MIC_REGS];
 };
 };
 
 
 #endif
 #endif

+ 24 - 0
include/sound/wm8960.h

@@ -0,0 +1,24 @@
+/*
+ * wm8960.h  --  WM8960 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 _WM8960_PDATA_H
+#define _WM8960_PDATA_H
+
+#define WM8960_DRES_400R 0
+#define WM8960_DRES_200R 1
+#define WM8960_DRES_600R 2
+#define WM8960_DRES_150R 3
+#define WM8960_DRES_MAX  3
+
+struct wm8960_data {
+	bool capless;  /* Headphone outputs configured in capless mode */
+
+	int dres;  /* Discharge resistance for headphone outputs */
+};
+
+#endif

+ 28 - 0
include/sound/wm9090.h

@@ -0,0 +1,28 @@
+/*
+ * linux/sound/wm9090.h -- Platform data for WM9090
+ *
+ * Copyright 2009, 2010 Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_WM9090_H
+#define __LINUX_SND_WM9090_H
+
+struct wm9090_platform_data {
+	/* Line inputs 1 & 2 can optionally be differential */
+	unsigned int lin1_diff:1;
+	unsigned int lin2_diff:1;
+
+	/* AGC configuration.  This is intended to protect the speaker
+	 * against overdriving and will therefore depend on the
+	 * hardware setup with incorrect runtime configuration
+	 * potentially causing hardware damage.
+	 */
+	unsigned int agc_ena:1;
+	u16 agc[3];
+};
+
+#endif

+ 1 - 1
sound/atmel/Kconfig

@@ -12,7 +12,7 @@ config SND_ATMEL_AC97C
 	tristate "Atmel AC97 Controller (AC97C) driver"
 	tristate "Atmel AC97 Controller (AC97C) driver"
 	select SND_PCM
 	select SND_PCM
 	select SND_AC97_CODEC
 	select SND_AC97_CODEC
-	depends on DW_DMAC && AVR32
+	depends on (DW_DMAC && AVR32) || ARCH_AT91
 	help
 	help
 	  ALSA sound driver for the Atmel AC97 controller.
 	  ALSA sound driver for the Atmel AC97 controller.
 
 

+ 266 - 89
sound/atmel/ac97c.c

@@ -13,6 +13,7 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/dmaengine.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
+#include <linux/atmel_pdc.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/module.h>
@@ -31,6 +32,10 @@
 
 
 #include <linux/dw_dmac.h>
 #include <linux/dw_dmac.h>
 
 
+#include <mach/cpu.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+
 #include "ac97c.h"
 #include "ac97c.h"
 
 
 enum {
 enum {
@@ -63,6 +68,7 @@ struct atmel_ac97c {
 	u64				cur_format;
 	u64				cur_format;
 	unsigned int			cur_rate;
 	unsigned int			cur_rate;
 	unsigned long			flags;
 	unsigned long			flags;
+	int				playback_period, capture_period;
 	/* Serialize access to opened variable */
 	/* Serialize access to opened variable */
 	spinlock_t			lock;
 	spinlock_t			lock;
 	void __iomem			*regs;
 	void __iomem			*regs;
@@ -242,10 +248,12 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
 	if (retval < 0)
 	if (retval < 0)
 		return retval;
 		return retval;
 	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
 	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
-	if (retval == 1)
-		if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
-			dw_dma_cyclic_free(chip->dma.tx_chan);
-
+	if (cpu_is_at32ap7000()) {
+		/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
+		if (retval == 1)
+			if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
+				dw_dma_cyclic_free(chip->dma.tx_chan);
+	}
 	/* Set restrictions to params. */
 	/* Set restrictions to params. */
 	mutex_lock(&opened_mutex);
 	mutex_lock(&opened_mutex);
 	chip->cur_rate = params_rate(hw_params);
 	chip->cur_rate = params_rate(hw_params);
@@ -266,9 +274,14 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
 	if (retval < 0)
 	if (retval < 0)
 		return retval;
 		return retval;
 	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
 	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
-	if (retval == 1)
-		if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
-			dw_dma_cyclic_free(chip->dma.rx_chan);
+	if (cpu_is_at32ap7000()) {
+		if (retval < 0)
+			return retval;
+		/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
+		if (retval == 1)
+			if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
+				dw_dma_cyclic_free(chip->dma.rx_chan);
+	}
 
 
 	/* Set restrictions to params. */
 	/* Set restrictions to params. */
 	mutex_lock(&opened_mutex);
 	mutex_lock(&opened_mutex);
@@ -282,16 +295,20 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
 static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream)
 static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream)
 {
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
-	if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
-		dw_dma_cyclic_free(chip->dma.tx_chan);
+	if (cpu_is_at32ap7000()) {
+		if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
+			dw_dma_cyclic_free(chip->dma.tx_chan);
+	}
 	return snd_pcm_lib_free_pages(substream);
 	return snd_pcm_lib_free_pages(substream);
 }
 }
 
 
 static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream)
 static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream)
 {
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
-	if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
-		dw_dma_cyclic_free(chip->dma.rx_chan);
+	if (cpu_is_at32ap7000()) {
+		if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
+			dw_dma_cyclic_free(chip->dma.rx_chan);
+	}
 	return snd_pcm_lib_free_pages(substream);
 	return snd_pcm_lib_free_pages(substream);
 }
 }
 
 
@@ -299,9 +316,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
 {
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	int block_size = frames_to_bytes(runtime, runtime->period_size);
 	unsigned long word = ac97c_readl(chip, OCA);
 	unsigned long word = ac97c_readl(chip, OCA);
 	int retval;
 	int retval;
 
 
+	chip->playback_period = 0;
 	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
 	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
 
 
 	/* assign channels to AC97C channel A */
 	/* assign channels to AC97C channel A */
@@ -320,11 +339,16 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
 	ac97c_writel(chip, OCA, word);
 	ac97c_writel(chip, OCA, word);
 
 
 	/* configure sample format and size */
 	/* configure sample format and size */
-	word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+	word = ac97c_readl(chip, CAMR);
+	if (chip->opened <= 1)
+		word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+	else
+		word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
 
 
 	switch (runtime->format) {
 	switch (runtime->format) {
 	case SNDRV_PCM_FORMAT_S16_LE:
 	case SNDRV_PCM_FORMAT_S16_LE:
-		word |= AC97C_CMR_CEM_LITTLE;
+		if (cpu_is_at32ap7000())
+			word |= AC97C_CMR_CEM_LITTLE;
 		break;
 		break;
 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
 		word &= ~(AC97C_CMR_CEM_LITTLE);
 		word &= ~(AC97C_CMR_CEM_LITTLE);
@@ -363,9 +387,18 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
 		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
 		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
 				runtime->rate);
 				runtime->rate);
 
 
-	if (!test_bit(DMA_TX_READY, &chip->flags))
-		retval = atmel_ac97c_prepare_dma(chip, substream,
-				DMA_TO_DEVICE);
+	if (cpu_is_at32ap7000()) {
+		if (!test_bit(DMA_TX_READY, &chip->flags))
+			retval = atmel_ac97c_prepare_dma(chip, substream,
+					DMA_TO_DEVICE);
+	} else {
+		/* Initialize and start the PDC */
+		writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
+		writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
+		writel(runtime->dma_addr + block_size,
+				chip->regs + ATMEL_PDC_TNPR);
+		writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
+	}
 
 
 	return retval;
 	return retval;
 }
 }
@@ -374,9 +407,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
 {
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	int block_size = frames_to_bytes(runtime, runtime->period_size);
 	unsigned long word = ac97c_readl(chip, ICA);
 	unsigned long word = ac97c_readl(chip, ICA);
 	int retval;
 	int retval;
 
 
+	chip->capture_period = 0;
 	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
 	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
 
 
 	/* assign channels to AC97C channel A */
 	/* assign channels to AC97C channel A */
@@ -395,11 +430,16 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
 	ac97c_writel(chip, ICA, word);
 	ac97c_writel(chip, ICA, word);
 
 
 	/* configure sample format and size */
 	/* configure sample format and size */
-	word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+	word = ac97c_readl(chip, CAMR);
+	if (chip->opened <= 1)
+		word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+	else
+		word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
 
 
 	switch (runtime->format) {
 	switch (runtime->format) {
 	case SNDRV_PCM_FORMAT_S16_LE:
 	case SNDRV_PCM_FORMAT_S16_LE:
-		word |= AC97C_CMR_CEM_LITTLE;
+		if (cpu_is_at32ap7000())
+			word |= AC97C_CMR_CEM_LITTLE;
 		break;
 		break;
 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
 		word &= ~(AC97C_CMR_CEM_LITTLE);
 		word &= ~(AC97C_CMR_CEM_LITTLE);
@@ -438,9 +478,18 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
 		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
 		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
 				runtime->rate);
 				runtime->rate);
 
 
-	if (!test_bit(DMA_RX_READY, &chip->flags))
-		retval = atmel_ac97c_prepare_dma(chip, substream,
-				DMA_FROM_DEVICE);
+	if (cpu_is_at32ap7000()) {
+		if (!test_bit(DMA_RX_READY, &chip->flags))
+			retval = atmel_ac97c_prepare_dma(chip, substream,
+					DMA_FROM_DEVICE);
+	} else {
+		/* Initialize and start the PDC */
+		writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
+		writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
+		writel(runtime->dma_addr + block_size,
+				chip->regs + ATMEL_PDC_RNPR);
+		writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
+	}
 
 
 	return retval;
 	return retval;
 }
 }
@@ -449,7 +498,7 @@ static int
 atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
-	unsigned long camr;
+	unsigned long camr, ptcr = 0;
 	int retval = 0;
 	int retval = 0;
 
 
 	camr = ac97c_readl(chip, CAMR);
 	camr = ac97c_readl(chip, CAMR);
@@ -458,15 +507,22 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
 	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
 	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_START:
-		retval = dw_dma_cyclic_start(chip->dma.tx_chan);
-		if (retval)
-			goto out;
-		camr |= AC97C_CMR_CENA;
+		if (cpu_is_at32ap7000()) {
+			retval = dw_dma_cyclic_start(chip->dma.tx_chan);
+			if (retval)
+				goto out;
+		} else {
+			ptcr = ATMEL_PDC_TXTEN;
+		}
+		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX;
 		break;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
 	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
 	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_STOP:
-		dw_dma_cyclic_stop(chip->dma.tx_chan);
+		if (cpu_is_at32ap7000())
+			dw_dma_cyclic_stop(chip->dma.tx_chan);
+		else
+			ptcr |= ATMEL_PDC_TXTDIS;
 		if (chip->opened <= 1)
 		if (chip->opened <= 1)
 			camr &= ~AC97C_CMR_CENA;
 			camr &= ~AC97C_CMR_CENA;
 		break;
 		break;
@@ -476,6 +532,8 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 	}
 	}
 
 
 	ac97c_writel(chip, CAMR, camr);
 	ac97c_writel(chip, CAMR, camr);
+	if (!cpu_is_at32ap7000())
+		writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
 out:
 out:
 	return retval;
 	return retval;
 }
 }
@@ -484,24 +542,32 @@ static int
 atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
-	unsigned long camr;
+	unsigned long camr, ptcr = 0;
 	int retval = 0;
 	int retval = 0;
 
 
 	camr = ac97c_readl(chip, CAMR);
 	camr = ac97c_readl(chip, CAMR);
+	ptcr = readl(chip->regs + ATMEL_PDC_PTSR);
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
 	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
 	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_START:
-		retval = dw_dma_cyclic_start(chip->dma.rx_chan);
-		if (retval)
-			goto out;
-		camr |= AC97C_CMR_CENA;
+		if (cpu_is_at32ap7000()) {
+			retval = dw_dma_cyclic_start(chip->dma.rx_chan);
+			if (retval)
+				goto out;
+		} else {
+			ptcr = ATMEL_PDC_RXTEN;
+		}
+		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDRX;
 		break;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
 	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
 	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_STOP:
-		dw_dma_cyclic_stop(chip->dma.rx_chan);
+		if (cpu_is_at32ap7000())
+			dw_dma_cyclic_stop(chip->dma.rx_chan);
+		else
+			ptcr |= (ATMEL_PDC_RXTDIS);
 		if (chip->opened <= 1)
 		if (chip->opened <= 1)
 			camr &= ~AC97C_CMR_CENA;
 			camr &= ~AC97C_CMR_CENA;
 		break;
 		break;
@@ -511,6 +577,8 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 	}
 	}
 
 
 	ac97c_writel(chip, CAMR, camr);
 	ac97c_writel(chip, CAMR, camr);
+	if (!cpu_is_at32ap7000())
+		writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
 out:
 out:
 	return retval;
 	return retval;
 }
 }
@@ -523,7 +591,10 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream)
 	snd_pcm_uframes_t	frames;
 	snd_pcm_uframes_t	frames;
 	unsigned long		bytes;
 	unsigned long		bytes;
 
 
-	bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
+	if (cpu_is_at32ap7000())
+		bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
+	else
+		bytes = readl(chip->regs + ATMEL_PDC_TPR);
 	bytes -= runtime->dma_addr;
 	bytes -= runtime->dma_addr;
 
 
 	frames = bytes_to_frames(runtime, bytes);
 	frames = bytes_to_frames(runtime, bytes);
@@ -540,7 +611,10 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
 	snd_pcm_uframes_t	frames;
 	snd_pcm_uframes_t	frames;
 	unsigned long		bytes;
 	unsigned long		bytes;
 
 
-	bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
+	if (cpu_is_at32ap7000())
+		bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
+	else
+		bytes = readl(chip->regs + ATMEL_PDC_RPR);
 	bytes -= runtime->dma_addr;
 	bytes -= runtime->dma_addr;
 
 
 	frames = bytes_to_frames(runtime, bytes);
 	frames = bytes_to_frames(runtime, bytes);
@@ -578,8 +652,11 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
 	u32			sr     = ac97c_readl(chip, SR);
 	u32			sr     = ac97c_readl(chip, SR);
 	u32			casr   = ac97c_readl(chip, CASR);
 	u32			casr   = ac97c_readl(chip, CASR);
 	u32			cosr   = ac97c_readl(chip, COSR);
 	u32			cosr   = ac97c_readl(chip, COSR);
+	u32			camr   = ac97c_readl(chip, CAMR);
 
 
 	if (sr & AC97C_SR_CAEVT) {
 	if (sr & AC97C_SR_CAEVT) {
+		struct snd_pcm_runtime *runtime;
+		int offset, next_period, block_size;
 		dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
 		dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
 				casr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
 				casr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
 				casr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
 				casr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
@@ -587,6 +664,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
 				casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
 				casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
 				casr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
 				casr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
 				!casr                    ? " NONE"    : "");
 				!casr                    ? " NONE"    : "");
+		if (!cpu_is_at32ap7000()) {
+			if ((casr & camr) & AC97C_CSR_ENDTX) {
+				runtime = chip->playback_substream->runtime;
+				block_size = frames_to_bytes(runtime,
+						runtime->period_size);
+				chip->playback_period++;
+
+				if (chip->playback_period == runtime->periods)
+					chip->playback_period = 0;
+				next_period = chip->playback_period + 1;
+				if (next_period == runtime->periods)
+					next_period = 0;
+
+				offset = block_size * next_period;
+
+				writel(runtime->dma_addr + offset,
+						chip->regs + ATMEL_PDC_TNPR);
+				writel(block_size / 2,
+						chip->regs + ATMEL_PDC_TNCR);
+
+				snd_pcm_period_elapsed(
+						chip->playback_substream);
+			}
+			if ((casr & camr) & AC97C_CSR_ENDRX) {
+				runtime = chip->capture_substream->runtime;
+				block_size = frames_to_bytes(runtime,
+						runtime->period_size);
+				chip->capture_period++;
+
+				if (chip->capture_period == runtime->periods)
+					chip->capture_period = 0;
+				next_period = chip->capture_period + 1;
+				if (next_period == runtime->periods)
+					next_period = 0;
+
+				offset = block_size * next_period;
+
+				writel(runtime->dma_addr + offset,
+						chip->regs + ATMEL_PDC_RNPR);
+				writel(block_size / 2,
+						chip->regs + ATMEL_PDC_RNCR);
+				snd_pcm_period_elapsed(chip->capture_substream);
+			}
+		}
 		retval = IRQ_HANDLED;
 		retval = IRQ_HANDLED;
 	}
 	}
 
 
@@ -608,15 +729,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
 	return retval;
 	return retval;
 }
 }
 
 
+static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = {
+	/* Playback */
+	{
+		.exclusive = 1,
+		.r = { {
+			.slots = ((1 << AC97_SLOT_PCM_LEFT)
+				  | (1 << AC97_SLOT_PCM_RIGHT)),
+		} },
+	},
+	/* PCM in */
+	{
+		.stream = 1,
+		.exclusive = 1,
+		.r = { {
+			.slots = ((1 << AC97_SLOT_PCM_LEFT)
+					| (1 << AC97_SLOT_PCM_RIGHT)),
+		} }
+	},
+	/* Mic in */
+	{
+		.stream = 1,
+		.exclusive = 1,
+		.r = { {
+			.slots = (1<<AC97_SLOT_MIC),
+		} }
+	},
+};
+
 static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
 static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
 {
 {
 	struct snd_pcm		*pcm;
 	struct snd_pcm		*pcm;
 	struct snd_pcm_hardware	hw = atmel_ac97c_hw;
 	struct snd_pcm_hardware	hw = atmel_ac97c_hw;
-	int			capture, playback, retval;
+	int			capture, playback, retval, err;
 
 
 	capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
 	capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
 	playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
 	playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
 
 
+	if (!cpu_is_at32ap7000()) {
+		err = snd_ac97_pcm_assign(chip->ac97_bus,
+				ARRAY_SIZE(at91_ac97_pcm_defs),
+				at91_ac97_pcm_defs);
+		if (err)
+			return err;
+	}
 	retval = snd_pcm_new(chip->card, chip->card->shortname,
 	retval = snd_pcm_new(chip->card, chip->card->shortname,
 			chip->pdev->id, playback, capture, &pcm);
 			chip->pdev->id, playback, capture, &pcm);
 	if (retval)
 	if (retval)
@@ -775,7 +931,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
 		return -ENXIO;
 		return -ENXIO;
 	}
 	}
 
 
-	pclk = clk_get(&pdev->dev, "pclk");
+	if (cpu_is_at32ap7000()) {
+		pclk = clk_get(&pdev->dev, "pclk");
+	} else {
+		pclk = clk_get(&pdev->dev, "ac97_clk");
+	}
+
 	if (IS_ERR(pclk)) {
 	if (IS_ERR(pclk)) {
 		dev_dbg(&pdev->dev, "no peripheral clock\n");
 		dev_dbg(&pdev->dev, "no peripheral clock\n");
 		return PTR_ERR(pclk);
 		return PTR_ERR(pclk);
@@ -844,43 +1005,52 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
 		goto err_ac97_bus;
 		goto err_ac97_bus;
 	}
 	}
 
 
-	if (pdata->rx_dws.dma_dev) {
-		struct dw_dma_slave *dws = &pdata->rx_dws;
-		dma_cap_mask_t mask;
+	if (cpu_is_at32ap7000()) {
+		if (pdata->rx_dws.dma_dev) {
+			struct dw_dma_slave *dws = &pdata->rx_dws;
+			dma_cap_mask_t mask;
 
 
-		dws->rx_reg = regs->start + AC97C_CARHR + 2;
+			dws->rx_reg = regs->start + AC97C_CARHR + 2;
 
 
-		dma_cap_zero(mask);
-		dma_cap_set(DMA_SLAVE, mask);
+			dma_cap_zero(mask);
+			dma_cap_set(DMA_SLAVE, mask);
 
 
-		chip->dma.rx_chan = dma_request_channel(mask, filter, dws);
+			chip->dma.rx_chan = dma_request_channel(mask, filter,
+								dws);
 
 
-		dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
+			dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
 				dev_name(&chip->dma.rx_chan->dev->device));
 				dev_name(&chip->dma.rx_chan->dev->device));
-		set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
-	}
+			set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+		}
 
 
-	if (pdata->tx_dws.dma_dev) {
-		struct dw_dma_slave *dws = &pdata->tx_dws;
-		dma_cap_mask_t mask;
+		if (pdata->tx_dws.dma_dev) {
+			struct dw_dma_slave *dws = &pdata->tx_dws;
+			dma_cap_mask_t mask;
 
 
-		dws->tx_reg = regs->start + AC97C_CATHR + 2;
+			dws->tx_reg = regs->start + AC97C_CATHR + 2;
 
 
-		dma_cap_zero(mask);
-		dma_cap_set(DMA_SLAVE, mask);
+			dma_cap_zero(mask);
+			dma_cap_set(DMA_SLAVE, mask);
 
 
-		chip->dma.tx_chan = dma_request_channel(mask, filter, dws);
+			chip->dma.tx_chan = dma_request_channel(mask, filter,
+								dws);
 
 
-		dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
+			dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
 				dev_name(&chip->dma.tx_chan->dev->device));
 				dev_name(&chip->dma.tx_chan->dev->device));
-		set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
-	}
+			set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+		}
 
 
-	if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
-			!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
-		dev_dbg(&pdev->dev, "DMA not available\n");
-		retval = -ENODEV;
-		goto err_dma;
+		if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
+				!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
+			dev_dbg(&pdev->dev, "DMA not available\n");
+			retval = -ENODEV;
+			goto err_dma;
+		}
+	} else {
+		/* Just pretend that we have DMA channel(for at91 i is actually
+		 * the PDC) */
+		set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+		set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
 	}
 	}
 
 
 	retval = atmel_ac97c_pcm_new(chip);
 	retval = atmel_ac97c_pcm_new(chip);
@@ -897,20 +1067,22 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
 
 
 	platform_set_drvdata(pdev, card);
 	platform_set_drvdata(pdev, card);
 
 
-	dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n",
-			chip->regs);
+	dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d\n",
+			chip->regs, irq);
 
 
 	return 0;
 	return 0;
 
 
 err_dma:
 err_dma:
-	if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
-		dma_release_channel(chip->dma.rx_chan);
-	if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
-		dma_release_channel(chip->dma.tx_chan);
-	clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
-	clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
-	chip->dma.rx_chan = NULL;
-	chip->dma.tx_chan = NULL;
+	if (cpu_is_at32ap7000()) {
+		if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
+			dma_release_channel(chip->dma.rx_chan);
+		if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
+			dma_release_channel(chip->dma.tx_chan);
+		clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+		clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+		chip->dma.rx_chan = NULL;
+		chip->dma.tx_chan = NULL;
+	}
 err_ac97_bus:
 err_ac97_bus:
 	snd_card_set_dev(card, NULL);
 	snd_card_set_dev(card, NULL);
 
 
@@ -934,10 +1106,12 @@ static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg)
 	struct snd_card *card = platform_get_drvdata(pdev);
 	struct snd_card *card = platform_get_drvdata(pdev);
 	struct atmel_ac97c *chip = card->private_data;
 	struct atmel_ac97c *chip = card->private_data;
 
 
-	if (test_bit(DMA_RX_READY, &chip->flags))
-		dw_dma_cyclic_stop(chip->dma.rx_chan);
-	if (test_bit(DMA_TX_READY, &chip->flags))
-		dw_dma_cyclic_stop(chip->dma.tx_chan);
+	if (cpu_is_at32ap7000()) {
+		if (test_bit(DMA_RX_READY, &chip->flags))
+			dw_dma_cyclic_stop(chip->dma.rx_chan);
+		if (test_bit(DMA_TX_READY, &chip->flags))
+			dw_dma_cyclic_stop(chip->dma.tx_chan);
+	}
 	clk_disable(chip->pclk);
 	clk_disable(chip->pclk);
 
 
 	return 0;
 	return 0;
@@ -949,11 +1123,12 @@ static int atmel_ac97c_resume(struct platform_device *pdev)
 	struct atmel_ac97c *chip = card->private_data;
 	struct atmel_ac97c *chip = card->private_data;
 
 
 	clk_enable(chip->pclk);
 	clk_enable(chip->pclk);
-	if (test_bit(DMA_RX_READY, &chip->flags))
-		dw_dma_cyclic_start(chip->dma.rx_chan);
-	if (test_bit(DMA_TX_READY, &chip->flags))
-		dw_dma_cyclic_start(chip->dma.tx_chan);
-
+	if (cpu_is_at32ap7000()) {
+		if (test_bit(DMA_RX_READY, &chip->flags))
+			dw_dma_cyclic_start(chip->dma.rx_chan);
+		if (test_bit(DMA_TX_READY, &chip->flags))
+			dw_dma_cyclic_start(chip->dma.tx_chan);
+	}
 	return 0;
 	return 0;
 }
 }
 #else
 #else
@@ -978,14 +1153,16 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev)
 	iounmap(chip->regs);
 	iounmap(chip->regs);
 	free_irq(chip->irq, chip);
 	free_irq(chip->irq, chip);
 
 
-	if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
-		dma_release_channel(chip->dma.rx_chan);
-	if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
-		dma_release_channel(chip->dma.tx_chan);
-	clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
-	clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
-	chip->dma.rx_chan = NULL;
-	chip->dma.tx_chan = NULL;
+	if (cpu_is_at32ap7000()) {
+		if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
+			dma_release_channel(chip->dma.rx_chan);
+		if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
+			dma_release_channel(chip->dma.tx_chan);
+		clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+		clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+		chip->dma.rx_chan = NULL;
+		chip->dma.tx_chan = NULL;
+	}
 
 
 	snd_card_set_dev(card, NULL);
 	snd_card_set_dev(card, NULL);
 	snd_card_free(card);
 	snd_card_free(card);

+ 5 - 0
sound/core/control.c

@@ -50,6 +50,10 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
 	struct snd_ctl_file *ctl;
 	struct snd_ctl_file *ctl;
 	int err;
 	int err;
 
 
+	err = nonseekable_open(inode, file);
+	if (err < 0)
+		return err;
+
 	card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
 	card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
 	if (!card) {
 	if (!card) {
 		err = -ENODEV;
 		err = -ENODEV;
@@ -1388,6 +1392,7 @@ static const struct file_operations snd_ctl_f_ops =
 	.read =		snd_ctl_read,
 	.read =		snd_ctl_read,
 	.open =		snd_ctl_open,
 	.open =		snd_ctl_open,
 	.release =	snd_ctl_release,
 	.release =	snd_ctl_release,
+	.llseek =	no_llseek,
 	.poll =		snd_ctl_poll,
 	.poll =		snd_ctl_poll,
 	.unlocked_ioctl =	snd_ctl_ioctl,
 	.unlocked_ioctl =	snd_ctl_ioctl,
 	.compat_ioctl =	snd_ctl_ioctl_compat,
 	.compat_ioctl =	snd_ctl_ioctl_compat,

+ 43 - 31
sound/core/info.c

@@ -164,40 +164,44 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
 {
 {
 	struct snd_info_private_data *data;
 	struct snd_info_private_data *data;
 	struct snd_info_entry *entry;
 	struct snd_info_entry *entry;
-	loff_t ret;
+	loff_t ret = -EINVAL, size;
 
 
 	data = file->private_data;
 	data = file->private_data;
 	entry = data->entry;
 	entry = data->entry;
-	lock_kernel();
-	switch (entry->content) {
-	case SNDRV_INFO_CONTENT_TEXT:
-		switch (orig) {
-		case SEEK_SET:
-			file->f_pos = offset;
-			ret = file->f_pos;
-			goto out;
-		case SEEK_CUR:
-			file->f_pos += offset;
-			ret = file->f_pos;
-			goto out;
-		case SEEK_END:
-		default:
-			ret = -EINVAL;
-			goto out;
-		}
+	mutex_lock(&entry->access);
+	if (entry->content == SNDRV_INFO_CONTENT_DATA &&
+	    entry->c.ops->llseek) {
+		offset = entry->c.ops->llseek(entry,
+					      data->file_private_data,
+					      file, offset, orig);
+		goto out;
+	}
+	if (entry->content == SNDRV_INFO_CONTENT_DATA)
+		size = entry->size;
+	else
+		size = 0;
+	switch (orig) {
+	case SEEK_SET:
 		break;
 		break;
-	case SNDRV_INFO_CONTENT_DATA:
-		if (entry->c.ops->llseek) {
-			ret = entry->c.ops->llseek(entry,
-						    data->file_private_data,
-						    file, offset, orig);
+	case SEEK_CUR:
+		offset += file->f_pos;
+		break;
+	case SEEK_END:
+		if (!size)
 			goto out;
 			goto out;
-		}
+		offset += size;
 		break;
 		break;
-	}
-	ret = -ENXIO;
-out:
-	unlock_kernel();
+	default:
+		goto out;
+	}
+	if (offset < 0)
+		goto out;
+	if (size && offset > size)
+		offset = size;
+	file->f_pos = offset;
+	ret = offset;
+ out:
+	mutex_unlock(&entry->access);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -232,10 +236,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
 			return -EFAULT;
 			return -EFAULT;
 		break;
 		break;
 	case SNDRV_INFO_CONTENT_DATA:
 	case SNDRV_INFO_CONTENT_DATA:
-		if (entry->c.ops->read)
+		if (pos >= entry->size)
+			return 0;
+		if (entry->c.ops->read) {
+			size = entry->size - pos;
+			size = min(count, size);
 			size = entry->c.ops->read(entry,
 			size = entry->c.ops->read(entry,
 						  data->file_private_data,
 						  data->file_private_data,
-						  file, buffer, count, pos);
+						  file, buffer, size, pos);
+		}
 		break;
 		break;
 	}
 	}
 	if ((ssize_t) size > 0)
 	if ((ssize_t) size > 0)
@@ -282,10 +291,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
 		size = count;
 		size = count;
 		break;
 		break;
 	case SNDRV_INFO_CONTENT_DATA:
 	case SNDRV_INFO_CONTENT_DATA:
-		if (entry->c.ops->write)
+		if (entry->c.ops->write && count > 0) {
+			size_t maxsize = entry->size - pos;
+			count = min(count, maxsize);
 			size = entry->c.ops->write(entry,
 			size = entry->c.ops->write(entry,
 						   data->file_private_data,
 						   data->file_private_data,
 						   file, buffer, count, pos);
 						   file, buffer, count, pos);
+		}
 		break;
 		break;
 	}
 	}
 	if ((ssize_t) size > 0)
 	if ((ssize_t) size > 0)

+ 65 - 6
sound/core/jack.c

@@ -24,7 +24,7 @@
 #include <sound/jack.h>
 #include <sound/jack.h>
 #include <sound/core.h>
 #include <sound/core.h>
 
 
-static int jack_types[] = {
+static int jack_switch_types[] = {
 	SW_HEADPHONE_INSERT,
 	SW_HEADPHONE_INSERT,
 	SW_MICROPHONE_INSERT,
 	SW_MICROPHONE_INSERT,
 	SW_LINEOUT_INSERT,
 	SW_LINEOUT_INSERT,
@@ -56,7 +56,7 @@ static int snd_jack_dev_register(struct snd_device *device)
 {
 {
 	struct snd_jack *jack = device->device_data;
 	struct snd_jack *jack = device->device_data;
 	struct snd_card *card = device->card;
 	struct snd_card *card = device->card;
-	int err;
+	int err, i;
 
 
 	snprintf(jack->name, sizeof(jack->name), "%s %s",
 	snprintf(jack->name, sizeof(jack->name), "%s %s",
 		 card->shortname, jack->id);
 		 card->shortname, jack->id);
@@ -66,6 +66,19 @@ static int snd_jack_dev_register(struct snd_device *device)
 	if (!jack->input_dev->dev.parent)
 	if (!jack->input_dev->dev.parent)
 		jack->input_dev->dev.parent = snd_card_get_device_link(card);
 		jack->input_dev->dev.parent = snd_card_get_device_link(card);
 
 
+	/* Add capabilities for any keys that are enabled */
+	for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
+		int testbit = SND_JACK_BTN_0 >> i;
+
+		if (!(jack->type & testbit))
+			continue;
+
+		if (!jack->key[i])
+			jack->key[i] = BTN_0 + i;
+
+		input_set_capability(jack->input_dev, EV_KEY, jack->key[i]);
+	}
+
 	err = input_register_device(jack->input_dev);
 	err = input_register_device(jack->input_dev);
 	if (err == 0)
 	if (err == 0)
 		jack->registered = 1;
 		jack->registered = 1;
@@ -113,10 +126,10 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
 
 
 	jack->type = type;
 	jack->type = type;
 
 
-	for (i = 0; i < ARRAY_SIZE(jack_types); i++)
+	for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++)
 		if (type & (1 << i))
 		if (type & (1 << i))
 			input_set_capability(jack->input_dev, EV_SW,
 			input_set_capability(jack->input_dev, EV_SW,
-					     jack_types[i]);
+					     jack_switch_types[i]);
 
 
 	err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
 	err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
 	if (err < 0)
 	if (err < 0)
@@ -151,6 +164,43 @@ void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
 }
 }
 EXPORT_SYMBOL(snd_jack_set_parent);
 EXPORT_SYMBOL(snd_jack_set_parent);
 
 
+/**
+ * snd_jack_set_key - Set a key mapping on a jack
+ *
+ * @jack:    The jack to configure
+ * @type:    Jack report type for this key
+ * @keytype: Input layer key type to be reported
+ *
+ * Map a SND_JACK_BTN_ button type to an input layer key, allowing
+ * reporting of keys on accessories via the jack abstraction.  If no
+ * mapping is provided but keys are enabled in the jack type then
+ * BTN_n numeric buttons will be reported.
+ *
+ * Note that this is intended to be use by simple devices with small
+ * numbers of keys that can be reported.  It is also possible to
+ * access the input device directly - devices with complex input
+ * capabilities on accessories should consider doing this rather than
+ * using this abstraction.
+ *
+ * This function may only be called prior to registration of the jack.
+ */
+int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type,
+		     int keytype)
+{
+	int key = fls(SND_JACK_BTN_0) - fls(type);
+
+	WARN_ON(jack->registered);
+
+	if (!keytype || key >= ARRAY_SIZE(jack->key))
+		return -EINVAL;
+
+	jack->type |= type;
+	jack->key[key] = keytype;
+
+	return 0;
+}
+EXPORT_SYMBOL(snd_jack_set_key);
+
 /**
 /**
  * snd_jack_report - Report the current status of a jack
  * snd_jack_report - Report the current status of a jack
  *
  *
@@ -164,10 +214,19 @@ void snd_jack_report(struct snd_jack *jack, int status)
 	if (!jack)
 	if (!jack)
 		return;
 		return;
 
 
-	for (i = 0; i < ARRAY_SIZE(jack_types); i++) {
+	for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
+		int testbit = SND_JACK_BTN_0 >> i;
+
+		if (jack->type & testbit)
+			input_report_key(jack->input_dev, jack->key[i],
+					 status & testbit);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) {
 		int testbit = 1 << i;
 		int testbit = 1 << i;
 		if (jack->type & testbit)
 		if (jack->type & testbit)
-			input_report_switch(jack->input_dev, jack_types[i],
+			input_report_switch(jack->input_dev,
+					    jack_switch_types[i],
 					    status & testbit);
 					    status & testbit);
 	}
 	}
 
 

+ 5 - 0
sound/core/oss/mixer_oss.c

@@ -43,6 +43,10 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
 	struct snd_mixer_oss_file *fmixer;
 	struct snd_mixer_oss_file *fmixer;
 	int err;
 	int err;
 
 
+	err = nonseekable_open(inode, file);
+	if (err < 0)
+		return err;
+
 	card = snd_lookup_oss_minor_data(iminor(inode),
 	card = snd_lookup_oss_minor_data(iminor(inode),
 					 SNDRV_OSS_DEVICE_TYPE_MIXER);
 					 SNDRV_OSS_DEVICE_TYPE_MIXER);
 	if (card == NULL)
 	if (card == NULL)
@@ -397,6 +401,7 @@ static const struct file_operations snd_mixer_oss_f_ops =
 	.owner =	THIS_MODULE,
 	.owner =	THIS_MODULE,
 	.open =		snd_mixer_oss_open,
 	.open =		snd_mixer_oss_open,
 	.release =	snd_mixer_oss_release,
 	.release =	snd_mixer_oss_release,
+	.llseek =	no_llseek,
 	.unlocked_ioctl =	snd_mixer_oss_ioctl,
 	.unlocked_ioctl =	snd_mixer_oss_ioctl,
 	.compat_ioctl =	snd_mixer_oss_ioctl_compat,
 	.compat_ioctl =	snd_mixer_oss_ioctl_compat,
 };
 };

+ 5 - 0
sound/core/oss/pcm_oss.c

@@ -2379,6 +2379,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
 	int nonblock;
 	int nonblock;
 	wait_queue_t wait;
 	wait_queue_t wait;
 
 
+	err = nonseekable_open(inode, file);
+	if (err < 0)
+		return err;
+
 	pcm = snd_lookup_oss_minor_data(iminor(inode),
 	pcm = snd_lookup_oss_minor_data(iminor(inode),
 					SNDRV_OSS_DEVICE_TYPE_PCM);
 					SNDRV_OSS_DEVICE_TYPE_PCM);
 	if (pcm == NULL) {
 	if (pcm == NULL) {
@@ -2977,6 +2981,7 @@ static const struct file_operations snd_pcm_oss_f_reg =
 	.write =	snd_pcm_oss_write,
 	.write =	snd_pcm_oss_write,
 	.open =		snd_pcm_oss_open,
 	.open =		snd_pcm_oss_open,
 	.release =	snd_pcm_oss_release,
 	.release =	snd_pcm_oss_release,
+	.llseek =	no_llseek,
 	.poll =		snd_pcm_oss_poll,
 	.poll =		snd_pcm_oss_poll,
 	.unlocked_ioctl =	snd_pcm_oss_ioctl,
 	.unlocked_ioctl =	snd_pcm_oss_ioctl,
 	.compat_ioctl =	snd_pcm_oss_ioctl_compat,
 	.compat_ioctl =	snd_pcm_oss_ioctl_compat,

+ 32 - 17
sound/core/pcm_native.c

@@ -2112,7 +2112,9 @@ static int snd_pcm_open_file(struct file *file,
 static int snd_pcm_playback_open(struct inode *inode, struct file *file)
 static int snd_pcm_playback_open(struct inode *inode, struct file *file)
 {
 {
 	struct snd_pcm *pcm;
 	struct snd_pcm *pcm;
-
+	int err = nonseekable_open(inode, file);
+	if (err < 0)
+		return err;
 	pcm = snd_lookup_minor_data(iminor(inode),
 	pcm = snd_lookup_minor_data(iminor(inode),
 				    SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
 				    SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
 	return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
 	return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
@@ -2121,7 +2123,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
 static int snd_pcm_capture_open(struct inode *inode, struct file *file)
 static int snd_pcm_capture_open(struct inode *inode, struct file *file)
 {
 {
 	struct snd_pcm *pcm;
 	struct snd_pcm *pcm;
-
+	int err = nonseekable_open(inode, file);
+	if (err < 0)
+		return err;
 	pcm = snd_lookup_minor_data(iminor(inode),
 	pcm = snd_lookup_minor_data(iminor(inode),
 				    SNDRV_DEVICE_TYPE_PCM_CAPTURE);
 				    SNDRV_DEVICE_TYPE_PCM_CAPTURE);
 	return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
 	return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
@@ -3312,18 +3316,13 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
 	struct snd_pcm_file * pcm_file;
 	struct snd_pcm_file * pcm_file;
 	struct snd_pcm_substream *substream;
 	struct snd_pcm_substream *substream;
 	struct snd_pcm_runtime *runtime;
 	struct snd_pcm_runtime *runtime;
-	int err = -ENXIO;
 
 
-	lock_kernel();
 	pcm_file = file->private_data;
 	pcm_file = file->private_data;
 	substream = pcm_file->substream;
 	substream = pcm_file->substream;
 	if (PCM_RUNTIME_CHECK(substream))
 	if (PCM_RUNTIME_CHECK(substream))
-		goto out;
+		return -ENXIO;
 	runtime = substream->runtime;
 	runtime = substream->runtime;
-	err = fasync_helper(fd, file, on, &runtime->fasync);
-out:
-	unlock_kernel();
-	return err;
+	return fasync_helper(fd, file, on, &runtime->fasync);
 }
 }
 
 
 /*
 /*
@@ -3443,14 +3442,28 @@ out:
 #endif /* CONFIG_SND_SUPPORT_OLD_API */
 #endif /* CONFIG_SND_SUPPORT_OLD_API */
 
 
 #ifndef CONFIG_MMU
 #ifndef CONFIG_MMU
-unsigned long dummy_get_unmapped_area(struct file *file, unsigned long addr,
-				      unsigned long len, unsigned long pgoff,
-				      unsigned long flags)
-{
-	return 0;
+static unsigned long snd_pcm_get_unmapped_area(struct file *file,
+					       unsigned long addr,
+					       unsigned long len,
+					       unsigned long pgoff,
+					       unsigned long flags)
+{
+	struct snd_pcm_file *pcm_file = file->private_data;
+	struct snd_pcm_substream *substream = pcm_file->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long offset = pgoff << PAGE_SHIFT;
+
+	switch (offset) {
+	case SNDRV_PCM_MMAP_OFFSET_STATUS:
+		return (unsigned long)runtime->status;
+	case SNDRV_PCM_MMAP_OFFSET_CONTROL:
+		return (unsigned long)runtime->control;
+	default:
+		return (unsigned long)runtime->dma_area + offset;
+	}
 }
 }
 #else
 #else
-# define dummy_get_unmapped_area NULL
+# define snd_pcm_get_unmapped_area NULL
 #endif
 #endif
 
 
 /*
 /*
@@ -3464,12 +3477,13 @@ const struct file_operations snd_pcm_f_ops[2] = {
 		.aio_write =		snd_pcm_aio_write,
 		.aio_write =		snd_pcm_aio_write,
 		.open =			snd_pcm_playback_open,
 		.open =			snd_pcm_playback_open,
 		.release =		snd_pcm_release,
 		.release =		snd_pcm_release,
+		.llseek =		no_llseek,
 		.poll =			snd_pcm_playback_poll,
 		.poll =			snd_pcm_playback_poll,
 		.unlocked_ioctl =	snd_pcm_playback_ioctl,
 		.unlocked_ioctl =	snd_pcm_playback_ioctl,
 		.compat_ioctl = 	snd_pcm_ioctl_compat,
 		.compat_ioctl = 	snd_pcm_ioctl_compat,
 		.mmap =			snd_pcm_mmap,
 		.mmap =			snd_pcm_mmap,
 		.fasync =		snd_pcm_fasync,
 		.fasync =		snd_pcm_fasync,
-		.get_unmapped_area =	dummy_get_unmapped_area,
+		.get_unmapped_area =	snd_pcm_get_unmapped_area,
 	},
 	},
 	{
 	{
 		.owner =		THIS_MODULE,
 		.owner =		THIS_MODULE,
@@ -3477,11 +3491,12 @@ const struct file_operations snd_pcm_f_ops[2] = {
 		.aio_read =		snd_pcm_aio_read,
 		.aio_read =		snd_pcm_aio_read,
 		.open =			snd_pcm_capture_open,
 		.open =			snd_pcm_capture_open,
 		.release =		snd_pcm_release,
 		.release =		snd_pcm_release,
+		.llseek =		no_llseek,
 		.poll =			snd_pcm_capture_poll,
 		.poll =			snd_pcm_capture_poll,
 		.unlocked_ioctl =	snd_pcm_capture_ioctl,
 		.unlocked_ioctl =	snd_pcm_capture_ioctl,
 		.compat_ioctl = 	snd_pcm_ioctl_compat,
 		.compat_ioctl = 	snd_pcm_ioctl_compat,
 		.mmap =			snd_pcm_mmap,
 		.mmap =			snd_pcm_mmap,
 		.fasync =		snd_pcm_fasync,
 		.fasync =		snd_pcm_fasync,
-		.get_unmapped_area =	dummy_get_unmapped_area,
+		.get_unmapped_area =	snd_pcm_get_unmapped_area,
 	}
 	}
 };
 };

+ 5 - 0
sound/core/rawmidi.c

@@ -376,6 +376,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
 	if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) 
 	if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) 
 		return -EINVAL;		/* invalid combination */
 		return -EINVAL;		/* invalid combination */
 
 
+	err = nonseekable_open(inode, file);
+	if (err < 0)
+		return err;
+
 	if (maj == snd_major) {
 	if (maj == snd_major) {
 		rmidi = snd_lookup_minor_data(iminor(inode),
 		rmidi = snd_lookup_minor_data(iminor(inode),
 					      SNDRV_DEVICE_TYPE_RAWMIDI);
 					      SNDRV_DEVICE_TYPE_RAWMIDI);
@@ -1391,6 +1395,7 @@ static const struct file_operations snd_rawmidi_f_ops =
 	.write =	snd_rawmidi_write,
 	.write =	snd_rawmidi_write,
 	.open =		snd_rawmidi_open,
 	.open =		snd_rawmidi_open,
 	.release =	snd_rawmidi_release,
 	.release =	snd_rawmidi_release,
+	.llseek =	no_llseek,
 	.poll =		snd_rawmidi_poll,
 	.poll =		snd_rawmidi_poll,
 	.unlocked_ioctl =	snd_rawmidi_ioctl,
 	.unlocked_ioctl =	snd_rawmidi_ioctl,
 	.compat_ioctl =	snd_rawmidi_ioctl_compat,
 	.compat_ioctl =	snd_rawmidi_ioctl_compat,

+ 6 - 0
sound/core/seq/seq_clientmgr.c

@@ -318,6 +318,11 @@ static int snd_seq_open(struct inode *inode, struct file *file)
 	int c, mode;			/* client id */
 	int c, mode;			/* client id */
 	struct snd_seq_client *client;
 	struct snd_seq_client *client;
 	struct snd_seq_user_client *user;
 	struct snd_seq_user_client *user;
+	int err;
+
+	err = nonseekable_open(inode, file);
+	if (err < 0)
+		return err;
 
 
 	if (mutex_lock_interruptible(&register_mutex))
 	if (mutex_lock_interruptible(&register_mutex))
 		return -ERESTARTSYS;
 		return -ERESTARTSYS;
@@ -2550,6 +2555,7 @@ static const struct file_operations snd_seq_f_ops =
 	.write =	snd_seq_write,
 	.write =	snd_seq_write,
 	.open =		snd_seq_open,
 	.open =		snd_seq_open,
 	.release =	snd_seq_release,
 	.release =	snd_seq_release,
+	.llseek =	no_llseek,
 	.poll =		snd_seq_poll,
 	.poll =		snd_seq_poll,
 	.unlocked_ioctl =	snd_seq_ioctl,
 	.unlocked_ioctl =	snd_seq_ioctl,
 	.compat_ioctl =	snd_seq_ioctl_compat,
 	.compat_ioctl =	snd_seq_ioctl_compat,

+ 38 - 35
sound/core/sound.c

@@ -120,7 +120,29 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
 
 
 EXPORT_SYMBOL(snd_lookup_minor_data);
 EXPORT_SYMBOL(snd_lookup_minor_data);
 
 
-static int __snd_open(struct inode *inode, struct file *file)
+#ifdef CONFIG_MODULES
+static struct snd_minor *autoload_device(unsigned int minor)
+{
+	int dev;
+	mutex_unlock(&sound_mutex); /* release lock temporarily */
+	dev = SNDRV_MINOR_DEVICE(minor);
+	if (dev == SNDRV_MINOR_CONTROL) {
+		/* /dev/aloadC? */
+		int card = SNDRV_MINOR_CARD(minor);
+		if (snd_cards[card] == NULL)
+			snd_request_card(card);
+	} else if (dev == SNDRV_MINOR_GLOBAL) {
+		/* /dev/aloadSEQ */
+		snd_request_other(minor);
+	}
+	mutex_lock(&sound_mutex); /* reacuire lock */
+	return snd_minors[minor];
+}
+#else /* !CONFIG_MODULES */
+#define autoload_device(minor)	NULL
+#endif /* CONFIG_MODULES */
+
+static int snd_open(struct inode *inode, struct file *file)
 {
 {
 	unsigned int minor = iminor(inode);
 	unsigned int minor = iminor(inode);
 	struct snd_minor *mptr = NULL;
 	struct snd_minor *mptr = NULL;
@@ -129,55 +151,36 @@ static int __snd_open(struct inode *inode, struct file *file)
 
 
 	if (minor >= ARRAY_SIZE(snd_minors))
 	if (minor >= ARRAY_SIZE(snd_minors))
 		return -ENODEV;
 		return -ENODEV;
+	mutex_lock(&sound_mutex);
 	mptr = snd_minors[minor];
 	mptr = snd_minors[minor];
 	if (mptr == NULL) {
 	if (mptr == NULL) {
-#ifdef CONFIG_MODULES
-		int dev = SNDRV_MINOR_DEVICE(minor);
-		if (dev == SNDRV_MINOR_CONTROL) {
-			/* /dev/aloadC? */
-			int card = SNDRV_MINOR_CARD(minor);
-			if (snd_cards[card] == NULL)
-				snd_request_card(card);
-		} else if (dev == SNDRV_MINOR_GLOBAL) {
-			/* /dev/aloadSEQ */
-			snd_request_other(minor);
-		}
-#ifndef CONFIG_SND_DYNAMIC_MINORS
-		/* /dev/snd/{controlC?,seq} */
-		mptr = snd_minors[minor];
-		if (mptr == NULL)
-#endif
-#endif
+		mptr = autoload_device(minor);
+		if (!mptr) {
+			mutex_unlock(&sound_mutex);
 			return -ENODEV;
 			return -ENODEV;
+		}
 	}
 	}
 	old_fops = file->f_op;
 	old_fops = file->f_op;
 	file->f_op = fops_get(mptr->f_ops);
 	file->f_op = fops_get(mptr->f_ops);
 	if (file->f_op == NULL) {
 	if (file->f_op == NULL) {
 		file->f_op = old_fops;
 		file->f_op = old_fops;
-		return -ENODEV;
+		err = -ENODEV;
 	}
 	}
-	if (file->f_op->open)
+	mutex_unlock(&sound_mutex);
+	if (err < 0)
+		return err;
+
+	if (file->f_op->open) {
 		err = file->f_op->open(inode, file);
 		err = file->f_op->open(inode, file);
-	if (err) {
-		fops_put(file->f_op);
-		file->f_op = fops_get(old_fops);
+		if (err) {
+			fops_put(file->f_op);
+			file->f_op = fops_get(old_fops);
+		}
 	}
 	}
 	fops_put(old_fops);
 	fops_put(old_fops);
 	return err;
 	return err;
 }
 }
 
 
-
-/* BKL pushdown: nasty #ifdef avoidance wrapper */
-static int snd_open(struct inode *inode, struct file *file)
-{
-	int ret;
-
-	lock_kernel();
-	ret = __snd_open(inode, file);
-	unlock_kernel();
-	return ret;
-}
-
 static const struct file_operations snd_fops =
 static const struct file_operations snd_fops =
 {
 {
 	.owner =	THIS_MODULE,
 	.owner =	THIS_MODULE,

+ 6 - 0
sound/core/timer.c

@@ -1238,6 +1238,11 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
 static int snd_timer_user_open(struct inode *inode, struct file *file)
 static int snd_timer_user_open(struct inode *inode, struct file *file)
 {
 {
 	struct snd_timer_user *tu;
 	struct snd_timer_user *tu;
+	int err;
+
+	err = nonseekable_open(inode, file);
+	if (err < 0)
+		return err;
 
 
 	tu = kzalloc(sizeof(*tu), GFP_KERNEL);
 	tu = kzalloc(sizeof(*tu), GFP_KERNEL);
 	if (tu == NULL)
 	if (tu == NULL)
@@ -1922,6 +1927,7 @@ static const struct file_operations snd_timer_f_ops =
 	.read =		snd_timer_user_read,
 	.read =		snd_timer_user_read,
 	.open =		snd_timer_user_open,
 	.open =		snd_timer_user_open,
 	.release =	snd_timer_user_release,
 	.release =	snd_timer_user_release,
+	.llseek =	no_llseek,
 	.poll =		snd_timer_user_poll,
 	.poll =		snd_timer_user_poll,
 	.unlocked_ioctl =	snd_timer_user_ioctl,
 	.unlocked_ioctl =	snd_timer_user_ioctl,
 	.compat_ioctl =	snd_timer_user_ioctl_compat,
 	.compat_ioctl =	snd_timer_user_ioctl_compat,

+ 25 - 58
sound/drivers/opl4/opl4_proc.c

@@ -49,77 +49,45 @@ static int snd_opl4_mem_proc_release(struct snd_info_entry *entry,
 	return 0;
 	return 0;
 }
 }
 
 
-static long snd_opl4_mem_proc_read(struct snd_info_entry *entry, void *file_private_data,
-				   struct file *file, char __user *_buf,
-				   unsigned long count, unsigned long pos)
+static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry,
+				      void *file_private_data,
+				      struct file *file, char __user *_buf,
+				      size_t count, loff_t pos)
 {
 {
 	struct snd_opl4 *opl4 = entry->private_data;
 	struct snd_opl4 *opl4 = entry->private_data;
-	long size;
 	char* buf;
 	char* buf;
 
 
-	size = count;
-	if (pos + size > entry->size)
-		size = entry->size - pos;
-	if (size > 0) {
-		buf = vmalloc(size);
-		if (!buf)
-			return -ENOMEM;
-		snd_opl4_read_memory(opl4, buf, pos, size);
-		if (copy_to_user(_buf, buf, size)) {
-			vfree(buf);
-			return -EFAULT;
-		}
+	buf = vmalloc(count);
+	if (!buf)
+		return -ENOMEM;
+	snd_opl4_read_memory(opl4, buf, pos, count);
+	if (copy_to_user(_buf, buf, count)) {
 		vfree(buf);
 		vfree(buf);
-		return size;
+		return -EFAULT;
 	}
 	}
-	return 0;
+	vfree(buf);
+	return count;
 }
 }
 
 
-static long snd_opl4_mem_proc_write(struct snd_info_entry *entry, void *file_private_data,
-				    struct file *file, const char __user *_buf,
-				    unsigned long count, unsigned long pos)
+static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry,
+				       void *file_private_data,
+				       struct file *file,
+				       const char __user *_buf,
+				       size_t count, loff_t pos)
 {
 {
 	struct snd_opl4 *opl4 = entry->private_data;
 	struct snd_opl4 *opl4 = entry->private_data;
-	long size;
 	char *buf;
 	char *buf;
 
 
-	size = count;
-	if (pos + size > entry->size)
-		size = entry->size - pos;
-	if (size > 0) {
-		buf = vmalloc(size);
-		if (!buf)
-			return -ENOMEM;
-		if (copy_from_user(buf, _buf, size)) {
-			vfree(buf);
-			return -EFAULT;
-		}
-		snd_opl4_write_memory(opl4, buf, pos, size);
+	buf = vmalloc(count);
+	if (!buf)
+		return -ENOMEM;
+	if (copy_from_user(buf, _buf, count)) {
 		vfree(buf);
 		vfree(buf);
-		return size;
-	}
-	return 0;
-}
-
-static long long snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, void *file_private_data,
-					  struct file *file, long long offset, int orig)
-{
-	switch (orig) {
-	case SEEK_SET:
-		file->f_pos = offset;
-		break;
-	case SEEK_CUR:
-		file->f_pos += offset;
-		break;
-	case SEEK_END: /* offset is negative */
-		file->f_pos = entry->size + offset;
-		break;
-	default:
-		return -EINVAL;
+		return -EFAULT;
 	}
 	}
-	if (file->f_pos > entry->size)
-		file->f_pos = entry->size;
-	return file->f_pos;
+	snd_opl4_write_memory(opl4, buf, pos, count);
+	vfree(buf);
+	return count;
 }
 }
 
 
 static struct snd_info_entry_ops snd_opl4_mem_proc_ops = {
 static struct snd_info_entry_ops snd_opl4_mem_proc_ops = {
@@ -127,7 +95,6 @@ static struct snd_info_entry_ops snd_opl4_mem_proc_ops = {
 	.release = snd_opl4_mem_proc_release,
 	.release = snd_opl4_mem_proc_release,
 	.read = snd_opl4_mem_proc_read,
 	.read = snd_opl4_mem_proc_read,
 	.write = snd_opl4_mem_proc_write,
 	.write = snd_opl4_mem_proc_write,
-	.llseek = snd_opl4_mem_proc_llseek,
 };
 };
 
 
 int snd_opl4_create_proc(struct snd_opl4 *opl4)
 int snd_opl4_create_proc(struct snd_opl4 *opl4)

+ 12 - 6
sound/i2c/i2c.c

@@ -98,7 +98,8 @@ int snd_i2c_bus_create(struct snd_card *card, const char *name,
 		bus->master = master;
 		bus->master = master;
 	}
 	}
 	strlcpy(bus->name, name, sizeof(bus->name));
 	strlcpy(bus->name, name, sizeof(bus->name));
-	if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &ops)) < 0) {
+	err = snd_device_new(card, SNDRV_DEV_BUS, bus, &ops);
+	if (err < 0) {
 		snd_i2c_bus_free(bus);
 		snd_i2c_bus_free(bus);
 		return err;
 		return err;
 	}
 	}
@@ -246,7 +247,8 @@ static int snd_i2c_bit_sendbyte(struct snd_i2c_bus *bus, unsigned char data)
 
 
 	for (i = 7; i >= 0; i--)
 	for (i = 7; i >= 0; i--)
 		snd_i2c_bit_send(bus, !!(data & (1 << i)));
 		snd_i2c_bit_send(bus, !!(data & (1 << i)));
-	if ((err = snd_i2c_bit_ack(bus)) < 0)
+	err = snd_i2c_bit_ack(bus);
+	if (err < 0)
 		return err;
 		return err;
 	return 0;
 	return 0;
 }
 }
@@ -278,12 +280,14 @@ static int snd_i2c_bit_sendbytes(struct snd_i2c_device *device,
 	if (device->flags & SND_I2C_DEVICE_ADDRTEN)
 	if (device->flags & SND_I2C_DEVICE_ADDRTEN)
 		return -EIO;		/* not yet implemented */
 		return -EIO;		/* not yet implemented */
 	snd_i2c_bit_start(bus);
 	snd_i2c_bit_start(bus);
-	if ((err = snd_i2c_bit_sendbyte(bus, device->addr << 1)) < 0) {
+	err = snd_i2c_bit_sendbyte(bus, device->addr << 1);
+	if (err < 0) {
 		snd_i2c_bit_hw_stop(bus);
 		snd_i2c_bit_hw_stop(bus);
 		return err;
 		return err;
 	}
 	}
 	while (count-- > 0) {
 	while (count-- > 0) {
-		if ((err = snd_i2c_bit_sendbyte(bus, *bytes++)) < 0) {
+		err = snd_i2c_bit_sendbyte(bus, *bytes++);
+		if (err < 0) {
 			snd_i2c_bit_hw_stop(bus);
 			snd_i2c_bit_hw_stop(bus);
 			return err;
 			return err;
 		}
 		}
@@ -302,12 +306,14 @@ static int snd_i2c_bit_readbytes(struct snd_i2c_device *device,
 	if (device->flags & SND_I2C_DEVICE_ADDRTEN)
 	if (device->flags & SND_I2C_DEVICE_ADDRTEN)
 		return -EIO;		/* not yet implemented */
 		return -EIO;		/* not yet implemented */
 	snd_i2c_bit_start(bus);
 	snd_i2c_bit_start(bus);
-	if ((err = snd_i2c_bit_sendbyte(bus, (device->addr << 1) | 1)) < 0) {
+	err = snd_i2c_bit_sendbyte(bus, (device->addr << 1) | 1);
+	if (err < 0) {
 		snd_i2c_bit_hw_stop(bus);
 		snd_i2c_bit_hw_stop(bus);
 		return err;
 		return err;
 	}
 	}
 	while (count-- > 0) {
 	while (count-- > 0) {
-		if ((err = snd_i2c_bit_readbyte(bus, count == 0)) < 0) {
+		err = snd_i2c_bit_readbyte(bus, count == 0);
+		if (err < 0) {
 			snd_i2c_bit_hw_stop(bus);
 			snd_i2c_bit_hw_stop(bus);
 			return err;
 			return err;
 		}
 		}

+ 2 - 14
sound/isa/Kconfig

@@ -128,26 +128,14 @@ config SND_CS4236
 	  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-cs4236.
 	  will be called snd-cs4236.
 
 
-config SND_ES968
-	tristate "Generic ESS ES968 driver"
-	depends on PNP
-	select ISAPNP
-	select SND_MPU401_UART
-	select SND_SB8_DSP
-	help
-	  Say Y here to include support for ESS AudioDrive ES968 chips.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-es968.
-
 config SND_ES1688
 config SND_ES1688
-	tristate "Generic ESS ES688/ES1688 driver"
+	tristate "Generic ESS ES688/ES1688 and ES968 PnP driver"
 	select SND_OPL3_LIB
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
 	select SND_MPU401_UART
 	select SND_PCM
 	select SND_PCM
 	help
 	help
 	  Say Y here to include support for ESS AudioDrive ES688 or
 	  Say Y here to include support for ESS AudioDrive ES688 or
-	  ES1688 chips.
+	  ES1688 chips. Also, this module support cards with ES968 PnP chip.
 
 
 	  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-es1688.
 	  will be called snd-es1688.

+ 190 - 35
sound/isa/es1688/es1688.c

@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/isa.h>
 #include <linux/isa.h>
+#include <linux/isapnp.h>
 #include <linux/time.h>
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
@@ -45,8 +46,13 @@ MODULE_SUPPORTED_DEVICE("{{ESS,ES688 PnP AudioDrive,pnp:ESS0100},"
 	        "{ESS,ES688 AudioDrive,pnp:ESS6881},"
 	        "{ESS,ES688 AudioDrive,pnp:ESS6881},"
 	        "{ESS,ES1688 AudioDrive,pnp:ESS1681}}");
 	        "{ESS,ES1688 AudioDrive,pnp:ESS1681}}");
 
 
+MODULE_ALIAS("snd_es968");
+
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+#ifdef CONFIG_PNP
+static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
+#endif
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240,0x260 */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240,0x260 */
 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* Usually 0x388 */
 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* Usually 0x388 */
@@ -60,6 +66,10 @@ MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
 module_param_array(id, charp, NULL, 0444);
 module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
 MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 module_param_array(enable, bool, NULL, 0444);
+#ifdef CONFIG_PNP
+module_param_array(isapnp, bool, NULL, 0444);
+MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
+#endif
 MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
 MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
 module_param_array(port, long, NULL, 0444);
 module_param_array(port, long, NULL, 0444);
 MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
 MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
@@ -74,14 +84,21 @@ MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
 module_param_array(dma8, int, NULL, 0444);
 module_param_array(dma8, int, NULL, 0444);
 MODULE_PARM_DESC(dma8, "8-bit DMA # for " CRD_NAME " driver.");
 MODULE_PARM_DESC(dma8, "8-bit DMA # for " CRD_NAME " driver.");
 
 
+#ifdef CONFIG_PNP
+#define is_isapnp_selected(dev)		isapnp[dev]
+#else
+#define is_isapnp_selected(dev)		0
+#endif
+
 static int __devinit snd_es1688_match(struct device *dev, unsigned int n)
 static int __devinit snd_es1688_match(struct device *dev, unsigned int n)
 {
 {
-	return enable[n];
+	return enable[n] && !is_isapnp_selected(n);
 }
 }
 
 
-static int __devinit snd_es1688_legacy_create(struct snd_card *card, 
-		struct device *dev, unsigned int n, struct snd_es1688 **rchip)
+static int __devinit snd_es1688_legacy_create(struct snd_card *card,
+					struct device *dev, unsigned int n)
 {
 {
+	struct snd_es1688 *chip = card->private_data;
 	static long possible_ports[] = {0x220, 0x240, 0x260};
 	static long possible_ports[] = {0x220, 0x240, 0x260};
 	static int possible_irqs[] = {5, 9, 10, 7, -1};
 	static int possible_irqs[] = {5, 9, 10, 7, -1};
 	static int possible_dmas[] = {1, 3, 0, -1};
 	static int possible_dmas[] = {1, 3, 0, -1};
@@ -104,47 +121,39 @@ static int __devinit snd_es1688_legacy_create(struct snd_card *card,
 	}
 	}
 
 
 	if (port[n] != SNDRV_AUTO_PORT)
 	if (port[n] != SNDRV_AUTO_PORT)
-		return snd_es1688_create(card, port[n], mpu_port[n], irq[n],
-				mpu_irq[n], dma8[n], ES1688_HW_AUTO, rchip);
+		return snd_es1688_create(card, chip, port[n], mpu_port[n],
+				irq[n], mpu_irq[n], dma8[n], ES1688_HW_AUTO);
 
 
 	i = 0;
 	i = 0;
 	do {
 	do {
 		port[n] = possible_ports[i];
 		port[n] = possible_ports[i];
-		error = snd_es1688_create(card, port[n], mpu_port[n], irq[n],
-				mpu_irq[n], dma8[n], ES1688_HW_AUTO, rchip);
+		error = snd_es1688_create(card, chip, port[n], mpu_port[n],
+				irq[n], mpu_irq[n], dma8[n], ES1688_HW_AUTO);
 	} while (error < 0 && ++i < ARRAY_SIZE(possible_ports));
 	} while (error < 0 && ++i < ARRAY_SIZE(possible_ports));
 
 
 	return error;
 	return error;
 }
 }
 
 
-static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
+static int __devinit snd_es1688_probe(struct snd_card *card, unsigned int n)
 {
 {
-	struct snd_card *card;
-	struct snd_es1688 *chip;
+	struct snd_es1688 *chip = card->private_data;
 	struct snd_opl3 *opl3;
 	struct snd_opl3 *opl3;
 	struct snd_pcm *pcm;
 	struct snd_pcm *pcm;
 	int error;
 	int error;
 
 
-	error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+	error = snd_es1688_pcm(card, chip, 0, &pcm);
 	if (error < 0)
 	if (error < 0)
 		return error;
 		return error;
 
 
-	error = snd_es1688_legacy_create(card, dev, n, &chip);
-	if (error < 0)
-		goto out;
-
-	error = snd_es1688_pcm(chip, 0, &pcm);
+	error = snd_es1688_mixer(card, chip);
 	if (error < 0)
 	if (error < 0)
-		goto out;
-
-	error = snd_es1688_mixer(chip);
-	if (error < 0)
-		goto out;
+		return error;
 
 
-	strcpy(card->driver, "ES1688");
-	strcpy(card->shortname, pcm->name);
-	sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", pcm->name,
-		chip->port, chip->irq, chip->dma8);
+	strlcpy(card->driver, "ES1688", sizeof(card->driver));
+	strlcpy(card->shortname, pcm->name, sizeof(card->shortname));
+	snprintf(card->longname, sizeof(card->longname),
+		"%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port,
+		 chip->irq, chip->dma8);
 
 
 	if (fm_port[n] == SNDRV_AUTO_PORT)
 	if (fm_port[n] == SNDRV_AUTO_PORT)
 		fm_port[n] = port[n];	/* share the same port */
 		fm_port[n] = port[n];	/* share the same port */
@@ -152,12 +161,12 @@ static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
 	if (fm_port[n] > 0) {
 	if (fm_port[n] > 0) {
 		if (snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
 		if (snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
 				OPL3_HW_OPL3, 0, &opl3) < 0)
 				OPL3_HW_OPL3, 0, &opl3) < 0)
-			dev_warn(dev,
+			dev_warn(card->dev,
 				 "opl3 not detected at 0x%lx\n", fm_port[n]);
 				 "opl3 not detected at 0x%lx\n", fm_port[n]);
 		else {
 		else {
 			error =	snd_opl3_hwdep_new(opl3, 0, 1, NULL);
 			error =	snd_opl3_hwdep_new(opl3, 0, 1, NULL);
 			if (error < 0)
 			if (error < 0)
-				goto out;
+				return error;
 		}
 		}
 	}
 	}
 
 
@@ -167,23 +176,41 @@ static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
 				chip->mpu_port, 0,
 				chip->mpu_port, 0,
 				mpu_irq[n], IRQF_DISABLED, NULL);
 				mpu_irq[n], IRQF_DISABLED, NULL);
 		if (error < 0)
 		if (error < 0)
-			goto out;
+			return error;
 	}
 	}
 
 
+	return snd_card_register(card);
+}
+
+static int __devinit snd_es1688_isa_probe(struct device *dev, unsigned int n)
+{
+	struct snd_card *card;
+	int error;
+
+	error = snd_card_create(index[n], id[n], THIS_MODULE,
+				sizeof(struct snd_es1688), &card);
+	if (error < 0)
+		return error;
+
+	error = snd_es1688_legacy_create(card, dev, n);
+	if (error < 0)
+		goto out;
+
 	snd_card_set_dev(card, dev);
 	snd_card_set_dev(card, dev);
 
 
-	error = snd_card_register(card);
+	error = snd_es1688_probe(card, n);
 	if (error < 0)
 	if (error < 0)
 		goto out;
 		goto out;
 
 
 	dev_set_drvdata(dev, card);
 	dev_set_drvdata(dev, card);
-	return 0;
 
 
-out:	snd_card_free(card);
+	return 0;
+out:
+	snd_card_free(card);
 	return error;
 	return error;
 }
 }
 
 
-static int __devexit snd_es1688_remove(struct device *dev, unsigned int n)
+static int __devexit snd_es1688_isa_remove(struct device *dev, unsigned int n)
 {
 {
 	snd_card_free(dev_get_drvdata(dev));
 	snd_card_free(dev_get_drvdata(dev));
 	dev_set_drvdata(dev, NULL);
 	dev_set_drvdata(dev, NULL);
@@ -192,8 +219,8 @@ static int __devexit snd_es1688_remove(struct device *dev, unsigned int n)
 
 
 static struct isa_driver snd_es1688_driver = {
 static struct isa_driver snd_es1688_driver = {
 	.match		= snd_es1688_match,
 	.match		= snd_es1688_match,
-	.probe		= snd_es1688_probe,
-	.remove		= __devexit_p(snd_es1688_remove),
+	.probe		= snd_es1688_isa_probe,
+	.remove		= __devexit_p(snd_es1688_isa_remove),
 #if 0	/* FIXME */
 #if 0	/* FIXME */
 	.suspend	= snd_es1688_suspend,
 	.suspend	= snd_es1688_suspend,
 	.resume		= snd_es1688_resume,
 	.resume		= snd_es1688_resume,
@@ -203,14 +230,142 @@ static struct isa_driver snd_es1688_driver = {
 	}
 	}
 };
 };
 
 
+static int snd_es968_pnp_is_probed;
+
+#ifdef CONFIG_PNP
+static int __devinit snd_card_es968_pnp(struct snd_card *card, unsigned int n,
+					struct pnp_card_link *pcard,
+					const struct pnp_card_device_id *pid)
+{
+	struct snd_es1688 *chip = card->private_data;
+	struct pnp_dev *pdev;
+	int error;
+
+	pdev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
+	if (pdev == NULL)
+		return -ENODEV;
+
+	error = pnp_activate_dev(pdev);
+	if (error < 0) {
+		snd_printk(KERN_ERR "ES968 pnp configure failure\n");
+		return error;
+	}
+	port[n] = pnp_port_start(pdev, 0);
+	dma8[n] = pnp_dma(pdev, 0);
+	irq[n] = pnp_irq(pdev, 0);
+
+	return snd_es1688_create(card, chip, port[n], mpu_port[n], irq[n],
+				 mpu_irq[n], dma8[n], ES1688_HW_AUTO);
+}
+
+static int __devinit snd_es968_pnp_detect(struct pnp_card_link *pcard,
+					  const struct pnp_card_device_id *pid)
+{
+	struct snd_card *card;
+	static unsigned int dev;
+	int error;
+	struct snd_es1688 *chip;
+
+	if (snd_es968_pnp_is_probed)
+		return -EBUSY;
+	for ( ; dev < SNDRV_CARDS; dev++) {
+		if (enable[dev] && isapnp[dev])
+			break;
+	}
+	if (dev == SNDRV_CARDS)
+		return -ENODEV;
+
+	error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+				sizeof(struct snd_es1688), &card);
+	if (error < 0)
+		return error;
+	chip = card->private_data;
+
+	error = snd_card_es968_pnp(card, dev, pcard, pid);
+	if (error < 0) {
+		snd_card_free(card);
+		return error;
+	}
+	snd_card_set_dev(card, &pcard->card->dev);
+	error = snd_es1688_probe(card, dev);
+	if (error < 0)
+		return error;
+	pnp_set_card_drvdata(pcard, card);
+	snd_es968_pnp_is_probed = 1;
+	return 0;
+}
+
+static void __devexit snd_es968_pnp_remove(struct pnp_card_link * pcard)
+{
+	snd_card_free(pnp_get_card_drvdata(pcard));
+	pnp_set_card_drvdata(pcard, NULL);
+	snd_es968_pnp_is_probed = 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_es968_pnp_suspend(struct pnp_card_link *pcard,
+				 pm_message_t state)
+{
+	struct snd_card *card = pnp_get_card_drvdata(pcard);
+	struct snd_es1688 *chip = card->private_data;
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	snd_pcm_suspend_all(chip->pcm);
+	return 0;
+}
+
+static int snd_es968_pnp_resume(struct pnp_card_link *pcard)
+{
+	struct snd_card *card = pnp_get_card_drvdata(pcard);
+	struct snd_es1688 *chip = card->private_data;
+
+	snd_es1688_reset(chip);
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	return 0;
+}
+#endif
+
+static struct pnp_card_device_id snd_es968_pnpids[] = {
+	{ .id = "ESS0968", .devs = { { "@@@0968" }, } },
+	{ .id = "ESS0968", .devs = { { "ESS0968" }, } },
+	{ .id = "", } /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp_card, snd_es968_pnpids);
+
+static struct pnp_card_driver es968_pnpc_driver = {
+	.flags		= PNP_DRIVER_RES_DISABLE,
+	.name		= DEV_NAME " PnP",
+	.id_table	= snd_es968_pnpids,
+	.probe		= snd_es968_pnp_detect,
+	.remove		= __devexit_p(snd_es968_pnp_remove),
+#ifdef CONFIG_PM
+	.suspend	= snd_es968_pnp_suspend,
+	.resume		= snd_es968_pnp_resume,
+#endif
+};
+#endif
+
 static int __init alsa_card_es1688_init(void)
 static int __init alsa_card_es1688_init(void)
 {
 {
+#ifdef CONFIG_PNP
+	pnp_register_card_driver(&es968_pnpc_driver);
+	if (snd_es968_pnp_is_probed)
+		return 0;
+	pnp_unregister_card_driver(&es968_pnpc_driver);
+#endif
 	return isa_register_driver(&snd_es1688_driver, SNDRV_CARDS);
 	return isa_register_driver(&snd_es1688_driver, SNDRV_CARDS);
 }
 }
 
 
 static void __exit alsa_card_es1688_exit(void)
 static void __exit alsa_card_es1688_exit(void)
 {
 {
-	isa_unregister_driver(&snd_es1688_driver);
+	if (!snd_es968_pnp_is_probed) {
+		isa_unregister_driver(&snd_es1688_driver);
+		return;
+	}
+#ifdef CONFIG_PNP
+	pnp_unregister_card_driver(&es968_pnpc_driver);
+#endif
 }
 }
 
 
 module_init(alsa_card_es1688_init);
 module_init(alsa_card_es1688_init);

+ 16 - 31
sound/isa/es1688/es1688_lib.c

@@ -99,7 +99,7 @@ static unsigned char snd_es1688_mixer_read(struct snd_es1688 *chip, unsigned cha
 	return result;
 	return result;
 }
 }
 
 
-static int snd_es1688_reset(struct snd_es1688 *chip)
+int snd_es1688_reset(struct snd_es1688 *chip)
 {
 {
 	int i;
 	int i;
 
 
@@ -115,6 +115,7 @@ static int snd_es1688_reset(struct snd_es1688 *chip)
 	snd_es1688_dsp_command(chip, 0xc6);	/* enable extended mode */
 	snd_es1688_dsp_command(chip, 0xc6);	/* enable extended mode */
 	return 0;
 	return 0;
 }
 }
+EXPORT_SYMBOL(snd_es1688_reset);
 
 
 static int snd_es1688_probe(struct snd_es1688 *chip)
 static int snd_es1688_probe(struct snd_es1688 *chip)
 {
 {
@@ -620,7 +621,6 @@ static int snd_es1688_free(struct snd_es1688 *chip)
 		disable_dma(chip->dma8);
 		disable_dma(chip->dma8);
 		free_dma(chip->dma8);
 		free_dma(chip->dma8);
 	}
 	}
-	kfree(chip);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -638,23 +638,20 @@ static const char *snd_es1688_chip_id(struct snd_es1688 *chip)
 }
 }
 
 
 int snd_es1688_create(struct snd_card *card,
 int snd_es1688_create(struct snd_card *card,
+		      struct snd_es1688 *chip,
 		      unsigned long port,
 		      unsigned long port,
 		      unsigned long mpu_port,
 		      unsigned long mpu_port,
 		      int irq,
 		      int irq,
 		      int mpu_irq,
 		      int mpu_irq,
 		      int dma8,
 		      int dma8,
-		      unsigned short hardware,
-		      struct snd_es1688 **rchip)
+		      unsigned short hardware)
 {
 {
 	static struct snd_device_ops ops = {
 	static struct snd_device_ops ops = {
 		.dev_free =	snd_es1688_dev_free,
 		.dev_free =	snd_es1688_dev_free,
 	};
 	};
                                 
                                 
-	struct snd_es1688 *chip;
 	int err;
 	int err;
 
 
-	*rchip = NULL;
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 	if (chip == NULL)
 	if (chip == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 	chip->irq = -1;
 	chip->irq = -1;
@@ -662,25 +659,21 @@ int snd_es1688_create(struct snd_card *card,
 	
 	
 	if ((chip->res_port = request_region(port + 4, 12, "ES1688")) == NULL) {
 	if ((chip->res_port = request_region(port + 4, 12, "ES1688")) == NULL) {
 		snd_printk(KERN_ERR "es1688: can't grab port 0x%lx\n", port + 4);
 		snd_printk(KERN_ERR "es1688: can't grab port 0x%lx\n", port + 4);
-		snd_es1688_free(chip);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 	if (request_irq(irq, snd_es1688_interrupt, IRQF_DISABLED, "ES1688", (void *) chip)) {
 	if (request_irq(irq, snd_es1688_interrupt, IRQF_DISABLED, "ES1688", (void *) chip)) {
 		snd_printk(KERN_ERR "es1688: can't grab IRQ %d\n", irq);
 		snd_printk(KERN_ERR "es1688: can't grab IRQ %d\n", irq);
-		snd_es1688_free(chip);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 	chip->irq = irq;
 	chip->irq = irq;
 	if (request_dma(dma8, "ES1688")) {
 	if (request_dma(dma8, "ES1688")) {
 		snd_printk(KERN_ERR "es1688: can't grab DMA8 %d\n", dma8);
 		snd_printk(KERN_ERR "es1688: can't grab DMA8 %d\n", dma8);
-		snd_es1688_free(chip);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 	chip->dma8 = dma8;
 	chip->dma8 = dma8;
 
 
 	spin_lock_init(&chip->reg_lock);
 	spin_lock_init(&chip->reg_lock);
 	spin_lock_init(&chip->mixer_lock);
 	spin_lock_init(&chip->mixer_lock);
-	chip->card = card;
 	chip->port = port;
 	chip->port = port;
 	mpu_port &= ~0x000f;
 	mpu_port &= ~0x000f;
 	if (mpu_port < 0x300 || mpu_port > 0x330)
 	if (mpu_port < 0x300 || mpu_port > 0x330)
@@ -689,23 +682,16 @@ int snd_es1688_create(struct snd_card *card,
 	chip->mpu_irq = mpu_irq;
 	chip->mpu_irq = mpu_irq;
 	chip->hardware = hardware;
 	chip->hardware = hardware;
 
 
-	if ((err = snd_es1688_probe(chip)) < 0) {
-		snd_es1688_free(chip);
+	err = snd_es1688_probe(chip);
+	if (err < 0)
 		return err;
 		return err;
-	}
-	if ((err = snd_es1688_init(chip, 1)) < 0) {
-		snd_es1688_free(chip);
-		return err;
-	}
 
 
-	/* Register device */
-	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
-		snd_es1688_free(chip);
+	err = snd_es1688_init(chip, 1);
+	if (err < 0)
 		return err;
 		return err;
-	}
 
 
-	*rchip = chip;
-	return 0;
+	/* Register device */
+	return snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
 }
 }
 
 
 static struct snd_pcm_ops snd_es1688_playback_ops = {
 static struct snd_pcm_ops snd_es1688_playback_ops = {
@@ -730,12 +716,14 @@ static struct snd_pcm_ops snd_es1688_capture_ops = {
 	.pointer =		snd_es1688_capture_pointer,
 	.pointer =		snd_es1688_capture_pointer,
 };
 };
 
 
-int snd_es1688_pcm(struct snd_es1688 * chip, int device, struct snd_pcm ** rpcm)
+int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip,
+		   int device, struct snd_pcm **rpcm)
 {
 {
 	struct snd_pcm *pcm;
 	struct snd_pcm *pcm;
 	int err;
 	int err;
 
 
-	if ((err = snd_pcm_new(chip->card, "ESx688", device, 1, 1, &pcm)) < 0)
+	err = snd_pcm_new(card, "ESx688", device, 1, 1, &pcm);
+	if (err < 0)
 		return err;
 		return err;
 
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1688_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1688_playback_ops);
@@ -1009,18 +997,15 @@ static unsigned char snd_es1688_init_table[][2] = {
 	{ ES1688_REC_DEV, 0x17 }
 	{ ES1688_REC_DEV, 0x17 }
 };
 };
                                         
                                         
-int snd_es1688_mixer(struct snd_es1688 *chip)
+int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip)
 {
 {
-	struct snd_card *card;
 	unsigned int idx;
 	unsigned int idx;
 	int err;
 	int err;
 	unsigned char reg, val;
 	unsigned char reg, val;
 
 
-	if (snd_BUG_ON(!chip || !chip->card))
+	if (snd_BUG_ON(!chip || !card))
 		return -EINVAL;
 		return -EINVAL;
 
 
-	card = chip->card;
-
 	strcpy(card->mixername, snd_es1688_chip_id(chip));
 	strcpy(card->mixername, snd_es1688_chip_id(chip));
 
 
 	for (idx = 0; idx < ARRAY_SIZE(snd_es1688_controls); idx++) {
 	for (idx = 0; idx < ARRAY_SIZE(snd_es1688_controls); idx++) {

+ 8 - 40
sound/isa/gus/gus_mem_proc.c

@@ -31,52 +31,21 @@ struct gus_proc_private {
 	struct snd_gus_card * gus;
 	struct snd_gus_card * gus;
 };
 };
 
 
-static long snd_gf1_mem_proc_dump(struct snd_info_entry *entry, void *file_private_data,
-			          struct file *file, char __user *buf,
-			          unsigned long count, unsigned long pos)
+static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry,
+				     void *file_private_data,
+				     struct file *file, char __user *buf,
+				     size_t count, loff_t pos)
 {
 {
-	long size;
 	struct gus_proc_private *priv = entry->private_data;
 	struct gus_proc_private *priv = entry->private_data;
 	struct snd_gus_card *gus = priv->gus;
 	struct snd_gus_card *gus = priv->gus;
 	int err;
 	int err;
 
 
-	size = count;
-	if (pos + size > priv->size)
-		size = (long)priv->size - pos;
-	if (size > 0) {
-		if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0)
-			return err;
-		return size;
-	}
-	return 0;
+	err = snd_gus_dram_read(gus, buf, pos, count, priv->rom);
+	if (err < 0)
+		return err;
+	return count;
 }			
 }			
 
 
-static long long snd_gf1_mem_proc_llseek(struct snd_info_entry *entry,
-					void *private_file_data,
-					struct file *file,
-					long long offset,
-					int orig)
-{
-	struct gus_proc_private *priv = entry->private_data;
-
-	switch (orig) {
-	case SEEK_SET:
-		file->f_pos = offset;
-		break;
-	case SEEK_CUR:
-		file->f_pos += offset;
-		break;
-	case SEEK_END: /* offset is negative */
-		file->f_pos = priv->size + offset;
-		break;
-	default:
-		return -EINVAL;
-	}
-	if (file->f_pos > priv->size)
-		file->f_pos = priv->size;
-	return file->f_pos;
-}
-
 static void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
 static void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
 {
 {
 	struct gus_proc_private *priv = entry->private_data;
 	struct gus_proc_private *priv = entry->private_data;
@@ -85,7 +54,6 @@ static void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
 
 
 static struct snd_info_entry_ops snd_gf1_mem_proc_ops = {
 static struct snd_info_entry_ops snd_gf1_mem_proc_ops = {
 	.read = snd_gf1_mem_proc_dump,
 	.read = snd_gf1_mem_proc_dump,
-	.llseek = snd_gf1_mem_proc_llseek,
 };
 };
 
 
 int snd_gf1_mem_proc_init(struct snd_gus_card * gus)
 int snd_gf1_mem_proc_init(struct snd_gus_card * gus)

+ 14 - 12
sound/isa/gus/gusextreme.c

@@ -95,7 +95,7 @@ static int __devinit snd_gusextreme_match(struct device *dev, unsigned int n)
 }
 }
 
 
 static int __devinit snd_gusextreme_es1688_create(struct snd_card *card,
 static int __devinit snd_gusextreme_es1688_create(struct snd_card *card,
-		struct device *dev, unsigned int n, struct snd_es1688 **rchip)
+		struct snd_es1688 *chip, struct device *dev, unsigned int n)
 {
 {
 	static long possible_ports[] = {0x220, 0x240, 0x260};
 	static long possible_ports[] = {0x220, 0x240, 0x260};
 	static int possible_irqs[] = {5, 9, 10, 7, -1};
 	static int possible_irqs[] = {5, 9, 10, 7, -1};
@@ -119,14 +119,14 @@ static int __devinit snd_gusextreme_es1688_create(struct snd_card *card,
 	}
 	}
 
 
 	if (port[n] != SNDRV_AUTO_PORT)
 	if (port[n] != SNDRV_AUTO_PORT)
-		return snd_es1688_create(card, port[n], mpu_port[n], irq[n],
-				mpu_irq[n], dma8[n], ES1688_HW_1688, rchip);
+		return snd_es1688_create(card, chip, port[n], mpu_port[n],
+				irq[n], mpu_irq[n], dma8[n], ES1688_HW_1688);
 
 
 	i = 0;
 	i = 0;
 	do {
 	do {
 		port[n] = possible_ports[i];
 		port[n] = possible_ports[i];
-		error = snd_es1688_create(card, port[n], mpu_port[n], irq[n],
-				mpu_irq[n], dma8[n], ES1688_HW_1688, rchip);
+		error = snd_es1688_create(card, chip, port[n], mpu_port[n],
+				irq[n], mpu_irq[n], dma8[n], ES1688_HW_1688);
 	} while (error < 0 && ++i < ARRAY_SIZE(possible_ports));
 	} while (error < 0 && ++i < ARRAY_SIZE(possible_ports));
 
 
 	return error;
 	return error;
@@ -206,9 +206,8 @@ static int __devinit snd_gusextreme_detect(struct snd_gus_card *gus,
 	return 0;
 	return 0;
 }
 }
 
 
-static int __devinit snd_gusextreme_mixer(struct snd_es1688 *chip)
+static int __devinit snd_gusextreme_mixer(struct snd_card *card)
 {
 {
-	struct snd_card *card = chip->card;
 	struct snd_ctl_elem_id id1, id2;
 	struct snd_ctl_elem_id id1, id2;
 	int error;
 	int error;
 
 
@@ -241,17 +240,20 @@ static int __devinit snd_gusextreme_probe(struct device *dev, unsigned int n)
 	struct snd_opl3 *opl3;
 	struct snd_opl3 *opl3;
 	int error;
 	int error;
 
 
-	error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+	error = snd_card_create(index[n], id[n], THIS_MODULE,
+				sizeof(struct snd_es1688), &card);
 	if (error < 0)
 	if (error < 0)
 		return error;
 		return error;
 
 
+	es1688 = card->private_data;
+
 	if (mpu_port[n] == SNDRV_AUTO_PORT)
 	if (mpu_port[n] == SNDRV_AUTO_PORT)
 		mpu_port[n] = 0;
 		mpu_port[n] = 0;
 
 
 	if (mpu_irq[n] > 15)
 	if (mpu_irq[n] > 15)
 		mpu_irq[n] = -1;
 		mpu_irq[n] = -1;
 
 
-	error = snd_gusextreme_es1688_create(card, dev, n, &es1688);
+	error = snd_gusextreme_es1688_create(card, es1688, dev, n);
 	if (error < 0)
 	if (error < 0)
 		goto out;
 		goto out;
 
 
@@ -280,11 +282,11 @@ static int __devinit snd_gusextreme_probe(struct device *dev, unsigned int n)
 	}
 	}
 	gus->codec_flag = 1;
 	gus->codec_flag = 1;
 
 
-	error = snd_es1688_pcm(es1688, 0, NULL);
+	error = snd_es1688_pcm(card, es1688, 0, NULL);
 	if (error < 0)
 	if (error < 0)
 		goto out;
 		goto out;
 
 
-	error = snd_es1688_mixer(es1688);
+	error = snd_es1688_mixer(card, es1688);
 	if (error < 0)
 	if (error < 0)
 		goto out;
 		goto out;
 
 
@@ -300,7 +302,7 @@ static int __devinit snd_gusextreme_probe(struct device *dev, unsigned int n)
 	if (error < 0)
 	if (error < 0)
 		goto out;
 		goto out;
 
 
-	error = snd_gusextreme_mixer(es1688);
+	error = snd_gusextreme_mixer(card);
 	if (error < 0)
 	if (error < 0)
 		goto out;
 		goto out;
 
 

+ 0 - 2
sound/isa/sb/Makefile

@@ -11,7 +11,6 @@ snd-sb8-objs := sb8.o
 snd-sb16-objs := sb16.o
 snd-sb16-objs := sb16.o
 snd-sbawe-objs := sbawe.o emu8000.o
 snd-sbawe-objs := sbawe.o emu8000.o
 snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
 snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
-snd-es968-objs := es968.o
 snd-jazz16-objs := jazz16.o
 snd-jazz16-objs := jazz16.o
 
 
 # Toplevel Module Dependency
 # Toplevel Module Dependency
@@ -21,7 +20,6 @@ obj-$(CONFIG_SND_SB8_DSP) += snd-sb8-dsp.o
 obj-$(CONFIG_SND_SB8) += snd-sb8.o
 obj-$(CONFIG_SND_SB8) += snd-sb8.o
 obj-$(CONFIG_SND_SB16) += snd-sb16.o
 obj-$(CONFIG_SND_SB16) += snd-sb16.o
 obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o
 obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o
-obj-$(CONFIG_SND_ES968) += snd-es968.o
 obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o
 obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o
 ifeq ($(CONFIG_SND_SB16_CSP),y)
 ifeq ($(CONFIG_SND_SB16_CSP),y)
   obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
   obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o

+ 0 - 248
sound/isa/sb/es968.c

@@ -1,248 +0,0 @@
-
-/*
-    card-es968.c - driver for ESS AudioDrive ES968 based soundcards.
-    Copyright (C) 1999 by Massimo Piccioni <dafastidio@libero.it>
-
-    Thanks to Pierfrancesco 'qM2' Passerini.
-
-    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/time.h>
-#include <linux/pnp.h>
-#include <linux/moduleparam.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/sb.h>
-
-#define PFX "es968: "
-
-MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
-MODULE_DESCRIPTION("ESS AudioDrive ES968");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ESS,AudioDrive ES968}}");
-
-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_ISAPNP; /* Enable this card */
-static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
-static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* Pnp setup */
-static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for es968 based soundcard.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for es968 based soundcard.");
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable es968 based soundcard.");
-
-struct snd_card_es968 {
-	struct pnp_dev *dev;
-	struct snd_sb *chip;
-};
-
-static struct pnp_card_device_id snd_es968_pnpids[] = {
-	{ .id = "ESS0968", .devs = { { "@@@0968" }, } },
-	{ .id = "", } /* end */
-};
-
-MODULE_DEVICE_TABLE(pnp_card, snd_es968_pnpids);
-
-#define	DRIVER_NAME	"snd-card-es968"
-
-static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id)
-{
-	struct snd_sb *chip = dev_id;
-
-	if (chip->open & SB_OPEN_PCM) {
-		return snd_sb8dsp_interrupt(chip);
-	} else {
-		return snd_sb8dsp_midi_interrupt(chip);
-	}
-}
-
-static int __devinit snd_card_es968_pnp(int dev, struct snd_card_es968 *acard,
-					struct pnp_card_link *card,
-					const struct pnp_card_device_id *id)
-{
-	struct pnp_dev *pdev;
-	int err;
-
-	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-	if (acard->dev == NULL)
-		return -ENODEV;
-
-	pdev = acard->dev;
-
-	err = pnp_activate_dev(pdev);
-	if (err < 0) {
-		snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
-		return err;
-	}
-	port[dev] = pnp_port_start(pdev, 0);
-	dma8[dev] = pnp_dma(pdev, 0);
-	irq[dev] = pnp_irq(pdev, 0);
-
-	return 0;
-}
-
-static int __devinit snd_card_es968_probe(int dev,
-					struct pnp_card_link *pcard,
-					const struct pnp_card_device_id *pid)
-{
-	int error;
-	struct snd_sb *chip;
-	struct snd_card *card;
-	struct snd_card_es968 *acard;
-
-	error = snd_card_create(index[dev], id[dev], THIS_MODULE,
-				sizeof(struct snd_card_es968), &card);
-	if (error < 0)
-		return error;
-	acard = card->private_data;
-	if ((error = snd_card_es968_pnp(dev, acard, pcard, pid))) {
-		snd_card_free(card);
-		return error;
-	}
-	snd_card_set_dev(card, &pcard->card->dev);
-
-	if ((error = snd_sbdsp_create(card, port[dev],
-				      irq[dev],
-				      snd_card_es968_interrupt,
-				      dma8[dev],
-				      -1,
-				      SB_HW_AUTO, &chip)) < 0) {
-		snd_card_free(card);
-		return error;
-	}
-	acard->chip = chip;
-
-	if ((error = snd_sb8dsp_pcm(chip, 0, NULL)) < 0) {
-		snd_card_free(card);
-		return error;
-	}
-
-	if ((error = snd_sbmixer_new(chip)) < 0) {
-		snd_card_free(card);
-		return error;
-	}
-
-	if ((error = snd_sb8dsp_midi(chip, 0, NULL)) < 0) {
-		snd_card_free(card);
-		return error;
-	}
-
-	strcpy(card->driver, "ES968");
-	strcpy(card->shortname, "ESS ES968");
-	sprintf(card->longname, "%s soundcard, %s at 0x%lx, irq %d, dma %d",
-		card->shortname, chip->name, chip->port, irq[dev], dma8[dev]);
-
-	if ((error = snd_card_register(card)) < 0) {
-		snd_card_free(card);
-		return error;
-	}
-	pnp_set_card_drvdata(pcard, card);
-	return 0;
-}
-
-static unsigned int __devinitdata es968_devices;
-
-static int __devinit snd_es968_pnp_detect(struct pnp_card_link *card,
-                                          const struct pnp_card_device_id *id)
-{
-	static int dev;
-	int res;
-
-	for ( ; dev < SNDRV_CARDS; dev++) {
-		if (!enable[dev])
-			continue;
-		res = snd_card_es968_probe(dev, card, id);
-		if (res < 0)
-			return res;
-		dev++;
-		es968_devices++;
-		return 0;
-	}
-	return -ENODEV;
-}
-
-static void __devexit snd_es968_pnp_remove(struct pnp_card_link * pcard)
-{
-	snd_card_free(pnp_get_card_drvdata(pcard));
-	pnp_set_card_drvdata(pcard, NULL);
-}
-
-#ifdef CONFIG_PM
-static int snd_es968_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
-{
-	struct snd_card *card = pnp_get_card_drvdata(pcard);
-	struct snd_card_es968 *acard = card->private_data;
-	struct snd_sb *chip = acard->chip;
-
-	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-	snd_pcm_suspend_all(chip->pcm);
-	snd_sbmixer_suspend(chip);
-	return 0;
-}
-
-static int snd_es968_pnp_resume(struct pnp_card_link *pcard)
-{
-	struct snd_card *card = pnp_get_card_drvdata(pcard);
-	struct snd_card_es968 *acard = card->private_data;
-	struct snd_sb *chip = acard->chip;
-
-	snd_sbdsp_reset(chip);
-	snd_sbmixer_resume(chip);
-	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-	return 0;
-}
-#endif
-
-static struct pnp_card_driver es968_pnpc_driver = {
-	.flags		= PNP_DRIVER_RES_DISABLE,
-	.name		= "es968",
-	.id_table	= snd_es968_pnpids,
-	.probe		= snd_es968_pnp_detect,
-	.remove		= __devexit_p(snd_es968_pnp_remove),
-#ifdef CONFIG_PM
-	.suspend	= snd_es968_pnp_suspend,
-	.resume		= snd_es968_pnp_resume,
-#endif
-};
-
-static int __init alsa_card_es968_init(void)
-{
-	int err = pnp_register_card_driver(&es968_pnpc_driver);
-	if (err)
-		return err;
-
-	if (!es968_devices) {
-		pnp_unregister_card_driver(&es968_pnpc_driver);
-#ifdef MODULE
-		snd_printk(KERN_ERR "no ES968 based soundcards found\n");
-#endif
-		return -ENODEV;
-	}
-	return 0;
-}
-
-static void __exit alsa_card_es968_exit(void)
-{
-	pnp_unregister_card_driver(&es968_pnpc_driver);
-}
-
-module_init(alsa_card_es968_init)
-module_exit(alsa_card_es968_exit)

+ 32 - 0
sound/pci/Kconfig

@@ -58,6 +58,18 @@ config SND_ALI5451
 	  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-ali5451.
 	  will be called snd-ali5451.
 
 
+config SND_ASIHPI
+	tristate "AudioScience ASIxxxx"
+	depends on X86
+	select FW_LOADER
+	select SND_PCM
+	select SND_HWDEP
+	help
+	  Say Y here to include support for AudioScience ASI sound cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-asihpi.
+
 config SND_ATIIXP
 config SND_ATIIXP
 	tristate "ATI IXP AC97 Controller"
 	tristate "ATI IXP AC97 Controller"
 	select SND_AC97_CODEC
 	select SND_AC97_CODEC
@@ -501,6 +513,16 @@ config SND_ES1968
 	  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-es1968.
 	  will be called snd-es1968.
 
 
+config SND_ES1968_INPUT
+	bool "Enable input device for es1968 volume buttons"
+	depends on SND_ES1968
+	depends on INPUT=y || INPUT=SND_ES1968
+	help
+	  If you say Y here, you will get an input device which reports
+	  keypresses for the volume buttons connected to the es1968 chip.
+	  If you say N the buttons will directly control the master volume.
+	  It is recommended to say Y.
+
 config SND_FM801
 config SND_FM801
 	tristate "ForteMedia FM801"
 	tristate "ForteMedia FM801"
 	select SND_OPL3_LIB
 	select SND_OPL3_LIB
@@ -655,6 +677,16 @@ config SND_MAESTRO3
 	  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-maestro3.
 	  will be called snd-maestro3.
 
 
+config SND_MAESTRO3_INPUT
+	bool "Enable input device for maestro3 volume buttons"
+	depends on SND_MAESTRO3
+	depends on INPUT=y || INPUT=SND_MAESTRO3
+	help
+	  If you say Y here, you will get an input device which reports
+	  keypresses for the volume buttons connected to the maestro3 chip.
+	  If you say N the buttons will directly control the master volume.
+	  It is recommended to say Y.
+
 config SND_MIXART
 config SND_MIXART
 	tristate "Digigram miXart"
 	tristate "Digigram miXart"
 	select SND_HWDEP
 	select SND_HWDEP

+ 1 - 0
sound/pci/Makefile

@@ -57,6 +57,7 @@ obj-$(CONFIG_SND_VIA82XX_MODEM) += snd-via82xx-modem.o
 obj-$(CONFIG_SND) += \
 obj-$(CONFIG_SND) += \
 	ac97/ \
 	ac97/ \
 	ali5451/ \
 	ali5451/ \
+	asihpi/ \
 	au88x0/ \
 	au88x0/ \
 	aw2/ \
 	aw2/ \
 	ctxfi/ \
 	ctxfi/ \

+ 5 - 0
sound/pci/asihpi/Makefile

@@ -0,0 +1,5 @@
+snd-asihpi-objs := asihpi.o hpioctl.o hpimsginit.o\
+	hpicmn.o hpifunc.o hpidebug.o hpidspcd.o\
+	hpios.o hpi6000.o hpi6205.o hpimsgx.o
+
+obj-$(CONFIG_SND_ASIHPI) += snd-asihpi.o

+ 3002 - 0
sound/pci/asihpi/asihpi.c

@@ -0,0 +1,3002 @@
+/*
+ *  Asihpi soundcard
+ *  Copyright (c) by AudioScience Inc <alsa@audioscience.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation;
+ *
+ *   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
+ *
+ *
+ *  The following is not a condition of use, merely a request:
+ *  If you modify this program, particularly if you fix errors, AudioScience Inc
+ *  would appreciate it if you grant us the right to use those modifications
+ *  for any purpose including commercial applications.
+ */
+/* >0: print Hw params, timer vars. >1: print stream write/copy sizes  */
+#define REALLY_VERBOSE_LOGGING 0
+
+#if REALLY_VERBOSE_LOGGING
+#define VPRINTK1 snd_printd
+#else
+#define VPRINTK1(...)
+#endif
+
+#if REALLY_VERBOSE_LOGGING > 1
+#define VPRINTK2 snd_printd
+#else
+#define VPRINTK2(...)
+#endif
+
+#ifndef ASI_STYLE_NAMES
+/* not sure how ALSA style name should look */
+#define ASI_STYLE_NAMES 1
+#endif
+
+#include "hpi_internal.h"
+#include "hpimsginit.h"
+#include "hpioctl.h"
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/hwdep.h>
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
+MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
+
+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_PNP;
+static int enable_hpi_hwdep = 1;
+
+module_param_array(index, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard.");
+
+module_param_array(id, charp, NULL, S_IRUGO);
+MODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard.");
+
+module_param_array(enable, bool, NULL, S_IRUGO);
+MODULE_PARM_DESC(enable, "ALSA enable AudioScience soundcard.");
+
+module_param(enable_hpi_hwdep, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(enable_hpi_hwdep,
+		"ALSA enable HPI hwdep for AudioScience soundcard ");
+
+/* identify driver */
+#ifdef KERNEL_ALSA_BUILD
+static char *build_info = "built using headers from kernel source";
+module_param(build_info, charp, S_IRUGO);
+MODULE_PARM_DESC(build_info, "built using headers from kernel source");
+#else
+static char *build_info = "built within ALSA source";
+module_param(build_info, charp, S_IRUGO);
+MODULE_PARM_DESC(build_info, "built within ALSA source");
+#endif
+
+/* set to 1 to dump every control from adapter to log */
+static const int mixer_dump;
+
+#define DEFAULT_SAMPLERATE 44100
+static int adapter_fs = DEFAULT_SAMPLERATE;
+
+static struct hpi_hsubsys *ss;	/* handle to HPI audio subsystem */
+
+/* defaults */
+#define PERIODS_MIN 2
+#define PERIOD_BYTES_MIN  2304
+#define BUFFER_BYTES_MAX (512 * 1024)
+
+/*#define TIMER_MILLISECONDS 20
+#define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000)
+*/
+
+#define MAX_CLOCKSOURCES (HPI_SAMPLECLOCK_SOURCE_LAST + 1 + 7)
+
+struct clk_source {
+	int source;
+	int index;
+	char *name;
+};
+
+struct clk_cache {
+	int count;
+	int has_local;
+	struct clk_source s[MAX_CLOCKSOURCES];
+};
+
+/* Per card data */
+struct snd_card_asihpi {
+	struct snd_card *card;
+	struct pci_dev *pci;
+	u16 adapter_index;
+	u32 serial_number;
+	u16 type;
+	u16 version;
+	u16 num_outstreams;
+	u16 num_instreams;
+
+	u32 h_mixer;
+	struct clk_cache cc;
+
+	u16 support_mmap;
+	u16 support_grouping;
+	u16 support_mrx;
+	u16 update_interval_frames;
+	u16 in_max_chans;
+	u16 out_max_chans;
+};
+
+/* Per stream data */
+struct snd_card_asihpi_pcm {
+	struct timer_list timer;
+	unsigned int respawn_timer;
+	unsigned int hpi_buffer_attached;
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int bytes_per_sec;
+	unsigned int pcm_irq_pos;	/* IRQ position */
+	unsigned int pcm_buf_pos;	/* position in buffer */
+	struct snd_pcm_substream *substream;
+	u32 h_stream;
+	struct hpi_format format;
+};
+
+/* universal stream verbs work with out or in stream handles */
+
+/* Functions to allow driver to give a buffer to HPI for busmastering */
+
+static u16 hpi_stream_host_buffer_attach(
+	struct hpi_hsubsys *hS,
+	u32 h_stream,   /* handle to outstream. */
+	u32 size_in_bytes, /* size in bytes of bus mastering buffer */
+	u32 pci_address
+)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	unsigned int obj = hpi_handle_object(h_stream);
+
+	if (!h_stream)
+		return HPI_ERROR_INVALID_OBJ;
+	hpi_init_message_response(&hm, &hr, obj,
+			obj == HPI_OBJ_OSTREAM ?
+				HPI_OSTREAM_HOSTBUFFER_ALLOC :
+				HPI_ISTREAM_HOSTBUFFER_ALLOC);
+
+	hpi_handle_to_indexes(h_stream, &hm.adapter_index,
+				&hm.obj_index);
+
+	hm.u.d.u.buffer.buffer_size = size_in_bytes;
+	hm.u.d.u.buffer.pci_address = pci_address;
+	hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+static u16 hpi_stream_host_buffer_detach(
+	struct hpi_hsubsys *hS,
+	u32  h_stream
+)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	unsigned int obj = hpi_handle_object(h_stream);
+
+	if (!h_stream)
+		return HPI_ERROR_INVALID_OBJ;
+
+	hpi_init_message_response(&hm, &hr,  obj,
+			obj == HPI_OBJ_OSTREAM ?
+				HPI_OSTREAM_HOSTBUFFER_FREE :
+				HPI_ISTREAM_HOSTBUFFER_FREE);
+
+	hpi_handle_to_indexes(h_stream, &hm.adapter_index,
+				&hm.obj_index);
+	hm.u.d.u.buffer.command = HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+static inline u16 hpi_stream_start(struct hpi_hsubsys *hS, u32 h_stream)
+{
+	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
+		return hpi_outstream_start(hS, h_stream);
+	else
+		return hpi_instream_start(hS, h_stream);
+}
+
+static inline u16 hpi_stream_stop(struct hpi_hsubsys *hS, u32 h_stream)
+{
+	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
+		return hpi_outstream_stop(hS, h_stream);
+	else
+		return hpi_instream_stop(hS, h_stream);
+}
+
+static inline u16 hpi_stream_get_info_ex(
+    struct hpi_hsubsys *hS,
+    u32 h_stream,
+    u16        *pw_state,
+    u32        *pbuffer_size,
+    u32        *pdata_in_buffer,
+    u32        *psample_count,
+    u32        *pauxiliary_data
+)
+{
+	if (hpi_handle_object(h_stream)  ==  HPI_OBJ_OSTREAM)
+		return hpi_outstream_get_info_ex(hS, h_stream, pw_state,
+					pbuffer_size, pdata_in_buffer,
+					psample_count, pauxiliary_data);
+	else
+		return hpi_instream_get_info_ex(hS, h_stream, pw_state,
+					pbuffer_size, pdata_in_buffer,
+					psample_count, pauxiliary_data);
+}
+
+static inline u16 hpi_stream_group_add(struct hpi_hsubsys *hS,
+					u32 h_master,
+					u32 h_stream)
+{
+	if (hpi_handle_object(h_master) ==  HPI_OBJ_OSTREAM)
+		return hpi_outstream_group_add(hS, h_master, h_stream);
+	else
+		return hpi_instream_group_add(hS, h_master, h_stream);
+}
+
+static inline u16 hpi_stream_group_reset(struct hpi_hsubsys *hS,
+						u32 h_stream)
+{
+	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
+		return hpi_outstream_group_reset(hS, h_stream);
+	else
+		return hpi_instream_group_reset(hS, h_stream);
+}
+
+static inline u16 hpi_stream_group_get_map(struct hpi_hsubsys *hS,
+				u32 h_stream, u32 *mo, u32 *mi)
+{
+	if (hpi_handle_object(h_stream) ==  HPI_OBJ_OSTREAM)
+		return hpi_outstream_group_get_map(hS, h_stream, mo, mi);
+	else
+		return hpi_instream_group_get_map(hS, h_stream, mo, mi);
+}
+
+static u16 handle_error(u16 err, int line, char *filename)
+{
+	if (err)
+		printk(KERN_WARNING
+			"in file %s, line %d: HPI error %d\n",
+			filename, line, err);
+	return err;
+}
+
+#define hpi_handle_error(x)  handle_error(x, __LINE__, __FILE__)
+
+/***************************** GENERAL PCM ****************/
+#if REALLY_VERBOSE_LOGGING
+static void print_hwparams(struct snd_pcm_hw_params *p)
+{
+	snd_printd("HWPARAMS \n");
+	snd_printd("samplerate %d \n", params_rate(p));
+	snd_printd("channels %d \n", params_channels(p));
+	snd_printd("format %d \n", params_format(p));
+	snd_printd("subformat %d \n", params_subformat(p));
+	snd_printd("buffer bytes %d \n", params_buffer_bytes(p));
+	snd_printd("period bytes %d \n", params_period_bytes(p));
+	snd_printd("access %d \n", params_access(p));
+	snd_printd("period_size %d \n", params_period_size(p));
+	snd_printd("periods %d \n", params_periods(p));
+	snd_printd("buffer_size %d \n", params_buffer_size(p));
+}
+#else
+#define print_hwparams(x)
+#endif
+
+static snd_pcm_format_t hpi_to_alsa_formats[] = {
+	-1,			/* INVALID */
+	SNDRV_PCM_FORMAT_U8,	/* HPI_FORMAT_PCM8_UNSIGNED        1 */
+	SNDRV_PCM_FORMAT_S16,	/* HPI_FORMAT_PCM16_SIGNED         2 */
+	-1,			/* HPI_FORMAT_MPEG_L1              3 */
+	SNDRV_PCM_FORMAT_MPEG,	/* HPI_FORMAT_MPEG_L2              4 */
+	SNDRV_PCM_FORMAT_MPEG,	/* HPI_FORMAT_MPEG_L3              5 */
+	-1,			/* HPI_FORMAT_DOLBY_AC2            6 */
+	-1,			/* HPI_FORMAT_DOLBY_AC3            7 */
+	SNDRV_PCM_FORMAT_S16_BE,/* HPI_FORMAT_PCM16_BIGENDIAN      8 */
+	-1,			/* HPI_FORMAT_AA_TAGIT1_HITS       9 */
+	-1,			/* HPI_FORMAT_AA_TAGIT1_INSERTS   10 */
+	SNDRV_PCM_FORMAT_S32,	/* HPI_FORMAT_PCM32_SIGNED        11 */
+	-1,			/* HPI_FORMAT_RAW_BITSTREAM       12 */
+	-1,			/* HPI_FORMAT_AA_TAGIT1_HITS_EX1  13 */
+	SNDRV_PCM_FORMAT_FLOAT,	/* HPI_FORMAT_PCM32_FLOAT         14 */
+#if 1
+	/* ALSA can't handle 3 byte sample size together with power-of-2
+	 *  constraint on buffer_bytes, so disable this format
+	 */
+	-1
+#else
+	/* SNDRV_PCM_FORMAT_S24_3LE */	/* { HPI_FORMAT_PCM24_SIGNED        15 */
+#endif
+};
+
+
+static int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format,
+					   u16 *hpi_format)
+{
+	u16 format;
+
+	for (format = HPI_FORMAT_PCM8_UNSIGNED;
+	     format <= HPI_FORMAT_PCM24_SIGNED; format++) {
+		if (hpi_to_alsa_formats[format] == alsa_format) {
+			*hpi_format = format;
+			return 0;
+		}
+	}
+
+	snd_printd(KERN_WARNING "failed match for alsa format %d\n",
+		   alsa_format);
+	*hpi_format = 0;
+	return -EINVAL;
+}
+
+static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi,
+					 struct snd_pcm_hardware *pcmhw)
+{
+	u16 err;
+	u32 h_control;
+	u32 sample_rate;
+	int idx;
+	unsigned int rate_min = 200000;
+	unsigned int rate_max = 0;
+	unsigned int rates = 0;
+
+	if (asihpi->support_mrx) {
+		rates |= SNDRV_PCM_RATE_CONTINUOUS;
+		rates |= SNDRV_PCM_RATE_8000_96000;
+		rate_min = 8000;
+		rate_max = 100000;
+	} else {
+		/* on cards without SRC,
+		   valid rates are determined by sampleclock */
+		err = hpi_mixer_get_control(ss, asihpi->h_mixer,
+					  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
+					  HPI_CONTROL_SAMPLECLOCK, &h_control);
+		if (err) {
+			snd_printk(KERN_ERR
+				"no local sampleclock, err %d\n", err);
+		}
+
+		for (idx = 0; idx < 100; idx++) {
+			if (hpi_sample_clock_query_local_rate(ss,
+				h_control, idx, &sample_rate)) {
+				if (!idx)
+					snd_printk(KERN_ERR
+						"local rate query failed\n");
+
+				break;
+			}
+
+			rate_min = min(rate_min, sample_rate);
+			rate_max = max(rate_max, sample_rate);
+
+			switch (sample_rate) {
+			case 5512:
+				rates |= SNDRV_PCM_RATE_5512;
+				break;
+			case 8000:
+				rates |= SNDRV_PCM_RATE_8000;
+				break;
+			case 11025:
+				rates |= SNDRV_PCM_RATE_11025;
+				break;
+			case 16000:
+				rates |= SNDRV_PCM_RATE_16000;
+				break;
+			case 22050:
+				rates |= SNDRV_PCM_RATE_22050;
+				break;
+			case 32000:
+				rates |= SNDRV_PCM_RATE_32000;
+				break;
+			case 44100:
+				rates |= SNDRV_PCM_RATE_44100;
+				break;
+			case 48000:
+				rates |= SNDRV_PCM_RATE_48000;
+				break;
+			case 64000:
+				rates |= SNDRV_PCM_RATE_64000;
+				break;
+			case 88200:
+				rates |= SNDRV_PCM_RATE_88200;
+				break;
+			case 96000:
+				rates |= SNDRV_PCM_RATE_96000;
+				break;
+			case 176400:
+				rates |= SNDRV_PCM_RATE_176400;
+				break;
+			case 192000:
+				rates |= SNDRV_PCM_RATE_192000;
+				break;
+			default: /* some other rate */
+				rates |= SNDRV_PCM_RATE_KNOT;
+			}
+		}
+	}
+
+	/* printk(KERN_INFO "Supported rates %X %d %d\n",
+	   rates, rate_min, rate_max); */
+	pcmhw->rates = rates;
+	pcmhw->rate_min = rate_min;
+	pcmhw->rate_max = rate_max;
+}
+
+static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
+					 struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
+	int err;
+	u16 format;
+	unsigned int bytes_per_sec;
+
+	print_hwparams(params);
+	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+	if (err < 0)
+		return err;
+	err = snd_card_asihpi_format_alsa2hpi(params_format(params), &format);
+	if (err)
+		return err;
+
+	VPRINTK1(KERN_INFO "format %d, %d chans, %d_hz\n",
+				format, params_channels(params),
+				params_rate(params));
+
+	hpi_handle_error(hpi_format_create(&dpcm->format,
+			params_channels(params),
+			format, params_rate(params), 0, 0));
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (hpi_instream_reset(ss, dpcm->h_stream) != 0)
+			return -EINVAL;
+
+		if (hpi_instream_set_format(ss,
+			dpcm->h_stream, &dpcm->format) != 0)
+			return -EINVAL;
+	}
+
+	dpcm->hpi_buffer_attached = 0;
+	if (card->support_mmap) {
+
+		err = hpi_stream_host_buffer_attach(ss, dpcm->h_stream,
+			params_buffer_bytes(params),  runtime->dma_addr);
+		if (err == 0) {
+			snd_printd(KERN_INFO
+				"stream_host_buffer_attach succeeded %u %lu\n",
+				params_buffer_bytes(params),
+				(unsigned long)runtime->dma_addr);
+		} else {
+			snd_printd(KERN_INFO
+					"stream_host_buffer_attach error %d\n",
+					err);
+			return -ENOMEM;
+		}
+
+		err = hpi_stream_get_info_ex(ss, dpcm->h_stream, NULL,
+						&dpcm->hpi_buffer_attached,
+						NULL, NULL, NULL);
+
+		snd_printd(KERN_INFO "stream_host_buffer_attach status 0x%x\n",
+				dpcm->hpi_buffer_attached);
+	}
+	bytes_per_sec = params_rate(params) * params_channels(params);
+	bytes_per_sec *= snd_pcm_format_width(params_format(params));
+	bytes_per_sec /= 8;
+	if (bytes_per_sec <= 0)
+		return -EINVAL;
+
+	dpcm->bytes_per_sec = bytes_per_sec;
+	dpcm->pcm_size = params_buffer_bytes(params);
+	dpcm->pcm_count = params_period_bytes(params);
+	snd_printd(KERN_INFO "pcm_size=%d, pcm_count=%d, bps=%d\n",
+			dpcm->pcm_size, dpcm->pcm_count, bytes_per_sec);
+
+	dpcm->pcm_irq_pos = 0;
+	dpcm->pcm_buf_pos = 0;
+	return 0;
+}
+
+static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
+					    substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+	int expiry;
+
+	expiry = (dpcm->pcm_count * HZ / dpcm->bytes_per_sec);
+	/* wait longer the first time, for samples to propagate */
+	expiry = max(expiry, 20);
+	dpcm->timer.expires = jiffies + expiry;
+	dpcm->respawn_timer = 1;
+	add_timer(&dpcm->timer);
+}
+
+static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+
+	dpcm->respawn_timer = 0;
+	del_timer(&dpcm->timer);
+}
+
+static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
+					   int cmd)
+{
+	struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
+	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
+	struct snd_pcm_substream *s;
+	u16 e;
+
+	snd_printd("trigger %dstream %d\n",
+			substream->stream, substream->number);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		snd_pcm_group_for_each_entry(s, substream) {
+			struct snd_card_asihpi_pcm *ds;
+			ds = s->runtime->private_data;
+
+			if (snd_pcm_substream_chip(s) != card)
+				continue;
+
+			if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
+				(card->support_mmap)) {
+				/* How do I know how much valid data is present
+				* in buffer? Just guessing 2 periods, but if
+				* buffer is bigger it may contain even more
+				* data??
+				*/
+				unsigned int preload = ds->pcm_count * 2;
+				VPRINTK2("preload %d\n", preload);
+				hpi_handle_error(hpi_outstream_write_buf(
+						ss, ds->h_stream,
+						&s->runtime->dma_area[0],
+						preload,
+						&ds->format));
+			}
+
+			if (card->support_grouping) {
+				VPRINTK1("\t_group %dstream %d\n", s->stream,
+						s->number);
+				e = hpi_stream_group_add(ss,
+					dpcm->h_stream,
+					ds->h_stream);
+				if (!e) {
+					snd_pcm_trigger_done(s, substream);
+				} else {
+					hpi_handle_error(e);
+					break;
+				}
+			} else
+				break;
+		}
+		snd_printd("start\n");
+		/* start the master stream */
+		snd_card_asihpi_pcm_timer_start(substream);
+		hpi_handle_error(hpi_stream_start(ss, dpcm->h_stream));
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		snd_card_asihpi_pcm_timer_stop(substream);
+		snd_pcm_group_for_each_entry(s, substream) {
+			if (snd_pcm_substream_chip(s) != card)
+				continue;
+
+			/*? workaround linked streams don't
+			transition to SETUP 20070706*/
+			s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
+
+			if (card->support_grouping) {
+				VPRINTK1("\t_group %dstream %d\n", s->stream,
+					s->number);
+				snd_pcm_trigger_done(s, substream);
+			} else
+				break;
+		}
+		snd_printd("stop\n");
+
+		/* _prepare and _hwparams reset the stream */
+		hpi_handle_error(hpi_stream_stop(ss, dpcm->h_stream));
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			hpi_handle_error(
+				hpi_outstream_reset(ss, dpcm->h_stream));
+
+		if (card->support_grouping)
+			hpi_handle_error(hpi_stream_group_reset(ss,
+						dpcm->h_stream));
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		snd_printd("pause release\n");
+		hpi_handle_error(hpi_stream_start(ss, dpcm->h_stream));
+		snd_card_asihpi_pcm_timer_start(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		snd_printd("pause\n");
+		snd_card_asihpi_pcm_timer_stop(substream);
+		hpi_handle_error(hpi_stream_stop(ss, dpcm->h_stream));
+		break;
+	default:
+		snd_printd("\tINVALID\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+snd_card_asihpi_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+	if (dpcm->hpi_buffer_attached)
+		hpi_stream_host_buffer_detach(ss, dpcm->h_stream);
+
+	snd_pcm_lib_free_pages(substream);
+	return 0;
+}
+
+static void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime)
+{
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+	kfree(dpcm);
+}
+
+/*algorithm outline
+ Without linking degenerates to getting single stream pos etc
+ Without mmap 2nd loop degenerates to snd_pcm_period_elapsed
+*/
+/*
+buf_pos=get_buf_pos(s);
+for_each_linked_stream(s) {
+	buf_pos=get_buf_pos(s);
+	min_buf_pos = modulo_min(min_buf_pos, buf_pos, pcm_size)
+	new_data = min(new_data, calc_new_data(buf_pos,irq_pos)
+}
+timer.expires = jiffies + predict_next_period_ready(min_buf_pos);
+for_each_linked_stream(s) {
+	s->buf_pos = min_buf_pos;
+	if (new_data > pcm_count) {
+		if (mmap) {
+			irq_pos = (irq_pos + pcm_count) % pcm_size;
+			if (playback) {
+				write(pcm_count);
+			} else {
+				read(pcm_count);
+			}
+		}
+		snd_pcm_period_elapsed(s);
+	}
+}
+*/
+
+/** Minimum of 2 modulo values.  Works correctly when the difference between
+* the values is less than half the modulus
+*/
+static inline unsigned int modulo_min(unsigned int a, unsigned int b,
+					unsigned long int modulus)
+{
+	unsigned int result;
+	if (((a-b) % modulus) < (modulus/2))
+		result = b;
+	else
+		result = a;
+
+	return result;
+}
+
+/** Timer function, equivalent to interrupt service routine for cards
+*/
+static void snd_card_asihpi_timer_function(unsigned long data)
+{
+	struct snd_card_asihpi_pcm *dpcm = (struct snd_card_asihpi_pcm *)data;
+	struct snd_card_asihpi *card = snd_pcm_substream_chip(dpcm->substream);
+	struct snd_pcm_runtime *runtime;
+	struct snd_pcm_substream *s;
+	unsigned int newdata = 0;
+	unsigned int buf_pos, min_buf_pos = 0;
+	unsigned int remdata, xfercount, next_jiffies;
+	int first = 1;
+	u16 state;
+	u32 buffer_size, data_avail, samples_played, aux;
+
+	/* find minimum newdata and buffer pos in group */
+	snd_pcm_group_for_each_entry(s, dpcm->substream) {
+		struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
+		runtime = s->runtime;
+
+		if (snd_pcm_substream_chip(s) != card)
+			continue;
+
+		hpi_handle_error(hpi_stream_get_info_ex(ss,
+					ds->h_stream, &state,
+					&buffer_size, &data_avail,
+					&samples_played, &aux));
+
+		/* number of bytes in on-card buffer */
+		runtime->delay = aux;
+
+		if (state == HPI_STATE_DRAINED) {
+			snd_printd(KERN_WARNING  "outstream %d drained\n",
+					s->number);
+			snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
+			return;
+		}
+
+		if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			buf_pos = frames_to_bytes(runtime, samples_played);
+		} else {
+			buf_pos = data_avail + ds->pcm_irq_pos;
+		}
+
+		if (first) {
+			/* can't statically init min when wrap is involved */
+			min_buf_pos = buf_pos;
+			newdata = (buf_pos - ds->pcm_irq_pos) % ds->pcm_size;
+			first = 0;
+		} else {
+			min_buf_pos =
+				modulo_min(min_buf_pos, buf_pos, UINT_MAX+1L);
+			newdata = min(
+				(buf_pos - ds->pcm_irq_pos) % ds->pcm_size,
+				newdata);
+		}
+
+		VPRINTK1("PB timer hw_ptr x%04lX, appl_ptr x%04lX\n",
+			(unsigned long)frames_to_bytes(runtime,
+						runtime->status->hw_ptr),
+			(unsigned long)frames_to_bytes(runtime,
+						runtime->control->appl_ptr));
+		VPRINTK1("%d S=%d, irq=%04X, pos=x%04X, left=x%04X,"
+			" aux=x%04X space=x%04X\n", s->number,
+			state,	ds->pcm_irq_pos, buf_pos, (int)data_avail,
+			(int)aux, buffer_size-data_avail);
+	}
+
+	remdata = newdata % dpcm->pcm_count;
+	xfercount = newdata - remdata; /* a multiple of pcm_count */
+	next_jiffies = ((dpcm->pcm_count-remdata) * HZ / dpcm->bytes_per_sec)+1;
+	next_jiffies = max(next_jiffies, 2U * HZ / 1000U);
+	dpcm->timer.expires = jiffies + next_jiffies;
+	VPRINTK1("jif %d buf pos x%04X newdata x%04X xc x%04X\n",
+			next_jiffies, min_buf_pos, newdata, xfercount);
+
+	snd_pcm_group_for_each_entry(s, dpcm->substream) {
+		struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
+		ds->pcm_buf_pos = min_buf_pos;
+
+		if (xfercount) {
+			if (card->support_mmap) {
+				ds->pcm_irq_pos = ds->pcm_irq_pos + xfercount;
+				if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+					VPRINTK2("write OS%d x%04x\n",
+							s->number,
+							ds->pcm_count);
+					hpi_handle_error(
+						hpi_outstream_write_buf(
+							ss, ds->h_stream,
+							&s->runtime->
+								dma_area[0],
+							xfercount,
+							&ds->format));
+				} else {
+					VPRINTK2("read IS%d x%04x\n",
+						s->number,
+						dpcm->pcm_count);
+					hpi_handle_error(
+						hpi_instream_read_buf(
+							ss, ds->h_stream,
+							NULL, xfercount));
+				}
+			} /* else R/W will be handled by read/write callbacks */
+			snd_pcm_period_elapsed(s);
+		}
+	}
+
+	if (dpcm->respawn_timer)
+		add_timer(&dpcm->timer);
+}
+
+/***************************** PLAYBACK OPS ****************/
+static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
+					  unsigned int cmd, void *arg)
+{
+	/* snd_printd(KERN_INFO "Playback ioctl %d\n", cmd); */
+	return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
+					    substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+
+	snd_printd(KERN_INFO "playback prepare %d\n", substream->number);
+
+	hpi_handle_error(hpi_outstream_reset(ss, dpcm->h_stream));
+	dpcm->pcm_irq_pos = 0;
+	dpcm->pcm_buf_pos = 0;
+
+	return 0;
+}
+
+static snd_pcm_uframes_t
+snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+	snd_pcm_uframes_t ptr;
+
+	u32 samples_played;
+	u16 err;
+
+	if (!snd_pcm_stream_linked(substream)) {
+		/* NOTE, can use samples played for playback position here and
+		* in timer fn because it LAGS the actual read pointer, and is a
+		* better representation of actual playout position
+		*/
+		err = hpi_outstream_get_info_ex(ss, dpcm->h_stream, NULL,
+					NULL, NULL,
+					&samples_played, NULL);
+		hpi_handle_error(err);
+
+		dpcm->pcm_buf_pos = frames_to_bytes(runtime, samples_played);
+	}
+	/* else must return most conservative value found in timer func
+	 * by looping over all streams
+	 */
+
+	ptr = bytes_to_frames(runtime, dpcm->pcm_buf_pos  % dpcm->pcm_size);
+	VPRINTK2("playback_pointer=%04ld\n", (unsigned long)ptr);
+	return ptr;
+}
+
+static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi,
+						u32 h_stream,
+						struct snd_pcm_hardware *pcmhw)
+{
+	struct hpi_format hpi_format;
+	u16 format;
+	u16 err;
+	u32 h_control;
+	u32 sample_rate = 48000;
+
+	/* on cards without SRC, must query at valid rate,
+	* maybe set by external sync
+	*/
+	err = hpi_mixer_get_control(ss, asihpi->h_mixer,
+				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
+				  HPI_CONTROL_SAMPLECLOCK, &h_control);
+
+	if (!err)
+		err = hpi_sample_clock_get_sample_rate(ss, h_control,
+				&sample_rate);
+
+	for (format = HPI_FORMAT_PCM8_UNSIGNED;
+	     format <= HPI_FORMAT_PCM24_SIGNED; format++) {
+		err = hpi_format_create(&hpi_format,
+					2, format, sample_rate, 128000, 0);
+		if (!err)
+			err = hpi_outstream_query_format(ss, h_stream,
+							&hpi_format);
+		if (!err && (hpi_to_alsa_formats[format] != -1))
+			pcmhw->formats |=
+				(1ULL << hpi_to_alsa_formats[format]);
+	}
+}
+
+static struct snd_pcm_hardware snd_card_asihpi_playback = {
+	.channels_min = 1,
+	.channels_max = 2,
+	.buffer_bytes_max = BUFFER_BYTES_MAX,
+	.period_bytes_min = PERIOD_BYTES_MIN,
+	.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
+	.periods_min = PERIODS_MIN,
+	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
+	.fifo_size = 0,
+};
+
+static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm;
+	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
+	int err;
+
+	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
+	if (dpcm == NULL)
+		return -ENOMEM;
+
+	err =
+	    hpi_outstream_open(ss, card->adapter_index,
+			      substream->number, &dpcm->h_stream);
+	hpi_handle_error(err);
+	if (err)
+		kfree(dpcm);
+	if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
+		return -EBUSY;
+	if (err)
+		return -EIO;
+
+	/*? also check ASI5000 samplerate source
+	    If external, only support external rate.
+	    If internal and other stream playing, cant switch
+	*/
+
+	init_timer(&dpcm->timer);
+	dpcm->timer.data = (unsigned long) dpcm;
+	dpcm->timer.function = snd_card_asihpi_timer_function;
+	dpcm->substream = substream;
+	runtime->private_data = dpcm;
+	runtime->private_free = snd_card_asihpi_runtime_free;
+
+	snd_card_asihpi_playback.channels_max = card->out_max_chans;
+	/*?snd_card_asihpi_playback.period_bytes_min =
+	card->out_max_chans * 4096; */
+
+	snd_card_asihpi_playback_format(card, dpcm->h_stream,
+					&snd_card_asihpi_playback);
+
+	snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_playback);
+
+	snd_card_asihpi_playback.info = SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_DOUBLE |
+					SNDRV_PCM_INFO_BATCH |
+					SNDRV_PCM_INFO_BLOCK_TRANSFER |
+					SNDRV_PCM_INFO_PAUSE;
+
+	if (card->support_mmap)
+		snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_MMAP |
+						SNDRV_PCM_INFO_MMAP_VALID;
+
+	if (card->support_grouping)
+		snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
+
+	/* struct is copied, so can create initializer dynamically */
+	runtime->hw = snd_card_asihpi_playback;
+
+	if (card->support_mmap)
+		err = snd_pcm_hw_constraint_pow2(runtime, 0,
+					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
+	if (err < 0)
+		return err;
+
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+		card->update_interval_frames);
+	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+		card->update_interval_frames * 4, UINT_MAX);
+
+	snd_pcm_set_sync(substream);
+
+	snd_printd(KERN_INFO "playback open\n");
+
+	return 0;
+}
+
+static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+
+	hpi_handle_error(hpi_outstream_close(ss, dpcm->h_stream));
+	snd_printd(KERN_INFO "playback close\n");
+
+	return 0;
+}
+
+static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream,
+					int channel,
+					snd_pcm_uframes_t pos,
+					void __user *src,
+					snd_pcm_uframes_t count)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+	unsigned int len;
+
+	len = frames_to_bytes(runtime, count);
+
+	if (copy_from_user(runtime->dma_area, src, len))
+		return -EFAULT;
+
+	VPRINTK2(KERN_DEBUG "playback copy%d %u bytes\n",
+			substream->number, len);
+
+	hpi_handle_error(hpi_outstream_write_buf(ss, dpcm->h_stream,
+				runtime->dma_area, len, &dpcm->format));
+
+	return 0;
+}
+
+static int snd_card_asihpi_playback_silence(struct snd_pcm_substream *
+					    substream, int channel,
+					    snd_pcm_uframes_t pos,
+					    snd_pcm_uframes_t count)
+{
+	unsigned int len;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+
+	len = frames_to_bytes(runtime, count);
+	snd_printd(KERN_INFO "playback silence  %u bytes\n", len);
+
+	memset(runtime->dma_area, 0, len);
+	hpi_handle_error(hpi_outstream_write_buf(ss, dpcm->h_stream,
+				runtime->dma_area, len, &dpcm->format));
+	return 0;
+}
+
+static struct snd_pcm_ops snd_card_asihpi_playback_ops = {
+	.open = snd_card_asihpi_playback_open,
+	.close = snd_card_asihpi_playback_close,
+	.ioctl = snd_card_asihpi_playback_ioctl,
+	.hw_params = snd_card_asihpi_pcm_hw_params,
+	.hw_free = snd_card_asihpi_hw_free,
+	.prepare = snd_card_asihpi_playback_prepare,
+	.trigger = snd_card_asihpi_trigger,
+	.pointer = snd_card_asihpi_playback_pointer,
+	.copy = snd_card_asihpi_playback_copy,
+	.silence = snd_card_asihpi_playback_silence,
+};
+
+static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
+	.open = snd_card_asihpi_playback_open,
+	.close = snd_card_asihpi_playback_close,
+	.ioctl = snd_card_asihpi_playback_ioctl,
+	.hw_params = snd_card_asihpi_pcm_hw_params,
+	.hw_free = snd_card_asihpi_hw_free,
+	.prepare = snd_card_asihpi_playback_prepare,
+	.trigger = snd_card_asihpi_trigger,
+	.pointer = snd_card_asihpi_playback_pointer,
+};
+
+/***************************** CAPTURE OPS ****************/
+static snd_pcm_uframes_t
+snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+
+	VPRINTK2("capture pointer %d=%d\n",
+			substream->number, dpcm->pcm_buf_pos);
+	/* NOTE Unlike playback can't use actual dwSamplesPlayed
+		for the capture position, because those samples aren't yet in
+		the local buffer available for reading.
+	*/
+	return bytes_to_frames(runtime, dpcm->pcm_buf_pos % dpcm->pcm_size);
+}
+
+static int snd_card_asihpi_capture_ioctl(struct snd_pcm_substream *substream,
+					 unsigned int cmd, void *arg)
+{
+	return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+
+	hpi_handle_error(hpi_instream_reset(ss, dpcm->h_stream));
+	dpcm->pcm_irq_pos = 0;
+	dpcm->pcm_buf_pos = 0;
+
+	snd_printd("capture prepare %d\n", substream->number);
+	return 0;
+}
+
+
+
+static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
+					u32 h_stream,
+					 struct snd_pcm_hardware *pcmhw)
+{
+  struct hpi_format hpi_format;
+	u16 format;
+	u16 err;
+	u32 h_control;
+	u32 sample_rate = 48000;
+
+	/* on cards without SRC, must query at valid rate,
+		maybe set by external sync */
+	err = hpi_mixer_get_control(ss, asihpi->h_mixer,
+				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
+				  HPI_CONTROL_SAMPLECLOCK, &h_control);
+
+	if (!err)
+		err = hpi_sample_clock_get_sample_rate(ss, h_control,
+			&sample_rate);
+
+	for (format = HPI_FORMAT_PCM8_UNSIGNED;
+		format <= HPI_FORMAT_PCM24_SIGNED; format++) {
+
+		err = hpi_format_create(&hpi_format, 2, format,
+				sample_rate, 128000, 0);
+		if (!err)
+			err = hpi_instream_query_format(ss, h_stream,
+					    &hpi_format);
+		if (!err)
+			pcmhw->formats |=
+				(1ULL << hpi_to_alsa_formats[format]);
+	}
+}
+
+
+static struct snd_pcm_hardware snd_card_asihpi_capture = {
+	.channels_min = 1,
+	.channels_max = 2,
+	.buffer_bytes_max = BUFFER_BYTES_MAX,
+	.period_bytes_min = PERIOD_BYTES_MIN,
+	.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
+	.periods_min = PERIODS_MIN,
+	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
+	.fifo_size = 0,
+};
+
+static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
+	struct snd_card_asihpi_pcm *dpcm;
+	int err;
+
+	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
+	if (dpcm == NULL)
+		return -ENOMEM;
+
+	snd_printd("hpi_instream_open adapter %d stream %d\n",
+		   card->adapter_index, substream->number);
+
+	err = hpi_handle_error(
+	    hpi_instream_open(ss, card->adapter_index,
+			     substream->number, &dpcm->h_stream));
+	if (err)
+		kfree(dpcm);
+	if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
+		return -EBUSY;
+	if (err)
+		return -EIO;
+
+
+	init_timer(&dpcm->timer);
+	dpcm->timer.data = (unsigned long) dpcm;
+	dpcm->timer.function = snd_card_asihpi_timer_function;
+	dpcm->substream = substream;
+	runtime->private_data = dpcm;
+	runtime->private_free = snd_card_asihpi_runtime_free;
+
+	snd_card_asihpi_capture.channels_max = card->in_max_chans;
+	snd_card_asihpi_capture_format(card, dpcm->h_stream,
+				       &snd_card_asihpi_capture);
+	snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_capture);
+	snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED;
+
+	if (card->support_mmap)
+		snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP |
+						SNDRV_PCM_INFO_MMAP_VALID;
+
+	runtime->hw = snd_card_asihpi_capture;
+
+	if (card->support_mmap)
+		err = snd_pcm_hw_constraint_pow2(runtime, 0,
+					SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
+	if (err < 0)
+		return err;
+
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+		card->update_interval_frames);
+	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+		card->update_interval_frames * 2, UINT_MAX);
+
+	snd_pcm_set_sync(substream);
+
+	return 0;
+}
+
+static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
+
+	hpi_handle_error(hpi_instream_close(ss, dpcm->h_stream));
+	return 0;
+}
+
+static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream,
+				int channel, snd_pcm_uframes_t pos,
+				void __user *dst, snd_pcm_uframes_t count)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+	u32 data_size;
+
+	data_size = frames_to_bytes(runtime, count);
+
+	VPRINTK2("capture copy%d %d bytes\n", substream->number, data_size);
+	hpi_handle_error(hpi_instream_read_buf(ss, dpcm->h_stream,
+				runtime->dma_area, data_size));
+
+	/* Used by capture_pointer */
+	dpcm->pcm_irq_pos = dpcm->pcm_irq_pos + data_size;
+
+	if (copy_to_user(dst, runtime->dma_area, data_size))
+		return -EFAULT;
+
+	return 0;
+}
+
+static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
+	.open = snd_card_asihpi_capture_open,
+	.close = snd_card_asihpi_capture_close,
+	.ioctl = snd_card_asihpi_capture_ioctl,
+	.hw_params = snd_card_asihpi_pcm_hw_params,
+	.hw_free = snd_card_asihpi_hw_free,
+	.prepare = snd_card_asihpi_capture_prepare,
+	.trigger = snd_card_asihpi_trigger,
+	.pointer = snd_card_asihpi_capture_pointer,
+};
+
+static struct snd_pcm_ops snd_card_asihpi_capture_ops = {
+	.open = snd_card_asihpi_capture_open,
+	.close = snd_card_asihpi_capture_close,
+	.ioctl = snd_card_asihpi_capture_ioctl,
+	.hw_params = snd_card_asihpi_pcm_hw_params,
+	.hw_free = snd_card_asihpi_hw_free,
+	.prepare = snd_card_asihpi_capture_prepare,
+	.trigger = snd_card_asihpi_trigger,
+	.pointer = snd_card_asihpi_capture_pointer,
+	.copy = snd_card_asihpi_capture_copy
+};
+
+static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
+				      int device, int substreams)
+{
+	struct snd_pcm *pcm;
+	int err;
+
+	err = snd_pcm_new(asihpi->card, "asihpi PCM", device,
+			 asihpi->num_outstreams, asihpi->num_instreams,
+			 &pcm);
+	if (err < 0)
+		return err;
+	/* pointer to ops struct is stored, dont change ops afterwards! */
+	if (asihpi->support_mmap) {
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				&snd_card_asihpi_playback_mmap_ops);
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+				&snd_card_asihpi_capture_mmap_ops);
+	} else {
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				&snd_card_asihpi_playback_ops);
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+				&snd_card_asihpi_capture_ops);
+	}
+
+	pcm->private_data = asihpi;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "asihpi PCM");
+
+	/*? do we want to emulate MMAP for non-BBM cards?
+	Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+						snd_dma_pci_data(asihpi->pci),
+						64*1024, BUFFER_BYTES_MAX);
+
+	return 0;
+}
+
+/***************************** MIXER CONTROLS ****************/
+struct hpi_control {
+	u32 h_control;
+	u16 control_type;
+	u16 src_node_type;
+	u16 src_node_index;
+	u16 dst_node_type;
+	u16 dst_node_index;
+	u16 band;
+	char name[44]; /* copied to snd_ctl_elem_id.name[44]; */
+};
+
+static char *asihpi_tuner_band_names[] =
+{
+	"invalid",
+	"AM",
+	"FM mono",
+	"TV NTSC-M",
+	"FM stereo",
+	"AUX",
+	"TV PAL BG",
+	"TV PAL I",
+	"TV PAL DK",
+	"TV SECAM",
+};
+
+compile_time_assert(
+	(ARRAY_SIZE(asihpi_tuner_band_names) ==
+		(HPI_TUNER_BAND_LAST+1)),
+	assert_tuner_band_names_size);
+
+#if ASI_STYLE_NAMES
+static char *asihpi_src_names[] =
+{
+	"no source",
+	"outstream",
+	"line_in",
+	"aes_in",
+	"tuner",
+	"RF",
+	"clock",
+	"bitstr",
+	"mic",
+	"cobranet",
+	"analog_in",
+	"adapter",
+};
+#else
+static char *asihpi_src_names[] =
+{
+	"no source",
+	"PCM playback",
+	"line in",
+	"digital in",
+	"tuner",
+	"RF",
+	"clock",
+	"bitstream",
+	"mic",
+	"cobranet in",
+	"analog in",
+	"adapter",
+};
+#endif
+
+compile_time_assert(
+	(ARRAY_SIZE(asihpi_src_names) ==
+		(HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)),
+	assert_src_names_size);
+
+#if ASI_STYLE_NAMES
+static char *asihpi_dst_names[] =
+{
+	"no destination",
+	"instream",
+	"line_out",
+	"aes_out",
+	"RF",
+	"speaker" ,
+	"cobranet",
+	"analog_out",
+};
+#else
+static char *asihpi_dst_names[] =
+{
+	"no destination",
+	"PCM capture",
+	"line out",
+	"digital out",
+	"RF",
+	"speaker",
+	"cobranet out",
+	"analog out"
+};
+#endif
+
+compile_time_assert(
+	(ARRAY_SIZE(asihpi_dst_names) ==
+		(HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)),
+	assert_dst_names_size);
+
+static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
+				struct snd_card_asihpi *asihpi)
+{
+	int err;
+
+	err = snd_ctl_add(card, snd_ctl_new1(ctl, asihpi));
+	if (err < 0)
+		return err;
+	else if (mixer_dump)
+		snd_printk(KERN_INFO "added %s(%d)\n", ctl->name, ctl->index);
+
+	return 0;
+}
+
+/* Convert HPI control name and location into ALSA control name */
+static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
+				struct hpi_control *hpi_ctl,
+				char *name)
+{
+	memset(snd_control, 0, sizeof(*snd_control));
+	snd_control->name = hpi_ctl->name;
+	snd_control->private_value = hpi_ctl->h_control;
+	snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	snd_control->index = 0;
+
+	if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
+		sprintf(hpi_ctl->name, "%s%d to %s%d %s",
+			asihpi_src_names[hpi_ctl->src_node_type],
+			hpi_ctl->src_node_index,
+			asihpi_dst_names[hpi_ctl->dst_node_type],
+			hpi_ctl->dst_node_index,
+			name);
+	else if (hpi_ctl->dst_node_type) {
+		sprintf(hpi_ctl->name, "%s%d %s",
+		asihpi_dst_names[hpi_ctl->dst_node_type],
+		hpi_ctl->dst_node_index,
+		name);
+	} else {
+		sprintf(hpi_ctl->name, "%s%d %s",
+		asihpi_src_names[hpi_ctl->src_node_type],
+		hpi_ctl->src_node_index,
+		name);
+	}
+}
+
+/*------------------------------------------------------------
+   Volume controls
+ ------------------------------------------------------------*/
+#define VOL_STEP_mB 1
+static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	u32 h_control = kcontrol->private_value;
+	u16 err;
+	/* native gains are in millibels */
+	short min_gain_mB;
+	short max_gain_mB;
+	short step_gain_mB;
+
+	err = hpi_volume_query_range(ss, h_control,
+			&min_gain_mB, &max_gain_mB, &step_gain_mB);
+	if (err) {
+		max_gain_mB = 0;
+		min_gain_mB = -10000;
+		step_gain_mB = VOL_STEP_mB;
+	}
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB;
+	uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB;
+	uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB;
+	return 0;
+}
+
+static int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	u32 h_control = kcontrol->private_value;
+	short an_gain_mB[HPI_MAX_CHANNELS];
+
+	hpi_handle_error(hpi_volume_get_gain(ss, h_control, an_gain_mB));
+	ucontrol->value.integer.value[0] = an_gain_mB[0] / VOL_STEP_mB;
+	ucontrol->value.integer.value[1] = an_gain_mB[1] / VOL_STEP_mB;
+
+	return 0;
+}
+
+static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	int change;
+	u32 h_control = kcontrol->private_value;
+	short an_gain_mB[HPI_MAX_CHANNELS];
+
+	an_gain_mB[0] =
+	    (ucontrol->value.integer.value[0]) * VOL_STEP_mB;
+	an_gain_mB[1] =
+	    (ucontrol->value.integer.value[1]) * VOL_STEP_mB;
+	/*  change = asihpi->mixer_volume[addr][0] != left ||
+	   asihpi->mixer_volume[addr][1] != right;
+	 */
+	change = 1;
+	hpi_handle_error(hpi_volume_set_gain(ss, h_control, an_gain_mB));
+	return change;
+}
+
+static const DECLARE_TLV_DB_SCALE(db_scale_100, -10000, VOL_STEP_mB, 0);
+
+static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
+					struct hpi_control *hpi_ctl)
+{
+	struct snd_card *card = asihpi->card;
+	struct snd_kcontrol_new snd_control;
+
+	asihpi_ctl_init(&snd_control, hpi_ctl, "volume");
+	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+	snd_control.info = snd_asihpi_volume_info;
+	snd_control.get = snd_asihpi_volume_get;
+	snd_control.put = snd_asihpi_volume_put;
+	snd_control.tlv.p = db_scale_100;
+
+	return ctl_add(card, &snd_control, asihpi);
+}
+
+/*------------------------------------------------------------
+   Level controls
+ ------------------------------------------------------------*/
+static int snd_asihpi_level_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	u32 h_control = kcontrol->private_value;
+	u16 err;
+	short min_gain_mB;
+	short max_gain_mB;
+	short step_gain_mB;
+
+	err =
+	    hpi_level_query_range(ss, h_control, &min_gain_mB,
+			       &max_gain_mB, &step_gain_mB);
+	if (err) {
+		max_gain_mB = 2400;
+		min_gain_mB = -1000;
+		step_gain_mB = 100;
+	}
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = min_gain_mB / HPI_UNITS_PER_dB;
+	uinfo->value.integer.max = max_gain_mB / HPI_UNITS_PER_dB;
+	uinfo->value.integer.step = step_gain_mB / HPI_UNITS_PER_dB;
+	return 0;
+}
+
+static int snd_asihpi_level_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u32 h_control = kcontrol->private_value;
+	short an_gain_mB[HPI_MAX_CHANNELS];
+
+	hpi_handle_error(hpi_level_get_gain(ss, h_control, an_gain_mB));
+	ucontrol->value.integer.value[0] =
+	    an_gain_mB[0] / HPI_UNITS_PER_dB;
+	ucontrol->value.integer.value[1] =
+	    an_gain_mB[1] / HPI_UNITS_PER_dB;
+
+	return 0;
+}
+
+static int snd_asihpi_level_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int change;
+	u32 h_control = kcontrol->private_value;
+	short an_gain_mB[HPI_MAX_CHANNELS];
+
+	an_gain_mB[0] =
+	    (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
+	an_gain_mB[1] =
+	    (ucontrol->value.integer.value[1]) * HPI_UNITS_PER_dB;
+	/*  change = asihpi->mixer_level[addr][0] != left ||
+	   asihpi->mixer_level[addr][1] != right;
+	 */
+	change = 1;
+	hpi_handle_error(hpi_level_set_gain(ss, h_control, an_gain_mB));
+	return change;
+}
+
+static const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0);
+
+static int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi,
+					struct hpi_control *hpi_ctl)
+{
+	struct snd_card *card = asihpi->card;
+	struct snd_kcontrol_new snd_control;
+
+	/* can't use 'volume' cos some nodes have volume as well */
+	asihpi_ctl_init(&snd_control, hpi_ctl, "level");
+	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+				SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+	snd_control.info = snd_asihpi_level_info;
+	snd_control.get = snd_asihpi_level_get;
+	snd_control.put = snd_asihpi_level_put;
+	snd_control.tlv.p = db_scale_level;
+
+	return ctl_add(card, &snd_control, asihpi);
+}
+
+/*------------------------------------------------------------
+   AESEBU controls
+ ------------------------------------------------------------*/
+
+/* AESEBU format */
+static char *asihpi_aesebu_format_names[] =
+{
+	"N/A",
+	"S/PDIF",
+	"AES/EBU",
+};
+
+static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item =
+			uinfo->value.enumerated.items - 1;
+
+	strcpy(uinfo->value.enumerated.name,
+		asihpi_aesebu_format_names[uinfo->value.enumerated.item]);
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol,
+			u16 (*func)(const struct hpi_hsubsys *, u32, u16 *))
+{
+	u32 h_control = kcontrol->private_value;
+	u16 source, err;
+
+	err = func(ss, h_control, &source);
+
+	/* default to N/A */
+	ucontrol->value.enumerated.item[0] = 0;
+	/* return success but set the control to N/A */
+	if (err)
+		return 0;
+	if (source == HPI_AESEBU_FORMAT_SPDIF)
+		ucontrol->value.enumerated.item[0] = 1;
+	if (source == HPI_AESEBU_FORMAT_AESEBU)
+		ucontrol->value.enumerated.item[0] = 2;
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol,
+			 u16 (*func)(const struct hpi_hsubsys *, u32, u16))
+{
+	u32 h_control = kcontrol->private_value;
+
+	/* default to S/PDIF */
+	u16 source = HPI_AESEBU_FORMAT_SPDIF;
+
+	if (ucontrol->value.enumerated.item[0] == 1)
+		source = HPI_AESEBU_FORMAT_SPDIF;
+	if (ucontrol->value.enumerated.item[0] == 2)
+		source = HPI_AESEBU_FORMAT_AESEBU;
+
+	if (func(ss, h_control, source) != 0)
+		return -EINVAL;
+
+	return 1;
+}
+
+static int snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol) {
+	return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
+					HPI_AESEBU__receiver_get_format);
+}
+
+static int snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol) {
+	return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
+					HPI_AESEBU__receiver_set_format);
+}
+
+static int snd_asihpi_aesebu_rxstatus_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 = 0X1F;
+	uinfo->value.integer.step = 1;
+
+	return 0;
+}
+
+static int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol) {
+
+	u32 h_control = kcontrol->private_value;
+	u16 status;
+
+	hpi_handle_error(HPI_AESEBU__receiver_get_error_status(
+				ss, h_control, &status));
+	ucontrol->value.integer.value[0] = status;
+	return 0;
+}
+
+static int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,
+					struct hpi_control *hpi_ctl)
+{
+	struct snd_card *card = asihpi->card;
+	struct snd_kcontrol_new snd_control;
+
+	asihpi_ctl_init(&snd_control, hpi_ctl, "format");
+	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	snd_control.info = snd_asihpi_aesebu_format_info;
+	snd_control.get = snd_asihpi_aesebu_rx_format_get;
+	snd_control.put = snd_asihpi_aesebu_rx_format_put;
+
+
+	if (ctl_add(card, &snd_control, asihpi) < 0)
+		return -EINVAL;
+
+	asihpi_ctl_init(&snd_control, hpi_ctl, "status");
+	snd_control.access =
+	    SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
+	snd_control.info = snd_asihpi_aesebu_rxstatus_info;
+	snd_control.get = snd_asihpi_aesebu_rxstatus_get;
+
+	return ctl_add(card, &snd_control, asihpi);
+}
+
+static int snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol) {
+	return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
+					HPI_AESEBU__transmitter_get_format);
+}
+
+static int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol) {
+	return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
+					HPI_AESEBU__transmitter_set_format);
+}
+
+
+static int __devinit snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi,
+					struct hpi_control *hpi_ctl)
+{
+	struct snd_card *card = asihpi->card;
+	struct snd_kcontrol_new snd_control;
+
+	asihpi_ctl_init(&snd_control, hpi_ctl, "format");
+	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	snd_control.info = snd_asihpi_aesebu_format_info;
+	snd_control.get = snd_asihpi_aesebu_tx_format_get;
+	snd_control.put = snd_asihpi_aesebu_tx_format_put;
+
+	return ctl_add(card, &snd_control, asihpi);
+}
+
+/*------------------------------------------------------------
+   Tuner controls
+ ------------------------------------------------------------*/
+
+/* Gain */
+
+static int snd_asihpi_tuner_gain_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	u32 h_control = kcontrol->private_value;
+	u16 err;
+	short idx;
+	u16 gain_range[3];
+
+	for (idx = 0; idx < 3; idx++) {
+		err = hpi_tuner_query_gain(ss, h_control,
+					  idx, &gain_range[idx]);
+		if (err != 0)
+			return err;
+	}
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = ((int)gain_range[0]) / HPI_UNITS_PER_dB;
+	uinfo->value.integer.max = ((int)gain_range[1]) / HPI_UNITS_PER_dB;
+	uinfo->value.integer.step = ((int) gain_range[2]) / HPI_UNITS_PER_dB;
+	return 0;
+}
+
+static int snd_asihpi_tuner_gain_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	/*
+	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
+	*/
+	u32 h_control = kcontrol->private_value;
+	short gain;
+
+	hpi_handle_error(hpi_tuner_get_gain(ss, h_control, &gain));
+	ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_gain_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	/*
+	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
+	*/
+	u32 h_control = kcontrol->private_value;
+	short gain;
+
+	gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
+	hpi_handle_error(hpi_tuner_set_gain(ss, h_control, gain));
+
+	return 1;
+}
+
+/* Band  */
+
+static int asihpi_tuner_band_query(struct snd_kcontrol *kcontrol,
+					u16 *band_list, u32 len) {
+	u32 h_control = kcontrol->private_value;
+	u16 err = 0;
+	u32 i;
+
+	for (i = 0; i < len; i++) {
+		err = hpi_tuner_query_band(ss,
+				h_control, i, &band_list[i]);
+		if (err != 0)
+			break;
+	}
+
+	if (err && (err != HPI_ERROR_INVALID_OBJ_INDEX))
+		return -EIO;
+
+	return i;
+}
+
+static int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	u16 tuner_bands[HPI_TUNER_BAND_LAST];
+	int num_bands = 0;
+
+	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
+				HPI_TUNER_BAND_LAST);
+
+	if (num_bands < 0)
+		return num_bands;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = num_bands;
+
+	if (num_bands > 0) {
+		if (uinfo->value.enumerated.item >=
+					uinfo->value.enumerated.items)
+			uinfo->value.enumerated.item =
+				uinfo->value.enumerated.items - 1;
+
+		strcpy(uinfo->value.enumerated.name,
+			asihpi_tuner_band_names[
+				tuner_bands[uinfo->value.enumerated.item]]);
+
+	}
+	return 0;
+}
+
+static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	u32 h_control = kcontrol->private_value;
+	/*
+	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
+	*/
+	u16 band, idx;
+	u16 tuner_bands[HPI_TUNER_BAND_LAST];
+	u32 num_bands = 0;
+
+	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
+				HPI_TUNER_BAND_LAST);
+
+	hpi_handle_error(hpi_tuner_get_band(ss, h_control, &band));
+
+	ucontrol->value.enumerated.item[0] = -1;
+	for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)
+		if (tuner_bands[idx] == band) {
+			ucontrol->value.enumerated.item[0] = idx;
+			break;
+		}
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	/*
+	struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
+	*/
+	u32 h_control = kcontrol->private_value;
+	u16 band;
+	u16 tuner_bands[HPI_TUNER_BAND_LAST];
+	u32 num_bands = 0;
+
+	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
+			HPI_TUNER_BAND_LAST);
+
+	band = tuner_bands[ucontrol->value.enumerated.item[0]];
+	hpi_handle_error(hpi_tuner_set_band(ss, h_control, band));
+
+	return 1;
+}
+
+/* Freq */
+
+static int snd_asihpi_tuner_freq_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	u32 h_control = kcontrol->private_value;
+	u16 err;
+	u16 tuner_bands[HPI_TUNER_BAND_LAST];
+	u16 num_bands = 0, band_iter, idx;
+	u32 freq_range[3], temp_freq_range[3];
+
+	num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
+			HPI_TUNER_BAND_LAST);
+
+	freq_range[0] = INT_MAX;
+	freq_range[1] = 0;
+	freq_range[2] = INT_MAX;
+
+	for (band_iter = 0; band_iter < num_bands; band_iter++) {
+		for (idx = 0; idx < 3; idx++) {
+			err = hpi_tuner_query_frequency(ss, h_control,
+				idx, tuner_bands[band_iter],
+				&temp_freq_range[idx]);
+			if (err != 0)
+				return err;
+		}
+
+		/* skip band with bogus stepping */
+		if (temp_freq_range[2] <= 0)
+			continue;
+
+		if (temp_freq_range[0] < freq_range[0])
+			freq_range[0] = temp_freq_range[0];
+		if (temp_freq_range[1] > freq_range[1])
+			freq_range[1] = temp_freq_range[1];
+		if (temp_freq_range[2] < freq_range[2])
+			freq_range[2] = temp_freq_range[2];
+	}
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = ((int)freq_range[0]);
+	uinfo->value.integer.max = ((int)freq_range[1]);
+	uinfo->value.integer.step = ((int)freq_range[2]);
+	return 0;
+}
+
+static int snd_asihpi_tuner_freq_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	u32 h_control = kcontrol->private_value;
+	u32 freq;
+
+	hpi_handle_error(hpi_tuner_get_frequency(ss, h_control, &freq));
+	ucontrol->value.integer.value[0] = freq;
+
+	return 0;
+}
+
+static int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	u32 h_control = kcontrol->private_value;
+	u32 freq;
+
+	freq = ucontrol->value.integer.value[0];
+	hpi_handle_error(hpi_tuner_set_frequency(ss, h_control, freq));
+
+	return 1;
+}
+
+/* Tuner control group initializer  */
+static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
+					struct hpi_control *hpi_ctl)
+{
+	struct snd_card *card = asihpi->card;
+	struct snd_kcontrol_new snd_control;
+
+	snd_control.private_value = hpi_ctl->h_control;
+	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+
+	if (!hpi_tuner_get_gain(ss, hpi_ctl->h_control, NULL)) {
+		asihpi_ctl_init(&snd_control, hpi_ctl, "gain");
+		snd_control.info = snd_asihpi_tuner_gain_info;
+		snd_control.get = snd_asihpi_tuner_gain_get;
+		snd_control.put = snd_asihpi_tuner_gain_put;
+
+		if (ctl_add(card, &snd_control, asihpi) < 0)
+			return -EINVAL;
+	}
+
+	asihpi_ctl_init(&snd_control, hpi_ctl, "band");
+	snd_control.info = snd_asihpi_tuner_band_info;
+	snd_control.get = snd_asihpi_tuner_band_get;
+	snd_control.put = snd_asihpi_tuner_band_put;
+
+	if (ctl_add(card, &snd_control, asihpi) < 0)
+		return -EINVAL;
+
+	asihpi_ctl_init(&snd_control, hpi_ctl, "freq");
+	snd_control.info = snd_asihpi_tuner_freq_info;
+	snd_control.get = snd_asihpi_tuner_freq_get;
+	snd_control.put = snd_asihpi_tuner_freq_put;
+
+	return ctl_add(card, &snd_control, asihpi);
+}
+
+/*------------------------------------------------------------
+   Meter controls
+ ------------------------------------------------------------*/
+static int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = HPI_MAX_CHANNELS;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0x7FFFFFFF;
+	return 0;
+}
+
+/* linear values for 10dB steps */
+static int log2lin[] = {
+	0x7FFFFFFF, /* 0dB */
+	679093956,
+	214748365,
+	 67909396,
+	 21474837,
+	  6790940,
+	  2147484, /* -60dB */
+	   679094,
+	   214748, /* -80 */
+	    67909,
+	    21475, /* -100 */
+	     6791,
+	     2147,
+	      679,
+	      214,
+	       68,
+	       21,
+		7,
+		2
+};
+
+static int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u32 h_control = kcontrol->private_value;
+	short an_gain_mB[HPI_MAX_CHANNELS], i;
+	u16 err;
+
+	err = hpi_meter_get_peak(ss, h_control, an_gain_mB);
+
+	for (i = 0; i < HPI_MAX_CHANNELS; i++) {
+		if (err) {
+			ucontrol->value.integer.value[i] = 0;
+		} else if (an_gain_mB[i] >= 0) {
+			ucontrol->value.integer.value[i] =
+				an_gain_mB[i] << 16;
+		} else {
+			/* -ve is log value in millibels < -60dB,
+			* convert to (roughly!) linear,
+			*/
+			ucontrol->value.integer.value[i] =
+					log2lin[an_gain_mB[i] / -1000];
+		}
+	}
+	return 0;
+}
+
+static int __devinit snd_asihpi_meter_add(struct snd_card_asihpi *asihpi,
+					struct hpi_control *hpi_ctl, int subidx)
+{
+	struct snd_card *card = asihpi->card;
+	struct snd_kcontrol_new snd_control;
+
+	asihpi_ctl_init(&snd_control, hpi_ctl, "meter");
+	snd_control.access =
+	    SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
+	snd_control.info = snd_asihpi_meter_info;
+	snd_control.get = snd_asihpi_meter_get;
+
+	snd_control.index = subidx;
+
+	return ctl_add(card, &snd_control, asihpi);
+}
+
+/*------------------------------------------------------------
+   Multiplexer controls
+ ------------------------------------------------------------*/
+static int snd_card_asihpi_mux_count_sources(struct snd_kcontrol *snd_control)
+{
+	u32 h_control = snd_control->private_value;
+	struct hpi_control hpi_ctl;
+	int s, err;
+	for (s = 0; s < 32; s++) {
+		err = hpi_multiplexer_query_source(ss, h_control, s,
+						  &hpi_ctl.
+						  src_node_type,
+						  &hpi_ctl.
+						  src_node_index);
+		if (err)
+			break;
+	}
+	return s;
+}
+
+static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_info *uinfo)
+{
+	int err;
+	u16 src_node_type, src_node_index;
+	u32 h_control = kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items =
+	    snd_card_asihpi_mux_count_sources(kcontrol);
+
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item =
+		    uinfo->value.enumerated.items - 1;
+
+	err =
+	    hpi_multiplexer_query_source(ss, h_control,
+					uinfo->value.enumerated.item,
+					&src_node_type, &src_node_index);
+
+	sprintf(uinfo->value.enumerated.name, "%s %d",
+		asihpi_src_names[src_node_type - HPI_SOURCENODE_BASE],
+		src_node_index);
+	return 0;
+}
+
+static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	u32 h_control = kcontrol->private_value;
+	u16 source_type, source_index;
+	u16 src_node_type, src_node_index;
+	int s;
+
+	hpi_handle_error(hpi_multiplexer_get_source(ss, h_control,
+				&source_type, &source_index));
+	/* Should cache this search result! */
+	for (s = 0; s < 256; s++) {
+		if (hpi_multiplexer_query_source(ss, h_control, s,
+					    &src_node_type, &src_node_index))
+			break;
+
+		if ((source_type == src_node_type)
+		    && (source_index == src_node_index)) {
+			ucontrol->value.enumerated.item[0] = s;
+			return 0;
+		}
+	}
+	snd_printd(KERN_WARNING
+		"control %x failed to match mux source %hu %hu\n",
+		h_control, source_type, source_index);
+	ucontrol->value.enumerated.item[0] = 0;
+	return 0;
+}
+
+static int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	int change;
+	u32 h_control = kcontrol->private_value;
+	u16 source_type, source_index;
+	u16 e;
+
+	change = 1;
+
+	e = hpi_multiplexer_query_source(ss, h_control,
+				    ucontrol->value.enumerated.item[0],
+				    &source_type, &source_index);
+	if (!e)
+		hpi_handle_error(
+			hpi_multiplexer_set_source(ss, h_control,
+						source_type, source_index));
+	return change;
+}
+
+
+static int  __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi,
+					struct hpi_control *hpi_ctl)
+{
+	struct snd_card *card = asihpi->card;
+	struct snd_kcontrol_new snd_control;
+
+#if ASI_STYLE_NAMES
+	asihpi_ctl_init(&snd_control, hpi_ctl, "multiplexer");
+#else
+	asihpi_ctl_init(&snd_control, hpi_ctl, "route");
+#endif
+	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	snd_control.info = snd_asihpi_mux_info;
+	snd_control.get = snd_asihpi_mux_get;
+	snd_control.put = snd_asihpi_mux_put;
+
+	return ctl_add(card, &snd_control, asihpi);
+
+}
+
+/*------------------------------------------------------------
+   Channel mode controls
+ ------------------------------------------------------------*/
+static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	static char *mode_names[HPI_CHANNEL_MODE_LAST] = {
+		"normal", "swap",
+		"from_left", "from_right",
+		"to_left", "to_right"
+	};
+
+	u32 h_control = kcontrol->private_value;
+	u16 mode;
+	int i;
+
+	/* HPI channel mode values can be from 1 to 6
+	Some adapters only support a contiguous subset
+	*/
+	for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)
+		if (hpi_channel_mode_query_mode(
+			ss,  h_control, i, &mode))
+			break;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = i;
+
+	if (uinfo->value.enumerated.item >= i)
+		uinfo->value.enumerated.item = i - 1;
+
+	strcpy(uinfo->value.enumerated.name,
+	       mode_names[uinfo->value.enumerated.item]);
+
+	return 0;
+}
+
+static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u32 h_control = kcontrol->private_value;
+	u16 mode;
+
+	if (hpi_channel_mode_get(ss, h_control, &mode))
+		mode = 1;
+
+	ucontrol->value.enumerated.item[0] = mode - 1;
+
+	return 0;
+}
+
+static int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int change;
+	u32 h_control = kcontrol->private_value;
+
+	change = 1;
+
+	hpi_handle_error(hpi_channel_mode_set(ss, h_control,
+			   ucontrol->value.enumerated.item[0] + 1));
+	return change;
+}
+
+
+static int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
+					struct hpi_control *hpi_ctl)
+{
+	struct snd_card *card = asihpi->card;
+	struct snd_kcontrol_new snd_control;
+
+	asihpi_ctl_init(&snd_control, hpi_ctl, "channel mode");
+	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	snd_control.info = snd_asihpi_cmode_info;
+	snd_control.get = snd_asihpi_cmode_get;
+	snd_control.put = snd_asihpi_cmode_put;
+
+	return ctl_add(card, &snd_control, asihpi);
+}
+
+/*------------------------------------------------------------
+   Sampleclock source  controls
+ ------------------------------------------------------------*/
+
+static char *sampleclock_sources[MAX_CLOCKSOURCES] =
+    { "N/A", "local PLL", "AES/EBU sync", "word external", "word header",
+	  "SMPTE", "AES/EBU in1", "auto", "network", "invalid",
+	  "prev module",
+	  "AES/EBU in2", "AES/EBU in3", "AES/EBU in4", "AES/EBU in5",
+	  "AES/EBU in6", "AES/EBU in7", "AES/EBU in8"};
+
+
+
+static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	struct snd_card_asihpi *asihpi =
+			(struct snd_card_asihpi *)(kcontrol->private_data);
+	struct clk_cache *clkcache = &asihpi->cc;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = clkcache->count;
+
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item =
+				uinfo->value.enumerated.items - 1;
+
+	strcpy(uinfo->value.enumerated.name,
+	       clkcache->s[uinfo->value.enumerated.item].name);
+	return 0;
+}
+
+static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_card_asihpi *asihpi =
+			(struct snd_card_asihpi *)(kcontrol->private_data);
+	struct clk_cache *clkcache = &asihpi->cc;
+	u32 h_control = kcontrol->private_value;
+	u16 source, srcindex = 0;
+	int i;
+
+	ucontrol->value.enumerated.item[0] = 0;
+	if (hpi_sample_clock_get_source(ss, h_control, &source))
+		source = 0;
+
+	if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
+		if (hpi_sample_clock_get_source_index(ss, h_control, &srcindex))
+			srcindex = 0;
+
+	for (i = 0; i < clkcache->count; i++)
+		if ((clkcache->s[i].source == source) &&
+			(clkcache->s[i].index == srcindex))
+			break;
+
+	ucontrol->value.enumerated.item[0] = i;
+
+	return 0;
+}
+
+static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_card_asihpi *asihpi =
+			(struct snd_card_asihpi *)(kcontrol->private_data);
+	struct clk_cache *clkcache = &asihpi->cc;
+	int change, item;
+	u32 h_control = kcontrol->private_value;
+
+	change = 1;
+	item = ucontrol->value.enumerated.item[0];
+	if (item >= clkcache->count)
+		item = clkcache->count-1;
+
+	hpi_handle_error(hpi_sample_clock_set_source(ss,
+				h_control, clkcache->s[item].source));
+
+	if (clkcache->s[item].source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
+		hpi_handle_error(hpi_sample_clock_set_source_index(ss,
+				h_control, clkcache->s[item].index));
+	return change;
+}
+
+/*------------------------------------------------------------
+   Clkrate controls
+ ------------------------------------------------------------*/
+/* Need to change this to enumerated control with list of rates */
+static int snd_asihpi_clklocal_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 = 8000;
+	uinfo->value.integer.max = 192000;
+	uinfo->value.integer.step = 100;
+
+	return 0;
+}
+
+static int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	u32 h_control = kcontrol->private_value;
+	u32 rate;
+	u16 e;
+
+	e = hpi_sample_clock_get_local_rate(ss, h_control, &rate);
+	if (!e)
+		ucontrol->value.integer.value[0] = rate;
+	else
+		ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	int change;
+	u32 h_control = kcontrol->private_value;
+
+	/*  change = asihpi->mixer_clkrate[addr][0] != left ||
+	   asihpi->mixer_clkrate[addr][1] != right;
+	 */
+	change = 1;
+	hpi_handle_error(hpi_sample_clock_set_local_rate(ss, h_control,
+				      ucontrol->value.integer.value[0]));
+	return change;
+}
+
+static int snd_asihpi_clkrate_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 = 8000;
+	uinfo->value.integer.max = 192000;
+	uinfo->value.integer.step = 100;
+
+	return 0;
+}
+
+static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	u32 h_control = kcontrol->private_value;
+	u32 rate;
+	u16 e;
+
+	e = hpi_sample_clock_get_sample_rate(ss, h_control, &rate);
+	if (!e)
+		ucontrol->value.integer.value[0] = rate;
+	else
+		ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
+					struct hpi_control *hpi_ctl)
+{
+	struct snd_card *card = asihpi->card;
+	struct snd_kcontrol_new snd_control;
+
+	struct clk_cache *clkcache = &asihpi->cc;
+	u32 hSC =  hpi_ctl->h_control;
+	int has_aes_in = 0;
+	int i, j;
+	u16 source;
+
+	snd_control.private_value = hpi_ctl->h_control;
+
+	clkcache->has_local = 0;
+
+	for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) {
+		if  (hpi_sample_clock_query_source(ss, hSC,
+				i, &source))
+			break;
+		clkcache->s[i].source = source;
+		clkcache->s[i].index = 0;
+		clkcache->s[i].name = sampleclock_sources[source];
+		if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
+			has_aes_in = 1;
+		if (source == HPI_SAMPLECLOCK_SOURCE_LOCAL)
+			clkcache->has_local = 1;
+	}
+	if (has_aes_in)
+		/* already will have picked up index 0 above */
+		for (j = 1; j < 8; j++) {
+			if (hpi_sample_clock_query_source_index(ss, hSC,
+				j, HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT,
+				&source))
+				break;
+			clkcache->s[i].source =
+				HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT;
+			clkcache->s[i].index = j;
+			clkcache->s[i].name = sampleclock_sources[
+					j+HPI_SAMPLECLOCK_SOURCE_LAST];
+			i++;
+		}
+	clkcache->count = i;
+
+	asihpi_ctl_init(&snd_control, hpi_ctl, "source");
+	snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
+	snd_control.info = snd_asihpi_clksrc_info;
+	snd_control.get = snd_asihpi_clksrc_get;
+	snd_control.put = snd_asihpi_clksrc_put;
+	if (ctl_add(card, &snd_control, asihpi) < 0)
+		return -EINVAL;
+
+
+	if (clkcache->has_local) {
+		asihpi_ctl_init(&snd_control, hpi_ctl, "local_rate");
+		snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
+		snd_control.info = snd_asihpi_clklocal_info;
+		snd_control.get = snd_asihpi_clklocal_get;
+		snd_control.put = snd_asihpi_clklocal_put;
+
+
+		if (ctl_add(card, &snd_control, asihpi) < 0)
+			return -EINVAL;
+	}
+
+	asihpi_ctl_init(&snd_control, hpi_ctl, "rate");
+	snd_control.access =
+	    SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
+	snd_control.info = snd_asihpi_clkrate_info;
+	snd_control.get = snd_asihpi_clkrate_get;
+
+	return ctl_add(card, &snd_control, asihpi);
+}
+/*------------------------------------------------------------
+   Mixer
+ ------------------------------------------------------------*/
+
+static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
+{
+	struct snd_card *card = asihpi->card;
+	unsigned int idx = 0;
+	unsigned int subindex = 0;
+	int err;
+	struct hpi_control hpi_ctl, prev_ctl;
+
+	if (snd_BUG_ON(!asihpi))
+		return -EINVAL;
+	strcpy(card->mixername, "asihpi mixer");
+
+	err =
+	    hpi_mixer_open(ss, asihpi->adapter_index,
+			  &asihpi->h_mixer);
+	hpi_handle_error(err);
+	if (err)
+		return -err;
+
+	for (idx = 0; idx < 2000; idx++) {
+		err = hpi_mixer_get_control_by_index(
+				ss, asihpi->h_mixer,
+				idx,
+				&hpi_ctl.src_node_type,
+				&hpi_ctl.src_node_index,
+				&hpi_ctl.dst_node_type,
+				&hpi_ctl.dst_node_index,
+				&hpi_ctl.control_type,
+				&hpi_ctl.h_control);
+		if (err) {
+			if (err == HPI_ERROR_CONTROL_DISABLED) {
+				if (mixer_dump)
+					snd_printk(KERN_INFO
+						   "disabled HPI control(%d)\n",
+						   idx);
+				continue;
+			} else
+				break;
+
+		}
+
+		hpi_ctl.src_node_type -= HPI_SOURCENODE_BASE;
+		hpi_ctl.dst_node_type -= HPI_DESTNODE_BASE;
+
+		/* ASI50xx in SSX mode has multiple meters on the same node.
+		   Use subindex to create distinct ALSA controls
+		   for any duplicated controls.
+		*/
+		if ((hpi_ctl.control_type == prev_ctl.control_type) &&
+		    (hpi_ctl.src_node_type == prev_ctl.src_node_type) &&
+		    (hpi_ctl.src_node_index == prev_ctl.src_node_index) &&
+		    (hpi_ctl.dst_node_type == prev_ctl.dst_node_type) &&
+		    (hpi_ctl.dst_node_index == prev_ctl.dst_node_index))
+			subindex++;
+		else
+			subindex = 0;
+
+		prev_ctl = hpi_ctl;
+
+		switch (hpi_ctl.control_type) {
+		case HPI_CONTROL_VOLUME:
+			err = snd_asihpi_volume_add(asihpi, &hpi_ctl);
+			break;
+		case HPI_CONTROL_LEVEL:
+			err = snd_asihpi_level_add(asihpi, &hpi_ctl);
+			break;
+		case HPI_CONTROL_MULTIPLEXER:
+			err = snd_asihpi_mux_add(asihpi, &hpi_ctl);
+			break;
+		case HPI_CONTROL_CHANNEL_MODE:
+			err = snd_asihpi_cmode_add(asihpi, &hpi_ctl);
+			break;
+		case HPI_CONTROL_METER:
+			err = snd_asihpi_meter_add(asihpi, &hpi_ctl, subindex);
+			break;
+		case HPI_CONTROL_SAMPLECLOCK:
+			err = snd_asihpi_sampleclock_add(
+						asihpi, &hpi_ctl);
+			break;
+		case HPI_CONTROL_CONNECTION:	/* ignore these */
+			continue;
+		case HPI_CONTROL_TUNER:
+			err = snd_asihpi_tuner_add(asihpi, &hpi_ctl);
+			break;
+		case HPI_CONTROL_AESEBU_TRANSMITTER:
+			err = snd_asihpi_aesebu_tx_add(asihpi, &hpi_ctl);
+			break;
+		case HPI_CONTROL_AESEBU_RECEIVER:
+			err = snd_asihpi_aesebu_rx_add(asihpi, &hpi_ctl);
+			break;
+		case HPI_CONTROL_VOX:
+		case HPI_CONTROL_BITSTREAM:
+		case HPI_CONTROL_MICROPHONE:
+		case HPI_CONTROL_PARAMETRIC_EQ:
+		case HPI_CONTROL_COMPANDER:
+		default:
+			if (mixer_dump)
+				snd_printk(KERN_INFO
+					"untranslated HPI control"
+					"(%d) %d %d %d %d %d\n",
+					idx,
+					hpi_ctl.control_type,
+					hpi_ctl.src_node_type,
+					hpi_ctl.src_node_index,
+					hpi_ctl.dst_node_type,
+					hpi_ctl.dst_node_index);
+			continue;
+		};
+		if (err < 0)
+			return err;
+	}
+	if (HPI_ERROR_INVALID_OBJ_INDEX != err)
+		hpi_handle_error(err);
+
+	snd_printk(KERN_INFO "%d mixer controls found\n", idx);
+
+	return 0;
+}
+
+/*------------------------------------------------------------
+   /proc interface
+ ------------------------------------------------------------*/
+
+static void
+snd_asihpi_proc_read(struct snd_info_entry *entry,
+			struct snd_info_buffer *buffer)
+{
+	struct snd_card_asihpi *asihpi = entry->private_data;
+	u16 version;
+	u32 h_control;
+	u32 rate = 0;
+	u16 source = 0;
+	int err;
+
+	snd_iprintf(buffer, "ASIHPI driver proc file\n");
+	snd_iprintf(buffer,
+		"adapter ID=%4X\n_index=%d\n"
+		"num_outstreams=%d\n_num_instreams=%d\n",
+		asihpi->type, asihpi->adapter_index,
+		asihpi->num_outstreams, asihpi->num_instreams);
+
+	version = asihpi->version;
+	snd_iprintf(buffer,
+		"serial#=%d\n_hw version %c%d\nDSP code version %03d\n",
+		asihpi->serial_number, ((version >> 3) & 0xf) + 'A',
+		version & 0x7,
+		((version >> 13) * 100) + ((version >> 7) & 0x3f));
+
+	err = hpi_mixer_get_control(ss, asihpi->h_mixer,
+				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
+				  HPI_CONTROL_SAMPLECLOCK, &h_control);
+
+	if (!err) {
+		err = hpi_sample_clock_get_sample_rate(ss,
+					h_control, &rate);
+		err += hpi_sample_clock_get_source(ss, h_control, &source);
+
+		if (!err)
+			snd_iprintf(buffer, "sample_clock=%d_hz, source %s\n",
+			rate, sampleclock_sources[source]);
+	}
+
+}
+
+
+static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi)
+{
+	struct snd_info_entry *entry;
+
+	if (!snd_card_proc_new(asihpi->card, "info", &entry))
+		snd_info_set_text_ops(entry, asihpi, snd_asihpi_proc_read);
+}
+
+/*------------------------------------------------------------
+   HWDEP
+ ------------------------------------------------------------*/
+
+static int snd_asihpi_hpi_open(struct snd_hwdep *hw, struct file *file)
+{
+	if (enable_hpi_hwdep)
+		return 0;
+	else
+		return -ENODEV;
+
+}
+
+static int snd_asihpi_hpi_release(struct snd_hwdep *hw, struct file *file)
+{
+	if (enable_hpi_hwdep)
+		return asihpi_hpi_release(file);
+	else
+		return -ENODEV;
+}
+
+static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	if (enable_hpi_hwdep)
+		return asihpi_hpi_ioctl(file, cmd, arg);
+	else
+		return -ENODEV;
+}
+
+
+/* results in /dev/snd/hwC#D0 file for each card with index #
+   also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'
+*/
+static int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
+	int device, struct snd_hwdep **rhwdep)
+{
+	struct snd_hwdep *hw;
+	int err;
+
+	if (rhwdep)
+		*rhwdep = NULL;
+	err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
+	if (err < 0)
+		return err;
+	strcpy(hw->name, "asihpi (HPI)");
+	hw->iface = SNDRV_HWDEP_IFACE_LAST;
+	hw->ops.open = snd_asihpi_hpi_open;
+	hw->ops.ioctl = snd_asihpi_hpi_ioctl;
+	hw->ops.release = snd_asihpi_hpi_release;
+	hw->private_data = asihpi;
+	if (rhwdep)
+		*rhwdep = hw;
+	return 0;
+}
+
+/*------------------------------------------------------------
+   CARD
+ ------------------------------------------------------------*/
+static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
+				       const struct pci_device_id *pci_id)
+{
+	int err;
+
+	u16 version;
+	int pcm_substreams;
+
+	struct hpi_adapter *hpi_card;
+	struct snd_card *card;
+	struct snd_card_asihpi *asihpi;
+
+	u32 h_control;
+	u32 h_stream;
+
+	static int dev;
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+
+	/* Should this be enable[hpi_card->index] ? */
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	err = asihpi_adapter_probe(pci_dev, pci_id);
+	if (err < 0)
+		return err;
+
+	hpi_card = pci_get_drvdata(pci_dev);
+	/* first try to give the card the same index as its hardware index */
+	err = snd_card_create(hpi_card->index,
+			      id[hpi_card->index], THIS_MODULE,
+			      sizeof(struct snd_card_asihpi),
+			      &card);
+	if (err < 0) {
+		/* if that fails, try the default index==next available */
+		err =
+		    snd_card_create(index[dev], id[dev],
+				    THIS_MODULE,
+				    sizeof(struct snd_card_asihpi),
+				    &card);
+		if (err < 0)
+			return err;
+		snd_printk(KERN_WARNING
+			"**** WARNING **** adapter index %d->ALSA index %d\n",
+			hpi_card->index, card->number);
+	}
+
+	asihpi = (struct snd_card_asihpi *) card->private_data;
+	asihpi->card = card;
+	asihpi->pci = hpi_card->pci;
+	asihpi->adapter_index = hpi_card->index;
+	hpi_handle_error(hpi_adapter_get_info(ss,
+				 asihpi->adapter_index,
+				 &asihpi->num_outstreams,
+				 &asihpi->num_instreams,
+				 &asihpi->version,
+				 &asihpi->serial_number, &asihpi->type));
+
+	version = asihpi->version;
+	snd_printk(KERN_INFO "adapter ID=%4X index=%d num_outstreams=%d "
+			"num_instreams=%d S/N=%d\n"
+			"hw version %c%d DSP code version %03d\n",
+			asihpi->type, asihpi->adapter_index,
+			asihpi->num_outstreams,
+			asihpi->num_instreams, asihpi->serial_number,
+			((version >> 3) & 0xf) + 'A',
+			version & 0x7,
+			((version >> 13) * 100) + ((version >> 7) & 0x3f));
+
+	pcm_substreams = asihpi->num_outstreams;
+	if (pcm_substreams < asihpi->num_instreams)
+		pcm_substreams = asihpi->num_instreams;
+
+	err = hpi_adapter_get_property(ss, asihpi->adapter_index,
+		HPI_ADAPTER_PROPERTY_CAPS1,
+		NULL, &asihpi->support_grouping);
+	if (err)
+		asihpi->support_grouping = 0;
+
+	err = hpi_adapter_get_property(ss, asihpi->adapter_index,
+		HPI_ADAPTER_PROPERTY_CAPS2,
+		&asihpi->support_mrx, NULL);
+	if (err)
+		asihpi->support_mrx = 0;
+
+	err = hpi_adapter_get_property(ss, asihpi->adapter_index,
+		HPI_ADAPTER_PROPERTY_INTERVAL,
+		NULL, &asihpi->update_interval_frames);
+	if (err)
+		asihpi->update_interval_frames = 512;
+
+	hpi_handle_error(hpi_instream_open(ss, asihpi->adapter_index,
+			     0, &h_stream));
+
+	err = hpi_instream_host_buffer_free(ss, h_stream);
+	asihpi->support_mmap = (!err);
+
+	hpi_handle_error(hpi_instream_close(ss, h_stream));
+
+	err = hpi_adapter_get_property(ss, asihpi->adapter_index,
+		HPI_ADAPTER_PROPERTY_CURCHANNELS,
+		&asihpi->in_max_chans, &asihpi->out_max_chans);
+	if (err) {
+		asihpi->in_max_chans = 2;
+		asihpi->out_max_chans = 2;
+	}
+
+	snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n",
+			asihpi->support_mmap,
+			asihpi->support_grouping,
+			asihpi->support_mrx
+	      );
+
+
+	err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams);
+	if (err < 0) {
+		snd_printk(KERN_ERR "pcm_new failed\n");
+		goto __nodev;
+	}
+	err = snd_card_asihpi_mixer_new(asihpi);
+	if (err < 0) {
+		snd_printk(KERN_ERR "mixer_new failed\n");
+		goto __nodev;
+	}
+
+	err = hpi_mixer_get_control(ss, asihpi->h_mixer,
+				  HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
+				  HPI_CONTROL_SAMPLECLOCK, &h_control);
+
+	if (!err)
+		err = hpi_sample_clock_set_local_rate(
+			ss, h_control, adapter_fs);
+
+	snd_asihpi_proc_init(asihpi);
+
+	/* always create, can be enabled or disabled dynamically
+	    by enable_hwdep  module param*/
+	snd_asihpi_hpi_new(asihpi, 0, NULL);
+
+	if (asihpi->support_mmap)
+		strcpy(card->driver, "ASIHPI-MMAP");
+	else
+		strcpy(card->driver, "ASIHPI");
+
+	sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
+	sprintf(card->longname, "%s %i",
+			card->shortname, asihpi->adapter_index);
+	err = snd_card_register(card);
+	if (!err) {
+		hpi_card->snd_card_asihpi = card;
+		dev++;
+		return 0;
+	}
+__nodev:
+	snd_card_free(card);
+	snd_printk(KERN_ERR "snd_asihpi_probe error %d\n", err);
+	return err;
+
+}
+
+static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev)
+{
+	struct hpi_adapter *hpi_card = pci_get_drvdata(pci_dev);
+
+	snd_card_free(hpi_card->snd_card_asihpi);
+	hpi_card->snd_card_asihpi = NULL;
+	asihpi_adapter_remove(pci_dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(asihpi_pci_tbl) = {
+	{HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
+		HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
+		(kernel_ulong_t)HPI_6205},
+	{HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
+		HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
+		(kernel_ulong_t)HPI_6000},
+	{0,}
+};
+MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);
+
+static struct pci_driver driver = {
+	.name = "asihpi",
+	.id_table = asihpi_pci_tbl,
+	.probe = snd_asihpi_probe,
+	.remove = __devexit_p(snd_asihpi_remove),
+#ifdef CONFIG_PM
+/*	.suspend = snd_asihpi_suspend,
+	.resume = snd_asihpi_resume, */
+#endif
+};
+
+static int __init snd_asihpi_init(void)
+{
+	asihpi_init();
+	return pci_register_driver(&driver);
+}
+
+static void __exit snd_asihpi_exit(void)
+{
+
+	pci_unregister_driver(&driver);
+	asihpi_exit();
+}
+
+module_init(snd_asihpi_init)
+module_exit(snd_asihpi_exit)
+

+ 2001 - 0
sound/pci/asihpi/hpi.h

@@ -0,0 +1,2001 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+*/
+/** \file hpi.h
+
+ AudioScience Hardware Programming Interface (HPI)
+ public API definition.
+
+ The HPI is a low-level hardware abstraction layer to all
+ AudioScience digital audio adapters
+*/
+/*
+ You must define one operating system that the HPI is to be compiled under
+ HPI_OS_WIN32_USER   32bit Windows
+ HPI_OS_DSP_C6000    DSP TI C6000  (automatically set)
+ HPI_OS_WDM          Windows WDM kernel driver
+ HPI_OS_LINUX        Linux userspace
+ HPI_OS_LINUX_KERNEL Linux kernel (automatically set)
+
+(C) Copyright AudioScience Inc. 1998-2010
+******************************************************************************/
+#ifndef _HPI_H_
+#define _HPI_H_
+/* HPI Version
+If HPI_VER_MINOR is odd then its a development release not intended for the
+public. If HPI_VER_MINOR is even then is a release version
+i.e 3.05.02 is a development version
+*/
+#define HPI_VERSION_CONSTRUCTOR(maj, min, rel) \
+	((maj << 16) + (min << 8) + rel)
+
+#define HPI_VER_MAJOR(v) ((int)(v >> 16))
+#define HPI_VER_MINOR(v) ((int)((v >> 8) & 0xFF))
+#define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
+
+/* Use single digits for versions less that 10 to avoid octal. */
+#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 18)
+
+/* Library version as documented in hpi-api-versions.txt */
+#define HPI_LIB_VER  HPI_VERSION_CONSTRUCTOR(9, 0, 0)
+
+#include <linux/types.h>
+#define HPI_EXCLUDE_DEPRECATED
+
+/******************************************************************************/
+/******************************************************************************/
+/********       HPI API DEFINITIONS                                       *****/
+/******************************************************************************/
+/******************************************************************************/
+/*******************************************/
+/**  Audio format types
+\ingroup stream
+*/
+enum HPI_FORMATS {
+/** Used internally on adapter. */
+	HPI_FORMAT_MIXER_NATIVE = 0,
+/** 8-bit unsigned PCM. Windows equivalent is WAVE_FORMAT_PCM. */
+	HPI_FORMAT_PCM8_UNSIGNED = 1,
+/** 16-bit signed PCM. Windows equivalent is WAVE_FORMAT_PCM. */
+	HPI_FORMAT_PCM16_SIGNED = 2,
+/** MPEG-1 Layer-1. */
+	HPI_FORMAT_MPEG_L1 = 3,
+/** MPEG-1 Layer-2.
+
+Windows equivalent is WAVE_FORMAT_MPEG.
+
+The following table shows what combinations of mode and bitrate are possible:
+
+<table border=1 cellspacing=0 cellpadding=5>
+<tr>
+<td><p><b>Bitrate (kbs)</b></p>
+<td><p><b>Mono</b></p>
+<td><p><b>Stereo,<br>Joint Stereo or<br>Dual Channel</b></p>
+
+<tr><td>32<td>X<td>_
+<tr><td>40<td>_<td>_
+<tr><td>48<td>X<td>_
+<tr><td>56<td>X<td>_
+<tr><td>64<td>X<td>X
+<tr><td>80<td>X<td>_
+<tr><td>96<td>X<td>X
+<tr><td>112<td>X<td>X
+<tr><td>128<td>X<td>X
+<tr><td>160<td>X<td>X
+<tr><td>192<td>X<td>X
+<tr><td>224<td>_<td>X
+<tr><td>256<td>-<td>X
+<tr><td>320<td>-<td>X
+<tr><td>384<td>_<td>X
+</table>
+*/
+	HPI_FORMAT_MPEG_L2 = 4,
+/** MPEG-1 Layer-3.
+Windows equivalent is WAVE_FORMAT_MPEG.
+
+The following table shows what combinations of mode and bitrate are possible:
+
+<table border=1 cellspacing=0 cellpadding=5>
+<tr>
+<td><p><b>Bitrate (kbs)</b></p>
+<td><p><b>Mono<br>Stereo @ 8,<br>11.025 and<br>12kHz*</b></p>
+<td><p><b>Mono<br>Stereo @ 16,<br>22.050 and<br>24kHz*</b></p>
+<td><p><b>Mono<br>Stereo @ 32,<br>44.1 and<br>48kHz</b></p>
+
+<tr><td>16<td>X<td>X<td>_
+<tr><td>24<td>X<td>X<td>_
+<tr><td>32<td>X<td>X<td>X
+<tr><td>40<td>X<td>X<td>X
+<tr><td>48<td>X<td>X<td>X
+<tr><td>56<td>X<td>X<td>X
+<tr><td>64<td>X<td>X<td>X
+<tr><td>80<td>_<td>X<td>X
+<tr><td>96<td>_<td>X<td>X
+<tr><td>112<td>_<td>X<td>X
+<tr><td>128<td>_<td>X<td>X
+<tr><td>144<td>_<td>X<td>_
+<tr><td>160<td>_<td>X<td>X
+<tr><td>192<td>_<td>_<td>X
+<tr><td>224<td>_<td>_<td>X
+<tr><td>256<td>-<td>_<td>X
+<tr><td>320<td>-<td>_<td>X
+</table>
+\b * Available on the ASI6000 series only
+*/
+	HPI_FORMAT_MPEG_L3 = 5,
+/** Dolby AC-2. */
+	HPI_FORMAT_DOLBY_AC2 = 6,
+/** Dolbt AC-3. */
+	HPI_FORMAT_DOLBY_AC3 = 7,
+/** 16-bit PCM big-endian. */
+	HPI_FORMAT_PCM16_BIGENDIAN = 8,
+/** TAGIT-1 algorithm - hits. */
+	HPI_FORMAT_AA_TAGIT1_HITS = 9,
+/** TAGIT-1 algorithm - inserts. */
+	HPI_FORMAT_AA_TAGIT1_INSERTS = 10,
+/** 32-bit signed PCM. Windows equivalent is WAVE_FORMAT_PCM.
+Each sample is a 32bit word. The most significant 24 bits contain a 24-bit
+sample and the least significant 8 bits are set to 0.
+*/
+	HPI_FORMAT_PCM32_SIGNED = 11,
+/** Raw bitstream - unknown format. */
+	HPI_FORMAT_RAW_BITSTREAM = 12,
+/** TAGIT-1 algorithm hits - extended. */
+	HPI_FORMAT_AA_TAGIT1_HITS_EX1 = 13,
+/** 32-bit PCM as an IEEE float. Windows equivalent is WAVE_FORMAT_IEEE_FLOAT.
+Each sample is a 32bit word in IEEE754 floating point format.
+The range is +1.0 to -1.0, which corresponds to digital fullscale.
+*/
+	HPI_FORMAT_PCM32_FLOAT = 14,
+/** 24-bit PCM signed. Windows equivalent is WAVE_FORMAT_PCM. */
+	HPI_FORMAT_PCM24_SIGNED = 15,
+/** OEM format 1 - private. */
+	HPI_FORMAT_OEM1 = 16,
+/** OEM format 2 - private. */
+	HPI_FORMAT_OEM2 = 17,
+/** Undefined format. */
+	HPI_FORMAT_UNDEFINED = 0xffff
+};
+
+/******************************************* in/out Stream states */
+/*******************************************/
+/** Stream States
+\ingroup stream
+*/
+enum HPI_STREAM_STATES {
+	/** State stopped - stream is stopped. */
+	HPI_STATE_STOPPED = 1,
+	/** State playing - stream is playing audio. */
+	HPI_STATE_PLAYING = 2,
+	/** State recording - stream is recording. */
+	HPI_STATE_RECORDING = 3,
+	/** State drained - playing stream ran out of data to play. */
+	HPI_STATE_DRAINED = 4,
+	/** State generate sine - to be implemented. */
+	HPI_STATE_SINEGEN = 5,
+	/** State wait - used for inter-card sync to mean waiting for all
+		cards to be ready. */
+	HPI_STATE_WAIT = 6
+};
+/******************************************* mixer source node types */
+/** Source node types
+\ingroup mixer
+*/
+enum HPI_SOURCENODES {
+	/** This define can be used instead of 0 to indicate
+	that there is no valid source node. A control that
+	exists on a destination node can be searched for using a source
+	node value of either 0, or HPI_SOURCENODE_NONE */
+	HPI_SOURCENODE_NONE = 100,
+	/** \deprecated Use HPI_SOURCENODE_NONE instead. */
+	HPI_SOURCENODE_BASE = 100,
+	/** Out Stream (Play) node. */
+	HPI_SOURCENODE_OSTREAM = 101,
+	/** Line in node - could be analog, AES/EBU or network. */
+	HPI_SOURCENODE_LINEIN = 102,
+	HPI_SOURCENODE_AESEBU_IN = 103,	     /**< AES/EBU input node. */
+	HPI_SOURCENODE_TUNER = 104,	     /**< tuner node. */
+	HPI_SOURCENODE_RF = 105,	     /**< RF input node. */
+	HPI_SOURCENODE_CLOCK_SOURCE = 106,   /**< clock source node. */
+	HPI_SOURCENODE_RAW_BITSTREAM = 107,  /**< raw bitstream node. */
+	HPI_SOURCENODE_MICROPHONE = 108,     /**< microphone node. */
+	/** Cobranet input node -
+	    Audio samples come from the Cobranet network and into the device. */
+	HPI_SOURCENODE_COBRANET = 109,
+	HPI_SOURCENODE_ANALOG = 110,	     /**< analog input node. */
+	HPI_SOURCENODE_ADAPTER = 111,	     /**< adapter node. */
+	/* !!!Update this  AND hpidebug.h if you add a new sourcenode type!!! */
+	HPI_SOURCENODE_LAST_INDEX = 111	     /**< largest ID */
+		/* AX6 max sourcenode types = 15 */
+};
+
+/******************************************* mixer dest node types */
+/** Destination node types
+\ingroup mixer
+*/
+enum HPI_DESTNODES {
+	/** This define can be used instead of 0 to indicate
+	that there is no valid destination node. A control that
+	exists on a source node can be searched for using a destination
+	node value of either 0, or HPI_DESTNODE_NONE */
+	HPI_DESTNODE_NONE = 200,
+	/** \deprecated Use HPI_DESTNODE_NONE instead. */
+	HPI_DESTNODE_BASE = 200,
+	/** In Stream (Record) node. */
+	HPI_DESTNODE_ISTREAM = 201,
+	HPI_DESTNODE_LINEOUT = 202,	    /**< line out node. */
+	HPI_DESTNODE_AESEBU_OUT = 203,	     /**< AES/EBU output node. */
+	HPI_DESTNODE_RF = 204,		     /**< RF output node. */
+	HPI_DESTNODE_SPEAKER = 205,	     /**< speaker output node. */
+	/** Cobranet output node -
+	    Audio samples from the device are sent out on the Cobranet network.*/
+	HPI_DESTNODE_COBRANET = 206,
+	HPI_DESTNODE_ANALOG = 207,	     /**< analog output node. */
+
+	/* !!!Update this AND hpidebug.h if you add a new destnode type!!! */
+	HPI_DESTNODE_LAST_INDEX = 207	     /**< largest ID */
+		/* AX6 max destnode types = 15 */
+};
+
+/*******************************************/
+/** Mixer control types
+\ingroup mixer
+*/
+enum HPI_CONTROLS {
+	HPI_CONTROL_GENERIC = 0,	/**< generic control. */
+	HPI_CONTROL_CONNECTION = 1, /**< A connection between nodes. */
+	HPI_CONTROL_VOLUME = 2,	      /**< volume control - works in dB_fs. */
+	HPI_CONTROL_METER = 3,	/**< peak meter control. */
+	HPI_CONTROL_MUTE = 4,	/*mute control - not used at present. */
+	HPI_CONTROL_MULTIPLEXER = 5,	/**< multiplexer control. */
+
+	HPI_CONTROL_AESEBU_TRANSMITTER = 6,	/**< AES/EBU transmitter control. */
+	HPI_CONTROL_AESEBUTX = HPI_CONTROL_AESEBU_TRANSMITTER,
+
+	HPI_CONTROL_AESEBU_RECEIVER = 7, /**< AES/EBU receiver control. */
+	HPI_CONTROL_AESEBURX = HPI_CONTROL_AESEBU_RECEIVER,
+
+	HPI_CONTROL_LEVEL = 8, /**< level/trim control - works in d_bu. */
+	HPI_CONTROL_TUNER = 9,	/**< tuner control. */
+/*      HPI_CONTROL_ONOFFSWITCH =       10 */
+	HPI_CONTROL_VOX = 11,	/**< vox control. */
+/*      HPI_CONTROL_AES18_TRANSMITTER = 12 */
+/*      HPI_CONTROL_AES18_RECEIVER = 13 */
+/*      HPI_CONTROL_AES18_BLOCKGENERATOR  = 14 */
+	HPI_CONTROL_CHANNEL_MODE = 15,	/**< channel mode control. */
+
+	HPI_CONTROL_BITSTREAM = 16,	/**< bitstream control. */
+	HPI_CONTROL_SAMPLECLOCK = 17,	/**< sample clock control. */
+	HPI_CONTROL_MICROPHONE = 18,	/**< microphone control. */
+	HPI_CONTROL_PARAMETRIC_EQ = 19,	/**< parametric EQ control. */
+	HPI_CONTROL_EQUALIZER = HPI_CONTROL_PARAMETRIC_EQ,
+
+	HPI_CONTROL_COMPANDER = 20,	/**< compander control. */
+	HPI_CONTROL_COBRANET = 21,	/**< cobranet control. */
+	HPI_CONTROL_TONEDETECTOR = 22,	/**< tone detector control. */
+	HPI_CONTROL_SILENCEDETECTOR = 23,	/**< silence detector control. */
+	HPI_CONTROL_PAD = 24,	/**< tuner PAD control. */
+	HPI_CONTROL_SRC = 25,	/**< samplerate converter control. */
+	HPI_CONTROL_UNIVERSAL = 26,	/**< universal control. */
+
+/*  !!! Update this AND hpidebug.h if you add a new control type!!!*/
+	HPI_CONTROL_LAST_INDEX = 26 /**<highest control type ID */
+/* WARNING types 256 or greater impact bit packing in all AX6 DSP code */
+};
+
+/* Shorthand names that match attribute names */
+
+/******************************************* ADAPTER ATTRIBUTES ****/
+
+/** Adapter properties
+These are used in HPI_AdapterSetProperty() and HPI_AdapterGetProperty()
+\ingroup adapter
+*/
+enum HPI_ADAPTER_PROPERTIES {
+/** \internal Used in dwProperty field of HPI_AdapterSetProperty() and
+HPI_AdapterGetProperty(). This errata applies to all ASI6000 cards with both
+analog and digital outputs. The CS4224 A/D+D/A has a one sample delay between
+left and right channels on both its input (ADC) and output (DAC).
+More details are available in Cirrus Logic errata ER284B2.
+PDF available from www.cirrus.com, released by Cirrus in 2001.
+*/
+	HPI_ADAPTER_PROPERTY_ERRATA_1 = 1,
+
+/** Adapter grouping property
+Indicates whether the adapter supports the grouping API (for ASIO and SSX2)
+*/
+	HPI_ADAPTER_PROPERTY_GROUPING = 2,
+
+/** Driver SSX2 property
+Tells the kernel driver to turn on SSX2 stream mapping.
+This feature is not used by the DSP. In fact the call is completely processed
+by the driver and is not passed on to the DSP at all.
+*/
+	HPI_ADAPTER_PROPERTY_ENABLE_SSX2 = 3,
+
+/** Adapter SSX2 property
+Indicates the state of the adapter's SSX2 setting. This setting is stored in
+non-volatile memory on the adapter. A typical call sequence would be to use
+HPI_ADAPTER_PROPERTY_SSX2_SETTING to set SSX2 on the adapter and then to reload
+the driver. The driver would query HPI_ADAPTER_PROPERTY_SSX2_SETTING during startup
+and if SSX2 is set, it would then call HPI_ADAPTER_PROPERTY_ENABLE_SSX2 to enable
+SSX2 stream mapping within the kernel level of the driver.
+*/
+	HPI_ADAPTER_PROPERTY_SSX2_SETTING = 4,
+
+/** Base number for readonly properties */
+	HPI_ADAPTER_PROPERTY_READONLYBASE = 256,
+
+/** Readonly adapter latency property.
+This property returns in the input and output latency in samples.
+Property 1 is the estimated input latency
+in samples, while Property 2 is that output latency in  samples.
+*/
+	HPI_ADAPTER_PROPERTY_LATENCY = 256,
+
+/** Readonly adapter granularity property.
+The granulariy is the smallest size chunk of stereo samples that is processed by
+the adapter.
+This property returns the record granularity in samples in Property 1.
+Property 2 returns the play granularity.
+*/
+	HPI_ADAPTER_PROPERTY_GRANULARITY = 257,
+
+/** Readonly adapter number of current channels property.
+Property 1 is the number of record channels per record device.
+Property 2 is the number of play channels per playback device.*/
+	HPI_ADAPTER_PROPERTY_CURCHANNELS = 258,
+
+/** Readonly adapter software version.
+The SOFTWARE_VERSION property returns the version of the software running
+on the adapter as Major.Minor.Release.
+Property 1 contains Major in bits 15..8 and Minor in bits 7..0.
+Property 2 contains Release in bits 7..0. */
+	HPI_ADAPTER_PROPERTY_SOFTWARE_VERSION = 259,
+
+/** Readonly adapter MAC address MSBs.
+The MAC_ADDRESS_MSB property returns
+the most significant 32 bits of the MAC address.
+Property 1 contains bits 47..32 of the MAC address.
+Property 2 contains bits 31..16 of the MAC address. */
+	HPI_ADAPTER_PROPERTY_MAC_ADDRESS_MSB = 260,
+
+/** Readonly adapter MAC address LSBs
+The MAC_ADDRESS_LSB property returns
+the least significant 16 bits of the MAC address.
+Property 1 contains bits 15..0 of the MAC address. */
+	HPI_ADAPTER_PROPERTY_MAC_ADDRESS_LSB = 261,
+
+/** Readonly extended adapter type number
+The EXTENDED_ADAPTER_TYPE property returns the 4 digits of an extended
+adapter type, i.e ASI8920-0022, 0022 is the extended type.
+The digits are returned as ASCII characters rather than the hex digits that
+are returned for the main type
+Property 1 returns the 1st two (left most) digits, i.e "00"
+in the example above, the upper byte being the left most digit.
+Property 2 returns the 2nd two digits, i.e "22" in the example above*/
+	HPI_ADAPTER_PROPERTY_EXTENDED_ADAPTER_TYPE = 262,
+
+/** Readonly debug log buffer information */
+	HPI_ADAPTER_PROPERTY_LOGTABLEN = 263,
+	HPI_ADAPTER_PROPERTY_LOGTABBEG = 264,
+
+/** Readonly adapter IP address
+For 192.168.1.101
+Property 1 returns the 1st two (left most) digits, i.e 192*256 + 168
+in the example above, the upper byte being the left most digit.
+Property 2 returns the 2nd two digits, i.e 1*256 + 101 in the example above, */
+	HPI_ADAPTER_PROPERTY_IP_ADDRESS = 265,
+
+/** Readonly adapter buffer processed count. Returns a buffer processed count
+that is incremented every time all buffers for all streams are updated. This
+is useful for checking completion of all stream operations across the adapter
+when using grouped streams.
+*/
+	HPI_ADAPTER_PROPERTY_BUFFER_UPDATE_COUNT = 266,
+
+/** Readonly mixer and stream intervals
+
+These intervals are  measured in mixer frames.
+To convert to time, divide  by the adapter samplerate.
+
+The mixer interval is the number of frames processed in one mixer iteration.
+The stream update interval is the interval at which streams check for and
+process data, and BBM host buffer counters are updated.
+
+Property 1 is the mixer interval in mixer frames.
+Property 2 is the stream update interval in mixer frames.
+*/
+	HPI_ADAPTER_PROPERTY_INTERVAL = 267,
+/** Adapter capabilities 1
+Property 1 - adapter can do multichannel (SSX1)
+Property 2 - adapter can do stream grouping (supports SSX2)
+*/
+	HPI_ADAPTER_PROPERTY_CAPS1 = 268,
+/** Adapter capabilities 2
+Property 1 - adapter can do samplerate conversion (MRX)
+Property 2 - adapter can do timestretch (TSX)
+*/
+	HPI_ADAPTER_PROPERTY_CAPS2 = 269
+};
+
+/** Adapter mode commands
+
+Used in wQueryOrSet field of HPI_AdapterSetModeEx().
+\ingroup adapter
+*/
+enum HPI_ADAPTER_MODE_CMDS {
+	HPI_ADAPTER_MODE_SET = 0,
+	HPI_ADAPTER_MODE_QUERY = 1
+};
+
+/** Adapter Modes
+	These are used by HPI_AdapterSetModeEx()
+
+\warning - more than 16 possible modes breaks
+a bitmask in the Windows WAVE DLL
+\ingroup adapter
+*/
+enum HPI_ADAPTER_MODES {
+/** 4 outstream mode.
+- ASI6114: 1 instream
+- ASI6044: 4 instreams
+- ASI6012: 1 instream
+- ASI6102: no instreams
+- ASI6022, ASI6122: 2 instreams
+- ASI5111, ASI5101: 2 instreams
+- ASI652x, ASI662x: 2 instreams
+- ASI654x, ASI664x: 4 instreams
+*/
+	HPI_ADAPTER_MODE_4OSTREAM = 1,
+
+/** 6 outstream mode.
+- ASI6012: 1 instream,
+- ASI6022, ASI6122: 2 instreams
+- ASI652x, ASI662x: 4 instreams
+*/
+	HPI_ADAPTER_MODE_6OSTREAM = 2,
+
+/** 8 outstream mode.
+- ASI6114: 8 instreams
+- ASI6118: 8 instreams
+- ASI6585: 8 instreams
+*/
+	HPI_ADAPTER_MODE_8OSTREAM = 3,
+
+/** 16 outstream mode.
+- ASI6416 16 instreams
+- ASI6518, ASI6618 16 instreams
+- ASI6118 16 mono out and in streams
+*/
+	HPI_ADAPTER_MODE_16OSTREAM = 4,
+
+/** one outstream mode.
+- ASI5111 1 outstream, 1 instream
+*/
+	HPI_ADAPTER_MODE_1OSTREAM = 5,
+
+/** ASI504X mode 1. 12 outstream, 4 instream 0 to 48kHz sample rates
+	(see ASI504X datasheet for more info).
+*/
+	HPI_ADAPTER_MODE_1 = 6,
+
+/** ASI504X mode 2. 4 outstreams, 4 instreams at 0 to 192kHz sample rates
+	(see ASI504X datasheet for more info).
+*/
+	HPI_ADAPTER_MODE_2 = 7,
+
+/** ASI504X mode 3. 4 outstreams, 4 instreams at 0 to 192kHz sample rates
+	(see ASI504X datasheet for more info).
+*/
+	HPI_ADAPTER_MODE_3 = 8,
+
+/** ASI504X multichannel mode.
+	2 outstreams -> 4 line outs = 1 to 8 channel streams),
+	4 lineins -> 1 instream (1 to 8 channel streams) at 0-48kHz.
+	For more info see the SSX Specification.
+*/
+	HPI_ADAPTER_MODE_MULTICHANNEL = 9,
+
+/** 12 outstream mode.
+- ASI6514, ASI6614: 2 instreams
+- ASI6540,ASI6544: 8 instreams
+- ASI6640,ASI6644: 8 instreams
+*/
+	HPI_ADAPTER_MODE_12OSTREAM = 10,
+
+/** 9 outstream mode.
+- ASI6044: 8 instreams
+*/
+	HPI_ADAPTER_MODE_9OSTREAM = 11,
+
+/** mono mode.
+- ASI6416: 16 outstreams/instreams
+- ASI5402: 2 outstreams/instreams
+*/
+	HPI_ADAPTER_MODE_MONO = 12,
+
+/** Low latency mode.
+- ASI6416/ASI6316: 1 16 channel outstream and instream
+*/
+	HPI_ADAPTER_MODE_LOW_LATENCY = 13
+};
+
+/* Note, adapters can have more than one capability -
+encoding as bitfield is recommended. */
+#define HPI_CAPABILITY_NONE             (0)
+#define HPI_CAPABILITY_MPEG_LAYER3      (1)
+
+/* Set this equal to maximum capability index,
+Must not be greater than 32 - see axnvdef.h */
+#define HPI_CAPABILITY_MAX                      1
+/* #define HPI_CAPABILITY_AAC              2 */
+
+/******************************************* STREAM ATTRIBUTES ****/
+
+/** MPEG Ancillary Data modes
+
+The mode for the ancillary data insertion or extraction to operate in.
+\ingroup stream
+*/
+enum HPI_MPEG_ANC_MODES {
+	/** the MPEG frames have energy information stored in them (5 bytes per stereo frame, 3 per mono) */
+	HPI_MPEG_ANC_HASENERGY = 0,
+	/** the entire ancillary data field is taken up by data from the Anc data buffer
+	On encode, the encoder will insert the energy bytes before filling the remainder
+	of the ancillary data space with data from the ancillary data buffer.
+	*/
+	HPI_MPEG_ANC_RAW = 1
+};
+
+/** Ancillary Data Alignment
+\ingroup instream
+*/
+enum HPI_ISTREAM_MPEG_ANC_ALIGNS {
+	/** data is packed against the end of data, then padded to the end of frame */
+	HPI_MPEG_ANC_ALIGN_LEFT = 0,
+	/** data is packed against the end of the frame */
+	HPI_MPEG_ANC_ALIGN_RIGHT = 1
+};
+
+/** MPEG modes
+MPEG modes - can be used optionally for HPI_FormatCreate()
+parameter dwAttributes.
+
+Using any mode setting other than HPI_MPEG_MODE_DEFAULT
+with single channel format will return an error.
+\ingroup stream
+*/
+enum HPI_MPEG_MODES {
+/** Causes the MPEG-1 Layer II bitstream to be recorded
+in single_channel mode when the number of channels is 1 and in stereo when the
+number of channels is 2. */
+	HPI_MPEG_MODE_DEFAULT = 0,
+	/** Standard stereo without joint-stereo compression */
+	HPI_MPEG_MODE_STEREO = 1,
+	/** Joint stereo  */
+	HPI_MPEG_MODE_JOINTSTEREO = 2,
+	/** Left and Right channels are completely independent */
+	HPI_MPEG_MODE_DUALCHANNEL = 3
+};
+/******************************************* MIXER ATTRIBUTES ****/
+
+/* \defgroup mixer_flags Mixer flags for HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES
+{
+*/
+#define HPI_MIXER_GET_CONTROL_MULTIPLE_CHANGED  (0)
+#define HPI_MIXER_GET_CONTROL_MULTIPLE_RESET    (1)
+/*}*/
+
+/** Commands used by HPI_MixerStore()
+\ingroup mixer
+*/
+enum HPI_MIXER_STORE_COMMAND {
+/** Save all mixer control settings. */
+	HPI_MIXER_STORE_SAVE = 1,
+/** Restore all controls from saved. */
+	HPI_MIXER_STORE_RESTORE = 2,
+/** Delete saved control settings. */
+	HPI_MIXER_STORE_DELETE = 3,
+/** Enable auto storage of some control settings. */
+	HPI_MIXER_STORE_ENABLE = 4,
+/** Disable auto storage of some control settings. */
+	HPI_MIXER_STORE_DISABLE = 5,
+/** Save the attributes of a single control. */
+	HPI_MIXER_STORE_SAVE_SINGLE = 6
+};
+
+/************************************* CONTROL ATTRIBUTE VALUES ****/
+/** Used by mixer plugin enable functions
+
+E.g. HPI_ParametricEQ_SetState()
+\ingroup mixer
+*/
+enum HPI_SWITCH_STATES {
+	HPI_SWITCH_OFF = 0,	/**< turn the mixer plugin on. */
+	HPI_SWITCH_ON = 1	/**< turn the mixer plugin off. */
+};
+
+/* Volume control special gain values */
+/** volumes units are 100ths of a dB
+\ingroup volume
+*/
+#define HPI_UNITS_PER_dB                100
+/** turns volume control OFF or MUTE
+\ingroup volume
+*/
+#define HPI_GAIN_OFF                    (-100 * HPI_UNITS_PER_dB)
+
+/** value returned for no signal
+\ingroup meter
+*/
+#define HPI_METER_MINIMUM               (-150 * HPI_UNITS_PER_dB)
+
+/** autofade profiles
+\ingroup volume
+*/
+enum HPI_VOLUME_AUTOFADES {
+/** log fade - dB attenuation changes linearly over time */
+	HPI_VOLUME_AUTOFADE_LOG = 2,
+/** linear fade - amplitude changes linearly */
+	HPI_VOLUME_AUTOFADE_LINEAR = 3
+};
+
+/** The physical encoding format of the AESEBU I/O.
+
+Used in HPI_AESEBU_Transmitter_SetFormat(), HPI_AESEBU_Receiver_SetFormat()
+along with related Get and Query functions
+\ingroup aestx
+*/
+enum HPI_AESEBU_FORMATS {
+/** AES/EBU physical format - AES/EBU balanced "professional"  */
+	HPI_AESEBU_FORMAT_AESEBU = 1,
+/** AES/EBU physical format - S/PDIF unbalanced "consumer"      */
+	HPI_AESEBU_FORMAT_SPDIF = 2
+};
+
+/** AES/EBU error status bits
+
+Returned by HPI_AESEBU_Receiver_GetErrorStatus()
+\ingroup aesrx
+*/
+enum HPI_AESEBU_ERRORS {
+/**  bit0: 1 when PLL is not locked */
+	HPI_AESEBU_ERROR_NOT_LOCKED = 0x01,
+/**  bit1: 1 when signal quality is poor */
+	HPI_AESEBU_ERROR_POOR_QUALITY = 0x02,
+/** bit2: 1 when there is a parity error */
+	HPI_AESEBU_ERROR_PARITY_ERROR = 0x04,
+/**  bit3: 1 when there is a bi-phase coding violation */
+	HPI_AESEBU_ERROR_BIPHASE_VIOLATION = 0x08,
+/**  bit4: 1 when the validity bit is high */
+	HPI_AESEBU_ERROR_VALIDITY = 0x10,
+/**  bit5: 1 when the CRC error bit is high */
+	HPI_AESEBU_ERROR_CRC = 0x20
+};
+
+/** \addtogroup pad
+\{
+*/
+/** The text string containing the station/channel combination. */
+#define HPI_PAD_CHANNEL_NAME_LEN        16
+/** The text string containing the artist. */
+#define HPI_PAD_ARTIST_LEN              64
+/** The text string containing the title. */
+#define HPI_PAD_TITLE_LEN               64
+/** The text string containing the comment. */
+#define HPI_PAD_COMMENT_LEN             256
+/** The PTY when the tuner has not recieved any PTY. */
+#define HPI_PAD_PROGRAM_TYPE_INVALID    0xffff
+/** \} */
+
+/** Data types for PTY string translation.
+\ingroup rds
+*/
+enum eHPI_RDS_type {
+	HPI_RDS_DATATYPE_RDS = 0,	/**< RDS bitstream.*/
+	HPI_RDS_DATATYPE_RBDS = 1	/**< RBDS bitstream.*/
+};
+
+/** Tuner bands
+
+Used for HPI_Tuner_SetBand(),HPI_Tuner_GetBand()
+\ingroup tuner
+*/
+enum HPI_TUNER_BAND {
+	HPI_TUNER_BAND_AM = 1,	 /**< AM band */
+	HPI_TUNER_BAND_FM = 2,	 /**< FM band (mono) */
+	HPI_TUNER_BAND_TV_NTSC_M = 3,	 /**< NTSC-M TV band*/
+	HPI_TUNER_BAND_TV = 3,	/* use TV_NTSC_M */
+	HPI_TUNER_BAND_FM_STEREO = 4,	 /**< FM band (stereo) */
+	HPI_TUNER_BAND_AUX = 5,	 /**< auxiliary input */
+	HPI_TUNER_BAND_TV_PAL_BG = 6,	 /**< PAL-B/G TV band*/
+	HPI_TUNER_BAND_TV_PAL_I = 7,	 /**< PAL-I TV band*/
+	HPI_TUNER_BAND_TV_PAL_DK = 8,	 /**< PAL-D/K TV band*/
+	HPI_TUNER_BAND_TV_SECAM_L = 9,	 /**< SECAM-L TV band*/
+	HPI_TUNER_BAND_LAST = 9	/**< the index of the last tuner band. */
+};
+
+/** Tuner mode attributes
+
+Used by HPI_Tuner_SetMode(), HPI_Tuner_GetMode()
+\ingroup tuner
+
+*/
+enum HPI_TUNER_MODES {
+	HPI_TUNER_MODE_RSS = 1,	/**< control  RSS */
+	HPI_TUNER_MODE_RDS = 2	/**< control  RBDS/RDS */
+};
+
+/** Tuner mode attribute values
+
+Used by HPI_Tuner_SetMode(), HPI_Tuner_GetMode()
+\ingroup tuner
+*/
+enum HPI_TUNER_MODE_VALUES {
+/* RSS attribute values */
+	HPI_TUNER_MODE_RSS_DISABLE = 0,	/**< RSS disable */
+	HPI_TUNER_MODE_RSS_ENABLE = 1,	/**< RSS enable */
+
+/* RDS mode attributes */
+	HPI_TUNER_MODE_RDS_DISABLE = 0,	/**< RDS - disabled */
+	HPI_TUNER_MODE_RDS_RDS = 1,  /**< RDS - RDS mode */
+	HPI_TUNER_MODE_RDS_RBDS = 2 /**<  RDS - RBDS mode */
+};
+
+/** Tuner Level settings
+\ingroup tuner
+*/
+enum HPI_TUNER_LEVEL {
+	HPI_TUNER_LEVEL_AVERAGE = 0,
+	HPI_TUNER_LEVEL_RAW = 1
+};
+
+/** Tuner Status Bits
+
+These bitfield values are returned by a call to HPI_Tuner_GetStatus().
+Multiple fields are returned from a single call.
+\ingroup tuner
+*/
+enum HPI_TUNER_STATUS_BITS {
+	HPI_TUNER_VIDEO_COLOR_PRESENT = 0x0001,	/**< video color is present. */
+	HPI_TUNER_VIDEO_IS_60HZ = 0x0020,	/**< 60 hz video detected. */
+	HPI_TUNER_VIDEO_HORZ_SYNC_MISSING = 0x0040,	/**< video HSYNC is missing. */
+	HPI_TUNER_VIDEO_STATUS_VALID = 0x0100,	/**< video status is valid. */
+	HPI_TUNER_PLL_LOCKED = 0x1000,		/**< the tuner's PLL is locked. */
+	HPI_TUNER_FM_STEREO = 0x2000,		/**< tuner reports back FM stereo. */
+	HPI_TUNER_DIGITAL = 0x0200,		/**< tuner reports digital programming. */
+	HPI_TUNER_MULTIPROGRAM = 0x0400		/**< tuner reports multiple programs. */
+};
+
+/** Channel Modes
+Used for HPI_ChannelModeSet/Get()
+\ingroup channelmode
+*/
+enum HPI_CHANNEL_MODES {
+/** Left channel out = left channel in, Right channel out = right channel in. */
+	HPI_CHANNEL_MODE_NORMAL = 1,
+/** Left channel out = right channel in, Right channel out = left channel in. */
+	HPI_CHANNEL_MODE_SWAP = 2,
+/** Left channel out = left channel in, Right channel out = left channel in. */
+	HPI_CHANNEL_MODE_LEFT_TO_STEREO = 3,
+/** Left channel out = right channel in, Right channel out = right channel in.*/
+	HPI_CHANNEL_MODE_RIGHT_TO_STEREO = 4,
+/** Left channel out = (left channel in + right channel in)/2,
+    Right channel out = mute. */
+	HPI_CHANNEL_MODE_STEREO_TO_LEFT = 5,
+/** Left channel out = mute,
+    Right channel out = (right channel in + left channel in)/2. */
+	HPI_CHANNEL_MODE_STEREO_TO_RIGHT = 6,
+	HPI_CHANNEL_MODE_LAST = 6
+};
+
+/** SampleClock source values
+\ingroup sampleclock
+*/
+enum HPI_SAMPLECLOCK_SOURCES {
+/** The sampleclock output is derived from its local samplerate generator.
+    The local samplerate may be set using HPI_SampleClock_SetLocalRate(). */
+	HPI_SAMPLECLOCK_SOURCE_LOCAL = 1,
+/** \deprecated Use HPI_SAMPLECLOCK_SOURCE_LOCAL instead */
+	HPI_SAMPLECLOCK_SOURCE_ADAPTER = 1,
+/** The adapter is clocked from a dedicated AES/EBU SampleClock input.*/
+	HPI_SAMPLECLOCK_SOURCE_AESEBU_SYNC = 2,
+/** From external wordclock connector */
+	HPI_SAMPLECLOCK_SOURCE_WORD = 3,
+/** Board-to-board header */
+	HPI_SAMPLECLOCK_SOURCE_WORD_HEADER = 4,
+/** FUTURE - SMPTE clock. */
+	HPI_SAMPLECLOCK_SOURCE_SMPTE = 5,
+/** One of the aesebu inputs */
+	HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT = 6,
+/** \deprecated The first aesebu input with a valid signal
+Superseded by separate Auto enable flag
+*/
+	HPI_SAMPLECLOCK_SOURCE_AESEBU_AUTO = 7,
+/** From a network interface e.g. Cobranet or Livewire at either 48 or 96kHz */
+	HPI_SAMPLECLOCK_SOURCE_NETWORK = 8,
+/** From previous adjacent module (ASI2416 only)*/
+	HPI_SAMPLECLOCK_SOURCE_PREV_MODULE = 10,
+/*! Update this if you add a new clock source.*/
+	HPI_SAMPLECLOCK_SOURCE_LAST = 10
+};
+
+/** Equalizer filter types. Used by HPI_ParametricEQ_SetBand()
+\ingroup parmeq
+*/
+enum HPI_FILTER_TYPE {
+	HPI_FILTER_TYPE_BYPASS = 0,	/**< filter is turned off */
+
+	HPI_FILTER_TYPE_LOWSHELF = 1,	/**< EQ low shelf */
+	HPI_FILTER_TYPE_HIGHSHELF = 2,	/**< EQ high shelf */
+	HPI_FILTER_TYPE_EQ_BAND = 3,	/**< EQ gain */
+
+	HPI_FILTER_TYPE_LOWPASS = 4,	/**< standard low pass */
+	HPI_FILTER_TYPE_HIGHPASS = 5,	/**< standard high pass */
+	HPI_FILTER_TYPE_BANDPASS = 6,	/**< standard band pass */
+	HPI_FILTER_TYPE_BANDSTOP = 7	/**< standard band stop/notch */
+};
+
+/** Async Event sources
+\ingroup async
+*/
+enum ASYNC_EVENT_SOURCES {
+	HPI_ASYNC_EVENT_GPIO = 1,	/**< GPIO event. */
+	HPI_ASYNC_EVENT_SILENCE = 2,	/**< silence event detected. */
+	HPI_ASYNC_EVENT_TONE = 3	/**< tone event detected. */
+};
+/*******************************************/
+/** HPI Error codes
+
+Almost all HPI functions return an error code
+A return value of zero means there was no error.
+Otherwise one of these error codes is returned.
+Error codes can be converted to a descriptive string using HPI_GetErrorText()
+
+\note When a new error code is added HPI_GetErrorText() MUST be updated.
+\note Codes 1-100 are reserved for driver use
+\ingroup utility
+*/
+enum HPI_ERROR_CODES {
+	/** Message type does not exist. */
+	HPI_ERROR_INVALID_TYPE = 100,
+	/** Object type does not exist. */
+	HPI_ERROR_INVALID_OBJ = 101,
+	/** Function does not exist. */
+	HPI_ERROR_INVALID_FUNC = 102,
+	/** The specified object (adapter/Stream) does not exist. */
+	HPI_ERROR_INVALID_OBJ_INDEX = 103,
+	/** Trying to access an object that has not been opened yet. */
+	HPI_ERROR_OBJ_NOT_OPEN = 104,
+	/** Trying to open an already open object. */
+	HPI_ERROR_OBJ_ALREADY_OPEN = 105,
+	/** PCI, ISA resource not valid. */
+	HPI_ERROR_INVALID_RESOURCE = 106,
+	/** GetInfo call from SubSysFindAdapters failed. */
+	HPI_ERROR_SUBSYSFINDADAPTERS_GETINFO = 107,
+	/** Default response was never updated with actual error code. */
+	HPI_ERROR_INVALID_RESPONSE = 108,
+	/** wSize field of response was not updated,
+	indicating that the message was not processed. */
+	HPI_ERROR_PROCESSING_MESSAGE = 109,
+	/** The network did not respond in a timely manner. */
+	HPI_ERROR_NETWORK_TIMEOUT = 110,
+	/** An HPI handle is invalid (uninitialised?). */
+	HPI_ERROR_INVALID_HANDLE = 111,
+	/** A function or attribute has not been implemented yet. */
+	HPI_ERROR_UNIMPLEMENTED = 112,
+	/** There are too many clients attempting to access a network resource. */
+	HPI_ERROR_NETWORK_TOO_MANY_CLIENTS = 113,
+	/** Response buffer passed to HPI_Message was smaller than returned response */
+	HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL = 114,
+	/** The returned response did not match the sent message */
+	HPI_ERROR_RESPONSE_MISMATCH = 115,
+
+	/** Too many adapters.*/
+	HPI_ERROR_TOO_MANY_ADAPTERS = 200,
+	/** Bad adpater. */
+	HPI_ERROR_BAD_ADAPTER = 201,
+	/** Adapter number out of range or not set properly. */
+	HPI_ERROR_BAD_ADAPTER_NUMBER = 202,
+	/** 2 adapters with the same adapter number. */
+	HPI_DUPLICATE_ADAPTER_NUMBER = 203,
+	/** DSP code failed to bootload. */
+	HPI_ERROR_DSP_BOOTLOAD = 204,
+	/** Adapter failed DSP code self test. */
+	HPI_ERROR_DSP_SELFTEST = 205,
+	/** Couldn't find or open the DSP code file. */
+	HPI_ERROR_DSP_FILE_NOT_FOUND = 206,
+	/** Internal DSP hardware error. */
+	HPI_ERROR_DSP_HARDWARE = 207,
+	/** Could not allocate memory in DOS. */
+	HPI_ERROR_DOS_MEMORY_ALLOC = 208,
+	/** Could not allocate memory */
+	HPI_ERROR_MEMORY_ALLOC = 208,
+	/** Failed to correctly load/config PLD .*/
+	HPI_ERROR_PLD_LOAD = 209,
+	/** Unexpected end of file, block length too big etc. */
+	HPI_ERROR_DSP_FILE_FORMAT = 210,
+
+	/** Found but could not open DSP code file. */
+	HPI_ERROR_DSP_FILE_ACCESS_DENIED = 211,
+	/** First DSP code section header not found in DSP file. */
+	HPI_ERROR_DSP_FILE_NO_HEADER = 212,
+	/** File read operation on DSP code file failed. */
+	HPI_ERROR_DSP_FILE_READ_ERROR = 213,
+	/** DSP code for adapter family not found. */
+	HPI_ERROR_DSP_SECTION_NOT_FOUND = 214,
+	/** Other OS specific error opening DSP file. */
+	HPI_ERROR_DSP_FILE_OTHER_ERROR = 215,
+	/** Sharing violation opening DSP code file. */
+	HPI_ERROR_DSP_FILE_SHARING_VIOLATION = 216,
+	/** DSP code section header had size == 0. */
+	HPI_ERROR_DSP_FILE_NULL_HEADER = 217,
+
+	/** Base number for flash errors. */
+	HPI_ERROR_FLASH = 220,
+
+	/** Flash has bad checksum */
+	HPI_ERROR_BAD_CHECKSUM = (HPI_ERROR_FLASH + 1),
+	HPI_ERROR_BAD_SEQUENCE = (HPI_ERROR_FLASH + 2),
+	HPI_ERROR_FLASH_ERASE = (HPI_ERROR_FLASH + 3),
+	HPI_ERROR_FLASH_PROGRAM = (HPI_ERROR_FLASH + 4),
+	HPI_ERROR_FLASH_VERIFY = (HPI_ERROR_FLASH + 5),
+	HPI_ERROR_FLASH_TYPE = (HPI_ERROR_FLASH + 6),
+	HPI_ERROR_FLASH_START = (HPI_ERROR_FLASH + 7),
+
+	/** Reserved for OEMs. */
+	HPI_ERROR_RESERVED_1 = 290,
+
+	/** Stream does not exist. */
+	HPI_ERROR_INVALID_STREAM = 300,
+	/** Invalid compression format. */
+	HPI_ERROR_INVALID_FORMAT = 301,
+	/** Invalid format samplerate */
+	HPI_ERROR_INVALID_SAMPLERATE = 302,
+	/** Invalid format number of channels. */
+	HPI_ERROR_INVALID_CHANNELS = 303,
+	/** Invalid format bitrate. */
+	HPI_ERROR_INVALID_BITRATE = 304,
+	/** Invalid datasize used for stream read/write. */
+	HPI_ERROR_INVALID_DATASIZE = 305,
+	/** Stream buffer is full during stream write. */
+	HPI_ERROR_BUFFER_FULL = 306,
+	/** Stream buffer is empty during stream read. */
+	HPI_ERROR_BUFFER_EMPTY = 307,
+	/** Invalid datasize used for stream read/write. */
+	HPI_ERROR_INVALID_DATA_TRANSFER = 308,
+	/** Packet ordering error for stream read/write. */
+	HPI_ERROR_INVALID_PACKET_ORDER = 309,
+
+	/** Object can't do requested operation in its current
+	state, eg set format, change rec mux state while recording.*/
+	HPI_ERROR_INVALID_OPERATION = 310,
+
+	/** Where an SRG is shared amongst streams, an incompatible samplerate is one
+	that is different to any currently playing or recording stream. */
+	HPI_ERROR_INCOMPATIBLE_SAMPLERATE = 311,
+	/** Adapter mode is illegal.*/
+	HPI_ERROR_BAD_ADAPTER_MODE = 312,
+
+	/** There have been too many attempts to set the adapter's
+	capabilities (using bad keys), the card should be returned
+	to ASI if further capabilities updates are required */
+	HPI_ERROR_TOO_MANY_CAPABILITY_CHANGE_ATTEMPTS = 313,
+	/** Streams on different adapters cannot be grouped. */
+	HPI_ERROR_NO_INTERADAPTER_GROUPS = 314,
+	/** Streams on different DSPs cannot be grouped. */
+	HPI_ERROR_NO_INTERDSP_GROUPS = 315,
+
+	/** Invalid mixer node for this adapter. */
+	HPI_ERROR_INVALID_NODE = 400,
+	/** Invalid control. */
+	HPI_ERROR_INVALID_CONTROL = 401,
+	/** Invalid control value was passed. */
+	HPI_ERROR_INVALID_CONTROL_VALUE = 402,
+	/** Control attribute not supported by this control. */
+	HPI_ERROR_INVALID_CONTROL_ATTRIBUTE = 403,
+	/** Control is disabled. */
+	HPI_ERROR_CONTROL_DISABLED = 404,
+	/** I2C transaction failed due to a missing ACK. */
+	HPI_ERROR_CONTROL_I2C_MISSING_ACK = 405,
+	/** Control attribute is valid, but not supported by this hardware. */
+	HPI_ERROR_UNSUPPORTED_CONTROL_ATTRIBUTE = 406,
+	/** Control is busy, or coming out of
+	reset and cannot be accessed at this time. */
+	HPI_ERROR_CONTROL_NOT_READY = 407,
+
+	/** Non volatile memory */
+	HPI_ERROR_NVMEM_BUSY = 450,
+	HPI_ERROR_NVMEM_FULL = 451,
+	HPI_ERROR_NVMEM_FAIL = 452,
+
+	/** I2C */
+	HPI_ERROR_I2C_MISSING_ACK = HPI_ERROR_CONTROL_I2C_MISSING_ACK,
+	HPI_ERROR_I2C_BAD_ADR = 460,
+
+	/** Entity errors */
+	HPI_ERROR_ENTITY_TYPE_MISMATCH = 470,
+	HPI_ERROR_ENTITY_ITEM_COUNT = 471,
+	HPI_ERROR_ENTITY_TYPE_INVALID = 472,
+	HPI_ERROR_ENTITY_ROLE_INVALID = 473,
+
+	/* AES18 specific errors were 500..507 */
+
+	/** custom error to use for debugging */
+	HPI_ERROR_CUSTOM = 600,
+
+	/** hpioct32.c can't obtain mutex */
+	HPI_ERROR_MUTEX_TIMEOUT = 700,
+
+	/** errors from HPI backends have values >= this */
+	HPI_ERROR_BACKEND_BASE = 900,
+
+	/** indicates a cached u16 value is invalid. */
+	HPI_ERROR_ILLEGAL_CACHE_VALUE = 0xffff
+};
+
+/** \defgroup maximums HPI maximum values
+\{
+*/
+/** Maximum number of adapters per HPI sub-system
+   WARNING: modifying this value changes the response structure size.*/
+#define HPI_MAX_ADAPTERS                20
+/** Maximum number of in or out streams per adapter */
+#define HPI_MAX_STREAMS                 16
+#define HPI_MAX_CHANNELS                2	/* per stream */
+#define HPI_MAX_NODES                   8	/* per mixer ? */
+#define HPI_MAX_CONTROLS                4	/* per node ? */
+/** maximum number of ancillary bytes per MPEG frame */
+#define HPI_MAX_ANC_BYTES_PER_FRAME     (64)
+#define HPI_STRING_LEN                  16
+
+/** Velocity units */
+#define HPI_OSTREAM_VELOCITY_UNITS      4096
+/** OutStream timescale units */
+#define HPI_OSTREAM_TIMESCALE_UNITS     10000
+/** OutStream timescale passthrough - turns timescaling on in passthough mode */
+#define HPI_OSTREAM_TIMESCALE_PASSTHROUGH       99999
+
+/**\}*/
+
+/* ////////////////////////////////////////////////////////////////////// */
+/* STRUCTURES */
+#ifndef DISABLE_PRAGMA_PACK1
+#pragma pack(push, 1)
+#endif
+
+/** Structure containing sample format information.
+    See also HPI_FormatCreate().
+  */
+struct hpi_format {
+	u32 sample_rate;
+				/**< 11025, 32000, 44100 ... */
+	u32 bit_rate;	      /**< for MPEG */
+	u32 attributes;
+				/**< Stereo/JointStereo/Mono */
+	u16 mode_legacy;
+				/**< Legacy ancillary mode or idle bit  */
+	u16 unused;	      /**< unused */
+	u16 channels; /**< 1,2..., (or ancillary mode or idle bit */
+	u16 format;   /**< HPI_FORMAT_PCM16, _MPEG etc. see #HPI_FORMATS. */
+};
+
+struct hpi_anc_frame {
+	u32 valid_bits_in_this_frame;
+	u8 b_data[HPI_MAX_ANC_BYTES_PER_FRAME];
+};
+
+/** An object for containing a single async event.
+*/
+struct hpi_async_event {
+	u16 event_type;	/**< type of event. \sa async_event  */
+	u16 sequence;  /**< sequence number, allows lost event detection */
+	u32 state;    /**< new state */
+	u32 h_object;	 /**< handle to the object returning the event. */
+	union {
+		struct {
+			u16 index; /**< GPIO bit index. */
+		} gpio;
+		struct {
+			u16 node_index;	/**< what node is the control on ? */
+			u16 node_type;	/**< what type of node is the control on ? */
+		} control;
+	} u;
+};
+
+/*/////////////////////////////////////////////////////////////////////////// */
+/* Public HPI Entity related definitions                                     */
+
+struct hpi_entity;
+
+enum e_entity_type {
+	entity_type_null,
+	entity_type_sequence,	/* sequence of potentially heterogeneous TLV entities */
+
+	entity_type_reference,	/* refers to a TLV entity or NULL */
+
+	entity_type_int,	/* 32 bit */
+	entity_type_float,	/* ieee754 binary 32 bit encoding */
+	entity_type_double,
+
+	entity_type_cstring,
+	entity_type_octet,
+	entity_type_ip4_address,
+	entity_type_ip6_address,
+	entity_type_mac_address,
+
+	LAST_ENTITY_TYPE
+};
+
+enum e_entity_role {
+	entity_role_null,
+	entity_role_value,
+	entity_role_classname,
+
+	entity_role_units,
+	entity_role_flags,
+	entity_role_range,
+
+	entity_role_mapping,
+	entity_role_enum,
+
+	entity_role_instance_of,
+	entity_role_depends_on,
+	entity_role_member_of_group,
+	entity_role_value_constraint,
+	entity_role_parameter_port,
+
+	entity_role_block,
+	entity_role_node_group,
+	entity_role_audio_port,
+	entity_role_clock_port,
+	LAST_ENTITY_ROLE
+};
+
+/* skip host side function declarations for
+   DSP compile and documentation extraction */
+
+struct hpi_hsubsys {
+	int not_really_used;
+};
+
+#ifndef DISABLE_PRAGMA_PACK1
+#pragma pack(pop)
+#endif
+
+/*////////////////////////////////////////////////////////////////////////// */
+/* HPI FUNCTIONS */
+
+/*/////////////////////////// */
+/* DATA and FORMAT and STREAM */
+
+u16 hpi_stream_estimate_buffer_size(struct hpi_format *pF,
+	u32 host_polling_rate_in_milli_seconds, u32 *recommended_buffer_size);
+
+/*/////////// */
+/* SUB SYSTEM */
+struct hpi_hsubsys *hpi_subsys_create(void
+	);
+
+void hpi_subsys_free(const struct hpi_hsubsys *ph_subsys);
+
+u16 hpi_subsys_get_version(const struct hpi_hsubsys *ph_subsys,
+	u32 *pversion);
+
+u16 hpi_subsys_get_version_ex(const struct hpi_hsubsys *ph_subsys,
+	u32 *pversion_ex);
+
+u16 hpi_subsys_get_info(const struct hpi_hsubsys *ph_subsys, u32 *pversion,
+	u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length);
+
+u16 hpi_subsys_find_adapters(const struct hpi_hsubsys *ph_subsys,
+	u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length);
+
+u16 hpi_subsys_get_num_adapters(const struct hpi_hsubsys *ph_subsys,
+	int *pn_num_adapters);
+
+u16 hpi_subsys_get_adapter(const struct hpi_hsubsys *ph_subsys, int iterator,
+	u32 *padapter_index, u16 *pw_adapter_type);
+
+u16 hpi_subsys_ssx2_bypass(const struct hpi_hsubsys *ph_subsys, u16 bypass);
+
+u16 hpi_subsys_set_host_network_interface(const struct hpi_hsubsys *ph_subsys,
+	const char *sz_interface);
+
+/*///////// */
+/* ADAPTER */
+
+u16 hpi_adapter_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index);
+
+u16 hpi_adapter_close(const struct hpi_hsubsys *ph_subsys, u16 adapter_index);
+
+u16 hpi_adapter_get_info(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 *pw_num_outstreams, u16 *pw_num_instreams,
+	u16 *pw_version, u32 *pserial_number, u16 *pw_adapter_type);
+
+u16 hpi_adapter_get_module_by_index(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 module_index, u16 *pw_num_outputs,
+	u16 *pw_num_inputs, u16 *pw_version, u32 *pserial_number,
+	u16 *pw_module_type, u32 *ph_module);
+
+u16 hpi_adapter_set_mode(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u32 adapter_mode);
+
+u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u32 adapter_mode, u16 query_or_set);
+
+u16 hpi_adapter_get_mode(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u32 *padapter_mode);
+
+u16 hpi_adapter_get_assert(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 *assert_present, char *psz_assert,
+	u16 *pw_line_number);
+
+u16 hpi_adapter_get_assert_ex(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 *assert_present, char *psz_assert,
+	u32 *pline_number, u16 *pw_assert_on_dsp);
+
+u16 hpi_adapter_test_assert(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 assert_id);
+
+u16 hpi_adapter_enable_capability(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 capability, u32 key);
+
+u16 hpi_adapter_self_test(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index);
+
+u16 hpi_adapter_debug_read(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u32 dsp_address, char *p_bytes, int *count_bytes);
+
+u16 hpi_adapter_set_property(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 property, u16 paramter1, u16 paramter2);
+
+u16 hpi_adapter_get_property(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 property, u16 *pw_paramter1,
+	u16 *pw_paramter2);
+
+u16 hpi_adapter_enumerate_property(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 index, u16 what_to_enumerate,
+	u16 property_index, u32 *psetting);
+
+/*////////////// */
+/* NonVol Memory */
+u16 hpi_nv_memory_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u32 *ph_nv_memory, u16 *pw_size_in_bytes);
+
+u16 hpi_nv_memory_read_byte(const struct hpi_hsubsys *ph_subsys,
+	u32 h_nv_memory, u16 index, u16 *pw_data);
+
+u16 hpi_nv_memory_write_byte(const struct hpi_hsubsys *ph_subsys,
+	u32 h_nv_memory, u16 index, u16 data);
+
+/*////////////// */
+/* Digital I/O */
+u16 hpi_gpio_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u32 *ph_gpio, u16 *pw_number_input_bits, u16 *pw_number_output_bits);
+
+u16 hpi_gpio_read_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
+	u16 bit_index, u16 *pw_bit_data);
+
+u16 hpi_gpio_read_all_bits(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
+	u16 aw_all_bit_data[4]
+	);
+
+u16 hpi_gpio_write_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
+	u16 bit_index, u16 bit_data);
+
+u16 hpi_gpio_write_status(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
+	u16 aw_all_bit_data[4]
+	);
+
+/**********************/
+/* Async Event Object */
+/**********************/
+u16 hpi_async_event_open(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u32 *ph_async);
+
+u16 hpi_async_event_close(const struct hpi_hsubsys *ph_subsys, u32 h_async);
+
+u16 hpi_async_event_wait(const struct hpi_hsubsys *ph_subsys, u32 h_async,
+	u16 maximum_events, struct hpi_async_event *p_events,
+	u16 *pw_number_returned);
+
+u16 hpi_async_event_get_count(const struct hpi_hsubsys *ph_subsys,
+	u32 h_async, u16 *pw_count);
+
+u16 hpi_async_event_get(const struct hpi_hsubsys *ph_subsys, u32 h_async,
+	u16 maximum_events, struct hpi_async_event *p_events,
+	u16 *pw_number_returned);
+
+/*/////////// */
+/* WATCH-DOG  */
+u16 hpi_watchdog_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u32 *ph_watchdog);
+
+u16 hpi_watchdog_set_time(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog,
+	u32 time_millisec);
+
+u16 hpi_watchdog_ping(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog);
+
+/**************/
+/* OUT STREAM */
+/**************/
+u16 hpi_outstream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u16 outstream_index, u32 *ph_outstream);
+
+u16 hpi_outstream_close(const struct hpi_hsubsys *ph_subsys, u32 h_outstream);
+
+u16 hpi_outstream_get_info_ex(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_to_play,
+	u32 *psamples_played, u32 *pauxiliary_data_to_play);
+
+u16 hpi_outstream_write_buf(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, const u8 *pb_write_buf, u32 bytes_to_write,
+	const struct hpi_format *p_format);
+
+u16 hpi_outstream_start(const struct hpi_hsubsys *ph_subsys, u32 h_outstream);
+
+u16 hpi_outstream_wait_start(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream);
+
+u16 hpi_outstream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_outstream);
+
+u16 hpi_outstream_sinegen(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream);
+
+u16 hpi_outstream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_outstream);
+
+u16 hpi_outstream_query_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, struct hpi_format *p_format);
+
+u16 hpi_outstream_set_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, struct hpi_format *p_format);
+
+u16 hpi_outstream_set_punch_in_out(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 punch_in_sample, u32 punch_out_sample);
+
+u16 hpi_outstream_set_velocity(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, short velocity);
+
+u16 hpi_outstream_ancillary_reset(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u16 mode);
+
+u16 hpi_outstream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 *pframes_available);
+
+u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, struct hpi_anc_frame *p_anc_frame_buffer,
+	u32 anc_frame_buffer_size_in_bytes,
+	u32 number_of_ancillary_frames_to_read);
+
+u16 hpi_outstream_set_time_scale(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 time_scaleX10000);
+
+u16 hpi_outstream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 size_in_bytes);
+
+u16 hpi_outstream_host_buffer_free(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream);
+
+u16 hpi_outstream_group_add(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 h_stream);
+
+u16 hpi_outstream_group_get_map(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 *poutstream_map, u32 *pinstream_map);
+
+u16 hpi_outstream_group_reset(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream);
+
+/*////////// */
+/* IN_STREAM */
+u16 hpi_instream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u16 instream_index, u32 *ph_instream);
+
+u16 hpi_instream_close(const struct hpi_hsubsys *ph_subsys, u32 h_instream);
+
+u16 hpi_instream_query_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, const struct hpi_format *p_format);
+
+u16 hpi_instream_set_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, const struct hpi_format *p_format);
+
+u16 hpi_instream_read_buf(const struct hpi_hsubsys *ph_subsys, u32 h_instream,
+	u8 *pb_read_buf, u32 bytes_to_read);
+
+u16 hpi_instream_start(const struct hpi_hsubsys *ph_subsys, u32 h_instream);
+
+u16 hpi_instream_wait_start(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream);
+
+u16 hpi_instream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_instream);
+
+u16 hpi_instream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_instream);
+
+u16 hpi_instream_get_info_ex(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_recorded,
+	u32 *psamples_recorded, u32 *pauxiliary_data_recorded);
+
+u16 hpi_instream_ancillary_reset(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u16 bytes_per_frame, u16 mode, u16 alignment,
+	u16 idle_bit);
+
+u16 hpi_instream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u32 *pframe_space);
+
+u16 hpi_instream_ancillary_write(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, const struct hpi_anc_frame *p_anc_frame_buffer,
+	u32 anc_frame_buffer_size_in_bytes,
+	u32 number_of_ancillary_frames_to_write);
+
+u16 hpi_instream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u32 size_in_bytes);
+
+u16 hpi_instream_host_buffer_free(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream);
+
+u16 hpi_instream_group_add(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u32 h_stream);
+
+u16 hpi_instream_group_get_map(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u32 *poutstream_map, u32 *pinstream_map);
+
+u16 hpi_instream_group_reset(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream);
+
+/*********/
+/* MIXER */
+/*********/
+u16 hpi_mixer_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u32 *ph_mixer);
+
+u16 hpi_mixer_close(const struct hpi_hsubsys *ph_subsys, u32 h_mixer);
+
+u16 hpi_mixer_get_control(const struct hpi_hsubsys *ph_subsys, u32 h_mixer,
+	u16 src_node_type, u16 src_node_type_index, u16 dst_node_type,
+	u16 dst_node_type_index, u16 control_type, u32 *ph_control);
+
+u16 hpi_mixer_get_control_by_index(const struct hpi_hsubsys *ph_subsys,
+	u32 h_mixer, u16 control_index, u16 *pw_src_node_type,
+	u16 *pw_src_node_index, u16 *pw_dst_node_type, u16 *pw_dst_node_index,
+	u16 *pw_control_type, u32 *ph_control);
+
+u16 hpi_mixer_store(const struct hpi_hsubsys *ph_subsys, u32 h_mixer,
+	enum HPI_MIXER_STORE_COMMAND command, u16 index);
+/*************************/
+/* mixer CONTROLS                */
+/*************************/
+/*************************/
+/* volume control                */
+/*************************/
+u16 hpi_volume_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_gain0_01dB[HPI_MAX_CHANNELS]
+	);
+
+u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_gain0_01dB_out[HPI_MAX_CHANNELS]
+	);
+
+#define hpi_volume_get_range hpi_volume_query_range
+u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB);
+
+u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_volume, u32 *p_channels);
+
+u16 hpi_volume_auto_fade(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_stop_gain0_01dB[HPI_MAX_CHANNELS], u32 duration_ms);
+
+u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, short an_stop_gain0_01dB[HPI_MAX_CHANNELS],
+	u32 duration_ms, u16 profile);
+
+/*************************/
+/* level control         */
+/*************************/
+u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB);
+
+u16 hpi_level_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_gain0_01dB[HPI_MAX_CHANNELS]
+	);
+
+u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_gain0_01dB_out[HPI_MAX_CHANNELS]
+	);
+
+/*************************/
+/* meter control                 */
+/*************************/
+u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_meter, u32 *p_channels);
+
+u16 hpi_meter_get_peak(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_peak0_01dB_out[HPI_MAX_CHANNELS]
+	);
+
+u16 hpi_meter_get_rms(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_peak0_01dB_out[HPI_MAX_CHANNELS]
+	);
+
+u16 hpi_meter_set_peak_ballistics(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 attack, u16 decay);
+
+u16 hpi_meter_set_rms_ballistics(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 attack, u16 decay);
+
+u16 hpi_meter_get_peak_ballistics(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *attack, u16 *decay);
+
+u16 hpi_meter_get_rms_ballistics(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *attack, u16 *decay);
+
+/*************************/
+/* channel mode control  */
+/*************************/
+u16 hpi_channel_mode_query_mode(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_mode, const u32 index, u16 *pw_mode);
+
+u16 hpi_channel_mode_set(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 mode);
+
+u16 hpi_channel_mode_get(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 *mode);
+
+/*************************/
+/* Tuner control                 */
+/*************************/
+u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_tuner, const u32 index, u16 *pw_band);
+
+u16 hpi_tuner_set_band(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 band);
+
+u16 hpi_tuner_get_band(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 *pw_band);
+
+u16 hpi_tuner_query_frequency(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_tuner, const u32 index, const u16 band, u32 *pfreq);
+
+u16 hpi_tuner_set_frequency(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 freq_ink_hz);
+
+u16 hpi_tuner_get_frequency(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pw_freq_ink_hz);
+
+u16 hpi_tuner_getRF_level(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short *pw_level);
+
+u16 hpi_tuner_get_rawRF_level(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, short *pw_level);
+
+u16 hpi_tuner_query_gain(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_tuner, const u32 index, u16 *pw_gain);
+
+u16 hpi_tuner_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short gain);
+
+u16 hpi_tuner_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short *pn_gain);
+
+u16 hpi_tuner_get_status(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 *pw_status_mask, u16 *pw_status);
+
+u16 hpi_tuner_set_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 mode, u32 value);
+
+u16 hpi_tuner_get_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 mode, u32 *pn_value);
+
+u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	char *p_rds_data);
+
+u16 hpi_tuner_query_deemphasis(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_tuner, const u32 index, const u16 band, u32 *pdeemphasis);
+
+u16 hpi_tuner_set_deemphasis(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 deemphasis);
+u16 hpi_tuner_get_deemphasis(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pdeemphasis);
+
+u16 hpi_tuner_query_program(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_tuner, u32 *pbitmap_program);
+
+u16 hpi_tuner_set_program(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 program);
+
+u16 hpi_tuner_get_program(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 *pprogram);
+
+u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, char *psz_dsp_version, const u32 string_size);
+
+u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, char *psz_sdk_version, const u32 string_size);
+
+u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pquality);
+
+/****************************/
+/* PADs control             */
+/****************************/
+
+u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, char *psz_string, const u32 string_length);
+
+u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	char *psz_string, const u32 string_length);
+
+u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	char *psz_string, const u32 string_length);
+
+u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	char *psz_string, const u32 string_length);
+
+u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *ppTY);
+
+u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 *ppI);
+
+u16 HPI_PAD__get_program_type_string(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, const u32 data_type, const u32 pTY, char *psz_string,
+	const u32 string_length);
+
+/****************************/
+/* AES/EBU Receiver control */
+/****************************/
+u16 HPI_AESEBU__receiver_query_format(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_aes_rx, const u32 index, u16 *pw_format);
+
+u16 HPI_AESEBU__receiver_set_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 source);
+
+u16 HPI_AESEBU__receiver_get_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_source);
+
+u16 HPI_AESEBU__receiver_get_sample_rate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *psample_rate);
+
+u16 HPI_AESEBU__receiver_get_user_data(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, u16 *pw_data);
+
+u16 HPI_AESEBU__receiver_get_channel_status(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, u16 index, u16 *pw_data);
+
+u16 HPI_AESEBU__receiver_get_error_status(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_error_data);
+
+/*******************************/
+/* AES/EBU Transmitter control */
+/*******************************/
+u16 HPI_AESEBU__transmitter_set_sample_rate(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, u32 sample_rate);
+
+u16 HPI_AESEBU__transmitter_set_user_data(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, u16 data);
+
+u16 HPI_AESEBU__transmitter_set_channel_status(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, u16 index, u16 data);
+
+u16 HPI_AESEBU__transmitter_get_channel_status(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, u16 index, u16 *pw_data);
+
+u16 HPI_AESEBU__transmitter_query_format(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_aes_tx, const u32 index, u16 *pw_format);
+
+u16 HPI_AESEBU__transmitter_set_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 output_format);
+
+u16 HPI_AESEBU__transmitter_get_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_output_format);
+
+/***********************/
+/* multiplexer control */
+/***********************/
+u16 hpi_multiplexer_set_source(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 source_node_type, u16 source_node_index);
+
+u16 hpi_multiplexer_get_source(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *source_node_type, u16 *source_node_index);
+
+u16 hpi_multiplexer_query_source(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, u16 *source_node_type,
+	u16 *source_node_index);
+
+/***************/
+/* VOX control */
+/***************/
+u16 hpi_vox_set_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_gain0_01dB);
+
+u16 hpi_vox_get_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short *an_gain0_01dB);
+
+/*********************/
+/* Bitstream control */
+/*********************/
+u16 hpi_bitstream_set_clock_edge(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 edge_type);
+
+u16 hpi_bitstream_set_data_polarity(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 polarity);
+
+u16 hpi_bitstream_get_activity(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_clk_activity, u16 *pw_data_activity);
+
+/***********************/
+/* SampleClock control */
+/***********************/
+
+u16 hpi_sample_clock_query_source(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_clock, const u32 index, u16 *pw_source);
+
+u16 hpi_sample_clock_set_source(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 source);
+
+u16 hpi_sample_clock_get_source(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_source);
+
+u16 hpi_sample_clock_query_source_index(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_clock, const u32 index, const u32 source,
+	u16 *pw_source_index);
+
+u16 hpi_sample_clock_set_source_index(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 source_index);
+
+u16 hpi_sample_clock_get_source_index(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_source_index);
+
+u16 hpi_sample_clock_get_sample_rate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *psample_rate);
+
+u16 hpi_sample_clock_query_local_rate(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_clock, const u32 index, u32 *psource);
+
+u16 hpi_sample_clock_set_local_rate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 sample_rate);
+
+u16 hpi_sample_clock_get_local_rate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *psample_rate);
+
+u16 hpi_sample_clock_set_auto(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 enable);
+
+u16 hpi_sample_clock_get_auto(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *penable);
+
+u16 hpi_sample_clock_set_local_rate_lock(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 lock);
+
+u16 hpi_sample_clock_get_local_rate_lock(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *plock);
+
+/***********************/
+/* Microphone control */
+/***********************/
+u16 hpi_microphone_set_phantom_power(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 on_off);
+
+u16 hpi_microphone_get_phantom_power(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_on_off);
+
+/*******************************
+  Parametric Equalizer control
+*******************************/
+u16 hpi_parametricEQ__get_info(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_number_of_bands, u16 *pw_enabled);
+
+u16 hpi_parametricEQ__set_state(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 on_off);
+
+u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, u16 type, u32 frequency_hz, short q100,
+	short gain0_01dB);
+
+u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, u16 *pn_type, u32 *pfrequency_hz,
+	short *pnQ100, short *pn_gain0_01dB);
+
+u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, short coeffs[5]
+	);
+
+/*******************************
+  Compressor Expander control
+*******************************/
+
+u16 hpi_compander_set(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 attack, u16 decay, short ratio100, short threshold0_01dB,
+	short makeup_gain0_01dB);
+
+u16 hpi_compander_get(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 *pw_attack, u16 *pw_decay, short *pw_ratio100,
+	short *pn_threshold0_01dB, short *pn_makeup_gain0_01dB);
+
+/*******************************
+  Cobranet HMI control
+*******************************/
+u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 hmi_address, u32 byte_count, u8 *pb_data);
+
+u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 hmi_address, u32 max_byte_count, u32 *pbyte_count, u8 *pb_data);
+
+u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pstatus, u32 *preadable_size,
+	u32 *pwriteable_size);
+
+/*Read the current IP address
+*/
+u16 hpi_cobranet_getI_paddress(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pi_paddress);
+
+/* Write the current IP address
+*/
+u16 hpi_cobranet_setI_paddress(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 i_paddress);
+
+/* Read the static IP address
+*/
+u16 hpi_cobranet_get_staticI_paddress(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pi_paddress);
+
+/* Write the static IP address
+*/
+u16 hpi_cobranet_set_staticI_paddress(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 i_paddress);
+
+/* Read the MAC address
+*/
+u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pmAC_MS_bs, u32 *pmAC_LS_bs);
+
+/*******************************
+  Tone Detector control
+*******************************/
+u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys, u32 hC,
+	u32 *state);
+
+u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys, u32 hC,
+	u32 enable);
+
+u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys, u32 hC,
+	u32 *enable);
+
+u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, u32 event_enable);
+
+u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, u32 *event_enable);
+
+u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, int threshold);
+
+u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, int *threshold);
+
+u16 hpi_tone_detector_get_frequency(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, u32 index, u32 *frequency);
+
+/*******************************
+  Silence Detector control
+*******************************/
+u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, u32 *state);
+
+u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, u32 enable);
+
+u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, u32 *enable);
+
+u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, u32 event_enable);
+
+u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, u32 *event_enable);
+
+u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, u32 delay);
+
+u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, u32 *delay);
+
+u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, int threshold);
+
+u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 hC, int *threshold);
+
+/*******************************
+  Universal control
+*******************************/
+u16 hpi_entity_find_next(struct hpi_entity *container_entity,
+	enum e_entity_type type, enum e_entity_role role, int recursive_flag,
+	struct hpi_entity **current_match);
+
+u16 hpi_entity_copy_value_from(struct hpi_entity *entity,
+	enum e_entity_type type, size_t item_count, void *value_dst_p);
+
+u16 hpi_entity_unpack(struct hpi_entity *entity, enum e_entity_type *type,
+	size_t *items, enum e_entity_role *role, void **value);
+
+u16 hpi_entity_alloc_and_pack(const enum e_entity_type type,
+	const size_t item_count, const enum e_entity_role role, void *value,
+	struct hpi_entity **entity);
+
+void hpi_entity_free(struct hpi_entity *entity);
+
+u16 hpi_universal_info(const struct hpi_hsubsys *ph_subsys, u32 hC,
+	struct hpi_entity **info);
+
+u16 hpi_universal_get(const struct hpi_hsubsys *ph_subsys, u32 hC,
+	struct hpi_entity **value);
+
+u16 hpi_universal_set(const struct hpi_hsubsys *ph_subsys, u32 hC,
+	struct hpi_entity *value);
+
+/*/////////// */
+/* DSP CLOCK  */
+/*/////////// */
+u16 hpi_clock_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u32 *ph_dsp_clock);
+
+u16 hpi_clock_set_time(const struct hpi_hsubsys *ph_subsys, u32 h_clock,
+	u16 hour, u16 minute, u16 second, u16 milli_second);
+
+u16 hpi_clock_get_time(const struct hpi_hsubsys *ph_subsys, u32 h_clock,
+	u16 *pw_hour, u16 *pw_minute, u16 *pw_second, u16 *pw_milli_second);
+
+/*/////////// */
+/* PROFILE        */
+/*/////////// */
+u16 hpi_profile_open_all(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 profile_index, u32 *ph_profile,
+	u16 *pw_max_profiles);
+
+u16 hpi_profile_get(const struct hpi_hsubsys *ph_subsys, u32 h_profile,
+	u16 index, u16 *pw_seconds, u32 *pmicro_seconds, u32 *pcall_count,
+	u32 *pmax_micro_seconds, u32 *pmin_micro_seconds);
+
+u16 hpi_profile_start_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile);
+
+u16 hpi_profile_stop_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile);
+
+u16 hpi_profile_get_name(const struct hpi_hsubsys *ph_subsys, u32 h_profile,
+	u16 index, char *sz_profile_name, u16 profile_name_length);
+
+u16 hpi_profile_get_utilization(const struct hpi_hsubsys *ph_subsys,
+	u32 h_profile, u32 *putilization);
+
+/*//////////////////// */
+/* UTILITY functions */
+
+u16 hpi_format_create(struct hpi_format *p_format, u16 channels, u16 format,
+	u32 sample_rate, u32 bit_rate, u32 attributes);
+
+/* Until it's verified, this function is for Windows OSs only */
+
+#endif	 /*_H_HPI_ */
+/*
+///////////////////////////////////////////////////////////////////////////////
+// See CVS for history.  Last complete set in rev 1.146
+////////////////////////////////////////////////////////////////////////////////
+*/

+ 1840 - 0
sound/pci/asihpi/hpi6000.c

@@ -0,0 +1,1840 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+ Hardware Programming Interface (HPI) for AudioScience ASI6200 series adapters.
+ These PCI bus adapters are based on the TI C6711 DSP.
+
+ Exported functions:
+ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
+
+ #defines
+ HIDE_PCI_ASSERTS to show the PCI asserts
+ PROFILE_DSP2 get profile data from DSP2 if present (instead of DSP 1)
+
+(C) Copyright AudioScience Inc. 1998-2003
+*******************************************************************************/
+#define SOURCEFILE_NAME "hpi6000.c"
+
+#include "hpi_internal.h"
+#include "hpimsginit.h"
+#include "hpidebug.h"
+#include "hpi6000.h"
+#include "hpidspcd.h"
+#include "hpicmn.h"
+
+#define HPI_HIF_BASE (0x00000200)	/* start of C67xx internal RAM */
+#define HPI_HIF_ADDR(member) \
+	(HPI_HIF_BASE + offsetof(struct hpi_hif_6000, member))
+#define HPI_HIF_ERROR_MASK      0x4000
+
+/* HPI6000 specific error codes */
+
+#define HPI6000_ERROR_BASE                              900
+#define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT             901
+#define HPI6000_ERROR_MSG_RESP_SEND_MSG_ACK             902
+#define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK             903
+#define HPI6000_ERROR_MSG_GET_ADR                       904
+#define HPI6000_ERROR_RESP_GET_ADR                      905
+#define HPI6000_ERROR_MSG_RESP_BLOCKWRITE32             906
+#define HPI6000_ERROR_MSG_RESP_BLOCKREAD32              907
+#define HPI6000_ERROR_MSG_INVALID_DSP_INDEX             908
+#define HPI6000_ERROR_CONTROL_CACHE_PARAMS              909
+
+#define HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT            911
+#define HPI6000_ERROR_SEND_DATA_ACK                     912
+#define HPI6000_ERROR_SEND_DATA_ADR                     913
+#define HPI6000_ERROR_SEND_DATA_TIMEOUT                 914
+#define HPI6000_ERROR_SEND_DATA_CMD                     915
+#define HPI6000_ERROR_SEND_DATA_WRITE                   916
+#define HPI6000_ERROR_SEND_DATA_IDLECMD                 917
+#define HPI6000_ERROR_SEND_DATA_VERIFY                  918
+
+#define HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT             921
+#define HPI6000_ERROR_GET_DATA_ACK                      922
+#define HPI6000_ERROR_GET_DATA_CMD                      923
+#define HPI6000_ERROR_GET_DATA_READ                     924
+#define HPI6000_ERROR_GET_DATA_IDLECMD                  925
+
+#define HPI6000_ERROR_CONTROL_CACHE_ADDRLEN             951
+#define HPI6000_ERROR_CONTROL_CACHE_READ                952
+#define HPI6000_ERROR_CONTROL_CACHE_FLUSH               953
+
+#define HPI6000_ERROR_MSG_RESP_GETRESPCMD               961
+#define HPI6000_ERROR_MSG_RESP_IDLECMD                  962
+#define HPI6000_ERROR_MSG_RESP_BLOCKVERIFY32            963
+
+/* adapter init errors */
+#define HPI6000_ERROR_UNHANDLED_SUBSYS_ID               930
+
+/* can't access PCI2040 */
+#define HPI6000_ERROR_INIT_PCI2040                      931
+/* can't access DSP HPI i/f */
+#define HPI6000_ERROR_INIT_DSPHPI                       932
+/* can't access internal DSP memory */
+#define HPI6000_ERROR_INIT_DSPINTMEM                    933
+/* can't access SDRAM - test#1 */
+#define HPI6000_ERROR_INIT_SDRAM1                       934
+/* can't access SDRAM - test#2 */
+#define HPI6000_ERROR_INIT_SDRAM2                       935
+
+#define HPI6000_ERROR_INIT_VERIFY                       938
+
+#define HPI6000_ERROR_INIT_NOACK                        939
+
+#define HPI6000_ERROR_INIT_PLDTEST1                     941
+#define HPI6000_ERROR_INIT_PLDTEST2                     942
+
+/* local defines */
+
+#define HIDE_PCI_ASSERTS
+#define PROFILE_DSP2
+
+/* for PCI2040 i/f chip */
+/* HPI CSR registers */
+/* word offsets from CSR base */
+/* use when io addresses defined as u32 * */
+
+#define INTERRUPT_EVENT_SET     0
+#define INTERRUPT_EVENT_CLEAR   1
+#define INTERRUPT_MASK_SET      2
+#define INTERRUPT_MASK_CLEAR    3
+#define HPI_ERROR_REPORT        4
+#define HPI_RESET               5
+#define HPI_DATA_WIDTH          6
+
+#define MAX_DSPS 2
+/* HPI registers, spaced 8K bytes = 2K words apart */
+#define DSP_SPACING             0x800
+
+#define CONTROL                 0x0000
+#define ADDRESS                 0x0200
+#define DATA_AUTOINC            0x0400
+#define DATA                    0x0600
+
+#define TIMEOUT 500000
+
+struct dsp_obj {
+	__iomem u32 *prHPI_control;
+	__iomem u32 *prHPI_address;
+	__iomem u32 *prHPI_data;
+	__iomem u32 *prHPI_data_auto_inc;
+	char c_dsp_rev;		/*A, B */
+	u32 control_cache_address_on_dsp;
+	u32 control_cache_length_on_dsp;
+	struct hpi_adapter_obj *pa_parent_adapter;
+};
+
+struct hpi_hw_obj {
+	__iomem u32 *dw2040_HPICSR;
+	__iomem u32 *dw2040_HPIDSP;
+
+	u16 num_dsp;
+	struct dsp_obj ado[MAX_DSPS];
+
+	u32 message_buffer_address_on_dsp;
+	u32 response_buffer_address_on_dsp;
+	u32 pCI2040HPI_error_count;
+
+	struct hpi_control_cache_single control_cache[HPI_NMIXER_CONTROLS];
+	struct hpi_control_cache *p_cache;
+};
+
+static u16 hpi6000_dsp_block_write32(struct hpi_adapter_obj *pao,
+	u16 dsp_index, u32 hpi_address, u32 *source, u32 count);
+static u16 hpi6000_dsp_block_read32(struct hpi_adapter_obj *pao,
+	u16 dsp_index, u32 hpi_address, u32 *dest, u32 count);
+
+static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
+	u32 *pos_error_code);
+static short hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj *pao,
+	u16 read_or_write);
+#define H6READ 1
+#define H6WRITE 0
+
+static short hpi6000_update_control_cache(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm);
+static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
+	u16 dsp_index, struct hpi_message *phm, struct hpi_response *phr);
+
+static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
+	struct hpi_response *phr);
+
+static short hpi6000_wait_dsp_ack(struct hpi_adapter_obj *pao, u16 dsp_index,
+	u32 ack_value);
+
+static short hpi6000_send_host_command(struct hpi_adapter_obj *pao,
+	u16 dsp_index, u32 host_cmd);
+
+static void hpi6000_send_dsp_interrupt(struct dsp_obj *pdo);
+
+static short hpi6000_send_data(struct hpi_adapter_obj *pao, u16 dsp_index,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static short hpi6000_get_data(struct hpi_adapter_obj *pao, u16 dsp_index,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void hpi_write_word(struct dsp_obj *pdo, u32 address, u32 data);
+
+static u32 hpi_read_word(struct dsp_obj *pdo, u32 address);
+
+static void hpi_write_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
+	u32 length);
+
+static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
+	u32 length);
+
+static void subsys_create_adapter(struct hpi_message *phm,
+	struct hpi_response *phr);
+
+static void subsys_delete_adapter(struct hpi_message *phm,
+	struct hpi_response *phr);
+
+static void adapter_get_asserts(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static short create_adapter_obj(struct hpi_adapter_obj *pao,
+	u32 *pos_error_code);
+
+/* local globals */
+
+static u16 gw_pci_read_asserts;	/* used to count PCI2040 errors */
+static u16 gw_pci_write_asserts;	/* used to count PCI2040 errors */
+
+static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
+{
+
+	switch (phm->function) {
+	case HPI_SUBSYS_OPEN:
+	case HPI_SUBSYS_CLOSE:
+	case HPI_SUBSYS_GET_INFO:
+	case HPI_SUBSYS_DRIVER_UNLOAD:
+	case HPI_SUBSYS_DRIVER_LOAD:
+	case HPI_SUBSYS_FIND_ADAPTERS:
+		/* messages that should not get here */
+		phr->error = HPI_ERROR_UNIMPLEMENTED;
+		break;
+	case HPI_SUBSYS_CREATE_ADAPTER:
+		subsys_create_adapter(phm, phr);
+		break;
+	case HPI_SUBSYS_DELETE_ADAPTER:
+		subsys_delete_adapter(phm, phr);
+		break;
+	default:
+		phr->error = HPI_ERROR_INVALID_FUNC;
+		break;
+	}
+}
+
+static void control_message(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+
+	switch (phm->function) {
+	case HPI_CONTROL_GET_STATE:
+		if (pao->has_control_cache) {
+			u16 err;
+			err = hpi6000_update_control_cache(pao, phm);
+
+			if (err) {
+				phr->error = err;
+				break;
+			}
+
+			if (hpi_check_control_cache(((struct hpi_hw_obj *)
+						pao->priv)->p_cache, phm,
+					phr))
+				break;
+		}
+		hw_message(pao, phm, phr);
+		break;
+	case HPI_CONTROL_GET_INFO:
+		hw_message(pao, phm, phr);
+		break;
+	case HPI_CONTROL_SET_STATE:
+		hw_message(pao, phm, phr);
+		hpi_sync_control_cache(((struct hpi_hw_obj *)pao->priv)->
+			p_cache, phm, phr);
+		break;
+	default:
+		phr->error = HPI_ERROR_INVALID_FUNC;
+		break;
+	}
+}
+
+static void adapter_message(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	switch (phm->function) {
+	case HPI_ADAPTER_GET_INFO:
+		hw_message(pao, phm, phr);
+		break;
+	case HPI_ADAPTER_GET_ASSERT:
+		adapter_get_asserts(pao, phm, phr);
+		break;
+	case HPI_ADAPTER_OPEN:
+	case HPI_ADAPTER_CLOSE:
+	case HPI_ADAPTER_TEST_ASSERT:
+	case HPI_ADAPTER_SELFTEST:
+	case HPI_ADAPTER_GET_MODE:
+	case HPI_ADAPTER_SET_MODE:
+	case HPI_ADAPTER_FIND_OBJECT:
+	case HPI_ADAPTER_GET_PROPERTY:
+	case HPI_ADAPTER_SET_PROPERTY:
+	case HPI_ADAPTER_ENUM_PROPERTY:
+		hw_message(pao, phm, phr);
+		break;
+	default:
+		phr->error = HPI_ERROR_INVALID_FUNC;
+		break;
+	}
+}
+
+static void outstream_message(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	switch (phm->function) {
+	case HPI_OSTREAM_HOSTBUFFER_ALLOC:
+	case HPI_OSTREAM_HOSTBUFFER_FREE:
+		/* Don't let these messages go to the HW function because
+		 * they're called without allocating the spinlock.
+		 * For the HPI6000 adapters the HW would return
+		 * HPI_ERROR_INVALID_FUNC anyway.
+		 */
+		phr->error = HPI_ERROR_INVALID_FUNC;
+		break;
+	default:
+		hw_message(pao, phm, phr);
+		return;
+	}
+}
+
+static void instream_message(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+
+	switch (phm->function) {
+	case HPI_ISTREAM_HOSTBUFFER_ALLOC:
+	case HPI_ISTREAM_HOSTBUFFER_FREE:
+		/* Don't let these messages go to the HW function because
+		 * they're called without allocating the spinlock.
+		 * For the HPI6000 adapters the HW would return
+		 * HPI_ERROR_INVALID_FUNC anyway.
+		 */
+		phr->error = HPI_ERROR_INVALID_FUNC;
+		break;
+	default:
+		hw_message(pao, phm, phr);
+		return;
+	}
+}
+
+/************************************************************************/
+/** HPI_6000()
+ * Entry point from HPIMAN
+ * All calls to the HPI start here
+ */
+void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_adapter_obj *pao = NULL;
+
+	/* subsytem messages get executed by every HPI. */
+	/* All other messages are ignored unless the adapter index matches */
+	/* an adapter in the HPI */
+	HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->object, phm->function);
+
+	/* if Dsp has crashed then do not communicate with it any more */
+	if (phm->object != HPI_OBJ_SUBSYSTEM) {
+		pao = hpi_find_adapter(phm->adapter_index);
+		if (!pao) {
+			HPI_DEBUG_LOG(DEBUG,
+				" %d,%d refused, for another HPI?\n",
+				phm->object, phm->function);
+			return;
+		}
+
+		if (pao->dsp_crashed >= 10) {
+			hpi_init_response(phr, phm->object, phm->function,
+				HPI_ERROR_DSP_HARDWARE);
+			HPI_DEBUG_LOG(DEBUG, " %d,%d dsp crashed.\n",
+				phm->object, phm->function);
+			return;
+		}
+	}
+	/* Init default response including the size field */
+	if (phm->function != HPI_SUBSYS_CREATE_ADAPTER)
+		hpi_init_response(phr, phm->object, phm->function,
+			HPI_ERROR_PROCESSING_MESSAGE);
+
+	switch (phm->type) {
+	case HPI_TYPE_MESSAGE:
+		switch (phm->object) {
+		case HPI_OBJ_SUBSYSTEM:
+			subsys_message(phm, phr);
+			break;
+
+		case HPI_OBJ_ADAPTER:
+			phr->size =
+				sizeof(struct hpi_response_header) +
+				sizeof(struct hpi_adapter_res);
+			adapter_message(pao, phm, phr);
+			break;
+
+		case HPI_OBJ_CONTROL:
+			control_message(pao, phm, phr);
+			break;
+
+		case HPI_OBJ_OSTREAM:
+			outstream_message(pao, phm, phr);
+			break;
+
+		case HPI_OBJ_ISTREAM:
+			instream_message(pao, phm, phr);
+			break;
+
+		default:
+			hw_message(pao, phm, phr);
+			break;
+		}
+		break;
+
+	default:
+		phr->error = HPI_ERROR_INVALID_TYPE;
+		break;
+	}
+}
+
+/************************************************************************/
+/* SUBSYSTEM */
+
+/* create an adapter object and initialise it based on resource information
+ * passed in in the message
+ * NOTE - you cannot use this function AND the FindAdapters function at the
+ * same time, the application must use only one of them to get the adapters
+ */
+static void subsys_create_adapter(struct hpi_message *phm,
+	struct hpi_response *phr)
+{
+	/* create temp adapter obj, because we don't know what index yet */
+	struct hpi_adapter_obj ao;
+	struct hpi_adapter_obj *pao;
+	u32 os_error_code;
+	short error = 0;
+	u32 dsp_index = 0;
+
+	HPI_DEBUG_LOG(VERBOSE, "subsys_create_adapter\n");
+
+	memset(&ao, 0, sizeof(ao));
+
+	/* this HPI only creates adapters for TI/PCI2040 based devices */
+	if (phm->u.s.resource.bus_type != HPI_BUS_PCI)
+		return;
+	if (phm->u.s.resource.r.pci->vendor_id != HPI_PCI_VENDOR_ID_TI)
+		return;
+	if (phm->u.s.resource.r.pci->device_id != HPI_PCI_DEV_ID_PCI2040)
+		return;
+
+	ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL);
+	if (!ao.priv) {
+		HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n");
+		phr->error = HPI_ERROR_MEMORY_ALLOC;
+		return;
+	}
+
+	/* create the adapter object based on the resource information */
+	/*? memcpy(&ao.Pci,&phm->u.s.Resource.r.Pci,sizeof(ao.Pci)); */
+	ao.pci = *phm->u.s.resource.r.pci;
+
+	error = create_adapter_obj(&ao, &os_error_code);
+	if (!error)
+		error = hpi_add_adapter(&ao);
+	if (error) {
+		phr->u.s.data = os_error_code;
+		kfree(ao.priv);
+		phr->error = error;
+		return;
+	}
+	/* need to update paParentAdapter */
+	pao = hpi_find_adapter(ao.index);
+	if (!pao) {
+		/* We just added this adapter, why can't we find it!? */
+		HPI_DEBUG_LOG(ERROR, "lost adapter after boot\n");
+		phr->error = 950;
+		return;
+	}
+
+	for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) {
+		struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+		phw->ado[dsp_index].pa_parent_adapter = pao;
+	}
+
+	phr->u.s.aw_adapter_list[ao.index] = ao.adapter_type;
+	phr->u.s.adapter_index = ao.index;
+	phr->u.s.num_adapters++;
+	phr->error = 0;
+}
+
+static void subsys_delete_adapter(struct hpi_message *phm,
+	struct hpi_response *phr)
+{
+	struct hpi_adapter_obj *pao = NULL;
+	struct hpi_hw_obj *phw;
+
+	pao = hpi_find_adapter(phm->adapter_index);
+	if (!pao)
+		return;
+
+	phw = (struct hpi_hw_obj *)pao->priv;
+
+	if (pao->has_control_cache)
+		hpi_free_control_cache(phw->p_cache);
+
+	hpi_delete_adapter(pao);
+	kfree(phw);
+
+	phr->error = 0;
+}
+
+/* this routine is called from SubSysFindAdapter and SubSysCreateAdapter */
+static short create_adapter_obj(struct hpi_adapter_obj *pao,
+	u32 *pos_error_code)
+{
+	short boot_error = 0;
+	u32 dsp_index = 0;
+	u32 control_cache_size = 0;
+	u32 control_cache_count = 0;
+	struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+
+	/* init error reporting */
+	pao->dsp_crashed = 0;
+
+	/* The PCI2040 has the following address map */
+	/* BAR0 - 4K = HPI control and status registers on PCI2040 (HPI CSR) */
+	/* BAR1 - 32K = HPI registers on DSP */
+	phw->dw2040_HPICSR = pao->pci.ap_mem_base[0];
+	phw->dw2040_HPIDSP = pao->pci.ap_mem_base[1];
+	HPI_DEBUG_LOG(VERBOSE, "csr %p, dsp %p\n", phw->dw2040_HPICSR,
+		phw->dw2040_HPIDSP);
+
+	/* set addresses for the possible DSP HPI interfaces */
+	for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) {
+		phw->ado[dsp_index].prHPI_control =
+			phw->dw2040_HPIDSP + (CONTROL +
+			DSP_SPACING * dsp_index);
+
+		phw->ado[dsp_index].prHPI_address =
+			phw->dw2040_HPIDSP + (ADDRESS +
+			DSP_SPACING * dsp_index);
+		phw->ado[dsp_index].prHPI_data =
+			phw->dw2040_HPIDSP + (DATA + DSP_SPACING * dsp_index);
+
+		phw->ado[dsp_index].prHPI_data_auto_inc =
+			phw->dw2040_HPIDSP + (DATA_AUTOINC +
+			DSP_SPACING * dsp_index);
+
+		HPI_DEBUG_LOG(VERBOSE, "ctl %p, adr %p, dat %p, dat++ %p\n",
+			phw->ado[dsp_index].prHPI_control,
+			phw->ado[dsp_index].prHPI_address,
+			phw->ado[dsp_index].prHPI_data,
+			phw->ado[dsp_index].prHPI_data_auto_inc);
+
+		phw->ado[dsp_index].pa_parent_adapter = pao;
+	}
+
+	phw->pCI2040HPI_error_count = 0;
+	pao->has_control_cache = 0;
+
+	/* Set the default number of DSPs on this card */
+	/* This is (conditionally) adjusted after bootloading */
+	/* of the first DSP in the bootload section. */
+	phw->num_dsp = 1;
+
+	boot_error = hpi6000_adapter_boot_load_dsp(pao, pos_error_code);
+	if (boot_error)
+		return boot_error;
+
+	HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");
+
+	phw->message_buffer_address_on_dsp = 0L;
+	phw->response_buffer_address_on_dsp = 0L;
+
+	/* get info about the adapter by asking the adapter */
+	/* send a HPI_ADAPTER_GET_INFO message */
+	{
+		struct hpi_message hM;
+		struct hpi_response hR0;	/* response from DSP 0 */
+		struct hpi_response hR1;	/* response from DSP 1 */
+		u16 error = 0;
+
+		HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n");
+		memset(&hM, 0, sizeof(hM));
+		hM.type = HPI_TYPE_MESSAGE;
+		hM.size = sizeof(struct hpi_message);
+		hM.object = HPI_OBJ_ADAPTER;
+		hM.function = HPI_ADAPTER_GET_INFO;
+		hM.adapter_index = 0;
+		memset(&hR0, 0, sizeof(hR0));
+		memset(&hR1, 0, sizeof(hR1));
+		hR0.size = sizeof(hR0);
+		hR1.size = sizeof(hR1);
+
+		error = hpi6000_message_response_sequence(pao, 0, &hM, &hR0);
+		if (hR0.error) {
+			HPI_DEBUG_LOG(DEBUG, "message error %d\n", hR0.error);
+			return hR0.error;
+		}
+		if (phw->num_dsp == 2) {
+			error = hpi6000_message_response_sequence(pao, 1, &hM,
+				&hR1);
+			if (error)
+				return error;
+		}
+		pao->adapter_type = hR0.u.a.adapter_type;
+		pao->index = hR0.u.a.adapter_index;
+	}
+
+	memset(&phw->control_cache[0], 0,
+		sizeof(struct hpi_control_cache_single) *
+		HPI_NMIXER_CONTROLS);
+	/* Read the control cache length to figure out if it is turned on */
+	control_cache_size =
+		hpi_read_word(&phw->ado[0],
+		HPI_HIF_ADDR(control_cache_size_in_bytes));
+	if (control_cache_size) {
+		control_cache_count =
+			hpi_read_word(&phw->ado[0],
+			HPI_HIF_ADDR(control_cache_count));
+		pao->has_control_cache = 1;
+
+		phw->p_cache =
+			hpi_alloc_control_cache(control_cache_count,
+			control_cache_size, (struct hpi_control_cache_info *)
+			&phw->control_cache[0]
+			);
+	} else
+		pao->has_control_cache = 0;
+
+	HPI_DEBUG_LOG(DEBUG, "get adapter info ASI%04X index %d\n",
+		pao->adapter_type, pao->index);
+	pao->open = 0;	/* upon creation the adapter is closed */
+	return 0;
+}
+
+/************************************************************************/
+/* ADAPTER */
+
+static void adapter_get_asserts(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+#ifndef HIDE_PCI_ASSERTS
+	/* if we have PCI2040 asserts then collect them */
+	if ((gw_pci_read_asserts > 0) || (gw_pci_write_asserts > 0)) {
+		phr->u.a.serial_number =
+			gw_pci_read_asserts * 100 + gw_pci_write_asserts;
+		phr->u.a.adapter_index = 1;	/* assert count */
+		phr->u.a.adapter_type = -1;	/* "dsp index" */
+		strcpy(phr->u.a.sz_adapter_assert, "PCI2040 error");
+		gw_pci_read_asserts = 0;
+		gw_pci_write_asserts = 0;
+		phr->error = 0;
+	} else
+#endif
+		hw_message(pao, phm, phr);	/*get DSP asserts */
+
+	return;
+}
+
+/************************************************************************/
+/* LOW-LEVEL */
+
+static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
+	u32 *pos_error_code)
+{
+	struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+	short error;
+	u32 timeout;
+	u32 read = 0;
+	u32 i = 0;
+	u32 data = 0;
+	u32 j = 0;
+	u32 test_addr = 0x80000000;
+	u32 test_data = 0x00000001;
+	u32 dw2040_reset = 0;
+	u32 dsp_index = 0;
+	u32 endian = 0;
+	u32 adapter_info = 0;
+	u32 delay = 0;
+
+	struct dsp_code dsp_code;
+	u16 boot_load_family = 0;
+
+	/* NOTE don't use wAdapterType in this routine. It is not setup yet */
+
+	switch (pao->pci.subsys_device_id) {
+	case 0x5100:
+	case 0x5110:	/* ASI5100 revB or higher with C6711D */
+	case 0x6100:
+	case 0x6200:
+		boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200);
+		break;
+	case 0x8800:
+		boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x8800);
+		break;
+	default:
+		return HPI6000_ERROR_UNHANDLED_SUBSYS_ID;
+	}
+
+	/* reset all DSPs, indicate two DSPs are present
+	 * set RST3-=1 to disconnect HAD8 to set DSP in little endian mode
+	 */
+	endian = 0;
+	dw2040_reset = 0x0003000F;
+	iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
+
+	/* read back register to make sure PCI2040 chip is functioning
+	 * note that bits 4..15 are read-only and so should always return zero,
+	 * even though we wrote 1 to them
+	 */
+	for (i = 0; i < 1000; i++)
+		delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);
+	if (delay != dw2040_reset) {
+		HPI_DEBUG_LOG(ERROR, "INIT_PCI2040 %x %x\n", dw2040_reset,
+			delay);
+		return HPI6000_ERROR_INIT_PCI2040;
+	}
+
+	/* Indicate that DSP#0,1 is a C6X */
+	iowrite32(0x00000003, phw->dw2040_HPICSR + HPI_DATA_WIDTH);
+	/* set Bit30 and 29 - which will prevent Target aborts from being
+	 * issued upon HPI or GP error
+	 */
+	iowrite32(0x60000000, phw->dw2040_HPICSR + INTERRUPT_MASK_SET);
+
+	/* isolate DSP HAD8 line from PCI2040 so that
+	 * Little endian can be set by pullup
+	 */
+	dw2040_reset = dw2040_reset & (~(endian << 3));
+	iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
+
+	phw->ado[0].c_dsp_rev = 'B';	/* revB */
+	phw->ado[1].c_dsp_rev = 'B';	/* revB */
+
+	/*Take both DSPs out of reset, setting HAD8 to the correct Endian */
+	dw2040_reset = dw2040_reset & (~0x00000001);	/* start DSP 0 */
+	iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
+	dw2040_reset = dw2040_reset & (~0x00000002);	/* start DSP 1 */
+	iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
+
+	/* set HAD8 back to PCI2040, now that DSP set to little endian mode */
+	dw2040_reset = dw2040_reset & (~0x00000008);
+	iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
+	/*delay to allow DSP to get going */
+	for (i = 0; i < 100; i++)
+		delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);
+
+	/* loop through all DSPs, downloading DSP code */
+	for (dsp_index = 0; dsp_index < phw->num_dsp; dsp_index++) {
+		struct dsp_obj *pdo = &phw->ado[dsp_index];
+
+		/* configure DSP so that we download code into the SRAM */
+		/* set control reg for little endian, HWOB=1 */
+		iowrite32(0x00010001, pdo->prHPI_control);
+
+		/* test access to the HPI address register (HPIA) */
+		test_data = 0x00000001;
+		for (j = 0; j < 32; j++) {
+			iowrite32(test_data, pdo->prHPI_address);
+			data = ioread32(pdo->prHPI_address);
+			if (data != test_data) {
+				HPI_DEBUG_LOG(ERROR, "INIT_DSPHPI %x %x %x\n",
+					test_data, data, dsp_index);
+				return HPI6000_ERROR_INIT_DSPHPI;
+			}
+			test_data = test_data << 1;
+		}
+
+/* if C6713 the setup PLL to generate 225MHz from 25MHz.
+* Since the PLLDIV1 read is sometimes wrong, even on a C6713,
+* we're going to do this unconditionally
+*/
+/* PLLDIV1 should have a value of 8000 after reset */
+/*
+	if (HpiReadWord(pdo,0x01B7C118) == 0x8000)
+*/
+		{
+			/* C6713 datasheet says we cannot program PLL from HPI,
+			 * and indeed if we try to set the PLL multiply from the
+			 * HPI, the PLL does not seem to lock,
+			 * so we enable the PLL and use the default of x 7
+			 */
+			/* bypass PLL */
+			hpi_write_word(pdo, 0x01B7C100, 0x0000);
+			for (i = 0; i < 100; i++)
+				delay = ioread32(phw->dw2040_HPICSR +
+					HPI_RESET);
+
+			/*  ** use default of PLL  x7 ** */
+			/* EMIF = 225/3=75MHz */
+			hpi_write_word(pdo, 0x01B7C120, 0x8002);
+			/* peri = 225/2 */
+			hpi_write_word(pdo, 0x01B7C11C, 0x8001);
+			/* cpu  = 225/1 */
+			hpi_write_word(pdo, 0x01B7C118, 0x8000);
+			/* ~200us delay */
+			for (i = 0; i < 2000; i++)
+				delay = ioread32(phw->dw2040_HPICSR +
+					HPI_RESET);
+			/* PLL not bypassed */
+			hpi_write_word(pdo, 0x01B7C100, 0x0001);
+			/* ~200us delay */
+			for (i = 0; i < 2000; i++)
+				delay = ioread32(phw->dw2040_HPICSR +
+					HPI_RESET);
+		}
+
+		/* test r/w to internal DSP memory
+		 * C6711 has L2 cache mapped to 0x0 when reset
+		 *
+		 *  revB - because of bug 3.0.1 last HPI read
+		 * (before HPI address issued) must be non-autoinc
+		 */
+		/* test each bit in the 32bit word */
+		for (i = 0; i < 100; i++) {
+			test_addr = 0x00000000;
+			test_data = 0x00000001;
+			for (j = 0; j < 32; j++) {
+				hpi_write_word(pdo, test_addr + i, test_data);
+				data = hpi_read_word(pdo, test_addr + i);
+				if (data != test_data) {
+					HPI_DEBUG_LOG(ERROR,
+						"DSP mem %x %x %x %x\n",
+						test_addr + i, test_data,
+						data, dsp_index);
+
+					return HPI6000_ERROR_INIT_DSPINTMEM;
+				}
+				test_data = test_data << 1;
+			}
+		}
+
+		/* memory map of ASI6200
+		   00000000-0000FFFF    16Kx32 internal program
+		   01800000-019FFFFF    Internal peripheral
+		   80000000-807FFFFF    CE0 2Mx32 SDRAM running @ 100MHz
+		   90000000-9000FFFF    CE1 Async peripherals:
+
+		   EMIF config
+		   ------------
+		   Global EMIF control
+		   0 -
+		   1 -
+		   2 -
+		   3 CLK2EN = 1   CLKOUT2 enabled
+		   4 CLK1EN = 0   CLKOUT1 disabled
+		   5 EKEN = 1 <--!! C6713 specific, enables ECLKOUT
+		   6 -
+		   7 NOHOLD = 1   external HOLD disabled
+		   8 HOLDA = 0    HOLDA output is low
+		   9 HOLD = 0             HOLD input is low
+		   10 ARDY = 1    ARDY input is high
+		   11 BUSREQ = 0   BUSREQ output is low
+		   12,13 Reserved = 1
+		 */
+		hpi_write_word(pdo, 0x01800000, 0x34A8);
+
+		/* EMIF CE0 setup - 2Mx32 Sync DRAM
+		   31..28       Wr setup
+		   27..22       Wr strobe
+		   21..20       Wr hold
+		   19..16       Rd setup
+		   15..14       -
+		   13..8        Rd strobe
+		   7..4         MTYPE   0011            Sync DRAM 32bits
+		   3            Wr hold MSB
+		   2..0         Rd hold
+		 */
+		hpi_write_word(pdo, 0x01800008, 0x00000030);
+
+		/* EMIF SDRAM Extension
+		   31-21        0
+		   20           WR2RD = 0
+		   19-18        WR2DEAC = 1
+		   17           WR2WR = 0
+		   16-15        R2WDQM = 2
+		   14-12        RD2WR = 4
+		   11-10        RD2DEAC = 1
+		   9            RD2RD = 1
+		   8-7          THZP = 10b
+		   6-5          TWR  = 2-1 = 01b (tWR = 10ns)
+		   4            TRRD = 0b = 2 ECLK (tRRD = 14ns)
+		   3-1          TRAS = 5-1 = 100b (Tras=42ns = 5 ECLK)
+		   1            CAS latency = 3 ECLK
+		   (for Micron 2M32-7 operating at 100Mhz)
+		 */
+
+		/* need to use this else DSP code crashes */
+		hpi_write_word(pdo, 0x01800020, 0x001BDF29);
+
+		/* EMIF SDRAM control - set up for a 2Mx32 SDRAM (512x32x4 bank)
+		   31           -               -
+		   30           SDBSZ   1               4 bank
+		   29..28       SDRSZ   00              11 row address pins
+		   27..26       SDCSZ   01              8 column address pins
+		   25           RFEN    1               refersh enabled
+		   24           INIT    1               init SDRAM
+		   23..20       TRCD    0001
+		   19..16       TRP             0001
+		   15..12       TRC             0110
+		   11..0        -               -
+		 */
+		/*      need to use this else DSP code crashes */
+		hpi_write_word(pdo, 0x01800018, 0x47117000);
+
+		/* EMIF SDRAM Refresh Timing */
+		hpi_write_word(pdo, 0x0180001C, 0x00000410);
+
+		/*MIF CE1 setup - Async peripherals
+		   @100MHz bus speed, each cycle is 10ns,
+		   31..28       Wr setup  = 1
+		   27..22       Wr strobe = 3                   30ns
+		   21..20       Wr hold = 1
+		   19..16       Rd setup =1
+		   15..14       Ta = 2
+		   13..8        Rd strobe = 3                   30ns
+		   7..4         MTYPE   0010            Async 32bits
+		   3            Wr hold MSB =0
+		   2..0         Rd hold = 1
+		 */
+		{
+			u32 cE1 =
+				(1L << 28) | (3L << 22) | (1L << 20) | (1L <<
+				16) | (2L << 14) | (3L << 8) | (2L << 4) | 1L;
+			hpi_write_word(pdo, 0x01800004, cE1);
+		}
+
+		/* delay a little to allow SDRAM and DSP to "get going" */
+
+		for (i = 0; i < 1000; i++)
+			delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);
+
+		/* test access to SDRAM */
+		{
+			test_addr = 0x80000000;
+			test_data = 0x00000001;
+			/* test each bit in the 32bit word */
+			for (j = 0; j < 32; j++) {
+				hpi_write_word(pdo, test_addr, test_data);
+				data = hpi_read_word(pdo, test_addr);
+				if (data != test_data) {
+					HPI_DEBUG_LOG(ERROR,
+						"DSP dram %x %x %x %x\n",
+						test_addr, test_data, data,
+						dsp_index);
+
+					return HPI6000_ERROR_INIT_SDRAM1;
+				}
+				test_data = test_data << 1;
+			}
+			/* test every Nth address in the DRAM */
+#define DRAM_SIZE_WORDS 0x200000	/*2_mx32 */
+#define DRAM_INC 1024
+			test_addr = 0x80000000;
+			test_data = 0x0;
+			for (i = 0; i < DRAM_SIZE_WORDS; i = i + DRAM_INC) {
+				hpi_write_word(pdo, test_addr + i, test_data);
+				test_data++;
+			}
+			test_addr = 0x80000000;
+			test_data = 0x0;
+			for (i = 0; i < DRAM_SIZE_WORDS; i = i + DRAM_INC) {
+				data = hpi_read_word(pdo, test_addr + i);
+				if (data != test_data) {
+					HPI_DEBUG_LOG(ERROR,
+						"DSP dram %x %x %x %x\n",
+						test_addr + i, test_data,
+						data, dsp_index);
+					return HPI6000_ERROR_INIT_SDRAM2;
+				}
+				test_data++;
+			}
+
+		}
+
+		/* write the DSP code down into the DSPs memory */
+		/*HpiDspCode_Open(nBootLoadFamily,&DspCode,pdwOsErrorCode); */
+		dsp_code.ps_dev = pao->pci.p_os_data;
+
+		error = hpi_dsp_code_open(boot_load_family, &dsp_code,
+			pos_error_code);
+
+		if (error)
+			return error;
+
+		while (1) {
+			u32 length;
+			u32 address;
+			u32 type;
+			u32 *pcode;
+
+			error = hpi_dsp_code_read_word(&dsp_code, &length);
+			if (error)
+				break;
+			if (length == 0xFFFFFFFF)
+				break;	/* end of code */
+
+			error = hpi_dsp_code_read_word(&dsp_code, &address);
+			if (error)
+				break;
+			error = hpi_dsp_code_read_word(&dsp_code, &type);
+			if (error)
+				break;
+			error = hpi_dsp_code_read_block(length, &dsp_code,
+				&pcode);
+			if (error)
+				break;
+			error = hpi6000_dsp_block_write32(pao, (u16)dsp_index,
+				address, pcode, length);
+			if (error)
+				break;
+		}
+
+		if (error) {
+			hpi_dsp_code_close(&dsp_code);
+			return error;
+		}
+		/* verify that code was written correctly */
+		/* this time through, assume no errors in DSP code file/array */
+		hpi_dsp_code_rewind(&dsp_code);
+		while (1) {
+			u32 length;
+			u32 address;
+			u32 type;
+			u32 *pcode;
+
+			hpi_dsp_code_read_word(&dsp_code, &length);
+			if (length == 0xFFFFFFFF)
+				break;	/* end of code */
+
+			hpi_dsp_code_read_word(&dsp_code, &address);
+			hpi_dsp_code_read_word(&dsp_code, &type);
+			hpi_dsp_code_read_block(length, &dsp_code, &pcode);
+
+			for (i = 0; i < length; i++) {
+				data = hpi_read_word(pdo, address);
+				if (data != *pcode) {
+					error = HPI6000_ERROR_INIT_VERIFY;
+					HPI_DEBUG_LOG(ERROR,
+						"DSP verify %x %x %x %x\n",
+						address, *pcode, data,
+						dsp_index);
+					break;
+				}
+				pcode++;
+				address += 4;
+			}
+			if (error)
+				break;
+		}
+		hpi_dsp_code_close(&dsp_code);
+		if (error)
+			return error;
+
+		/* zero out the hostmailbox */
+		{
+			u32 address = HPI_HIF_ADDR(host_cmd);
+			for (i = 0; i < 4; i++) {
+				hpi_write_word(pdo, address, 0);
+				address += 4;
+			}
+		}
+		/* write the DSP number into the hostmailbox */
+		/* structure before starting the DSP */
+		hpi_write_word(pdo, HPI_HIF_ADDR(dsp_number), dsp_index);
+
+		/* write the DSP adapter Info into the */
+		/* hostmailbox before starting the DSP */
+		if (dsp_index > 0)
+			hpi_write_word(pdo, HPI_HIF_ADDR(adapter_info),
+				adapter_info);
+
+		/* step 3. Start code by sending interrupt */
+		iowrite32(0x00030003, pdo->prHPI_control);
+		for (i = 0; i < 10000; i++)
+			delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);
+
+		/* wait for a non-zero value in hostcmd -
+		 * indicating initialization is complete
+		 *
+		 * Init could take a while if DSP checks SDRAM memory
+		 * Was 200000. Increased to 2000000 for ASI8801 so we
+		 * don't get 938 errors.
+		 */
+		timeout = 2000000;
+		while (timeout) {
+			do {
+				read = hpi_read_word(pdo,
+					HPI_HIF_ADDR(host_cmd));
+			} while (--timeout
+				&& hpi6000_check_PCI2040_error_flag(pao,
+					H6READ));
+
+			if (read)
+				break;
+			/* The following is a workaround for bug #94:
+			 * Bluescreen on install and subsequent boots on a
+			 * DELL PowerEdge 600SC PC with 1.8GHz P4 and
+			 * ServerWorks chipset. Without this delay the system
+			 * locks up with a bluescreen (NOT GPF or pagefault).
+			 */
+			else
+				hpios_delay_micro_seconds(1000);
+		}
+		if (timeout == 0)
+			return HPI6000_ERROR_INIT_NOACK;
+
+		/* read the DSP adapter Info from the */
+		/* hostmailbox structure after starting the DSP */
+		if (dsp_index == 0) {
+			/*u32 dwTestData=0; */
+			u32 mask = 0;
+
+			adapter_info =
+				hpi_read_word(pdo,
+				HPI_HIF_ADDR(adapter_info));
+			if (HPI_ADAPTER_FAMILY_ASI
+				(HPI_HIF_ADAPTER_INFO_EXTRACT_ADAPTER
+					(adapter_info)) ==
+				HPI_ADAPTER_FAMILY_ASI(0x6200))
+				/* all 6200 cards have this many DSPs */
+				phw->num_dsp = 2;
+
+			/* test that the PLD is programmed */
+			/* and we can read/write 24bits */
+#define PLD_BASE_ADDRESS 0x90000000L	/*for ASI6100/6200/8800 */
+
+			switch (boot_load_family) {
+			case HPI_ADAPTER_FAMILY_ASI(0x6200):
+				/* ASI6100/6200 has 24bit path to FPGA */
+				mask = 0xFFFFFF00L;
+				/* ASI5100 uses AX6 code, */
+				/* but has no PLD r/w register to test */
+				if (HPI_ADAPTER_FAMILY_ASI(pao->pci.
+						subsys_device_id) ==
+					HPI_ADAPTER_FAMILY_ASI(0x5100))
+					mask = 0x00000000L;
+				break;
+			case HPI_ADAPTER_FAMILY_ASI(0x8800):
+				/* ASI8800 has 16bit path to FPGA */
+				mask = 0xFFFF0000L;
+				break;
+			}
+			test_data = 0xAAAAAA00L & mask;
+			/* write to 24 bit Debug register (D31-D8) */
+			hpi_write_word(pdo, PLD_BASE_ADDRESS + 4L, test_data);
+			read = hpi_read_word(pdo,
+				PLD_BASE_ADDRESS + 4L) & mask;
+			if (read != test_data) {
+				HPI_DEBUG_LOG(ERROR, "PLD %x %x\n", test_data,
+					read);
+				return HPI6000_ERROR_INIT_PLDTEST1;
+			}
+			test_data = 0x55555500L & mask;
+			hpi_write_word(pdo, PLD_BASE_ADDRESS + 4L, test_data);
+			read = hpi_read_word(pdo,
+				PLD_BASE_ADDRESS + 4L) & mask;
+			if (read != test_data) {
+				HPI_DEBUG_LOG(ERROR, "PLD %x %x\n", test_data,
+					read);
+				return HPI6000_ERROR_INIT_PLDTEST2;
+			}
+		}
+	}	/* for numDSP */
+	return 0;
+}
+
+#define PCI_TIMEOUT 100
+
+static int hpi_set_address(struct dsp_obj *pdo, u32 address)
+{
+	u32 timeout = PCI_TIMEOUT;
+
+	do {
+		iowrite32(address, pdo->prHPI_address);
+	} while (hpi6000_check_PCI2040_error_flag(pdo->pa_parent_adapter,
+			H6WRITE)
+		&& --timeout);
+
+	if (timeout)
+		return 0;
+
+	return 1;
+}
+
+/* write one word to the HPI port */
+static void hpi_write_word(struct dsp_obj *pdo, u32 address, u32 data)
+{
+	if (hpi_set_address(pdo, address))
+		return;
+	iowrite32(data, pdo->prHPI_data);
+}
+
+/* read one word from the HPI port */
+static u32 hpi_read_word(struct dsp_obj *pdo, u32 address)
+{
+	u32 data = 0;
+
+	if (hpi_set_address(pdo, address))
+		return 0;	/*? no way to return error */
+
+	/* take care of errata in revB DSP (2.0.1) */
+	data = ioread32(pdo->prHPI_data);
+	return data;
+}
+
+/* write a block of 32bit words to the DSP HPI port using auto-inc mode */
+static void hpi_write_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
+	u32 length)
+{
+	u16 length16 = length - 1;
+
+	if (length == 0)
+		return;
+
+	if (hpi_set_address(pdo, address))
+		return;
+
+	iowrite32_rep(pdo->prHPI_data_auto_inc, pdata, length16);
+
+	/* take care of errata in revB DSP (2.0.1) */
+	/* must end with non auto-inc */
+	iowrite32(*(pdata + length - 1), pdo->prHPI_data);
+}
+
+/** read a block of 32bit words from the DSP HPI port using auto-inc mode
+ */
+static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
+	u32 length)
+{
+	u16 length16 = length - 1;
+
+	if (length == 0)
+		return;
+
+	if (hpi_set_address(pdo, address))
+		return;
+
+	ioread32_rep(pdo->prHPI_data_auto_inc, pdata, length16);
+
+	/* take care of errata in revB DSP (2.0.1) */
+	/* must end with non auto-inc */
+	*(pdata + length - 1) = ioread32(pdo->prHPI_data);
+}
+
+static u16 hpi6000_dsp_block_write32(struct hpi_adapter_obj *pao,
+	u16 dsp_index, u32 hpi_address, u32 *source, u32 count)
+{
+	struct dsp_obj *pdo =
+		&(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+	u32 time_out = PCI_TIMEOUT;
+	int c6711_burst_size = 128;
+	u32 local_hpi_address = hpi_address;
+	int local_count = count;
+	int xfer_size;
+	u32 *pdata = source;
+
+	while (local_count) {
+		if (local_count > c6711_burst_size)
+			xfer_size = c6711_burst_size;
+		else
+			xfer_size = local_count;
+
+		time_out = PCI_TIMEOUT;
+		do {
+			hpi_write_block(pdo, local_hpi_address, pdata,
+				xfer_size);
+		} while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE)
+			&& --time_out);
+
+		if (!time_out)
+			break;
+		pdata += xfer_size;
+		local_hpi_address += sizeof(u32) * xfer_size;
+		local_count -= xfer_size;
+	}
+
+	if (time_out)
+		return 0;
+	else
+		return 1;
+}
+
+static u16 hpi6000_dsp_block_read32(struct hpi_adapter_obj *pao,
+	u16 dsp_index, u32 hpi_address, u32 *dest, u32 count)
+{
+	struct dsp_obj *pdo =
+		&(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+	u32 time_out = PCI_TIMEOUT;
+	int c6711_burst_size = 16;
+	u32 local_hpi_address = hpi_address;
+	int local_count = count;
+	int xfer_size;
+	u32 *pdata = dest;
+	u32 loop_count = 0;
+
+	while (local_count) {
+		if (local_count > c6711_burst_size)
+			xfer_size = c6711_burst_size;
+		else
+			xfer_size = local_count;
+
+		time_out = PCI_TIMEOUT;
+		do {
+			hpi_read_block(pdo, local_hpi_address, pdata,
+				xfer_size);
+		} while (hpi6000_check_PCI2040_error_flag(pao, H6READ)
+			&& --time_out);
+		if (!time_out)
+			break;
+
+		pdata += xfer_size;
+		local_hpi_address += sizeof(u32) * xfer_size;
+		local_count -= xfer_size;
+		loop_count++;
+	}
+
+	if (time_out)
+		return 0;
+	else
+		return 1;
+}
+
+static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
+	u16 dsp_index, struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+	struct dsp_obj *pdo = &phw->ado[dsp_index];
+	u32 timeout;
+	u16 ack;
+	u32 address;
+	u32 length;
+	u32 *p_data;
+	u16 error = 0;
+
+	/* does the DSP we are referencing exist? */
+	if (dsp_index >= phw->num_dsp)
+		return HPI6000_ERROR_MSG_INVALID_DSP_INDEX;
+
+	ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE);
+	if (ack & HPI_HIF_ERROR_MASK) {
+		pao->dsp_crashed++;
+		return HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT;
+	}
+	pao->dsp_crashed = 0;
+
+	/* send the message */
+
+	/* get the address and size */
+	if (phw->message_buffer_address_on_dsp == 0) {
+		timeout = TIMEOUT;
+		do {
+			address =
+				hpi_read_word(pdo,
+				HPI_HIF_ADDR(message_buffer_address));
+			phw->message_buffer_address_on_dsp = address;
+		} while (hpi6000_check_PCI2040_error_flag(pao, H6READ)
+			&& --timeout);
+		if (!timeout)
+			return HPI6000_ERROR_MSG_GET_ADR;
+	} else
+		address = phw->message_buffer_address_on_dsp;
+
+	/*        dwLength = sizeof(struct hpi_message); */
+	length = phm->size;
+
+	/* send it */
+	p_data = (u32 *)phm;
+	if (hpi6000_dsp_block_write32(pao, dsp_index, address, p_data,
+			(u16)length / 4))
+		return HPI6000_ERROR_MSG_RESP_BLOCKWRITE32;
+
+	if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_GET_RESP))
+		return HPI6000_ERROR_MSG_RESP_GETRESPCMD;
+	hpi6000_send_dsp_interrupt(pdo);
+
+	ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_GET_RESP);
+	if (ack & HPI_HIF_ERROR_MASK)
+		return HPI6000_ERROR_MSG_RESP_GET_RESP_ACK;
+
+	/* get the address and size */
+	if (phw->response_buffer_address_on_dsp == 0) {
+		timeout = TIMEOUT;
+		do {
+			address =
+				hpi_read_word(pdo,
+				HPI_HIF_ADDR(response_buffer_address));
+		} while (hpi6000_check_PCI2040_error_flag(pao, H6READ)
+			&& --timeout);
+		phw->response_buffer_address_on_dsp = address;
+
+		if (!timeout)
+			return HPI6000_ERROR_RESP_GET_ADR;
+	} else
+		address = phw->response_buffer_address_on_dsp;
+
+	/* read the length of the response back from the DSP */
+	timeout = TIMEOUT;
+	do {
+		length = hpi_read_word(pdo, HPI_HIF_ADDR(length));
+	} while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout);
+	if (!timeout)
+		length = sizeof(struct hpi_response);
+
+	/* get it */
+	p_data = (u32 *)phr;
+	if (hpi6000_dsp_block_read32(pao, dsp_index, address, p_data,
+			(u16)length / 4))
+		return HPI6000_ERROR_MSG_RESP_BLOCKREAD32;
+
+	/* set i/f back to idle */
+	if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE))
+		return HPI6000_ERROR_MSG_RESP_IDLECMD;
+	hpi6000_send_dsp_interrupt(pdo);
+
+	error = hpi_validate_response(phm, phr);
+	return error;
+}
+
+/* have to set up the below defines to match stuff in the MAP file */
+
+#define MSG_ADDRESS (HPI_HIF_BASE+0x18)
+#define MSG_LENGTH 11
+#define RESP_ADDRESS (HPI_HIF_BASE+0x44)
+#define RESP_LENGTH 16
+#define QUEUE_START  (HPI_HIF_BASE+0x88)
+#define QUEUE_SIZE 0x8000
+
+static short hpi6000_send_data_check_adr(u32 address, u32 length_in_dwords)
+{
+/*#define CHECKING       // comment this line in to enable checking */
+#ifdef CHECKING
+	if (address < (u32)MSG_ADDRESS)
+		return 0;
+	if (address > (u32)(QUEUE_START + QUEUE_SIZE))
+		return 0;
+	if ((address + (length_in_dwords << 2)) >
+		(u32)(QUEUE_START + QUEUE_SIZE))
+		return 0;
+#else
+	(void)address;
+	(void)length_in_dwords;
+	return 1;
+#endif
+}
+
+static short hpi6000_send_data(struct hpi_adapter_obj *pao, u16 dsp_index,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct dsp_obj *pdo =
+		&(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+	u32 data_sent = 0;
+	u16 ack;
+	u32 length, address;
+	u32 *p_data = (u32 *)phm->u.d.u.data.pb_data;
+	u16 time_out = 8;
+
+	(void)phr;
+
+	/* round dwDataSize down to nearest 4 bytes */
+	while ((data_sent < (phm->u.d.u.data.data_size & ~3L))
+		&& --time_out) {
+		ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE);
+		if (ack & HPI_HIF_ERROR_MASK)
+			return HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT;
+
+		if (hpi6000_send_host_command(pao, dsp_index,
+				HPI_HIF_SEND_DATA))
+			return HPI6000_ERROR_SEND_DATA_CMD;
+
+		hpi6000_send_dsp_interrupt(pdo);
+
+		ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_SEND_DATA);
+
+		if (ack & HPI_HIF_ERROR_MASK)
+			return HPI6000_ERROR_SEND_DATA_ACK;
+
+		do {
+			/* get the address and size */
+			address = hpi_read_word(pdo, HPI_HIF_ADDR(address));
+			/* DSP returns number of DWORDS */
+			length = hpi_read_word(pdo, HPI_HIF_ADDR(length));
+		} while (hpi6000_check_PCI2040_error_flag(pao, H6READ));
+
+		if (!hpi6000_send_data_check_adr(address, length))
+			return HPI6000_ERROR_SEND_DATA_ADR;
+
+		/* send the data. break data into 512 DWORD blocks (2K bytes)
+		 * and send using block write. 2Kbytes is the max as this is the
+		 * memory window given to the HPI data register by the PCI2040
+		 */
+
+		{
+			u32 len = length;
+			u32 blk_len = 512;
+			while (len) {
+				if (len < blk_len)
+					blk_len = len;
+				if (hpi6000_dsp_block_write32(pao, dsp_index,
+						address, p_data, blk_len))
+					return HPI6000_ERROR_SEND_DATA_WRITE;
+				address += blk_len * 4;
+				p_data += blk_len;
+				len -= blk_len;
+			}
+		}
+
+		if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE))
+			return HPI6000_ERROR_SEND_DATA_IDLECMD;
+
+		hpi6000_send_dsp_interrupt(pdo);
+
+		data_sent += length * 4;
+	}
+	if (!time_out)
+		return HPI6000_ERROR_SEND_DATA_TIMEOUT;
+	return 0;
+}
+
+static short hpi6000_get_data(struct hpi_adapter_obj *pao, u16 dsp_index,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct dsp_obj *pdo =
+		&(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+	u32 data_got = 0;
+	u16 ack;
+	u32 length, address;
+	u32 *p_data = (u32 *)phm->u.d.u.data.pb_data;
+
+	(void)phr;	/* this parameter not used! */
+
+	/* round dwDataSize down to nearest 4 bytes */
+	while (data_got < (phm->u.d.u.data.data_size & ~3L)) {
+		ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE);
+		if (ack & HPI_HIF_ERROR_MASK)
+			return HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT;
+
+		if (hpi6000_send_host_command(pao, dsp_index,
+				HPI_HIF_GET_DATA))
+			return HPI6000_ERROR_GET_DATA_CMD;
+		hpi6000_send_dsp_interrupt(pdo);
+
+		ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_GET_DATA);
+
+		if (ack & HPI_HIF_ERROR_MASK)
+			return HPI6000_ERROR_GET_DATA_ACK;
+
+		/* get the address and size */
+		do {
+			address = hpi_read_word(pdo, HPI_HIF_ADDR(address));
+			length = hpi_read_word(pdo, HPI_HIF_ADDR(length));
+		} while (hpi6000_check_PCI2040_error_flag(pao, H6READ));
+
+		/* read the data */
+		{
+			u32 len = length;
+			u32 blk_len = 512;
+			while (len) {
+				if (len < blk_len)
+					blk_len = len;
+				if (hpi6000_dsp_block_read32(pao, dsp_index,
+						address, p_data, blk_len))
+					return HPI6000_ERROR_GET_DATA_READ;
+				address += blk_len * 4;
+				p_data += blk_len;
+				len -= blk_len;
+			}
+		}
+
+		if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE))
+			return HPI6000_ERROR_GET_DATA_IDLECMD;
+		hpi6000_send_dsp_interrupt(pdo);
+
+		data_got += length * 4;
+	}
+	return 0;
+}
+
+static void hpi6000_send_dsp_interrupt(struct dsp_obj *pdo)
+{
+	iowrite32(0x00030003, pdo->prHPI_control);	/* DSPINT */
+}
+
+static short hpi6000_send_host_command(struct hpi_adapter_obj *pao,
+	u16 dsp_index, u32 host_cmd)
+{
+	struct dsp_obj *pdo =
+		&(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+	u32 timeout = TIMEOUT;
+
+	/* set command */
+	do {
+		hpi_write_word(pdo, HPI_HIF_ADDR(host_cmd), host_cmd);
+		/* flush the FIFO */
+		hpi_set_address(pdo, HPI_HIF_ADDR(host_cmd));
+	} while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE) && --timeout);
+
+	/* reset the interrupt bit */
+	iowrite32(0x00040004, pdo->prHPI_control);
+
+	if (timeout)
+		return 0;
+	else
+		return 1;
+}
+
+/* if the PCI2040 has recorded an HPI timeout, reset the error and return 1 */
+static short hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj *pao,
+	u16 read_or_write)
+{
+	u32 hPI_error;
+
+	struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+
+	/* read the error bits from the PCI2040 */
+	hPI_error = ioread32(phw->dw2040_HPICSR + HPI_ERROR_REPORT);
+	if (hPI_error) {
+		/* reset the error flag */
+		iowrite32(0L, phw->dw2040_HPICSR + HPI_ERROR_REPORT);
+		phw->pCI2040HPI_error_count++;
+		if (read_or_write == 1)
+			gw_pci_read_asserts++;	   /************* inc global */
+		else
+			gw_pci_write_asserts++;
+		return 1;
+	} else
+		return 0;
+}
+
+static short hpi6000_wait_dsp_ack(struct hpi_adapter_obj *pao, u16 dsp_index,
+	u32 ack_value)
+{
+	struct dsp_obj *pdo =
+		&(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+	u32 ack = 0L;
+	u32 timeout;
+	u32 hPIC = 0L;
+
+	/* wait for host interrupt to signal ack is ready */
+	timeout = TIMEOUT;
+	while (--timeout) {
+		hPIC = ioread32(pdo->prHPI_control);
+		if (hPIC & 0x04)	/* 0x04 = HINT from DSP */
+			break;
+	}
+	if (timeout == 0)
+		return HPI_HIF_ERROR_MASK;
+
+	/* wait for dwAckValue */
+	timeout = TIMEOUT;
+	while (--timeout) {
+		/* read the ack mailbox */
+		ack = hpi_read_word(pdo, HPI_HIF_ADDR(dsp_ack));
+		if (ack == ack_value)
+			break;
+		if ((ack & HPI_HIF_ERROR_MASK)
+			&& !hpi6000_check_PCI2040_error_flag(pao, H6READ))
+			break;
+		/*for (i=0;i<1000;i++) */
+		/*      dwPause=i+1; */
+	}
+	if (ack & HPI_HIF_ERROR_MASK)
+		/* indicates bad read from DSP -
+		   typically 0xffffff is read for some reason */
+		ack = HPI_HIF_ERROR_MASK;
+
+	if (timeout == 0)
+		ack = HPI_HIF_ERROR_MASK;
+	return (short)ack;
+}
+
+static short hpi6000_update_control_cache(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm)
+{
+	const u16 dsp_index = 0;
+	struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+	struct dsp_obj *pdo = &phw->ado[dsp_index];
+	u32 timeout;
+	u32 cache_dirty_flag;
+	u16 err;
+
+	hpios_dsplock_lock(pao);
+
+	timeout = TIMEOUT;
+	do {
+		cache_dirty_flag =
+			hpi_read_word((struct dsp_obj *)pdo,
+			HPI_HIF_ADDR(control_cache_is_dirty));
+	} while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout);
+	if (!timeout) {
+		err = HPI6000_ERROR_CONTROL_CACHE_PARAMS;
+		goto unlock;
+	}
+
+	if (cache_dirty_flag) {
+		/* read the cached controls */
+		u32 address;
+		u32 length;
+
+		timeout = TIMEOUT;
+		if (pdo->control_cache_address_on_dsp == 0) {
+			do {
+				address =
+					hpi_read_word((struct dsp_obj *)pdo,
+					HPI_HIF_ADDR(control_cache_address));
+
+				length = hpi_read_word((struct dsp_obj *)pdo,
+					HPI_HIF_ADDR
+					(control_cache_size_in_bytes));
+			} while (hpi6000_check_PCI2040_error_flag(pao, H6READ)
+				&& --timeout);
+			if (!timeout) {
+				err = HPI6000_ERROR_CONTROL_CACHE_ADDRLEN;
+				goto unlock;
+			}
+			pdo->control_cache_address_on_dsp = address;
+			pdo->control_cache_length_on_dsp = length;
+		} else {
+			address = pdo->control_cache_address_on_dsp;
+			length = pdo->control_cache_length_on_dsp;
+		}
+
+		if (hpi6000_dsp_block_read32(pao, dsp_index, address,
+				(u32 *)&phw->control_cache[0],
+				length / sizeof(u32))) {
+			err = HPI6000_ERROR_CONTROL_CACHE_READ;
+			goto unlock;
+		}
+		do {
+			hpi_write_word((struct dsp_obj *)pdo,
+				HPI_HIF_ADDR(control_cache_is_dirty), 0);
+			/* flush the FIFO */
+			hpi_set_address(pdo, HPI_HIF_ADDR(host_cmd));
+		} while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE)
+			&& --timeout);
+		if (!timeout) {
+			err = HPI6000_ERROR_CONTROL_CACHE_FLUSH;
+			goto unlock;
+		}
+
+	}
+	err = 0;
+
+unlock:
+	hpios_dsplock_unlock(pao);
+	return err;
+}
+
+/** Get dsp index for multi DSP adapters only */
+static u16 get_dsp_index(struct hpi_adapter_obj *pao, struct hpi_message *phm)
+{
+	u16 ret = 0;
+	switch (phm->object) {
+	case HPI_OBJ_ISTREAM:
+		if (phm->obj_index < 2)
+			ret = 1;
+		break;
+	case HPI_OBJ_PROFILE:
+		ret = phm->obj_index;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+/** Complete transaction with DSP
+
+Send message, get response, send or get stream data if any.
+*/
+static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
+	struct hpi_response *phr)
+{
+	u16 error = 0;
+	u16 dsp_index = 0;
+	u16 num_dsp = ((struct hpi_hw_obj *)pao->priv)->num_dsp;
+	hpios_dsplock_lock(pao);
+
+	if (num_dsp < 2)
+		dsp_index = 0;
+	else {
+		dsp_index = get_dsp_index(pao, phm);
+
+		/* is this  checked on the DSP anyway? */
+		if ((phm->function == HPI_ISTREAM_GROUP_ADD)
+			|| (phm->function == HPI_OSTREAM_GROUP_ADD)) {
+			struct hpi_message hm;
+			u16 add_index;
+			hm.obj_index = phm->u.d.u.stream.stream_index;
+			hm.object = phm->u.d.u.stream.object_type;
+			add_index = get_dsp_index(pao, &hm);
+			if (add_index != dsp_index) {
+				phr->error = HPI_ERROR_NO_INTERDSP_GROUPS;
+				return;
+			}
+		}
+	}
+	error = hpi6000_message_response_sequence(pao, dsp_index, phm, phr);
+
+	/* maybe an error response */
+	if (error) {
+		/* something failed in the HPI/DSP interface */
+		phr->error = error;
+		/* just the header of the response is valid */
+		phr->size = sizeof(struct hpi_response_header);
+		goto err;
+	}
+
+	if (phr->error != 0)	/* something failed in the DSP */
+		goto err;
+
+	switch (phm->function) {
+	case HPI_OSTREAM_WRITE:
+	case HPI_ISTREAM_ANC_WRITE:
+		error = hpi6000_send_data(pao, dsp_index, phm, phr);
+		break;
+	case HPI_ISTREAM_READ:
+	case HPI_OSTREAM_ANC_READ:
+		error = hpi6000_get_data(pao, dsp_index, phm, phr);
+		break;
+	case HPI_ADAPTER_GET_ASSERT:
+		phr->u.a.adapter_index = 0;	/* dsp 0 default */
+		if (num_dsp == 2) {
+			if (!phr->u.a.adapter_type) {
+				/* no assert from dsp 0, check dsp 1 */
+				error = hpi6000_message_response_sequence(pao,
+					1, phm, phr);
+				phr->u.a.adapter_index = 1;
+			}
+		}
+	}
+
+	if (error)
+		phr->error = error;
+
+err:
+	hpios_dsplock_unlock(pao);
+	return;
+}

+ 70 - 0
sound/pci/asihpi/hpi6000.h

@@ -0,0 +1,70 @@
+/*****************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+Public declarations for DSP Proramming Interface to TI C6701
+
+Shared between hpi6000.c and DSP code
+
+(C) Copyright AudioScience Inc. 1998-2003
+******************************************************************************/
+
+#ifndef _HPI6000_H_
+#define _HPI6000_H_
+
+#define HPI_NMIXER_CONTROLS 200
+
+/*
+ * Control caching is always supported in the HPI code.
+ * The DSP should make sure that dwControlCacheSizeInBytes is initialized to 0
+ * during boot to make it in-active.
+ */
+struct hpi_hif_6000 {
+	u32 host_cmd;
+	u32 dsp_ack;
+	u32 address;
+	u32 length;
+	u32 message_buffer_address;
+	u32 response_buffer_address;
+	u32 dsp_number;
+	u32 adapter_info;
+	u32 control_cache_is_dirty;
+	u32 control_cache_address;
+	u32 control_cache_size_in_bytes;
+	u32 control_cache_count;
+};
+
+#define HPI_HIF_PACK_ADAPTER_INFO(adapter, version_major, version_minor) \
+		((adapter << 16) | (version_major << 8) | version_minor)
+#define HPI_HIF_ADAPTER_INFO_EXTRACT_ADAPTER(adapterinfo) \
+		((adapterinfo >> 16) & 0xffff)
+#define HPI_HIF_ADAPTER_INFO_EXTRACT_HWVERSION_MAJOR(adapterinfo) \
+		((adapterinfo >> 8) & 0xff)
+#define HPI_HIF_ADAPTER_INFO_EXTRACT_HWVERSION_MINOR(adapterinfo) \
+		(adapterinfo & 0xff)
+
+/* Command/status exchanged between host and DSP */
+#define HPI_HIF_IDLE            0
+#define HPI_HIF_SEND_MSG        1
+#define HPI_HIF_GET_RESP        2
+#define HPI_HIF_DATA_MASK       0x10
+#define HPI_HIF_SEND_DATA       0x13
+#define HPI_HIF_GET_DATA        0x14
+#define HPI_HIF_SEND_DONE       5
+#define HPI_HIF_RESET           9
+
+#endif				/* _HPI6000_H_ */

+ 2331 - 0
sound/pci/asihpi/hpi6205.c

@@ -0,0 +1,2331 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+ Hardware Programming Interface (HPI) for AudioScience
+ ASI50xx, AS51xx, ASI6xxx, ASI87xx ASI89xx series adapters.
+ These PCI and PCIe bus adapters are based on a
+ TMS320C6205 PCI bus mastering DSP,
+ and (except ASI50xx) TI TMS320C6xxx floating point DSP
+
+ Exported function:
+ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
+
+(C) Copyright AudioScience Inc. 1998-2010
+*******************************************************************************/
+#define SOURCEFILE_NAME "hpi6205.c"
+
+#include "hpi_internal.h"
+#include "hpimsginit.h"
+#include "hpidebug.h"
+#include "hpi6205.h"
+#include "hpidspcd.h"
+#include "hpicmn.h"
+
+/*****************************************************************************/
+/* HPI6205 specific error codes */
+#define HPI6205_ERROR_BASE                      1000
+/*#define HPI6205_ERROR_MEM_ALLOC 1001 */
+#define HPI6205_ERROR_6205_NO_IRQ               1002
+#define HPI6205_ERROR_6205_INIT_FAILED          1003
+/*#define HPI6205_ERROR_MISSING_DSPCODE 1004 */
+#define HPI6205_ERROR_UNKNOWN_PCI_DEVICE        1005
+#define HPI6205_ERROR_6205_REG                  1006
+#define HPI6205_ERROR_6205_DSPPAGE              1007
+#define HPI6205_ERROR_BAD_DSPINDEX              1008
+#define HPI6205_ERROR_C6713_HPIC                1009
+#define HPI6205_ERROR_C6713_HPIA                1010
+#define HPI6205_ERROR_C6713_PLL                 1011
+#define HPI6205_ERROR_DSP_INTMEM                1012
+#define HPI6205_ERROR_DSP_EXTMEM                1013
+#define HPI6205_ERROR_DSP_PLD                   1014
+#define HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT     1015
+#define HPI6205_ERROR_MSG_RESP_TIMEOUT          1016
+#define HPI6205_ERROR_6205_EEPROM               1017
+#define HPI6205_ERROR_DSP_EMIF                  1018
+
+#define hpi6205_error(dsp_index, err) (err)
+/*****************************************************************************/
+/* for C6205 PCI i/f */
+/* Host Status Register (HSR) bitfields */
+#define C6205_HSR_INTSRC        0x01
+#define C6205_HSR_INTAVAL       0x02
+#define C6205_HSR_INTAM         0x04
+#define C6205_HSR_CFGERR        0x08
+#define C6205_HSR_EEREAD        0x10
+/* Host-to-DSP Control Register (HDCR) bitfields */
+#define C6205_HDCR_WARMRESET    0x01
+#define C6205_HDCR_DSPINT       0x02
+#define C6205_HDCR_PCIBOOT      0x04
+/* DSP Page Register (DSPP) bitfields, */
+/* defines 4 Mbyte page that BAR0 points to */
+#define C6205_DSPP_MAP1         0x400
+
+/* BAR0 maps to prefetchable 4 Mbyte memory block set by DSPP.
+ * BAR1 maps to non-prefetchable 8 Mbyte memory block
+ * of DSP memory mapped registers (starting at 0x01800000).
+ * 0x01800000 is hardcoded in the PCI i/f, so that only the offset from this
+ * needs to be added to the BAR1 base address set in the PCI config reg
+ */
+#define C6205_BAR1_PCI_IO_OFFSET (0x027FFF0L)
+#define C6205_BAR1_HSR  (C6205_BAR1_PCI_IO_OFFSET)
+#define C6205_BAR1_HDCR (C6205_BAR1_PCI_IO_OFFSET+4)
+#define C6205_BAR1_DSPP (C6205_BAR1_PCI_IO_OFFSET+8)
+
+/* used to control LED (revA) and reset C6713 (revB) */
+#define C6205_BAR0_TIMER1_CTL (0x01980000L)
+
+/* For first 6713 in CE1 space, using DA17,16,2 */
+#define HPICL_ADDR      0x01400000L
+#define HPICH_ADDR      0x01400004L
+#define HPIAL_ADDR      0x01410000L
+#define HPIAH_ADDR      0x01410004L
+#define HPIDIL_ADDR     0x01420000L
+#define HPIDIH_ADDR     0x01420004L
+#define HPIDL_ADDR      0x01430000L
+#define HPIDH_ADDR      0x01430004L
+
+#define C6713_EMIF_GCTL         0x01800000
+#define C6713_EMIF_CE1          0x01800004
+#define C6713_EMIF_CE0          0x01800008
+#define C6713_EMIF_CE2          0x01800010
+#define C6713_EMIF_CE3          0x01800014
+#define C6713_EMIF_SDRAMCTL     0x01800018
+#define C6713_EMIF_SDRAMTIMING  0x0180001C
+#define C6713_EMIF_SDRAMEXT     0x01800020
+
+struct hpi_hw_obj {
+	/* PCI registers */
+	__iomem u32 *prHSR;
+	__iomem u32 *prHDCR;
+	__iomem u32 *prDSPP;
+
+	u32 dsp_page;
+
+	struct consistent_dma_area h_locked_mem;
+	struct bus_master_interface *p_interface_buffer;
+
+	u16 flag_outstream_just_reset[HPI_MAX_STREAMS];
+	/* a non-NULL handle means there is an HPI allocated buffer */
+	struct consistent_dma_area instream_host_buffers[HPI_MAX_STREAMS];
+	struct consistent_dma_area outstream_host_buffers[HPI_MAX_STREAMS];
+	/* non-zero size means a buffer exists, may be external */
+	u32 instream_host_buffer_size[HPI_MAX_STREAMS];
+	u32 outstream_host_buffer_size[HPI_MAX_STREAMS];
+
+	struct consistent_dma_area h_control_cache;
+	struct consistent_dma_area h_async_event_buffer;
+/*      struct hpi_control_cache_single *pControlCache; */
+	struct hpi_async_event *p_async_event_buffer;
+	struct hpi_control_cache *p_cache;
+};
+
+/*****************************************************************************/
+/* local prototypes */
+
+#define check_before_bbm_copy(status, p_bbm_data, l_first_write, l_second_write)
+
+static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us);
+
+static void send_dsp_command(struct hpi_hw_obj *phw, int cmd);
+
+static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
+	u32 *pos_error_code);
+
+static u16 message_response_sequence(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
+	struct hpi_response *phr);
+
+#define HPI6205_TIMEOUT 1000000
+
+static void subsys_create_adapter(struct hpi_message *phm,
+	struct hpi_response *phr);
+static void subsys_delete_adapter(struct hpi_message *phm,
+	struct hpi_response *phr);
+
+static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
+	u32 *pos_error_code);
+
+static void delete_adapter_obj(struct hpi_adapter_obj *pao);
+
+static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+static void outstream_write(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void outstream_get_info(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void outstream_start(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void outstream_open(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void outstream_reset(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void instream_host_buffer_free(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void instream_read(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void instream_get_info(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static void instream_start(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr);
+
+static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
+	u32 address);
+
+static u16 boot_loader_write_mem32(struct hpi_adapter_obj *pao, int dsp_index,
+	u32 address, u32 data);
+
+static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao,
+	int dsp_index);
+
+static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
+	u32 address, u32 length);
+
+static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
+	int dsp_index);
+
+static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
+	int dsp_index);
+
+static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index);
+
+/*****************************************************************************/
+
+static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
+{
+
+	switch (phm->function) {
+	case HPI_SUBSYS_OPEN:
+	case HPI_SUBSYS_CLOSE:
+	case HPI_SUBSYS_GET_INFO:
+	case HPI_SUBSYS_DRIVER_UNLOAD:
+	case HPI_SUBSYS_DRIVER_LOAD:
+	case HPI_SUBSYS_FIND_ADAPTERS:
+		/* messages that should not get here */
+		phr->error = HPI_ERROR_UNIMPLEMENTED;
+		break;
+	case HPI_SUBSYS_CREATE_ADAPTER:
+		subsys_create_adapter(phm, phr);
+		break;
+	case HPI_SUBSYS_DELETE_ADAPTER:
+		subsys_delete_adapter(phm, phr);
+		break;
+	default:
+		phr->error = HPI_ERROR_INVALID_FUNC;
+		break;
+	}
+}
+
+static void control_message(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+
+	struct hpi_hw_obj *phw = pao->priv;
+
+	switch (phm->function) {
+	case HPI_CONTROL_GET_STATE:
+		if (pao->has_control_cache) {
+			rmb();	/* make sure we see updates DM_aed from DSP */
+			if (hpi_check_control_cache(phw->p_cache, phm, phr))
+				break;
+		}
+		hw_message(pao, phm, phr);
+		break;
+	case HPI_CONTROL_GET_INFO:
+		hw_message(pao, phm, phr);
+		break;
+	case HPI_CONTROL_SET_STATE:
+		hw_message(pao, phm, phr);
+		if (pao->has_control_cache)
+			hpi_sync_control_cache(phw->p_cache, phm, phr);
+		break;
+	default:
+		phr->error = HPI_ERROR_INVALID_FUNC;
+		break;
+	}
+}
+
+static void adapter_message(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	switch (phm->function) {
+	default:
+		hw_message(pao, phm, phr);
+		break;
+	}
+}
+
+static void outstream_message(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+
+	if (phm->obj_index >= HPI_MAX_STREAMS) {
+		phr->error = HPI_ERROR_INVALID_STREAM;
+		HPI_DEBUG_LOG(WARNING,
+			"message referencing invalid stream %d "
+			"on adapter index %d\n", phm->obj_index,
+			phm->adapter_index);
+		return;
+	}
+
+	switch (phm->function) {
+	case HPI_OSTREAM_WRITE:
+		outstream_write(pao, phm, phr);
+		break;
+	case HPI_OSTREAM_GET_INFO:
+		outstream_get_info(pao, phm, phr);
+		break;
+	case HPI_OSTREAM_HOSTBUFFER_ALLOC:
+		outstream_host_buffer_allocate(pao, phm, phr);
+		break;
+	case HPI_OSTREAM_HOSTBUFFER_GET_INFO:
+		outstream_host_buffer_get_info(pao, phm, phr);
+		break;
+	case HPI_OSTREAM_HOSTBUFFER_FREE:
+		outstream_host_buffer_free(pao, phm, phr);
+		break;
+	case HPI_OSTREAM_START:
+		outstream_start(pao, phm, phr);
+		break;
+	case HPI_OSTREAM_OPEN:
+		outstream_open(pao, phm, phr);
+		break;
+	case HPI_OSTREAM_RESET:
+		outstream_reset(pao, phm, phr);
+		break;
+	default:
+		hw_message(pao, phm, phr);
+		break;
+	}
+}
+
+static void instream_message(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+
+	if (phm->obj_index >= HPI_MAX_STREAMS) {
+		phr->error = HPI_ERROR_INVALID_STREAM;
+		HPI_DEBUG_LOG(WARNING,
+			"message referencing invalid stream %d "
+			"on adapter index %d\n", phm->obj_index,
+			phm->adapter_index);
+		return;
+	}
+
+	switch (phm->function) {
+	case HPI_ISTREAM_READ:
+		instream_read(pao, phm, phr);
+		break;
+	case HPI_ISTREAM_GET_INFO:
+		instream_get_info(pao, phm, phr);
+		break;
+	case HPI_ISTREAM_HOSTBUFFER_ALLOC:
+		instream_host_buffer_allocate(pao, phm, phr);
+		break;
+	case HPI_ISTREAM_HOSTBUFFER_GET_INFO:
+		instream_host_buffer_get_info(pao, phm, phr);
+		break;
+	case HPI_ISTREAM_HOSTBUFFER_FREE:
+		instream_host_buffer_free(pao, phm, phr);
+		break;
+	case HPI_ISTREAM_START:
+		instream_start(pao, phm, phr);
+		break;
+	default:
+		hw_message(pao, phm, phr);
+		break;
+	}
+}
+
+/*****************************************************************************/
+/** Entry point to this HPI backend
+ * All calls to the HPI start here
+ */
+void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_adapter_obj *pao = NULL;
+
+	/* subsytem messages are processed by every HPI.
+	 * All other messages are ignored unless the adapter index matches
+	 * an adapter in the HPI
+	 */
+	HPI_DEBUG_LOG(DEBUG, "HPI obj=%d, func=%d\n", phm->object,
+		phm->function);
+
+	/* if Dsp has crashed then do not communicate with it any more */
+	if (phm->object != HPI_OBJ_SUBSYSTEM) {
+		pao = hpi_find_adapter(phm->adapter_index);
+		if (!pao) {
+			HPI_DEBUG_LOG(DEBUG,
+				" %d,%d refused, for another HPI?\n",
+				phm->object, phm->function);
+			return;
+		}
+
+		if ((pao->dsp_crashed >= 10)
+			&& (phm->function != HPI_ADAPTER_DEBUG_READ)) {
+			/* allow last resort debug read even after crash */
+			hpi_init_response(phr, phm->object, phm->function,
+				HPI_ERROR_DSP_HARDWARE);
+			HPI_DEBUG_LOG(WARNING, " %d,%d dsp crashed.\n",
+				phm->object, phm->function);
+			return;
+		}
+	}
+
+	/* Init default response  */
+	if (phm->function != HPI_SUBSYS_CREATE_ADAPTER)
+		hpi_init_response(phr, phm->object, phm->function,
+			HPI_ERROR_PROCESSING_MESSAGE);
+
+	HPI_DEBUG_LOG(VERBOSE, "start of switch\n");
+	switch (phm->type) {
+	case HPI_TYPE_MESSAGE:
+		switch (phm->object) {
+		case HPI_OBJ_SUBSYSTEM:
+			subsys_message(phm, phr);
+			break;
+
+		case HPI_OBJ_ADAPTER:
+			phr->size =
+				sizeof(struct hpi_response_header) +
+				sizeof(struct hpi_adapter_res);
+			adapter_message(pao, phm, phr);
+			break;
+
+		case HPI_OBJ_CONTROLEX:
+		case HPI_OBJ_CONTROL:
+			control_message(pao, phm, phr);
+			break;
+
+		case HPI_OBJ_OSTREAM:
+			outstream_message(pao, phm, phr);
+			break;
+
+		case HPI_OBJ_ISTREAM:
+			instream_message(pao, phm, phr);
+			break;
+
+		default:
+			hw_message(pao, phm, phr);
+			break;
+		}
+		break;
+
+	default:
+		phr->error = HPI_ERROR_INVALID_TYPE;
+		break;
+	}
+}
+
+/*****************************************************************************/
+/* SUBSYSTEM */
+
+/** Create an adapter object and initialise it based on resource information
+ * passed in in the message
+ * *** NOTE - you cannot use this function AND the FindAdapters function at the
+ * same time, the application must use only one of them to get the adapters ***
+ */
+static void subsys_create_adapter(struct hpi_message *phm,
+	struct hpi_response *phr)
+{
+	/* create temp adapter obj, because we don't know what index yet */
+	struct hpi_adapter_obj ao;
+	u32 os_error_code;
+	u16 err;
+
+	HPI_DEBUG_LOG(DEBUG, " subsys_create_adapter\n");
+
+	memset(&ao, 0, sizeof(ao));
+
+	/* this HPI only creates adapters for TI/PCI devices */
+	if (phm->u.s.resource.bus_type != HPI_BUS_PCI)
+		return;
+	if (phm->u.s.resource.r.pci->vendor_id != HPI_PCI_VENDOR_ID_TI)
+		return;
+	if (phm->u.s.resource.r.pci->device_id != HPI_PCI_DEV_ID_DSP6205)
+		return;
+
+	ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL);
+	if (!ao.priv) {
+		HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n");
+		phr->error = HPI_ERROR_MEMORY_ALLOC;
+		return;
+	}
+
+	ao.pci = *phm->u.s.resource.r.pci;
+	err = create_adapter_obj(&ao, &os_error_code);
+	if (!err)
+		err = hpi_add_adapter(&ao);
+	if (err) {
+		phr->u.s.data = os_error_code;
+		delete_adapter_obj(&ao);
+		phr->error = err;
+		return;
+	}
+
+	phr->u.s.aw_adapter_list[ao.index] = ao.adapter_type;
+	phr->u.s.adapter_index = ao.index;
+	phr->u.s.num_adapters++;
+	phr->error = 0;
+}
+
+/** delete an adapter - required by WDM driver */
+static void subsys_delete_adapter(struct hpi_message *phm,
+	struct hpi_response *phr)
+{
+	struct hpi_adapter_obj *pao;
+	struct hpi_hw_obj *phw;
+
+	pao = hpi_find_adapter(phm->adapter_index);
+	if (!pao) {
+		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
+		return;
+	}
+	phw = (struct hpi_hw_obj *)pao->priv;
+	/* reset adapter h/w */
+	/* Reset C6713 #1 */
+	boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
+	/* reset C6205 */
+	iowrite32(C6205_HDCR_WARMRESET, phw->prHDCR);
+
+	delete_adapter_obj(pao);
+	phr->error = 0;
+}
+
+/** Create adapter object
+  allocate buffers, bootload DSPs, initialise control cache
+*/
+static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
+	u32 *pos_error_code)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	struct bus_master_interface *interface;
+	u32 phys_addr;
+#ifndef HPI6205_NO_HSR_POLL
+	u32 time_out = HPI6205_TIMEOUT;
+	u32 temp1;
+#endif
+	int i;
+	u16 err;
+
+	/* init error reporting */
+	pao->dsp_crashed = 0;
+
+	for (i = 0; i < HPI_MAX_STREAMS; i++)
+		phw->flag_outstream_just_reset[i] = 1;
+
+	/* The C6205 memory area 1 is 8Mbyte window into DSP registers */
+	phw->prHSR =
+		pao->pci.ap_mem_base[1] +
+		C6205_BAR1_HSR / sizeof(*pao->pci.ap_mem_base[1]);
+	phw->prHDCR =
+		pao->pci.ap_mem_base[1] +
+		C6205_BAR1_HDCR / sizeof(*pao->pci.ap_mem_base[1]);
+	phw->prDSPP =
+		pao->pci.ap_mem_base[1] +
+		C6205_BAR1_DSPP / sizeof(*pao->pci.ap_mem_base[1]);
+
+	pao->has_control_cache = 0;
+
+	if (hpios_locked_mem_alloc(&phw->h_locked_mem,
+			sizeof(struct bus_master_interface),
+			pao->pci.p_os_data))
+		phw->p_interface_buffer = NULL;
+	else if (hpios_locked_mem_get_virt_addr(&phw->h_locked_mem,
+			(void *)&phw->p_interface_buffer))
+		phw->p_interface_buffer = NULL;
+
+	HPI_DEBUG_LOG(DEBUG, "interface buffer address %p\n",
+		phw->p_interface_buffer);
+
+	if (phw->p_interface_buffer) {
+		memset((void *)phw->p_interface_buffer, 0,
+			sizeof(struct bus_master_interface));
+		phw->p_interface_buffer->dsp_ack = H620_HIF_UNKNOWN;
+	}
+
+	err = adapter_boot_load_dsp(pao, pos_error_code);
+	if (err)
+		/* no need to clean up as SubSysCreateAdapter */
+		/* calls DeleteAdapter on error. */
+		return err;
+
+	HPI_DEBUG_LOG(INFO, "load DSP code OK\n");
+
+	/* allow boot load even if mem alloc wont work */
+	if (!phw->p_interface_buffer)
+		return hpi6205_error(0, HPI_ERROR_MEMORY_ALLOC);
+
+	interface = phw->p_interface_buffer;
+
+#ifndef HPI6205_NO_HSR_POLL
+	/* wait for first interrupt indicating the DSP init is done */
+	time_out = HPI6205_TIMEOUT * 10;
+	temp1 = 0;
+	while (((temp1 & C6205_HSR_INTSRC) == 0) && --time_out)
+		temp1 = ioread32(phw->prHSR);
+
+	if (temp1 & C6205_HSR_INTSRC)
+		HPI_DEBUG_LOG(INFO,
+			"interrupt confirming DSP code running OK\n");
+	else {
+		HPI_DEBUG_LOG(ERROR,
+			"timed out waiting for interrupt "
+			"confirming DSP code running\n");
+		return hpi6205_error(0, HPI6205_ERROR_6205_NO_IRQ);
+	}
+
+	/* reset the interrupt */
+	iowrite32(C6205_HSR_INTSRC, phw->prHSR);
+#endif
+
+	/* make sure the DSP has started ok */
+	if (!wait_dsp_ack(phw, H620_HIF_RESET, HPI6205_TIMEOUT * 10)) {
+		HPI_DEBUG_LOG(ERROR, "timed out waiting reset state \n");
+		return hpi6205_error(0, HPI6205_ERROR_6205_INIT_FAILED);
+	}
+	/* Note that *pao, *phw are zeroed after allocation,
+	 * so pointers and flags are NULL by default.
+	 * Allocate bus mastering control cache buffer and tell the DSP about it
+	 */
+	if (interface->control_cache.number_of_controls) {
+		void *p_control_cache_virtual;
+
+		err = hpios_locked_mem_alloc(&phw->h_control_cache,
+			interface->control_cache.size_in_bytes,
+			pao->pci.p_os_data);
+		if (!err)
+			err = hpios_locked_mem_get_virt_addr(&phw->
+				h_control_cache, &p_control_cache_virtual);
+		if (!err) {
+			memset(p_control_cache_virtual, 0,
+				interface->control_cache.size_in_bytes);
+
+			phw->p_cache =
+				hpi_alloc_control_cache(interface->
+				control_cache.number_of_controls,
+				interface->control_cache.size_in_bytes,
+				(struct hpi_control_cache_info *)
+				p_control_cache_virtual);
+		}
+		if (!err) {
+			err = hpios_locked_mem_get_phys_addr(&phw->
+				h_control_cache, &phys_addr);
+			interface->control_cache.physical_address32 =
+				phys_addr;
+		}
+
+		if (!err)
+			pao->has_control_cache = 1;
+		else {
+			if (hpios_locked_mem_valid(&phw->h_control_cache))
+				hpios_locked_mem_free(&phw->h_control_cache);
+			pao->has_control_cache = 0;
+		}
+	}
+	/* allocate bus mastering async buffer and tell the DSP about it */
+	if (interface->async_buffer.b.size) {
+		err = hpios_locked_mem_alloc(&phw->h_async_event_buffer,
+			interface->async_buffer.b.size *
+			sizeof(struct hpi_async_event), pao->pci.p_os_data);
+		if (!err)
+			err = hpios_locked_mem_get_virt_addr
+				(&phw->h_async_event_buffer, (void *)
+				&phw->p_async_event_buffer);
+		if (!err)
+			memset((void *)phw->p_async_event_buffer, 0,
+				interface->async_buffer.b.size *
+				sizeof(struct hpi_async_event));
+		if (!err) {
+			err = hpios_locked_mem_get_phys_addr
+				(&phw->h_async_event_buffer, &phys_addr);
+			interface->async_buffer.physical_address32 =
+				phys_addr;
+		}
+		if (err) {
+			if (hpios_locked_mem_valid(&phw->
+					h_async_event_buffer)) {
+				hpios_locked_mem_free
+					(&phw->h_async_event_buffer);
+				phw->p_async_event_buffer = NULL;
+			}
+		}
+	}
+	send_dsp_command(phw, H620_HIF_IDLE);
+
+	{
+		struct hpi_message hM;
+		struct hpi_response hR;
+		u32 max_streams;
+
+		HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n");
+		memset(&hM, 0, sizeof(hM));
+		hM.type = HPI_TYPE_MESSAGE;
+		hM.size = sizeof(hM);
+		hM.object = HPI_OBJ_ADAPTER;
+		hM.function = HPI_ADAPTER_GET_INFO;
+		hM.adapter_index = 0;
+		memset(&hR, 0, sizeof(hR));
+		hR.size = sizeof(hR);
+
+		err = message_response_sequence(pao, &hM, &hR);
+		if (err) {
+			HPI_DEBUG_LOG(ERROR, "message transport error %d\n",
+				err);
+			return err;
+		}
+		if (hR.error)
+			return hR.error;
+
+		pao->adapter_type = hR.u.a.adapter_type;
+		pao->index = hR.u.a.adapter_index;
+
+		max_streams = hR.u.a.num_outstreams + hR.u.a.num_instreams;
+
+		hpios_locked_mem_prepare((max_streams * 6) / 10, max_streams,
+			65536, pao->pci.p_os_data);
+
+		HPI_DEBUG_LOG(VERBOSE,
+			"got adapter info type %x index %d serial %d\n",
+			hR.u.a.adapter_type, hR.u.a.adapter_index,
+			hR.u.a.serial_number);
+	}
+
+	pao->open = 0;	/* upon creation the adapter is closed */
+
+	HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");
+	return 0;
+}
+
+/** Free memory areas allocated by adapter
+ * this routine is called from SubSysDeleteAdapter,
+  * and SubSysCreateAdapter if duplicate index
+*/
+static void delete_adapter_obj(struct hpi_adapter_obj *pao)
+{
+	struct hpi_hw_obj *phw;
+	int i;
+
+	phw = pao->priv;
+
+	if (hpios_locked_mem_valid(&phw->h_async_event_buffer)) {
+		hpios_locked_mem_free(&phw->h_async_event_buffer);
+		phw->p_async_event_buffer = NULL;
+	}
+
+	if (hpios_locked_mem_valid(&phw->h_control_cache)) {
+		hpios_locked_mem_free(&phw->h_control_cache);
+		hpi_free_control_cache(phw->p_cache);
+	}
+
+	if (hpios_locked_mem_valid(&phw->h_locked_mem)) {
+		hpios_locked_mem_free(&phw->h_locked_mem);
+		phw->p_interface_buffer = NULL;
+	}
+
+	for (i = 0; i < HPI_MAX_STREAMS; i++)
+		if (hpios_locked_mem_valid(&phw->instream_host_buffers[i])) {
+			hpios_locked_mem_free(&phw->instream_host_buffers[i]);
+			/*?phw->InStreamHostBuffers[i] = NULL; */
+			phw->instream_host_buffer_size[i] = 0;
+		}
+
+	for (i = 0; i < HPI_MAX_STREAMS; i++)
+		if (hpios_locked_mem_valid(&phw->outstream_host_buffers[i])) {
+			hpios_locked_mem_free(&phw->outstream_host_buffers
+				[i]);
+			phw->outstream_host_buffer_size[i] = 0;
+		}
+
+	hpios_locked_mem_unprepare(pao->pci.p_os_data);
+
+	hpi_delete_adapter(pao);
+	kfree(phw);
+}
+
+/*****************************************************************************/
+/* OutStream Host buffer functions */
+
+/** Allocate or attach buffer for busmastering
+*/
+static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	u16 err = 0;
+	u32 command = phm->u.d.u.buffer.command;
+	struct hpi_hw_obj *phw = pao->priv;
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+
+	hpi_init_response(phr, phm->object, phm->function, 0);
+
+	if (command == HPI_BUFFER_CMD_EXTERNAL
+		|| command == HPI_BUFFER_CMD_INTERNAL_ALLOC) {
+		/* ALLOC phase, allocate a buffer with power of 2 size,
+		   get its bus address for PCI bus mastering
+		 */
+		phm->u.d.u.buffer.buffer_size =
+			roundup_pow_of_two(phm->u.d.u.buffer.buffer_size);
+		/* return old size and allocated size,
+		   so caller can detect change */
+		phr->u.d.u.stream_info.data_available =
+			phw->outstream_host_buffer_size[phm->obj_index];
+		phr->u.d.u.stream_info.buffer_size =
+			phm->u.d.u.buffer.buffer_size;
+
+		if (phw->outstream_host_buffer_size[phm->obj_index] ==
+			phm->u.d.u.buffer.buffer_size) {
+			/* Same size, no action required */
+			return;
+		}
+
+		if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
+					obj_index]))
+			hpios_locked_mem_free(&phw->outstream_host_buffers
+				[phm->obj_index]);
+
+		err = hpios_locked_mem_alloc(&phw->outstream_host_buffers
+			[phm->obj_index], phm->u.d.u.buffer.buffer_size,
+			pao->pci.p_os_data);
+
+		if (err) {
+			phr->error = HPI_ERROR_INVALID_DATASIZE;
+			phw->outstream_host_buffer_size[phm->obj_index] = 0;
+			return;
+		}
+
+		err = hpios_locked_mem_get_phys_addr
+			(&phw->outstream_host_buffers[phm->obj_index],
+			&phm->u.d.u.buffer.pci_address);
+		/* get the phys addr into msg for single call alloc caller
+		 * needs to do this for split alloc (or use the same message)
+		 * return the phy address for split alloc in the respose too
+		 */
+		phr->u.d.u.stream_info.auxiliary_data_available =
+			phm->u.d.u.buffer.pci_address;
+
+		if (err) {
+			hpios_locked_mem_free(&phw->outstream_host_buffers
+				[phm->obj_index]);
+			phw->outstream_host_buffer_size[phm->obj_index] = 0;
+			phr->error = HPI_ERROR_MEMORY_ALLOC;
+			return;
+		}
+	}
+
+	if (command == HPI_BUFFER_CMD_EXTERNAL
+		|| command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) {
+		/* GRANT phase.  Set up the BBM status, tell the DSP about
+		   the buffer so it can start using BBM.
+		 */
+		struct hpi_hostbuffer_status *status;
+
+		if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
+				buffer_size - 1)) {
+			HPI_DEBUG_LOG(ERROR,
+				"buffer size must be 2^N not %d\n",
+				phm->u.d.u.buffer.buffer_size);
+			phr->error = HPI_ERROR_INVALID_DATASIZE;
+			return;
+		}
+		phw->outstream_host_buffer_size[phm->obj_index] =
+			phm->u.d.u.buffer.buffer_size;
+		status = &interface->outstream_host_buffer_status[phm->
+			obj_index];
+		status->samples_processed = 0;
+		status->stream_state = HPI_STATE_STOPPED;
+		status->dSP_index = 0;
+		status->host_index = status->dSP_index;
+		status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
+
+		hw_message(pao, phm, phr);
+
+		if (phr->error
+			&& hpios_locked_mem_valid(&phw->
+				outstream_host_buffers[phm->obj_index])) {
+			hpios_locked_mem_free(&phw->outstream_host_buffers
+				[phm->obj_index]);
+			phw->outstream_host_buffer_size[phm->obj_index] = 0;
+		}
+	}
+}
+
+static void outstream_host_buffer_get_info(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+	struct hpi_hostbuffer_status *status;
+	u8 *p_bbm_data;
+
+	if (hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
+				obj_index])) {
+		if (hpios_locked_mem_get_virt_addr(&phw->
+				outstream_host_buffers[phm->obj_index],
+				(void *)&p_bbm_data)) {
+			phr->error = HPI_ERROR_INVALID_OPERATION;
+			return;
+		}
+		status = &interface->outstream_host_buffer_status[phm->
+			obj_index];
+		hpi_init_response(phr, HPI_OBJ_OSTREAM,
+			HPI_OSTREAM_HOSTBUFFER_GET_INFO, 0);
+		phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data;
+		phr->u.d.u.hostbuffer_info.p_status = status;
+	} else {
+		hpi_init_response(phr, HPI_OBJ_OSTREAM,
+			HPI_OSTREAM_HOSTBUFFER_GET_INFO,
+			HPI_ERROR_INVALID_OPERATION);
+	}
+}
+
+static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	u32 command = phm->u.d.u.buffer.command;
+
+	if (phw->outstream_host_buffer_size[phm->obj_index]) {
+		if (command == HPI_BUFFER_CMD_EXTERNAL
+			|| command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) {
+			phw->outstream_host_buffer_size[phm->obj_index] = 0;
+			hw_message(pao, phm, phr);
+			/* Tell adapter to stop using the host buffer. */
+		}
+		if (command == HPI_BUFFER_CMD_EXTERNAL
+			|| command == HPI_BUFFER_CMD_INTERNAL_FREE)
+			hpios_locked_mem_free(&phw->outstream_host_buffers
+				[phm->obj_index]);
+	}
+	/* Should HPI_ERROR_INVALID_OPERATION be returned
+	   if no host buffer is allocated? */
+	else
+		hpi_init_response(phr, HPI_OBJ_OSTREAM,
+			HPI_OSTREAM_HOSTBUFFER_FREE, 0);
+
+}
+
+static long outstream_get_space_available(struct hpi_hostbuffer_status
+	*status)
+{
+	return status->size_in_bytes - ((long)(status->host_index) -
+		(long)(status->dSP_index));
+}
+
+static void outstream_write(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+	struct hpi_hostbuffer_status *status;
+	long space_available;
+
+	if (!phw->outstream_host_buffer_size[phm->obj_index]) {
+		/* there  is no BBM buffer, write via message */
+		hw_message(pao, phm, phr);
+		return;
+	}
+
+	hpi_init_response(phr, phm->object, phm->function, 0);
+	status = &interface->outstream_host_buffer_status[phm->obj_index];
+
+	if (phw->flag_outstream_just_reset[phm->obj_index]) {
+		/* Format can only change after reset. Must tell DSP. */
+		u16 function = phm->function;
+		phw->flag_outstream_just_reset[phm->obj_index] = 0;
+		phm->function = HPI_OSTREAM_SET_FORMAT;
+		hw_message(pao, phm, phr);	/* send the format to the DSP */
+		phm->function = function;
+		if (phr->error)
+			return;
+	}
+#if 1
+	if (phw->flag_outstream_just_reset[phm->obj_index]) {
+		/* First OutStremWrite() call following reset will write data to the
+		   adapter's buffers, reducing delay before stream can start
+		 */
+		int partial_write = 0;
+		unsigned int original_size = 0;
+
+		/* Send the first buffer to the DSP the old way. */
+		/* Limit size of first transfer - */
+		/* expect that this will not usually be triggered. */
+		if (phm->u.d.u.data.data_size > HPI6205_SIZEOF_DATA) {
+			partial_write = 1;
+			original_size = phm->u.d.u.data.data_size;
+			phm->u.d.u.data.data_size = HPI6205_SIZEOF_DATA;
+		}
+		/* write it */
+		phm->function = HPI_OSTREAM_WRITE;
+		hw_message(pao, phm, phr);
+		/* update status information that the DSP would typically
+		 * update (and will update next time the DSP
+		 * buffer update task reads data from the host BBM buffer)
+		 */
+		status->auxiliary_data_available = phm->u.d.u.data.data_size;
+		status->host_index += phm->u.d.u.data.data_size;
+		status->dSP_index += phm->u.d.u.data.data_size;
+
+		/* if we did a full write, we can return from here. */
+		if (!partial_write)
+			return;
+
+		/* tweak buffer parameters and let the rest of the */
+		/* buffer land in internal BBM buffer */
+		phm->u.d.u.data.data_size =
+			original_size - HPI6205_SIZEOF_DATA;
+		phm->u.d.u.data.pb_data += HPI6205_SIZEOF_DATA;
+	}
+#endif
+
+	space_available = outstream_get_space_available(status);
+	if (space_available < (long)phm->u.d.u.data.data_size) {
+		phr->error = HPI_ERROR_INVALID_DATASIZE;
+		return;
+	}
+
+	/* HostBuffers is used to indicate host buffer is internally allocated.
+	   otherwise, assumed external, data written externally */
+	if (phm->u.d.u.data.pb_data
+		&& hpios_locked_mem_valid(&phw->outstream_host_buffers[phm->
+				obj_index])) {
+		u8 *p_bbm_data;
+		long l_first_write;
+		u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data;
+
+		if (hpios_locked_mem_get_virt_addr(&phw->
+				outstream_host_buffers[phm->obj_index],
+				(void *)&p_bbm_data)) {
+			phr->error = HPI_ERROR_INVALID_OPERATION;
+			return;
+		}
+
+		/* either all data,
+		   or enough to fit from current to end of BBM buffer */
+		l_first_write =
+			min(phm->u.d.u.data.data_size,
+			status->size_in_bytes -
+			(status->host_index & (status->size_in_bytes - 1)));
+
+		memcpy(p_bbm_data +
+			(status->host_index & (status->size_in_bytes - 1)),
+			p_app_data, l_first_write);
+		/* remaining data if any */
+		memcpy(p_bbm_data, p_app_data + l_first_write,
+			phm->u.d.u.data.data_size - l_first_write);
+	}
+	status->host_index += phm->u.d.u.data.data_size;
+}
+
+static void outstream_get_info(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+	struct hpi_hostbuffer_status *status;
+
+	if (!phw->outstream_host_buffer_size[phm->obj_index]) {
+		hw_message(pao, phm, phr);
+		return;
+	}
+
+	hpi_init_response(phr, phm->object, phm->function, 0);
+
+	status = &interface->outstream_host_buffer_status[phm->obj_index];
+
+	phr->u.d.u.stream_info.state = (u16)status->stream_state;
+	phr->u.d.u.stream_info.samples_transferred =
+		status->samples_processed;
+	phr->u.d.u.stream_info.buffer_size = status->size_in_bytes;
+	phr->u.d.u.stream_info.data_available =
+		status->size_in_bytes - outstream_get_space_available(status);
+	phr->u.d.u.stream_info.auxiliary_data_available =
+		status->auxiliary_data_available;
+}
+
+static void outstream_start(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	hw_message(pao, phm, phr);
+}
+
+static void outstream_reset(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	phw->flag_outstream_just_reset[phm->obj_index] = 1;
+	hw_message(pao, phm, phr);
+}
+
+static void outstream_open(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	outstream_reset(pao, phm, phr);
+}
+
+/*****************************************************************************/
+/* InStream Host buffer functions */
+
+static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	u16 err = 0;
+	u32 command = phm->u.d.u.buffer.command;
+	struct hpi_hw_obj *phw = pao->priv;
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+
+	hpi_init_response(phr, phm->object, phm->function, 0);
+
+	if (command == HPI_BUFFER_CMD_EXTERNAL
+		|| command == HPI_BUFFER_CMD_INTERNAL_ALLOC) {
+
+		phm->u.d.u.buffer.buffer_size =
+			roundup_pow_of_two(phm->u.d.u.buffer.buffer_size);
+		phr->u.d.u.stream_info.data_available =
+			phw->instream_host_buffer_size[phm->obj_index];
+		phr->u.d.u.stream_info.buffer_size =
+			phm->u.d.u.buffer.buffer_size;
+
+		if (phw->instream_host_buffer_size[phm->obj_index] ==
+			phm->u.d.u.buffer.buffer_size) {
+			/* Same size, no action required */
+			return;
+		}
+
+		if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
+					obj_index]))
+			hpios_locked_mem_free(&phw->instream_host_buffers
+				[phm->obj_index]);
+
+		err = hpios_locked_mem_alloc(&phw->instream_host_buffers[phm->
+				obj_index], phm->u.d.u.buffer.buffer_size,
+			pao->pci.p_os_data);
+
+		if (err) {
+			phr->error = HPI_ERROR_INVALID_DATASIZE;
+			phw->instream_host_buffer_size[phm->obj_index] = 0;
+			return;
+		}
+
+		err = hpios_locked_mem_get_phys_addr
+			(&phw->instream_host_buffers[phm->obj_index],
+			&phm->u.d.u.buffer.pci_address);
+		/* get the phys addr into msg for single call alloc. Caller
+		   needs to do this for split alloc so return the phy address */
+		phr->u.d.u.stream_info.auxiliary_data_available =
+			phm->u.d.u.buffer.pci_address;
+		if (err) {
+			hpios_locked_mem_free(&phw->instream_host_buffers
+				[phm->obj_index]);
+			phw->instream_host_buffer_size[phm->obj_index] = 0;
+			phr->error = HPI_ERROR_MEMORY_ALLOC;
+			return;
+		}
+	}
+
+	if (command == HPI_BUFFER_CMD_EXTERNAL
+		|| command == HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER) {
+		struct hpi_hostbuffer_status *status;
+
+		if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
+				buffer_size - 1)) {
+			HPI_DEBUG_LOG(ERROR,
+				"buffer size must be 2^N not %d\n",
+				phm->u.d.u.buffer.buffer_size);
+			phr->error = HPI_ERROR_INVALID_DATASIZE;
+			return;
+		}
+
+		phw->instream_host_buffer_size[phm->obj_index] =
+			phm->u.d.u.buffer.buffer_size;
+		status = &interface->instream_host_buffer_status[phm->
+			obj_index];
+		status->samples_processed = 0;
+		status->stream_state = HPI_STATE_STOPPED;
+		status->dSP_index = 0;
+		status->host_index = status->dSP_index;
+		status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
+
+		hw_message(pao, phm, phr);
+		if (phr->error
+			&& hpios_locked_mem_valid(&phw->
+				instream_host_buffers[phm->obj_index])) {
+			hpios_locked_mem_free(&phw->instream_host_buffers
+				[phm->obj_index]);
+			phw->instream_host_buffer_size[phm->obj_index] = 0;
+		}
+	}
+}
+
+static void instream_host_buffer_get_info(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+	struct hpi_hostbuffer_status *status;
+	u8 *p_bbm_data;
+
+	if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
+				obj_index])) {
+		if (hpios_locked_mem_get_virt_addr(&phw->
+				instream_host_buffers[phm->obj_index],
+				(void *)&p_bbm_data)) {
+			phr->error = HPI_ERROR_INVALID_OPERATION;
+			return;
+		}
+		status = &interface->instream_host_buffer_status[phm->
+			obj_index];
+		hpi_init_response(phr, HPI_OBJ_ISTREAM,
+			HPI_ISTREAM_HOSTBUFFER_GET_INFO, 0);
+		phr->u.d.u.hostbuffer_info.p_buffer = p_bbm_data;
+		phr->u.d.u.hostbuffer_info.p_status = status;
+	} else {
+		hpi_init_response(phr, HPI_OBJ_ISTREAM,
+			HPI_ISTREAM_HOSTBUFFER_GET_INFO,
+			HPI_ERROR_INVALID_OPERATION);
+	}
+}
+
+static void instream_host_buffer_free(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	u32 command = phm->u.d.u.buffer.command;
+
+	if (phw->instream_host_buffer_size[phm->obj_index]) {
+		if (command == HPI_BUFFER_CMD_EXTERNAL
+			|| command == HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER) {
+			phw->instream_host_buffer_size[phm->obj_index] = 0;
+			hw_message(pao, phm, phr);
+		}
+
+		if (command == HPI_BUFFER_CMD_EXTERNAL
+			|| command == HPI_BUFFER_CMD_INTERNAL_FREE)
+			hpios_locked_mem_free(&phw->instream_host_buffers
+				[phm->obj_index]);
+
+	} else {
+		/* Should HPI_ERROR_INVALID_OPERATION be returned
+		   if no host buffer is allocated? */
+		hpi_init_response(phr, HPI_OBJ_ISTREAM,
+			HPI_ISTREAM_HOSTBUFFER_FREE, 0);
+
+	}
+
+}
+
+static void instream_start(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	hw_message(pao, phm, phr);
+}
+
+static long instream_get_bytes_available(struct hpi_hostbuffer_status *status)
+{
+	return (long)(status->dSP_index) - (long)(status->host_index);
+}
+
+static void instream_read(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+	struct hpi_hostbuffer_status *status;
+	long data_available;
+	u8 *p_bbm_data;
+	long l_first_read;
+	u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data;
+
+	if (!phw->instream_host_buffer_size[phm->obj_index]) {
+		hw_message(pao, phm, phr);
+		return;
+	}
+	hpi_init_response(phr, phm->object, phm->function, 0);
+
+	status = &interface->instream_host_buffer_status[phm->obj_index];
+	data_available = instream_get_bytes_available(status);
+	if (data_available < (long)phm->u.d.u.data.data_size) {
+		phr->error = HPI_ERROR_INVALID_DATASIZE;
+		return;
+	}
+
+	if (hpios_locked_mem_valid(&phw->instream_host_buffers[phm->
+				obj_index])) {
+		if (hpios_locked_mem_get_virt_addr(&phw->
+				instream_host_buffers[phm->obj_index],
+				(void *)&p_bbm_data)) {
+			phr->error = HPI_ERROR_INVALID_OPERATION;
+			return;
+		}
+
+		/* either all data,
+		   or enough to fit from current to end of BBM buffer */
+		l_first_read =
+			min(phm->u.d.u.data.data_size,
+			status->size_in_bytes -
+			(status->host_index & (status->size_in_bytes - 1)));
+
+		memcpy(p_app_data,
+			p_bbm_data +
+			(status->host_index & (status->size_in_bytes - 1)),
+			l_first_read);
+		/* remaining data if any */
+		memcpy(p_app_data + l_first_read, p_bbm_data,
+			phm->u.d.u.data.data_size - l_first_read);
+	}
+	status->host_index += phm->u.d.u.data.data_size;
+}
+
+static void instream_get_info(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+	struct hpi_hostbuffer_status *status;
+	if (!phw->instream_host_buffer_size[phm->obj_index]) {
+		hw_message(pao, phm, phr);
+		return;
+	}
+
+	status = &interface->instream_host_buffer_status[phm->obj_index];
+
+	hpi_init_response(phr, phm->object, phm->function, 0);
+
+	phr->u.d.u.stream_info.state = (u16)status->stream_state;
+	phr->u.d.u.stream_info.samples_transferred =
+		status->samples_processed;
+	phr->u.d.u.stream_info.buffer_size = status->size_in_bytes;
+	phr->u.d.u.stream_info.data_available =
+		instream_get_bytes_available(status);
+	phr->u.d.u.stream_info.auxiliary_data_available =
+		status->auxiliary_data_available;
+}
+
+/*****************************************************************************/
+/* LOW-LEVEL */
+#define HPI6205_MAX_FILES_TO_LOAD 2
+
+static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
+	u32 *pos_error_code)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	struct dsp_code dsp_code;
+	u16 boot_code_id[HPI6205_MAX_FILES_TO_LOAD];
+	u16 firmware_id = pao->pci.subsys_device_id;
+	u32 temp;
+	int dsp = 0, i = 0;
+	u16 err = 0;
+
+	boot_code_id[0] = HPI_ADAPTER_ASI(0x6205);
+
+	/* special cases where firmware_id != subsys ID */
+	switch (firmware_id) {
+	case HPI_ADAPTER_FAMILY_ASI(0x5000):
+		boot_code_id[0] = firmware_id;
+		firmware_id = 0;
+		break;
+	case HPI_ADAPTER_FAMILY_ASI(0x5300):
+	case HPI_ADAPTER_FAMILY_ASI(0x5400):
+	case HPI_ADAPTER_FAMILY_ASI(0x6300):
+		firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6400);
+		break;
+	case HPI_ADAPTER_FAMILY_ASI(0x5600):
+	case HPI_ADAPTER_FAMILY_ASI(0x6500):
+		firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6600);
+		break;
+	}
+	boot_code_id[1] = firmware_id;
+
+	/* reset DSP by writing a 1 to the WARMRESET bit */
+	temp = C6205_HDCR_WARMRESET;
+	iowrite32(temp, phw->prHDCR);
+	hpios_delay_micro_seconds(1000);
+
+	/* check that PCI i/f was configured by EEPROM */
+	temp = ioread32(phw->prHSR);
+	if ((temp & (C6205_HSR_CFGERR | C6205_HSR_EEREAD)) !=
+		C6205_HSR_EEREAD)
+		return hpi6205_error(0, HPI6205_ERROR_6205_EEPROM);
+	temp |= 0x04;
+	/* disable PINTA interrupt */
+	iowrite32(temp, phw->prHSR);
+
+	/* check control register reports PCI boot mode */
+	temp = ioread32(phw->prHDCR);
+	if (!(temp & C6205_HDCR_PCIBOOT))
+		return hpi6205_error(0, HPI6205_ERROR_6205_REG);
+
+	/* try writing a couple of numbers to the DSP page register */
+	/* and reading them back. */
+	temp = 1;
+	iowrite32(temp, phw->prDSPP);
+	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
+		return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
+	temp = 2;
+	iowrite32(temp, phw->prDSPP);
+	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
+		return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
+	temp = 3;
+	iowrite32(temp, phw->prDSPP);
+	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
+		return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
+	/* reset DSP page to the correct number */
+	temp = 0;
+	iowrite32(temp, phw->prDSPP);
+	if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
+		return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
+	phw->dsp_page = 0;
+
+	/* release 6713 from reset before 6205 is bootloaded.
+	   This ensures that the EMIF is inactive,
+	   and the 6713 HPI gets the correct bootmode etc
+	 */
+	if (boot_code_id[1] != 0) {
+		/* DSP 1 is a C6713 */
+		/* CLKX0 <- '1' release the C6205 bootmode pulldowns */
+		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002202);
+		hpios_delay_micro_seconds(100);
+		/* Reset the 6713 #1 - revB */
+		boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
+
+		/* dummy read every 4 words for 6205 advisory 1.4.4 */
+		boot_loader_read_mem32(pao, 0, 0);
+
+		hpios_delay_micro_seconds(100);
+		/* Release C6713 from reset - revB */
+		boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4);
+		hpios_delay_micro_seconds(100);
+	}
+
+	for (dsp = 0; dsp < HPI6205_MAX_FILES_TO_LOAD; dsp++) {
+		/* is there a DSP to load? */
+		if (boot_code_id[dsp] == 0)
+			continue;
+
+		err = boot_loader_config_emif(pao, dsp);
+		if (err)
+			return err;
+
+		err = boot_loader_test_internal_memory(pao, dsp);
+		if (err)
+			return err;
+
+		err = boot_loader_test_external_memory(pao, dsp);
+		if (err)
+			return err;
+
+		err = boot_loader_test_pld(pao, dsp);
+		if (err)
+			return err;
+
+		/* write the DSP code down into the DSPs memory */
+		dsp_code.ps_dev = pao->pci.p_os_data;
+		err = hpi_dsp_code_open(boot_code_id[dsp], &dsp_code,
+			pos_error_code);
+		if (err)
+			return err;
+
+		while (1) {
+			u32 length;
+			u32 address;
+			u32 type;
+			u32 *pcode;
+
+			err = hpi_dsp_code_read_word(&dsp_code, &length);
+			if (err)
+				break;
+			if (length == 0xFFFFFFFF)
+				break;	/* end of code */
+
+			err = hpi_dsp_code_read_word(&dsp_code, &address);
+			if (err)
+				break;
+			err = hpi_dsp_code_read_word(&dsp_code, &type);
+			if (err)
+				break;
+			err = hpi_dsp_code_read_block(length, &dsp_code,
+				&pcode);
+			if (err)
+				break;
+			for (i = 0; i < (int)length; i++) {
+				err = boot_loader_write_mem32(pao, dsp,
+					address, *pcode);
+				if (err)
+					break;
+				/* dummy read every 4 words */
+				/* for 6205 advisory 1.4.4 */
+				if (i % 4 == 0)
+					boot_loader_read_mem32(pao, dsp,
+						address);
+				pcode++;
+				address += 4;
+			}
+
+		}
+		if (err) {
+			hpi_dsp_code_close(&dsp_code);
+			return err;
+		}
+
+		/* verify code */
+		hpi_dsp_code_rewind(&dsp_code);
+		while (1) {
+			u32 length = 0;
+			u32 address = 0;
+			u32 type = 0;
+			u32 *pcode = NULL;
+			u32 data = 0;
+
+			hpi_dsp_code_read_word(&dsp_code, &length);
+			if (length == 0xFFFFFFFF)
+				break;	/* end of code */
+
+			hpi_dsp_code_read_word(&dsp_code, &address);
+			hpi_dsp_code_read_word(&dsp_code, &type);
+			hpi_dsp_code_read_block(length, &dsp_code, &pcode);
+
+			for (i = 0; i < (int)length; i++) {
+				data = boot_loader_read_mem32(pao, dsp,
+					address);
+				if (data != *pcode) {
+					err = 0;
+					break;
+				}
+				pcode++;
+				address += 4;
+			}
+			if (err)
+				break;
+		}
+		hpi_dsp_code_close(&dsp_code);
+		if (err)
+			return err;
+	}
+
+	/* After bootloading all DSPs, start DSP0 running
+	 * The DSP0 code will handle starting and synchronizing with its slaves
+	 */
+	if (phw->p_interface_buffer) {
+		/* we need to tell the card the physical PCI address */
+		u32 physicalPC_iaddress;
+		struct bus_master_interface *interface =
+			phw->p_interface_buffer;
+		u32 host_mailbox_address_on_dsp;
+		u32 physicalPC_iaddress_verify = 0;
+		int time_out = 10;
+		/* set ack so we know when DSP is ready to go */
+		/* (dwDspAck will be changed to HIF_RESET) */
+		interface->dsp_ack = H620_HIF_UNKNOWN;
+		wmb();	/* ensure ack is written before dsp writes back */
+
+		err = hpios_locked_mem_get_phys_addr(&phw->h_locked_mem,
+			&physicalPC_iaddress);
+
+		/* locate the host mailbox on the DSP. */
+		host_mailbox_address_on_dsp = 0x80000000;
+		while ((physicalPC_iaddress != physicalPC_iaddress_verify)
+			&& time_out--) {
+			err = boot_loader_write_mem32(pao, 0,
+				host_mailbox_address_on_dsp,
+				physicalPC_iaddress);
+			physicalPC_iaddress_verify =
+				boot_loader_read_mem32(pao, 0,
+				host_mailbox_address_on_dsp);
+		}
+	}
+	HPI_DEBUG_LOG(DEBUG, "starting DS_ps running\n");
+	/* enable interrupts */
+	temp = ioread32(phw->prHSR);
+	temp &= ~(u32)C6205_HSR_INTAM;
+	iowrite32(temp, phw->prHSR);
+
+	/* start code running... */
+	temp = ioread32(phw->prHDCR);
+	temp |= (u32)C6205_HDCR_DSPINT;
+	iowrite32(temp, phw->prHDCR);
+
+	/* give the DSP 10ms to start up */
+	hpios_delay_micro_seconds(10000);
+	return err;
+
+}
+
+/*****************************************************************************/
+/* Bootloader utility functions */
+
+static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
+	u32 address)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	u32 data = 0;
+	__iomem u32 *p_data;
+
+	if (dsp_index == 0) {
+		/* DSP 0 is always C6205 */
+		if ((address >= 0x01800000) & (address < 0x02000000)) {
+			/* BAR1 register access */
+			p_data = pao->pci.ap_mem_base[1] +
+				(address & 0x007fffff) /
+				sizeof(*pao->pci.ap_mem_base[1]);
+			/* HPI_DEBUG_LOG(WARNING,
+			   "BAR1 access %08x\n", dwAddress); */
+		} else {
+			u32 dw4M_page = address >> 22L;
+			if (dw4M_page != phw->dsp_page) {
+				phw->dsp_page = dw4M_page;
+				/* *INDENT OFF* */
+				iowrite32(phw->dsp_page, phw->prDSPP);
+				/* *INDENT-ON* */
+			}
+			address &= 0x3fffff;	/* address within 4M page */
+			/* BAR0 memory access */
+			p_data = pao->pci.ap_mem_base[0] +
+				address / sizeof(u32);
+		}
+		data = ioread32(p_data);
+	} else if (dsp_index == 1) {
+		/* DSP 1 is a C6713 */
+		u32 lsb;
+		boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address);
+		boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16);
+		lsb = boot_loader_read_mem32(pao, 0, HPIDL_ADDR);
+		data = boot_loader_read_mem32(pao, 0, HPIDH_ADDR);
+		data = (data << 16) | (lsb & 0xFFFF);
+	}
+	return data;
+}
+
+static u16 boot_loader_write_mem32(struct hpi_adapter_obj *pao, int dsp_index,
+	u32 address, u32 data)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	u16 err = 0;
+	__iomem u32 *p_data;
+	/*      u32 dwVerifyData=0; */
+
+	if (dsp_index == 0) {
+		/* DSP 0 is always C6205 */
+		if ((address >= 0x01800000) & (address < 0x02000000)) {
+			/* BAR1 - DSP  register access using */
+			/* Non-prefetchable PCI access */
+			p_data = pao->pci.ap_mem_base[1] +
+				(address & 0x007fffff) /
+				sizeof(*pao->pci.ap_mem_base[1]);
+		} else {
+			/* BAR0 access - all of DSP memory using */
+			/* pre-fetchable PCI access */
+			u32 dw4M_page = address >> 22L;
+			if (dw4M_page != phw->dsp_page) {
+				phw->dsp_page = dw4M_page;
+				/* *INDENT-OFF* */
+				iowrite32(phw->dsp_page, phw->prDSPP);
+				/* *INDENT-ON* */
+			}
+			address &= 0x3fffff;	/* address within 4M page */
+			p_data = pao->pci.ap_mem_base[0] +
+				address / sizeof(u32);
+		}
+		iowrite32(data, p_data);
+	} else if (dsp_index == 1) {
+		/* DSP 1 is a C6713 */
+		boot_loader_write_mem32(pao, 0, HPIAL_ADDR, address);
+		boot_loader_write_mem32(pao, 0, HPIAH_ADDR, address >> 16);
+
+		/* dummy read every 4 words for 6205 advisory 1.4.4 */
+		boot_loader_read_mem32(pao, 0, 0);
+
+		boot_loader_write_mem32(pao, 0, HPIDL_ADDR, data);
+		boot_loader_write_mem32(pao, 0, HPIDH_ADDR, data >> 16);
+
+		/* dummy read every 4 words for 6205 advisory 1.4.4 */
+		boot_loader_read_mem32(pao, 0, 0);
+	} else
+		err = hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
+	return err;
+}
+
+static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
+{
+	u16 err = 0;
+
+	if (dsp_index == 0) {
+		u32 setting;
+
+		/* DSP 0 is always C6205 */
+
+		/* Set the EMIF */
+		/* memory map of C6205 */
+		/* 00000000-0000FFFF    16Kx32 internal program */
+		/* 00400000-00BFFFFF    CE0     2Mx32 SDRAM running @ 100MHz */
+
+		/* EMIF config */
+		/*------------ */
+		/* Global EMIF control */
+		boot_loader_write_mem32(pao, dsp_index, 0x01800000, 0x3779);
+#define WS_OFS 28
+#define WST_OFS 22
+#define WH_OFS 20
+#define RS_OFS 16
+#define RST_OFS 8
+#define MTYPE_OFS 4
+#define RH_OFS 0
+
+		/* EMIF CE0 setup - 2Mx32 Sync DRAM on ASI5000 cards only */
+		setting = 0x00000030;
+		boot_loader_write_mem32(pao, dsp_index, 0x01800008, setting);
+		if (setting != boot_loader_read_mem32(pao, dsp_index,
+				0x01800008))
+			return hpi6205_error(dsp_index,
+				HPI6205_ERROR_DSP_EMIF);
+
+		/* EMIF CE1 setup - 32 bit async. This is 6713 #1 HPI, */
+		/* which occupies D15..0. 6713 starts at 27MHz, so need */
+		/* plenty of wait states. See dsn8701.rtf, and 6713 errata. */
+		/* WST should be 71, but 63  is max possible */
+		setting =
+			(1L << WS_OFS) | (63L << WST_OFS) | (1L << WH_OFS) |
+			(1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) |
+			(2L << MTYPE_OFS);
+		boot_loader_write_mem32(pao, dsp_index, 0x01800004, setting);
+		if (setting != boot_loader_read_mem32(pao, dsp_index,
+				0x01800004))
+			return hpi6205_error(dsp_index,
+				HPI6205_ERROR_DSP_EMIF);
+
+		/* EMIF CE2 setup - 32 bit async. This is 6713 #2 HPI, */
+		/* which occupies D15..0. 6713 starts at 27MHz, so need */
+		/* plenty of wait states */
+		setting =
+			(1L << WS_OFS) | (28L << WST_OFS) | (1L << WH_OFS) |
+			(1L << RS_OFS) | (63L << RST_OFS) | (1L << RH_OFS) |
+			(2L << MTYPE_OFS);
+		boot_loader_write_mem32(pao, dsp_index, 0x01800010, setting);
+		if (setting != boot_loader_read_mem32(pao, dsp_index,
+				0x01800010))
+			return hpi6205_error(dsp_index,
+				HPI6205_ERROR_DSP_EMIF);
+
+		/* EMIF CE3 setup - 32 bit async. */
+		/* This is the PLD on the ASI5000 cards only */
+		setting =
+			(1L << WS_OFS) | (10L << WST_OFS) | (1L << WH_OFS) |
+			(1L << RS_OFS) | (10L << RST_OFS) | (1L << RH_OFS) |
+			(2L << MTYPE_OFS);
+		boot_loader_write_mem32(pao, dsp_index, 0x01800014, setting);
+		if (setting != boot_loader_read_mem32(pao, dsp_index,
+				0x01800014))
+			return hpi6205_error(dsp_index,
+				HPI6205_ERROR_DSP_EMIF);
+
+		/* set EMIF SDRAM control for 2Mx32 SDRAM (512x32x4 bank) */
+		/*  need to use this else DSP code crashes? */
+		boot_loader_write_mem32(pao, dsp_index, 0x01800018,
+			0x07117000);
+
+		/* EMIF SDRAM Refresh Timing */
+		/* EMIF SDRAM timing  (orig = 0x410, emulator = 0x61a) */
+		boot_loader_write_mem32(pao, dsp_index, 0x0180001C,
+			0x00000410);
+
+	} else if (dsp_index == 1) {
+		/* test access to the C6713s HPI registers */
+		u32 write_data = 0, read_data = 0, i = 0;
+
+		/* Set up HPIC for little endian, by setiing HPIC:HWOB=1 */
+		write_data = 1;
+		boot_loader_write_mem32(pao, 0, HPICL_ADDR, write_data);
+		boot_loader_write_mem32(pao, 0, HPICH_ADDR, write_data);
+		/* C67 HPI is on lower 16bits of 32bit EMIF */
+		read_data =
+			0xFFF7 & boot_loader_read_mem32(pao, 0, HPICL_ADDR);
+		if (write_data != read_data) {
+			err = hpi6205_error(dsp_index,
+				HPI6205_ERROR_C6713_HPIC);
+			HPI_DEBUG_LOG(ERROR, "HPICL %x %x\n", write_data,
+				read_data);
+
+			return err;
+		}
+		/* HPIA - walking ones test */
+		write_data = 1;
+		for (i = 0; i < 32; i++) {
+			boot_loader_write_mem32(pao, 0, HPIAL_ADDR,
+				write_data);
+			boot_loader_write_mem32(pao, 0, HPIAH_ADDR,
+				(write_data >> 16));
+			read_data =
+				0xFFFF & boot_loader_read_mem32(pao, 0,
+				HPIAL_ADDR);
+			read_data =
+				read_data | ((0xFFFF &
+					boot_loader_read_mem32(pao, 0,
+						HPIAH_ADDR))
+				<< 16);
+			if (read_data != write_data) {
+				err = hpi6205_error(dsp_index,
+					HPI6205_ERROR_C6713_HPIA);
+				HPI_DEBUG_LOG(ERROR, "HPIA %x %x\n",
+					write_data, read_data);
+				return err;
+			}
+			write_data = write_data << 1;
+		}
+
+		/* setup C67x PLL
+		 *  ** C6713 datasheet says we cannot program PLL from HPI,
+		 * and indeed if we try to set the PLL multiply from the HPI,
+		 * the PLL does not seem to lock, so we enable the PLL and
+		 * use the default multiply of x 7, which for a 27MHz clock
+		 * gives a DSP speed of 189MHz
+		 */
+		/* bypass PLL */
+		boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0000);
+		hpios_delay_micro_seconds(1000);
+		/* EMIF = 189/3=63MHz */
+		boot_loader_write_mem32(pao, dsp_index, 0x01B7C120, 0x8002);
+		/* peri = 189/2 */
+		boot_loader_write_mem32(pao, dsp_index, 0x01B7C11C, 0x8001);
+		/* cpu  = 189/1 */
+		boot_loader_write_mem32(pao, dsp_index, 0x01B7C118, 0x8000);
+		hpios_delay_micro_seconds(1000);
+		/* ** SGT test to take GPO3 high when we start the PLL */
+		/* and low when the delay is completed */
+		/* FSX0 <- '1' (GPO3) */
+		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A0A);
+		/* PLL not bypassed */
+		boot_loader_write_mem32(pao, dsp_index, 0x01B7C100, 0x0001);
+		hpios_delay_micro_seconds(1000);
+		/* FSX0 <- '0' (GPO3) */
+		boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002A02);
+
+		/* 6205 EMIF CE1 resetup - 32 bit async. */
+		/* Now 6713 #1 is running at 189MHz can reduce waitstates */
+		boot_loader_write_mem32(pao, 0, 0x01800004,	/* CE1 */
+			(1L << WS_OFS) | (8L << WST_OFS) | (1L << WH_OFS) |
+			(1L << RS_OFS) | (12L << RST_OFS) | (1L << RH_OFS) |
+			(2L << MTYPE_OFS));
+
+		hpios_delay_micro_seconds(1000);
+
+		/* check that we can read one of the PLL registers */
+		/* PLL should not be bypassed! */
+		if ((boot_loader_read_mem32(pao, dsp_index, 0x01B7C100) & 0xF)
+			!= 0x0001) {
+			err = hpi6205_error(dsp_index,
+				HPI6205_ERROR_C6713_PLL);
+			return err;
+		}
+		/* setup C67x EMIF  (note this is the only use of
+		   BAR1 via BootLoader_WriteMem32) */
+		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_GCTL,
+			0x000034A8);
+		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_CE0,
+			0x00000030);
+		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMEXT,
+			0x001BDF29);
+		boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMCTL,
+			0x47117000);
+		boot_loader_write_mem32(pao, dsp_index,
+			C6713_EMIF_SDRAMTIMING, 0x00000410);
+
+		hpios_delay_micro_seconds(1000);
+	} else if (dsp_index == 2) {
+		/* DSP 2 is a C6713 */
+
+	} else
+		err = hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
+	return err;
+}
+
+static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
+	u32 start_address, u32 length)
+{
+	u32 i = 0, j = 0;
+	u32 test_addr = 0;
+	u32 test_data = 0, data = 0;
+
+	length = 1000;
+
+	/* for 1st word, test each bit in the 32bit word, */
+	/* dwLength specifies number of 32bit words to test */
+	/*for(i=0; i<dwLength; i++) */
+	i = 0;
+	{
+		test_addr = start_address + i * 4;
+		test_data = 0x00000001;
+		for (j = 0; j < 32; j++) {
+			boot_loader_write_mem32(pao, dsp_index, test_addr,
+				test_data);
+			data = boot_loader_read_mem32(pao, dsp_index,
+				test_addr);
+			if (data != test_data) {
+				HPI_DEBUG_LOG(VERBOSE,
+					"memtest error details  "
+					"%08x %08x %08x %i\n", test_addr,
+					test_data, data, dsp_index);
+				return 1;	/* error */
+			}
+			test_data = test_data << 1;
+		}	/* for(j) */
+	}	/* for(i) */
+
+	/* for the next 100 locations test each location, leaving it as zero */
+	/* write a zero to the next word in memory before we read */
+	/* the previous write to make sure every memory location is unique */
+	for (i = 0; i < 100; i++) {
+		test_addr = start_address + i * 4;
+		test_data = 0xA5A55A5A;
+		boot_loader_write_mem32(pao, dsp_index, test_addr, test_data);
+		boot_loader_write_mem32(pao, dsp_index, test_addr + 4, 0);
+		data = boot_loader_read_mem32(pao, dsp_index, test_addr);
+		if (data != test_data) {
+			HPI_DEBUG_LOG(VERBOSE,
+				"memtest error details  "
+				"%08x %08x %08x %i\n", test_addr, test_data,
+				data, dsp_index);
+			return 1;	/* error */
+		}
+		/* leave location as zero */
+		boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0);
+	}
+
+	/* zero out entire memory block */
+	for (i = 0; i < length; i++) {
+		test_addr = start_address + i * 4;
+		boot_loader_write_mem32(pao, dsp_index, test_addr, 0x0);
+	}
+	return 0;
+}
+
+static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
+	int dsp_index)
+{
+	int err = 0;
+	if (dsp_index == 0) {
+		/* DSP 0 is a C6205 */
+		/* 64K prog mem */
+		err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
+			0x10000);
+		if (!err)
+			/* 64K data mem */
+			err = boot_loader_test_memory(pao, dsp_index,
+				0x80000000, 0x10000);
+	} else if ((dsp_index == 1) || (dsp_index == 2)) {
+		/* DSP 1&2 are a C6713 */
+		/* 192K internal mem */
+		err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
+			0x30000);
+		if (!err)
+			/* 64K internal mem / L2 cache */
+			err = boot_loader_test_memory(pao, dsp_index,
+				0x00030000, 0x10000);
+	} else
+		return hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
+
+	if (err)
+		return hpi6205_error(dsp_index, HPI6205_ERROR_DSP_INTMEM);
+	else
+		return 0;
+}
+
+static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
+	int dsp_index)
+{
+	u32 dRAM_start_address = 0;
+	u32 dRAM_size = 0;
+
+	if (dsp_index == 0) {
+		/* only test for SDRAM if an ASI5000 card */
+		if (pao->pci.subsys_device_id == 0x5000) {
+			/* DSP 0 is always C6205 */
+			dRAM_start_address = 0x00400000;
+			dRAM_size = 0x200000;
+			/*dwDRAMinc=1024; */
+		} else
+			return 0;
+	} else if ((dsp_index == 1) || (dsp_index == 2)) {
+		/* DSP 1 is a C6713 */
+		dRAM_start_address = 0x80000000;
+		dRAM_size = 0x200000;
+		/*dwDRAMinc=1024; */
+	} else
+		return hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
+
+	if (boot_loader_test_memory(pao, dsp_index, dRAM_start_address,
+			dRAM_size))
+		return hpi6205_error(dsp_index, HPI6205_ERROR_DSP_EXTMEM);
+	return 0;
+}
+
+static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index)
+{
+	u32 data = 0;
+	if (dsp_index == 0) {
+		/* only test for DSP0 PLD on ASI5000 card */
+		if (pao->pci.subsys_device_id == 0x5000) {
+			/* PLD is located at CE3=0x03000000 */
+			data = boot_loader_read_mem32(pao, dsp_index,
+				0x03000008);
+			if ((data & 0xF) != 0x5)
+				return hpi6205_error(dsp_index,
+					HPI6205_ERROR_DSP_PLD);
+			data = boot_loader_read_mem32(pao, dsp_index,
+				0x0300000C);
+			if ((data & 0xF) != 0xA)
+				return hpi6205_error(dsp_index,
+					HPI6205_ERROR_DSP_PLD);
+		}
+	} else if (dsp_index == 1) {
+		/* DSP 1 is a C6713 */
+		if (pao->pci.subsys_device_id == 0x8700) {
+			/* PLD is located at CE1=0x90000000 */
+			data = boot_loader_read_mem32(pao, dsp_index,
+				0x90000010);
+			if ((data & 0xFF) != 0xAA)
+				return hpi6205_error(dsp_index,
+					HPI6205_ERROR_DSP_PLD);
+			/* 8713 - LED on */
+			boot_loader_write_mem32(pao, dsp_index, 0x90000000,
+				0x02);
+		}
+	}
+	return 0;
+}
+
+/** Transfer data to or from DSP
+ nOperation = H620_H620_HIF_SEND_DATA or H620_HIF_GET_DATA
+*/
+static short hpi6205_transfer_data(struct hpi_adapter_obj *pao, u8 *p_data,
+	u32 data_size, int operation)
+{
+	struct hpi_hw_obj *phw = pao->priv;
+	u32 data_transferred = 0;
+	u16 err = 0;
+#ifndef HPI6205_NO_HSR_POLL
+	u32 time_out;
+#endif
+	u32 temp2;
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+
+	if (!p_data)
+		return HPI_ERROR_INVALID_DATA_TRANSFER;
+
+	data_size &= ~3L;	/* round data_size down to nearest 4 bytes */
+
+	/* make sure state is IDLE */
+	if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT))
+		return HPI_ERROR_DSP_HARDWARE;
+
+	while (data_transferred < data_size) {
+		u32 this_copy = data_size - data_transferred;
+
+		if (this_copy > HPI6205_SIZEOF_DATA)
+			this_copy = HPI6205_SIZEOF_DATA;
+
+		if (operation == H620_HIF_SEND_DATA)
+			memcpy((void *)&interface->u.b_data[0],
+				&p_data[data_transferred], this_copy);
+
+		interface->transfer_size_in_bytes = this_copy;
+
+#ifdef HPI6205_NO_HSR_POLL
+		/* DSP must change this back to nOperation */
+		interface->dsp_ack = H620_HIF_IDLE;
+#endif
+
+		send_dsp_command(phw, operation);
+
+#ifdef HPI6205_NO_HSR_POLL
+		temp2 = wait_dsp_ack(phw, operation, HPI6205_TIMEOUT);
+		HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n",
+			HPI6205_TIMEOUT - temp2, this_copy);
+
+		if (!temp2) {
+			/* timed out */
+			HPI_DEBUG_LOG(ERROR,
+				"timed out waiting for " "state %d got %d\n",
+				operation, interface->dsp_ack);
+
+			break;
+		}
+#else
+		/* spin waiting on the result */
+		time_out = HPI6205_TIMEOUT;
+		temp2 = 0;
+		while ((temp2 == 0) && time_out--) {
+			/* give 16k bus mastering transfer time to happen */
+			/*(16k / 132Mbytes/s = 122usec) */
+			hpios_delay_micro_seconds(20);
+			temp2 = ioread32(phw->prHSR);
+			temp2 &= C6205_HSR_INTSRC;
+		}
+		HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n",
+			HPI6205_TIMEOUT - time_out, this_copy);
+		if (temp2 == C6205_HSR_INTSRC) {
+			HPI_DEBUG_LOG(VERBOSE,
+				"interrupt from HIF <data> OK\n");
+			/*
+			   if(interface->dwDspAck != nOperation) {
+			   HPI_DEBUG_LOG(DEBUG("interface->dwDspAck=%d,
+			   expected %d \n",
+			   interface->dwDspAck,nOperation);
+			   }
+			 */
+		}
+/* need to handle this differently... */
+		else {
+			HPI_DEBUG_LOG(ERROR,
+				"interrupt from HIF <data> BAD\n");
+			err = HPI_ERROR_DSP_HARDWARE;
+		}
+
+		/* reset the interrupt from the DSP */
+		iowrite32(C6205_HSR_INTSRC, phw->prHSR);
+#endif
+		if (operation == H620_HIF_GET_DATA)
+			memcpy(&p_data[data_transferred],
+				(void *)&interface->u.b_data[0], this_copy);
+
+		data_transferred += this_copy;
+	}
+	if (interface->dsp_ack != operation)
+		HPI_DEBUG_LOG(DEBUG, "interface->dsp_ack=%d, expected %d\n",
+			interface->dsp_ack, operation);
+	/*                      err=HPI_ERROR_DSP_HARDWARE; */
+
+	send_dsp_command(phw, H620_HIF_IDLE);
+
+	return err;
+}
+
+/* wait for up to timeout_us microseconds for the DSP
+   to signal state by DMA into dwDspAck
+*/
+static int wait_dsp_ack(struct hpi_hw_obj *phw, int state, int timeout_us)
+{
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+	int t = timeout_us / 4;
+
+	rmb();	/* ensure interface->dsp_ack is up to date */
+	while ((interface->dsp_ack != state) && --t) {
+		hpios_delay_micro_seconds(4);
+		rmb();	/* DSP changes dsp_ack by DMA */
+	}
+
+	/*HPI_DEBUG_LOG(VERBOSE, "Spun %d for %d\n", timeout_us/4-t, state); */
+	return t * 4;
+}
+
+/* set the busmaster interface to cmd, then interrupt the DSP */
+static void send_dsp_command(struct hpi_hw_obj *phw, int cmd)
+{
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+
+	u32 r;
+
+	interface->host_cmd = cmd;
+	wmb();	/* DSP gets state by DMA, make sure it is written to memory */
+	/* before we interrupt the DSP */
+	r = ioread32(phw->prHDCR);
+	r |= (u32)C6205_HDCR_DSPINT;
+	iowrite32(r, phw->prHDCR);
+	r &= ~(u32)C6205_HDCR_DSPINT;
+	iowrite32(r, phw->prHDCR);
+}
+
+static unsigned int message_count;
+
+static u16 message_response_sequence(struct hpi_adapter_obj *pao,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+#ifndef HPI6205_NO_HSR_POLL
+	u32 temp2;
+#endif
+	u32 time_out, time_out2;
+	struct hpi_hw_obj *phw = pao->priv;
+	struct bus_master_interface *interface = phw->p_interface_buffer;
+	u16 err = 0;
+
+	message_count++;
+	/* Assume buffer of type struct bus_master_interface
+	   is allocated "noncacheable" */
+
+	if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
+		HPI_DEBUG_LOG(DEBUG, "timeout waiting for idle\n");
+		return hpi6205_error(0, HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT);
+	}
+	interface->u.message_buffer = *phm;
+	/* signal we want a response */
+	send_dsp_command(phw, H620_HIF_GET_RESP);
+
+	time_out2 = wait_dsp_ack(phw, H620_HIF_GET_RESP, HPI6205_TIMEOUT);
+
+	if (time_out2 == 0) {
+		HPI_DEBUG_LOG(ERROR,
+			"(%u) timed out waiting for " "GET_RESP state [%x]\n",
+			message_count, interface->dsp_ack);
+	} else {
+		HPI_DEBUG_LOG(VERBOSE,
+			"(%u) transition to GET_RESP after %u\n",
+			message_count, HPI6205_TIMEOUT - time_out2);
+	}
+	/* spin waiting on HIF interrupt flag (end of msg process) */
+	time_out = HPI6205_TIMEOUT;
+
+#ifndef HPI6205_NO_HSR_POLL
+	temp2 = 0;
+	while ((temp2 == 0) && --time_out) {
+		temp2 = ioread32(phw->prHSR);
+		temp2 &= C6205_HSR_INTSRC;
+		hpios_delay_micro_seconds(1);
+	}
+	if (temp2 == C6205_HSR_INTSRC) {
+		rmb();	/* ensure we see latest value for dsp_ack */
+		if ((interface->dsp_ack != H620_HIF_GET_RESP)) {
+			HPI_DEBUG_LOG(DEBUG,
+				"(%u)interface->dsp_ack(0x%x) != "
+				"H620_HIF_GET_RESP, t=%u\n", message_count,
+				interface->dsp_ack,
+				HPI6205_TIMEOUT - time_out);
+		} else {
+			HPI_DEBUG_LOG(VERBOSE,
+				"(%u)int with GET_RESP after %u\n",
+				message_count, HPI6205_TIMEOUT - time_out);
+		}
+
+	} else {
+		/* can we do anything else in response to the error ? */
+		HPI_DEBUG_LOG(ERROR,
+			"interrupt from HIF module BAD (function %x)\n",
+			phm->function);
+	}
+
+	/* reset the interrupt from the DSP */
+	iowrite32(C6205_HSR_INTSRC, phw->prHSR);
+#endif
+
+	/* read the result */
+	if (time_out != 0)
+		*phr = interface->u.response_buffer;
+
+	/* set interface back to idle */
+	send_dsp_command(phw, H620_HIF_IDLE);
+
+	if ((time_out == 0) || (time_out2 == 0)) {
+		HPI_DEBUG_LOG(DEBUG, "something timed out!\n");
+		return hpi6205_error(0, HPI6205_ERROR_MSG_RESP_TIMEOUT);
+	}
+	/* special case for adapter close - */
+	/* wait for the DSP to indicate it is idle */
+	if (phm->function == HPI_ADAPTER_CLOSE) {
+		if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
+			HPI_DEBUG_LOG(DEBUG,
+				"timeout waiting for idle "
+				"(on adapter_close)\n");
+			return hpi6205_error(0,
+				HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT);
+		}
+	}
+	err = hpi_validate_response(phm, phr);
+	return err;
+}
+
+static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
+	struct hpi_response *phr)
+{
+
+	u16 err = 0;
+
+	hpios_dsplock_lock(pao);
+
+	err = message_response_sequence(pao, phm, phr);
+
+	/* maybe an error response */
+	if (err) {
+		/* something failed in the HPI/DSP interface */
+		phr->error = err;
+		pao->dsp_crashed++;
+
+		/* just the header of the response is valid */
+		phr->size = sizeof(struct hpi_response_header);
+		goto err;
+	} else
+		pao->dsp_crashed = 0;
+
+	if (phr->error != 0)	/* something failed in the DSP */
+		goto err;
+
+	switch (phm->function) {
+	case HPI_OSTREAM_WRITE:
+	case HPI_ISTREAM_ANC_WRITE:
+		err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data,
+			phm->u.d.u.data.data_size, H620_HIF_SEND_DATA);
+		break;
+
+	case HPI_ISTREAM_READ:
+	case HPI_OSTREAM_ANC_READ:
+		err = hpi6205_transfer_data(pao, phm->u.d.u.data.pb_data,
+			phm->u.d.u.data.data_size, H620_HIF_GET_DATA);
+		break;
+
+	case HPI_CONTROL_SET_STATE:
+		if (phm->object == HPI_OBJ_CONTROLEX
+			&& phm->u.cx.attribute == HPI_COBRANET_SET_DATA)
+			err = hpi6205_transfer_data(pao,
+				phm->u.cx.u.cobranet_bigdata.pb_data,
+				phm->u.cx.u.cobranet_bigdata.byte_count,
+				H620_HIF_SEND_DATA);
+		break;
+
+	case HPI_CONTROL_GET_STATE:
+		if (phm->object == HPI_OBJ_CONTROLEX
+			&& phm->u.cx.attribute == HPI_COBRANET_GET_DATA)
+			err = hpi6205_transfer_data(pao,
+				phm->u.cx.u.cobranet_bigdata.pb_data,
+				phr->u.cx.u.cobranet_data.byte_count,
+				H620_HIF_GET_DATA);
+		break;
+	}
+	phr->error = err;
+
+err:
+	hpios_dsplock_unlock(pao);
+
+	return;
+}

+ 93 - 0
sound/pci/asihpi/hpi6205.h

@@ -0,0 +1,93 @@
+/*****************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+Host Interface module for an ASI6205 based
+bus mastering PCI adapter.
+
+Copyright AudioScience, Inc., 2003
+******************************************************************************/
+
+#ifndef _HPI6205_H_
+#define _HPI6205_H_
+
+/* transitional conditional compile shared between host and DSP */
+/* #define HPI6205_NO_HSR_POLL */
+
+#include "hpi_internal.h"
+
+/***********************************************************
+	Defines used for basic messaging
+************************************************************/
+#define H620_HIF_RESET          0
+#define H620_HIF_IDLE           1
+#define H620_HIF_GET_RESP       2
+#define H620_HIF_DATA_DONE      3
+#define H620_HIF_DATA_MASK      0x10
+#define H620_HIF_SEND_DATA      0x14
+#define H620_HIF_GET_DATA       0x15
+#define H620_HIF_UNKNOWN                0x0000ffff
+
+/***********************************************************
+	Types used for mixer control caching
+************************************************************/
+
+#define H620_MAX_ISTREAMS 32
+#define H620_MAX_OSTREAMS 32
+#define HPI_NMIXER_CONTROLS 2048
+
+/*********************************************************************
+This is used for dynamic control cache allocation
+**********************************************************************/
+struct controlcache_6205 {
+	u32 number_of_controls;
+	u32 physical_address32;
+	u32 size_in_bytes;
+};
+
+/*********************************************************************
+This is used for dynamic allocation of async event array
+**********************************************************************/
+struct async_event_buffer_6205 {
+	u32 physical_address32;
+	u32 spare;
+	struct hpi_fifo_buffer b;
+};
+
+/***********************************************************
+The Host located memory buffer that the 6205 will bus master
+in and out of.
+************************************************************/
+#define HPI6205_SIZEOF_DATA (16*1024)
+struct bus_master_interface {
+	u32 host_cmd;
+	u32 dsp_ack;
+	u32 transfer_size_in_bytes;
+	union {
+		struct hpi_message message_buffer;
+		struct hpi_response response_buffer;
+		u8 b_data[HPI6205_SIZEOF_DATA];
+	} u;
+	struct controlcache_6205 control_cache;
+	struct async_event_buffer_6205 async_buffer;
+	struct hpi_hostbuffer_status
+	 instream_host_buffer_status[H620_MAX_ISTREAMS];
+	struct hpi_hostbuffer_status
+	 outstream_host_buffer_status[H620_MAX_OSTREAMS];
+};
+
+#endif

+ 1641 - 0
sound/pci/asihpi/hpi_internal.h

@@ -0,0 +1,1641 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+HPI internal definitions
+
+(C) Copyright AudioScience Inc. 1996-2009
+******************************************************************************/
+
+#ifndef _HPI_INTERNAL_H_
+#define _HPI_INTERNAL_H_
+
+#include "hpi.h"
+/** maximum number of memory regions mapped to an adapter */
+#define HPI_MAX_ADAPTER_MEM_SPACES (2)
+
+/* Each OS needs its own hpios.h, or specific define as above */
+#include "hpios.h"
+
+/* physical memory allocation */
+void hpios_locked_mem_init(void
+	);
+void hpios_locked_mem_free_all(void
+	);
+#define hpios_locked_mem_prepare(a, b, c, d);
+#define hpios_locked_mem_unprepare(a)
+
+/** Allocate and map an area of locked memory for bus master DMA operations.
+
+On success, *pLockedMemeHandle is a valid handle, and 0 is returned
+On error *pLockedMemHandle marked invalid, non-zero returned.
+
+If this function succeeds, then HpiOs_LockedMem_GetVirtAddr() and
+HpiOs_LockedMem_GetPyhsAddr() will always succed on the returned handle.
+*/
+u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_locked_mem_handle,
+							   /**< memory handle */
+	u32 size, /**< size in bytes to allocate */
+	struct pci_dev *p_os_reference
+	/**< OS specific data required for memory allocation */
+	);
+
+/** Free mapping and memory represented by LockedMemHandle
+
+Frees any resources, then invalidates the handle.
+Returns 0 on success, 1 if handle is invalid.
+
+*/
+u16 hpios_locked_mem_free(struct consistent_dma_area *locked_mem_handle);
+
+/** Get the physical PCI address of memory represented by LockedMemHandle.
+
+If handle is invalid *pPhysicalAddr is set to zero and return 1
+*/
+u16 hpios_locked_mem_get_phys_addr(struct consistent_dma_area
+	*locked_mem_handle, u32 *p_physical_addr);
+
+/** Get the CPU address of of memory represented by LockedMemHandle.
+
+If handle is NULL *ppvVirtualAddr is set to NULL and return 1
+*/
+u16 hpios_locked_mem_get_virt_addr(struct consistent_dma_area
+	*locked_mem_handle, void **ppv_virtual_addr);
+
+/** Check that handle is valid
+i.e it represents a valid memory area
+*/
+u16 hpios_locked_mem_valid(struct consistent_dma_area *locked_mem_handle);
+
+/* timing/delay */
+void hpios_delay_micro_seconds(u32 num_micro_sec);
+
+struct hpi_message;
+struct hpi_response;
+
+typedef void hpi_handler_func(struct hpi_message *, struct hpi_response *);
+
+/* If the assert fails, compiler complains
+   something like size of array `msg' is negative.
+   Unlike linux BUILD_BUG_ON, this works outside function scope.
+*/
+#define compile_time_assert(cond, msg) \
+    typedef char ASSERT_##msg[(cond) ? 1 : -1]
+
+/*/////////////////////////////////////////////////////////////////////////// */
+/* Private HPI Entity related definitions                                     */
+
+#define STR_SIZE_FIELD_MAX 65535U
+#define STR_TYPE_FIELD_MAX 255U
+#define STR_ROLE_FIELD_MAX 255U
+
+struct hpi_entity_str {
+	uint16_t size;
+	uint8_t type;
+	uint8_t role;
+};
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4200)
+#endif
+
+struct hpi_entity {
+	struct hpi_entity_str header;
+#if ! defined(HPI_OS_DSP_C6000) || (defined(HPI_OS_DSP_C6000) && (__TI_COMPILER_VERSION__ > 6000008))
+	/* DSP C6000 compiler v6.0.8 and lower
+	   do not support  flexible array member */
+	uint8_t value[];
+#else
+	/* NOTE! Using sizeof(struct hpi_entity) will give erroneous results */
+#define HPI_INTERNAL_WARN_ABOUT_ENTITY_VALUE
+	uint8_t value[1];
+#endif
+};
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+/******************************************* bus types */
+enum HPI_BUSES {
+	HPI_BUS_ISAPNP = 1,
+	HPI_BUS_PCI = 2,
+	HPI_BUS_USB = 3,
+	HPI_BUS_NET = 4
+};
+
+/******************************************* CONTROL ATTRIBUTES ****/
+/* (in order of control type ID */
+
+	/* This allows for 255 control types, 256 unique attributes each */
+#define HPI_CTL_ATTR(ctl, ai) (HPI_CONTROL_##ctl * 0x100 + ai)
+
+/* Get the sub-index of the attribute for a control type */
+#define HPI_CTL_ATTR_INDEX(i) (i&0xff)
+
+/* Generic control attributes.  */
+
+/** Enable a control.
+0=disable, 1=enable
+\note generic to all mixer plugins?
+*/
+#define HPI_GENERIC_ENABLE HPI_CTL_ATTR(GENERIC, 1)
+
+/** Enable event generation for a control.
+0=disable, 1=enable
+\note generic to all controls that can generate events
+*/
+#define HPI_GENERIC_EVENT_ENABLE HPI_CTL_ATTR(GENERIC, 2)
+
+/* Volume Control attributes */
+#define HPI_VOLUME_GAIN                 HPI_CTL_ATTR(VOLUME, 1)
+#define HPI_VOLUME_AUTOFADE             HPI_CTL_ATTR(VOLUME, 2)
+
+/** For HPI_ControlQuery() to get the number of channels of a volume control*/
+#define HPI_VOLUME_NUM_CHANNELS         HPI_CTL_ATTR(VOLUME, 6)
+#define HPI_VOLUME_RANGE                HPI_CTL_ATTR(VOLUME, 10)
+
+/** Level Control attributes */
+#define HPI_LEVEL_GAIN                  HPI_CTL_ATTR(LEVEL, 1)
+#define HPI_LEVEL_RANGE                 HPI_CTL_ATTR(LEVEL, 10)
+
+/* Meter Control attributes */
+/** return RMS signal level */
+#define HPI_METER_RMS                   HPI_CTL_ATTR(METER, 1)
+/** return peak signal level */
+#define HPI_METER_PEAK                  HPI_CTL_ATTR(METER, 2)
+/** ballistics for ALL rms meters on adapter */
+#define HPI_METER_RMS_BALLISTICS        HPI_CTL_ATTR(METER, 3)
+/** ballistics for ALL peak meters on adapter */
+#define HPI_METER_PEAK_BALLISTICS       HPI_CTL_ATTR(METER, 4)
+
+/** For HPI_ControlQuery() to get the number of channels of a meter control*/
+#define HPI_METER_NUM_CHANNELS          HPI_CTL_ATTR(METER, 5)
+
+/* Multiplexer control attributes */
+#define HPI_MULTIPLEXER_SOURCE          HPI_CTL_ATTR(MULTIPLEXER, 1)
+#define HPI_MULTIPLEXER_QUERYSOURCE     HPI_CTL_ATTR(MULTIPLEXER, 2)
+
+/** AES/EBU transmitter control attributes */
+/** AESEBU or SPDIF */
+#define HPI_AESEBUTX_FORMAT             HPI_CTL_ATTR(AESEBUTX, 1)
+#define HPI_AESEBUTX_SAMPLERATE         HPI_CTL_ATTR(AESEBUTX, 3)
+#define HPI_AESEBUTX_CHANNELSTATUS      HPI_CTL_ATTR(AESEBUTX, 4)
+#define HPI_AESEBUTX_USERDATA           HPI_CTL_ATTR(AESEBUTX, 5)
+
+/** AES/EBU receiver control attributes */
+#define HPI_AESEBURX_FORMAT             HPI_CTL_ATTR(AESEBURX, 1)
+#define HPI_AESEBURX_ERRORSTATUS        HPI_CTL_ATTR(AESEBURX, 2)
+#define HPI_AESEBURX_SAMPLERATE         HPI_CTL_ATTR(AESEBURX, 3)
+#define HPI_AESEBURX_CHANNELSTATUS      HPI_CTL_ATTR(AESEBURX, 4)
+#define HPI_AESEBURX_USERDATA           HPI_CTL_ATTR(AESEBURX, 5)
+
+/** \defgroup tuner_defs Tuners
+\{
+*/
+/** \defgroup tuner_attrs Tuner control attributes
+\{
+*/
+#define HPI_TUNER_BAND                  HPI_CTL_ATTR(TUNER, 1)
+#define HPI_TUNER_FREQ                  HPI_CTL_ATTR(TUNER, 2)
+#define HPI_TUNER_LEVEL                 HPI_CTL_ATTR(TUNER, 3)
+#define HPI_TUNER_AUDIOMUTE             HPI_CTL_ATTR(TUNER, 4)
+/* use TUNER_STATUS instead */
+#define HPI_TUNER_VIDEO_STATUS          HPI_CTL_ATTR(TUNER, 5)
+#define HPI_TUNER_GAIN                  HPI_CTL_ATTR(TUNER, 6)
+#define HPI_TUNER_STATUS                HPI_CTL_ATTR(TUNER, 7)
+#define HPI_TUNER_MODE                  HPI_CTL_ATTR(TUNER, 8)
+/** RDS data. */
+#define HPI_TUNER_RDS                   HPI_CTL_ATTR(TUNER, 9)
+/** Audio pre-emphasis. */
+#define HPI_TUNER_DEEMPHASIS            HPI_CTL_ATTR(TUNER, 10)
+/** HD Radio tuner program control. */
+#define HPI_TUNER_PROGRAM               HPI_CTL_ATTR(TUNER, 11)
+/** HD Radio tuner digital signal quality. */
+#define HPI_TUNER_HDRADIO_SIGNAL_QUALITY        HPI_CTL_ATTR(TUNER, 12)
+/** HD Radio SDK firmware version. */
+#define HPI_TUNER_HDRADIO_SDK_VERSION   HPI_CTL_ATTR(TUNER, 13)
+/** HD Radio DSP firmware version. */
+#define HPI_TUNER_HDRADIO_DSP_VERSION   HPI_CTL_ATTR(TUNER, 14)
+
+/** \} */
+
+/** \defgroup pads_attrs Tuner PADs control attributes
+\{
+*/
+/** The text string containing the station/channel combination. */
+#define HPI_PAD_CHANNEL_NAME            HPI_CTL_ATTR(PAD, 1)
+/** The text string containing the artist. */
+#define HPI_PAD_ARTIST                  HPI_CTL_ATTR(PAD, 2)
+/** The text string containing the title. */
+#define HPI_PAD_TITLE                   HPI_CTL_ATTR(PAD, 3)
+/** The text string containing the comment. */
+#define HPI_PAD_COMMENT                 HPI_CTL_ATTR(PAD, 4)
+/** The integer containing the PTY code. */
+#define HPI_PAD_PROGRAM_TYPE            HPI_CTL_ATTR(PAD, 5)
+/** The integer containing the program identification. */
+#define HPI_PAD_PROGRAM_ID              HPI_CTL_ATTR(PAD, 6)
+/** The integer containing whether traffic information is supported.
+Contains either 1 or 0. */
+#define HPI_PAD_TA_SUPPORT              HPI_CTL_ATTR(PAD, 7)
+/** The integer containing whether traffic announcement is in progress.
+Contains either 1 or 0. */
+#define HPI_PAD_TA_ACTIVE               HPI_CTL_ATTR(PAD, 8)
+/** \} */
+/** \} */
+
+/* VOX control attributes */
+#define HPI_VOX_THRESHOLD               HPI_CTL_ATTR(VOX, 1)
+
+/*?? channel mode used hpi_multiplexer_source attribute == 1 */
+#define HPI_CHANNEL_MODE_MODE HPI_CTL_ATTR(CHANNEL_MODE, 1)
+
+/** \defgroup channel_modes Channel Modes
+Used for HPI_ChannelModeSet/Get()
+\{
+*/
+/** Left channel out = left channel in, Right channel out = right channel in. */
+#define HPI_CHANNEL_MODE_NORMAL                 1
+/** Left channel out = right channel in, Right channel out = left channel in. */
+#define HPI_CHANNEL_MODE_SWAP                   2
+/** Left channel out = left channel in, Right channel out = left channel in. */
+#define HPI_CHANNEL_MODE_LEFT_TO_STEREO         3
+/** Left channel out = right channel in, Right channel out = right channel in.*/
+#define HPI_CHANNEL_MODE_RIGHT_TO_STEREO        4
+/** Left channel out = (left channel in + right channel in)/2,
+    Right channel out = mute. */
+#define HPI_CHANNEL_MODE_STEREO_TO_LEFT         5
+/** Left channel out = mute,
+    Right channel out = (right channel in + left channel in)/2. */
+#define HPI_CHANNEL_MODE_STEREO_TO_RIGHT        6
+#define HPI_CHANNEL_MODE_LAST                   6
+/** \} */
+
+/* Bitstream control set attributes */
+#define HPI_BITSTREAM_DATA_POLARITY     HPI_CTL_ATTR(BITSTREAM, 1)
+#define HPI_BITSTREAM_CLOCK_EDGE        HPI_CTL_ATTR(BITSTREAM, 2)
+#define HPI_BITSTREAM_CLOCK_SOURCE      HPI_CTL_ATTR(BITSTREAM, 3)
+
+#define HPI_POLARITY_POSITIVE           0
+#define HPI_POLARITY_NEGATIVE           1
+
+/* Bitstream control get attributes */
+#define HPI_BITSTREAM_ACTIVITY          1
+
+/* SampleClock control attributes */
+#define HPI_SAMPLECLOCK_SOURCE                  HPI_CTL_ATTR(SAMPLECLOCK, 1)
+#define HPI_SAMPLECLOCK_SAMPLERATE              HPI_CTL_ATTR(SAMPLECLOCK, 2)
+#define HPI_SAMPLECLOCK_SOURCE_INDEX            HPI_CTL_ATTR(SAMPLECLOCK, 3)
+#define HPI_SAMPLECLOCK_LOCAL_SAMPLERATE\
+	HPI_CTL_ATTR(SAMPLECLOCK, 4)
+#define HPI_SAMPLECLOCK_AUTO                    HPI_CTL_ATTR(SAMPLECLOCK, 5)
+#define HPI_SAMPLECLOCK_LOCAL_LOCK                      HPI_CTL_ATTR(SAMPLECLOCK, 6)
+
+/* Microphone control attributes */
+#define HPI_MICROPHONE_PHANTOM_POWER HPI_CTL_ATTR(MICROPHONE, 1)
+
+/** Equalizer control attributes
+*/
+/** Used to get number of filters in an EQ. (Can't set) */
+#define HPI_EQUALIZER_NUM_FILTERS HPI_CTL_ATTR(EQUALIZER, 1)
+/** Set/get the filter by type, freq, Q, gain */
+#define HPI_EQUALIZER_FILTER HPI_CTL_ATTR(EQUALIZER, 2)
+/** Get the biquad coefficients */
+#define HPI_EQUALIZER_COEFFICIENTS HPI_CTL_ATTR(EQUALIZER, 3)
+
+#define HPI_COMPANDER_PARAMS HPI_CTL_ATTR(COMPANDER, 1)
+
+/* Cobranet control attributes.
+   MUST be distinct from all other control attributes.
+   This is so that host side processing can easily identify a Cobranet control
+   and apply additional host side operations (like copying data) as required.
+*/
+#define HPI_COBRANET_SET         HPI_CTL_ATTR(COBRANET, 1)
+#define HPI_COBRANET_GET         HPI_CTL_ATTR(COBRANET, 2)
+#define HPI_COBRANET_SET_DATA    HPI_CTL_ATTR(COBRANET, 3)
+#define HPI_COBRANET_GET_DATA    HPI_CTL_ATTR(COBRANET, 4)
+#define HPI_COBRANET_GET_STATUS  HPI_CTL_ATTR(COBRANET, 5)
+#define HPI_COBRANET_SEND_PACKET HPI_CTL_ATTR(COBRANET, 6)
+#define HPI_COBRANET_GET_PACKET  HPI_CTL_ATTR(COBRANET, 7)
+
+/*------------------------------------------------------------
+ Cobranet Chip Bridge - copied from HMI.H
+------------------------------------------------------------*/
+#define  HPI_COBRANET_HMI_cobra_bridge           0x20000
+#define  HPI_COBRANET_HMI_cobra_bridge_tx_pkt_buf \
+	(HPI_COBRANET_HMI_cobra_bridge + 0x1000)
+#define  HPI_COBRANET_HMI_cobra_bridge_rx_pkt_buf \
+	(HPI_COBRANET_HMI_cobra_bridge + 0x2000)
+#define  HPI_COBRANET_HMI_cobra_if_table1         0x110000
+#define  HPI_COBRANET_HMI_cobra_if_phy_address \
+	(HPI_COBRANET_HMI_cobra_if_table1 + 0xd)
+#define  HPI_COBRANET_HMI_cobra_protocolIP       0x72000
+#define  HPI_COBRANET_HMI_cobra_ip_mon_currentIP \
+	(HPI_COBRANET_HMI_cobra_protocolIP + 0x0)
+#define  HPI_COBRANET_HMI_cobra_ip_mon_staticIP \
+	(HPI_COBRANET_HMI_cobra_protocolIP + 0x2)
+#define  HPI_COBRANET_HMI_cobra_sys              0x100000
+#define  HPI_COBRANET_HMI_cobra_sys_desc \
+		(HPI_COBRANET_HMI_cobra_sys + 0x0)
+#define  HPI_COBRANET_HMI_cobra_sys_objectID \
+	(HPI_COBRANET_HMI_cobra_sys + 0x100)
+#define  HPI_COBRANET_HMI_cobra_sys_contact \
+	(HPI_COBRANET_HMI_cobra_sys + 0x200)
+#define  HPI_COBRANET_HMI_cobra_sys_name \
+		(HPI_COBRANET_HMI_cobra_sys + 0x300)
+#define  HPI_COBRANET_HMI_cobra_sys_location \
+	(HPI_COBRANET_HMI_cobra_sys + 0x400)
+
+/*------------------------------------------------------------
+ Cobranet Chip Status bits
+------------------------------------------------------------*/
+#define HPI_COBRANET_HMI_STATUS_RXPACKET 2
+#define HPI_COBRANET_HMI_STATUS_TXPACKET 3
+
+/*------------------------------------------------------------
+ Ethernet header size
+------------------------------------------------------------*/
+#define HPI_ETHERNET_HEADER_SIZE (16)
+
+/* These defines are used to fill in protocol information for an Ethernet packet
+    sent using HMI on CS18102 */
+/** ID supplied by Cirrius for ASI packets. */
+#define HPI_ETHERNET_PACKET_ID                  0x85
+/** Simple packet - no special routing required */
+#define HPI_ETHERNET_PACKET_V1                  0x01
+/** This packet must make its way to the host across the HPI interface */
+#define HPI_ETHERNET_PACKET_HOSTED_VIA_HMI      0x20
+/** This packet must make its way to the host across the HPI interface */
+#define HPI_ETHERNET_PACKET_HOSTED_VIA_HMI_V1   0x21
+/** This packet must make its way to the host across the HPI interface */
+#define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI      0x40
+/** This packet must make its way to the host across the HPI interface */
+#define HPI_ETHERNET_PACKET_HOSTED_VIA_HPI_V1   0x41
+
+#define HPI_ETHERNET_UDP_PORT (44600)	/*!< UDP messaging port */
+
+/** Base network time out is set to 100 milli-seconds. */
+#define HPI_ETHERNET_TIMEOUT_MS      (100)
+
+/** \defgroup tonedet_attr Tonedetector attributes
+\{
+Used by HPI_ToneDetector_Set() and HPI_ToneDetector_Get()
+*/
+
+/** Set the threshold level of a tonedetector,
+Threshold is a -ve number in units of dB/100,
+*/
+#define HPI_TONEDETECTOR_THRESHOLD HPI_CTL_ATTR(TONEDETECTOR, 1)
+
+/** Get the current state of tonedetection
+The result is a bitmap of detected tones.  pairs of bits represent the left
+and right channels, with left channel in LSB.
+The lowest frequency detector state is in the LSB
+*/
+#define HPI_TONEDETECTOR_STATE HPI_CTL_ATTR(TONEDETECTOR, 2)
+
+/** Get the frequency of a tonedetector band.
+*/
+#define HPI_TONEDETECTOR_FREQUENCY HPI_CTL_ATTR(TONEDETECTOR, 3)
+
+/**\}*/
+
+/** \defgroup silencedet_attr SilenceDetector attributes
+\{
+*/
+
+/** Get the current state of tonedetection
+The result is a bitmap with 1s for silent channels. Left channel is in LSB
+*/
+#define HPI_SILENCEDETECTOR_STATE \
+  HPI_CTL_ATTR(SILENCEDETECTOR, 2)
+
+/** Set the threshold level of a SilenceDetector,
+Threshold is a -ve number in units of dB/100,
+*/
+#define HPI_SILENCEDETECTOR_THRESHOLD \
+  HPI_CTL_ATTR(SILENCEDETECTOR, 1)
+
+/** get/set the silence time before the detector triggers
+*/
+#define HPI_SILENCEDETECTOR_DELAY \
+       HPI_CTL_ATTR(SILENCEDETECTOR, 3)
+
+/**\}*/
+
+/* Locked memory buffer alloc/free phases */
+/** use one message to allocate or free physical memory */
+#define HPI_BUFFER_CMD_EXTERNAL                 0
+/** alloc physical memory */
+#define HPI_BUFFER_CMD_INTERNAL_ALLOC           1
+/** send physical memory address to adapter */
+#define HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER    2
+/** notify adapter to stop using physical buffer */
+#define HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER   3
+/** free physical buffer */
+#define HPI_BUFFER_CMD_INTERNAL_FREE            4
+
+/******************************************* CONTROLX ATTRIBUTES ****/
+/* NOTE: All controlx attributes must be unique, unlike control attributes */
+
+/*****************************************************************************/
+/*****************************************************************************/
+/********               HPI LOW LEVEL MESSAGES                  *******/
+/*****************************************************************************/
+/*****************************************************************************/
+/** Pnp ids */
+/** "ASI"  - actual is "ASX" - need to change */
+#define HPI_ID_ISAPNP_AUDIOSCIENCE      0x0669
+/** PCI vendor ID that AudioScience uses */
+#define HPI_PCI_VENDOR_ID_AUDIOSCIENCE  0x175C
+/** PCI vendor ID that the DSP56301 has */
+#define HPI_PCI_VENDOR_ID_MOTOROLA      0x1057
+/** PCI vendor ID that TI uses */
+#define HPI_PCI_VENDOR_ID_TI            0x104C
+
+#define HPI_PCI_DEV_ID_PCI2040          0xAC60
+/** TI's C6205 PCI interface has this ID */
+#define HPI_PCI_DEV_ID_DSP6205          0xA106
+
+#define HPI_USB_VENDOR_ID_AUDIOSCIENCE  0x1257
+#define HPI_USB_W2K_TAG                 0x57495341	/* "ASIW"       */
+#define HPI_USB_LINUX_TAG               0x4C495341	/* "ASIL"       */
+
+/** First 2 hex digits define the adapter family */
+#define HPI_ADAPTER_FAMILY_MASK         0xff00
+
+#define HPI_ADAPTER_FAMILY_ASI(f)   (f & HPI_ADAPTER_FAMILY_MASK)
+#define HPI_ADAPTER_ASI(f)   (f)
+
+/******************************************* message types */
+#define HPI_TYPE_MESSAGE                        1
+#define HPI_TYPE_RESPONSE                       2
+#define HPI_TYPE_DATA                           3
+#define HPI_TYPE_SSX2BYPASS_MESSAGE             4
+
+/******************************************* object types */
+#define HPI_OBJ_SUBSYSTEM                       1
+#define HPI_OBJ_ADAPTER                         2
+#define HPI_OBJ_OSTREAM                         3
+#define HPI_OBJ_ISTREAM                         4
+#define HPI_OBJ_MIXER                           5
+#define HPI_OBJ_NODE                            6
+#define HPI_OBJ_CONTROL                         7
+#define HPI_OBJ_NVMEMORY                        8
+#define HPI_OBJ_GPIO                            9
+#define HPI_OBJ_WATCHDOG                        10
+#define HPI_OBJ_CLOCK                           11
+#define HPI_OBJ_PROFILE                         12
+#define HPI_OBJ_CONTROLEX                       13
+#define HPI_OBJ_ASYNCEVENT                      14
+
+#define HPI_OBJ_MAXINDEX                        14
+
+/******************************************* methods/functions */
+
+#define HPI_OBJ_FUNCTION_SPACING        0x100
+#define HPI_MAKE_INDEX(obj, index) (obj * HPI_OBJ_FUNCTION_SPACING + index)
+#define HPI_EXTRACT_INDEX(fn) (fn & 0xff)
+
+/* SUB-SYSTEM */
+#define HPI_SUBSYS_OPEN                 HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 1)
+#define HPI_SUBSYS_GET_VERSION          HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 2)
+#define HPI_SUBSYS_GET_INFO             HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 3)
+#define HPI_SUBSYS_FIND_ADAPTERS        HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 4)
+#define HPI_SUBSYS_CREATE_ADAPTER       HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 5)
+#define HPI_SUBSYS_CLOSE                HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 6)
+#define HPI_SUBSYS_DELETE_ADAPTER       HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 7)
+#define HPI_SUBSYS_DRIVER_LOAD          HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 8)
+#define HPI_SUBSYS_DRIVER_UNLOAD        HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 9)
+#define HPI_SUBSYS_READ_PORT_8          HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 10)
+#define HPI_SUBSYS_WRITE_PORT_8         HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 11)
+#define HPI_SUBSYS_GET_NUM_ADAPTERS     HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 12)
+#define HPI_SUBSYS_GET_ADAPTER          HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 13)
+#define HPI_SUBSYS_SET_NETWORK_INTERFACE HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 14)
+#define HPI_SUBSYS_FUNCTION_COUNT 14
+/* ADAPTER */
+#define HPI_ADAPTER_OPEN                HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 1)
+#define HPI_ADAPTER_CLOSE               HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 2)
+#define HPI_ADAPTER_GET_INFO            HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 3)
+#define HPI_ADAPTER_GET_ASSERT          HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 4)
+#define HPI_ADAPTER_TEST_ASSERT         HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 5)
+#define HPI_ADAPTER_SET_MODE            HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 6)
+#define HPI_ADAPTER_GET_MODE            HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 7)
+#define HPI_ADAPTER_ENABLE_CAPABILITY   HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 8)
+#define HPI_ADAPTER_SELFTEST            HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 9)
+#define HPI_ADAPTER_FIND_OBJECT         HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 10)
+#define HPI_ADAPTER_QUERY_FLASH         HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 11)
+#define HPI_ADAPTER_START_FLASH         HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 12)
+#define HPI_ADAPTER_PROGRAM_FLASH       HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 13)
+#define HPI_ADAPTER_SET_PROPERTY        HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 14)
+#define HPI_ADAPTER_GET_PROPERTY        HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 15)
+#define HPI_ADAPTER_ENUM_PROPERTY       HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 16)
+#define HPI_ADAPTER_MODULE_INFO         HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 17)
+#define HPI_ADAPTER_DEBUG_READ          HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 18)
+#define HPI_ADAPTER_FUNCTION_COUNT 18
+/* OUTPUT STREAM */
+#define HPI_OSTREAM_OPEN                HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 1)
+#define HPI_OSTREAM_CLOSE               HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 2)
+#define HPI_OSTREAM_WRITE               HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 3)
+#define HPI_OSTREAM_START               HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 4)
+#define HPI_OSTREAM_STOP                HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 5)
+#define HPI_OSTREAM_RESET               HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 6)
+#define HPI_OSTREAM_GET_INFO            HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 7)
+#define HPI_OSTREAM_QUERY_FORMAT        HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 8)
+#define HPI_OSTREAM_DATA                HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 9)
+#define HPI_OSTREAM_SET_VELOCITY        HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 10)
+#define HPI_OSTREAM_SET_PUNCHINOUT      HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 11)
+#define HPI_OSTREAM_SINEGEN             HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 12)
+#define HPI_OSTREAM_ANC_RESET           HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 13)
+#define HPI_OSTREAM_ANC_GET_INFO        HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 14)
+#define HPI_OSTREAM_ANC_READ            HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 15)
+#define HPI_OSTREAM_SET_TIMESCALE       HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 16)
+#define HPI_OSTREAM_SET_FORMAT          HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 17)
+#define HPI_OSTREAM_HOSTBUFFER_ALLOC    HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 18)
+#define HPI_OSTREAM_HOSTBUFFER_FREE     HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 19)
+#define HPI_OSTREAM_GROUP_ADD           HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 20)
+#define HPI_OSTREAM_GROUP_GETMAP        HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 21)
+#define HPI_OSTREAM_GROUP_RESET         HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 22)
+#define HPI_OSTREAM_HOSTBUFFER_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 23)
+#define HPI_OSTREAM_WAIT_START          HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 24)
+#define HPI_OSTREAM_FUNCTION_COUNT              24
+/* INPUT STREAM */
+#define HPI_ISTREAM_OPEN                HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 1)
+#define HPI_ISTREAM_CLOSE               HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 2)
+#define HPI_ISTREAM_SET_FORMAT          HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 3)
+#define HPI_ISTREAM_READ                HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 4)
+#define HPI_ISTREAM_START               HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 5)
+#define HPI_ISTREAM_STOP                HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 6)
+#define HPI_ISTREAM_RESET               HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 7)
+#define HPI_ISTREAM_GET_INFO            HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 8)
+#define HPI_ISTREAM_QUERY_FORMAT        HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 9)
+#define HPI_ISTREAM_ANC_RESET           HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 10)
+#define HPI_ISTREAM_ANC_GET_INFO        HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 11)
+#define HPI_ISTREAM_ANC_WRITE           HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 12)
+#define HPI_ISTREAM_HOSTBUFFER_ALLOC    HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 13)
+#define HPI_ISTREAM_HOSTBUFFER_FREE     HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 14)
+#define HPI_ISTREAM_GROUP_ADD           HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 15)
+#define HPI_ISTREAM_GROUP_GETMAP        HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 16)
+#define HPI_ISTREAM_GROUP_RESET         HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 17)
+#define HPI_ISTREAM_HOSTBUFFER_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 18)
+#define HPI_ISTREAM_WAIT_START          HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 19)
+#define HPI_ISTREAM_FUNCTION_COUNT              19
+/* MIXER */
+/* NOTE:
+   GET_NODE_INFO, SET_CONNECTION, GET_CONNECTIONS are not currently used */
+#define HPI_MIXER_OPEN                  HPI_MAKE_INDEX(HPI_OBJ_MIXER, 1)
+#define HPI_MIXER_CLOSE                 HPI_MAKE_INDEX(HPI_OBJ_MIXER, 2)
+#define HPI_MIXER_GET_INFO              HPI_MAKE_INDEX(HPI_OBJ_MIXER, 3)
+#define HPI_MIXER_GET_NODE_INFO         HPI_MAKE_INDEX(HPI_OBJ_MIXER, 4)
+#define HPI_MIXER_GET_CONTROL           HPI_MAKE_INDEX(HPI_OBJ_MIXER, 5)
+#define HPI_MIXER_SET_CONNECTION        HPI_MAKE_INDEX(HPI_OBJ_MIXER, 6)
+#define HPI_MIXER_GET_CONNECTIONS       HPI_MAKE_INDEX(HPI_OBJ_MIXER, 7)
+#define HPI_MIXER_GET_CONTROL_BY_INDEX  HPI_MAKE_INDEX(HPI_OBJ_MIXER, 8)
+#define HPI_MIXER_GET_CONTROL_ARRAY_BY_INDEX  HPI_MAKE_INDEX(HPI_OBJ_MIXER, 9)
+#define HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES HPI_MAKE_INDEX(HPI_OBJ_MIXER, 10)
+#define HPI_MIXER_STORE                 HPI_MAKE_INDEX(HPI_OBJ_MIXER, 11)
+#define HPI_MIXER_FUNCTION_COUNT        11
+/* MIXER CONTROLS */
+#define HPI_CONTROL_GET_INFO            HPI_MAKE_INDEX(HPI_OBJ_CONTROL, 1)
+#define HPI_CONTROL_GET_STATE           HPI_MAKE_INDEX(HPI_OBJ_CONTROL, 2)
+#define HPI_CONTROL_SET_STATE           HPI_MAKE_INDEX(HPI_OBJ_CONTROL, 3)
+#define HPI_CONTROL_FUNCTION_COUNT 3
+/* NONVOL MEMORY */
+#define HPI_NVMEMORY_OPEN               HPI_MAKE_INDEX(HPI_OBJ_NVMEMORY, 1)
+#define HPI_NVMEMORY_READ_BYTE          HPI_MAKE_INDEX(HPI_OBJ_NVMEMORY, 2)
+#define HPI_NVMEMORY_WRITE_BYTE         HPI_MAKE_INDEX(HPI_OBJ_NVMEMORY, 3)
+#define HPI_NVMEMORY_FUNCTION_COUNT 3
+/* GPIO */
+#define HPI_GPIO_OPEN                   HPI_MAKE_INDEX(HPI_OBJ_GPIO, 1)
+#define HPI_GPIO_READ_BIT               HPI_MAKE_INDEX(HPI_OBJ_GPIO, 2)
+#define HPI_GPIO_WRITE_BIT              HPI_MAKE_INDEX(HPI_OBJ_GPIO, 3)
+#define HPI_GPIO_READ_ALL               HPI_MAKE_INDEX(HPI_OBJ_GPIO, 4)
+#define HPI_GPIO_WRITE_STATUS           HPI_MAKE_INDEX(HPI_OBJ_GPIO, 5)
+#define HPI_GPIO_FUNCTION_COUNT 5
+/* ASYNC EVENT */
+#define HPI_ASYNCEVENT_OPEN             HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 1)
+#define HPI_ASYNCEVENT_CLOSE            HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 2)
+#define HPI_ASYNCEVENT_WAIT             HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 3)
+#define HPI_ASYNCEVENT_GETCOUNT         HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 4)
+#define HPI_ASYNCEVENT_GET              HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 5)
+#define HPI_ASYNCEVENT_SENDEVENTS       HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 6)
+#define HPI_ASYNCEVENT_FUNCTION_COUNT 6
+/* WATCH-DOG */
+#define HPI_WATCHDOG_OPEN               HPI_MAKE_INDEX(HPI_OBJ_WATCHDOG, 1)
+#define HPI_WATCHDOG_SET_TIME           HPI_MAKE_INDEX(HPI_OBJ_WATCHDOG, 2)
+#define HPI_WATCHDOG_PING               HPI_MAKE_INDEX(HPI_OBJ_WATCHDOG, 3)
+/* CLOCK */
+#define HPI_CLOCK_OPEN                  HPI_MAKE_INDEX(HPI_OBJ_CLOCK, 1)
+#define HPI_CLOCK_SET_TIME              HPI_MAKE_INDEX(HPI_OBJ_CLOCK, 2)
+#define HPI_CLOCK_GET_TIME              HPI_MAKE_INDEX(HPI_OBJ_CLOCK, 3)
+/* PROFILE */
+#define HPI_PROFILE_OPEN_ALL            HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 1)
+#define HPI_PROFILE_START_ALL           HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 2)
+#define HPI_PROFILE_STOP_ALL            HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 3)
+#define HPI_PROFILE_GET                 HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 4)
+#define HPI_PROFILE_GET_IDLECOUNT       HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 5)
+#define HPI_PROFILE_GET_NAME            HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 6)
+#define HPI_PROFILE_GET_UTILIZATION     HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 7)
+#define HPI_PROFILE_FUNCTION_COUNT 7
+/* ////////////////////////////////////////////////////////////////////// */
+/* PRIVATE ATTRIBUTES */
+
+/* ////////////////////////////////////////////////////////////////////// */
+/* STRUCTURES */
+#ifndef DISABLE_PRAGMA_PACK1
+#pragma pack(push, 1)
+#endif
+
+/** PCI bus resource */
+struct hpi_pci {
+	u32 __iomem *ap_mem_base[HPI_MAX_ADAPTER_MEM_SPACES];
+	struct pci_dev *p_os_data;
+
+#ifndef HPI64BIT		/* keep structure size constant */
+	u32 padding[HPI_MAX_ADAPTER_MEM_SPACES + 1];
+#endif
+	u16 vendor_id;
+	u16 device_id;
+	u16 subsys_vendor_id;
+	u16 subsys_device_id;
+	u16 bus_number;
+	u16 device_number;
+	u32 interrupt;
+};
+
+struct hpi_resource {
+	union {
+		const struct hpi_pci *pci;
+		const char *net_if;
+	} r;
+#ifndef HPI64BIT		/* keep structure size constant */
+	u32 pad_to64;
+#endif
+	u16 bus_type;		/* HPI_BUS_PNPISA, _PCI, _USB etc */
+	u16 padding;
+
+};
+
+/** Format info used inside struct hpi_message
+    Not the same as public API struct hpi_format */
+struct hpi_msg_format {
+	u32 sample_rate;
+				/**< 11025, 32000, 44100 ... */
+	u32 bit_rate;	      /**< for MPEG */
+	u32 attributes;
+				/**< Stereo/JointStereo/Mono */
+	u16 channels;	      /**< 1,2..., (or ancillary mode or idle bit */
+	u16 format; /**< HPI_FORMAT_PCM16, _MPEG etc. see \ref HPI_FORMATS. */
+};
+
+/**  Buffer+format structure.
+	 Must be kept 7 * 32 bits to match public struct hpi_datastruct */
+struct hpi_msg_data {
+	struct hpi_msg_format format;
+	u8 *pb_data;
+#ifndef HPI64BIT
+	u32 padding;
+#endif
+	u32 data_size;
+};
+
+/** struct hpi_datastructure used up to 3.04 driver */
+struct hpi_data_legacy32 {
+	struct hpi_format format;
+	u32 pb_data;
+	u32 data_size;
+};
+
+#ifdef HPI64BIT
+/* Compatibility version of struct hpi_data*/
+struct hpi_data_compat32 {
+	struct hpi_msg_format format;
+	u32 pb_data;
+	u32 padding;
+	u32 data_size;
+};
+#endif
+
+struct hpi_buffer {
+  /** placehoder for backward compatability (see dwBufferSize) */
+	struct hpi_msg_format reserved;
+	u32 command;	/**< HPI_BUFFER_CMD_xxx*/
+	u32 pci_address; /**< PCI physical address of buffer for DSP DMA */
+	u32 buffer_size; /**< must line up with data_size of HPI_DATA*/
+};
+
+/*/////////////////////////////////////////////////////////////////////////// */
+/* This is used for background buffer bus mastering stream buffers.           */
+struct hpi_hostbuffer_status {
+	u32 samples_processed;
+	u32 auxiliary_data_available;
+	u32 stream_state;
+	/* DSP index in to the host bus master buffer. */
+	u32 dSP_index;
+	/* Host index in to the host bus master buffer. */
+	u32 host_index;
+	u32 size_in_bytes;
+};
+
+struct hpi_streamid {
+	u16 object_type;
+		    /**< Type of object, HPI_OBJ_OSTREAM or HPI_OBJ_ISTREAM. */
+	u16 stream_index; /**< outstream or instream index. */
+};
+
+struct hpi_punchinout {
+	u32 punch_in_sample;
+	u32 punch_out_sample;
+};
+
+struct hpi_subsys_msg {
+	struct hpi_resource resource;
+};
+
+struct hpi_subsys_res {
+	u32 version;
+	u32 data;		/* used to return extended version */
+	u16 num_adapters;	/* number of adapters */
+	u16 adapter_index;
+	u16 aw_adapter_list[HPI_MAX_ADAPTERS];
+};
+
+struct hpi_adapter_msg {
+	u32 adapter_mode;	/* adapter mode */
+	u16 assert_id;		/* assert number for "test assert" call
+				   object_index for find object call
+				   query_or_set for hpi_adapter_set_mode_ex() */
+	u16 object_type;	/* for adapter find object call */
+};
+
+union hpi_adapterx_msg {
+	struct hpi_adapter_msg adapter;
+	struct {
+		u32 offset;
+	} query_flash;
+	struct {
+		u32 offset;
+		u32 length;
+		u32 key;
+	} start_flash;
+	struct {
+		u32 checksum;
+		u16 sequence;
+		u16 length;
+		u16 offset; /**< offset from start of msg to data */
+		u16 unused;
+	} program_flash;
+	struct {
+		u16 property;
+		u16 parameter1;
+		u16 parameter2;
+	} property_set;
+	struct {
+		u16 index;
+		u16 what;
+		u16 property_index;
+	} property_enum;
+	struct {
+		u16 index;
+	} module_info;
+	struct {
+		u32 dsp_address;
+		u32 count_bytes;
+	} debug_read;
+};
+
+struct hpi_adapter_res {
+	u32 serial_number;
+	u16 adapter_type;
+	u16 adapter_index;	/* is this needed? also used for dsp_index */
+	u16 num_instreams;
+	u16 num_outstreams;
+	u16 num_mixers;
+	u16 version;
+	u8 sz_adapter_assert[HPI_STRING_LEN];
+};
+
+union hpi_adapterx_res {
+	struct hpi_adapter_res adapter;
+	struct {
+		u32 checksum;
+		u32 length;
+		u32 version;
+	} query_flash;
+	struct {
+		u16 sequence;
+	} program_flash;
+	struct {
+		u16 parameter1;
+		u16 parameter2;
+	} property_get;
+};
+
+struct hpi_stream_msg {
+	union {
+		struct hpi_msg_data data;
+		struct hpi_data_legacy32 data32;
+		u16 velocity;
+		struct hpi_punchinout pio;
+		u32 time_scale;
+		struct hpi_buffer buffer;
+		struct hpi_streamid stream;
+	} u;
+};
+
+struct hpi_stream_res {
+	union {
+		struct {
+			/* size of hardware buffer */
+			u32 buffer_size;
+			/* OutStream - data to play,
+			   InStream - data recorded */
+			u32 data_available;
+			/* OutStream - samples played,
+			   InStream - samples recorded */
+			u32 samples_transferred;
+			/* Adapter - OutStream - data to play,
+			   InStream - data recorded */
+			u32 auxiliary_data_available;
+			u16 state;	/* HPI_STATE_PLAYING, _STATE_STOPPED */
+			u16 padding;
+		} stream_info;
+		struct {
+			u32 buffer_size;
+			u32 data_available;
+			u32 samples_transfered;
+			u16 state;
+			u16 outstream_index;
+			u16 instream_index;
+			u16 padding;
+			u32 auxiliary_data_available;
+		} legacy_stream_info;
+		struct {
+			/* bitmap of grouped OutStreams */
+			u32 outstream_group_map;
+			/* bitmap of grouped InStreams */
+			u32 instream_group_map;
+		} group_info;
+		struct {
+			/* pointer to the buffer */
+			u8 *p_buffer;
+			/* pointer to the hostbuffer status */
+			struct hpi_hostbuffer_status *p_status;
+		} hostbuffer_info;
+	} u;
+};
+
+struct hpi_mixer_msg {
+	u16 control_index;
+	u16 control_type;	/* = HPI_CONTROL_METER _VOLUME etc */
+	u16 padding1;		/* maintain alignment of subsequent fields */
+	u16 node_type1;		/* = HPI_SOURCENODE_LINEIN etc */
+	u16 node_index1;	/* = 0..N */
+	u16 node_type2;
+	u16 node_index2;
+	u16 padding2;		/* round to 4 bytes */
+};
+
+struct hpi_mixer_res {
+	u16 src_node_type;	/* = HPI_SOURCENODE_LINEIN etc */
+	u16 src_node_index;	/* = 0..N */
+	u16 dst_node_type;
+	u16 dst_node_index;
+	/* Also controlType for MixerGetControlByIndex */
+	u16 control_index;
+	/* may indicate which DSP the control is located on */
+	u16 dsp_index;
+};
+
+union hpi_mixerx_msg {
+	struct {
+		u16 starting_index;
+		u16 flags;
+		u32 length_in_bytes;	/* length in bytes of p_data */
+		u32 p_data;	/* pointer to a data array */
+	} gcabi;
+	struct {
+		u16 command;
+		u16 index;
+	} store;		/* for HPI_MIXER_STORE message */
+};
+
+union hpi_mixerx_res {
+	struct {
+		u32 bytes_returned;	/* size of items returned */
+		u32 p_data;	/* pointer to data array */
+		u16 more_to_do;	/* indicates if there is more to do */
+	} gcabi;
+};
+
+struct hpi_control_msg {
+	u16 attribute;		/* control attribute or property */
+	u16 saved_index;
+	u32 param1;		/* generic parameter 1 */
+	u32 param2;		/* generic parameter 2 */
+	short an_log_value[HPI_MAX_CHANNELS];
+};
+
+struct hpi_control_union_msg {
+	u16 attribute;		/* control attribute or property */
+	u16 saved_index;	/* only used in ctrl save/restore */
+	union {
+		struct {
+			u32 param1;	/* generic parameter 1 */
+			u32 param2;	/* generic parameter 2 */
+			short an_log_value[HPI_MAX_CHANNELS];
+		} old;
+		union {
+			u32 frequency;
+			u32 gain;
+			u32 band;
+			u32 deemphasis;
+			u32 program;
+			struct {
+				u32 mode;
+				u32 value;
+			} mode;
+		} tuner;
+	} u;
+};
+
+struct hpi_control_res {
+	/* Could make union. dwParam, anLogValue never used in same response */
+	u32 param1;
+	u32 param2;
+	short an_log_value[HPI_MAX_CHANNELS];
+};
+
+union hpi_control_union_res {
+	struct {
+		u32 param1;
+		u32 param2;
+		short an_log_value[HPI_MAX_CHANNELS];
+	} old;
+	union {
+		u32 band;
+		u32 frequency;
+		u32 gain;
+		u32 level;
+		u32 deemphasis;
+		struct {
+			u32 data[2];
+			u32 bLER;
+		} rds;
+	} tuner;
+	struct {
+		char sz_data[8];
+		u32 remaining_chars;
+	} chars8;
+	char c_data12[12];
+};
+
+/* HPI_CONTROLX_STRUCTURES */
+
+/* Message */
+
+/** Used for all HMI variables where max length <= 8 bytes
+*/
+struct hpi_controlx_msg_cobranet_data {
+	u32 hmi_address;
+	u32 byte_count;
+	u32 data[2];
+};
+
+/** Used for string data, and for packet bridge
+*/
+struct hpi_controlx_msg_cobranet_bigdata {
+	u32 hmi_address;
+	u32 byte_count;
+	u8 *pb_data;
+#ifndef HPI64BIT
+	u32 padding;
+#endif
+};
+
+/** Used for PADS control reading of string fields.
+*/
+struct hpi_controlx_msg_pad_data {
+	u32 field;
+	u32 byte_count;
+	u8 *pb_data;
+#ifndef HPI64BIT
+	u32 padding;
+#endif
+};
+
+/** Used for generic data
+*/
+
+struct hpi_controlx_msg_generic {
+	u32 param1;
+	u32 param2;
+};
+
+struct hpi_controlx_msg {
+	u16 attribute;		/* control attribute or property */
+	u16 saved_index;
+	union {
+		struct hpi_controlx_msg_cobranet_data cobranet_data;
+		struct hpi_controlx_msg_cobranet_bigdata cobranet_bigdata;
+		struct hpi_controlx_msg_generic generic;
+		struct hpi_controlx_msg_pad_data pad_data;
+		/*struct param_value universal_value; */
+		/* nothing extra to send for status read */
+	} u;
+};
+
+/* Response */
+/**
+*/
+struct hpi_controlx_res_cobranet_data {
+	u32 byte_count;
+	u32 data[2];
+};
+
+struct hpi_controlx_res_cobranet_bigdata {
+	u32 byte_count;
+};
+
+struct hpi_controlx_res_cobranet_status {
+	u32 status;
+	u32 readable_size;
+	u32 writeable_size;
+};
+
+struct hpi_controlx_res_generic {
+	u32 param1;
+	u32 param2;
+};
+
+struct hpi_controlx_res {
+	union {
+		struct hpi_controlx_res_cobranet_bigdata cobranet_bigdata;
+		struct hpi_controlx_res_cobranet_data cobranet_data;
+		struct hpi_controlx_res_cobranet_status cobranet_status;
+		struct hpi_controlx_res_generic generic;
+		/*struct param_info universal_info; */
+		/*struct param_value universal_value; */
+	} u;
+};
+
+struct hpi_nvmemory_msg {
+	u16 address;
+	u16 data;
+};
+
+struct hpi_nvmemory_res {
+	u16 size_in_bytes;
+	u16 data;
+};
+
+struct hpi_gpio_msg {
+	u16 bit_index;
+	u16 bit_data;
+};
+
+struct hpi_gpio_res {
+	u16 number_input_bits;
+	u16 number_output_bits;
+	u16 bit_data[4];
+};
+
+struct hpi_async_msg {
+	u32 events;
+	u16 maximum_events;
+	u16 padding;
+};
+
+struct hpi_async_res {
+	union {
+		struct {
+			u16 count;
+		} count;
+		struct {
+			u32 events;
+			u16 number_returned;
+			u16 padding;
+		} get;
+		struct hpi_async_event event;
+	} u;
+};
+
+struct hpi_watchdog_msg {
+	u32 time_ms;
+};
+
+struct hpi_watchdog_res {
+	u32 time_ms;
+};
+
+struct hpi_clock_msg {
+	u16 hours;
+	u16 minutes;
+	u16 seconds;
+	u16 milli_seconds;
+};
+
+struct hpi_clock_res {
+	u16 size_in_bytes;
+	u16 hours;
+	u16 minutes;
+	u16 seconds;
+	u16 milli_seconds;
+	u16 padding;
+};
+
+struct hpi_profile_msg {
+	u16 bin_index;
+	u16 padding;
+};
+
+struct hpi_profile_res_open {
+	u16 max_profiles;
+};
+
+struct hpi_profile_res_time {
+	u32 micro_seconds;
+	u32 call_count;
+	u32 max_micro_seconds;
+	u32 min_micro_seconds;
+	u16 seconds;
+};
+
+struct hpi_profile_res_name {
+	u8 sz_name[32];
+};
+
+struct hpi_profile_res {
+	union {
+		struct hpi_profile_res_open o;
+		struct hpi_profile_res_time t;
+		struct hpi_profile_res_name n;
+	} u;
+};
+
+struct hpi_message_header {
+	u16 size;		/* total size in bytes */
+	u8 type;		/* HPI_TYPE_MESSAGE  */
+	u8 version;		/* message version */
+	u16 object;		/* HPI_OBJ_* */
+	u16 function;		/* HPI_SUBSYS_xxx, HPI_ADAPTER_xxx */
+	u16 adapter_index;	/* the adapter index */
+	u16 obj_index;		/* */
+};
+
+struct hpi_message {
+	/* following fields must match HPI_MESSAGE_HEADER */
+	u16 size;		/* total size in bytes */
+	u8 type;		/* HPI_TYPE_MESSAGE  */
+	u8 version;		/* message version */
+	u16 object;		/* HPI_OBJ_* */
+	u16 function;		/* HPI_SUBSYS_xxx, HPI_ADAPTER_xxx */
+	u16 adapter_index;	/* the adapter index */
+	u16 obj_index;		/*  */
+	union {
+		struct hpi_subsys_msg s;
+		struct hpi_adapter_msg a;
+		union hpi_adapterx_msg ax;
+		struct hpi_stream_msg d;
+		struct hpi_mixer_msg m;
+		union hpi_mixerx_msg mx;	/* extended mixer; */
+		struct hpi_control_msg c;	/* mixer control; */
+		/* identical to struct hpi_control_msg,
+		   but field naming is improved */
+		struct hpi_control_union_msg cu;
+		struct hpi_controlx_msg cx;	/* extended mixer control; */
+		struct hpi_nvmemory_msg n;
+		struct hpi_gpio_msg l;	/* digital i/o */
+		struct hpi_watchdog_msg w;
+		struct hpi_clock_msg t;	/* dsp time */
+		struct hpi_profile_msg p;
+		struct hpi_async_msg as;
+		char fixed_size[32];
+	} u;
+};
+
+#define HPI_MESSAGE_SIZE_BY_OBJECT { \
+	sizeof(struct hpi_message_header) ,   /* default, no object type 0 */ \
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_subsys_msg),\
+	sizeof(struct hpi_message_header) + sizeof(union hpi_adapterx_msg),\
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_stream_msg),\
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_stream_msg),\
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_mixer_msg),\
+	sizeof(struct hpi_message_header) ,   /* no node message */ \
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_control_msg),\
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_nvmemory_msg),\
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_gpio_msg),\
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_watchdog_msg),\
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_clock_msg),\
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_profile_msg),\
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_controlx_msg),\
+	sizeof(struct hpi_message_header) + sizeof(struct hpi_async_msg) \
+}
+
+struct hpi_response_header {
+	u16 size;
+	u8 type;		/* HPI_TYPE_RESPONSE  */
+	u8 version;		/* response version */
+	u16 object;		/* HPI_OBJ_* */
+	u16 function;		/* HPI_SUBSYS_xxx, HPI_ADAPTER_xxx */
+	u16 error;		/* HPI_ERROR_xxx */
+	u16 specific_error;	/* adapter specific error */
+};
+
+struct hpi_response {
+/* following fields must match HPI_RESPONSE_HEADER */
+	u16 size;
+	u8 type;		/* HPI_TYPE_RESPONSE  */
+	u8 version;		/* response version */
+	u16 object;		/* HPI_OBJ_* */
+	u16 function;		/* HPI_SUBSYS_xxx, HPI_ADAPTER_xxx */
+	u16 error;		/* HPI_ERROR_xxx */
+	u16 specific_error;	/* adapter specific error */
+	union {
+		struct hpi_subsys_res s;
+		struct hpi_adapter_res a;
+		union hpi_adapterx_res ax;
+		struct hpi_stream_res d;
+		struct hpi_mixer_res m;
+		union hpi_mixerx_res mx;	/* extended mixer; */
+		struct hpi_control_res c;	/* mixer control; */
+		/* identical to hpi_control_res, but field naming is improved */
+		union hpi_control_union_res cu;
+		struct hpi_controlx_res cx;	/* extended mixer control; */
+		struct hpi_nvmemory_res n;
+		struct hpi_gpio_res l;	/* digital i/o */
+		struct hpi_watchdog_res w;
+		struct hpi_clock_res t;	/* dsp time */
+		struct hpi_profile_res p;
+		struct hpi_async_res as;
+		u8 bytes[52];
+	} u;
+};
+
+#define HPI_RESPONSE_SIZE_BY_OBJECT { \
+	sizeof(struct hpi_response_header) ,/* default, no object type 0 */ \
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_subsys_res),\
+	sizeof(struct hpi_response_header) + sizeof(union  hpi_adapterx_res),\
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_stream_res),\
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_stream_res),\
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_mixer_res),\
+	sizeof(struct hpi_response_header) , /* no node response */ \
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_control_res),\
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_nvmemory_res),\
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_gpio_res),\
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_watchdog_res),\
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_clock_res),\
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_profile_res),\
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_controlx_res),\
+	sizeof(struct hpi_response_header) + sizeof(struct hpi_async_res) \
+}
+
+/*********************** version 1 message/response *****************************/
+#define HPINET_ETHERNET_DATA_SIZE (1500)
+#define HPINET_IP_HDR_SIZE (20)
+#define HPINET_IP_DATA_SIZE (HPINET_ETHERNET_DATA_SIZE - HPINET_IP_HDR_SIZE)
+#define HPINET_UDP_HDR_SIZE (8)
+#define HPINET_UDP_DATA_SIZE (HPINET_IP_DATA_SIZE - HPINET_UDP_HDR_SIZE)
+#define HPINET_ASI_HDR_SIZE (2)
+#define HPINET_ASI_DATA_SIZE (HPINET_UDP_DATA_SIZE - HPINET_ASI_HDR_SIZE)
+
+#define HPI_MAX_PAYLOAD_SIZE (HPINET_ASI_DATA_SIZE - 2)
+
+/* New style message/response, but still V0 compatible */
+struct hpi_msg_adapter_get_info {
+	struct hpi_message_header h;
+};
+
+struct hpi_res_adapter_get_info {
+	struct hpi_response_header h;	/*v0 */
+	struct hpi_adapter_res p;
+};
+
+/* padding is so these are same size as v0 hpi_message */
+struct hpi_msg_adapter_query_flash {
+	struct hpi_message_header h;
+	u32 offset;
+	u8 pad_to_version0_size[sizeof(struct hpi_message) -	/* V0 res */
+		sizeof(struct hpi_message_header) - 1 * sizeof(u32)];
+};
+
+/* padding is so these are same size as v0 hpi_response */
+struct hpi_res_adapter_query_flash {
+	struct hpi_response_header h;
+	u32 checksum;
+	u32 length;
+	u32 version;
+	u8 pad_to_version0_size[sizeof(struct hpi_response) -	/* V0 res */
+		sizeof(struct hpi_response_header) - 3 * sizeof(u32)];
+};
+
+struct hpi_msg_adapter_start_flash {
+	struct hpi_message_header h;
+	u32 offset;
+	u32 length;
+	u32 key;
+	u8 pad_to_version0_size[sizeof(struct hpi_message) -	/* V0 res */
+		sizeof(struct hpi_message_header) - 3 * sizeof(u32)];
+};
+
+struct hpi_res_adapter_start_flash {
+	struct hpi_response_header h;
+	u8 pad_to_version0_size[sizeof(struct hpi_response) -	/* V0 res */
+		sizeof(struct hpi_response_header)];
+};
+
+struct hpi_msg_adapter_program_flash_payload {
+	u32 checksum;
+	u16 sequence;
+	u16 length;
+	u16 offset; /**< offset from start of msg to data */
+	u16 unused;
+	/* ensure sizeof(header + payload) == sizeof(hpi_message_V0)
+	   because old firmware expects data after message of this size */
+	u8 pad_to_version0_size[sizeof(struct hpi_message) -	/* V0 message */
+		sizeof(struct hpi_message_header) - sizeof(u32) -
+		4 * sizeof(u16)];
+};
+
+struct hpi_msg_adapter_program_flash {
+	struct hpi_message_header h;
+	struct hpi_msg_adapter_program_flash_payload p;
+	u32 data[256];
+};
+
+struct hpi_res_adapter_program_flash {
+	struct hpi_response_header h;
+	u16 sequence;
+	u8 pad_to_version0_size[sizeof(struct hpi_response) -	/* V0 res */
+		sizeof(struct hpi_response_header) - sizeof(u16)];
+};
+
+#if 1
+#define hpi_message_header_v1 hpi_message_header
+#define hpi_response_header_v1 hpi_response_header
+#else
+/* V1 headers in Addition to v0 headers */
+struct hpi_message_header_v1 {
+	struct hpi_message_header h0;
+/* struct {
+} h1; */
+};
+
+struct hpi_response_header_v1 {
+	struct hpi_response_header h0;
+	struct {
+		u16 adapter_index;	/* the adapter index */
+		u16 obj_index;	/* object index */
+	} h1;
+};
+#endif
+
+/* STRV HPI Packet */
+struct hpi_msg_strv {
+	struct hpi_message_header h;
+	struct hpi_entity strv;
+};
+
+struct hpi_res_strv {
+	struct hpi_response_header h;
+	struct hpi_entity strv;
+};
+#define MIN_STRV_PACKET_SIZE sizeof(struct hpi_res_strv)
+
+struct hpi_msg_payload_v0 {
+	struct hpi_message_header h;
+	union {
+		struct hpi_subsys_msg s;
+		struct hpi_adapter_msg a;
+		union hpi_adapterx_msg ax;
+		struct hpi_stream_msg d;
+		struct hpi_mixer_msg m;
+		union hpi_mixerx_msg mx;
+		struct hpi_control_msg c;
+		struct hpi_control_union_msg cu;
+		struct hpi_controlx_msg cx;
+		struct hpi_nvmemory_msg n;
+		struct hpi_gpio_msg l;
+		struct hpi_watchdog_msg w;
+		struct hpi_clock_msg t;
+		struct hpi_profile_msg p;
+		struct hpi_async_msg as;
+	} u;
+};
+
+struct hpi_res_payload_v0 {
+	struct hpi_response_header h;
+	union {
+		struct hpi_subsys_res s;
+		struct hpi_adapter_res a;
+		union hpi_adapterx_res ax;
+		struct hpi_stream_res d;
+		struct hpi_mixer_res m;
+		union hpi_mixerx_res mx;
+		struct hpi_control_res c;
+		union hpi_control_union_res cu;
+		struct hpi_controlx_res cx;
+		struct hpi_nvmemory_res n;
+		struct hpi_gpio_res l;
+		struct hpi_watchdog_res w;
+		struct hpi_clock_res t;
+		struct hpi_profile_res p;
+		struct hpi_async_res as;
+	} u;
+};
+
+union hpi_message_buffer_v1 {
+	struct hpi_message m0;	/* version 0 */
+	struct hpi_message_header_v1 h;
+	unsigned char buf[HPI_MAX_PAYLOAD_SIZE];
+};
+
+union hpi_response_buffer_v1 {
+	struct hpi_response r0;	/* version 0 */
+	struct hpi_response_header_v1 h;
+	unsigned char buf[HPI_MAX_PAYLOAD_SIZE];
+};
+
+compile_time_assert((sizeof(union hpi_message_buffer_v1) <=
+		HPI_MAX_PAYLOAD_SIZE), message_buffer_ok);
+compile_time_assert((sizeof(union hpi_response_buffer_v1) <=
+		HPI_MAX_PAYLOAD_SIZE), response_buffer_ok);
+
+/*////////////////////////////////////////////////////////////////////////// */
+/* declarations for compact control calls  */
+struct hpi_control_defn {
+	u8 type;
+	u8 channels;
+	u8 src_node_type;
+	u8 src_node_index;
+	u8 dest_node_type;
+	u8 dest_node_index;
+};
+
+/*////////////////////////////////////////////////////////////////////////// */
+/* declarations for control caching (internal to HPI<->DSP interaction)      */
+
+/** A compact representation of (part of) a controls state.
+Used for efficient transfer of the control state
+between DSP and host or across a network
+*/
+struct hpi_control_cache_info {
+	/** one of HPI_CONTROL_* */
+	u8 control_type;
+	/** The total size of cached information in 32-bit words. */
+	u8 size_in32bit_words;
+	/** The original index of the control on the DSP */
+	u16 control_index;
+};
+
+struct hpi_control_cache_single {
+	struct hpi_control_cache_info i;
+	union {
+		struct {	/* volume */
+			u16 an_log[2];
+		} v;
+		struct {	/* peak meter */
+			u16 an_log_peak[2];
+			u16 an_logRMS[2];
+		} p;
+		struct {	/* channel mode */
+			u16 mode;
+		} m;
+		struct {	/* multiplexer */
+			u16 source_node_type;
+			u16 source_node_index;
+		} x;
+		struct {	/* level/trim */
+			u16 an_log[2];
+		} l;
+		struct {	/* tuner - partial caching.
+				   some attributes go to the DSP. */
+			u32 freq_ink_hz;
+			u16 band;
+			u16 level;
+		} t;
+		struct {	/* AESEBU rx status */
+			u32 error_status;
+			u32 source;
+		} aes3rx;
+		struct {	/* AESEBU tx */
+			u32 format;
+		} aes3tx;
+		struct {	/* tone detector */
+			u16 state;
+		} tone;
+		struct {	/* silence detector */
+			u32 state;
+			u32 count;
+		} silence;
+		struct {	/* sample clock */
+			u16 source;
+			u16 source_index;
+			u32 sample_rate;
+		} clk;
+		struct {	/* microphone control */
+			u16 state;
+		} phantom_power;
+		struct {	/* generic control */
+			u32 dw1;
+			u32 dw2;
+		} g;
+	} u;
+};
+
+struct hpi_control_cache_pad {
+	struct hpi_control_cache_info i;
+	u32 field_valid_flags;
+	u8 c_channel[8];
+	u8 c_artist[40];
+	u8 c_title[40];
+	u8 c_comment[200];
+	u32 pTY;
+	u32 pI;
+	u32 traffic_supported;
+	u32 traffic_anouncement;
+};
+
+/*/////////////////////////////////////////////////////////////////////////// */
+/* declarations for 2^N sized FIFO buffer (internal to HPI<->DSP interaction) */
+struct hpi_fifo_buffer {
+	u32 size;
+	u32 dSP_index;
+	u32 host_index;
+};
+
+#ifndef DISABLE_PRAGMA_PACK1
+#pragma pack(pop)
+#endif
+
+/* skip host side function declarations for DSP
+   compile and documentation extraction */
+
+char hpi_handle_object(const u32 handle);
+
+void hpi_handle_to_indexes(const u32 handle, u16 *pw_adapter_index,
+	u16 *pw_object_index);
+
+u32 hpi_indexes_to_handle(const char c_object, const u16 adapter_index,
+	const u16 object_index);
+
+/*////////////////////////////////////////////////////////////////////////// */
+
+/* main HPI entry point */
+hpi_handler_func hpi_send_recv;
+
+/* UDP message */
+void hpi_send_recvUDP(struct hpi_message *phm, struct hpi_response *phr,
+	const unsigned int timeout);
+
+/* used in PnP OS/driver */
+u16 hpi_subsys_create_adapter(const struct hpi_hsubsys *ph_subsys,
+	const struct hpi_resource *p_resource, u16 *pw_adapter_index);
+
+u16 hpi_subsys_delete_adapter(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index);
+
+u16 hpi_outstream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u8 **pp_buffer,
+	struct hpi_hostbuffer_status **pp_status);
+
+u16 hpi_instream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u8 **pp_buffer,
+	struct hpi_hostbuffer_status **pp_status);
+
+u16 hpi_adapter_restart(u16 adapter_index);
+
+/*
+The following 3 functions were last declared in header files for
+driver 3.10. HPI_ControlQuery() used to be the recommended way
+of getting a volume range. Declared here for binary asihpi32.dll
+compatibility.
+*/
+
+void hpi_format_to_msg(struct hpi_msg_format *pMF,
+	const struct hpi_format *pF);
+void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR);
+
+/*////////////////////////////////////////////////////////////////////////// */
+/* declarations for individual HPI entry points */
+hpi_handler_func HPI_1000;
+hpi_handler_func HPI_6000;
+hpi_handler_func HPI_6205;
+hpi_handler_func HPI_COMMON;
+
+#endif				/* _HPI_INTERNAL_H_ */

+ 643 - 0
sound/pci/asihpi/hpicmn.c

@@ -0,0 +1,643 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+\file hpicmn.c
+
+ Common functions used by hpixxxx.c modules
+
+(C) Copyright AudioScience Inc. 1998-2003
+*******************************************************************************/
+#define SOURCEFILE_NAME "hpicmn.c"
+
+#include "hpi_internal.h"
+#include "hpidebug.h"
+#include "hpicmn.h"
+
+struct hpi_adapters_list {
+	struct hpios_spinlock list_lock;
+	struct hpi_adapter_obj adapter[HPI_MAX_ADAPTERS];
+	u16 gw_num_adapters;
+};
+
+static struct hpi_adapters_list adapters;
+
+/**
+* Given an HPI Message that was sent out and a response that was received,
+* validate that the response has the correct fields filled in,
+* i.e ObjectType, Function etc
+**/
+u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr)
+{
+	u16 error = 0;
+
+	if ((phr->type != HPI_TYPE_RESPONSE)
+		|| (phr->object != phm->object)
+		|| (phr->function != phm->function))
+		error = HPI_ERROR_INVALID_RESPONSE;
+
+	return error;
+}
+
+u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
+{
+	u16 retval = 0;
+	/*HPI_ASSERT(pao->wAdapterType); */
+
+	hpios_alistlock_lock(&adapters);
+
+	if (pao->index >= HPI_MAX_ADAPTERS) {
+		retval = HPI_ERROR_BAD_ADAPTER_NUMBER;
+		goto unlock;
+	}
+
+	if (adapters.adapter[pao->index].adapter_type) {
+		{
+			retval = HPI_DUPLICATE_ADAPTER_NUMBER;
+			goto unlock;
+		}
+	}
+	adapters.adapter[pao->index] = *pao;
+	hpios_dsplock_init(&adapters.adapter[pao->index]);
+	adapters.gw_num_adapters++;
+
+unlock:
+	hpios_alistlock_un_lock(&adapters);
+	return retval;
+}
+
+void hpi_delete_adapter(struct hpi_adapter_obj *pao)
+{
+	memset(pao, 0, sizeof(struct hpi_adapter_obj));
+
+	hpios_alistlock_lock(&adapters);
+	adapters.gw_num_adapters--;	/* dec the number of adapters */
+	hpios_alistlock_un_lock(&adapters);
+}
+
+/**
+* FindAdapter returns a pointer to the struct hpi_adapter_obj with
+* index wAdapterIndex in an HPI_ADAPTERS_LIST structure.
+*
+*/
+struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index)
+{
+	struct hpi_adapter_obj *pao = NULL;
+
+	if (adapter_index >= HPI_MAX_ADAPTERS) {
+		HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d ",
+			adapter_index);
+		return NULL;
+	}
+
+	pao = &adapters.adapter[adapter_index];
+	if (pao->adapter_type != 0) {
+		/*
+		   HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n",
+		   wAdapterIndex);
+		 */
+		return pao;
+	} else {
+		/*
+		   HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n",
+		   wAdapterIndex);
+		 */
+		return NULL;
+	}
+}
+
+/**
+*
+* wipe an HPI_ADAPTERS_LIST structure.
+*
+**/
+static void wipe_adapter_list(void
+	)
+{
+	memset(&adapters, 0, sizeof(adapters));
+}
+
+/**
+* SubSysGetAdapters fills awAdapterList in an struct hpi_response structure
+* with all adapters in the given HPI_ADAPTERS_LIST.
+*
+*/
+static void subsys_get_adapters(struct hpi_response *phr)
+{
+	/* fill in the response adapter array with the position */
+	/* identified by the adapter number/index of the adapters in */
+	/* this HPI */
+	/* i.e. if we have an A120 with it's jumper set to */
+	/* Adapter Number 2 then put an Adapter type A120 in the */
+	/* array in position 1 */
+	/* NOTE: AdapterNumber is 1..N, Index is 0..N-1 */
+
+	/* input:  NONE */
+	/* output: wNumAdapters */
+	/*                 awAdapter[] */
+	/* */
+
+	short i;
+	struct hpi_adapter_obj *pao = NULL;
+
+	HPI_DEBUG_LOG(VERBOSE, "subsys_get_adapters\n");
+
+	/* for each adapter, place it's type in the position of the array */
+	/* corresponding to it's adapter number */
+	for (i = 0; i < adapters.gw_num_adapters; i++) {
+		pao = &adapters.adapter[i];
+		if (phr->u.s.aw_adapter_list[pao->index] != 0) {
+			phr->error = HPI_DUPLICATE_ADAPTER_NUMBER;
+			phr->specific_error = pao->index;
+			return;
+		}
+		phr->u.s.aw_adapter_list[pao->index] = pao->adapter_type;
+	}
+
+	phr->u.s.num_adapters = adapters.gw_num_adapters;
+	phr->error = 0;	/* the function completed OK; */
+}
+
+static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
+{
+	unsigned int i;
+	int cached = 0;
+	if (!pC)
+		return 0;
+	if ((!pC->init) && (pC->p_cache != NULL) && (pC->control_count)
+		&& (pC->cache_size_in_bytes)
+		) {
+		u32 *p_master_cache;
+		pC->init = 1;
+
+		p_master_cache = (u32 *)pC->p_cache;
+		HPI_DEBUG_LOG(VERBOSE, "check %d controls\n",
+			pC->control_count);
+		for (i = 0; i < pC->control_count; i++) {
+			struct hpi_control_cache_info *info =
+				(struct hpi_control_cache_info *)
+				p_master_cache;
+
+			if (info->control_type) {
+				pC->p_info[i] = info;
+				cached++;
+			} else
+				pC->p_info[i] = NULL;
+
+			if (info->size_in32bit_words)
+				p_master_cache += info->size_in32bit_words;
+			else
+				p_master_cache +=
+					sizeof(struct
+					hpi_control_cache_single) /
+					sizeof(u32);
+
+			HPI_DEBUG_LOG(VERBOSE,
+				"cached %d, pinfo %p index %d type %d\n",
+				cached, pC->p_info[i], info->control_index,
+				info->control_type);
+		}
+		/*
+		   We didn't find anything to cache, so try again later !
+		 */
+		if (!cached)
+			pC->init = 0;
+	}
+	return pC->init;
+}
+
+/** Find a control.
+*/
+static short find_control(struct hpi_message *phm,
+	struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI,
+	u16 *pw_control_index)
+{
+	*pw_control_index = phm->obj_index;
+
+	if (!control_cache_alloc_check(p_cache)) {
+		HPI_DEBUG_LOG(VERBOSE,
+			"control_cache_alloc_check() failed. adap%d ci%d\n",
+			phm->adapter_index, *pw_control_index);
+		return 0;
+	}
+
+	*pI = p_cache->p_info[*pw_control_index];
+	if (!*pI) {
+		HPI_DEBUG_LOG(VERBOSE, "uncached adap %d, control %d\n",
+			phm->adapter_index, *pw_control_index);
+		return 0;
+	} else {
+		HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
+			(*pI)->control_type);
+	}
+	return 1;
+}
+
+/** Used by the kernel driver to figure out if a buffer needs mapping.
+ */
+short hpi_check_buffer_mapping(struct hpi_control_cache *p_cache,
+	struct hpi_message *phm, void **p, unsigned int *pN)
+{
+	*pN = 0;
+	*p = NULL;
+	if ((phm->function == HPI_CONTROL_GET_STATE)
+		&& (phm->object == HPI_OBJ_CONTROLEX)
+		) {
+		u16 control_index;
+		struct hpi_control_cache_info *pI;
+
+		if (!find_control(phm, p_cache, &pI, &control_index))
+			return 0;
+	}
+	return 0;
+}
+
+/* allow unified treatment of several string fields within struct */
+#define HPICMN_PAD_OFS_AND_SIZE(m)  {\
+	offsetof(struct hpi_control_cache_pad, m), \
+	sizeof(((struct hpi_control_cache_pad *)(NULL))->m) }
+
+struct pad_ofs_size {
+	unsigned int offset;
+	unsigned int field_size;
+};
+
+static struct pad_ofs_size pad_desc[] = {
+	HPICMN_PAD_OFS_AND_SIZE(c_channel),	/* HPI_PAD_CHANNEL_NAME */
+	HPICMN_PAD_OFS_AND_SIZE(c_artist),	/* HPI_PAD_ARTIST */
+	HPICMN_PAD_OFS_AND_SIZE(c_title),	/* HPI_PAD_TITLE */
+	HPICMN_PAD_OFS_AND_SIZE(c_comment),	/* HPI_PAD_COMMENT */
+};
+
+/** CheckControlCache checks the cache and fills the struct hpi_response
+ * accordingly. It returns one if a cache hit occurred, zero otherwise.
+ */
+short hpi_check_control_cache(struct hpi_control_cache *p_cache,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	short found = 1;
+	u16 control_index;
+	struct hpi_control_cache_info *pI;
+	struct hpi_control_cache_single *pC;
+	struct hpi_control_cache_pad *p_pad;
+
+	if (!find_control(phm, p_cache, &pI, &control_index))
+		return 0;
+
+	phr->error = 0;
+
+	/* pC is the default cached control strucure. May be cast to
+	   something else in the following switch statement.
+	 */
+	pC = (struct hpi_control_cache_single *)pI;
+	p_pad = (struct hpi_control_cache_pad *)pI;
+
+	switch (pI->control_type) {
+
+	case HPI_CONTROL_METER:
+		if (phm->u.c.attribute == HPI_METER_PEAK) {
+			phr->u.c.an_log_value[0] = pC->u.p.an_log_peak[0];
+			phr->u.c.an_log_value[1] = pC->u.p.an_log_peak[1];
+		} else if (phm->u.c.attribute == HPI_METER_RMS) {
+			phr->u.c.an_log_value[0] = pC->u.p.an_logRMS[0];
+			phr->u.c.an_log_value[1] = pC->u.p.an_logRMS[1];
+		} else
+			found = 0;
+		break;
+	case HPI_CONTROL_VOLUME:
+		if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
+			phr->u.c.an_log_value[0] = pC->u.v.an_log[0];
+			phr->u.c.an_log_value[1] = pC->u.v.an_log[1];
+		} else
+			found = 0;
+		break;
+	case HPI_CONTROL_MULTIPLEXER:
+		if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
+			phr->u.c.param1 = pC->u.x.source_node_type;
+			phr->u.c.param2 = pC->u.x.source_node_index;
+		} else {
+			found = 0;
+		}
+		break;
+	case HPI_CONTROL_CHANNEL_MODE:
+		if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
+			phr->u.c.param1 = pC->u.m.mode;
+		else
+			found = 0;
+		break;
+	case HPI_CONTROL_LEVEL:
+		if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
+			phr->u.c.an_log_value[0] = pC->u.l.an_log[0];
+			phr->u.c.an_log_value[1] = pC->u.l.an_log[1];
+		} else
+			found = 0;
+		break;
+	case HPI_CONTROL_TUNER:
+		{
+			struct hpi_control_cache_single *pCT =
+				(struct hpi_control_cache_single *)pI;
+			if (phm->u.c.attribute == HPI_TUNER_FREQ)
+				phr->u.c.param1 = pCT->u.t.freq_ink_hz;
+			else if (phm->u.c.attribute == HPI_TUNER_BAND)
+				phr->u.c.param1 = pCT->u.t.band;
+			else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
+				&& (phm->u.c.param1 ==
+					HPI_TUNER_LEVEL_AVERAGE))
+				phr->u.c.param1 = pCT->u.t.level;
+			else
+				found = 0;
+		}
+		break;
+	case HPI_CONTROL_AESEBU_RECEIVER:
+		if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
+			phr->u.c.param1 = pC->u.aes3rx.error_status;
+		else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
+			phr->u.c.param1 = pC->u.aes3rx.source;
+		else
+			found = 0;
+		break;
+	case HPI_CONTROL_AESEBU_TRANSMITTER:
+		if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
+			phr->u.c.param1 = pC->u.aes3tx.format;
+		else
+			found = 0;
+		break;
+	case HPI_CONTROL_TONEDETECTOR:
+		if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE)
+			phr->u.c.param1 = pC->u.tone.state;
+		else
+			found = 0;
+		break;
+	case HPI_CONTROL_SILENCEDETECTOR:
+		if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
+			phr->u.c.param1 = pC->u.silence.state;
+			phr->u.c.param2 = pC->u.silence.count;
+		} else
+			found = 0;
+		break;
+	case HPI_CONTROL_MICROPHONE:
+		if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
+			phr->u.c.param1 = pC->u.phantom_power.state;
+		else
+			found = 0;
+		break;
+	case HPI_CONTROL_SAMPLECLOCK:
+		if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
+			phr->u.c.param1 = pC->u.clk.source;
+		else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
+			if (pC->u.clk.source_index ==
+				HPI_ERROR_ILLEGAL_CACHE_VALUE) {
+				phr->u.c.param1 = 0;
+				phr->error = HPI_ERROR_INVALID_OPERATION;
+			} else
+				phr->u.c.param1 = pC->u.clk.source_index;
+		} else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
+			phr->u.c.param1 = pC->u.clk.sample_rate;
+		else
+			found = 0;
+		break;
+	case HPI_CONTROL_PAD:
+
+		if (!(p_pad->field_valid_flags & (1 <<
+					HPI_CTL_ATTR_INDEX(phm->u.c.
+						attribute)))) {
+			phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
+			break;
+		}
+
+		if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
+			phr->u.c.param1 = p_pad->pI;
+		else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
+			phr->u.c.param1 = p_pad->pTY;
+		else {
+			unsigned int index =
+				HPI_CTL_ATTR_INDEX(phm->u.c.attribute) - 1;
+			unsigned int offset = phm->u.c.param1;
+			unsigned int pad_string_len, field_size;
+			char *pad_string;
+			unsigned int tocopy;
+
+			HPI_DEBUG_LOG(VERBOSE, "PADS HPI_PADS_ %d\n",
+				phm->u.c.attribute);
+
+			if (index > ARRAY_SIZE(pad_desc) - 1) {
+				phr->error =
+					HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
+				break;
+			}
+
+			pad_string = ((char *)p_pad) + pad_desc[index].offset;
+			field_size = pad_desc[index].field_size;
+			/* Ensure null terminator */
+			pad_string[field_size - 1] = 0;
+
+			pad_string_len = strlen(pad_string) + 1;
+
+			if (offset > pad_string_len) {
+				phr->error = HPI_ERROR_INVALID_CONTROL_VALUE;
+				break;
+			}
+
+			tocopy = pad_string_len - offset;
+			if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
+				tocopy = sizeof(phr->u.cu.chars8.sz_data);
+
+			HPI_DEBUG_LOG(VERBOSE,
+				"PADS memcpy(%d), offset %d \n", tocopy,
+				offset);
+			memcpy(phr->u.cu.chars8.sz_data, &pad_string[offset],
+				tocopy);
+
+			phr->u.cu.chars8.remaining_chars =
+				pad_string_len - offset - tocopy;
+		}
+		break;
+	default:
+		found = 0;
+		break;
+	}
+
+	if (found)
+		HPI_DEBUG_LOG(VERBOSE,
+			"cached adap %d, ctl %d, type %d, attr %d\n",
+			phm->adapter_index, pI->control_index,
+			pI->control_type, phm->u.c.attribute);
+	else
+		HPI_DEBUG_LOG(VERBOSE,
+			"uncached adap %d, ctl %d, ctl type %d\n",
+			phm->adapter_index, pI->control_index,
+			pI->control_type);
+
+	if (found)
+		phr->size =
+			sizeof(struct hpi_response_header) +
+			sizeof(struct hpi_control_res);
+
+	return found;
+}
+
+/** Updates the cache with Set values.
+
+Only update if no error.
+Volume and Level return the limited values in the response, so use these
+Multiplexer does so use sent values
+*/
+void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
+	struct hpi_message *phm, struct hpi_response *phr)
+{
+	u16 control_index;
+	struct hpi_control_cache_single *pC;
+	struct hpi_control_cache_info *pI;
+
+	if (!find_control(phm, p_cache, &pI, &control_index))
+		return;
+
+	/* pC is the default cached control strucure.
+	   May be cast to something else in the following switch statement.
+	 */
+	pC = (struct hpi_control_cache_single *)pI;
+
+	switch (pI->control_type) {
+	case HPI_CONTROL_VOLUME:
+		if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
+			pC->u.v.an_log[0] = phr->u.c.an_log_value[0];
+			pC->u.v.an_log[1] = phr->u.c.an_log_value[1];
+		}
+		break;
+	case HPI_CONTROL_MULTIPLEXER:
+		/* mux does not return its setting on Set command. */
+		if (phr->error)
+			return;
+		if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
+			pC->u.x.source_node_type = (u16)phm->u.c.param1;
+			pC->u.x.source_node_index = (u16)phm->u.c.param2;
+		}
+		break;
+	case HPI_CONTROL_CHANNEL_MODE:
+		/* mode does not return its setting on Set command. */
+		if (phr->error)
+			return;
+		if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
+			pC->u.m.mode = (u16)phm->u.c.param1;
+		break;
+	case HPI_CONTROL_LEVEL:
+		if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
+			pC->u.v.an_log[0] = phr->u.c.an_log_value[0];
+			pC->u.v.an_log[1] = phr->u.c.an_log_value[1];
+		}
+		break;
+	case HPI_CONTROL_MICROPHONE:
+		if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
+			pC->u.phantom_power.state = (u16)phm->u.c.param1;
+		break;
+	case HPI_CONTROL_AESEBU_TRANSMITTER:
+		if (phr->error)
+			return;
+		if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
+			pC->u.aes3tx.format = phm->u.c.param1;
+		break;
+	case HPI_CONTROL_AESEBU_RECEIVER:
+		if (phr->error)
+			return;
+		if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
+			pC->u.aes3rx.source = phm->u.c.param1;
+		break;
+	case HPI_CONTROL_SAMPLECLOCK:
+		if (phr->error)
+			return;
+		if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
+			pC->u.clk.source = (u16)phm->u.c.param1;
+		else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX)
+			pC->u.clk.source_index = (u16)phm->u.c.param1;
+		else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
+			pC->u.clk.sample_rate = phm->u.c.param1;
+		break;
+	default:
+		break;
+	}
+}
+
+struct hpi_control_cache *hpi_alloc_control_cache(const u32
+	number_of_controls, const u32 size_in_bytes,
+	struct hpi_control_cache_info *pDSP_control_buffer)
+{
+	struct hpi_control_cache *p_cache =
+		kmalloc(sizeof(*p_cache), GFP_KERNEL);
+	p_cache->cache_size_in_bytes = size_in_bytes;
+	p_cache->control_count = number_of_controls;
+	p_cache->p_cache =
+		(struct hpi_control_cache_single *)pDSP_control_buffer;
+	p_cache->init = 0;
+	p_cache->p_info =
+		kmalloc(sizeof(*p_cache->p_info) * p_cache->control_count,
+		GFP_KERNEL);
+	return p_cache;
+}
+
+void hpi_free_control_cache(struct hpi_control_cache *p_cache)
+{
+	if ((p_cache->init) && (p_cache->p_info)) {
+		kfree(p_cache->p_info);
+		p_cache->p_info = NULL;
+		p_cache->init = 0;
+		kfree(p_cache);
+	}
+}
+
+static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
+{
+
+	switch (phm->function) {
+	case HPI_SUBSYS_OPEN:
+	case HPI_SUBSYS_CLOSE:
+	case HPI_SUBSYS_DRIVER_UNLOAD:
+		phr->error = 0;
+		break;
+	case HPI_SUBSYS_DRIVER_LOAD:
+		wipe_adapter_list();
+		hpios_alistlock_init(&adapters);
+		phr->error = 0;
+		break;
+	case HPI_SUBSYS_GET_INFO:
+		subsys_get_adapters(phr);
+		break;
+	case HPI_SUBSYS_CREATE_ADAPTER:
+	case HPI_SUBSYS_DELETE_ADAPTER:
+		phr->error = 0;
+		break;
+	default:
+		phr->error = HPI_ERROR_INVALID_FUNC;
+		break;
+	}
+}
+
+void HPI_COMMON(struct hpi_message *phm, struct hpi_response *phr)
+{
+	switch (phm->type) {
+	case HPI_TYPE_MESSAGE:
+		switch (phm->object) {
+		case HPI_OBJ_SUBSYSTEM:
+			subsys_message(phm, phr);
+			break;
+		}
+		break;
+
+	default:
+		phr->error = HPI_ERROR_INVALID_TYPE;
+		break;
+	}
+}

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

@@ -0,0 +1,64 @@
+/**
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+*/
+
+struct hpi_adapter_obj {
+	struct hpi_pci pci;	/* PCI info - bus#,dev#,address etc */
+	u16 adapter_type;	/* ASI6701 etc */
+	u16 index;		/* */
+	u16 open;		/* =1 when adapter open */
+	u16 mixer_open;
+
+	struct hpios_spinlock dsp_lock;
+
+	u16 dsp_crashed;
+	u16 has_control_cache;
+	void *priv;
+};
+
+struct hpi_control_cache {
+	u32 init;	     /**< indicates whether the
+				structures are initialized */
+	u32 control_count;
+	u32 cache_size_in_bytes;
+	struct hpi_control_cache_info
+	**p_info;		 /**< pointer to allocated memory of
+				lookup pointers. */
+	struct hpi_control_cache_single
+	*p_cache;		 /**< pointer to DSP's control cache. */
+};
+
+struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index);
+u16 hpi_add_adapter(struct hpi_adapter_obj *pao);
+
+void hpi_delete_adapter(struct hpi_adapter_obj *pao);
+
+short hpi_check_control_cache(struct hpi_control_cache *pC,
+	struct hpi_message *phm, struct hpi_response *phr);
+struct hpi_control_cache *hpi_alloc_control_cache(const u32
+	number_of_controls, const u32 size_in_bytes,
+	struct hpi_control_cache_info
+	*pDSP_control_buffer);
+void hpi_free_control_cache(struct hpi_control_cache *p_cache);
+
+void hpi_sync_control_cache(struct hpi_control_cache *pC,
+	struct hpi_message *phm, struct hpi_response *phr);
+u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
+short hpi_check_buffer_mapping(struct hpi_control_cache *p_cache,
+	struct hpi_message *phm, void **p, unsigned int *pN);

+ 225 - 0
sound/pci/asihpi/hpidebug.c

@@ -0,0 +1,225 @@
+/************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+Debug macro translation.
+
+************************************************************************/
+
+#include "hpi_internal.h"
+#include "hpidebug.h"
+
+/* Debug level; 0 quiet; 1 informative, 2 debug, 3 verbose debug.  */
+int hpi_debug_level = HPI_DEBUG_LEVEL_DEFAULT;
+
+void hpi_debug_init(void)
+{
+	printk(KERN_INFO "debug start\n");
+}
+
+int hpi_debug_level_set(int level)
+{
+	int old_level;
+
+	old_level = hpi_debug_level;
+	hpi_debug_level = level;
+	return old_level;
+}
+
+int hpi_debug_level_get(void)
+{
+	return hpi_debug_level;
+}
+
+#ifdef HPIOS_DEBUG_PRINT
+/* implies OS has no printf-like function */
+#include <stdarg.h>
+
+void hpi_debug_printf(char *fmt, ...)
+{
+	va_list arglist;
+	char buffer[128];
+
+	va_start(arglist, fmt);
+
+	if (buffer[0])
+		HPIOS_DEBUG_PRINT(buffer);
+	va_end(arglist);
+}
+#endif
+
+struct treenode {
+	void *array;
+	unsigned int num_elements;
+};
+
+#define make_treenode_from_array(nodename, array) \
+static void *tmp_strarray_##nodename[] = array; \
+static struct treenode nodename = { \
+	&tmp_strarray_##nodename, \
+	ARRAY_SIZE(tmp_strarray_##nodename) \
+};
+
+#define get_treenode_elem(node_ptr, idx, type)  \
+	(&(*((type *)(node_ptr)->array)[idx]))
+
+make_treenode_from_array(hpi_control_type_strings, HPI_CONTROL_TYPE_STRINGS)
+
+	make_treenode_from_array(hpi_subsys_strings, HPI_SUBSYS_STRINGS)
+	make_treenode_from_array(hpi_adapter_strings, HPI_ADAPTER_STRINGS)
+	make_treenode_from_array(hpi_istream_strings, HPI_ISTREAM_STRINGS)
+	make_treenode_from_array(hpi_ostream_strings, HPI_OSTREAM_STRINGS)
+	make_treenode_from_array(hpi_mixer_strings, HPI_MIXER_STRINGS)
+	make_treenode_from_array(hpi_node_strings,
+	{
+	"NODE is invalid object"})
+
+	make_treenode_from_array(hpi_control_strings, HPI_CONTROL_STRINGS)
+	make_treenode_from_array(hpi_nvmemory_strings, HPI_OBJ_STRINGS)
+	make_treenode_from_array(hpi_digitalio_strings, HPI_DIGITALIO_STRINGS)
+	make_treenode_from_array(hpi_watchdog_strings, HPI_WATCHDOG_STRINGS)
+	make_treenode_from_array(hpi_clock_strings, HPI_CLOCK_STRINGS)
+	make_treenode_from_array(hpi_profile_strings, HPI_PROFILE_STRINGS)
+	make_treenode_from_array(hpi_asyncevent_strings, HPI_ASYNCEVENT_STRINGS)
+#define HPI_FUNCTION_STRINGS \
+{ \
+  &hpi_subsys_strings,\
+  &hpi_adapter_strings,\
+  &hpi_ostream_strings,\
+  &hpi_istream_strings,\
+  &hpi_mixer_strings,\
+  &hpi_node_strings,\
+  &hpi_control_strings,\
+  &hpi_nvmemory_strings,\
+  &hpi_digitalio_strings,\
+  &hpi_watchdog_strings,\
+  &hpi_clock_strings,\
+  &hpi_profile_strings,\
+  &hpi_control_strings, \
+  &hpi_asyncevent_strings \
+};
+	make_treenode_from_array(hpi_function_strings, HPI_FUNCTION_STRINGS)
+
+	compile_time_assert(HPI_OBJ_MAXINDEX == 14, obj_list_doesnt_match);
+
+static char *hpi_function_string(unsigned int function)
+{
+	unsigned int object;
+	struct treenode *tmp;
+
+	object = function / HPI_OBJ_FUNCTION_SPACING;
+	function = function - object * HPI_OBJ_FUNCTION_SPACING;
+
+	if (object == 0 || object == HPI_OBJ_NODE
+		|| object > hpi_function_strings.num_elements)
+		return "invalid object";
+
+	tmp = get_treenode_elem(&hpi_function_strings, object - 1,
+		struct treenode *);
+
+	if (function == 0 || function > tmp->num_elements)
+		return "invalid function";
+
+	return get_treenode_elem(tmp, function - 1, char *);
+}
+
+void hpi_debug_message(struct hpi_message *phm, char *sz_fileline)
+{
+	if (phm) {
+		if ((phm->object <= HPI_OBJ_MAXINDEX) && phm->object) {
+			u16 index = 0;
+			u16 attrib = 0;
+			int is_control = 0;
+
+			index = phm->obj_index;
+			switch (phm->object) {
+			case HPI_OBJ_ADAPTER:
+			case HPI_OBJ_PROFILE:
+				break;
+			case HPI_OBJ_MIXER:
+				if (phm->function ==
+					HPI_MIXER_GET_CONTROL_BY_INDEX)
+					index = phm->u.m.control_index;
+				break;
+			case HPI_OBJ_OSTREAM:
+			case HPI_OBJ_ISTREAM:
+				break;
+
+			case HPI_OBJ_CONTROLEX:
+			case HPI_OBJ_CONTROL:
+				if (phm->version == 1)
+					attrib = HPI_CTL_ATTR(UNIVERSAL, 1);
+				else
+					attrib = phm->u.c.attribute;
+				is_control = 1;
+				break;
+			default:
+				break;
+			}
+
+			if (is_control && (attrib & 0xFF00)) {
+				int control_type = (attrib & 0xFF00) >> 8;
+				int attr_index = HPI_CTL_ATTR_INDEX(attrib);
+				/* note the KERN facility level
+				   is in szFileline already */
+				printk("%s adapter %d %s "
+					"ctrl_index x%04x %s %d\n",
+					sz_fileline, phm->adapter_index,
+					hpi_function_string(phm->function),
+					index,
+					get_treenode_elem
+					(&hpi_control_type_strings,
+						control_type, char *),
+					attr_index);
+
+			} else
+				printk("%s adapter %d %s "
+					"idx x%04x attr x%04x \n",
+					sz_fileline, phm->adapter_index,
+					hpi_function_string(phm->function),
+					index, attrib);
+		} else {
+			printk("adap=%d, invalid obj=%d, func=0x%x\n",
+				phm->adapter_index, phm->object,
+				phm->function);
+		}
+	} else
+		printk(KERN_ERR
+			"NULL message pointer to hpi_debug_message!\n");
+}
+
+void hpi_debug_data(u16 *pdata, u32 len)
+{
+	u32 i;
+	int j;
+	int k;
+	int lines;
+	int cols = 8;
+
+	lines = (len + cols - 1) / cols;
+	if (lines > 8)
+		lines = 8;
+
+	for (i = 0, j = 0; j < lines; j++) {
+		printk(KERN_DEBUG "%p:", (pdata + i));
+
+		for (k = 0; k < cols && i < len; i++, k++)
+			printk("%s%04x", k == 0 ? "" : " ", pdata[i]);
+
+		printk("\n");
+	}
+}

+ 385 - 0
sound/pci/asihpi/hpidebug.h

@@ -0,0 +1,385 @@
+/*****************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+Debug macros.
+
+*****************************************************************************/
+
+#ifndef _HPIDEBUG_H
+#define _HPIDEBUG_H
+
+#include "hpi_internal.h"
+
+/* Define debugging levels.  */
+enum { HPI_DEBUG_LEVEL_ERROR = 0,	/* always log errors */
+	HPI_DEBUG_LEVEL_WARNING = 1,
+	HPI_DEBUG_LEVEL_NOTICE = 2,
+	HPI_DEBUG_LEVEL_INFO = 3,
+	HPI_DEBUG_LEVEL_DEBUG = 4,
+	HPI_DEBUG_LEVEL_VERBOSE = 5	/* same printk level as DEBUG */
+};
+
+#define HPI_DEBUG_LEVEL_DEFAULT HPI_DEBUG_LEVEL_NOTICE
+
+/* an OS can define an extra flag string that is appended to
+   the start of each message, eg see hpios_linux.h */
+
+#ifdef SOURCEFILE_NAME
+#define FILE_LINE  SOURCEFILE_NAME ":" __stringify(__LINE__) " "
+#else
+#define FILE_LINE  __FILE__ ":" __stringify(__LINE__) " "
+#endif
+
+#if defined(HPI_DEBUG) && defined(_WINDOWS)
+#define HPI_DEBUGBREAK() debug_break()
+#else
+#define HPI_DEBUGBREAK()
+#endif
+
+#define HPI_DEBUG_ASSERT(expression) \
+	do { \
+		if (!(expression)) {\
+			printk(KERN_ERR  FILE_LINE\
+				"ASSERT " __stringify(expression));\
+			HPI_DEBUGBREAK();\
+		} \
+	} while (0)
+
+#define HPI_DEBUG_LOG(level, ...) \
+	do { \
+		if (hpi_debug_level >= HPI_DEBUG_LEVEL_##level) { \
+			printk(HPI_DEBUG_FLAG_##level \
+			FILE_LINE  __VA_ARGS__); \
+		} \
+	} while (0)
+
+void hpi_debug_init(void);
+int hpi_debug_level_set(int level);
+int hpi_debug_level_get(void);
+/* needed by Linux driver for dynamic debug level changes */
+extern int hpi_debug_level;
+
+void hpi_debug_message(struct hpi_message *phm, char *sz_fileline);
+
+void hpi_debug_data(u16 *pdata, u32 len);
+
+#define HPI_DEBUG_DATA(pdata, len)                                      \
+	do {                                                            \
+		if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE) \
+			hpi_debug_data(pdata, len); \
+	} while (0)
+
+#define HPI_DEBUG_MESSAGE(level, phm)                                   \
+	do {                                                            \
+		if (hpi_debug_level >= HPI_DEBUG_LEVEL_##level) {         \
+			hpi_debug_message(phm,HPI_DEBUG_FLAG_##level    \
+				FILE_LINE __stringify(level));\
+		}                                                       \
+	} while (0)
+
+#define HPI_DEBUG_RESPONSE(phr)                                         \
+	do {                                                            \
+		if ((hpi_debug_level >= HPI_DEBUG_LEVEL_DEBUG) && (phr->error))\
+			HPI_DEBUG_LOG(ERROR, \
+				"HPI response - error# %d\n", \
+				phr->error); \
+		else if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE) \
+			HPI_DEBUG_LOG(VERBOSE, "HPI response OK\n");\
+	} while (0)
+
+#ifndef compile_time_assert
+#define compile_time_assert(cond, msg) \
+    typedef char msg[(cond) ? 1 : -1]
+#endif
+
+	  /* check that size is exactly some number */
+#define function_count_check(sym, size) \
+    compile_time_assert((sym##_FUNCTION_COUNT) == (size),\
+	    strings_match_defs_##sym)
+
+/* These strings should be generated using a macro which defines
+   the corresponding symbol values.  */
+#define HPI_OBJ_STRINGS \
+{                               \
+  "HPI_OBJ_SUBSYSTEM",        \
+  "HPI_OBJ_ADAPTER",          \
+  "HPI_OBJ_OSTREAM",          \
+  "HPI_OBJ_ISTREAM",          \
+  "HPI_OBJ_MIXER",            \
+  "HPI_OBJ_NODE",             \
+  "HPI_OBJ_CONTROL",          \
+  "HPI_OBJ_NVMEMORY",         \
+  "HPI_OBJ_DIGITALIO",        \
+  "HPI_OBJ_WATCHDOG",         \
+  "HPI_OBJ_CLOCK",            \
+  "HPI_OBJ_PROFILE",          \
+  "HPI_OBJ_CONTROLEX"         \
+}
+
+#define HPI_SUBSYS_STRINGS      \
+{                               \
+  "HPI_SUBSYS_OPEN",          \
+  "HPI_SUBSYS_GET_VERSION",   \
+  "HPI_SUBSYS_GET_INFO",      \
+  "HPI_SUBSYS_FIND_ADAPTERS", \
+  "HPI_SUBSYS_CREATE_ADAPTER",\
+  "HPI_SUBSYS_CLOSE",         \
+  "HPI_SUBSYS_DELETE_ADAPTER", \
+  "HPI_SUBSYS_DRIVER_LOAD", \
+  "HPI_SUBSYS_DRIVER_UNLOAD", \
+  "HPI_SUBSYS_READ_PORT_8",   \
+  "HPI_SUBSYS_WRITE_PORT_8",  \
+  "HPI_SUBSYS_GET_NUM_ADAPTERS",\
+  "HPI_SUBSYS_GET_ADAPTER",   \
+  "HPI_SUBSYS_SET_NETWORK_INTERFACE"\
+}
+function_count_check(HPI_SUBSYS, 14);
+
+#define HPI_ADAPTER_STRINGS     \
+{                               \
+  "HPI_ADAPTER_OPEN",         \
+  "HPI_ADAPTER_CLOSE",        \
+  "HPI_ADAPTER_GET_INFO",     \
+  "HPI_ADAPTER_GET_ASSERT",   \
+  "HPI_ADAPTER_TEST_ASSERT",    \
+  "HPI_ADAPTER_SET_MODE",       \
+  "HPI_ADAPTER_GET_MODE",       \
+  "HPI_ADAPTER_ENABLE_CAPABILITY",\
+  "HPI_ADAPTER_SELFTEST",        \
+  "HPI_ADAPTER_FIND_OBJECT",     \
+  "HPI_ADAPTER_QUERY_FLASH",     \
+  "HPI_ADAPTER_START_FLASH",     \
+  "HPI_ADAPTER_PROGRAM_FLASH",   \
+  "HPI_ADAPTER_SET_PROPERTY",    \
+  "HPI_ADAPTER_GET_PROPERTY",    \
+  "HPI_ADAPTER_ENUM_PROPERTY",    \
+  "HPI_ADAPTER_MODULE_INFO",    \
+  "HPI_ADAPTER_DEBUG_READ"    \
+}
+
+function_count_check(HPI_ADAPTER, 18);
+
+#define HPI_OSTREAM_STRINGS     \
+{                               \
+  "HPI_OSTREAM_OPEN",         \
+  "HPI_OSTREAM_CLOSE",        \
+  "HPI_OSTREAM_WRITE",        \
+  "HPI_OSTREAM_START",        \
+  "HPI_OSTREAM_STOP",         \
+  "HPI_OSTREAM_RESET",                \
+  "HPI_OSTREAM_GET_INFO",     \
+  "HPI_OSTREAM_QUERY_FORMAT", \
+  "HPI_OSTREAM_DATA",         \
+  "HPI_OSTREAM_SET_VELOCITY", \
+  "HPI_OSTREAM_SET_PUNCHINOUT", \
+  "HPI_OSTREAM_SINEGEN",        \
+  "HPI_OSTREAM_ANC_RESET",      \
+  "HPI_OSTREAM_ANC_GET_INFO",   \
+  "HPI_OSTREAM_ANC_READ",       \
+  "HPI_OSTREAM_SET_TIMESCALE",\
+  "HPI_OSTREAM_SET_FORMAT", \
+  "HPI_OSTREAM_HOSTBUFFER_ALLOC", \
+  "HPI_OSTREAM_HOSTBUFFER_FREE", \
+  "HPI_OSTREAM_GROUP_ADD",\
+  "HPI_OSTREAM_GROUP_GETMAP", \
+  "HPI_OSTREAM_GROUP_RESET", \
+  "HPI_OSTREAM_HOSTBUFFER_GET_INFO", \
+  "HPI_OSTREAM_WAIT_START", \
+}
+function_count_check(HPI_OSTREAM, 24);
+
+#define HPI_ISTREAM_STRINGS     \
+{                               \
+  "HPI_ISTREAM_OPEN",         \
+  "HPI_ISTREAM_CLOSE",        \
+  "HPI_ISTREAM_SET_FORMAT",   \
+  "HPI_ISTREAM_READ",         \
+  "HPI_ISTREAM_START",        \
+  "HPI_ISTREAM_STOP",         \
+  "HPI_ISTREAM_RESET",        \
+  "HPI_ISTREAM_GET_INFO",     \
+  "HPI_ISTREAM_QUERY_FORMAT", \
+  "HPI_ISTREAM_ANC_RESET",      \
+  "HPI_ISTREAM_ANC_GET_INFO",   \
+  "HPI_ISTREAM_ANC_WRITE",   \
+  "HPI_ISTREAM_HOSTBUFFER_ALLOC",\
+  "HPI_ISTREAM_HOSTBUFFER_FREE", \
+  "HPI_ISTREAM_GROUP_ADD", \
+  "HPI_ISTREAM_GROUP_GETMAP", \
+  "HPI_ISTREAM_GROUP_RESET", \
+  "HPI_ISTREAM_HOSTBUFFER_GET_INFO", \
+  "HPI_ISTREAM_WAIT_START", \
+}
+function_count_check(HPI_ISTREAM, 19);
+
+#define HPI_MIXER_STRINGS       \
+{                               \
+  "HPI_MIXER_OPEN",           \
+  "HPI_MIXER_CLOSE",          \
+  "HPI_MIXER_GET_INFO",       \
+  "HPI_MIXER_GET_NODE_INFO",  \
+  "HPI_MIXER_GET_CONTROL",    \
+  "HPI_MIXER_SET_CONNECTION", \
+  "HPI_MIXER_GET_CONNECTIONS",        \
+  "HPI_MIXER_GET_CONTROL_BY_INDEX",   \
+  "HPI_MIXER_GET_CONTROL_ARRAY_BY_INDEX",     \
+  "HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES",    \
+  "HPI_MIXER_STORE",  \
+}
+function_count_check(HPI_MIXER, 11);
+
+#define HPI_CONTROL_STRINGS     \
+{                               \
+  "HPI_CONTROL_GET_INFO",     \
+  "HPI_CONTROL_GET_STATE",    \
+  "HPI_CONTROL_SET_STATE"     \
+}
+function_count_check(HPI_CONTROL, 3);
+
+#define HPI_NVMEMORY_STRINGS    \
+{                               \
+  "HPI_NVMEMORY_OPEN",        \
+  "HPI_NVMEMORY_READ_BYTE",   \
+  "HPI_NVMEMORY_WRITE_BYTE"   \
+}
+function_count_check(HPI_NVMEMORY, 3);
+
+#define HPI_DIGITALIO_STRINGS   \
+{                               \
+  "HPI_GPIO_OPEN",            \
+  "HPI_GPIO_READ_BIT",        \
+  "HPI_GPIO_WRITE_BIT",       \
+  "HPI_GPIO_READ_ALL",                \
+  "HPI_GPIO_WRITE_STATUS"\
+}
+function_count_check(HPI_GPIO, 5);
+
+#define HPI_WATCHDOG_STRINGS    \
+{                               \
+  "HPI_WATCHDOG_OPEN",        \
+  "HPI_WATCHDOG_SET_TIME",    \
+  "HPI_WATCHDOG_PING"         \
+}
+
+#define HPI_CLOCK_STRINGS       \
+{                               \
+  "HPI_CLOCK_OPEN",           \
+  "HPI_CLOCK_SET_TIME",       \
+  "HPI_CLOCK_GET_TIME"        \
+}
+
+#define HPI_PROFILE_STRINGS     \
+{                               \
+  "HPI_PROFILE_OPEN_ALL",     \
+  "HPI_PROFILE_START_ALL",    \
+  "HPI_PROFILE_STOP_ALL",     \
+  "HPI_PROFILE_GET",          \
+  "HPI_PROFILE_GET_IDLECOUNT",  \
+  "HPI_PROFILE_GET_NAME",       \
+  "HPI_PROFILE_GET_UTILIZATION" \
+}
+function_count_check(HPI_PROFILE, 7);
+
+#define HPI_ASYNCEVENT_STRINGS  \
+{                               \
+  "HPI_ASYNCEVENT_OPEN",\
+  "HPI_ASYNCEVENT_CLOSE  ",\
+  "HPI_ASYNCEVENT_WAIT",\
+  "HPI_ASYNCEVENT_GETCOUNT",\
+  "HPI_ASYNCEVENT_GET",\
+  "HPI_ASYNCEVENT_SENDEVENTS"\
+}
+function_count_check(HPI_ASYNCEVENT, 6);
+
+#define HPI_CONTROL_TYPE_STRINGS \
+{ \
+	"null control", \
+	"HPI_CONTROL_CONNECTION", \
+	"HPI_CONTROL_VOLUME", \
+	"HPI_CONTROL_METER", \
+	"HPI_CONTROL_MUTE", \
+	"HPI_CONTROL_MULTIPLEXER", \
+	"HPI_CONTROL_AESEBU_TRANSMITTER", \
+	"HPI_CONTROL_AESEBU_RECEIVER", \
+	"HPI_CONTROL_LEVEL", \
+	"HPI_CONTROL_TUNER", \
+	"HPI_CONTROL_ONOFFSWITCH", \
+	"HPI_CONTROL_VOX", \
+	"HPI_CONTROL_AES18_TRANSMITTER", \
+	"HPI_CONTROL_AES18_RECEIVER", \
+	"HPI_CONTROL_AES18_BLOCKGENERATOR", \
+	"HPI_CONTROL_CHANNEL_MODE", \
+	"HPI_CONTROL_BITSTREAM", \
+	"HPI_CONTROL_SAMPLECLOCK", \
+	"HPI_CONTROL_MICROPHONE", \
+	"HPI_CONTROL_PARAMETRIC_EQ", \
+	"HPI_CONTROL_COMPANDER", \
+	"HPI_CONTROL_COBRANET", \
+	"HPI_CONTROL_TONE_DETECT", \
+	"HPI_CONTROL_SILENCE_DETECT", \
+	"HPI_CONTROL_PAD", \
+	"HPI_CONTROL_SRC" ,\
+	"HPI_CONTROL_UNIVERSAL" \
+}
+
+compile_time_assert((HPI_CONTROL_LAST_INDEX + 1 == 27),
+	controltype_strings_match_defs);
+
+#define HPI_SOURCENODE_STRINGS \
+{ \
+	"no source", \
+	"HPI_SOURCENODE_OSTREAM", \
+	"HPI_SOURCENODE_LINEIN", \
+	"HPI_SOURCENODE_AESEBU_IN", \
+	"HPI_SOURCENODE_TUNER", \
+	"HPI_SOURCENODE_RF", \
+	"HPI_SOURCENODE_CLOCK_SOURCE", \
+	"HPI_SOURCENODE_RAW_BITSTREAM", \
+	"HPI_SOURCENODE_MICROPHONE", \
+	"HPI_SOURCENODE_COBRANET", \
+	"HPI_SOURCENODE_ANALOG", \
+	"HPI_SOURCENODE_ADAPTER" \
+}
+
+compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) ==
+	(12), sourcenode_strings_match_defs);
+
+#define HPI_DESTNODE_STRINGS \
+{ \
+	"no destination", \
+	"HPI_DESTNODE_ISTREAM", \
+	"HPI_DESTNODE_LINEOUT", \
+	"HPI_DESTNODE_AESEBU_OUT", \
+	"HPI_DESTNODE_RF", \
+	"HPI_DESTNODE_SPEAKER", \
+	"HPI_DESTNODE_COBRANET", \
+	"HPI_DESTNODE_ANALOG" \
+}
+compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_BASE + 1) == (8),
+	destnode_strings_match_defs);
+
+#define HPI_CONTROL_CHANNEL_MODE_STRINGS \
+{ \
+	"XXX HPI_CHANNEL_MODE_ERROR XXX", \
+	"HPI_CHANNEL_MODE_NORMAL", \
+	"HPI_CHANNEL_MODE_SWAP", \
+	"HPI_CHANNEL_MODE_LEFT_ONLY", \
+	"HPI_CHANNEL_MODE_RIGHT_ONLY" \
+}
+
+#endif				/* _HPIDEBUG_H  */

+ 172 - 0
sound/pci/asihpi/hpidspcd.c

@@ -0,0 +1,172 @@
+/***********************************************************************/
+/*!
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+\file
+Functions for reading DSP code to load into DSP
+
+(Linux only:) If DSPCODE_FIRMWARE_LOADER is defined, code is read using
+hotplug firmware loader from individual dsp code files
+
+If neither of the above is defined, code is read from linked arrays.
+DSPCODE_ARRAY is defined.
+
+HPI_INCLUDE_**** must be defined
+and the appropriate hzz?????.c or hex?????.c linked in
+
+ */
+/***********************************************************************/
+#define SOURCEFILE_NAME "hpidspcd.c"
+#include "hpidspcd.h"
+#include "hpidebug.h"
+
+/**
+ Header structure for binary dsp code file (see asidsp.doc)
+ This structure must match that used in s2bin.c for generation of asidsp.bin
+ */
+
+#ifndef DISABLE_PRAGMA_PACK1
+#pragma pack(push, 1)
+#endif
+
+struct code_header {
+	u32 size;
+	char type[4];
+	u32 adapter;
+	u32 version;
+	u32 crc;
+};
+
+#ifndef DISABLE_PRAGMA_PACK1
+#pragma pack(pop)
+#endif
+
+#define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \
+	    HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
+
+/***********************************************************************/
+#include "linux/pci.h"
+/*-------------------------------------------------------------------*/
+short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code,
+	u32 *pos_error_code)
+{
+	const struct firmware *ps_firmware = ps_dsp_code->ps_firmware;
+	struct code_header header;
+	char fw_name[20];
+	int err;
+
+	sprintf(fw_name, "asihpi/dsp%04x.bin", adapter);
+	HPI_DEBUG_LOG(INFO, "requesting firmware for %s\n", fw_name);
+
+	err = request_firmware(&ps_firmware, fw_name,
+		&ps_dsp_code->ps_dev->dev);
+	if (err != 0) {
+		HPI_DEBUG_LOG(ERROR, "%d, request_firmware failed for  %s\n",
+			err, fw_name);
+		goto error1;
+	}
+	if (ps_firmware->size < sizeof(header)) {
+		HPI_DEBUG_LOG(ERROR, "header size too small %s\n", fw_name);
+		goto error2;
+	}
+	memcpy(&header, ps_firmware->data, sizeof(header));
+	if (header.adapter != adapter) {
+		HPI_DEBUG_LOG(ERROR, "adapter type incorrect %4x != %4x\n",
+			header.adapter, adapter);
+		goto error2;
+	}
+	if (header.size != ps_firmware->size) {
+		HPI_DEBUG_LOG(ERROR, "code size wrong  %d != %ld\n",
+			header.size, (unsigned long)ps_firmware->size);
+		goto error2;
+	}
+
+	if (header.version / 10000 != HPI_VER_DECIMAL / 10000) {
+		HPI_DEBUG_LOG(ERROR,
+			"firmware major version mismatch "
+			"DSP image %d != driver %d\n", header.version,
+			HPI_VER_DECIMAL);
+		goto error2;
+	}
+
+	if (header.version != HPI_VER_DECIMAL) {
+		HPI_DEBUG_LOG(WARNING,
+			"version mismatch  DSP image %d != driver %d\n",
+			header.version, HPI_VER_DECIMAL);
+		/* goto error2;  still allow driver to load */
+	}
+
+	HPI_DEBUG_LOG(INFO, "dsp code %s opened\n", fw_name);
+	ps_dsp_code->ps_firmware = ps_firmware;
+	ps_dsp_code->block_length = header.size / sizeof(u32);
+	ps_dsp_code->word_count = sizeof(header) / sizeof(u32);
+	ps_dsp_code->version = header.version;
+	ps_dsp_code->crc = header.crc;
+	return 0;
+
+error2:
+	release_firmware(ps_firmware);
+error1:
+	ps_dsp_code->ps_firmware = NULL;
+	ps_dsp_code->block_length = 0;
+	return HPI_ERROR_DSP_FILE_NOT_FOUND;
+}
+
+/*-------------------------------------------------------------------*/
+void hpi_dsp_code_close(struct dsp_code *ps_dsp_code)
+{
+	if (ps_dsp_code->ps_firmware != NULL) {
+		HPI_DEBUG_LOG(DEBUG, "dsp code closed\n");
+		release_firmware(ps_dsp_code->ps_firmware);
+		ps_dsp_code->ps_firmware = NULL;
+	}
+}
+
+/*-------------------------------------------------------------------*/
+void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code)
+{
+	/* Go back to start of  data, after header */
+	ps_dsp_code->word_count = sizeof(struct code_header) / sizeof(u32);
+}
+
+/*-------------------------------------------------------------------*/
+short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code, u32 *pword)
+{
+	if (ps_dsp_code->word_count + 1 > ps_dsp_code->block_length)
+		return (HPI_ERROR_DSP_FILE_FORMAT);
+
+	*pword = ((u32 *)(ps_dsp_code->ps_firmware->data))[ps_dsp_code->
+		word_count];
+	ps_dsp_code->word_count++;
+	return 0;
+}
+
+/*-------------------------------------------------------------------*/
+short hpi_dsp_code_read_block(size_t words_requested,
+	struct dsp_code *ps_dsp_code, u32 **ppblock)
+{
+	if (ps_dsp_code->word_count + words_requested >
+		ps_dsp_code->block_length)
+		return HPI_ERROR_DSP_FILE_FORMAT;
+
+	*ppblock =
+		((u32 *)(ps_dsp_code->ps_firmware->data)) +
+		ps_dsp_code->word_count;
+	ps_dsp_code->word_count += words_requested;
+	return 0;
+}

+ 104 - 0
sound/pci/asihpi/hpidspcd.h

@@ -0,0 +1,104 @@
+/***********************************************************************/
+/**
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+\file
+Functions for reading DSP code to load into DSP
+
+ hpi_dspcode_defines HPI DSP code loading method
+Define exactly one of these to select how the DSP code is supplied to
+the adapter.
+
+End users writing applications that use the HPI interface do not have to
+use any of the below defines; they are only necessary for building drivers
+
+HPI_DSPCODE_FILE:
+DSP code is supplied as a file that is opened and read from by the driver.
+
+HPI_DSPCODE_FIRMWARE:
+DSP code is read using the hotplug firmware loader module.
+     Only valid when compiling the HPI kernel driver under Linux.
+*/
+/***********************************************************************/
+#ifndef _HPIDSPCD_H_
+#define _HPIDSPCD_H_
+
+#include "hpi_internal.h"
+
+#ifndef DISABLE_PRAGMA_PACK1
+#pragma pack(push, 1)
+#endif
+
+/** Descriptor for dspcode from firmware loader */
+struct dsp_code {
+	/**  Firmware descriptor */
+	const struct firmware *ps_firmware;
+	struct pci_dev *ps_dev;
+	/** Expected number of words in the whole dsp code,INCL header */
+	long int block_length;
+	/** Number of words read so far */
+	long int word_count;
+	/** Version read from dsp code file */
+	u32 version;
+	/** CRC read from dsp code file */
+	u32 crc;
+};
+
+#ifndef DISABLE_PRAGMA_PACK1
+#pragma pack(pop)
+#endif
+
+/** Prepare *psDspCode to refer to the requuested adapter.
+ Searches the file, or selects the appropriate linked array
+
+\return 0 for success, or error code if requested code is not available
+*/
+short hpi_dsp_code_open(
+	/** Code identifier, usually adapter family */
+	u32 adapter,
+	/** Pointer to DSP code control structure */
+	struct dsp_code *ps_dsp_code,
+	/** Pointer to dword to receive OS specific error code */
+	u32 *pos_error_code);
+
+/** Close the DSP code file */
+void hpi_dsp_code_close(struct dsp_code *ps_dsp_code);
+
+/** Rewind to the beginning of the DSP code file (for verify) */
+void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code);
+
+/** Read one word from the dsp code file
+	\return 0 for success, or error code if eof, or block length exceeded
+*/
+short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code,
+				      /**< DSP code descriptor */
+	u32 *pword /**< where to store the read word */
+	);
+
+/** Get a block of dsp code into an internal buffer, and provide a pointer to
+that buffer. (If dsp code is already an array in memory, it is referenced,
+not copied.)
+
+\return Error if requested number of words are not available
+*/
+short hpi_dsp_code_read_block(size_t words_requested,
+	struct dsp_code *ps_dsp_code,
+	/* Pointer to store (Pointer to code buffer) */
+	u32 **ppblock);
+
+#endif

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

@@ -0,0 +1,3864 @@
+
+#include "hpi_internal.h"
+#include "hpimsginit.h"
+
+#include "hpidebug.h"
+
+struct hpi_handle {
+	unsigned int obj_index:12;
+	unsigned int obj_type:4;
+	unsigned int adapter_index:14;
+	unsigned int spare:1;
+	unsigned int read_only:1;
+};
+
+union handle_word {
+	struct hpi_handle h;
+	u32 w;
+};
+
+u32 hpi_indexes_to_handle(const char c_object, const u16 adapter_index,
+	const u16 object_index)
+{
+	union handle_word handle;
+
+	handle.h.adapter_index = adapter_index;
+	handle.h.spare = 0;
+	handle.h.read_only = 0;
+	handle.h.obj_type = c_object;
+	handle.h.obj_index = object_index;
+	return handle.w;
+}
+
+void hpi_handle_to_indexes(const u32 handle, u16 *pw_adapter_index,
+	u16 *pw_object_index)
+{
+	union handle_word uhandle;
+	uhandle.w = handle;
+
+	if (pw_adapter_index)
+		*pw_adapter_index = (u16)uhandle.h.adapter_index;
+	if (pw_object_index)
+		*pw_object_index = (u16)uhandle.h.obj_index;
+}
+
+char hpi_handle_object(const u32 handle)
+{
+	union handle_word uhandle;
+	uhandle.w = handle;
+	return (char)uhandle.h.obj_type;
+}
+
+#define u32TOINDEX(h, i1) \
+do {\
+	if (h == 0) \
+		return HPI_ERROR_INVALID_OBJ; \
+	else \
+		hpi_handle_to_indexes(h, i1, NULL); \
+} while (0)
+
+#define u32TOINDEXES(h, i1, i2) \
+do {\
+	if (h == 0) \
+		return HPI_ERROR_INVALID_OBJ; \
+	else \
+		hpi_handle_to_indexes(h, i1, i2);\
+} while (0)
+
+void hpi_format_to_msg(struct hpi_msg_format *pMF,
+	const struct hpi_format *pF)
+{
+	pMF->sample_rate = pF->sample_rate;
+	pMF->bit_rate = pF->bit_rate;
+	pMF->attributes = pF->attributes;
+	pMF->channels = pF->channels;
+	pMF->format = pF->format;
+}
+
+static void hpi_msg_to_format(struct hpi_format *pF,
+	struct hpi_msg_format *pMF)
+{
+	pF->sample_rate = pMF->sample_rate;
+	pF->bit_rate = pMF->bit_rate;
+	pF->attributes = pMF->attributes;
+	pF->channels = pMF->channels;
+	pF->format = pMF->format;
+	pF->mode_legacy = 0;
+	pF->unused = 0;
+}
+
+void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR)
+{
+	pSR->u.legacy_stream_info.auxiliary_data_available =
+		pSR->u.stream_info.auxiliary_data_available;
+	pSR->u.legacy_stream_info.state = pSR->u.stream_info.state;
+}
+
+static struct hpi_hsubsys gh_subsys;
+
+struct hpi_hsubsys *hpi_subsys_create(void
+	)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	memset(&gh_subsys, 0, sizeof(struct hpi_hsubsys));
+
+	{
+		hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+			HPI_SUBSYS_OPEN);
+		hpi_send_recv(&hm, &hr);
+
+		if (hr.error == 0)
+			return &gh_subsys;
+
+	}
+	return NULL;
+}
+
+void hpi_subsys_free(const struct hpi_hsubsys *ph_subsys)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_CLOSE);
+	hpi_send_recv(&hm, &hr);
+
+}
+
+u16 hpi_subsys_get_version(const struct hpi_hsubsys *ph_subsys, u32 *pversion)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_GET_VERSION);
+	hpi_send_recv(&hm, &hr);
+	*pversion = hr.u.s.version;
+	return hr.error;
+}
+
+u16 hpi_subsys_get_version_ex(const struct hpi_hsubsys *ph_subsys,
+	u32 *pversion_ex)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_GET_VERSION);
+	hpi_send_recv(&hm, &hr);
+	*pversion_ex = hr.u.s.data;
+	return hr.error;
+}
+
+u16 hpi_subsys_get_info(const struct hpi_hsubsys *ph_subsys, u32 *pversion,
+	u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_GET_INFO);
+
+	hpi_send_recv(&hm, &hr);
+
+	*pversion = hr.u.s.version;
+	if (list_length > HPI_MAX_ADAPTERS)
+		memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list,
+			HPI_MAX_ADAPTERS);
+	else
+		memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list, list_length);
+	*pw_num_adapters = hr.u.s.num_adapters;
+	return hr.error;
+}
+
+u16 hpi_subsys_find_adapters(const struct hpi_hsubsys *ph_subsys,
+	u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_FIND_ADAPTERS);
+
+	hpi_send_recv(&hm, &hr);
+
+	if (list_length > HPI_MAX_ADAPTERS) {
+		memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list,
+			HPI_MAX_ADAPTERS * sizeof(u16));
+		memset(&aw_adapter_list[HPI_MAX_ADAPTERS], 0,
+			(list_length - HPI_MAX_ADAPTERS) * sizeof(u16));
+	} else
+		memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list,
+			list_length * sizeof(u16));
+	*pw_num_adapters = hr.u.s.num_adapters;
+
+	return hr.error;
+}
+
+u16 hpi_subsys_create_adapter(const struct hpi_hsubsys *ph_subsys,
+	const struct hpi_resource *p_resource, u16 *pw_adapter_index)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_CREATE_ADAPTER);
+	hm.u.s.resource = *p_resource;
+
+	hpi_send_recv(&hm, &hr);
+
+	*pw_adapter_index = hr.u.s.adapter_index;
+	return hr.error;
+}
+
+u16 hpi_subsys_delete_adapter(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_DELETE_ADAPTER);
+	hm.adapter_index = adapter_index;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_subsys_get_num_adapters(const struct hpi_hsubsys *ph_subsys,
+	int *pn_num_adapters)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_GET_NUM_ADAPTERS);
+	hpi_send_recv(&hm, &hr);
+	*pn_num_adapters = (int)hr.u.s.num_adapters;
+	return hr.error;
+}
+
+u16 hpi_subsys_get_adapter(const struct hpi_hsubsys *ph_subsys, int iterator,
+	u32 *padapter_index, u16 *pw_adapter_type)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_GET_ADAPTER);
+	hm.adapter_index = (u16)iterator;
+	hpi_send_recv(&hm, &hr);
+	*padapter_index = (int)hr.u.s.adapter_index;
+	*pw_adapter_type = hr.u.s.aw_adapter_list[0];
+	return hr.error;
+}
+
+u16 hpi_subsys_set_host_network_interface(const struct hpi_hsubsys *ph_subsys,
+	const char *sz_interface)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_SET_NETWORK_INTERFACE);
+	if (sz_interface == NULL)
+		return HPI_ERROR_INVALID_RESOURCE;
+	hm.u.s.resource.r.net_if = sz_interface;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_adapter_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_OPEN);
+	hm.adapter_index = adapter_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+
+}
+
+u16 hpi_adapter_close(const struct hpi_hsubsys *ph_subsys, u16 adapter_index)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_CLOSE);
+	hm.adapter_index = adapter_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_adapter_set_mode(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u32 adapter_mode)
+{
+	return hpi_adapter_set_mode_ex(ph_subsys, adapter_index, adapter_mode,
+		HPI_ADAPTER_MODE_SET);
+}
+
+u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u32 adapter_mode, u16 query_or_set)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_SET_MODE);
+	hm.adapter_index = adapter_index;
+	hm.u.a.adapter_mode = adapter_mode;
+	hm.u.a.assert_id = query_or_set;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_adapter_get_mode(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u32 *padapter_mode)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_GET_MODE);
+	hm.adapter_index = adapter_index;
+	hpi_send_recv(&hm, &hr);
+	if (padapter_mode)
+		*padapter_mode = hr.u.a.serial_number;
+	return hr.error;
+}
+
+u16 hpi_adapter_get_info(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 *pw_num_outstreams, u16 *pw_num_instreams,
+	u16 *pw_version, u32 *pserial_number, u16 *pw_adapter_type)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_GET_INFO);
+	hm.adapter_index = adapter_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	*pw_adapter_type = hr.u.a.adapter_type;
+	*pw_num_outstreams = hr.u.a.num_outstreams;
+	*pw_num_instreams = hr.u.a.num_instreams;
+	*pw_version = hr.u.a.version;
+	*pserial_number = hr.u.a.serial_number;
+	return hr.error;
+}
+
+u16 hpi_adapter_get_module_by_index(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 module_index, u16 *pw_num_outputs,
+	u16 *pw_num_inputs, u16 *pw_version, u32 *pserial_number,
+	u16 *pw_module_type, u32 *ph_module)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_MODULE_INFO);
+	hm.adapter_index = adapter_index;
+	hm.u.ax.module_info.index = module_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	*pw_module_type = hr.u.a.adapter_type;
+	*pw_num_outputs = hr.u.a.num_outstreams;
+	*pw_num_inputs = hr.u.a.num_instreams;
+	*pw_version = hr.u.a.version;
+	*pserial_number = hr.u.a.serial_number;
+	*ph_module = 0;
+
+	return hr.error;
+}
+
+u16 hpi_adapter_get_assert(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 *assert_present, char *psz_assert,
+	u16 *pw_line_number)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_GET_ASSERT);
+	hm.adapter_index = adapter_index;
+	hpi_send_recv(&hm, &hr);
+
+	*assert_present = 0;
+
+	if (!hr.error) {
+
+		*pw_line_number = (u16)hr.u.a.serial_number;
+		if (*pw_line_number) {
+
+			int i;
+			char *src = (char *)hr.u.a.sz_adapter_assert;
+			char *dst = psz_assert;
+
+			*assert_present = 1;
+
+			for (i = 0; i < HPI_STRING_LEN; i++) {
+				char c;
+				c = *src++;
+				*dst++ = c;
+				if (c == 0)
+					break;
+			}
+
+		}
+	}
+	return hr.error;
+}
+
+u16 hpi_adapter_get_assert_ex(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 *assert_present, char *psz_assert,
+	u32 *pline_number, u16 *pw_assert_on_dsp)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_GET_ASSERT);
+	hm.adapter_index = adapter_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	*assert_present = 0;
+
+	if (!hr.error) {
+
+		*pline_number = hr.u.a.serial_number;
+
+		*assert_present = hr.u.a.adapter_type;
+
+		*pw_assert_on_dsp = hr.u.a.adapter_index;
+
+		if (!*assert_present && *pline_number)
+
+			*assert_present = 1;
+
+		if (*assert_present) {
+
+			int i;
+			char *src = (char *)hr.u.a.sz_adapter_assert;
+			char *dst = psz_assert;
+
+			for (i = 0; i < HPI_STRING_LEN; i++) {
+				char c;
+				c = *src++;
+				*dst++ = c;
+				if (c == 0)
+					break;
+			}
+
+		} else {
+			*psz_assert = 0;
+		}
+	}
+	return hr.error;
+}
+
+u16 hpi_adapter_test_assert(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 assert_id)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_TEST_ASSERT);
+	hm.adapter_index = adapter_index;
+	hm.u.a.assert_id = assert_id;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_adapter_enable_capability(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 capability, u32 key)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_ENABLE_CAPABILITY);
+	hm.adapter_index = adapter_index;
+	hm.u.a.assert_id = capability;
+	hm.u.a.adapter_mode = key;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_adapter_self_test(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_SELFTEST);
+	hm.adapter_index = adapter_index;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_adapter_debug_read(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u32 dsp_address, char *p_buffer, int *count_bytes)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_DEBUG_READ);
+
+	hr.size = sizeof(hr);
+
+	hm.adapter_index = adapter_index;
+	hm.u.ax.debug_read.dsp_address = dsp_address;
+
+	if (*count_bytes > sizeof(hr.u.bytes))
+		*count_bytes = sizeof(hr.u.bytes);
+
+	hm.u.ax.debug_read.count_bytes = *count_bytes;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (!hr.error) {
+		*count_bytes = hr.size - 12;
+		memcpy(p_buffer, &hr.u.bytes, *count_bytes);
+	} else
+		*count_bytes = 0;
+	return hr.error;
+}
+
+u16 hpi_adapter_set_property(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 property, u16 parameter1, u16 parameter2)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_SET_PROPERTY);
+	hm.adapter_index = adapter_index;
+	hm.u.ax.property_set.property = property;
+	hm.u.ax.property_set.parameter1 = parameter1;
+	hm.u.ax.property_set.parameter2 = parameter2;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_adapter_get_property(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 property, u16 *pw_parameter1,
+	u16 *pw_parameter2)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_GET_PROPERTY);
+	hm.adapter_index = adapter_index;
+	hm.u.ax.property_set.property = property;
+
+	hpi_send_recv(&hm, &hr);
+	if (!hr.error) {
+		if (pw_parameter1)
+			*pw_parameter1 = hr.u.ax.property_get.parameter1;
+		if (pw_parameter2)
+			*pw_parameter2 = hr.u.ax.property_get.parameter2;
+	}
+
+	return hr.error;
+}
+
+u16 hpi_adapter_enumerate_property(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 index, u16 what_to_enumerate,
+	u16 property_index, u32 *psetting)
+{
+	return 0;
+}
+
+u16 hpi_format_create(struct hpi_format *p_format, u16 channels, u16 format,
+	u32 sample_rate, u32 bit_rate, u32 attributes)
+{
+	u16 error = 0;
+	struct hpi_msg_format fmt;
+
+	switch (channels) {
+	case 1:
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+	case 16:
+		break;
+	default:
+		error = HPI_ERROR_INVALID_CHANNELS;
+		return error;
+	}
+	fmt.channels = channels;
+
+	switch (format) {
+	case HPI_FORMAT_PCM16_SIGNED:
+	case HPI_FORMAT_PCM24_SIGNED:
+	case HPI_FORMAT_PCM32_SIGNED:
+	case HPI_FORMAT_PCM32_FLOAT:
+	case HPI_FORMAT_PCM16_BIGENDIAN:
+	case HPI_FORMAT_PCM8_UNSIGNED:
+	case HPI_FORMAT_MPEG_L1:
+	case HPI_FORMAT_MPEG_L2:
+	case HPI_FORMAT_MPEG_L3:
+	case HPI_FORMAT_DOLBY_AC2:
+	case HPI_FORMAT_AA_TAGIT1_HITS:
+	case HPI_FORMAT_AA_TAGIT1_INSERTS:
+	case HPI_FORMAT_RAW_BITSTREAM:
+	case HPI_FORMAT_AA_TAGIT1_HITS_EX1:
+	case HPI_FORMAT_OEM1:
+	case HPI_FORMAT_OEM2:
+		break;
+	default:
+		error = HPI_ERROR_INVALID_FORMAT;
+		return error;
+	}
+	fmt.format = format;
+
+	if (sample_rate < 8000L) {
+		error = HPI_ERROR_INCOMPATIBLE_SAMPLERATE;
+		sample_rate = 8000L;
+	}
+	if (sample_rate > 200000L) {
+		error = HPI_ERROR_INCOMPATIBLE_SAMPLERATE;
+		sample_rate = 200000L;
+	}
+	fmt.sample_rate = sample_rate;
+
+	switch (format) {
+	case HPI_FORMAT_MPEG_L1:
+	case HPI_FORMAT_MPEG_L2:
+	case HPI_FORMAT_MPEG_L3:
+		fmt.bit_rate = bit_rate;
+		break;
+	case HPI_FORMAT_PCM16_SIGNED:
+	case HPI_FORMAT_PCM16_BIGENDIAN:
+		fmt.bit_rate = channels * sample_rate * 2;
+		break;
+	case HPI_FORMAT_PCM32_SIGNED:
+	case HPI_FORMAT_PCM32_FLOAT:
+		fmt.bit_rate = channels * sample_rate * 4;
+		break;
+	case HPI_FORMAT_PCM8_UNSIGNED:
+		fmt.bit_rate = channels * sample_rate;
+		break;
+	default:
+		fmt.bit_rate = 0;
+	}
+
+	switch (format) {
+	case HPI_FORMAT_MPEG_L2:
+		if ((channels == 1)
+			&& (attributes != HPI_MPEG_MODE_DEFAULT)) {
+			attributes = HPI_MPEG_MODE_DEFAULT;
+			error = HPI_ERROR_INVALID_FORMAT;
+		} else if (attributes > HPI_MPEG_MODE_DUALCHANNEL) {
+			attributes = HPI_MPEG_MODE_DEFAULT;
+			error = HPI_ERROR_INVALID_FORMAT;
+		}
+		fmt.attributes = attributes;
+		break;
+	default:
+		fmt.attributes = attributes;
+	}
+
+	hpi_msg_to_format(p_format, &fmt);
+	return error;
+}
+
+u16 hpi_stream_estimate_buffer_size(struct hpi_format *p_format,
+	u32 host_polling_rate_in_milli_seconds, u32 *recommended_buffer_size)
+{
+
+	u32 bytes_per_second;
+	u32 size;
+	u16 channels;
+	struct hpi_format *pF = p_format;
+
+	channels = pF->channels;
+
+	switch (pF->format) {
+	case HPI_FORMAT_PCM16_BIGENDIAN:
+	case HPI_FORMAT_PCM16_SIGNED:
+		bytes_per_second = pF->sample_rate * 2L * channels;
+		break;
+	case HPI_FORMAT_PCM24_SIGNED:
+		bytes_per_second = pF->sample_rate * 3L * channels;
+		break;
+	case HPI_FORMAT_PCM32_SIGNED:
+	case HPI_FORMAT_PCM32_FLOAT:
+		bytes_per_second = pF->sample_rate * 4L * channels;
+		break;
+	case HPI_FORMAT_PCM8_UNSIGNED:
+		bytes_per_second = pF->sample_rate * 1L * channels;
+		break;
+	case HPI_FORMAT_MPEG_L1:
+	case HPI_FORMAT_MPEG_L2:
+	case HPI_FORMAT_MPEG_L3:
+		bytes_per_second = pF->bit_rate / 8L;
+		break;
+	case HPI_FORMAT_DOLBY_AC2:
+
+		bytes_per_second = 256000L / 8L;
+		break;
+	default:
+		return HPI_ERROR_INVALID_FORMAT;
+	}
+	size = (bytes_per_second * host_polling_rate_in_milli_seconds * 2) /
+		1000L;
+
+	*recommended_buffer_size =
+		roundup_pow_of_two(((size + 4095L) & ~4095L));
+	return 0;
+}
+
+u16 hpi_outstream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u16 outstream_index, u32 *ph_outstream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_OPEN);
+	hm.adapter_index = adapter_index;
+	hm.obj_index = outstream_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0)
+		*ph_outstream =
+			hpi_indexes_to_handle(HPI_OBJ_OSTREAM, adapter_index,
+			outstream_index);
+	else
+		*ph_outstream = 0;
+	return hr.error;
+}
+
+u16 hpi_outstream_close(const struct hpi_hsubsys *ph_subsys, u32 h_outstream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_HOSTBUFFER_FREE);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_GROUP_RESET);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_CLOSE);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_get_info_ex(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_to_play,
+	u32 *psamples_played, u32 *pauxiliary_data_to_play)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_GET_INFO);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	if (pw_state)
+		*pw_state = hr.u.d.u.stream_info.state;
+	if (pbuffer_size)
+		*pbuffer_size = hr.u.d.u.stream_info.buffer_size;
+	if (pdata_to_play)
+		*pdata_to_play = hr.u.d.u.stream_info.data_available;
+	if (psamples_played)
+		*psamples_played = hr.u.d.u.stream_info.samples_transferred;
+	if (pauxiliary_data_to_play)
+		*pauxiliary_data_to_play =
+			hr.u.d.u.stream_info.auxiliary_data_available;
+	return hr.error;
+}
+
+u16 hpi_outstream_write_buf(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, const u8 *pb_data, u32 bytes_to_write,
+	const struct hpi_format *p_format)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_WRITE);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hm.u.d.u.data.pb_data = (u8 *)pb_data;
+	hm.u.d.u.data.data_size = bytes_to_write;
+
+	hpi_format_to_msg(&hm.u.d.u.data.format, p_format);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_start(const struct hpi_hsubsys *ph_subsys, u32 h_outstream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_START);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_wait_start(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_WAIT_START);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_outstream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_STOP);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_sinegen(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_SINEGEN);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_outstream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_RESET);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_query_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, struct hpi_format *p_format)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_QUERY_FORMAT);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_format_to_msg(&hm.u.d.u.data.format, p_format);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_set_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, struct hpi_format *p_format)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_SET_FORMAT);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_format_to_msg(&hm.u.d.u.data.format, p_format);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_set_velocity(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, short velocity)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_SET_VELOCITY);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hm.u.d.u.velocity = velocity;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_set_punch_in_out(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 punch_in_sample, u32 punch_out_sample)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_SET_PUNCHINOUT);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+	hm.u.d.u.pio.punch_in_sample = punch_in_sample;
+	hm.u.d.u.pio.punch_out_sample = punch_out_sample;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_ancillary_reset(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u16 mode)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_ANC_RESET);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hm.u.d.u.data.format.channels = mode;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_outstream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 *pframes_available)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_ANC_GET_INFO);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+	if (hr.error == 0) {
+		if (pframes_available)
+			*pframes_available =
+				hr.u.d.u.stream_info.data_available /
+				sizeof(struct hpi_anc_frame);
+	}
+	return hr.error;
+}
+
+u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, struct hpi_anc_frame *p_anc_frame_buffer,
+	u32 anc_frame_buffer_size_in_bytes,
+	u32 number_of_ancillary_frames_to_read)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_ANC_READ);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hm.u.d.u.data.pb_data = (u8 *)p_anc_frame_buffer;
+	hm.u.d.u.data.data_size =
+		number_of_ancillary_frames_to_read *
+		sizeof(struct hpi_anc_frame);
+	if (hm.u.d.u.data.data_size <= anc_frame_buffer_size_in_bytes)
+		hpi_send_recv(&hm, &hr);
+	else
+		hr.error = HPI_ERROR_INVALID_DATA_TRANSFER;
+	return hr.error;
+}
+
+u16 hpi_outstream_set_time_scale(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 time_scale)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_SET_TIMESCALE);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+	hm.u.d.u.time_scale = time_scale;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_outstream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 size_in_bytes)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_HOSTBUFFER_ALLOC);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hm.u.d.u.data.data_size = size_in_bytes;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_outstream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u8 **pp_buffer,
+	struct hpi_hostbuffer_status **pp_status)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_HOSTBUFFER_GET_INFO);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0) {
+		if (pp_buffer)
+			*pp_buffer = hr.u.d.u.hostbuffer_info.p_buffer;
+		if (pp_status)
+			*pp_status = hr.u.d.u.hostbuffer_info.p_status;
+	}
+	return hr.error;
+}
+
+u16 hpi_outstream_host_buffer_free(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_HOSTBUFFER_FREE);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_outstream_group_add(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 h_stream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	u16 adapter;
+	char c_obj_type;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_GROUP_ADD);
+	hr.error = 0;
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	c_obj_type = hpi_handle_object(h_stream);
+	switch (c_obj_type) {
+	case HPI_OBJ_OSTREAM:
+		hm.u.d.u.stream.object_type = HPI_OBJ_OSTREAM;
+		u32TOINDEXES(h_stream, &adapter,
+			&hm.u.d.u.stream.stream_index);
+		break;
+	case HPI_OBJ_ISTREAM:
+		hm.u.d.u.stream.object_type = HPI_OBJ_ISTREAM;
+		u32TOINDEXES(h_stream, &adapter,
+			&hm.u.d.u.stream.stream_index);
+		break;
+	default:
+		return HPI_ERROR_INVALID_STREAM;
+	}
+	if (adapter != hm.adapter_index)
+		return HPI_ERROR_NO_INTERADAPTER_GROUPS;
+
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_outstream_group_get_map(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream, u32 *poutstream_map, u32 *pinstream_map)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_GROUP_GETMAP);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	if (poutstream_map)
+		*poutstream_map = hr.u.d.u.group_info.outstream_group_map;
+	if (pinstream_map)
+		*pinstream_map = hr.u.d.u.group_info.instream_group_map;
+
+	return hr.error;
+}
+
+u16 hpi_outstream_group_reset(const struct hpi_hsubsys *ph_subsys,
+	u32 h_outstream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+		HPI_OSTREAM_GROUP_RESET);
+	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_instream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u16 instream_index, u32 *ph_instream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_OPEN);
+	hm.adapter_index = adapter_index;
+	hm.obj_index = instream_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0)
+		*ph_instream =
+			hpi_indexes_to_handle(HPI_OBJ_ISTREAM, adapter_index,
+			instream_index);
+	else
+		*ph_instream = 0;
+
+	return hr.error;
+}
+
+u16 hpi_instream_close(const struct hpi_hsubsys *ph_subsys, u32 h_instream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_HOSTBUFFER_FREE);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_GROUP_RESET);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_CLOSE);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_instream_query_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, const struct hpi_format *p_format)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_QUERY_FORMAT);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hpi_format_to_msg(&hm.u.d.u.data.format, p_format);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_instream_set_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, const struct hpi_format *p_format)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_SET_FORMAT);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hpi_format_to_msg(&hm.u.d.u.data.format, p_format);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_instream_read_buf(const struct hpi_hsubsys *ph_subsys, u32 h_instream,
+	u8 *pb_data, u32 bytes_to_read)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_READ);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hm.u.d.u.data.data_size = bytes_to_read;
+	hm.u.d.u.data.pb_data = pb_data;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_instream_start(const struct hpi_hsubsys *ph_subsys, u32 h_instream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_START);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_instream_wait_start(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_WAIT_START);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_instream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_instream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_STOP);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_instream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_instream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_RESET);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_instream_get_info_ex(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_recorded,
+	u32 *psamples_recorded, u32 *pauxiliary_data_recorded)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_GET_INFO);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	if (pw_state)
+		*pw_state = hr.u.d.u.stream_info.state;
+	if (pbuffer_size)
+		*pbuffer_size = hr.u.d.u.stream_info.buffer_size;
+	if (pdata_recorded)
+		*pdata_recorded = hr.u.d.u.stream_info.data_available;
+	if (psamples_recorded)
+		*psamples_recorded = hr.u.d.u.stream_info.samples_transferred;
+	if (pauxiliary_data_recorded)
+		*pauxiliary_data_recorded =
+			hr.u.d.u.stream_info.auxiliary_data_available;
+	return hr.error;
+}
+
+u16 hpi_instream_ancillary_reset(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u16 bytes_per_frame, u16 mode, u16 alignment,
+	u16 idle_bit)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_ANC_RESET);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hm.u.d.u.data.format.attributes = bytes_per_frame;
+	hm.u.d.u.data.format.format = (mode << 8) | (alignment & 0xff);
+	hm.u.d.u.data.format.channels = idle_bit;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_instream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u32 *pframe_space)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_ANC_GET_INFO);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+	if (pframe_space)
+		*pframe_space =
+			(hr.u.d.u.stream_info.buffer_size -
+			hr.u.d.u.stream_info.data_available) /
+			sizeof(struct hpi_anc_frame);
+	return hr.error;
+}
+
+u16 hpi_instream_ancillary_write(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, const struct hpi_anc_frame *p_anc_frame_buffer,
+	u32 anc_frame_buffer_size_in_bytes,
+	u32 number_of_ancillary_frames_to_write)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_ANC_WRITE);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hm.u.d.u.data.pb_data = (u8 *)p_anc_frame_buffer;
+	hm.u.d.u.data.data_size =
+		number_of_ancillary_frames_to_write *
+		sizeof(struct hpi_anc_frame);
+	if (hm.u.d.u.data.data_size <= anc_frame_buffer_size_in_bytes)
+		hpi_send_recv(&hm, &hr);
+	else
+		hr.error = HPI_ERROR_INVALID_DATA_TRANSFER;
+	return hr.error;
+}
+
+u16 hpi_instream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u32 size_in_bytes)
+{
+
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_HOSTBUFFER_ALLOC);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hm.u.d.u.data.data_size = size_in_bytes;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_instream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u8 **pp_buffer,
+	struct hpi_hostbuffer_status **pp_status)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_HOSTBUFFER_GET_INFO);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0) {
+		if (pp_buffer)
+			*pp_buffer = hr.u.d.u.hostbuffer_info.p_buffer;
+		if (pp_status)
+			*pp_status = hr.u.d.u.hostbuffer_info.p_status;
+	}
+	return hr.error;
+}
+
+u16 hpi_instream_host_buffer_free(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream)
+{
+
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_HOSTBUFFER_FREE);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_instream_group_add(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u32 h_stream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	u16 adapter;
+	char c_obj_type;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_GROUP_ADD);
+	hr.error = 0;
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	c_obj_type = hpi_handle_object(h_stream);
+
+	switch (c_obj_type) {
+	case HPI_OBJ_OSTREAM:
+		hm.u.d.u.stream.object_type = HPI_OBJ_OSTREAM;
+		u32TOINDEXES(h_stream, &adapter,
+			&hm.u.d.u.stream.stream_index);
+		break;
+	case HPI_OBJ_ISTREAM:
+		hm.u.d.u.stream.object_type = HPI_OBJ_ISTREAM;
+		u32TOINDEXES(h_stream, &adapter,
+			&hm.u.d.u.stream.stream_index);
+		break;
+	default:
+		return HPI_ERROR_INVALID_STREAM;
+	}
+
+	if (adapter != hm.adapter_index)
+		return HPI_ERROR_NO_INTERADAPTER_GROUPS;
+
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_instream_group_get_map(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream, u32 *poutstream_map, u32 *pinstream_map)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_HOSTBUFFER_FREE);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	if (poutstream_map)
+		*poutstream_map = hr.u.d.u.group_info.outstream_group_map;
+	if (pinstream_map)
+		*pinstream_map = hr.u.d.u.group_info.instream_group_map;
+
+	return hr.error;
+}
+
+u16 hpi_instream_group_reset(const struct hpi_hsubsys *ph_subsys,
+	u32 h_instream)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+		HPI_ISTREAM_GROUP_RESET);
+	u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_mixer_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u32 *ph_mixer)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_OPEN);
+	hm.adapter_index = adapter_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0)
+		*ph_mixer =
+			hpi_indexes_to_handle(HPI_OBJ_MIXER, adapter_index,
+			0);
+	else
+		*ph_mixer = 0;
+	return hr.error;
+}
+
+u16 hpi_mixer_close(const struct hpi_hsubsys *ph_subsys, u32 h_mixer)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_CLOSE);
+	u32TOINDEX(h_mixer, &hm.adapter_index);
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+u16 hpi_mixer_get_control(const struct hpi_hsubsys *ph_subsys, u32 h_mixer,
+	u16 src_node_type, u16 src_node_type_index, u16 dst_node_type,
+	u16 dst_node_type_index, u16 control_type, u32 *ph_control)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER,
+		HPI_MIXER_GET_CONTROL);
+	u32TOINDEX(h_mixer, &hm.adapter_index);
+	hm.u.m.node_type1 = src_node_type;
+	hm.u.m.node_index1 = src_node_type_index;
+	hm.u.m.node_type2 = dst_node_type;
+	hm.u.m.node_index2 = dst_node_type_index;
+	hm.u.m.control_type = control_type;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0)
+		*ph_control =
+			hpi_indexes_to_handle(HPI_OBJ_CONTROL,
+			hm.adapter_index, hr.u.m.control_index);
+	else
+		*ph_control = 0;
+	return hr.error;
+}
+
+u16 hpi_mixer_get_control_by_index(const struct hpi_hsubsys *ph_subsys,
+	u32 h_mixer, u16 control_index, u16 *pw_src_node_type,
+	u16 *pw_src_node_index, u16 *pw_dst_node_type, u16 *pw_dst_node_index,
+	u16 *pw_control_type, u32 *ph_control)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER,
+		HPI_MIXER_GET_CONTROL_BY_INDEX);
+	u32TOINDEX(h_mixer, &hm.adapter_index);
+	hm.u.m.control_index = control_index;
+	hpi_send_recv(&hm, &hr);
+
+	if (pw_src_node_type) {
+		*pw_src_node_type =
+			hr.u.m.src_node_type + HPI_SOURCENODE_NONE;
+		*pw_src_node_index = hr.u.m.src_node_index;
+		*pw_dst_node_type = hr.u.m.dst_node_type + HPI_DESTNODE_NONE;
+		*pw_dst_node_index = hr.u.m.dst_node_index;
+	}
+	if (pw_control_type)
+		*pw_control_type = hr.u.m.control_index;
+
+	if (ph_control) {
+		if (hr.error == 0)
+			*ph_control =
+				hpi_indexes_to_handle(HPI_OBJ_CONTROL,
+				hm.adapter_index, control_index);
+		else
+			*ph_control = 0;
+	}
+	return hr.error;
+}
+
+u16 hpi_mixer_store(const struct hpi_hsubsys *ph_subsys, u32 h_mixer,
+	enum HPI_MIXER_STORE_COMMAND command, u16 index)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_STORE);
+	u32TOINDEX(h_mixer, &hm.adapter_index);
+	hm.u.mx.store.command = command;
+	hm.u.mx.store.index = index;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+static
+u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_control, const u16 attrib, const u32 param1,
+	const u32 param2)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_SET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = attrib;
+	hm.u.c.param1 = param1;
+	hm.u.c.param2 = param2;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
+static
+u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_control, const u16 attrib, u32 param1, u32 param2,
+	u32 *pparam1, u32 *pparam2)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = attrib;
+	hm.u.c.param1 = param1;
+	hm.u.c.param2 = param2;
+	hpi_send_recv(&hm, &hr);
+	if (pparam1)
+		*pparam1 = hr.u.c.param1;
+	if (pparam2)
+		*pparam2 = hr.u.c.param2;
+
+	return hr.error;
+}
+
+#define hpi_control_param1_get(s, h, a, p1) \
+		hpi_control_param_get(s, h, a, 0, 0, p1, NULL)
+#define hpi_control_param2_get(s, h, a, p1, p2) \
+		hpi_control_param_get(s, h, a, 0, 0, p1, p2)
+#define hpi_control_ex_param1_get(s, h, a, p1) \
+		hpi_control_ex_param_get(s, h, a, 0, 0, p1, NULL)
+#define hpi_control_ex_param2_get(s, h, a, p1, p2) \
+		hpi_control_ex_param_get(s, h, a, 0, 0, p1, p2)
+
+static
+u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_control, const u16 attrib, const u32 index,
+	const u32 param, u32 *psetting)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_INFO);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+
+	hm.u.c.attribute = attrib;
+	hm.u.c.param1 = index;
+	hm.u.c.param2 = param;
+
+	hpi_send_recv(&hm, &hr);
+	*psetting = hr.u.c.param1;
+
+	return hr.error;
+}
+
+static u16 hpi_control_get_string(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_control, const u16 attribute, char *psz_string,
+	const u32 string_length)
+{
+	unsigned int sub_string_index = 0, j = 0;
+	char c = 0;
+	unsigned int n = 0;
+	u16 hE = 0;
+
+	if ((string_length < 1) || (string_length > 256))
+		return HPI_ERROR_INVALID_CONTROL_VALUE;
+	for (sub_string_index = 0; sub_string_index < string_length;
+		sub_string_index += 8) {
+		struct hpi_message hm;
+		struct hpi_response hr;
+
+		hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+			HPI_CONTROL_GET_STATE);
+		u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+		hm.u.c.attribute = attribute;
+		hm.u.c.param1 = sub_string_index;
+		hm.u.c.param2 = 0;
+		hpi_send_recv(&hm, &hr);
+
+		if (sub_string_index == 0
+			&& (hr.u.cu.chars8.remaining_chars + 8) >
+			string_length)
+			return HPI_ERROR_INVALID_CONTROL_VALUE;
+
+		if (hr.error) {
+			hE = hr.error;
+			break;
+		}
+		for (j = 0; j < 8; j++) {
+			c = hr.u.cu.chars8.sz_data[j];
+			psz_string[sub_string_index + j] = c;
+			n++;
+			if (n >= string_length) {
+				psz_string[string_length - 1] = 0;
+				hE = HPI_ERROR_INVALID_CONTROL_VALUE;
+				break;
+			}
+			if (c == 0)
+				break;
+		}
+
+		if ((hr.u.cu.chars8.remaining_chars == 0)
+			&& ((sub_string_index + j) < string_length)
+			&& (c != 0)) {
+			c = 0;
+			psz_string[sub_string_index + j] = c;
+		}
+		if (c == 0)
+			break;
+	}
+	return hE;
+}
+
+u16 HPI_AESEBU__receiver_query_format(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_aes_rx, const u32 index, u16 *pw_format)
+{
+	u32 qr;
+	u16 err;
+
+	err = hpi_control_query(ph_subsys, h_aes_rx, HPI_AESEBURX_FORMAT,
+		index, 0, &qr);
+	*pw_format = (u16)qr;
+	return err;
+}
+
+u16 HPI_AESEBU__receiver_set_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 format)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_AESEBURX_FORMAT, format, 0);
+}
+
+u16 HPI_AESEBU__receiver_get_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_format)
+{
+	u16 err;
+	u32 param;
+
+	err = hpi_control_param1_get(ph_subsys, h_control,
+		HPI_AESEBURX_FORMAT, &param);
+	if (!err && pw_format)
+		*pw_format = (u16)param;
+
+	return err;
+}
+
+u16 HPI_AESEBU__receiver_get_sample_rate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *psample_rate)
+{
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_AESEBURX_SAMPLERATE, psample_rate);
+}
+
+u16 HPI_AESEBU__receiver_get_user_data(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, u16 *pw_data)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_AESEBURX_USERDATA;
+	hm.u.c.param1 = index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (pw_data)
+		*pw_data = (u16)hr.u.c.param2;
+	return hr.error;
+}
+
+u16 HPI_AESEBU__receiver_get_channel_status(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, u16 index, u16 *pw_data)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_AESEBURX_CHANNELSTATUS;
+	hm.u.c.param1 = index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (pw_data)
+		*pw_data = (u16)hr.u.c.param2;
+	return hr.error;
+}
+
+u16 HPI_AESEBU__receiver_get_error_status(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_error_data)
+{
+	u32 error_data = 0;
+	u16 error = 0;
+
+	error = hpi_control_param1_get(ph_subsys, h_control,
+		HPI_AESEBURX_ERRORSTATUS, &error_data);
+	if (pw_error_data)
+		*pw_error_data = (u16)error_data;
+	return error;
+}
+
+u16 HPI_AESEBU__transmitter_set_sample_rate(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, u32 sample_rate)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_AESEBUTX_SAMPLERATE, sample_rate, 0);
+}
+
+u16 HPI_AESEBU__transmitter_set_user_data(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, u16 data)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_AESEBUTX_USERDATA, index, data);
+}
+
+u16 HPI_AESEBU__transmitter_set_channel_status(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, u16 index, u16 data)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_AESEBUTX_CHANNELSTATUS, index, data);
+}
+
+u16 HPI_AESEBU__transmitter_get_channel_status(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, u16 index, u16 *pw_data)
+{
+	return HPI_ERROR_INVALID_OPERATION;
+}
+
+u16 HPI_AESEBU__transmitter_query_format(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_aes_tx, const u32 index, u16 *pw_format)
+{
+	u32 qr;
+	u16 err;
+
+	err = hpi_control_query(ph_subsys, h_aes_tx, HPI_AESEBUTX_FORMAT,
+		index, 0, &qr);
+	*pw_format = (u16)qr;
+	return err;
+}
+
+u16 HPI_AESEBU__transmitter_set_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 output_format)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_AESEBUTX_FORMAT, output_format, 0);
+}
+
+u16 HPI_AESEBU__transmitter_get_format(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_output_format)
+{
+	u16 err;
+	u32 param;
+
+	err = hpi_control_param1_get(ph_subsys, h_control,
+		HPI_AESEBUTX_FORMAT, &param);
+	if (!err && pw_output_format)
+		*pw_output_format = (u16)param;
+
+	return err;
+}
+
+u16 hpi_bitstream_set_clock_edge(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 edge_type)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_BITSTREAM_CLOCK_EDGE, edge_type, 0);
+}
+
+u16 hpi_bitstream_set_data_polarity(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 polarity)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_BITSTREAM_DATA_POLARITY, polarity, 0);
+}
+
+u16 hpi_bitstream_get_activity(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_clk_activity, u16 *pw_data_activity)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_BITSTREAM_ACTIVITY;
+	hpi_send_recv(&hm, &hr);
+	if (pw_clk_activity)
+		*pw_clk_activity = (u16)hr.u.c.param1;
+	if (pw_data_activity)
+		*pw_data_activity = (u16)hr.u.c.param2;
+	return hr.error;
+}
+
+u16 hpi_channel_mode_query_mode(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_mode, const u32 index, u16 *pw_mode)
+{
+	u32 qr;
+	u16 err;
+
+	err = hpi_control_query(ph_subsys, h_mode, HPI_CHANNEL_MODE_MODE,
+		index, 0, &qr);
+	*pw_mode = (u16)qr;
+	return err;
+}
+
+u16 hpi_channel_mode_set(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 mode)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_CHANNEL_MODE_MODE, mode, 0);
+}
+
+u16 hpi_channel_mode_get(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 *mode)
+{
+	u32 mode32 = 0;
+	u16 error = hpi_control_param1_get(ph_subsys, h_control,
+		HPI_CHANNEL_MODE_MODE, &mode32);
+	if (mode)
+		*mode = (u16)mode32;
+	return error;
+}
+
+u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 hmi_address, u32 byte_count, u8 *pb_data)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
+		HPI_CONTROL_SET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+
+	hm.u.cx.u.cobranet_data.byte_count = byte_count;
+	hm.u.cx.u.cobranet_data.hmi_address = hmi_address;
+
+	if (byte_count <= 8) {
+		memcpy(hm.u.cx.u.cobranet_data.data, pb_data, byte_count);
+		hm.u.cx.attribute = HPI_COBRANET_SET;
+	} else {
+		hm.u.cx.u.cobranet_bigdata.pb_data = pb_data;
+		hm.u.cx.attribute = HPI_COBRANET_SET_DATA;
+	}
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 hmi_address, u32 max_byte_count, u32 *pbyte_count, u8 *pb_data)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+
+	hm.u.cx.u.cobranet_data.byte_count = max_byte_count;
+	hm.u.cx.u.cobranet_data.hmi_address = hmi_address;
+
+	if (max_byte_count <= 8) {
+		hm.u.cx.attribute = HPI_COBRANET_GET;
+	} else {
+		hm.u.cx.u.cobranet_bigdata.pb_data = pb_data;
+		hm.u.cx.attribute = HPI_COBRANET_GET_DATA;
+	}
+
+	hpi_send_recv(&hm, &hr);
+	if (!hr.error && pb_data) {
+
+		*pbyte_count = hr.u.cx.u.cobranet_data.byte_count;
+
+		if (*pbyte_count < max_byte_count)
+			max_byte_count = *pbyte_count;
+
+		if (hm.u.cx.attribute == HPI_COBRANET_GET) {
+			memcpy(pb_data, hr.u.cx.u.cobranet_data.data,
+				max_byte_count);
+		} else {
+
+		}
+
+	}
+	return hr.error;
+}
+
+u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pstatus, u32 *preadable_size,
+	u32 *pwriteable_size)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+
+	hm.u.cx.attribute = HPI_COBRANET_GET_STATUS;
+
+	hpi_send_recv(&hm, &hr);
+	if (!hr.error) {
+		if (pstatus)
+			*pstatus = hr.u.cx.u.cobranet_status.status;
+		if (preadable_size)
+			*preadable_size =
+				hr.u.cx.u.cobranet_status.readable_size;
+		if (pwriteable_size)
+			*pwriteable_size =
+				hr.u.cx.u.cobranet_status.writeable_size;
+	}
+	return hr.error;
+}
+
+u16 hpi_cobranet_getI_paddress(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pi_paddress)
+{
+	u32 byte_count;
+	u32 iP;
+	u16 error;
+	error = hpi_cobranet_hmi_read(ph_subsys, h_control,
+		HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, &byte_count,
+		(u8 *)&iP);
+
+	*pi_paddress =
+		((iP & 0xff000000) >> 8) | ((iP & 0x00ff0000) << 8) | ((iP &
+			0x0000ff00) >> 8) | ((iP & 0x000000ff) << 8);
+
+	if (error)
+		*pi_paddress = 0;
+
+	return error;
+
+}
+
+u16 hpi_cobranet_setI_paddress(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 i_paddress)
+{
+	u32 iP;
+	u16 error;
+
+	iP = ((i_paddress & 0xff000000) >> 8) | ((i_paddress & 0x00ff0000) <<
+		8) | ((i_paddress & 0x0000ff00) >> 8) | ((i_paddress &
+			0x000000ff) << 8);
+
+	error = hpi_cobranet_hmi_write(ph_subsys, h_control,
+		HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, (u8 *)&iP);
+
+	return error;
+
+}
+
+u16 hpi_cobranet_get_staticI_paddress(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pi_paddress)
+{
+	u32 byte_count;
+	u32 iP;
+	u16 error;
+	error = hpi_cobranet_hmi_read(ph_subsys, h_control,
+		HPI_COBRANET_HMI_cobra_ip_mon_staticIP, 4, &byte_count,
+		(u8 *)&iP);
+
+	*pi_paddress =
+		((iP & 0xff000000) >> 8) | ((iP & 0x00ff0000) << 8) | ((iP &
+			0x0000ff00) >> 8) | ((iP & 0x000000ff) << 8);
+
+	if (error)
+		*pi_paddress = 0;
+
+	return error;
+
+}
+
+u16 hpi_cobranet_set_staticI_paddress(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 i_paddress)
+{
+	u32 iP;
+	u16 error;
+
+	iP = ((i_paddress & 0xff000000) >> 8) | ((i_paddress & 0x00ff0000) <<
+		8) | ((i_paddress & 0x0000ff00) >> 8) | ((i_paddress &
+			0x000000ff) << 8);
+
+	error = hpi_cobranet_hmi_write(ph_subsys, h_control,
+		HPI_COBRANET_HMI_cobra_ip_mon_staticIP, 4, (u8 *)&iP);
+
+	return error;
+
+}
+
+u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pmAC_MS_bs, u32 *pmAC_LS_bs)
+{
+	u32 byte_count;
+	u16 error;
+	u32 mAC;
+	error = hpi_cobranet_hmi_read(ph_subsys, h_control,
+		HPI_COBRANET_HMI_cobra_if_phy_address, 4, &byte_count,
+		(u8 *)&mAC);
+	*pmAC_MS_bs =
+		((mAC & 0xff000000) >> 8) | ((mAC & 0x00ff0000) << 8) | ((mAC
+			& 0x0000ff00) >> 8) | ((mAC & 0x000000ff) << 8);
+	error += hpi_cobranet_hmi_read(ph_subsys, h_control,
+		HPI_COBRANET_HMI_cobra_if_phy_address + 1, 4, &byte_count,
+		(u8 *)&mAC);
+	*pmAC_LS_bs =
+		((mAC & 0xff000000) >> 8) | ((mAC & 0x00ff0000) << 8) | ((mAC
+			& 0x0000ff00) >> 8) | ((mAC & 0x000000ff) << 8);
+
+	if (error) {
+		*pmAC_MS_bs = 0;
+		*pmAC_LS_bs = 0;
+	}
+
+	return error;
+}
+
+u16 hpi_compander_set(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 attack, u16 decay, short ratio100, short threshold0_01dB,
+	short makeup_gain0_01dB)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_SET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+
+	hm.u.c.param1 = attack + ((u32)ratio100 << 16);
+	hm.u.c.param2 = (decay & 0xFFFFL);
+	hm.u.c.an_log_value[0] = threshold0_01dB;
+	hm.u.c.an_log_value[1] = makeup_gain0_01dB;
+	hm.u.c.attribute = HPI_COMPANDER_PARAMS;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_compander_get(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 *pw_attack, u16 *pw_decay, short *pw_ratio100,
+	short *pn_threshold0_01dB, short *pn_makeup_gain0_01dB)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_COMPANDER_PARAMS;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (pw_attack)
+		*pw_attack = (short)(hr.u.c.param1 & 0xFFFF);
+	if (pw_decay)
+		*pw_decay = (short)(hr.u.c.param2 & 0xFFFF);
+	if (pw_ratio100)
+		*pw_ratio100 = (short)(hr.u.c.param1 >> 16);
+
+	if (pn_threshold0_01dB)
+		*pn_threshold0_01dB = hr.u.c.an_log_value[0];
+	if (pn_makeup_gain0_01dB)
+		*pn_makeup_gain0_01dB = hr.u.c.an_log_value[1];
+
+	return hr.error;
+}
+
+u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_LEVEL_RANGE;
+
+	hpi_send_recv(&hm, &hr);
+	if (hr.error) {
+		hr.u.c.an_log_value[0] = 0;
+		hr.u.c.an_log_value[1] = 0;
+		hr.u.c.param1 = 0;
+	}
+	if (min_gain_01dB)
+		*min_gain_01dB = hr.u.c.an_log_value[0];
+	if (max_gain_01dB)
+		*max_gain_01dB = hr.u.c.an_log_value[1];
+	if (step_gain_01dB)
+		*step_gain_01dB = (short)hr.u.c.param1;
+	return hr.error;
+}
+
+u16 hpi_level_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_gain0_01dB[HPI_MAX_CHANNELS]
+	)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_SET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	memcpy(hm.u.c.an_log_value, an_gain0_01dB,
+		sizeof(short) * HPI_MAX_CHANNELS);
+	hm.u.c.attribute = HPI_LEVEL_GAIN;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_gain0_01dB[HPI_MAX_CHANNELS]
+	)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_LEVEL_GAIN;
+
+	hpi_send_recv(&hm, &hr);
+
+	memcpy(an_gain0_01dB, hr.u.c.an_log_value,
+		sizeof(short) * HPI_MAX_CHANNELS);
+	return hr.error;
+}
+
+u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_meter, u32 *p_channels)
+{
+	return hpi_control_query(ph_subsys, h_meter, HPI_METER_NUM_CHANNELS,
+		0, 0, p_channels);
+}
+
+u16 hpi_meter_get_peak(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_peakdB[HPI_MAX_CHANNELS]
+	)
+{
+	short i = 0;
+
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.obj_index = hm.obj_index;
+	hm.u.c.attribute = HPI_METER_PEAK;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (!hr.error)
+		memcpy(an_peakdB, hr.u.c.an_log_value,
+			sizeof(short) * HPI_MAX_CHANNELS);
+	else
+		for (i = 0; i < HPI_MAX_CHANNELS; i++)
+			an_peakdB[i] = HPI_METER_MINIMUM;
+	return hr.error;
+}
+
+u16 hpi_meter_get_rms(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_rmsdB[HPI_MAX_CHANNELS]
+	)
+{
+	short i = 0;
+
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_METER_RMS;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (!hr.error)
+		memcpy(an_rmsdB, hr.u.c.an_log_value,
+			sizeof(short) * HPI_MAX_CHANNELS);
+	else
+		for (i = 0; i < HPI_MAX_CHANNELS; i++)
+			an_rmsdB[i] = HPI_METER_MINIMUM;
+
+	return hr.error;
+}
+
+u16 hpi_meter_set_rms_ballistics(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 attack, u16 decay)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_METER_RMS_BALLISTICS, attack, decay);
+}
+
+u16 hpi_meter_get_rms_ballistics(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pn_attack, u16 *pn_decay)
+{
+	u32 attack;
+	u32 decay;
+	u16 error;
+
+	error = hpi_control_param2_get(ph_subsys, h_control,
+		HPI_METER_RMS_BALLISTICS, &attack, &decay);
+
+	if (pn_attack)
+		*pn_attack = (unsigned short)attack;
+	if (pn_decay)
+		*pn_decay = (unsigned short)decay;
+
+	return error;
+}
+
+u16 hpi_meter_set_peak_ballistics(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 attack, u16 decay)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_METER_PEAK_BALLISTICS, attack, decay);
+}
+
+u16 hpi_meter_get_peak_ballistics(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pn_attack, u16 *pn_decay)
+{
+	u32 attack;
+	u32 decay;
+	u16 error;
+
+	error = hpi_control_param2_get(ph_subsys, h_control,
+		HPI_METER_PEAK_BALLISTICS, &attack, &decay);
+
+	if (pn_attack)
+		*pn_attack = (short)attack;
+	if (pn_decay)
+		*pn_decay = (short)decay;
+
+	return error;
+}
+
+u16 hpi_microphone_set_phantom_power(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 on_off)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_MICROPHONE_PHANTOM_POWER, (u32)on_off, 0);
+}
+
+u16 hpi_microphone_get_phantom_power(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_on_off)
+{
+	u16 error = 0;
+	u32 on_off = 0;
+	error = hpi_control_param1_get(ph_subsys, h_control,
+		HPI_MICROPHONE_PHANTOM_POWER, &on_off);
+	if (pw_on_off)
+		*pw_on_off = (u16)on_off;
+	return error;
+}
+
+u16 hpi_multiplexer_set_source(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 source_node_type, u16 source_node_index)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_MULTIPLEXER_SOURCE, source_node_type, source_node_index);
+}
+
+u16 hpi_multiplexer_get_source(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *source_node_type, u16 *source_node_index)
+{
+	u32 node, index;
+	u16 error = hpi_control_param2_get(ph_subsys, h_control,
+		HPI_MULTIPLEXER_SOURCE, &node,
+		&index);
+	if (source_node_type)
+		*source_node_type = (u16)node;
+	if (source_node_index)
+		*source_node_index = (u16)index;
+	return error;
+}
+
+u16 hpi_multiplexer_query_source(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, u16 *source_node_type,
+	u16 *source_node_index)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_MULTIPLEXER_QUERYSOURCE;
+	hm.u.c.param1 = index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (source_node_type)
+		*source_node_type = (u16)hr.u.c.param1;
+	if (source_node_index)
+		*source_node_index = (u16)hr.u.c.param2;
+	return hr.error;
+}
+
+u16 hpi_parametricEQ__get_info(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_number_of_bands, u16 *pw_on_off)
+{
+	u32 oB = 0;
+	u32 oO = 0;
+	u16 error = 0;
+
+	error = hpi_control_param2_get(ph_subsys, h_control,
+		HPI_EQUALIZER_NUM_FILTERS, &oO, &oB);
+	if (pw_number_of_bands)
+		*pw_number_of_bands = (u16)oB;
+	if (pw_on_off)
+		*pw_on_off = (u16)oO;
+	return error;
+}
+
+u16 hpi_parametricEQ__set_state(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 on_off)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_EQUALIZER_NUM_FILTERS, on_off, 0);
+}
+
+u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, u16 *pn_type, u32 *pfrequency_hz,
+	short *pnQ100, short *pn_gain0_01dB)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_EQUALIZER_FILTER;
+	hm.u.c.param2 = index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (pfrequency_hz)
+		*pfrequency_hz = hr.u.c.param1;
+	if (pn_type)
+		*pn_type = (u16)(hr.u.c.param2 >> 16);
+	if (pnQ100)
+		*pnQ100 = hr.u.c.an_log_value[1];
+	if (pn_gain0_01dB)
+		*pn_gain0_01dB = hr.u.c.an_log_value[0];
+
+	return hr.error;
+}
+
+u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, u16 type, u32 frequency_hz, short q100,
+	short gain0_01dB)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_SET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+
+	hm.u.c.param1 = frequency_hz;
+	hm.u.c.param2 = (index & 0xFFFFL) + ((u32)type << 16);
+	hm.u.c.an_log_value[0] = gain0_01dB;
+	hm.u.c.an_log_value[1] = q100;
+	hm.u.c.attribute = HPI_EQUALIZER_FILTER;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 index, short coeffs[5]
+	)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_EQUALIZER_COEFFICIENTS;
+	hm.u.c.param2 = index;
+
+	hpi_send_recv(&hm, &hr);
+
+	coeffs[0] = (short)hr.u.c.an_log_value[0];
+	coeffs[1] = (short)hr.u.c.an_log_value[1];
+	coeffs[2] = (short)hr.u.c.param1;
+	coeffs[3] = (short)(hr.u.c.param1 >> 16);
+	coeffs[4] = (short)hr.u.c.param2;
+
+	return hr.error;
+}
+
+u16 hpi_sample_clock_query_source(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_clock, const u32 index, u16 *pw_source)
+{
+	u32 qr;
+	u16 err;
+
+	err = hpi_control_query(ph_subsys, h_clock, HPI_SAMPLECLOCK_SOURCE,
+		index, 0, &qr);
+	*pw_source = (u16)qr;
+	return err;
+}
+
+u16 hpi_sample_clock_set_source(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 source)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_SOURCE, source, 0);
+}
+
+u16 hpi_sample_clock_get_source(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_source)
+{
+	u16 error = 0;
+	u32 source = 0;
+	error = hpi_control_param1_get(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_SOURCE, &source);
+	if (!error)
+		if (pw_source)
+			*pw_source = (u16)source;
+	return error;
+}
+
+u16 hpi_sample_clock_query_source_index(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_clock, const u32 index, const u32 source,
+	u16 *pw_source_index)
+{
+	u32 qr;
+	u16 err;
+
+	err = hpi_control_query(ph_subsys, h_clock,
+		HPI_SAMPLECLOCK_SOURCE_INDEX, index, source, &qr);
+	*pw_source_index = (u16)qr;
+	return err;
+}
+
+u16 hpi_sample_clock_set_source_index(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 source_index)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_SOURCE_INDEX, source_index, 0);
+}
+
+u16 hpi_sample_clock_get_source_index(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 *pw_source_index)
+{
+	u16 error = 0;
+	u32 source_index = 0;
+	error = hpi_control_param1_get(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_SOURCE_INDEX, &source_index);
+	if (!error)
+		if (pw_source_index)
+			*pw_source_index = (u16)source_index;
+	return error;
+}
+
+u16 hpi_sample_clock_query_local_rate(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_clock, const u32 index, u32 *prate)
+{
+	u16 err;
+	err = hpi_control_query(ph_subsys, h_clock,
+		HPI_SAMPLECLOCK_LOCAL_SAMPLERATE, index, 0, prate);
+
+	return err;
+}
+
+u16 hpi_sample_clock_set_local_rate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 sample_rate)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_LOCAL_SAMPLERATE, sample_rate, 0);
+}
+
+u16 hpi_sample_clock_get_local_rate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *psample_rate)
+{
+	u16 error = 0;
+	u32 sample_rate = 0;
+	error = hpi_control_param1_get(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_LOCAL_SAMPLERATE, &sample_rate);
+	if (!error)
+		if (psample_rate)
+			*psample_rate = sample_rate;
+	return error;
+}
+
+u16 hpi_sample_clock_get_sample_rate(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *psample_rate)
+{
+	u16 error = 0;
+	u32 sample_rate = 0;
+	error = hpi_control_param1_get(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_SAMPLERATE, &sample_rate);
+	if (!error)
+		if (psample_rate)
+			*psample_rate = sample_rate;
+	return error;
+}
+
+u16 hpi_sample_clock_set_auto(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 enable)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_AUTO, enable, 0);
+}
+
+u16 hpi_sample_clock_get_auto(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *penable)
+{
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_AUTO, penable);
+}
+
+u16 hpi_sample_clock_set_local_rate_lock(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 lock)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_LOCAL_LOCK, lock, 0);
+}
+
+u16 hpi_sample_clock_get_local_rate_lock(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *plock)
+{
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_SAMPLECLOCK_LOCAL_LOCK, plock);
+}
+
+u16 hpi_tone_detector_get_frequency(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 index, u32 *frequency)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_TONEDETECTOR_FREQUENCY, index, 0, frequency, NULL);
+}
+
+u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *state)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_TONEDETECTOR_STATE, 0, 0, (u32 *)state, NULL);
+}
+
+u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 enable)
+{
+	return hpi_control_param_set(ph_subsys, h_control, HPI_GENERIC_ENABLE,
+		(u32)enable, 0);
+}
+
+u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *enable)
+{
+	return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE,
+		0, 0, (u32 *)enable, NULL);
+}
+
+u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 event_enable)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_GENERIC_EVENT_ENABLE, (u32)event_enable, 0);
+}
+
+u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *event_enable)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_GENERIC_EVENT_ENABLE, 0, 0, (u32 *)event_enable, NULL);
+}
+
+u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, int threshold)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_TONEDETECTOR_THRESHOLD, (u32)threshold, 0);
+}
+
+u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, int *threshold)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_TONEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL);
+}
+
+u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *state)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_SILENCEDETECTOR_STATE, 0, 0, (u32 *)state, NULL);
+}
+
+u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 enable)
+{
+	return hpi_control_param_set(ph_subsys, h_control, HPI_GENERIC_ENABLE,
+		(u32)enable, 0);
+}
+
+u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *enable)
+{
+	return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE,
+		0, 0, (u32 *)enable, NULL);
+}
+
+u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 event_enable)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_GENERIC_EVENT_ENABLE, (u32)event_enable, 0);
+}
+
+u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *event_enable)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_GENERIC_EVENT_ENABLE, 0, 0, (u32 *)event_enable, NULL);
+}
+
+u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 delay)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_SILENCEDETECTOR_DELAY, (u32)delay, 0);
+}
+
+u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *delay)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_SILENCEDETECTOR_DELAY, 0, 0, (u32 *)delay, NULL);
+}
+
+u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, int threshold)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_SILENCEDETECTOR_THRESHOLD, (u32)threshold, 0);
+}
+
+u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, int *threshold)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_SILENCEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL);
+}
+
+u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_tuner, const u32 index, u16 *pw_band)
+{
+	u32 qr;
+	u16 err;
+
+	err = hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_BAND, index, 0,
+		&qr);
+	*pw_band = (u16)qr;
+	return err;
+}
+
+u16 hpi_tuner_set_band(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 band)
+{
+	return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_BAND,
+		band, 0);
+}
+
+u16 hpi_tuner_get_band(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 *pw_band)
+{
+	u32 band = 0;
+	u16 error = 0;
+
+	error = hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_BAND,
+		&band);
+	if (pw_band)
+		*pw_band = (u16)band;
+	return error;
+}
+
+u16 hpi_tuner_query_frequency(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_tuner, const u32 index, const u16 band, u32 *pfreq)
+{
+	return hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_FREQ, index,
+		band, pfreq);
+}
+
+u16 hpi_tuner_set_frequency(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 freq_ink_hz)
+{
+	return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_FREQ,
+		freq_ink_hz, 0);
+}
+
+u16 hpi_tuner_get_frequency(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pw_freq_ink_hz)
+{
+	return hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_FREQ,
+		pw_freq_ink_hz);
+}
+
+u16 hpi_tuner_query_gain(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_tuner, const u32 index, u16 *pw_gain)
+{
+	u32 qr;
+	u16 err;
+
+	err = hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_BAND, index, 0,
+		&qr);
+	*pw_gain = (u16)qr;
+	return err;
+}
+
+u16 hpi_tuner_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short gain)
+{
+	return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_GAIN,
+		gain, 0);
+}
+
+u16 hpi_tuner_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short *pn_gain)
+{
+	u32 gain = 0;
+	u16 error = 0;
+
+	error = hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_GAIN,
+		&gain);
+	if (pn_gain)
+		*pn_gain = (u16)gain;
+	return error;
+}
+
+u16 hpi_tuner_getRF_level(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short *pw_level)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_TUNER_LEVEL;
+	hm.u.c.param1 = HPI_TUNER_LEVEL_AVERAGE;
+	hpi_send_recv(&hm, &hr);
+	if (pw_level)
+		*pw_level = (short)hr.u.c.param1;
+	return hr.error;
+}
+
+u16 hpi_tuner_get_rawRF_level(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, short *pw_level)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_TUNER_LEVEL;
+	hm.u.c.param1 = HPI_TUNER_LEVEL_RAW;
+	hpi_send_recv(&hm, &hr);
+	if (pw_level)
+		*pw_level = (short)hr.u.c.param1;
+	return hr.error;
+}
+
+u16 hpi_tuner_query_deemphasis(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_tuner, const u32 index, const u16 band, u32 *pdeemphasis)
+{
+	return hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_DEEMPHASIS,
+		index, band, pdeemphasis);
+}
+
+u16 hpi_tuner_set_deemphasis(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 deemphasis)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_TUNER_DEEMPHASIS, deemphasis, 0);
+}
+
+u16 hpi_tuner_get_deemphasis(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pdeemphasis)
+{
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_TUNER_DEEMPHASIS, pdeemphasis);
+}
+
+u16 hpi_tuner_query_program(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_tuner, u32 *pbitmap_program)
+{
+	return hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_PROGRAM, 0, 0,
+		pbitmap_program);
+}
+
+u16 hpi_tuner_set_program(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 program)
+{
+	return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_PROGRAM,
+		program, 0);
+}
+
+u16 hpi_tuner_get_program(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 *pprogram)
+{
+	return hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_PROGRAM,
+		pprogram);
+}
+
+u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, char *psz_dsp_version, const u32 string_size)
+{
+	return hpi_control_get_string(ph_subsys, h_control,
+		HPI_TUNER_HDRADIO_DSP_VERSION, psz_dsp_version, string_size);
+}
+
+u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, char *psz_sdk_version, const u32 string_size)
+{
+	return hpi_control_get_string(ph_subsys, h_control,
+		HPI_TUNER_HDRADIO_SDK_VERSION, psz_sdk_version, string_size);
+}
+
+u16 hpi_tuner_get_status(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u16 *pw_status_mask, u16 *pw_status)
+{
+	u32 status = 0;
+	u16 error = 0;
+
+	error = hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_STATUS,
+		&status);
+	if (pw_status) {
+		if (!error) {
+			*pw_status_mask = (u16)(status >> 16);
+			*pw_status = (u16)(status & 0xFFFF);
+		} else {
+			*pw_status_mask = 0;
+			*pw_status = 0;
+		}
+	}
+	return error;
+}
+
+u16 hpi_tuner_set_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 mode, u32 value)
+{
+	return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_MODE,
+		mode, value);
+}
+
+u16 hpi_tuner_get_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 mode, u32 *pn_value)
+{
+	return hpi_control_param_get(ph_subsys, h_control, HPI_TUNER_MODE,
+		mode, 0, pn_value, NULL);
+}
+
+u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pquality)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_TUNER_HDRADIO_SIGNAL_QUALITY, 0, 0, pquality, NULL);
+}
+
+u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	char *p_data)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_TUNER_RDS;
+	hpi_send_recv(&hm, &hr);
+	if (p_data) {
+		*(u32 *)&p_data[0] = hr.u.cu.tuner.rds.data[0];
+		*(u32 *)&p_data[4] = hr.u.cu.tuner.rds.data[1];
+		*(u32 *)&p_data[8] = hr.u.cu.tuner.rds.bLER;
+	}
+	return hr.error;
+}
+
+u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, char *psz_string, const u32 data_length)
+{
+	return hpi_control_get_string(ph_subsys, h_control,
+		HPI_PAD_CHANNEL_NAME, psz_string, data_length);
+}
+
+u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	char *psz_string, const u32 data_length)
+{
+	return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_ARTIST,
+		psz_string, data_length);
+}
+
+u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	char *psz_string, const u32 data_length)
+{
+	return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_TITLE,
+		psz_string, data_length);
+}
+
+u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	char *psz_string, const u32 data_length)
+{
+	return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_COMMENT,
+		psz_string, data_length);
+}
+
+u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *ppTY)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_PAD_PROGRAM_TYPE, 0, 0, ppTY, NULL);
+}
+
+u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	u32 *ppI)
+{
+	return hpi_control_param_get(ph_subsys, h_control, HPI_PAD_PROGRAM_ID,
+		0, 0, ppI, NULL);
+}
+
+u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys,
+	const u32 h_volume, u32 *p_channels)
+{
+	return hpi_control_query(ph_subsys, h_volume, HPI_VOLUME_NUM_CHANNELS,
+		0, 0, p_channels);
+}
+
+u16 hpi_volume_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_log_gain[HPI_MAX_CHANNELS]
+	)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_SET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	memcpy(hm.u.c.an_log_value, an_log_gain,
+		sizeof(short) * HPI_MAX_CHANNELS);
+	hm.u.c.attribute = HPI_VOLUME_GAIN;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_log_gain[HPI_MAX_CHANNELS]
+	)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_VOLUME_GAIN;
+
+	hpi_send_recv(&hm, &hr);
+
+	memcpy(an_log_gain, hr.u.c.an_log_value,
+		sizeof(short) * HPI_MAX_CHANNELS);
+	return hr.error;
+}
+
+u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_VOLUME_RANGE;
+
+	hpi_send_recv(&hm, &hr);
+	if (hr.error) {
+		hr.u.c.an_log_value[0] = 0;
+		hr.u.c.an_log_value[1] = 0;
+		hr.u.c.param1 = 0;
+	}
+	if (min_gain_01dB)
+		*min_gain_01dB = hr.u.c.an_log_value[0];
+	if (max_gain_01dB)
+		*max_gain_01dB = hr.u.c.an_log_value[1];
+	if (step_gain_01dB)
+		*step_gain_01dB = (short)hr.u.c.param1;
+	return hr.error;
+}
+
+u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, short an_stop_gain0_01dB[HPI_MAX_CHANNELS],
+	u32 duration_ms, u16 profile)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_SET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+
+	memcpy(hm.u.c.an_log_value, an_stop_gain0_01dB,
+		sizeof(short) * HPI_MAX_CHANNELS);
+
+	hm.u.c.attribute = HPI_VOLUME_AUTOFADE;
+	hm.u.c.param1 = duration_ms;
+	hm.u.c.param2 = profile;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_volume_auto_fade(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_stop_gain0_01dB[HPI_MAX_CHANNELS], u32 duration_ms)
+{
+	return hpi_volume_auto_fade_profile(ph_subsys, h_control,
+		an_stop_gain0_01dB, duration_ms, HPI_VOLUME_AUTOFADE_LOG);
+}
+
+u16 hpi_vox_set_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short an_gain0_01dB)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_SET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_VOX_THRESHOLD;
+
+	hm.u.c.an_log_value[0] = an_gain0_01dB;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_vox_get_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+	short *an_gain0_01dB)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+		HPI_CONTROL_GET_STATE);
+	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+	hm.u.c.attribute = HPI_VOX_THRESHOLD;
+
+	hpi_send_recv(&hm, &hr);
+
+	*an_gain0_01dB = hr.u.c.an_log_value[0];
+
+	return hr.error;
+}
+
+static size_t strv_packet_size = MIN_STRV_PACKET_SIZE;
+
+static size_t entity_type_to_size[LAST_ENTITY_TYPE] = {
+	0,
+	sizeof(struct hpi_entity),
+	sizeof(void *),
+
+	sizeof(int),
+	sizeof(float),
+	sizeof(double),
+
+	sizeof(char),
+	sizeof(char),
+
+	4 * sizeof(char),
+	16 * sizeof(char),
+	6 * sizeof(char),
+};
+
+inline size_t hpi_entity_size(struct hpi_entity *entity_ptr)
+{
+	return entity_ptr->header.size;
+}
+
+inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr)
+{
+	return sizeof(entity_ptr->header);
+}
+
+inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr)
+{
+	return hpi_entity_size(entity_ptr) -
+		hpi_entity_header_size(entity_ptr);
+}
+
+inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr)
+{
+	return hpi_entity_value_size(entity_ptr) /
+		entity_type_to_size[entity_ptr->header.type];
+}
+
+inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity
+	*entity_ptr)
+{
+	return (void *)(((uint8_t *) entity_ptr) +
+		hpi_entity_size(entity_ptr));
+}
+
+inline u16 hpi_entity_check_type(const enum e_entity_type t)
+{
+	if (t >= 0 && t < STR_TYPE_FIELD_MAX)
+		return 0;
+	return HPI_ERROR_ENTITY_TYPE_INVALID;
+}
+
+inline u16 hpi_entity_check_role(const enum e_entity_role r)
+{
+	if (r >= 0 && r < STR_ROLE_FIELD_MAX)
+		return 0;
+	return HPI_ERROR_ENTITY_ROLE_INVALID;
+}
+
+static u16 hpi_entity_get_next(struct hpi_entity *entity, int recursive_flag,
+	void *guard_p, struct hpi_entity **next)
+{
+	HPI_DEBUG_ASSERT(entity != NULL);
+	HPI_DEBUG_ASSERT(next != NULL);
+	HPI_DEBUG_ASSERT(hpi_entity_size(entity) != 0);
+
+	if (guard_p <= (void *)entity) {
+		*next = NULL;
+		return 0;
+	}
+
+	if (recursive_flag && entity->header.type == entity_type_sequence)
+		*next = (struct hpi_entity *)entity->value;
+	else
+		*next = (struct hpi_entity *)hpi_entity_ptr_to_next(entity);
+
+	if (guard_p <= (void *)*next) {
+		*next = NULL;
+		return 0;
+	}
+
+	HPI_DEBUG_ASSERT(guard_p >= (void *)hpi_entity_ptr_to_next(*next));
+	return 0;
+}
+
+u16 hpi_entity_find_next(struct hpi_entity *container_entity,
+	enum e_entity_type type, enum e_entity_role role, int recursive_flag,
+	struct hpi_entity **current_match)
+{
+	struct hpi_entity *tmp = NULL;
+	void *guard_p = NULL;
+
+	HPI_DEBUG_ASSERT(container_entity != NULL);
+	guard_p = hpi_entity_ptr_to_next(container_entity);
+
+	if (*current_match != NULL)
+		hpi_entity_get_next(*current_match, recursive_flag, guard_p,
+			&tmp);
+	else
+		hpi_entity_get_next(container_entity, 1, guard_p, &tmp);
+
+	while (tmp) {
+		u16 err;
+
+		HPI_DEBUG_ASSERT((void *)tmp >= (void *)container_entity);
+
+		if ((!type || tmp->header.type == type) && (!role
+				|| tmp->header.role == role)) {
+			*current_match = tmp;
+			return 0;
+		}
+
+		err = hpi_entity_get_next(tmp, recursive_flag, guard_p,
+			current_match);
+		if (err)
+			return err;
+
+		tmp = *current_match;
+	}
+
+	*current_match = NULL;
+	return 0;
+}
+
+void hpi_entity_free(struct hpi_entity *entity)
+{
+	if (entity != NULL)
+		kfree(entity);
+}
+
+static u16 hpi_entity_alloc_and_copy(struct hpi_entity *src,
+	struct hpi_entity **dst)
+{
+	size_t buf_size;
+	HPI_DEBUG_ASSERT(dst != NULL);
+	HPI_DEBUG_ASSERT(src != NULL);
+
+	buf_size = hpi_entity_size(src);
+	*dst = kmalloc(buf_size, GFP_KERNEL);
+	if (*dst == NULL)
+		return HPI_ERROR_MEMORY_ALLOC;
+	memcpy(*dst, src, buf_size);
+	return 0;
+}
+
+u16 hpi_universal_info(const struct hpi_hsubsys *ph_subsys, u32 hC,
+	struct hpi_entity **info)
+{
+	struct hpi_msg_strv hm;
+	struct hpi_res_strv *phr;
+	u16 hpi_err;
+	int remaining_attempts = 2;
+	size_t resp_packet_size = 1024;
+
+	*info = NULL;
+
+	while (remaining_attempts--) {
+		phr = kmalloc(resp_packet_size, GFP_KERNEL);
+		HPI_DEBUG_ASSERT(phr != NULL);
+
+		hpi_init_message_responseV1(&hm.h, (u16)sizeof(hm), &phr->h,
+			(u16)resp_packet_size, HPI_OBJ_CONTROL,
+			HPI_CONTROL_GET_INFO);
+		u32TOINDEXES(hC, &hm.h.adapter_index, &hm.h.obj_index);
+
+		hm.strv.header.size = sizeof(hm.strv);
+		phr->strv.header.size = resp_packet_size - sizeof(phr->h);
+
+		hpi_send_recv((struct hpi_message *)&hm.h,
+			(struct hpi_response *)&phr->h);
+		if (phr->h.error == HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL) {
+
+			HPI_DEBUG_ASSERT(phr->h.specific_error >
+				MIN_STRV_PACKET_SIZE
+				&& phr->h.specific_error < 1500);
+			resp_packet_size = phr->h.specific_error;
+		} else {
+			remaining_attempts = 0;
+			if (!phr->h.error)
+				hpi_entity_alloc_and_copy(&phr->strv, info);
+		}
+
+		hpi_err = phr->h.error;
+		kfree(phr);
+	}
+
+	return hpi_err;
+}
+
+u16 hpi_universal_get(const struct hpi_hsubsys *ph_subsys, u32 hC,
+	struct hpi_entity **value)
+{
+	struct hpi_msg_strv hm;
+	struct hpi_res_strv *phr;
+	u16 hpi_err;
+	int remaining_attempts = 2;
+
+	*value = NULL;
+
+	while (remaining_attempts--) {
+		phr = kmalloc(strv_packet_size, GFP_KERNEL);
+		if (!phr)
+			return HPI_ERROR_MEMORY_ALLOC;
+
+		hpi_init_message_responseV1(&hm.h, (u16)sizeof(hm), &phr->h,
+			(u16)strv_packet_size, HPI_OBJ_CONTROL,
+			HPI_CONTROL_GET_STATE);
+		u32TOINDEXES(hC, &hm.h.adapter_index, &hm.h.obj_index);
+
+		hm.strv.header.size = sizeof(hm.strv);
+		phr->strv.header.size = strv_packet_size - sizeof(phr->h);
+
+		hpi_send_recv((struct hpi_message *)&hm.h,
+			(struct hpi_response *)&phr->h);
+		if (phr->h.error == HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL) {
+
+			HPI_DEBUG_ASSERT(phr->h.specific_error >
+				MIN_STRV_PACKET_SIZE
+				&& phr->h.specific_error < 1000);
+			strv_packet_size = phr->h.specific_error;
+		} else {
+			remaining_attempts = 0;
+			if (!phr->h.error)
+				hpi_entity_alloc_and_copy(&phr->strv, value);
+		}
+
+		hpi_err = phr->h.error;
+		kfree(phr);
+	}
+
+	return hpi_err;
+}
+
+u16 hpi_universal_set(const struct hpi_hsubsys *ph_subsys, u32 hC,
+	struct hpi_entity *value)
+{
+	struct hpi_msg_strv *phm;
+	struct hpi_res_strv hr;
+
+	phm = kmalloc(sizeof(phm->h) + value->header.size, GFP_KERNEL);
+	HPI_DEBUG_ASSERT(phm != NULL);
+
+	hpi_init_message_responseV1(&phm->h,
+		sizeof(phm->h) + value->header.size, &hr.h, sizeof(hr),
+		HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
+	u32TOINDEXES(hC, &phm->h.adapter_index, &phm->h.obj_index);
+	hr.strv.header.size = sizeof(hr.strv);
+
+	memcpy(&phm->strv, value, value->header.size);
+	hpi_send_recv((struct hpi_message *)&phm->h,
+		(struct hpi_response *)&hr.h);
+
+	return hr.h.error;
+}
+
+u16 hpi_entity_alloc_and_pack(const enum e_entity_type type,
+	const size_t item_count, const enum e_entity_role role, void *value,
+	struct hpi_entity **entity)
+{
+	size_t bytes_to_copy, total_size;
+	u16 hE = 0;
+	*entity = NULL;
+
+	hE = hpi_entity_check_type(type);
+	if (hE)
+		return hE;
+
+	HPI_DEBUG_ASSERT(role > entity_role_null && type < LAST_ENTITY_TYPE);
+
+	bytes_to_copy = entity_type_to_size[type] * item_count;
+	total_size = hpi_entity_header_size(*entity) + bytes_to_copy;
+
+	HPI_DEBUG_ASSERT(total_size >= hpi_entity_header_size(*entity)
+		&& total_size < STR_SIZE_FIELD_MAX);
+
+	*entity = kmalloc(total_size, GFP_KERNEL);
+	if (*entity == NULL)
+		return HPI_ERROR_MEMORY_ALLOC;
+	memcpy((*entity)->value, value, bytes_to_copy);
+	(*entity)->header.size =
+		hpi_entity_header_size(*entity) + bytes_to_copy;
+	(*entity)->header.type = type;
+	(*entity)->header.role = role;
+	return 0;
+}
+
+u16 hpi_entity_copy_value_from(struct hpi_entity *entity,
+	enum e_entity_type type, size_t item_count, void *value_dst_p)
+{
+	size_t bytes_to_copy;
+
+	if (entity->header.type != type)
+		return HPI_ERROR_ENTITY_TYPE_MISMATCH;
+
+	if (hpi_entity_item_count(entity) != item_count)
+		return HPI_ERROR_ENTITY_ITEM_COUNT;
+
+	bytes_to_copy = entity_type_to_size[type] * item_count;
+	memcpy(value_dst_p, entity->value, bytes_to_copy);
+	return 0;
+}
+
+u16 hpi_entity_unpack(struct hpi_entity *entity, enum e_entity_type *type,
+	size_t *item_count, enum e_entity_role *role, void **value)
+{
+	u16 err = 0;
+	HPI_DEBUG_ASSERT(entity != NULL);
+
+	if (type)
+		*type = entity->header.type;
+
+	if (role)
+		*role = entity->header.role;
+
+	if (value)
+		*value = entity->value;
+
+	if (item_count != NULL) {
+		if (entity->header.type == entity_type_sequence) {
+			void *guard_p = hpi_entity_ptr_to_next(entity);
+			struct hpi_entity *next = NULL;
+			void *contents = entity->value;
+
+			*item_count = 0;
+			while (contents < guard_p) {
+				(*item_count)++;
+				err = hpi_entity_get_next(contents, 0,
+					guard_p, &next);
+				if (next == NULL || err)
+					break;
+				contents = next;
+			}
+		} else {
+			*item_count = hpi_entity_item_count(entity);
+		}
+	}
+	return err;
+}
+
+u16 hpi_gpio_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u32 *ph_gpio, u16 *pw_number_input_bits, u16 *pw_number_output_bits)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_OPEN);
+	hm.adapter_index = adapter_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0) {
+		*ph_gpio =
+			hpi_indexes_to_handle(HPI_OBJ_GPIO, adapter_index, 0);
+		if (pw_number_input_bits)
+			*pw_number_input_bits = hr.u.l.number_input_bits;
+		if (pw_number_output_bits)
+			*pw_number_output_bits = hr.u.l.number_output_bits;
+	} else
+		*ph_gpio = 0;
+	return hr.error;
+}
+
+u16 hpi_gpio_read_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
+	u16 bit_index, u16 *pw_bit_data)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_READ_BIT);
+	u32TOINDEX(h_gpio, &hm.adapter_index);
+	hm.u.l.bit_index = bit_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	*pw_bit_data = hr.u.l.bit_data[0];
+	return hr.error;
+}
+
+u16 hpi_gpio_read_all_bits(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
+	u16 aw_all_bit_data[4]
+	)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_READ_ALL);
+	u32TOINDEX(h_gpio, &hm.adapter_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	if (aw_all_bit_data) {
+		aw_all_bit_data[0] = hr.u.l.bit_data[0];
+		aw_all_bit_data[1] = hr.u.l.bit_data[1];
+		aw_all_bit_data[2] = hr.u.l.bit_data[2];
+		aw_all_bit_data[3] = hr.u.l.bit_data[3];
+	}
+	return hr.error;
+}
+
+u16 hpi_gpio_write_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
+	u16 bit_index, u16 bit_data)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_WRITE_BIT);
+	u32TOINDEX(h_gpio, &hm.adapter_index);
+	hm.u.l.bit_index = bit_index;
+	hm.u.l.bit_data = bit_data;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_gpio_write_status(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
+	u16 aw_all_bit_data[4]
+	)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO,
+		HPI_GPIO_WRITE_STATUS);
+	u32TOINDEX(h_gpio, &hm.adapter_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	if (aw_all_bit_data) {
+		aw_all_bit_data[0] = hr.u.l.bit_data[0];
+		aw_all_bit_data[1] = hr.u.l.bit_data[1];
+		aw_all_bit_data[2] = hr.u.l.bit_data[2];
+		aw_all_bit_data[3] = hr.u.l.bit_data[3];
+	}
+	return hr.error;
+}
+
+u16 hpi_async_event_open(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u32 *ph_async)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT,
+		HPI_ASYNCEVENT_OPEN);
+	hm.adapter_index = adapter_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0)
+
+		*ph_async =
+			hpi_indexes_to_handle(HPI_OBJ_ASYNCEVENT,
+			adapter_index, 0);
+	else
+		*ph_async = 0;
+	return hr.error;
+
+}
+
+u16 hpi_async_event_close(const struct hpi_hsubsys *ph_subsys, u32 h_async)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT,
+		HPI_ASYNCEVENT_OPEN);
+	u32TOINDEX(h_async, &hm.adapter_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_async_event_wait(const struct hpi_hsubsys *ph_subsys, u32 h_async,
+	u16 maximum_events, struct hpi_async_event *p_events,
+	u16 *pw_number_returned)
+{
+	return 0;
+}
+
+u16 hpi_async_event_get_count(const struct hpi_hsubsys *ph_subsys,
+	u32 h_async, u16 *pw_count)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT,
+		HPI_ASYNCEVENT_GETCOUNT);
+	u32TOINDEX(h_async, &hm.adapter_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0)
+		if (pw_count)
+			*pw_count = hr.u.as.u.count.count;
+
+	return hr.error;
+}
+
+u16 hpi_async_event_get(const struct hpi_hsubsys *ph_subsys, u32 h_async,
+	u16 maximum_events, struct hpi_async_event *p_events,
+	u16 *pw_number_returned)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT,
+		HPI_ASYNCEVENT_GET);
+	u32TOINDEX(h_async, &hm.adapter_index);
+
+	hpi_send_recv(&hm, &hr);
+	if (!hr.error) {
+		memcpy(p_events, &hr.u.as.u.event,
+			sizeof(struct hpi_async_event));
+		*pw_number_returned = 1;
+	}
+
+	return hr.error;
+}
+
+u16 hpi_nv_memory_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u32 *ph_nv_memory, u16 *pw_size_in_bytes)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_NVMEMORY,
+		HPI_NVMEMORY_OPEN);
+	hm.adapter_index = adapter_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0) {
+		*ph_nv_memory =
+			hpi_indexes_to_handle(HPI_OBJ_NVMEMORY, adapter_index,
+			0);
+		if (pw_size_in_bytes)
+			*pw_size_in_bytes = hr.u.n.size_in_bytes;
+	} else
+		*ph_nv_memory = 0;
+	return hr.error;
+}
+
+u16 hpi_nv_memory_read_byte(const struct hpi_hsubsys *ph_subsys,
+	u32 h_nv_memory, u16 index, u16 *pw_data)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_NVMEMORY,
+		HPI_NVMEMORY_READ_BYTE);
+	u32TOINDEX(h_nv_memory, &hm.adapter_index);
+	hm.u.n.address = index;
+
+	hpi_send_recv(&hm, &hr);
+
+	*pw_data = hr.u.n.data;
+	return hr.error;
+}
+
+u16 hpi_nv_memory_write_byte(const struct hpi_hsubsys *ph_subsys,
+	u32 h_nv_memory, u16 index, u16 data)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_NVMEMORY,
+		HPI_NVMEMORY_WRITE_BYTE);
+	u32TOINDEX(h_nv_memory, &hm.adapter_index);
+	hm.u.n.address = index;
+	hm.u.n.data = data;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_profile_open_all(const struct hpi_hsubsys *ph_subsys,
+	u16 adapter_index, u16 profile_index, u32 *ph_profile,
+	u16 *pw_max_profiles)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE,
+		HPI_PROFILE_OPEN_ALL);
+	hm.adapter_index = adapter_index;
+	hm.obj_index = profile_index;
+	hpi_send_recv(&hm, &hr);
+
+	*pw_max_profiles = hr.u.p.u.o.max_profiles;
+	if (hr.error == 0)
+		*ph_profile =
+			hpi_indexes_to_handle(HPI_OBJ_PROFILE, adapter_index,
+			profile_index);
+	else
+		*ph_profile = 0;
+	return hr.error;
+}
+
+u16 hpi_profile_get(const struct hpi_hsubsys *ph_subsys, u32 h_profile,
+	u16 bin_index, u16 *pw_seconds, u32 *pmicro_seconds, u32 *pcall_count,
+	u32 *pmax_micro_seconds, u32 *pmin_micro_seconds)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE, HPI_PROFILE_GET);
+	u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index);
+	hm.u.p.bin_index = bin_index;
+	hpi_send_recv(&hm, &hr);
+	if (pw_seconds)
+		*pw_seconds = hr.u.p.u.t.seconds;
+	if (pmicro_seconds)
+		*pmicro_seconds = hr.u.p.u.t.micro_seconds;
+	if (pcall_count)
+		*pcall_count = hr.u.p.u.t.call_count;
+	if (pmax_micro_seconds)
+		*pmax_micro_seconds = hr.u.p.u.t.max_micro_seconds;
+	if (pmin_micro_seconds)
+		*pmin_micro_seconds = hr.u.p.u.t.min_micro_seconds;
+	return hr.error;
+}
+
+u16 hpi_profile_get_utilization(const struct hpi_hsubsys *ph_subsys,
+	u32 h_profile, u32 *putilization)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE,
+		HPI_PROFILE_GET_UTILIZATION);
+	u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+	if (hr.error) {
+		if (putilization)
+			*putilization = 0;
+	} else {
+		if (putilization)
+			*putilization = hr.u.p.u.t.call_count;
+	}
+	return hr.error;
+}
+
+u16 hpi_profile_get_name(const struct hpi_hsubsys *ph_subsys, u32 h_profile,
+	u16 bin_index, char *sz_name, u16 name_length)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE,
+		HPI_PROFILE_GET_NAME);
+	u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index);
+	hm.u.p.bin_index = bin_index;
+	hpi_send_recv(&hm, &hr);
+	if (hr.error) {
+		if (sz_name)
+			strcpy(sz_name, "??");
+	} else {
+		if (sz_name)
+			memcpy(sz_name, (char *)hr.u.p.u.n.sz_name,
+				name_length);
+	}
+	return hr.error;
+}
+
+u16 hpi_profile_start_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE,
+		HPI_PROFILE_START_ALL);
+	u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_profile_stop_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE,
+		HPI_PROFILE_STOP_ALL);
+	u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index);
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_watchdog_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
+	u32 *ph_watchdog)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_WATCHDOG,
+		HPI_WATCHDOG_OPEN);
+	hm.adapter_index = adapter_index;
+
+	hpi_send_recv(&hm, &hr);
+
+	if (hr.error == 0)
+		*ph_watchdog =
+			hpi_indexes_to_handle(HPI_OBJ_WATCHDOG, adapter_index,
+			0);
+	else
+		*ph_watchdog = 0;
+	return hr.error;
+}
+
+u16 hpi_watchdog_set_time(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog,
+	u32 time_millisec)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_WATCHDOG,
+		HPI_WATCHDOG_SET_TIME);
+	u32TOINDEX(h_watchdog, &hm.adapter_index);
+	hm.u.w.time_ms = time_millisec;
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}
+
+u16 hpi_watchdog_ping(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_WATCHDOG,
+		HPI_WATCHDOG_PING);
+	u32TOINDEX(h_watchdog, &hm.adapter_index);
+
+	hpi_send_recv(&hm, &hr);
+
+	return hr.error;
+}

+ 130 - 0
sound/pci/asihpi/hpimsginit.c

@@ -0,0 +1,130 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+ Hardware Programming Interface (HPI) Utility functions.
+
+ (C) Copyright AudioScience Inc. 2007
+*******************************************************************************/
+
+#include "hpi_internal.h"
+#include "hpimsginit.h"
+
+/* The actual message size for each object type */
+static u16 msg_size[HPI_OBJ_MAXINDEX + 1] = HPI_MESSAGE_SIZE_BY_OBJECT;
+/* The actual response size for each object type */
+static u16 res_size[HPI_OBJ_MAXINDEX + 1] = HPI_RESPONSE_SIZE_BY_OBJECT;
+/* Flag to enable alternate message type for SSX2 bypass. */
+static u16 gwSSX2_bypass;
+
+/** \internal
+  * Used by ASIO driver to disable SSX2 for a single process
+  * \param phSubSys Pointer to HPI subsystem handle.
+  * \param wBypass New bypass setting 0 = off, nonzero = on
+  * \return Previous bypass setting.
+  */
+u16 hpi_subsys_ssx2_bypass(const struct hpi_hsubsys *ph_subsys, u16 bypass)
+{
+	u16 old_value = gwSSX2_bypass;
+
+	gwSSX2_bypass = bypass;
+
+	return old_value;
+}
+
+/** \internal
+  * initialize the HPI message structure
+  */
+static void hpi_init_message(struct hpi_message *phm, u16 object,
+	u16 function)
+{
+	memset(phm, 0, sizeof(*phm));
+	if ((object > 0) && (object <= HPI_OBJ_MAXINDEX))
+		phm->size = msg_size[object];
+	else
+		phm->size = sizeof(*phm);
+
+	if (gwSSX2_bypass)
+		phm->type = HPI_TYPE_SSX2BYPASS_MESSAGE;
+	else
+		phm->type = HPI_TYPE_MESSAGE;
+	phm->object = object;
+	phm->function = function;
+	phm->version = 0;
+	/* Expect adapter index to be set by caller */
+}
+
+/** \internal
+  * initialize the HPI response structure
+  */
+void hpi_init_response(struct hpi_response *phr, u16 object, u16 function,
+	u16 error)
+{
+	memset(phr, 0, sizeof(*phr));
+	phr->type = HPI_TYPE_RESPONSE;
+	if ((object > 0) && (object <= HPI_OBJ_MAXINDEX))
+		phr->size = res_size[object];
+	else
+		phr->size = sizeof(*phr);
+	phr->object = object;
+	phr->function = function;
+	phr->error = error;
+	phr->specific_error = 0;
+	phr->version = 0;
+}
+
+void hpi_init_message_response(struct hpi_message *phm,
+	struct hpi_response *phr, u16 object, u16 function)
+{
+	hpi_init_message(phm, object, function);
+	/* default error return if the response is
+	   not filled in by the callee */
+	hpi_init_response(phr, object, function,
+		HPI_ERROR_PROCESSING_MESSAGE);
+}
+
+static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size,
+	u16 object, u16 function)
+{
+	memset(phm, 0, sizeof(*phm));
+	if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) {
+		phm->size = size;
+		phm->type = HPI_TYPE_MESSAGE;
+		phm->object = object;
+		phm->function = function;
+		phm->version = 1;
+		/* Expect adapter index to be set by caller */
+	}
+}
+
+void hpi_init_responseV1(struct hpi_response_header *phr, u16 size,
+	u16 object, u16 function)
+{
+	memset(phr, 0, sizeof(*phr));
+	phr->size = size;
+	phr->version = 1;
+	phr->type = HPI_TYPE_RESPONSE;
+	phr->error = HPI_ERROR_PROCESSING_MESSAGE;
+}
+
+void hpi_init_message_responseV1(struct hpi_message_header *phm, u16 msg_size,
+	struct hpi_response_header *phr, u16 res_size, u16 object,
+	u16 function)
+{
+	hpi_init_messageV1(phm, msg_size, object, function);
+	hpi_init_responseV1(phr, res_size, object, function);
+}

+ 40 - 0
sound/pci/asihpi/hpimsginit.h

@@ -0,0 +1,40 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+ Hardware Programming Interface (HPI) Utility functions
+
+ (C) Copyright AudioScience Inc. 2007
+*******************************************************************************/
+/* Initialise response headers, or msg/response pairs.
+Note that it is valid to just init a response e.g. when a lower level is preparing
+a response to a message.
+However, when sending a message, a matching response buffer always must be prepared
+*/
+
+void hpi_init_response(struct hpi_response *phr, u16 object, u16 function,
+	u16 error);
+
+void hpi_init_message_response(struct hpi_message *phm,
+	struct hpi_response *phr, u16 object, u16 function);
+
+void hpi_init_responseV1(struct hpi_response_header *phr, u16 size,
+	u16 object, u16 function);
+
+void hpi_init_message_responseV1(struct hpi_message_header *phm, u16 msg_size,
+	struct hpi_response_header *phr, u16 res_size, u16 object,
+	u16 function);

+ 907 - 0
sound/pci/asihpi/hpimsgx.c

@@ -0,0 +1,907 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+Extended Message Function With Response Cacheing
+
+(C) Copyright AudioScience Inc. 2002
+*****************************************************************************/
+#define SOURCEFILE_NAME "hpimsgx.c"
+#include "hpi_internal.h"
+#include "hpimsginit.h"
+#include "hpimsgx.h"
+#include "hpidebug.h"
+
+static struct pci_device_id asihpi_pci_tbl[] = {
+#include "hpipcida.h"
+};
+
+static struct hpios_spinlock msgx_lock;
+
+static hpi_handler_func *hpi_entry_points[HPI_MAX_ADAPTERS];
+
+static hpi_handler_func *hpi_lookup_entry_point_function(const struct hpi_pci
+	*pci_info)
+{
+
+	int i;
+
+	for (i = 0; asihpi_pci_tbl[i].vendor != 0; i++) {
+		if (asihpi_pci_tbl[i].vendor != PCI_ANY_ID
+			&& asihpi_pci_tbl[i].vendor != pci_info->vendor_id)
+			continue;
+		if (asihpi_pci_tbl[i].device != PCI_ANY_ID
+			&& asihpi_pci_tbl[i].device != pci_info->device_id)
+			continue;
+		if (asihpi_pci_tbl[i].subvendor != PCI_ANY_ID
+			&& asihpi_pci_tbl[i].subvendor !=
+			pci_info->subsys_vendor_id)
+			continue;
+		if (asihpi_pci_tbl[i].subdevice != PCI_ANY_ID
+			&& asihpi_pci_tbl[i].subdevice !=
+			pci_info->subsys_device_id)
+			continue;
+
+		HPI_DEBUG_LOG(DEBUG, " %x,%lu\n", i,
+			asihpi_pci_tbl[i].driver_data);
+		return (hpi_handler_func *) asihpi_pci_tbl[i].driver_data;
+	}
+
+	return NULL;
+}
+
+static inline void hw_entry_point(struct hpi_message *phm,
+	struct hpi_response *phr)
+{
+
+	hpi_handler_func *ep;
+
+	if (phm->adapter_index < HPI_MAX_ADAPTERS) {
+		ep = (hpi_handler_func *) hpi_entry_points[phm->
+			adapter_index];
+		if (ep) {
+			HPI_DEBUG_MESSAGE(DEBUG, phm);
+			ep(phm, phr);
+			HPI_DEBUG_RESPONSE(phr);
+			return;
+		}
+	}
+	hpi_init_response(phr, phm->object, phm->function,
+		HPI_ERROR_PROCESSING_MESSAGE);
+}
+
+static void adapter_open(struct hpi_message *phm, struct hpi_response *phr);
+static void adapter_close(struct hpi_message *phm, struct hpi_response *phr);
+
+static void mixer_open(struct hpi_message *phm, struct hpi_response *phr);
+static void mixer_close(struct hpi_message *phm, struct hpi_response *phr);
+
+static void outstream_open(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner);
+static void outstream_close(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner);
+static void instream_open(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner);
+static void instream_close(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner);
+
+static void HPIMSGX__reset(u16 adapter_index);
+static u16 HPIMSGX__init(struct hpi_message *phm, struct hpi_response *phr);
+static void HPIMSGX__cleanup(u16 adapter_index, void *h_owner);
+
+#ifndef DISABLE_PRAGMA_PACK1
+#pragma pack(push, 1)
+#endif
+
+struct hpi_subsys_response {
+	struct hpi_response_header h;
+	struct hpi_subsys_res s;
+};
+
+struct hpi_adapter_response {
+	struct hpi_response_header h;
+	struct hpi_adapter_res a;
+};
+
+struct hpi_mixer_response {
+	struct hpi_response_header h;
+	struct hpi_mixer_res m;
+};
+
+struct hpi_stream_response {
+	struct hpi_response_header h;
+	struct hpi_stream_res d;
+};
+
+struct adapter_info {
+	u16 type;
+	u16 num_instreams;
+	u16 num_outstreams;
+};
+
+struct asi_open_state {
+	int open_flag;
+	void *h_owner;
+};
+
+#ifndef DISABLE_PRAGMA_PACK1
+#pragma pack(pop)
+#endif
+
+/* Globals */
+static struct hpi_adapter_response rESP_HPI_ADAPTER_OPEN[HPI_MAX_ADAPTERS];
+
+static struct hpi_stream_response
+	rESP_HPI_OSTREAM_OPEN[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
+
+static struct hpi_stream_response
+	rESP_HPI_ISTREAM_OPEN[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
+
+static struct hpi_mixer_response rESP_HPI_MIXER_OPEN[HPI_MAX_ADAPTERS];
+
+static struct hpi_subsys_response gRESP_HPI_SUBSYS_FIND_ADAPTERS;
+
+static struct adapter_info aDAPTER_INFO[HPI_MAX_ADAPTERS];
+
+/* use these to keep track of opens from user mode apps/DLLs */
+static struct asi_open_state
+	outstream_user_open[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
+
+static struct asi_open_state
+	instream_user_open[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS];
+
+static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner)
+{
+	switch (phm->function) {
+	case HPI_SUBSYS_GET_VERSION:
+		hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
+			HPI_SUBSYS_GET_VERSION, 0);
+		phr->u.s.version = HPI_VER >> 8;	/* return major.minor */
+		phr->u.s.data = HPI_VER;	/* return major.minor.release */
+		break;
+	case HPI_SUBSYS_OPEN:
+		/*do not propagate the message down the chain */
+		hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_OPEN, 0);
+		break;
+	case HPI_SUBSYS_CLOSE:
+		/*do not propagate the message down the chain */
+		hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CLOSE,
+			0);
+		HPIMSGX__cleanup(HPIMSGX_ALLADAPTERS, h_owner);
+		break;
+	case HPI_SUBSYS_DRIVER_LOAD:
+		/* Initialize this module's internal state */
+		hpios_msgxlock_init(&msgx_lock);
+		memset(&hpi_entry_points, 0, sizeof(hpi_entry_points));
+		hpios_locked_mem_init();
+		/* Init subsys_findadapters response to no-adapters */
+		HPIMSGX__reset(HPIMSGX_ALLADAPTERS);
+		hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
+			HPI_SUBSYS_DRIVER_LOAD, 0);
+		/* individual HPIs dont implement driver load */
+		HPI_COMMON(phm, phr);
+		break;
+	case HPI_SUBSYS_DRIVER_UNLOAD:
+		HPI_COMMON(phm, phr);
+		HPIMSGX__cleanup(HPIMSGX_ALLADAPTERS, h_owner);
+		hpios_locked_mem_free_all();
+		hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
+			HPI_SUBSYS_DRIVER_UNLOAD, 0);
+		return;
+
+	case HPI_SUBSYS_GET_INFO:
+		HPI_COMMON(phm, phr);
+		break;
+
+	case HPI_SUBSYS_FIND_ADAPTERS:
+		memcpy(phr, &gRESP_HPI_SUBSYS_FIND_ADAPTERS,
+			sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS));
+		break;
+	case HPI_SUBSYS_GET_NUM_ADAPTERS:
+		memcpy(phr, &gRESP_HPI_SUBSYS_FIND_ADAPTERS,
+			sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS));
+		phr->function = HPI_SUBSYS_GET_NUM_ADAPTERS;
+		break;
+	case HPI_SUBSYS_GET_ADAPTER:
+		{
+			int count = phm->adapter_index;
+			int index = 0;
+			hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
+				HPI_SUBSYS_GET_ADAPTER, 0);
+
+			/* This is complicated by the fact that we want to
+			 * "skip" 0's in the adapter list.
+			 * First, make sure we are pointing to a
+			 * non-zero adapter type.
+			 */
+			while (gRESP_HPI_SUBSYS_FIND_ADAPTERS.
+				s.aw_adapter_list[index] == 0) {
+				index++;
+				if (index >= HPI_MAX_ADAPTERS)
+					break;
+			}
+			while (count) {
+				/* move on to the next adapter */
+				index++;
+				if (index >= HPI_MAX_ADAPTERS)
+					break;
+				while (gRESP_HPI_SUBSYS_FIND_ADAPTERS.
+					s.aw_adapter_list[index] == 0) {
+					index++;
+					if (index >= HPI_MAX_ADAPTERS)
+						break;
+				}
+				count--;
+			}
+
+			if (index < HPI_MAX_ADAPTERS) {
+				phr->u.s.adapter_index = (u16)index;
+				phr->u.s.aw_adapter_list[0] =
+					gRESP_HPI_SUBSYS_FIND_ADAPTERS.
+					s.aw_adapter_list[index];
+			} else {
+				phr->u.s.adapter_index = 0;
+				phr->u.s.aw_adapter_list[0] = 0;
+				phr->error = HPI_ERROR_BAD_ADAPTER_NUMBER;
+			}
+			break;
+		}
+	case HPI_SUBSYS_CREATE_ADAPTER:
+		HPIMSGX__init(phm, phr);
+		break;
+	case HPI_SUBSYS_DELETE_ADAPTER:
+		HPIMSGX__cleanup(phm->adapter_index, h_owner);
+		{
+			struct hpi_message hm;
+			struct hpi_response hr;
+			/* call to HPI_ADAPTER_CLOSE */
+			hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+				HPI_ADAPTER_CLOSE);
+			hm.adapter_index = phm->adapter_index;
+			hw_entry_point(&hm, &hr);
+		}
+		hw_entry_point(phm, phr);
+		gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.
+			aw_adapter_list[phm->adapter_index]
+			= 0;
+		hpi_entry_points[phm->adapter_index] = NULL;
+		break;
+	default:
+		hw_entry_point(phm, phr);
+		break;
+	}
+}
+
+static void adapter_message(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner)
+{
+	switch (phm->function) {
+	case HPI_ADAPTER_OPEN:
+		adapter_open(phm, phr);
+		break;
+	case HPI_ADAPTER_CLOSE:
+		adapter_close(phm, phr);
+		break;
+	default:
+		hw_entry_point(phm, phr);
+		break;
+	}
+}
+
+static void mixer_message(struct hpi_message *phm, struct hpi_response *phr)
+{
+	switch (phm->function) {
+	case HPI_MIXER_OPEN:
+		mixer_open(phm, phr);
+		break;
+	case HPI_MIXER_CLOSE:
+		mixer_close(phm, phr);
+		break;
+	default:
+		hw_entry_point(phm, phr);
+		break;
+	}
+}
+
+static void outstream_message(struct hpi_message *phm,
+	struct hpi_response *phr, void *h_owner)
+{
+	if (phm->obj_index >= aDAPTER_INFO[phm->adapter_index].num_outstreams) {
+		hpi_init_response(phr, HPI_OBJ_OSTREAM, phm->function,
+			HPI_ERROR_INVALID_OBJ_INDEX);
+		return;
+	}
+
+	switch (phm->function) {
+	case HPI_OSTREAM_OPEN:
+		outstream_open(phm, phr, h_owner);
+		break;
+	case HPI_OSTREAM_CLOSE:
+		outstream_close(phm, phr, h_owner);
+		break;
+	default:
+		hw_entry_point(phm, phr);
+		break;
+	}
+}
+
+static void instream_message(struct hpi_message *phm,
+	struct hpi_response *phr, void *h_owner)
+{
+	if (phm->obj_index >= aDAPTER_INFO[phm->adapter_index].num_instreams) {
+		hpi_init_response(phr, HPI_OBJ_ISTREAM, phm->function,
+			HPI_ERROR_INVALID_OBJ_INDEX);
+		return;
+	}
+
+	switch (phm->function) {
+	case HPI_ISTREAM_OPEN:
+		instream_open(phm, phr, h_owner);
+		break;
+	case HPI_ISTREAM_CLOSE:
+		instream_close(phm, phr, h_owner);
+		break;
+	default:
+		hw_entry_point(phm, phr);
+		break;
+	}
+}
+
+/* NOTE: HPI_Message() must be defined in the driver as a wrapper for
+ * HPI_MessageEx so that functions in hpifunc.c compile.
+ */
+void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner)
+{
+	HPI_DEBUG_MESSAGE(DEBUG, phm);
+
+	if (phm->type != HPI_TYPE_MESSAGE) {
+		hpi_init_response(phr, phm->object, phm->function,
+			HPI_ERROR_INVALID_TYPE);
+		return;
+	}
+
+	if (phm->adapter_index >= HPI_MAX_ADAPTERS
+		&& phm->adapter_index != HPIMSGX_ALLADAPTERS) {
+		hpi_init_response(phr, phm->object, phm->function,
+			HPI_ERROR_BAD_ADAPTER_NUMBER);
+		return;
+	}
+
+	switch (phm->object) {
+	case HPI_OBJ_SUBSYSTEM:
+		subsys_message(phm, phr, h_owner);
+		break;
+
+	case HPI_OBJ_ADAPTER:
+		adapter_message(phm, phr, h_owner);
+		break;
+
+	case HPI_OBJ_MIXER:
+		mixer_message(phm, phr);
+		break;
+
+	case HPI_OBJ_OSTREAM:
+		outstream_message(phm, phr, h_owner);
+		break;
+
+	case HPI_OBJ_ISTREAM:
+		instream_message(phm, phr, h_owner);
+		break;
+
+	default:
+		hw_entry_point(phm, phr);
+		break;
+	}
+	HPI_DEBUG_RESPONSE(phr);
+#if 1
+	if (phr->error >= HPI_ERROR_BACKEND_BASE) {
+		void *ep = NULL;
+		char *ep_name;
+
+		HPI_DEBUG_MESSAGE(ERROR, phm);
+
+		if (phm->adapter_index < HPI_MAX_ADAPTERS)
+			ep = hpi_entry_points[phm->adapter_index];
+
+		/* Don't need this? Have adapter index in debug info
+		   Know at driver load time index->backend mapping */
+		if (ep == HPI_6000)
+			ep_name = "HPI_6000";
+		else if (ep == HPI_6205)
+			ep_name = "HPI_6205";
+		else
+			ep_name = "unknown";
+
+		HPI_DEBUG_LOG(ERROR, "HPI %s response - error# %d\n", ep_name,
+			phr->error);
+
+		if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE)
+			hpi_debug_data((u16 *)phm,
+				sizeof(*phm) / sizeof(u16));
+	}
+#endif
+}
+
+static void adapter_open(struct hpi_message *phm, struct hpi_response *phr)
+{
+	HPI_DEBUG_LOG(VERBOSE, "adapter_open\n");
+	memcpy(phr, &rESP_HPI_ADAPTER_OPEN[phm->adapter_index],
+		sizeof(rESP_HPI_ADAPTER_OPEN[0]));
+}
+
+static void adapter_close(struct hpi_message *phm, struct hpi_response *phr)
+{
+	HPI_DEBUG_LOG(VERBOSE, "adapter_close\n");
+	hpi_init_response(phr, HPI_OBJ_ADAPTER, HPI_ADAPTER_CLOSE, 0);
+}
+
+static void mixer_open(struct hpi_message *phm, struct hpi_response *phr)
+{
+	memcpy(phr, &rESP_HPI_MIXER_OPEN[phm->adapter_index],
+		sizeof(rESP_HPI_MIXER_OPEN[0]));
+}
+
+static void mixer_close(struct hpi_message *phm, struct hpi_response *phr)
+{
+	hpi_init_response(phr, HPI_OBJ_MIXER, HPI_MIXER_CLOSE, 0);
+}
+
+static void instream_open(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner)
+{
+
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_response(phr, HPI_OBJ_ISTREAM, HPI_ISTREAM_OPEN, 0);
+
+	hpios_msgxlock_lock(&msgx_lock);
+
+	if (instream_user_open[phm->adapter_index][phm->obj_index].open_flag)
+		phr->error = HPI_ERROR_OBJ_ALREADY_OPEN;
+	else if (rESP_HPI_ISTREAM_OPEN[phm->adapter_index]
+		[phm->obj_index].h.error)
+		memcpy(phr,
+			&rESP_HPI_ISTREAM_OPEN[phm->adapter_index][phm->
+				obj_index],
+			sizeof(rESP_HPI_ISTREAM_OPEN[0][0]));
+	else {
+		instream_user_open[phm->adapter_index][phm->
+			obj_index].open_flag = 1;
+		hpios_msgxlock_un_lock(&msgx_lock);
+
+		/* issue a reset */
+		hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+			HPI_ISTREAM_RESET);
+		hm.adapter_index = phm->adapter_index;
+		hm.obj_index = phm->obj_index;
+		hw_entry_point(&hm, &hr);
+
+		hpios_msgxlock_lock(&msgx_lock);
+		if (hr.error) {
+			instream_user_open[phm->adapter_index][phm->
+				obj_index].open_flag = 0;
+			phr->error = hr.error;
+		} else {
+			instream_user_open[phm->adapter_index][phm->
+				obj_index].open_flag = 1;
+			instream_user_open[phm->adapter_index][phm->
+				obj_index].h_owner = h_owner;
+			memcpy(phr,
+				&rESP_HPI_ISTREAM_OPEN[phm->adapter_index]
+				[phm->obj_index],
+				sizeof(rESP_HPI_ISTREAM_OPEN[0][0]));
+		}
+	}
+	hpios_msgxlock_un_lock(&msgx_lock);
+}
+
+static void instream_close(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner)
+{
+
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_response(phr, HPI_OBJ_ISTREAM, HPI_ISTREAM_CLOSE, 0);
+
+	hpios_msgxlock_lock(&msgx_lock);
+	if (h_owner ==
+		instream_user_open[phm->adapter_index][phm->
+			obj_index].h_owner) {
+		/* HPI_DEBUG_LOG(INFO,"closing adapter %d "
+		   "instream %d owned by %p\n",
+		   phm->wAdapterIndex, phm->wObjIndex, hOwner); */
+		instream_user_open[phm->adapter_index][phm->
+			obj_index].h_owner = NULL;
+		hpios_msgxlock_un_lock(&msgx_lock);
+		/* issue a reset */
+		hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+			HPI_ISTREAM_RESET);
+		hm.adapter_index = phm->adapter_index;
+		hm.obj_index = phm->obj_index;
+		hw_entry_point(&hm, &hr);
+		hpios_msgxlock_lock(&msgx_lock);
+		if (hr.error) {
+			instream_user_open[phm->adapter_index][phm->
+				obj_index].h_owner = h_owner;
+			phr->error = hr.error;
+		} else {
+			instream_user_open[phm->adapter_index][phm->
+				obj_index].open_flag = 0;
+			instream_user_open[phm->adapter_index][phm->
+				obj_index].h_owner = NULL;
+		}
+	} else {
+		HPI_DEBUG_LOG(WARNING,
+			"%p trying to close %d instream %d owned by %p\n",
+			h_owner, phm->adapter_index, phm->obj_index,
+			instream_user_open[phm->adapter_index][phm->
+				obj_index].h_owner);
+		phr->error = HPI_ERROR_OBJ_NOT_OPEN;
+	}
+	hpios_msgxlock_un_lock(&msgx_lock);
+}
+
+static void outstream_open(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner)
+{
+
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_response(phr, HPI_OBJ_OSTREAM, HPI_OSTREAM_OPEN, 0);
+
+	hpios_msgxlock_lock(&msgx_lock);
+
+	if (outstream_user_open[phm->adapter_index][phm->obj_index].open_flag)
+		phr->error = HPI_ERROR_OBJ_ALREADY_OPEN;
+	else if (rESP_HPI_OSTREAM_OPEN[phm->adapter_index]
+		[phm->obj_index].h.error)
+		memcpy(phr,
+			&rESP_HPI_OSTREAM_OPEN[phm->adapter_index][phm->
+				obj_index],
+			sizeof(rESP_HPI_OSTREAM_OPEN[0][0]));
+	else {
+		outstream_user_open[phm->adapter_index][phm->
+			obj_index].open_flag = 1;
+		hpios_msgxlock_un_lock(&msgx_lock);
+
+		/* issue a reset */
+		hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+			HPI_OSTREAM_RESET);
+		hm.adapter_index = phm->adapter_index;
+		hm.obj_index = phm->obj_index;
+		hw_entry_point(&hm, &hr);
+
+		hpios_msgxlock_lock(&msgx_lock);
+		if (hr.error) {
+			outstream_user_open[phm->adapter_index][phm->
+				obj_index].open_flag = 0;
+			phr->error = hr.error;
+		} else {
+			outstream_user_open[phm->adapter_index][phm->
+				obj_index].open_flag = 1;
+			outstream_user_open[phm->adapter_index][phm->
+				obj_index].h_owner = h_owner;
+			memcpy(phr,
+				&rESP_HPI_OSTREAM_OPEN[phm->adapter_index]
+				[phm->obj_index],
+				sizeof(rESP_HPI_OSTREAM_OPEN[0][0]));
+		}
+	}
+	hpios_msgxlock_un_lock(&msgx_lock);
+}
+
+static void outstream_close(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner)
+{
+
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_response(phr, HPI_OBJ_OSTREAM, HPI_OSTREAM_CLOSE, 0);
+
+	hpios_msgxlock_lock(&msgx_lock);
+
+	if (h_owner ==
+		outstream_user_open[phm->adapter_index][phm->
+			obj_index].h_owner) {
+		/* HPI_DEBUG_LOG(INFO,"closing adapter %d "
+		   "outstream %d owned by %p\n",
+		   phm->wAdapterIndex, phm->wObjIndex, hOwner); */
+		outstream_user_open[phm->adapter_index][phm->
+			obj_index].h_owner = NULL;
+		hpios_msgxlock_un_lock(&msgx_lock);
+		/* issue a reset */
+		hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+			HPI_OSTREAM_RESET);
+		hm.adapter_index = phm->adapter_index;
+		hm.obj_index = phm->obj_index;
+		hw_entry_point(&hm, &hr);
+		hpios_msgxlock_lock(&msgx_lock);
+		if (hr.error) {
+			outstream_user_open[phm->adapter_index][phm->
+				obj_index].h_owner = h_owner;
+			phr->error = hr.error;
+		} else {
+			outstream_user_open[phm->adapter_index][phm->
+				obj_index].open_flag = 0;
+			outstream_user_open[phm->adapter_index][phm->
+				obj_index].h_owner = NULL;
+		}
+	} else {
+		HPI_DEBUG_LOG(WARNING,
+			"%p trying to close %d outstream %d owned by %p\n",
+			h_owner, phm->adapter_index, phm->obj_index,
+			outstream_user_open[phm->adapter_index][phm->
+				obj_index].h_owner);
+		phr->error = HPI_ERROR_OBJ_NOT_OPEN;
+	}
+	hpios_msgxlock_un_lock(&msgx_lock);
+}
+
+static u16 adapter_prepare(u16 adapter)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	/* Open the adapter and streams */
+	u16 i;
+
+	/* call to HPI_ADAPTER_OPEN */
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_OPEN);
+	hm.adapter_index = adapter;
+	hw_entry_point(&hm, &hr);
+	memcpy(&rESP_HPI_ADAPTER_OPEN[adapter], &hr,
+		sizeof(rESP_HPI_ADAPTER_OPEN[0]));
+	if (hr.error)
+		return hr.error;
+
+	/* call to HPI_ADAPTER_GET_INFO */
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+		HPI_ADAPTER_GET_INFO);
+	hm.adapter_index = adapter;
+	hw_entry_point(&hm, &hr);
+	if (hr.error)
+		return hr.error;
+
+	aDAPTER_INFO[adapter].num_outstreams = hr.u.a.num_outstreams;
+	aDAPTER_INFO[adapter].num_instreams = hr.u.a.num_instreams;
+	aDAPTER_INFO[adapter].type = hr.u.a.adapter_type;
+
+	gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list[adapter] =
+		hr.u.a.adapter_type;
+	gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters++;
+	if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters > HPI_MAX_ADAPTERS)
+		gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters =
+			HPI_MAX_ADAPTERS;
+
+	/* call to HPI_OSTREAM_OPEN */
+	for (i = 0; i < aDAPTER_INFO[adapter].num_outstreams; i++) {
+		hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
+			HPI_OSTREAM_OPEN);
+		hm.adapter_index = adapter;
+		hm.obj_index = i;
+		hw_entry_point(&hm, &hr);
+		memcpy(&rESP_HPI_OSTREAM_OPEN[adapter][i], &hr,
+			sizeof(rESP_HPI_OSTREAM_OPEN[0][0]));
+		outstream_user_open[adapter][i].open_flag = 0;
+		outstream_user_open[adapter][i].h_owner = NULL;
+	}
+
+	/* call to HPI_ISTREAM_OPEN */
+	for (i = 0; i < aDAPTER_INFO[adapter].num_instreams; i++) {
+		hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
+			HPI_ISTREAM_OPEN);
+		hm.adapter_index = adapter;
+		hm.obj_index = i;
+		hw_entry_point(&hm, &hr);
+		memcpy(&rESP_HPI_ISTREAM_OPEN[adapter][i], &hr,
+			sizeof(rESP_HPI_ISTREAM_OPEN[0][0]));
+		instream_user_open[adapter][i].open_flag = 0;
+		instream_user_open[adapter][i].h_owner = NULL;
+	}
+
+	/* call to HPI_MIXER_OPEN */
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_OPEN);
+	hm.adapter_index = adapter;
+	hw_entry_point(&hm, &hr);
+	memcpy(&rESP_HPI_MIXER_OPEN[adapter], &hr,
+		sizeof(rESP_HPI_MIXER_OPEN[0]));
+
+	return gRESP_HPI_SUBSYS_FIND_ADAPTERS.h.error;
+}
+
+static void HPIMSGX__reset(u16 adapter_index)
+{
+	int i;
+	u16 adapter;
+	struct hpi_response hr;
+
+	if (adapter_index == HPIMSGX_ALLADAPTERS) {
+		/* reset all responses to contain errors */
+		hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM,
+			HPI_SUBSYS_FIND_ADAPTERS, 0);
+		memcpy(&gRESP_HPI_SUBSYS_FIND_ADAPTERS, &hr,
+			sizeof(&gRESP_HPI_SUBSYS_FIND_ADAPTERS));
+
+		for (adapter = 0; adapter < HPI_MAX_ADAPTERS; adapter++) {
+
+			hpi_init_response(&hr, HPI_OBJ_ADAPTER,
+				HPI_ADAPTER_OPEN, HPI_ERROR_BAD_ADAPTER);
+			memcpy(&rESP_HPI_ADAPTER_OPEN[adapter], &hr,
+				sizeof(rESP_HPI_ADAPTER_OPEN[adapter]));
+
+			hpi_init_response(&hr, HPI_OBJ_MIXER, HPI_MIXER_OPEN,
+				HPI_ERROR_INVALID_OBJ);
+			memcpy(&rESP_HPI_MIXER_OPEN[adapter], &hr,
+				sizeof(rESP_HPI_MIXER_OPEN[adapter]));
+
+			for (i = 0; i < HPI_MAX_STREAMS; i++) {
+				hpi_init_response(&hr, HPI_OBJ_OSTREAM,
+					HPI_OSTREAM_OPEN,
+					HPI_ERROR_INVALID_OBJ);
+				memcpy(&rESP_HPI_OSTREAM_OPEN[adapter][i],
+					&hr,
+					sizeof(rESP_HPI_OSTREAM_OPEN[adapter]
+						[i]));
+				hpi_init_response(&hr, HPI_OBJ_ISTREAM,
+					HPI_ISTREAM_OPEN,
+					HPI_ERROR_INVALID_OBJ);
+				memcpy(&rESP_HPI_ISTREAM_OPEN[adapter][i],
+					&hr,
+					sizeof(rESP_HPI_ISTREAM_OPEN[adapter]
+						[i]));
+			}
+		}
+	} else if (adapter_index < HPI_MAX_ADAPTERS) {
+		rESP_HPI_ADAPTER_OPEN[adapter_index].h.error =
+			HPI_ERROR_BAD_ADAPTER;
+		rESP_HPI_MIXER_OPEN[adapter_index].h.error =
+			HPI_ERROR_INVALID_OBJ;
+		for (i = 0; i < HPI_MAX_STREAMS; i++) {
+			rESP_HPI_OSTREAM_OPEN[adapter_index][i].h.error =
+				HPI_ERROR_INVALID_OBJ;
+			rESP_HPI_ISTREAM_OPEN[adapter_index][i].h.error =
+				HPI_ERROR_INVALID_OBJ;
+		}
+		if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.
+			s.aw_adapter_list[adapter_index]) {
+			gRESP_HPI_SUBSYS_FIND_ADAPTERS.
+				s.aw_adapter_list[adapter_index] = 0;
+			gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters--;
+		}
+	}
+}
+
+static u16 HPIMSGX__init(struct hpi_message *phm,
+	/* HPI_SUBSYS_CREATE_ADAPTER structure with */
+	/* resource list or NULL=find all */
+	struct hpi_response *phr
+	/* response from HPI_ADAPTER_GET_INFO */
+	)
+{
+	hpi_handler_func *entry_point_func;
+	struct hpi_response hr;
+
+	if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters >= HPI_MAX_ADAPTERS)
+		return HPI_ERROR_BAD_ADAPTER_NUMBER;
+
+	/* Init response here so we can pass in previous adapter list */
+	hpi_init_response(&hr, phm->object, phm->function,
+		HPI_ERROR_INVALID_OBJ);
+	memcpy(hr.u.s.aw_adapter_list,
+		gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list,
+		sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list));
+
+	entry_point_func =
+		hpi_lookup_entry_point_function(phm->u.s.resource.r.pci);
+
+	if (entry_point_func) {
+		HPI_DEBUG_MESSAGE(DEBUG, phm);
+		entry_point_func(phm, &hr);
+	} else {
+		phr->error = HPI_ERROR_PROCESSING_MESSAGE;
+		return phr->error;
+	}
+	if (hr.error == 0) {
+		/* the adapter was created succesfully
+		   save the mapping for future use */
+		hpi_entry_points[hr.u.s.adapter_index] = entry_point_func;
+		/* prepare adapter (pre-open streams etc.) */
+		HPI_DEBUG_LOG(DEBUG,
+			"HPI_SUBSYS_CREATE_ADAPTER successful,"
+			" preparing adapter\n");
+		adapter_prepare(hr.u.s.adapter_index);
+	}
+	memcpy(phr, &hr, hr.size);
+	return phr->error;
+}
+
+static void HPIMSGX__cleanup(u16 adapter_index, void *h_owner)
+{
+	int i, adapter, adapter_limit;
+
+	if (!h_owner)
+		return;
+
+	if (adapter_index == HPIMSGX_ALLADAPTERS) {
+		adapter = 0;
+		adapter_limit = HPI_MAX_ADAPTERS;
+	} else {
+		adapter = adapter_index;
+		adapter_limit = adapter + 1;
+	}
+
+	for (; adapter < adapter_limit; adapter++) {
+		/*      printk(KERN_INFO "Cleanup adapter #%d\n",wAdapter); */
+		for (i = 0; i < HPI_MAX_STREAMS; i++) {
+			if (h_owner ==
+				outstream_user_open[adapter][i].h_owner) {
+				struct hpi_message hm;
+				struct hpi_response hr;
+
+				HPI_DEBUG_LOG(DEBUG,
+					"close adapter %d ostream %d\n",
+					adapter, i);
+
+				hpi_init_message_response(&hm, &hr,
+					HPI_OBJ_OSTREAM, HPI_OSTREAM_RESET);
+				hm.adapter_index = (u16)adapter;
+				hm.obj_index = (u16)i;
+				hw_entry_point(&hm, &hr);
+
+				hm.function = HPI_OSTREAM_HOSTBUFFER_FREE;
+				hw_entry_point(&hm, &hr);
+
+				hm.function = HPI_OSTREAM_GROUP_RESET;
+				hw_entry_point(&hm, &hr);
+
+				outstream_user_open[adapter][i].open_flag = 0;
+				outstream_user_open[adapter][i].h_owner =
+					NULL;
+			}
+			if (h_owner == instream_user_open[adapter][i].h_owner) {
+				struct hpi_message hm;
+				struct hpi_response hr;
+
+				HPI_DEBUG_LOG(DEBUG,
+					"close adapter %d istream %d\n",
+					adapter, i);
+
+				hpi_init_message_response(&hm, &hr,
+					HPI_OBJ_ISTREAM, HPI_ISTREAM_RESET);
+				hm.adapter_index = (u16)adapter;
+				hm.obj_index = (u16)i;
+				hw_entry_point(&hm, &hr);
+
+				hm.function = HPI_ISTREAM_HOSTBUFFER_FREE;
+				hw_entry_point(&hm, &hr);
+
+				hm.function = HPI_ISTREAM_GROUP_RESET;
+				hw_entry_point(&hm, &hr);
+
+				instream_user_open[adapter][i].open_flag = 0;
+				instream_user_open[adapter][i].h_owner = NULL;
+			}
+		}
+	}
+}

+ 36 - 0
sound/pci/asihpi/hpimsgx.h

@@ -0,0 +1,36 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+ HPI Extended Message Handler Functions
+
+(C) Copyright AudioScience Inc. 1997-2003
+******************************************************************************/
+
+#ifndef _HPIMSGX_H_
+#define _HPIMSGX_H_
+
+#include "hpi_internal.h"
+
+#define HPIMSGX_ALLADAPTERS     (0xFFFF)
+
+void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
+	void *h_owner);
+
+#define HPI_MESSAGE_LOWER_LAYER hpi_send_recv_ex
+
+#endif				/* _HPIMSGX_H_ */

+ 484 - 0
sound/pci/asihpi/hpioctl.c

@@ -0,0 +1,484 @@
+/*******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+Common Linux HPI ioctl and module probe/remove functions
+*******************************************************************************/
+#define SOURCEFILE_NAME "hpioctl.c"
+
+#include "hpi_internal.h"
+#include "hpimsginit.h"
+#include "hpidebug.h"
+#include "hpimsgx.h"
+#include "hpioctl.h"
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <asm/uaccess.h>
+#include <linux/stringify.h>
+
+#ifdef MODULE_FIRMWARE
+MODULE_FIRMWARE("asihpi/dsp5000.bin");
+MODULE_FIRMWARE("asihpi/dsp6200.bin");
+MODULE_FIRMWARE("asihpi/dsp6205.bin");
+MODULE_FIRMWARE("asihpi/dsp6400.bin");
+MODULE_FIRMWARE("asihpi/dsp6600.bin");
+MODULE_FIRMWARE("asihpi/dsp8700.bin");
+MODULE_FIRMWARE("asihpi/dsp8900.bin");
+#endif
+
+static int prealloc_stream_buf;
+module_param(prealloc_stream_buf, int, S_IRUGO);
+MODULE_PARM_DESC(prealloc_stream_buf,
+	"preallocate size for per-adapter stream buffer");
+
+/* Allow the debug level to be changed after module load.
+ E.g.   echo 2 > /sys/module/asihpi/parameters/hpiDebugLevel
+*/
+module_param(hpi_debug_level, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(hpi_debug_level, "debug verbosity 0..5");
+
+/* List of adapters found */
+static struct hpi_adapter adapters[HPI_MAX_ADAPTERS];
+
+/* Wrapper function to HPI_Message to enable dumping of the
+   message and response types.
+*/
+static void hpi_send_recv_f(struct hpi_message *phm, struct hpi_response *phr,
+	struct file *file)
+{
+	int adapter = phm->adapter_index;
+
+	if ((adapter >= HPI_MAX_ADAPTERS || adapter < 0)
+		&& (phm->object != HPI_OBJ_SUBSYSTEM))
+		phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
+	else
+		hpi_send_recv_ex(phm, phr, file);
+}
+
+/* This is called from hpifunc.c functions, called by ALSA
+ * (or other kernel process) In this case there is no file descriptor
+ * available for the message cache code
+ */
+void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr)
+{
+	hpi_send_recv_f(phm, phr, HOWNER_KERNEL);
+}
+
+EXPORT_SYMBOL(hpi_send_recv);
+/* for radio-asihpi */
+
+int asihpi_hpi_release(struct file *file)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+/* HPI_DEBUG_LOG(INFO,"hpi_release file %p, pid %d\n", file, current->pid); */
+	/* close the subsystem just in case the application forgot to. */
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_CLOSE);
+	hpi_send_recv_ex(&hm, &hr, file);
+	return 0;
+}
+
+long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct hpi_ioctl_linux __user *phpi_ioctl_data;
+	void __user *puhm;
+	void __user *puhr;
+	union hpi_message_buffer_v1 *hm;
+	union hpi_response_buffer_v1 *hr;
+	u16 res_max_size;
+	u32 uncopied_bytes;
+	struct hpi_adapter *pa = NULL;
+	int err = 0;
+
+	if (cmd != HPI_IOCTL_LINUX)
+		return -EINVAL;
+
+	hm = kmalloc(sizeof(*hm), GFP_KERNEL);
+	hr = kmalloc(sizeof(*hr), GFP_KERNEL);
+	if (!hm || !hr) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg;
+
+	/* Read the message and response pointers from user space.  */
+	get_user(puhm, &phpi_ioctl_data->phm);
+	get_user(puhr, &phpi_ioctl_data->phr);
+
+	/* Now read the message size and data from user space.  */
+	get_user(hm->h.size, (u16 __user *)puhm);
+	if (hm->h.size > sizeof(*hm))
+		hm->h.size = sizeof(*hm);
+
+	/*printk(KERN_INFO "message size %d\n", hm->h.wSize); */
+
+	uncopied_bytes = copy_from_user(hm, puhm, hm->h.size);
+	if (uncopied_bytes) {
+		HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes);
+		err = -EFAULT;
+		goto out;
+	}
+
+	get_user(res_max_size, (u16 __user *)puhr);
+	/* printk(KERN_INFO "user response size %d\n", res_max_size); */
+	if (res_max_size < sizeof(struct hpi_response_header)) {
+		HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size);
+		err = -EFAULT;
+		goto out;
+	}
+
+	pa = &adapters[hm->h.adapter_index];
+	hr->h.size = 0;
+	if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
+		switch (hm->h.function) {
+		case HPI_SUBSYS_CREATE_ADAPTER:
+		case HPI_SUBSYS_DELETE_ADAPTER:
+			/* Application must not use these functions! */
+			hr->h.size = sizeof(hr->h);
+			hr->h.error = HPI_ERROR_INVALID_OPERATION;
+			hr->h.function = hm->h.function;
+			uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
+			if (uncopied_bytes)
+				err = -EFAULT;
+			else
+				err = 0;
+			goto out;
+
+		default:
+			hpi_send_recv_f(&hm->m0, &hr->r0, file);
+		}
+	} else {
+		u16 __user *ptr = NULL;
+		u32 size = 0;
+
+		/* -1=no data 0=read from user mem, 1=write to user mem */
+		int wrflag = -1;
+		u32 adapter = hm->h.adapter_index;
+
+		if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) {
+			hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
+				HPI_ADAPTER_OPEN,
+				HPI_ERROR_BAD_ADAPTER_NUMBER);
+
+			uncopied_bytes =
+				copy_to_user(puhr, hr, sizeof(hr->h));
+			if (uncopied_bytes)
+				err = -EFAULT;
+			else
+				err = 0;
+			goto out;
+		}
+
+		if (mutex_lock_interruptible(&adapters[adapter].mutex)) {
+			err = -EINTR;
+			goto out;
+		}
+
+		/* Dig out any pointers embedded in the message.  */
+		switch (hm->h.function) {
+		case HPI_OSTREAM_WRITE:
+		case HPI_ISTREAM_READ:{
+				/* Yes, sparse, this is correct. */
+				ptr = (u16 __user *)hm->m0.u.d.u.data.pb_data;
+				size = hm->m0.u.d.u.data.data_size;
+
+				/* Allocate buffer according to application request.
+				   ?Is it better to alloc/free for the duration
+				   of the transaction?
+				 */
+				if (pa->buffer_size < size) {
+					HPI_DEBUG_LOG(DEBUG,
+						"realloc adapter %d stream "
+						"buffer from %zd to %d\n",
+						hm->h.adapter_index,
+						pa->buffer_size, size);
+					if (pa->p_buffer) {
+						pa->buffer_size = 0;
+						vfree(pa->p_buffer);
+					}
+					pa->p_buffer = vmalloc(size);
+					if (pa->p_buffer)
+						pa->buffer_size = size;
+					else {
+						HPI_DEBUG_LOG(ERROR,
+							"HPI could not allocate "
+							"stream buffer size %d\n",
+							size);
+
+						mutex_unlock(&adapters
+							[adapter].mutex);
+						err = -EINVAL;
+						goto out;
+					}
+				}
+
+				hm->m0.u.d.u.data.pb_data = pa->p_buffer;
+				if (hm->h.function == HPI_ISTREAM_READ)
+					/* from card, WRITE to user mem */
+					wrflag = 1;
+				else
+					wrflag = 0;
+				break;
+			}
+
+		default:
+			size = 0;
+			break;
+		}
+
+		if (size && (wrflag == 0)) {
+			uncopied_bytes =
+				copy_from_user(pa->p_buffer, ptr, size);
+			if (uncopied_bytes)
+				HPI_DEBUG_LOG(WARNING,
+					"missed %d of %d "
+					"bytes from user\n", uncopied_bytes,
+					size);
+		}
+
+		hpi_send_recv_f(&hm->m0, &hr->r0, file);
+
+		if (size && (wrflag == 1)) {
+			uncopied_bytes =
+				copy_to_user(ptr, pa->p_buffer, size);
+			if (uncopied_bytes)
+				HPI_DEBUG_LOG(WARNING,
+					"missed %d of %d " "bytes to user\n",
+					uncopied_bytes, size);
+		}
+
+		mutex_unlock(&adapters[adapter].mutex);
+	}
+
+	/* on return response size must be set */
+	/*printk(KERN_INFO "response size %d\n", hr->h.wSize); */
+
+	if (!hr->h.size) {
+		HPI_DEBUG_LOG(ERROR, "response zero size\n");
+		err = -EFAULT;
+		goto out;
+	}
+
+	if (hr->h.size > res_max_size) {
+		HPI_DEBUG_LOG(ERROR, "response too big %d %d\n", hr->h.size,
+			res_max_size);
+		/*HPI_DEBUG_MESSAGE(ERROR, hm); */
+		err = -EFAULT;
+		goto out;
+	}
+
+	uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
+	if (uncopied_bytes) {
+		HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes);
+		err = -EFAULT;
+		goto out;
+	}
+
+out:
+	kfree(hm);
+	kfree(hr);
+	return err;
+}
+
+int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
+	const struct pci_device_id *pci_id)
+{
+	int err, idx, nm;
+	unsigned int memlen;
+	struct hpi_message hm;
+	struct hpi_response hr;
+	struct hpi_adapter adapter;
+	struct hpi_pci pci;
+
+	memset(&adapter, 0, sizeof(adapter));
+
+	printk(KERN_DEBUG "probe PCI device (%04x:%04x,%04x:%04x,%04x)\n",
+		pci_dev->vendor, pci_dev->device, pci_dev->subsystem_vendor,
+		pci_dev->subsystem_device, pci_dev->devfn);
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_CREATE_ADAPTER);
+	hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER,
+		HPI_ERROR_PROCESSING_MESSAGE);
+
+	hm.adapter_index = -1;	/* an invalid index */
+
+	/* fill in HPI_PCI information from kernel provided information */
+	adapter.pci = pci_dev;
+
+	nm = HPI_MAX_ADAPTER_MEM_SPACES;
+
+	for (idx = 0; idx < nm; idx++) {
+		HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n",
+			idx, pci_dev->resource[idx].name,
+			(unsigned long long)pci_resource_start(pci_dev, idx),
+			(unsigned long long)pci_resource_end(pci_dev, idx),
+			(unsigned long long)pci_resource_flags(pci_dev, idx));
+
+		if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
+			memlen = pci_resource_len(pci_dev, idx);
+			adapter.ap_remapped_mem_base[idx] =
+				ioremap(pci_resource_start(pci_dev, idx),
+				memlen);
+			if (!adapter.ap_remapped_mem_base[idx]) {
+				HPI_DEBUG_LOG(ERROR,
+					"ioremap failed, aborting\n");
+				/* unmap previously mapped pci mem space */
+				goto err;
+			}
+		}
+
+		pci.ap_mem_base[idx] = adapter.ap_remapped_mem_base[idx];
+	}
+
+	/* could replace Pci with direct pointer to pci_dev for linux
+	   Instead wrap accessor functions for IDs etc.
+	   Would it work for windows?
+	 */
+	pci.bus_number = pci_dev->bus->number;
+	pci.vendor_id = (u16)pci_dev->vendor;
+	pci.device_id = (u16)pci_dev->device;
+	pci.subsys_vendor_id = (u16)(pci_dev->subsystem_vendor & 0xffff);
+	pci.subsys_device_id = (u16)(pci_dev->subsystem_device & 0xffff);
+	pci.device_number = pci_dev->devfn;
+	pci.interrupt = pci_dev->irq;
+	pci.p_os_data = pci_dev;
+
+	hm.u.s.resource.bus_type = HPI_BUS_PCI;
+	hm.u.s.resource.r.pci = &pci;
+
+	/* call CreateAdapterObject on the relevant hpi module */
+	hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+	if (hr.error)
+		goto err;
+
+	if (prealloc_stream_buf) {
+		adapter.p_buffer = vmalloc(prealloc_stream_buf);
+		if (!adapter.p_buffer) {
+			HPI_DEBUG_LOG(ERROR,
+				"HPI could not allocate "
+				"kernel buffer size %d\n",
+				prealloc_stream_buf);
+			goto err;
+		}
+	}
+
+	adapter.index = hr.u.s.adapter_index;
+	adapter.type = hr.u.s.aw_adapter_list[adapter.index];
+	hm.adapter_index = adapter.index;
+
+	err = hpi_adapter_open(NULL, adapter.index);
+	if (err)
+		goto err;
+
+	adapter.snd_card_asihpi = NULL;
+	/* WARNING can't init mutex in 'adapter'
+	 * and then copy it to adapters[] ?!?!
+	 */
+	adapters[hr.u.s.adapter_index] = adapter;
+	mutex_init(&adapters[adapter.index].mutex);
+	pci_set_drvdata(pci_dev, &adapters[adapter.index]);
+
+	printk(KERN_INFO "probe found adapter ASI%04X HPI index #%d.\n",
+		adapter.type, adapter.index);
+
+	return 0;
+
+err:
+	for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
+		if (adapter.ap_remapped_mem_base[idx]) {
+			iounmap(adapter.ap_remapped_mem_base[idx]);
+			adapter.ap_remapped_mem_base[idx] = NULL;
+		}
+	}
+
+	if (adapter.p_buffer) {
+		adapter.buffer_size = 0;
+		vfree(adapter.p_buffer);
+	}
+
+	HPI_DEBUG_LOG(ERROR, "adapter_probe failed\n");
+	return -ENODEV;
+}
+
+void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
+{
+	int idx;
+	struct hpi_message hm;
+	struct hpi_response hr;
+	struct hpi_adapter *pa;
+	pa = (struct hpi_adapter *)pci_get_drvdata(pci_dev);
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_DELETE_ADAPTER);
+	hm.adapter_index = pa->index;
+	hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+
+	/* unmap PCI memory space, mapped during device init. */
+	for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
+		if (pa->ap_remapped_mem_base[idx]) {
+			iounmap(pa->ap_remapped_mem_base[idx]);
+			pa->ap_remapped_mem_base[idx] = NULL;
+		}
+	}
+
+	if (pa->p_buffer) {
+		pa->buffer_size = 0;
+		vfree(pa->p_buffer);
+	}
+
+	pci_set_drvdata(pci_dev, NULL);
+	/*
+	   printk(KERN_INFO "PCI device (%04x:%04x,%04x:%04x,%04x),"
+	   " HPI index # %d, removed.\n",
+	   pci_dev->vendor, pci_dev->device,
+	   pci_dev->subsystem_vendor,
+	   pci_dev->subsystem_device, pci_dev->devfn,
+	   pa->index);
+	 */
+}
+
+void __init asihpi_init(void)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	memset(adapters, 0, sizeof(adapters));
+
+	printk(KERN_INFO "ASIHPI driver %d.%02d.%02d\n",
+		HPI_VER_MAJOR(HPI_VER), HPI_VER_MINOR(HPI_VER),
+		HPI_VER_RELEASE(HPI_VER));
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_DRIVER_LOAD);
+	hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+}
+
+void asihpi_exit(void)
+{
+	struct hpi_message hm;
+	struct hpi_response hr;
+
+	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
+		HPI_SUBSYS_DRIVER_UNLOAD);
+	hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+}

+ 38 - 0
sound/pci/asihpi/hpioctl.h

@@ -0,0 +1,38 @@
+/*******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+Linux HPI ioctl, and shared module init functions
+*******************************************************************************/
+
+int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
+	const struct pci_device_id *pci_id);
+void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev);
+void __init asihpi_init(void);
+void __exit asihpi_exit(void);
+
+int asihpi_hpi_release(struct file *file);
+
+long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+
+/* This is called from hpifunc.c functions, called by ALSA
+ * (or other kernel process) In this case there is no file descriptor
+ * available for the message cache code
+ */
+void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr);
+
+#define HOWNER_KERNEL ((void *)-1)

+ 114 - 0
sound/pci/asihpi/hpios.c

@@ -0,0 +1,114 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+HPI Operating System function implementation for Linux
+
+(C) Copyright AudioScience Inc. 1997-2003
+******************************************************************************/
+#define SOURCEFILE_NAME "hpios.c"
+#include "hpi_internal.h"
+#include "hpidebug.h"
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+void hpios_delay_micro_seconds(u32 num_micro_sec)
+{
+	if ((usecs_to_jiffies(num_micro_sec) > 1) && !in_interrupt()) {
+		/* MUST NOT SCHEDULE IN INTERRUPT CONTEXT! */
+		schedule_timeout_uninterruptible(usecs_to_jiffies
+			(num_micro_sec));
+	} else if (num_micro_sec <= 2000)
+		udelay(num_micro_sec);
+	else
+		mdelay(num_micro_sec / 1000);
+
+}
+
+void hpios_locked_mem_init(void)
+{
+}
+
+/** Allocated an area of locked memory for bus master DMA operations.
+
+On error, return -ENOMEM, and *pMemArea.size = 0
+*/
+u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size,
+	struct pci_dev *pdev)
+{
+	/*?? any benefit in using managed dmam_alloc_coherent? */
+	p_mem_area->vaddr =
+		dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle,
+		GFP_DMA32 | GFP_KERNEL);
+
+	if (p_mem_area->vaddr) {
+		HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n",
+			size, (unsigned int)p_mem_area->dma_handle,
+			p_mem_area->vaddr);
+		p_mem_area->pdev = &pdev->dev;
+		p_mem_area->size = size;
+		return 0;
+	} else {
+		HPI_DEBUG_LOG(WARNING,
+			"failed to allocate %d bytes locked memory\n", size);
+		p_mem_area->size = 0;
+		return -ENOMEM;
+	}
+}
+
+u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area)
+{
+	if (p_mem_area->size) {
+		dma_free_coherent(p_mem_area->pdev, p_mem_area->size,
+			p_mem_area->vaddr, p_mem_area->dma_handle);
+		HPI_DEBUG_LOG(DEBUG, "freed %lu bytes, dma 0x%x vma %p\n",
+			(unsigned long)p_mem_area->size,
+			(unsigned int)p_mem_area->dma_handle,
+			p_mem_area->vaddr);
+		p_mem_area->size = 0;
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+void hpios_locked_mem_free_all(void)
+{
+}
+
+void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx,
+	unsigned int length)
+{
+	HPI_DEBUG_LOG(DEBUG, "mapping %d %s %08llx-%08llx %04llx len 0x%x\n",
+		idx, pci_dev->resource[idx].name,
+		(unsigned long long)pci_resource_start(pci_dev, idx),
+		(unsigned long long)pci_resource_end(pci_dev, idx),
+		(unsigned long long)pci_resource_flags(pci_dev, idx), length);
+
+	if (!(pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM)) {
+		HPI_DEBUG_LOG(ERROR, "not an io memory resource\n");
+		return NULL;
+	}
+
+	if (length > pci_resource_len(pci_dev, idx)) {
+		HPI_DEBUG_LOG(ERROR, "resource too small for requested %d \n",
+			length);
+		return NULL;
+	}
+
+	return ioremap(pci_resource_start(pci_dev, idx), length);
+}

+ 178 - 0
sound/pci/asihpi/hpios.h

@@ -0,0 +1,178 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+HPI Operating System Specific macros for Linux Kernel driver
+
+(C) Copyright AudioScience Inc. 1997-2003
+******************************************************************************/
+#ifndef _HPIOS_H_
+#define _HPIOS_H_
+
+#undef HPI_OS_LINUX_KERNEL
+#define HPI_OS_LINUX_KERNEL
+
+#define HPI_OS_DEFINED
+#define HPI_KERNEL_MODE
+
+#define HPI_REASSIGN_DUPLICATE_ADAPTER_IDX
+
+#include <linux/io.h>
+#include <asm/system.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+
+#define HPI_NO_OS_FILE_OPS
+
+#ifdef CONFIG_64BIT
+#define HPI64BIT
+#endif
+
+/** Details of a memory area allocated with  pci_alloc_consistent
+Need all info for parameters to pci_free_consistent
+*/
+struct consistent_dma_area {
+	struct device *pdev;
+	/* looks like dma-mapping dma_devres ?! */
+	size_t size;
+	void *vaddr;
+	dma_addr_t dma_handle;
+};
+
+static inline u16 hpios_locked_mem_get_phys_addr(struct consistent_dma_area
+	*locked_mem_handle, u32 *p_physical_addr)
+{
+	*p_physical_addr = locked_mem_handle->dma_handle;
+	return 0;
+}
+
+static inline u16 hpios_locked_mem_get_virt_addr(struct consistent_dma_area
+	*locked_mem_handle, void **pp_virtual_addr)
+{
+	*pp_virtual_addr = locked_mem_handle->vaddr;
+	return 0;
+}
+
+static inline u16 hpios_locked_mem_valid(struct consistent_dma_area
+	*locked_mem_handle)
+{
+	return locked_mem_handle->size != 0;
+}
+
+struct hpi_ioctl_linux {
+	void __user *phm;
+	void __user *phr;
+};
+
+/* Conflict?: H is already used by a number of drivers hid, bluetooth hci,
+   and some sound drivers sb16, hdsp, emu10k. AFAIK 0xFC is ununsed command
+*/
+#define HPI_IOCTL_LINUX _IOWR('H', 0xFC, struct hpi_ioctl_linux)
+
+#define HPI_DEBUG_FLAG_ERROR   KERN_ERR
+#define HPI_DEBUG_FLAG_WARNING KERN_WARNING
+#define HPI_DEBUG_FLAG_NOTICE  KERN_NOTICE
+#define HPI_DEBUG_FLAG_INFO    KERN_INFO
+#define HPI_DEBUG_FLAG_DEBUG   KERN_DEBUG
+#define HPI_DEBUG_FLAG_VERBOSE KERN_DEBUG	/* kernel has no verbose */
+
+#include <linux/spinlock.h>
+
+#define HPI_LOCKING
+
+struct hpios_spinlock {
+	spinlock_t lock;	/* SEE hpios_spinlock */
+	int lock_context;
+};
+
+/* The reason for all this evilness is that ALSA calls some of a drivers
+ * operators in atomic context, and some not.  But all our functions channel
+ * through the HPI_Message conduit, so we can't handle the different context
+ * per function
+ */
+#define IN_LOCK_BH 1
+#define IN_LOCK_IRQ 0
+static inline void cond_lock(struct hpios_spinlock *l)
+{
+	if (irqs_disabled()) {
+		/* NO bh or isr can execute on this processor,
+		   so ordinary lock will do
+		 */
+		spin_lock(&((l)->lock));
+		l->lock_context = IN_LOCK_IRQ;
+	} else {
+		spin_lock_bh(&((l)->lock));
+		l->lock_context = IN_LOCK_BH;
+	}
+}
+
+static inline void cond_unlock(struct hpios_spinlock *l)
+{
+	if (l->lock_context == IN_LOCK_BH)
+		spin_unlock_bh(&((l)->lock));
+	else
+		spin_unlock(&((l)->lock));
+}
+
+#define hpios_msgxlock_init(obj)      spin_lock_init(&(obj)->lock)
+#define hpios_msgxlock_lock(obj)   cond_lock(obj)
+#define hpios_msgxlock_un_lock(obj) cond_unlock(obj)
+
+#define hpios_dsplock_init(obj)       spin_lock_init(&(obj)->dsp_lock.lock)
+#define hpios_dsplock_lock(obj)    cond_lock(&(obj)->dsp_lock)
+#define hpios_dsplock_unlock(obj)  cond_unlock(&(obj)->dsp_lock)
+
+#ifdef CONFIG_SND_DEBUG
+#define HPI_DEBUG
+#endif
+
+#define HPI_ALIST_LOCKING
+#define hpios_alistlock_init(obj)    spin_lock_init(&((obj)->list_lock.lock))
+#define hpios_alistlock_lock(obj) spin_lock(&((obj)->list_lock.lock))
+#define hpios_alistlock_un_lock(obj) spin_unlock(&((obj)->list_lock.lock))
+
+struct hpi_adapter {
+	/* mutex prevents contention for one card
+	   between multiple user programs (via ioctl) */
+	struct mutex mutex;
+	u16 index;
+	u16 type;
+
+	/* ALSA card structure */
+	void *snd_card_asihpi;
+
+	char *p_buffer;
+	size_t buffer_size;
+	struct pci_dev *pci;
+	void __iomem *ap_remapped_mem_base[HPI_MAX_ADAPTER_MEM_SPACES];
+};
+
+static inline void hpios_unmap_io(void __iomem *addr,
+	unsigned long size)
+{
+	iounmap(addr);
+}
+
+void __iomem *hpios_map_io(struct pci_dev *pci_dev, int idx,
+	unsigned int length);
+
+#endif

+ 37 - 0
sound/pci/asihpi/hpipcida.h

@@ -0,0 +1,37 @@
+/******************************************************************************
+
+    AudioScience HPI driver
+    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of version 2 of the GNU General Public License as
+    published by the Free Software Foundation;
+
+    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
+
+ Array initializer for PCI card IDs
+
+(C) Copyright AudioScience Inc. 1998-2003
+*******************************************************************************/
+
+/*NOTE: when adding new lines to this header file
+  they MUST be grouped by HPI entry point.
+*/
+
+{
+HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
+		HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
+		(kernel_ulong_t) HPI_6205}
+, {
+HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
+		HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
+		(kernel_ulong_t) HPI_6000}
+, {
+0}

+ 14 - 26
sound/pci/cs4281.c

@@ -1139,40 +1139,28 @@ static void snd_cs4281_proc_read(struct snd_info_entry *entry,
 	snd_iprintf(buffer, "Spurious end IRQs    : %u\n", chip->spurious_dtc_irq);
 	snd_iprintf(buffer, "Spurious end IRQs    : %u\n", chip->spurious_dtc_irq);
 }
 }
 
 
-static long snd_cs4281_BA0_read(struct snd_info_entry *entry,
-				void *file_private_data,
-				struct file *file, char __user *buf,
-				unsigned long count, unsigned long pos)
+static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry,
+				   void *file_private_data,
+				   struct file *file, char __user *buf,
+				   size_t count, loff_t pos)
 {
 {
-	long size;
 	struct cs4281 *chip = entry->private_data;
 	struct cs4281 *chip = entry->private_data;
 	
 	
-	size = count;
-	if (pos + size > CS4281_BA0_SIZE)
-		size = (long)CS4281_BA0_SIZE - pos;
-	if (size > 0) {
-		if (copy_to_user_fromio(buf, chip->ba0 + pos, size))
-			return -EFAULT;
-	}
-	return size;
+	if (copy_to_user_fromio(buf, chip->ba0 + pos, count))
+		return -EFAULT;
+	return count;
 }
 }
 
 
-static long snd_cs4281_BA1_read(struct snd_info_entry *entry,
-				void *file_private_data,
-				struct file *file, char __user *buf,
-				unsigned long count, unsigned long pos)
+static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry,
+				   void *file_private_data,
+				   struct file *file, char __user *buf,
+				   size_t count, loff_t pos)
 {
 {
-	long size;
 	struct cs4281 *chip = entry->private_data;
 	struct cs4281 *chip = entry->private_data;
 	
 	
-	size = count;
-	if (pos + size > CS4281_BA1_SIZE)
-		size = (long)CS4281_BA1_SIZE - pos;
-	if (size > 0) {
-		if (copy_to_user_fromio(buf, chip->ba1 + pos, size))
-			return -EFAULT;
-	}
-	return size;
+	if (copy_to_user_fromio(buf, chip->ba1 + pos, count))
+		return -EFAULT;
+	return count;
 }
 }
 
 
 static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = {
 static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = {

+ 7 - 12
sound/pci/cs46xx/cs46xx_lib.c

@@ -2657,21 +2657,16 @@ static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) { }
  *  proc interface
  *  proc interface
  */
  */
 
 
-static long snd_cs46xx_io_read(struct snd_info_entry *entry, void *file_private_data,
-			       struct file *file, char __user *buf,
-			       unsigned long count, unsigned long pos)
+static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry,
+				  void *file_private_data,
+				  struct file *file, char __user *buf,
+				  size_t count, loff_t pos)
 {
 {
-	long size;
 	struct snd_cs46xx_region *region = entry->private_data;
 	struct snd_cs46xx_region *region = entry->private_data;
 	
 	
-	size = count;
-	if (pos + (size_t)size > region->size)
-		size = region->size - pos;
-	if (size > 0) {
-		if (copy_to_user_fromio(buf, region->remap_addr + pos, size))
-			return -EFAULT;
-	}
-	return size;
+	if (copy_to_user_fromio(buf, region->remap_addr + pos, count))
+		return -EFAULT;
+	return count;
 }
 }
 
 
 static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = {
 static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = {

+ 24 - 27
sound/pci/emu10k1/emuproc.c

@@ -341,15 +341,17 @@ static void snd_emu10k1_proc_acode_read(struct snd_info_entry *entry,
 #define TOTAL_SIZE_CODE		(0x200*8)
 #define TOTAL_SIZE_CODE		(0x200*8)
 #define A_TOTAL_SIZE_CODE	(0x400*8)
 #define A_TOTAL_SIZE_CODE	(0x400*8)
 
 
-static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
-				    void *file_private_data,
-				    struct file *file, char __user *buf,
-				    unsigned long count, unsigned long pos)
+static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
+				       void *file_private_data,
+				       struct file *file, char __user *buf,
+				       size_t count, loff_t pos)
 {
 {
-	long size;
 	struct snd_emu10k1 *emu = entry->private_data;
 	struct snd_emu10k1 *emu = entry->private_data;
 	unsigned int offset;
 	unsigned int offset;
 	int tram_addr = 0;
 	int tram_addr = 0;
+	unsigned int *tmp;
+	long res;
+	unsigned int idx;
 	
 	
 	if (!strcmp(entry->name, "fx8010_tram_addr")) {
 	if (!strcmp(entry->name, "fx8010_tram_addr")) {
 		offset = TANKMEMADDRREGBASE;
 		offset = TANKMEMADDRREGBASE;
@@ -361,30 +363,25 @@ static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
 	} else {
 	} else {
 		offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE;
 		offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE;
 	}
 	}
-	size = count;
-	if (pos + size > entry->size)
-		size = (long)entry->size - pos;
-	if (size > 0) {
-		unsigned int *tmp;
-		long res;
-		unsigned int idx;
-		if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL)
-			return -ENOMEM;
-		for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++)
-			if (tram_addr && emu->audigy) {
-				tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0) >> 11;
-				tmp[idx] |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
-			} else 
-				tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
-		if (copy_to_user(buf, ((char *)tmp) + (pos & 3), size))
-			res = -EFAULT;
-		else {
-			res = size;
+
+	tmp = kmalloc(count + 8, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+	for (idx = 0; idx < ((pos & 3) + count + 3) >> 2; idx++) {
+		unsigned int val;
+		val = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
+		if (tram_addr && emu->audigy) {
+			val >>= 11;
+			val |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
 		}
 		}
-		kfree(tmp);
-		return res;
+		tmp[idx] = val;
 	}
 	}
-	return 0;
+	if (copy_to_user(buf, ((char *)tmp) + (pos & 3), count))
+		res = -EFAULT;
+	else
+		res = count;
+	kfree(tmp);
+	return res;
 }
 }
 
 
 static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, 
 static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, 

+ 119 - 10
sound/pci/es1968.c

@@ -104,6 +104,7 @@
 #include <linux/gameport.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
+#include <linux/input.h>
 
 
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
@@ -517,14 +518,9 @@ struct es1968 {
 
 
 	/* ALSA Stuff */
 	/* ALSA Stuff */
 	struct snd_ac97 *ac97;
 	struct snd_ac97 *ac97;
-	struct snd_kcontrol *master_switch; /* for h/w volume control */
-	struct snd_kcontrol *master_volume;
-
 	struct snd_rawmidi *rmidi;
 	struct snd_rawmidi *rmidi;
 
 
 	spinlock_t reg_lock;
 	spinlock_t reg_lock;
-	spinlock_t ac97_lock;
-	struct tasklet_struct hwvol_tq;
 	unsigned int in_suspend;
 	unsigned int in_suspend;
 
 
 	/* Maestro Stuff */
 	/* Maestro Stuff */
@@ -547,6 +543,16 @@ struct es1968 {
 #ifdef SUPPORT_JOYSTICK
 #ifdef SUPPORT_JOYSTICK
 	struct gameport *gameport;
 	struct gameport *gameport;
 #endif
 #endif
+
+#ifdef CONFIG_SND_ES1968_INPUT
+	struct input_dev *input_dev;
+	char phys[64];			/* physical device path */
+#else
+	struct snd_kcontrol *master_switch; /* for h/w volume control */
+	struct snd_kcontrol *master_volume;
+	spinlock_t ac97_lock;
+	struct tasklet_struct hwvol_tq;
+#endif
 };
 };
 
 
 static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
 static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
@@ -632,28 +638,38 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip)
 static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
 static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
 {
 {
 	struct es1968 *chip = ac97->private_data;
 	struct es1968 *chip = ac97->private_data;
+#ifndef CONFIG_SND_ES1968_INPUT
 	unsigned long flags;
 	unsigned long flags;
+#endif
 
 
 	snd_es1968_ac97_wait(chip);
 	snd_es1968_ac97_wait(chip);
 
 
 	/* Write the bus */
 	/* Write the bus */
+#ifndef CONFIG_SND_ES1968_INPUT
 	spin_lock_irqsave(&chip->ac97_lock, flags);
 	spin_lock_irqsave(&chip->ac97_lock, flags);
+#endif
 	outw(val, chip->io_port + ESM_AC97_DATA);
 	outw(val, chip->io_port + ESM_AC97_DATA);
 	/*msleep(1);*/
 	/*msleep(1);*/
 	outb(reg, chip->io_port + ESM_AC97_INDEX);
 	outb(reg, chip->io_port + ESM_AC97_INDEX);
 	/*msleep(1);*/
 	/*msleep(1);*/
+#ifndef CONFIG_SND_ES1968_INPUT
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
+#endif
 }
 }
 
 
 static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
 {
 	u16 data = 0;
 	u16 data = 0;
 	struct es1968 *chip = ac97->private_data;
 	struct es1968 *chip = ac97->private_data;
+#ifndef CONFIG_SND_ES1968_INPUT
 	unsigned long flags;
 	unsigned long flags;
+#endif
 
 
 	snd_es1968_ac97_wait(chip);
 	snd_es1968_ac97_wait(chip);
 
 
+#ifndef CONFIG_SND_ES1968_INPUT
 	spin_lock_irqsave(&chip->ac97_lock, flags);
 	spin_lock_irqsave(&chip->ac97_lock, flags);
+#endif
 	outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX);
 	outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX);
 	/*msleep(1);*/
 	/*msleep(1);*/
 
 
@@ -661,7 +677,9 @@ static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short
 		data = inw(chip->io_port + ESM_AC97_DATA);
 		data = inw(chip->io_port + ESM_AC97_DATA);
 		/*msleep(1);*/
 		/*msleep(1);*/
 	}
 	}
+#ifndef CONFIG_SND_ES1968_INPUT
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
+#endif
 
 
 	return data;
 	return data;
 }
 }
@@ -1874,13 +1892,17 @@ static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es)
 	}
 	}
 }
 }
 
 
-/*
- */
+/* The hardware volume works by incrementing / decrementing 2 counters
+   (without wrap around) in response to volume button presses and then
+   generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
+   of a byte wide register. The meaning of bits 0 and 4 is unknown. */
 static void es1968_update_hw_volume(unsigned long private_data)
 static void es1968_update_hw_volume(unsigned long private_data)
 {
 {
 	struct es1968 *chip = (struct es1968 *) private_data;
 	struct es1968 *chip = (struct es1968 *) private_data;
 	int x, val;
 	int x, val;
+#ifndef CONFIG_SND_ES1968_INPUT
 	unsigned long flags;
 	unsigned long flags;
+#endif
 
 
 	/* Figure out which volume control button was pushed,
 	/* Figure out which volume control button was pushed,
 	   based on differences from the default register
 	   based on differences from the default register
@@ -1895,6 +1917,7 @@ static void es1968_update_hw_volume(unsigned long private_data)
 	if (chip->in_suspend)
 	if (chip->in_suspend)
 		return;
 		return;
 
 
+#ifndef CONFIG_SND_ES1968_INPUT
 	if (! chip->master_switch || ! chip->master_volume)
 	if (! chip->master_switch || ! chip->master_volume)
 		return;
 		return;
 
 
@@ -1937,6 +1960,35 @@ static void es1968_update_hw_volume(unsigned long private_data)
 		break;
 		break;
 	}
 	}
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
+#else
+	if (!chip->input_dev)
+		return;
+
+	val = 0;
+	switch (x) {
+	case 0x88:
+		/* The counters have not changed, yet we've received a HV
+		   interrupt. According to tests run by various people this
+		   happens when pressing the mute button. */
+		val = KEY_MUTE;
+		break;
+	case 0xaa:
+		/* counters increased by 1 -> volume up */
+		val = KEY_VOLUMEUP;
+		break;
+	case 0x66:
+		/* counters decreased by 1 -> volume down */
+		val = KEY_VOLUMEDOWN;
+		break;
+	}
+
+	if (val) {
+		input_report_key(chip->input_dev, val, 1);
+		input_sync(chip->input_dev);
+		input_report_key(chip->input_dev, val, 0);
+		input_sync(chip->input_dev);
+	}
+#endif
 }
 }
 
 
 /*
 /*
@@ -1953,7 +2005,11 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id)
 	outw(inw(chip->io_port + 4) & 1, chip->io_port + 4);
 	outw(inw(chip->io_port + 4) & 1, chip->io_port + 4);
 
 
 	if (event & ESM_HWVOL_IRQ)
 	if (event & ESM_HWVOL_IRQ)
+#ifdef CONFIG_SND_ES1968_INPUT
+		es1968_update_hw_volume((unsigned long)chip);
+#else
 		tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */
 		tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */
+#endif
 
 
 	/* else ack 'em all, i imagine */
 	/* else ack 'em all, i imagine */
 	outb(0xFF, chip->io_port + 0x1A);
 	outb(0xFF, chip->io_port + 0x1A);
@@ -1993,7 +2049,9 @@ snd_es1968_mixer(struct es1968 *chip)
 {
 {
 	struct snd_ac97_bus *pbus;
 	struct snd_ac97_bus *pbus;
 	struct snd_ac97_template ac97;
 	struct snd_ac97_template ac97;
+#ifndef CONFIG_SND_ES1968_INPUT
 	struct snd_ctl_elem_id elem_id;
 	struct snd_ctl_elem_id elem_id;
+#endif
 	int err;
 	int err;
 	static struct snd_ac97_bus_ops ops = {
 	static struct snd_ac97_bus_ops ops = {
 		.write = snd_es1968_ac97_write,
 		.write = snd_es1968_ac97_write,
@@ -2009,6 +2067,7 @@ snd_es1968_mixer(struct es1968 *chip)
 	if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0)
 	if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0)
 		return err;
 		return err;
 
 
+#ifndef CONFIG_SND_ES1968_INPUT
 	/* attach master switch / volumes for h/w volume control */
 	/* attach master switch / volumes for h/w volume control */
 	memset(&elem_id, 0, sizeof(elem_id));
 	memset(&elem_id, 0, sizeof(elem_id));
 	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
@@ -2018,6 +2077,7 @@ snd_es1968_mixer(struct es1968 *chip)
 	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	strcpy(elem_id.name, "Master Playback Volume");
 	strcpy(elem_id.name, "Master Playback Volume");
 	chip->master_volume = snd_ctl_find_id(chip->card, &elem_id);
 	chip->master_volume = snd_ctl_find_id(chip->card, &elem_id);
+#endif
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2341,6 +2401,7 @@ static void snd_es1968_start_irq(struct es1968 *chip)
 	w = ESM_HIRQ_DSIE | ESM_HIRQ_HW_VOLUME;
 	w = ESM_HIRQ_DSIE | ESM_HIRQ_HW_VOLUME;
 	if (chip->rmidi)
 	if (chip->rmidi)
 		w |= ESM_HIRQ_MPU401;
 		w |= ESM_HIRQ_MPU401;
+	outb(w, chip->io_port + 0x1A);
 	outw(w, chip->io_port + ESM_PORT_HOST_IRQ);
 	outw(w, chip->io_port + ESM_PORT_HOST_IRQ);
 }
 }
 
 
@@ -2474,8 +2535,49 @@ static inline int snd_es1968_create_gameport(struct es1968 *chip, int dev) { ret
 static inline void snd_es1968_free_gameport(struct es1968 *chip) { }
 static inline void snd_es1968_free_gameport(struct es1968 *chip) { }
 #endif
 #endif
 
 
+#ifdef CONFIG_SND_ES1968_INPUT
+static int __devinit snd_es1968_input_register(struct es1968 *chip)
+{
+	struct input_dev *input_dev;
+	int err;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	snprintf(chip->phys, sizeof(chip->phys), "pci-%s/input0",
+		 pci_name(chip->pci));
+
+	input_dev->name = chip->card->driver;
+	input_dev->phys = chip->phys;
+	input_dev->id.bustype = BUS_PCI;
+	input_dev->id.vendor  = chip->pci->vendor;
+	input_dev->id.product = chip->pci->device;
+	input_dev->dev.parent = &chip->pci->dev;
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(KEY_MUTE, input_dev->keybit);
+	__set_bit(KEY_VOLUMEDOWN, input_dev->keybit);
+	__set_bit(KEY_VOLUMEUP, input_dev->keybit);
+
+	err = input_register_device(input_dev);
+	if (err) {
+		input_free_device(input_dev);
+		return err;
+	}
+
+	chip->input_dev = input_dev;
+	return 0;
+}
+#endif /* CONFIG_SND_ES1968_INPUT */
+
 static int snd_es1968_free(struct es1968 *chip)
 static int snd_es1968_free(struct es1968 *chip)
 {
 {
+#ifdef CONFIG_SND_ES1968_INPUT
+	if (chip->input_dev)
+		input_unregister_device(chip->input_dev);
+#endif
+
 	if (chip->io_port) {
 	if (chip->io_port) {
 		if (chip->irq >= 0)
 		if (chip->irq >= 0)
 			synchronize_irq(chip->irq);
 			synchronize_irq(chip->irq);
@@ -2486,8 +2588,6 @@ static int snd_es1968_free(struct es1968 *chip)
 	if (chip->irq >= 0)
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 		free_irq(chip->irq, chip);
 	snd_es1968_free_gameport(chip);
 	snd_es1968_free_gameport(chip);
-	chip->master_switch = NULL;
-	chip->master_volume = NULL;
 	pci_release_regions(chip->pci);
 	pci_release_regions(chip->pci);
 	pci_disable_device(chip->pci);
 	pci_disable_device(chip->pci);
 	kfree(chip);
 	kfree(chip);
@@ -2558,9 +2658,11 @@ static int __devinit snd_es1968_create(struct snd_card *card,
 	spin_lock_init(&chip->substream_lock);
 	spin_lock_init(&chip->substream_lock);
 	INIT_LIST_HEAD(&chip->buf_list);
 	INIT_LIST_HEAD(&chip->buf_list);
 	INIT_LIST_HEAD(&chip->substream_list);
 	INIT_LIST_HEAD(&chip->substream_list);
-	spin_lock_init(&chip->ac97_lock);
 	mutex_init(&chip->memory_mutex);
 	mutex_init(&chip->memory_mutex);
+#ifndef CONFIG_SND_ES1968_INPUT
+	spin_lock_init(&chip->ac97_lock);
 	tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip);
 	tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip);
+#endif
 	chip->card = card;
 	chip->card = card;
 	chip->pci = pci;
 	chip->pci = pci;
 	chip->irq = -1;
 	chip->irq = -1;
@@ -2713,6 +2815,13 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci,
 
 
 	snd_es1968_create_gameport(chip, dev);
 	snd_es1968_create_gameport(chip, dev);
 
 
+#ifdef CONFIG_SND_ES1968_INPUT
+	err = snd_es1968_input_register(chip);
+	if (err)
+		snd_printk(KERN_WARNING "Input device registration "
+			"failed with error %i", err);
+#endif
+
 	snd_es1968_start_irq(chip);
 	snd_es1968_start_irq(chip);
 
 
 	chip->clock = clock[dev];
 	chip->clock = clock[dev];

+ 1 - 0
sound/pci/hda/Kconfig

@@ -145,6 +145,7 @@ config SND_HDA_CODEC_NVHDMI
 
 
 config SND_HDA_CODEC_INTELHDMI
 config SND_HDA_CODEC_INTELHDMI
 	bool "Build INTEL HDMI HD-audio codec support"
 	bool "Build INTEL HDMI HD-audio codec support"
+	select SND_DYNAMIC_MINORS
 	default y
 	default y
 	help
 	help
 	  Say Y here to include INTEL HDMI HD-audio codec support in
 	  Say Y here to include INTEL HDMI HD-audio codec support in

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

@@ -1209,8 +1209,7 @@ static void free_hda_cache(struct hda_cache_rec *cache)
 }
 }
 
 
 /* query the hash.  allocate an entry if not found. */
 /* query the hash.  allocate an entry if not found. */
-static struct hda_cache_head  *get_alloc_hash(struct hda_cache_rec *cache,
-					      u32 key)
+static struct hda_cache_head  *get_hash(struct hda_cache_rec *cache, u32 key)
 {
 {
 	u16 idx = key % (u16)ARRAY_SIZE(cache->hash);
 	u16 idx = key % (u16)ARRAY_SIZE(cache->hash);
 	u16 cur = cache->hash[idx];
 	u16 cur = cache->hash[idx];
@@ -1222,17 +1221,27 @@ static struct hda_cache_head  *get_alloc_hash(struct hda_cache_rec *cache,
 			return info;
 			return info;
 		cur = info->next;
 		cur = info->next;
 	}
 	}
+	return NULL;
+}
 
 
-	/* add a new hash entry */
-	info = snd_array_new(&cache->buf);
-	if (!info)
-		return NULL;
-	cur = snd_array_index(&cache->buf, info);
-	info->key = key;
-	info->val = 0;
-	info->next = cache->hash[idx];
-	cache->hash[idx] = cur;
-
+/* query the hash.  allocate an entry if not found. */
+static struct hda_cache_head  *get_alloc_hash(struct hda_cache_rec *cache,
+					      u32 key)
+{
+	struct hda_cache_head *info = get_hash(cache, key);
+	if (!info) {
+		u16 idx, cur;
+		/* add a new hash entry */
+		info = snd_array_new(&cache->buf);
+		if (!info)
+			return NULL;
+		cur = snd_array_index(&cache->buf, info);
+		info->key = key;
+		info->val = 0;
+		idx = key % (u16)ARRAY_SIZE(cache->hash);
+		info->next = cache->hash[idx];
+		cache->hash[idx] = cur;
+	}
 	return info;
 	return info;
 }
 }
 
 
@@ -1461,6 +1470,8 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
 	info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
 	info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
 	if (!info)
 	if (!info)
 		return 0;
 		return 0;
+	if (snd_BUG_ON(mask & ~0xff))
+		mask &= 0xff;
 	val &= mask;
 	val &= mask;
 	val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask;
 	val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask;
 	if (info->vol[ch] == val)
 	if (info->vol[ch] == val)
@@ -1486,6 +1497,9 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
 			     int direction, int idx, int mask, int val)
 			     int direction, int idx, int mask, int val)
 {
 {
 	int ch, ret = 0;
 	int ch, ret = 0;
+
+	if (snd_BUG_ON(mask & ~0xff))
+		mask &= 0xff;
 	for (ch = 0; ch < 2; ch++)
 	for (ch = 0; ch < 2; ch++)
 		ret |= snd_hda_codec_amp_update(codec, nid, ch, direction,
 		ret |= snd_hda_codec_amp_update(codec, nid, ch, direction,
 						idx, mask, val);
 						idx, mask, val);
@@ -2716,6 +2730,41 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
 }
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
 EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
 
 
+/**
+ * snd_hda_codec_update_cache - check cache and write the cmd only when needed
+ * @codec: the HDA codec
+ * @nid: NID to send the command
+ * @direct: direct flag
+ * @verb: the verb to send
+ * @parm: the parameter for the verb
+ *
+ * This function works like snd_hda_codec_write_cache(), but it doesn't send
+ * command if the parameter is already identical with the cached value.
+ * If not, it sends the command and refreshes the cache.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
+			       int direct, unsigned int verb, unsigned int parm)
+{
+	struct hda_cache_head *c;
+	u32 key;
+
+	/* parm may contain the verb stuff for get/set amp */
+	verb = verb | (parm >> 8);
+	parm &= 0xff;
+	key = build_cmd_cache_key(nid, verb);
+	mutex_lock(&codec->bus->cmd_mutex);
+	c = get_hash(&codec->cmd_cache, key);
+	if (c && c->val == parm) {
+		mutex_unlock(&codec->bus->cmd_mutex);
+		return 0;
+	}
+	mutex_unlock(&codec->bus->cmd_mutex);
+	return snd_hda_codec_write_cache(codec, nid, direct, verb, parm);
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache);
+
 /**
 /**
  * snd_hda_codec_resume_cache - Resume the all commands from the cache
  * snd_hda_codec_resume_cache - Resume the all commands from the cache
  * @codec: HD-audio codec
  * @codec: HD-audio codec
@@ -4218,7 +4267,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 			break;
 			break;
 		case AC_JACK_MIC_IN: {
 		case AC_JACK_MIC_IN: {
 			int preferred, alt;
 			int preferred, alt;
-			if (loc == AC_JACK_LOC_FRONT) {
+			if (loc == AC_JACK_LOC_FRONT ||
+			    (loc & 0x30) == AC_JACK_LOC_INTERNAL) {
 				preferred = AUTO_PIN_FRONT_MIC;
 				preferred = AUTO_PIN_FRONT_MIC;
 				alt = AUTO_PIN_MIC;
 				alt = AUTO_PIN_MIC;
 			} else {
 			} else {

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

@@ -885,9 +885,12 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
 			      int direct, unsigned int verb, unsigned int parm);
 			      int direct, unsigned int verb, unsigned int parm);
 void snd_hda_sequence_write_cache(struct hda_codec *codec,
 void snd_hda_sequence_write_cache(struct hda_codec *codec,
 				  const struct hda_verb *seq);
 				  const struct hda_verb *seq);
+int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
+			      int direct, unsigned int verb, unsigned int parm);
 void snd_hda_codec_resume_cache(struct hda_codec *codec);
 void snd_hda_codec_resume_cache(struct hda_codec *codec);
 #else
 #else
 #define snd_hda_codec_write_cache	snd_hda_codec_write
 #define snd_hda_codec_write_cache	snd_hda_codec_write
+#define snd_hda_codec_update_cache	snd_hda_codec_write
 #define snd_hda_sequence_write_cache	snd_hda_sequence_write
 #define snd_hda_sequence_write_cache	snd_hda_sequence_write
 #endif
 #endif
 
 

+ 63 - 46
sound/pci/hda/hda_intel.c

@@ -84,7 +84,7 @@ 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);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
-module_param_array(probe_only, bool, NULL, 0444);
+module_param_array(probe_only, int, NULL, 0444);
 MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
 MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
 module_param(single_cmd, bool, 0444);
 module_param(single_cmd, bool, 0444);
 MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
 MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
@@ -174,7 +174,7 @@ MODULE_DESCRIPTION("Intel HDA driver");
 #define   ICH6_GSTS_FSTS	(1 << 1)   /* flush status */
 #define   ICH6_GSTS_FSTS	(1 << 1)   /* flush status */
 #define ICH6_REG_INTCTL			0x20
 #define ICH6_REG_INTCTL			0x20
 #define ICH6_REG_INTSTS			0x24
 #define ICH6_REG_INTSTS			0x24
-#define ICH6_REG_WALCLK			0x30
+#define ICH6_REG_WALLCLK		0x30	/* 24Mhz source */
 #define ICH6_REG_SYNC			0x34	
 #define ICH6_REG_SYNC			0x34	
 #define ICH6_REG_CORBLBASE		0x40
 #define ICH6_REG_CORBLBASE		0x40
 #define ICH6_REG_CORBUBASE		0x44
 #define ICH6_REG_CORBUBASE		0x44
@@ -340,8 +340,8 @@ struct azx_dev {
 	unsigned int period_bytes; /* size of the period in bytes */
 	unsigned int period_bytes; /* size of the period in bytes */
 	unsigned int frags;	/* number for period in the play buffer */
 	unsigned int frags;	/* number for period in the play buffer */
 	unsigned int fifo_size;	/* FIFO size */
 	unsigned int fifo_size;	/* FIFO size */
-	unsigned long start_jiffies;	/* start + minimum jiffies */
-	unsigned long min_jiffies;	/* minimum jiffies before position is valid */
+	unsigned long start_wallclk;	/* start + minimum wallclk */
+	unsigned long period_wallclk;	/* wallclk for period */
 
 
 	void __iomem *sd_addr;	/* stream descriptor pointer */
 	void __iomem *sd_addr;	/* stream descriptor pointer */
 
 
@@ -361,7 +361,6 @@ struct azx_dev {
 	unsigned int opened :1;
 	unsigned int opened :1;
 	unsigned int running :1;
 	unsigned int running :1;
 	unsigned int irq_pending :1;
 	unsigned int irq_pending :1;
-	unsigned int start_flag: 1;	/* stream full start flag */
 	/*
 	/*
 	 * For VIA:
 	 * For VIA:
 	 *  A flag to ensure DMA position is 0
 	 *  A flag to ensure DMA position is 0
@@ -425,7 +424,7 @@ struct azx {
 	struct snd_dma_buffer posbuf;
 	struct snd_dma_buffer posbuf;
 
 
 	/* flags */
 	/* flags */
-	int position_fix;
+	int position_fix[2]; /* for both playback/capture streams */
 	int poll_count;
 	int poll_count;
 	unsigned int running :1;
 	unsigned int running :1;
 	unsigned int initialized :1;
 	unsigned int initialized :1;
@@ -858,10 +857,13 @@ static void azx_power_notify(struct hda_bus *bus);
 #endif
 #endif
 
 
 /* reset codec link */
 /* reset codec link */
-static int azx_reset(struct azx *chip)
+static int azx_reset(struct azx *chip, int full_reset)
 {
 {
 	int count;
 	int count;
 
 
+	if (!full_reset)
+		goto __skip;
+
 	/* clear STATESTS */
 	/* clear STATESTS */
 	azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
 	azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
 
 
@@ -887,6 +889,7 @@ static int azx_reset(struct azx *chip)
 	/* Brent Chartrand said to wait >= 540us for codecs to initialize */
 	/* Brent Chartrand said to wait >= 540us for codecs to initialize */
 	msleep(1);
 	msleep(1);
 
 
+      __skip:
 	/* check to see if controller is ready */
 	/* check to see if controller is ready */
 	if (!azx_readb(chip, GCTL)) {
 	if (!azx_readb(chip, GCTL)) {
 		snd_printd(SFX "azx_reset: controller not ready!\n");
 		snd_printd(SFX "azx_reset: controller not ready!\n");
@@ -998,13 +1001,13 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
 /*
 /*
  * reset and start the controller registers
  * reset and start the controller registers
  */
  */
-static void azx_init_chip(struct azx *chip)
+static void azx_init_chip(struct azx *chip, int full_reset)
 {
 {
 	if (chip->initialized)
 	if (chip->initialized)
 		return;
 		return;
 
 
 	/* reset controller */
 	/* reset controller */
-	azx_reset(chip);
+	azx_reset(chip, full_reset);
 
 
 	/* initialize interrupts */
 	/* initialize interrupts */
 	azx_int_clear(chip);
 	azx_int_clear(chip);
@@ -1302,8 +1305,10 @@ 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 == POS_FIX_POSBUF ||
-	    chip->position_fix == POS_FIX_AUTO ||
+	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) {
 	    chip->via_dmapos_patch) {
 		if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
 		if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
 			azx_writel(chip, DPLBASE,
 			azx_writel(chip, DPLBASE,
@@ -1348,7 +1353,7 @@ static void azx_bus_reset(struct hda_bus *bus)
 
 
 	bus->in_reset = 1;
 	bus->in_reset = 1;
 	azx_stop_chip(chip);
 	azx_stop_chip(chip);
-	azx_init_chip(chip);
+	azx_init_chip(chip, 1);
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 	if (chip->initialized) {
 	if (chip->initialized) {
 		int i;
 		int i;
@@ -1422,7 +1427,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
 				 * get back to the sanity state.
 				 * get back to the sanity state.
 				 */
 				 */
 				azx_stop_chip(chip);
 				azx_stop_chip(chip);
-				azx_init_chip(chip);
+				azx_init_chip(chip, 1);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -1670,8 +1675,9 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 			return err;
 			return err;
 	}
 	}
 
 
-	azx_dev->min_jiffies = (runtime->period_size * HZ) /
-						(runtime->rate * 2);
+	/* wallclk has 24Mhz clock source */
+	azx_dev->period_wallclk = (((runtime->period_size * 24000) /
+						runtime->rate) * 1000);
 	azx_setup_controller(chip, azx_dev);
 	azx_setup_controller(chip, azx_dev);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
 		azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
@@ -1725,14 +1731,15 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 		if (s->pcm->card != substream->pcm->card)
 		if (s->pcm->card != substream->pcm->card)
 			continue;
 			continue;
 		azx_dev = get_azx_dev(s);
 		azx_dev = get_azx_dev(s);
-		if (rstart) {
-			azx_dev->start_flag = 1;
-			azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies;
-		}
-		if (start)
+		if (start) {
+			azx_dev->start_wallclk = azx_readl(chip, WALLCLK);
+			if (!rstart)
+				azx_dev->start_wallclk -=
+						azx_dev->period_wallclk;
 			azx_stream_start(chip, azx_dev);
 			azx_stream_start(chip, azx_dev);
-		else
+		} else {
 			azx_stream_stop(chip, azx_dev);
 			azx_stream_stop(chip, azx_dev);
+		}
 		azx_dev->running = start;
 		azx_dev->running = start;
 	}
 	}
 	spin_unlock(&chip->reg_lock);
 	spin_unlock(&chip->reg_lock);
@@ -1843,13 +1850,16 @@ static unsigned int azx_get_position(struct azx *chip,
 
 
 	if (chip->via_dmapos_patch)
 	if (chip->via_dmapos_patch)
 		pos = azx_via_get_position(chip, azx_dev);
 		pos = azx_via_get_position(chip, azx_dev);
-	else if (chip->position_fix == POS_FIX_POSBUF ||
-		 chip->position_fix == 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);
+	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);
+		}
 	}
 	}
 	if (pos >= azx_dev->bufsize)
 	if (pos >= azx_dev->bufsize)
 		pos = 0;
 		pos = 0;
@@ -1876,32 +1886,35 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
  */
  */
 static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
 static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
 {
 {
+	u32 wallclk;
 	unsigned int pos;
 	unsigned int pos;
+	int stream;
 
 
-	if (azx_dev->start_flag &&
-	    time_before_eq(jiffies, azx_dev->start_jiffies))
+	wallclk = azx_readl(chip, WALLCLK) - azx_dev->start_wallclk;
+	if (wallclk < (azx_dev->period_wallclk * 2) / 3)
 		return -1;	/* bogus (too early) interrupt */
 		return -1;	/* bogus (too early) interrupt */
-	azx_dev->start_flag = 0;
 
 
+	stream = azx_dev->substream->stream;
 	pos = azx_get_position(chip, azx_dev);
 	pos = azx_get_position(chip, azx_dev);
-	if (chip->position_fix == POS_FIX_AUTO) {
+	if (chip->position_fix[stream] == POS_FIX_AUTO) {
 		if (!pos) {
 		if (!pos) {
 			printk(KERN_WARNING
 			printk(KERN_WARNING
 			       "hda-intel: Invalid position buffer, "
 			       "hda-intel: Invalid position buffer, "
 			       "using LPIB read method instead.\n");
 			       "using LPIB read method instead.\n");
-			chip->position_fix = POS_FIX_LPIB;
+			chip->position_fix[stream] = POS_FIX_LPIB;
 			pos = azx_get_position(chip, azx_dev);
 			pos = azx_get_position(chip, azx_dev);
 		} else
 		} else
-			chip->position_fix = POS_FIX_POSBUF;
+			chip->position_fix[stream] = POS_FIX_POSBUF;
 	}
 	}
 
 
-	if (!bdl_pos_adj[chip->dev_index])
-		return 1; /* no delayed ack */
 	if (WARN_ONCE(!azx_dev->period_bytes,
 	if (WARN_ONCE(!azx_dev->period_bytes,
 		      "hda-intel: zero azx_dev->period_bytes"))
 		      "hda-intel: zero azx_dev->period_bytes"))
-		return 0; /* this shouldn't happen! */
-	if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
-		return 0; /* NG - it's below the period boundary */
+		return -1; /* this shouldn't happen! */
+	if (wallclk <= azx_dev->period_wallclk &&
+	    pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
+		/* NG - it's below the first next period boundary */
+		return bdl_pos_adj[chip->dev_index] ? 0 : -1;
+	azx_dev->start_wallclk = wallclk;
 	return 1; /* OK, it's fine */
 	return 1; /* OK, it's fine */
 }
 }
 
 
@@ -1911,7 +1924,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
 static void azx_irq_pending_work(struct work_struct *work)
 static void azx_irq_pending_work(struct work_struct *work)
 {
 {
 	struct azx *chip = container_of(work, struct azx, irq_pending_work);
 	struct azx *chip = container_of(work, struct azx, irq_pending_work);
-	int i, pending;
+	int i, pending, ok;
 
 
 	if (!chip->irq_pending_warned) {
 	if (!chip->irq_pending_warned) {
 		printk(KERN_WARNING
 		printk(KERN_WARNING
@@ -1930,11 +1943,14 @@ static void azx_irq_pending_work(struct work_struct *work)
 			    !azx_dev->substream ||
 			    !azx_dev->substream ||
 			    !azx_dev->running)
 			    !azx_dev->running)
 				continue;
 				continue;
-			if (azx_position_ok(chip, azx_dev)) {
+			ok = azx_position_ok(chip, azx_dev);
+			if (ok > 0) {
 				azx_dev->irq_pending = 0;
 				azx_dev->irq_pending = 0;
 				spin_unlock(&chip->reg_lock);
 				spin_unlock(&chip->reg_lock);
 				snd_pcm_period_elapsed(azx_dev->substream);
 				snd_pcm_period_elapsed(azx_dev->substream);
 				spin_lock(&chip->reg_lock);
 				spin_lock(&chip->reg_lock);
+			} else if (ok < 0) {
+				pending = 0;	/* too early */
 			} else
 			} else
 				pending++;
 				pending++;
 		}
 		}
@@ -2112,7 +2128,7 @@ static void azx_power_notify(struct hda_bus *bus)
 		}
 		}
 	}
 	}
 	if (power_on)
 	if (power_on)
-		azx_init_chip(chip);
+		azx_init_chip(chip, 1);
 	else if (chip->running && power_save_controller &&
 	else if (chip->running && power_save_controller &&
 		 !bus->power_keep_link_on)
 		 !bus->power_keep_link_on)
 		azx_stop_chip(chip);
 		azx_stop_chip(chip);
@@ -2182,7 +2198,7 @@ static int azx_resume(struct pci_dev *pci)
 	azx_init_pci(chip);
 	azx_init_pci(chip);
 
 
 	if (snd_hda_codecs_inuse(chip->bus))
 	if (snd_hda_codecs_inuse(chip->bus))
-		azx_init_chip(chip);
+		azx_init_chip(chip, 1);
 
 
 	snd_hda_resume(chip->bus);
 	snd_hda_resume(chip->bus);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -2431,7 +2447,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
 	chip->dev_index = dev;
 	chip->dev_index = dev;
 	INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
 	INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
 
 
-	chip->position_fix = check_position_fix(chip, position_fix[dev]);
+	chip->position_fix[0] = chip->position_fix[1] =
+		check_position_fix(chip, position_fix[dev]);
 	check_probe_mask(chip, dev);
 	check_probe_mask(chip, dev);
 
 
 	chip->single_cmd = single_cmd;
 	chip->single_cmd = single_cmd;
@@ -2577,7 +2594,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
 
 
 	/* initialize chip */
 	/* initialize chip */
 	azx_init_pci(chip);
 	azx_init_pci(chip);
-	azx_init_chip(chip);
+	azx_init_chip(chip, (probe_only[dev] & 2) == 0);
 
 
 	/* codec detection */
 	/* codec detection */
 	if (!chip->codec_mask) {
 	if (!chip->codec_mask) {
@@ -2666,7 +2683,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
 			goto out_free;
 			goto out_free;
 	}
 	}
 #endif
 #endif
-	if (!probe_only[dev]) {
+	if ((probe_only[dev] & 1) == 0) {
 		err = azx_codec_configure(chip);
 		err = azx_codec_configure(chip);
 		if (err < 0)
 		if (err < 0)
 			goto out_free;
 			goto out_free;

+ 17 - 4
sound/pci/hda/patch_analog.c

@@ -71,9 +71,10 @@ struct ad198x_spec {
 	struct hda_input_mux private_imux;
 	struct hda_input_mux private_imux;
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
 
-	unsigned int jack_present :1;
-	unsigned int inv_jack_detect:1;	/* inverted jack-detection */
-	unsigned int inv_eapd:1;	/* inverted EAPD implementation */
+	unsigned int jack_present: 1;
+	unsigned int inv_jack_detect: 1;/* inverted jack-detection */
+	unsigned int inv_eapd: 1;	/* inverted EAPD implementation */
+	unsigned int analog_beep: 1;	/* analog beep input present */
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	struct hda_loopback_check loopback;
 	struct hda_loopback_check loopback;
@@ -165,6 +166,12 @@ static struct snd_kcontrol_new ad_beep_mixer[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
+static struct snd_kcontrol_new ad_beep2_mixer[] = {
+	HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
+	{ } /* end */
+};
+
 #define set_beep_amp(spec, nid, idx, dir) \
 #define set_beep_amp(spec, nid, idx, dir) \
 	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
 	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
 #else
 #else
@@ -203,7 +210,8 @@ static int ad198x_build_controls(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 	if (spec->beep_amp) {
 	if (spec->beep_amp) {
 		struct snd_kcontrol_new *knew;
 		struct snd_kcontrol_new *knew;
-		for (knew = ad_beep_mixer; knew->name; knew++) {
+		knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
+		for ( ; knew->name; knew++) {
 			struct snd_kcontrol *kctl;
 			struct snd_kcontrol *kctl;
 			kctl = snd_ctl_new1(knew, codec);
 			kctl = snd_ctl_new1(knew, codec);
 			if (!kctl)
 			if (!kctl)
@@ -3481,6 +3489,8 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
 	HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
@@ -3522,6 +3532,8 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = {
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	/* docking mic boost */
 	/* docking mic boost */
 	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	/* Analog PC Beeper - allow firmware/ACPI beeps */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
 	/* Analog mixer - docking mic; mute as default */
 	/* Analog mixer - docking mic; mute as default */
 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
 	/* enable EAPD bit */
 	/* enable EAPD bit */
@@ -3654,6 +3666,7 @@ static int patch_ad1984(struct hda_codec *codec)
 		spec->input_mux = &ad1984_thinkpad_capture_source;
 		spec->input_mux = &ad1984_thinkpad_capture_source;
 		spec->mixers[0] = ad1984_thinkpad_mixers;
 		spec->mixers[0] = ad1984_thinkpad_mixers;
 		spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
 		spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
+		spec->analog_beep = 1;
 		break;
 		break;
 	case AD1984_DELL_DESKTOP:
 	case AD1984_DELL_DESKTOP:
 		spec->multiout.dig_out_nid = 0;
 		spec->multiout.dig_out_nid = 0;

+ 152 - 5
sound/pci/hda/patch_conexant.c

@@ -115,6 +115,7 @@ struct conexant_spec {
 	unsigned int port_d_mode;
 	unsigned int port_d_mode;
 	unsigned int dell_vostro:1;
 	unsigned int dell_vostro:1;
 	unsigned int ideapad:1;
 	unsigned int ideapad:1;
+	unsigned int thinkpad:1;
 
 
 	unsigned int ext_mic_present;
 	unsigned int ext_mic_present;
 	unsigned int recording;
 	unsigned int recording;
@@ -1784,6 +1785,7 @@ static struct hda_verb cxt5051_init_verbs[] = {
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
 	/* SPDIF route: PCM */
 	/* SPDIF route: PCM */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
 	{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
 	/* EAPD */
 	/* EAPD */
 	{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 
 	{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 
@@ -1840,6 +1842,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
 	/* SPDIF route: PCM */
 	/* SPDIF route: PCM */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* needed for W500 Advanced Mini Dock 250410 */
 	{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
 	{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
 	/* EAPD */
 	/* EAPD */
 	{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
 	{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
@@ -1911,7 +1914,7 @@ enum {
 	CXT5051_LAPTOP,	 /* Laptops w/ EAPD support */
 	CXT5051_LAPTOP,	 /* Laptops w/ EAPD support */
 	CXT5051_HP,	/* no docking */
 	CXT5051_HP,	/* no docking */
 	CXT5051_HP_DV6736,	/* HP without mic switch */
 	CXT5051_HP_DV6736,	/* HP without mic switch */
-	CXT5051_LENOVO_X200,	/* Lenovo X200 laptop */
+	CXT5051_LENOVO_X200,	/* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */
 	CXT5051_F700,       /* HP Compaq Presario F700 */
 	CXT5051_F700,       /* HP Compaq Presario F700 */
 	CXT5051_TOSHIBA,	/* Toshiba M300 & co */
 	CXT5051_TOSHIBA,	/* Toshiba M300 & co */
 	CXT5051_MODELS
 	CXT5051_MODELS
@@ -2033,6 +2036,9 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
 	/* Port D (HP/LO) */
 	/* Port D (HP/LO) */
 	pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
 	pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
 		? spec->port_d_mode : 0;
 		? spec->port_d_mode : 0;
+	/* Mute if Port A is connected on Thinkpad */
+	if (spec->thinkpad && (spec->hp_present & 1))
+		pinctl = 0;
 	snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 	snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 			pinctl);
 			pinctl);
 
 
@@ -2213,6 +2219,50 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
 	}
 	}
 }
 }
 
 
+/* toggle input of built-in digital mic and mic jack appropriately
+   order is: external mic -> dock mic -> interal mic */
+static void cxt5066_thinkpad_automic(struct hda_codec *codec)
+{
+	unsigned int ext_present, dock_present;
+
+	static struct hda_verb ext_mic_present[] = {
+		{0x14, AC_VERB_SET_CONNECT_SEL, 0},
+		{0x17, AC_VERB_SET_CONNECT_SEL, 1},
+		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+		{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+		{}
+	};
+	static struct hda_verb dock_mic_present[] = {
+		{0x14, AC_VERB_SET_CONNECT_SEL, 0},
+		{0x17, AC_VERB_SET_CONNECT_SEL, 0},
+		{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+		{}
+	};
+	static struct hda_verb ext_mic_absent[] = {
+		{0x14, AC_VERB_SET_CONNECT_SEL, 2},
+		{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+		{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+		{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+		{}
+	};
+
+	ext_present = snd_hda_jack_detect(codec, 0x1b);
+	dock_present = snd_hda_jack_detect(codec, 0x1a);
+	if (ext_present) {
+		snd_printdd("CXT5066: external microphone detected\n");
+		snd_hda_sequence_write(codec, ext_mic_present);
+	} else if (dock_present) {
+		snd_printdd("CXT5066: dock microphone detected\n");
+		snd_hda_sequence_write(codec, dock_mic_present);
+	} else {
+		snd_printdd("CXT5066: external microphone absent\n");
+		snd_hda_sequence_write(codec, ext_mic_absent);
+	}
+}
+
 /* mute internal speaker if HP is plugged */
 /* mute internal speaker if HP is plugged */
 static void cxt5066_hp_automute(struct hda_codec *codec)
 static void cxt5066_hp_automute(struct hda_codec *codec)
 {
 {
@@ -2225,7 +2275,8 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
 	/* Port D */
 	/* Port D */
 	portD = snd_hda_jack_detect(codec, 0x1c);
 	portD = snd_hda_jack_detect(codec, 0x1c);
 
 
-	spec->hp_present = !!(portA | portD);
+	spec->hp_present = !!(portA);
+	spec->hp_present |= portD ? 2 : 0;
 	snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
 	snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
 		portA, portD, spec->hp_present);
 		portA, portD, spec->hp_present);
 	cxt5066_update_speaker(codec);
 	cxt5066_update_speaker(codec);
@@ -2276,6 +2327,20 @@ static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res)
 	}
 	}
 }
 }
 
 
+/* unsolicited event for jack sensing */
+static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res)
+{
+	snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26);
+	switch (res >> 26) {
+	case CONEXANT_HP_EVENT:
+		cxt5066_hp_automute(codec);
+		break;
+	case CONEXANT_MIC_EVENT:
+		cxt5066_thinkpad_automic(codec);
+		break;
+	}
+}
+
 static const struct hda_input_mux cxt5066_analog_mic_boost = {
 static const struct hda_input_mux cxt5066_analog_mic_boost = {
 	.num_items = 5,
 	.num_items = 5,
 	.items = {
 	.items = {
@@ -2294,7 +2359,7 @@ static void cxt5066_set_mic_boost(struct hda_codec *codec)
 		AC_VERB_SET_AMP_GAIN_MUTE,
 		AC_VERB_SET_AMP_GAIN_MUTE,
 		AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
 		AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
 			cxt5066_analog_mic_boost.items[spec->mic_boost].index);
 			cxt5066_analog_mic_boost.items[spec->mic_boost].index);
-	if (spec->ideapad) {
+	if (spec->ideapad || spec->thinkpad) {
 		/* adjust the internal mic as well...it is not through 0x17 */
 		/* adjust the internal mic as well...it is not through 0x17 */
 		snd_hda_codec_write_cache(codec, 0x23, 0,
 		snd_hda_codec_write_cache(codec, 0x23, 0,
 			AC_VERB_SET_AMP_GAIN_MUTE,
 			AC_VERB_SET_AMP_GAIN_MUTE,
@@ -2782,6 +2847,64 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = {
 	{ } /* end */
 	{ } /* end */
 };
 };
 
 
+static struct hda_verb cxt5066_init_verbs_thinkpad[] = {
+	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
+	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
+
+	/* Port G: internal speakers  */
+	{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+	/* Port A: HP, Amp  */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+	{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+	/* Port B: Mic Dock */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+	/* Port C: Mic */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+	/* Port D: HP Dock, Amp */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+	{0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+	/* DAC1 */
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+	/* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	{0x14, AC_VERB_SET_CONNECT_SEL, 2},	/* default to internal mic */
+
+	/* Audio input selector */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2},
+	{0x17, AC_VERB_SET_CONNECT_SEL, 1},	/* route ext mic */
+
+	/* SPDIF route: PCM */
+	{0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
+
+	{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+	/* internal microphone */
+	{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
+
+	/* EAPD */
+	{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+
+	/* enable unsolicited events for Port A, B, C and D */
+	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+	{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+	{ } /* end */
+};
+
 static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
 static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{ } /* end */
 	{ } /* end */
@@ -2800,6 +2923,8 @@ static int cxt5066_init(struct hda_codec *codec)
 			cxt5066_vostro_automic(codec);
 			cxt5066_vostro_automic(codec);
 		else if (spec->ideapad)
 		else if (spec->ideapad)
 			cxt5066_ideapad_automic(codec);
 			cxt5066_ideapad_automic(codec);
+		else if (spec->thinkpad)
+			cxt5066_thinkpad_automic(codec);
 	}
 	}
 	cxt5066_set_mic_boost(codec);
 	cxt5066_set_mic_boost(codec);
 	return 0;
 	return 0;
@@ -2821,20 +2946,22 @@ static int cxt5066_olpc_init(struct hda_codec *codec)
 }
 }
 
 
 enum {
 enum {
-	CXT5066_LAPTOP,			/* Laptops w/ EAPD support */
+	CXT5066_LAPTOP,		/* Laptops w/ EAPD support */
 	CXT5066_DELL_LAPTOP,	/* Dell Laptop */
 	CXT5066_DELL_LAPTOP,	/* Dell Laptop */
 	CXT5066_OLPC_XO_1_5,	/* OLPC XO 1.5 */
 	CXT5066_OLPC_XO_1_5,	/* OLPC XO 1.5 */
 	CXT5066_DELL_VOSTO,	/* Dell Vostro 1015i */
 	CXT5066_DELL_VOSTO,	/* Dell Vostro 1015i */
 	CXT5066_IDEAPAD,	/* Lenovo IdeaPad U150 */
 	CXT5066_IDEAPAD,	/* Lenovo IdeaPad U150 */
+	CXT5066_THINKPAD,	/* Lenovo ThinkPad T410s, others? */
 	CXT5066_MODELS
 	CXT5066_MODELS
 };
 };
 
 
 static const char *cxt5066_models[CXT5066_MODELS] = {
 static const char *cxt5066_models[CXT5066_MODELS] = {
-	[CXT5066_LAPTOP]		= "laptop",
+	[CXT5066_LAPTOP]	= "laptop",
 	[CXT5066_DELL_LAPTOP]	= "dell-laptop",
 	[CXT5066_DELL_LAPTOP]	= "dell-laptop",
 	[CXT5066_OLPC_XO_1_5]	= "olpc-xo-1_5",
 	[CXT5066_OLPC_XO_1_5]	= "olpc-xo-1_5",
 	[CXT5066_DELL_VOSTO]    = "dell-vostro",
 	[CXT5066_DELL_VOSTO]    = "dell-vostro",
 	[CXT5066_IDEAPAD]	= "ideapad",
 	[CXT5066_IDEAPAD]	= "ideapad",
+	[CXT5066_THINKPAD]	= "thinkpad",
 };
 };
 
 
 static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
 static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
@@ -2849,6 +2976,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
 	SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
 	SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
+	SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
 	{}
 	{}
 };
 };
 
 
@@ -2953,6 +3081,22 @@ static int patch_cxt5066(struct hda_codec *codec)
 		/* no S/PDIF out */
 		/* no S/PDIF out */
 		spec->multiout.dig_out_nid = 0;
 		spec->multiout.dig_out_nid = 0;
 
 
+		/* input source automatically selected */
+		spec->input_mux = NULL;
+		break;
+	case CXT5066_THINKPAD:
+		codec->patch_ops.init = cxt5066_init;
+		codec->patch_ops.unsol_event = cxt5066_thinkpad_event;
+		spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
+		spec->mixers[spec->num_mixers++] = cxt5066_mixers;
+		spec->init_verbs[0] = cxt5066_init_verbs_thinkpad;
+		spec->thinkpad = 1;
+		spec->port_d_mode = PIN_OUT;
+		spec->mic_boost = 2;	/* default 20dB gain */
+
+		/* no S/PDIF out */
+		spec->multiout.dig_out_nid = 0;
+
 		/* input source automatically selected */
 		/* input source automatically selected */
 		spec->input_mux = NULL;
 		spec->input_mux = NULL;
 		break;
 		break;
@@ -2975,6 +3119,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
 	  .patch = patch_cxt5066 },
 	  .patch = patch_cxt5066 },
 	{ .id = 0x14f15067, .name = "CX20583 (Pebble HSF)",
 	{ .id = 0x14f15067, .name = "CX20583 (Pebble HSF)",
 	  .patch = patch_cxt5066 },
 	  .patch = patch_cxt5066 },
+	{ .id = 0x14f15069, .name = "CX20585",
+	  .patch = patch_cxt5066 },
 	{} /* terminator */
 	{} /* terminator */
 };
 };
 
 
@@ -2983,6 +3129,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15047");
 MODULE_ALIAS("snd-hda-codec-id:14f15051");
 MODULE_ALIAS("snd-hda-codec-id:14f15051");
 MODULE_ALIAS("snd-hda-codec-id:14f15066");
 MODULE_ALIAS("snd-hda-codec-id:14f15066");
 MODULE_ALIAS("snd-hda-codec-id:14f15067");
 MODULE_ALIAS("snd-hda-codec-id:14f15067");
+MODULE_ALIAS("snd-hda-codec-id:14f15069");
 
 
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
 MODULE_DESCRIPTION("Conexant HD-audio codec");

+ 4 - 6
sound/pci/hda/patch_hdmi.c

@@ -766,7 +766,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 	if (spec->num_pins >= MAX_HDMI_PINS) {
 	if (spec->num_pins >= MAX_HDMI_PINS) {
 		snd_printk(KERN_WARNING
 		snd_printk(KERN_WARNING
 			   "HDMI: no space for pin %d\n", pin_nid);
 			   "HDMI: no space for pin %d\n", pin_nid);
-		return -EINVAL;
+		return -E2BIG;
 	}
 	}
 
 
 	hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
 	hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
@@ -788,7 +788,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
 	if (spec->num_cvts >= MAX_HDMI_CVTS) {
 	if (spec->num_cvts >= MAX_HDMI_CVTS) {
 		snd_printk(KERN_WARNING
 		snd_printk(KERN_WARNING
 			   "HDMI: no space for converter %d\n", nid);
 			   "HDMI: no space for converter %d\n", nid);
-		return -EINVAL;
+		return -E2BIG;
 	}
 	}
 
 
 	spec->cvt[spec->num_cvts] = nid;
 	spec->cvt[spec->num_cvts] = nid;
@@ -820,15 +820,13 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
 
 		switch (type) {
 		switch (type) {
 		case AC_WID_AUD_OUT:
 		case AC_WID_AUD_OUT:
-			if (hdmi_add_cvt(codec, nid) < 0)
-				return -EINVAL;
+			hdmi_add_cvt(codec, nid);
 			break;
 			break;
 		case AC_WID_PIN:
 		case AC_WID_PIN:
 			caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
 			caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
 			if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
 			if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
 				continue;
 				continue;
-			if (hdmi_add_pin(codec, nid) < 0)
-				return -EINVAL;
+			hdmi_add_pin(codec, nid);
 			break;
 			break;
 		}
 		}
 	}
 	}

+ 12 - 9
sound/pci/hda/patch_intelhdmi.c

@@ -40,7 +40,7 @@
  *
  *
  * The HDA correspondence of pipes/ports are converter/pin nodes.
  * The HDA correspondence of pipes/ports are converter/pin nodes.
  */
  */
-#define MAX_HDMI_CVTS	2
+#define MAX_HDMI_CVTS	3
 #define MAX_HDMI_PINS	3
 #define MAX_HDMI_PINS	3
 
 
 #include "patch_hdmi.c"
 #include "patch_hdmi.c"
@@ -48,6 +48,7 @@
 static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = {
 static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = {
 	"INTEL HDMI 0",
 	"INTEL HDMI 0",
 	"INTEL HDMI 1",
 	"INTEL HDMI 1",
+	"INTEL HDMI 2",
 };
 };
 
 
 /*
 /*
@@ -185,14 +186,15 @@ static int patch_intel_hdmi(struct hda_codec *codec)
 }
 }
 
 
 static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
 static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
-	{ .id = 0x808629fb, .name = "G45 DEVCL",  .patch = patch_intel_hdmi },
-	{ .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi },
-	{ .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi },
-	{ .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi },
-	{ .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi },
-	{ .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi },
-	{ .id = 0x10951392, .name = "SiI1392 HDMI",     .patch = patch_intel_hdmi },
-	{} /* terminator */
+{ .id = 0x808629fb, .name = "Crestline HDMI",	.patch = patch_intel_hdmi },
+{ .id = 0x80862801, .name = "Bearlake HDMI",	.patch = patch_intel_hdmi },
+{ .id = 0x80862802, .name = "Cantiga HDMI",	.patch = patch_intel_hdmi },
+{ .id = 0x80862803, .name = "Eaglelake HDMI",	.patch = patch_intel_hdmi },
+{ .id = 0x80862804, .name = "IbexPeak HDMI",	.patch = patch_intel_hdmi },
+{ .id = 0x80860054, .name = "IbexPeak HDMI",	.patch = patch_intel_hdmi },
+{ .id = 0x80862805, .name = "CougarPoint HDMI",	.patch = patch_intel_hdmi },
+{ .id = 0x10951392, .name = "SiI1392 HDMI",	.patch = patch_intel_hdmi },
+{} /* terminator */
 };
 };
 
 
 MODULE_ALIAS("snd-hda-codec-id:808629fb");
 MODULE_ALIAS("snd-hda-codec-id:808629fb");
@@ -200,6 +202,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862801");
 MODULE_ALIAS("snd-hda-codec-id:80862802");
 MODULE_ALIAS("snd-hda-codec-id:80862802");
 MODULE_ALIAS("snd-hda-codec-id:80862803");
 MODULE_ALIAS("snd-hda-codec-id:80862803");
 MODULE_ALIAS("snd-hda-codec-id:80862804");
 MODULE_ALIAS("snd-hda-codec-id:80862804");
+MODULE_ALIAS("snd-hda-codec-id:80862805");
 MODULE_ALIAS("snd-hda-codec-id:80860054");
 MODULE_ALIAS("snd-hda-codec-id:80860054");
 MODULE_ALIAS("snd-hda-codec-id:10951392");
 MODULE_ALIAS("snd-hda-codec-id:10951392");
 
 

+ 184 - 54
sound/pci/hda/patch_realtek.c

@@ -276,6 +276,18 @@ struct alc_mic_route {
 
 
 #define MUX_IDX_UNDEF	((unsigned char)-1)
 #define MUX_IDX_UNDEF	((unsigned char)-1)
 
 
+struct alc_customize_define {
+	unsigned int  sku_cfg;
+	unsigned char port_connectivity;
+	unsigned char check_sum;
+	unsigned char customization;
+	unsigned char external_amp;
+	unsigned int  enable_pcbeep:1;
+	unsigned int  platform_type:1;
+	unsigned int  swap:1;
+	unsigned int  override:1;
+};
+
 struct alc_spec {
 struct alc_spec {
 	/* codec parameterization */
 	/* codec parameterization */
 	struct snd_kcontrol_new *mixers[5];	/* mixer arrays */
 	struct snd_kcontrol_new *mixers[5];	/* mixer arrays */
@@ -333,6 +345,7 @@ struct alc_spec {
 
 
 	/* dynamic controls, init_verbs and input_mux */
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
 	struct auto_pin_cfg autocfg;
+	struct alc_customize_define cdefine;
 	struct snd_array kctls;
 	struct snd_array kctls;
 	struct hda_input_mux private_imux[3];
 	struct hda_input_mux private_imux[3];
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
@@ -1248,6 +1261,62 @@ static void alc_init_auto_mic(struct hda_codec *codec)
 	spec->unsol_event = alc_sku_unsol_event;
 	spec->unsol_event = alc_sku_unsol_event;
 }
 }
 
 
+static int alc_auto_parse_customize_define(struct hda_codec *codec)
+{
+	unsigned int ass, tmp, i;
+	unsigned nid = 0;
+	struct alc_spec *spec = codec->spec;
+
+	ass = codec->subsystem_id & 0xffff;
+	if (ass != codec->bus->pci->subsystem_device && (ass & 1))
+		goto do_sku;
+
+	nid = 0x1d;
+	if (codec->vendor_id == 0x10ec0260)
+		nid = 0x17;
+	ass = snd_hda_codec_get_pincfg(codec, nid);
+
+	if (!(ass & 1)) {
+		printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
+		       codec->chip_name, ass);
+		return -1;
+	}
+
+	/* check sum */
+	tmp = 0;
+	for (i = 1; i < 16; i++) {
+		if ((ass >> i) & 1)
+			tmp++;
+	}
+	if (((ass >> 16) & 0xf) != tmp)
+		return -1;
+
+	spec->cdefine.port_connectivity = ass >> 30;
+	spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
+	spec->cdefine.check_sum = (ass >> 16) & 0xf;
+	spec->cdefine.customization = ass >> 8;
+do_sku:
+	spec->cdefine.sku_cfg = ass;
+	spec->cdefine.external_amp = (ass & 0x38) >> 3;
+	spec->cdefine.platform_type = (ass & 0x4) >> 2;
+	spec->cdefine.swap = (ass & 0x2) >> 1;
+	spec->cdefine.override = ass & 0x1;
+
+	snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
+		   nid, spec->cdefine.sku_cfg);
+	snd_printd("SKU: port_connectivity=0x%x\n",
+		   spec->cdefine.port_connectivity);
+	snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
+	snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
+	snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
+	snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
+	snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
+	snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
+	snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
+
+	return 0;
+}
+
 /* check subsystem ID and set up device-specific initialization;
 /* check subsystem ID and set up device-specific initialization;
  * return 1 if initialized, 0 if invalid SSID
  * return 1 if initialized, 0 if invalid SSID
  */
  */
@@ -3415,6 +3484,10 @@ static int alc_init(struct hda_codec *codec)
 	if (spec->init_hook)
 	if (spec->init_hook)
 		spec->init_hook(codec);
 		spec->init_hook(codec);
 
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	if (codec->patch_ops.check_power_status)
+		codec->patch_ops.check_power_status(codec, 0x01);
+#endif
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3775,6 +3848,10 @@ static int alc_resume(struct hda_codec *codec)
 	codec->patch_ops.init(codec);
 	codec->patch_ops.init(codec);
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_cache(codec);
 	snd_hda_codec_resume_cache(codec);
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	if (codec->patch_ops.check_power_status)
+		codec->patch_ops.check_power_status(codec, 0x01);
+#endif
 	return 0;
 	return 0;
 }
 }
 #endif
 #endif
@@ -3797,6 +3874,17 @@ static struct hda_codec_ops alc_patch_ops = {
 	.reboot_notify = alc_shutup,
 	.reboot_notify = alc_shutup,
 };
 };
 
 
+/* replace the codec chip_name with the given string */
+static int alc_codec_rename(struct hda_codec *codec, const char *name)
+{
+	kfree(codec->chip_name);
+	codec->chip_name = kstrdup(name, GFP_KERNEL);
+	if (!codec->chip_name) {
+		alc_free(codec);
+		return -ENOMEM;
+	}
+	return 0;
+}
 
 
 /*
 /*
  * Test configuration for debugging
  * Test configuration for debugging
@@ -10189,21 +10277,20 @@ static int alc882_auto_create_input_ctls(struct hda_codec *codec,
 
 
 static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
 static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
 					      hda_nid_t nid, int pin_type,
 					      hda_nid_t nid, int pin_type,
-					      int dac_idx)
+					      hda_nid_t dac)
 {
 {
-	/* set as output */
-	struct alc_spec *spec = codec->spec;
 	int idx;
 	int idx;
 
 
+	/* set as output */
 	alc_set_pin_output(codec, nid, pin_type);
 	alc_set_pin_output(codec, nid, pin_type);
-	if (dac_idx >= spec->multiout.num_dacs)
-		return;
-	if (spec->multiout.dac_nids[dac_idx] == 0x25)
+
+	if (dac == 0x25)
 		idx = 4;
 		idx = 4;
+	else if (dac >= 0x02 && dac <= 0x05)
+		idx = dac - 2;
 	else
 	else
-		idx = spec->multiout.dac_nids[dac_idx] - 2;
+		return;
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
-
 }
 }
 
 
 static void alc882_auto_init_multi_out(struct hda_codec *codec)
 static void alc882_auto_init_multi_out(struct hda_codec *codec)
@@ -10216,22 +10303,29 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec)
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
 		if (nid)
 		if (nid)
 			alc882_auto_set_output_and_unmute(codec, nid, pin_type,
 			alc882_auto_set_output_and_unmute(codec, nid, pin_type,
-							  i);
+					spec->multiout.dac_nids[i]);
 	}
 	}
 }
 }
 
 
 static void alc882_auto_init_hp_out(struct hda_codec *codec)
 static void alc882_auto_init_hp_out(struct hda_codec *codec)
 {
 {
 	struct alc_spec *spec = codec->spec;
 	struct alc_spec *spec = codec->spec;
-	hda_nid_t pin;
+	hda_nid_t pin, dac;
 
 
 	pin = spec->autocfg.hp_pins[0];
 	pin = spec->autocfg.hp_pins[0];
-	if (pin) /* connect to front */
-		/* use dac 0 */
-		alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+	if (pin) {
+		dac = spec->multiout.hp_nid;
+		if (!dac)
+			dac = spec->multiout.dac_nids[0]; /* to front */
+		alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
+	}
 	pin = spec->autocfg.speaker_pins[0];
 	pin = spec->autocfg.speaker_pins[0];
-	if (pin)
-		alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
+	if (pin) {
+		dac = spec->multiout.extra_out_nid[0];
+		if (!dac)
+			dac = spec->multiout.dac_nids[0]; /* to front */
+		alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
+	}
 }
 }
 
 
 static void alc882_auto_init_analog_input(struct hda_codec *codec)
 static void alc882_auto_init_analog_input(struct hda_codec *codec)
@@ -10345,6 +10439,10 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 	err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
 	err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
+					   "Headphone");
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 	err = alc880_auto_create_extra_out(spec,
 	err = alc880_auto_create_extra_out(spec,
@@ -10352,10 +10450,6 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
 					   "Speaker");
 					   "Speaker");
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
-	err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
-					   "Headphone");
-	if (err < 0)
-		return err;
 	err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
 	err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
@@ -10425,6 +10519,8 @@ static int patch_alc882(struct hda_codec *codec)
 
 
 	codec->spec = spec;
 	codec->spec = spec;
 
 
+	alc_auto_parse_customize_define(codec);
+
 	switch (codec->vendor_id) {
 	switch (codec->vendor_id) {
 	case 0x10ec0882:
 	case 0x10ec0882:
 	case 0x10ec0885:
 	case 0x10ec0885:
@@ -10484,9 +10580,6 @@ static int patch_alc882(struct hda_codec *codec)
 	spec->stream_digital_playback = &alc882_pcm_digital_playback;
 	spec->stream_digital_playback = &alc882_pcm_digital_playback;
 	spec->stream_digital_capture = &alc882_pcm_digital_capture;
 	spec->stream_digital_capture = &alc882_pcm_digital_capture;
 
 
-	if (codec->vendor_id == 0x10ec0888)
-		spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
-
 	if (!spec->adc_nids && spec->input_mux) {
 	if (!spec->adc_nids && spec->input_mux) {
 		int i, j;
 		int i, j;
 		spec->num_adc_nids = 0;
 		spec->num_adc_nids = 0;
@@ -10521,7 +10614,9 @@ static int patch_alc882(struct hda_codec *codec)
 	}
 	}
 
 
 	set_capture_mixer(codec);
 	set_capture_mixer(codec);
-	set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+
+	if (spec->cdefine.enable_pcbeep)
+		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
 
 	if (board_config == ALC882_AUTO)
 	if (board_config == ALC882_AUTO)
 		alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
 		alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
@@ -12308,6 +12403,7 @@ static int patch_alc262(struct hda_codec *codec)
 	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
 	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
 	}
 	}
 #endif
 #endif
+	alc_auto_parse_customize_define(codec);
 
 
 	alc_fix_pll_init(codec, 0x20, 0x0a, 10);
 	alc_fix_pll_init(codec, 0x20, 0x0a, 10);
 
 
@@ -12386,7 +12482,7 @@ static int patch_alc262(struct hda_codec *codec)
 	}
 	}
 	if (!spec->cap_mixer && !spec->no_analog)
 	if (!spec->cap_mixer && !spec->no_analog)
 		set_capture_mixer(codec);
 		set_capture_mixer(codec);
-	if (!spec->no_analog)
+	if (!spec->no_analog && spec->cdefine.enable_pcbeep)
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
 
 	spec->vmaster_nid = 0x0c;
 	spec->vmaster_nid = 0x0c;
@@ -14005,6 +14101,35 @@ static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
 	/* NID is set in alc_build_pcms */
 	/* NID is set in alc_build_pcms */
 };
 };
 
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int alc269_mic2_for_mute_led(struct hda_codec *codec)
+{
+	switch (codec->subsystem_id) {
+	case 0x103c1586:
+		return 1;
+	}
+	return 0;
+}
+
+static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
+{
+	/* update mute-LED according to the speaker mute state */
+	if (nid == 0x01 || nid == 0x14) {
+		int pinval;
+		if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
+		    HDA_AMP_MUTE)
+			pinval = 0x24;
+		else
+			pinval = 0x20;
+		/* mic2 vref pin is used for mute LED control */
+		snd_hda_codec_update_cache(codec, 0x19, 0,
+					   AC_VERB_SET_PIN_WIDGET_CONTROL,
+					   pinval);
+	}
+	return alc_check_power_status(codec, nid);
+}
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+
 /*
 /*
  * BIOS auto configuration
  * BIOS auto configuration
  */
  */
@@ -14082,7 +14207,7 @@ enum {
 	ALC269_FIXUP_SONY_VAIO,
 	ALC269_FIXUP_SONY_VAIO,
 };
 };
 
 
-const static struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
+static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
 	{}
 	{}
 };
 };
@@ -14290,17 +14415,17 @@ static int patch_alc269(struct hda_codec *codec)
 
 
 	codec->spec = spec;
 	codec->spec = spec;
 
 
-	alc_fix_pll_init(codec, 0x20, 0x04, 15);
+	alc_auto_parse_customize_define(codec);
 
 
 	if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
 	if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
-		kfree(codec->chip_name);
-		codec->chip_name = kstrdup("ALC259", GFP_KERNEL);
-		if (!codec->chip_name) {
-			alc_free(codec);
-			return -ENOMEM;
-		}
+		if (codec->bus->pci->subsystem_vendor == 0x1025 &&
+		    spec->cdefine.platform_type == 1)
+			alc_codec_rename(codec, "ALC271X");
+		else
+			alc_codec_rename(codec, "ALC259");
 		is_alc269vb = 1;
 		is_alc269vb = 1;
-	}
+	} else
+		alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
 
 	board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
 	board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
 						  alc269_models,
 						  alc269_models,
@@ -14365,7 +14490,8 @@ static int patch_alc269(struct hda_codec *codec)
 
 
 	if (!spec->cap_mixer)
 	if (!spec->cap_mixer)
 		set_capture_mixer(codec);
 		set_capture_mixer(codec);
-	set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
+	if (spec->cdefine.enable_pcbeep)
+		set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
 
 
 	if (board_config == ALC269_AUTO)
 	if (board_config == ALC269_AUTO)
 		alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
 		alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
@@ -14378,6 +14504,8 @@ static int patch_alc269(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	if (!spec->loopback.amplist)
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc269_loopbacks;
 		spec->loopback.amplist = alc269_loopbacks;
+	if (alc269_mic2_for_mute_led(codec))
+		codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
 #endif
 #endif
 
 
 	return 0;
 	return 0;
@@ -18525,16 +18653,16 @@ static int patch_alc662(struct hda_codec *codec)
 
 
 	codec->spec = spec;
 	codec->spec = spec;
 
 
+	alc_auto_parse_customize_define(codec);
+
 	alc_fix_pll_init(codec, 0x20, 0x04, 15);
 	alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
 
-	if (alc_read_coef_idx(codec, 0)==0x8020){
-		kfree(codec->chip_name);
-		codec->chip_name = kstrdup("ALC661", GFP_KERNEL);
-		if (!codec->chip_name) {
-			alc_free(codec);
-			return -ENOMEM;
-		}
-	}
+	if (alc_read_coef_idx(codec, 0) == 0x8020)
+		alc_codec_rename(codec, "ALC661");
+	else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
+		 codec->bus->pci->subsystem_vendor == 0x1025 &&
+		 spec->cdefine.platform_type == 1)
+		alc_codec_rename(codec, "ALC272X");
 
 
 	board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
 	board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
 						  alc662_models,
 						  alc662_models,
@@ -18584,18 +18712,20 @@ static int patch_alc662(struct hda_codec *codec)
 	if (!spec->cap_mixer)
 	if (!spec->cap_mixer)
 		set_capture_mixer(codec);
 		set_capture_mixer(codec);
 
 
-	switch (codec->vendor_id) {
-	case 0x10ec0662:
-		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-		break;
-	case 0x10ec0272:
-	case 0x10ec0663:
-	case 0x10ec0665:
-		set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
-		break;
-	case 0x10ec0273:
-		set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
-		break;
+	if (spec->cdefine.enable_pcbeep) {
+		switch (codec->vendor_id) {
+		case 0x10ec0662:
+			set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+			break;
+		case 0x10ec0272:
+		case 0x10ec0663:
+		case 0x10ec0665:
+			set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
+			break;
+		case 0x10ec0273:
+			set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
+			break;
+		}
 	}
 	}
 	spec->vmaster_nid = 0x02;
 	spec->vmaster_nid = 0x02;
 
 

+ 64 - 25
sound/pci/ice1712/aureon.c

@@ -1956,11 +1956,10 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
 	return 0;
 	return 0;
 }
 }
 
 
-
 /*
 /*
- * initialize the chip
+ * reset the chip
  */
  */
-static int __devinit aureon_init(struct snd_ice1712 *ice)
+static int aureon_reset(struct snd_ice1712 *ice)
 {
 {
 	static const unsigned short wm_inits_aureon[] = {
 	static const unsigned short wm_inits_aureon[] = {
 		/* These come first to reduce init pop noise */
 		/* These come first to reduce init pop noise */
@@ -2047,30 +2046,10 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
 		0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
 		0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
 		(unsigned short)-1
 		(unsigned short)-1
 	};
 	};
-	struct aureon_spec *spec;
 	unsigned int tmp;
 	unsigned int tmp;
 	const unsigned short *p;
 	const unsigned short *p;
-	int err, i;
-
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (!spec)
-		return -ENOMEM;
-	ice->spec = spec;
-
-	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
-		ice->num_total_dacs = 6;
-		ice->num_total_adcs = 2;
-	} else {
-		/* aureon 7.1 and prodigy 7.1 */
-		ice->num_total_dacs = 8;
-		ice->num_total_adcs = 2;
-	}
-
-	/* to remeber the register values of CS8415 */
-	ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
-	if (!ice->akm)
-		return -ENOMEM;
-	ice->akm_codecs = 1;
+	int err;
+	struct aureon_spec *spec = ice->spec;
 
 
 	err = aureon_ac97_init(ice);
 	err = aureon_ac97_init(ice);
 	if (err != 0)
 	if (err != 0)
@@ -2118,6 +2097,61 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
 	/* initialize PCA9554 pin directions & set default input */
 	/* initialize PCA9554 pin directions & set default input */
 	aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
 	aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
 	aureon_pca9554_write(ice, PCA9554_OUT, 0x00);   /* internal AUX */
 	aureon_pca9554_write(ice, PCA9554_OUT, 0x00);   /* internal AUX */
+	return 0;
+}
+
+/*
+ * suspend/resume
+ */
+#ifdef CONFIG_PM
+static int aureon_resume(struct snd_ice1712 *ice)
+{
+	struct aureon_spec *spec = ice->spec;
+	int err, i;
+
+	err = aureon_reset(ice);
+	if (err != 0)
+		return err;
+
+	/* workaround for poking volume with alsamixer after resume:
+	 * just set stored volume again */
+	for (i = 0; i < ice->num_total_dacs; i++)
+		wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
+	return 0;
+}
+#endif
+
+/*
+ * initialize the chip
+ */
+static int __devinit aureon_init(struct snd_ice1712 *ice)
+{
+	struct aureon_spec *spec;
+	int i, err;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return -ENOMEM;
+	ice->spec = spec;
+
+	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
+		ice->num_total_dacs = 6;
+		ice->num_total_adcs = 2;
+	} else {
+		/* aureon 7.1 and prodigy 7.1 */
+		ice->num_total_dacs = 8;
+		ice->num_total_adcs = 2;
+	}
+
+	/* to remeber the register values of CS8415 */
+	ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+	if (!ice->akm)
+		return -ENOMEM;
+	ice->akm_codecs = 1;
+
+	err = aureon_reset(ice);
+	if (err != 0)
+		return err;
 
 
 	spec->master[0] = WM_VOL_MUTE;
 	spec->master[0] = WM_VOL_MUTE;
 	spec->master[1] = WM_VOL_MUTE;
 	spec->master[1] = WM_VOL_MUTE;
@@ -2126,6 +2160,11 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
 		wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
 		wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
 	}
 	}
 
 
+#ifdef CONFIG_PM
+	ice->pm_resume = aureon_resume;
+	ice->pm_suspend_enabled = 1;
+#endif
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 133 - 6
sound/pci/maestro3.c

@@ -41,6 +41,7 @@
 #include <linux/vmalloc.h>
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/firmware.h>
+#include <linux/input.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/control.h>
@@ -844,11 +845,17 @@ struct snd_m3 {
 	struct m3_dma *substreams;
 	struct m3_dma *substreams;
 
 
 	spinlock_t reg_lock;
 	spinlock_t reg_lock;
-	spinlock_t ac97_lock;
 
 
+#ifdef CONFIG_SND_MAESTRO3_INPUT
+	struct input_dev *input_dev;
+	char phys[64];			/* physical device path */
+#else
+	spinlock_t ac97_lock;
 	struct snd_kcontrol *master_switch;
 	struct snd_kcontrol *master_switch;
 	struct snd_kcontrol *master_volume;
 	struct snd_kcontrol *master_volume;
 	struct tasklet_struct hwvol_tq;
 	struct tasklet_struct hwvol_tq;
+#endif
+
 	unsigned int in_suspend;
 	unsigned int in_suspend;
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
@@ -1598,18 +1605,32 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s)
 	}
 	}
 }
 }
 
 
+/* The m3's hardware volume works by incrementing / decrementing 2 counters
+   (without wrap around) in response to volume button presses and then
+   generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
+   of a byte wide register. The meaning of bits 0 and 4 is unknown. */
 static void snd_m3_update_hw_volume(unsigned long private_data)
 static void snd_m3_update_hw_volume(unsigned long private_data)
 {
 {
 	struct snd_m3 *chip = (struct snd_m3 *) private_data;
 	struct snd_m3 *chip = (struct snd_m3 *) private_data;
 	int x, val;
 	int x, val;
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	unsigned long flags;
 	unsigned long flags;
+#endif
 
 
 	/* Figure out which volume control button was pushed,
 	/* Figure out which volume control button was pushed,
 	   based on differences from the default register
 	   based on differences from the default register
 	   values. */
 	   values. */
 	x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee;
 	x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee;
 
 
-	/* Reset the volume control registers. */
+	/* Reset the volume counters to 4. Tests on the allegro integrated
+	   into a Compaq N600C laptop, have revealed that:
+	   1) Writing any value will result in the 2 counters being reset to
+	      4 so writing 0x88 is not strictly necessary
+	   2) Writing to any of the 4 involved registers will reset all 4
+	      of them (and reading them always returns the same value for all
+	      of them)
+	   It could be that a maestro deviates from this, so leave the code
+	   as is. */
 	outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE);
 	outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE);
 	outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE);
 	outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE);
 	outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER);
 	outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER);
@@ -1620,6 +1641,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
 	if (chip->in_suspend)
 	if (chip->in_suspend)
 		return;
 		return;
 
 
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	if (!chip->master_switch || !chip->master_volume)
 	if (!chip->master_switch || !chip->master_volume)
 		return;
 		return;
 
 
@@ -1629,7 +1651,9 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
 	val = chip->ac97->regs[AC97_MASTER_VOL];
 	val = chip->ac97->regs[AC97_MASTER_VOL];
 	switch (x) {
 	switch (x) {
 	case 0x88:
 	case 0x88:
-		/* mute */
+		/* The counters have not changed, yet we've received a HV
+		   interrupt. According to tests run by various people this
+		   happens when pressing the mute button. */
 		val ^= 0x8000;
 		val ^= 0x8000;
 		chip->ac97->regs[AC97_MASTER_VOL] = val;
 		chip->ac97->regs[AC97_MASTER_VOL] = val;
 		outw(val, chip->iobase + CODEC_DATA);
 		outw(val, chip->iobase + CODEC_DATA);
@@ -1638,7 +1662,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
 			       &chip->master_switch->id);
 			       &chip->master_switch->id);
 		break;
 		break;
 	case 0xaa:
 	case 0xaa:
-		/* volume up */
+		/* counters increased by 1 -> volume up */
 		if ((val & 0x7f) > 0)
 		if ((val & 0x7f) > 0)
 			val--;
 			val--;
 		if ((val & 0x7f00) > 0)
 		if ((val & 0x7f00) > 0)
@@ -1650,7 +1674,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
 			       &chip->master_volume->id);
 			       &chip->master_volume->id);
 		break;
 		break;
 	case 0x66:
 	case 0x66:
-		/* volume down */
+		/* counters decreased by 1 -> volume down */
 		if ((val & 0x7f) < 0x1f)
 		if ((val & 0x7f) < 0x1f)
 			val++;
 			val++;
 		if ((val & 0x7f00) < 0x1f00)
 		if ((val & 0x7f00) < 0x1f00)
@@ -1663,6 +1687,35 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
 		break;
 		break;
 	}
 	}
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
+#else
+	if (!chip->input_dev)
+		return;
+
+	val = 0;
+	switch (x) {
+	case 0x88:
+		/* The counters have not changed, yet we've received a HV
+		   interrupt. According to tests run by various people this
+		   happens when pressing the mute button. */
+		val = KEY_MUTE;
+		break;
+	case 0xaa:
+		/* counters increased by 1 -> volume up */
+		val = KEY_VOLUMEUP;
+		break;
+	case 0x66:
+		/* counters decreased by 1 -> volume down */
+		val = KEY_VOLUMEDOWN;
+		break;
+	}
+
+	if (val) {
+		input_report_key(chip->input_dev, val, 1);
+		input_sync(chip->input_dev);
+		input_report_key(chip->input_dev, val, 0);
+		input_sync(chip->input_dev);
+	}
+#endif
 }
 }
 
 
 static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
 static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
@@ -1677,7 +1730,11 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
 		return IRQ_NONE;
 		return IRQ_NONE;
 
 
 	if (status & HV_INT_PENDING)
 	if (status & HV_INT_PENDING)
+#ifdef CONFIG_SND_MAESTRO3_INPUT
+		snd_m3_update_hw_volume((unsigned long)chip);
+#else
 		tasklet_schedule(&chip->hwvol_tq);
 		tasklet_schedule(&chip->hwvol_tq);
+#endif
 
 
 	/*
 	/*
 	 * ack an assp int if its running
 	 * ack an assp int if its running
@@ -1943,18 +2000,24 @@ static unsigned short
 snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
 {
 	struct snd_m3 *chip = ac97->private_data;
 	struct snd_m3 *chip = ac97->private_data;
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	unsigned long flags;
 	unsigned long flags;
+#endif
 	unsigned short data = 0xffff;
 	unsigned short data = 0xffff;
 
 
 	if (snd_m3_ac97_wait(chip))
 	if (snd_m3_ac97_wait(chip))
 		goto fail;
 		goto fail;
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	spin_lock_irqsave(&chip->ac97_lock, flags);
 	spin_lock_irqsave(&chip->ac97_lock, flags);
+#endif
 	snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
 	snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
 	if (snd_m3_ac97_wait(chip))
 	if (snd_m3_ac97_wait(chip))
 		goto fail_unlock;
 		goto fail_unlock;
 	data = snd_m3_inw(chip, CODEC_DATA);
 	data = snd_m3_inw(chip, CODEC_DATA);
 fail_unlock:
 fail_unlock:
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
+#endif
 fail:
 fail:
 	return data;
 	return data;
 }
 }
@@ -1963,14 +2026,20 @@ static void
 snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
 snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
 {
 {
 	struct snd_m3 *chip = ac97->private_data;
 	struct snd_m3 *chip = ac97->private_data;
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	unsigned long flags;
 	unsigned long flags;
+#endif
 
 
 	if (snd_m3_ac97_wait(chip))
 	if (snd_m3_ac97_wait(chip))
 		return;
 		return;
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	spin_lock_irqsave(&chip->ac97_lock, flags);
 	spin_lock_irqsave(&chip->ac97_lock, flags);
+#endif
 	snd_m3_outw(chip, val, CODEC_DATA);
 	snd_m3_outw(chip, val, CODEC_DATA);
 	snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
 	snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
 	spin_unlock_irqrestore(&chip->ac97_lock, flags);
+#endif
 }
 }
 
 
 
 
@@ -2077,7 +2146,9 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip)
 {
 {
 	struct snd_ac97_bus *pbus;
 	struct snd_ac97_bus *pbus;
 	struct snd_ac97_template ac97;
 	struct snd_ac97_template ac97;
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	struct snd_ctl_elem_id elem_id;
 	struct snd_ctl_elem_id elem_id;
+#endif
 	int err;
 	int err;
 	static struct snd_ac97_bus_ops ops = {
 	static struct snd_ac97_bus_ops ops = {
 		.write = snd_m3_ac97_write,
 		.write = snd_m3_ac97_write,
@@ -2097,6 +2168,7 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip)
 	schedule_timeout_uninterruptible(msecs_to_jiffies(100));
 	schedule_timeout_uninterruptible(msecs_to_jiffies(100));
 	snd_ac97_write(chip->ac97, AC97_PCM, 0);
 	snd_ac97_write(chip->ac97, AC97_PCM, 0);
 
 
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	memset(&elem_id, 0, sizeof(elem_id));
 	memset(&elem_id, 0, sizeof(elem_id));
 	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	strcpy(elem_id.name, "Master Playback Switch");
 	strcpy(elem_id.name, "Master Playback Switch");
@@ -2105,6 +2177,7 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip)
 	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	strcpy(elem_id.name, "Master Playback Volume");
 	strcpy(elem_id.name, "Master Playback Volume");
 	chip->master_volume = snd_ctl_find_id(chip->card, &elem_id);
 	chip->master_volume = snd_ctl_find_id(chip->card, &elem_id);
+#endif
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2370,6 +2443,7 @@ snd_m3_enable_ints(struct snd_m3 *chip)
 	val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/;
 	val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/;
 	if (chip->hv_config & HV_CTRL_ENABLE)
 	if (chip->hv_config & HV_CTRL_ENABLE)
 		val |= HV_INT_ENABLE;
 		val |= HV_INT_ENABLE;
+	outb(val, chip->iobase + HOST_INT_STATUS);
 	outw(val, io + HOST_INT_CTRL);
 	outw(val, io + HOST_INT_CTRL);
 	outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
 	outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
 	     io + ASSP_CONTROL_C);
 	     io + ASSP_CONTROL_C);
@@ -2384,6 +2458,11 @@ static int snd_m3_free(struct snd_m3 *chip)
 	struct m3_dma *s;
 	struct m3_dma *s;
 	int i;
 	int i;
 
 
+#ifdef CONFIG_SND_MAESTRO3_INPUT
+	if (chip->input_dev)
+		input_unregister_device(chip->input_dev);
+#endif
+
 	if (chip->substreams) {
 	if (chip->substreams) {
 		spin_lock_irq(&chip->reg_lock);
 		spin_lock_irq(&chip->reg_lock);
 		for (i = 0; i < chip->num_substreams; i++) {
 		for (i = 0; i < chip->num_substreams; i++) {
@@ -2510,6 +2589,41 @@ static int m3_resume(struct pci_dev *pci)
 }
 }
 #endif /* CONFIG_PM */
 #endif /* CONFIG_PM */
 
 
+#ifdef CONFIG_SND_MAESTRO3_INPUT
+static int __devinit snd_m3_input_register(struct snd_m3 *chip)
+{
+	struct input_dev *input_dev;
+	int err;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+
+	snprintf(chip->phys, sizeof(chip->phys), "pci-%s/input0",
+		 pci_name(chip->pci));
+
+	input_dev->name = chip->card->driver;
+	input_dev->phys = chip->phys;
+	input_dev->id.bustype = BUS_PCI;
+	input_dev->id.vendor  = chip->pci->vendor;
+	input_dev->id.product = chip->pci->device;
+	input_dev->dev.parent = &chip->pci->dev;
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(KEY_MUTE, input_dev->keybit);
+	__set_bit(KEY_VOLUMEDOWN, input_dev->keybit);
+	__set_bit(KEY_VOLUMEUP, input_dev->keybit);
+
+	err = input_register_device(input_dev);
+	if (err) {
+		input_free_device(input_dev);
+		return err;
+	}
+
+	chip->input_dev = input_dev;
+	return 0;
+}
+#endif /* CONFIG_INPUT */
 
 
 /*
 /*
  */
  */
@@ -2553,7 +2667,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
 	}
 	}
 
 
 	spin_lock_init(&chip->reg_lock);
 	spin_lock_init(&chip->reg_lock);
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	spin_lock_init(&chip->ac97_lock);
 	spin_lock_init(&chip->ac97_lock);
+#endif
 
 
 	switch (pci->device) {
 	switch (pci->device) {
 	case PCI_DEVICE_ID_ESS_ALLEGRO:
 	case PCI_DEVICE_ID_ESS_ALLEGRO:
@@ -2636,7 +2752,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
 
 
 	snd_m3_hv_init(chip);
 	snd_m3_hv_init(chip);
 
 
+#ifndef CONFIG_SND_MAESTRO3_INPUT
 	tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
 	tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
+#endif
 
 
 	if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED,
 	if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED,
 			card->driver, chip)) {
 			card->driver, chip)) {
@@ -2668,7 +2786,16 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
 
 
 	if ((err = snd_m3_pcm(chip, 0)) < 0)
 	if ((err = snd_m3_pcm(chip, 0)) < 0)
 		return err;
 		return err;
-    
+
+#ifdef CONFIG_SND_MAESTRO3_INPUT
+	if (chip->hv_config & HV_CTRL_ENABLE) {
+		err = snd_m3_input_register(chip);
+		if (err)
+			snd_printk(KERN_WARNING "Input device registration "
+				"failed with error %i", err);
+	}
+#endif
+
 	snd_m3_enable_ints(chip);
 	snd_m3_enable_ints(chip);
 	snd_m3_assp_continue(chip);
 	snd_m3_assp_continue(chip);
 
 

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov