Browse Source

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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (214 commits)
  ALSA: hda - Add pin-fix for HP dc5750
  ALSA: als4000: Fix potentially invalid DMA mode setup
  ALSA: als4000: enable burst mode
  ALSA: hda - Fix initial capsrc selection in patch_alc269()
  ASoC: TWL4030: Capture route runtime DAPM ordering fix
  ALSA: hda - Add PC-beep whitelist for an Intel board
  ALSA: hda - More relax for pending period handling
  ALSA: hda - Define AC_FMT_* constants
  ALSA: hda - Fix beep frequency on IDT 92HD73xx and 92HD71Bxx codecs
  ALSA: hda - Add support for HDMI HBR passthrough
  ALSA: hda - Set Stream Type in Stream Format according to AES0
  ALSA: hda - Fix Thinkpad X300 so SPDIF is not exposed
  ALSA: hda - FIX to not expose SPDIF on Thinkpad X301, since it does not have the ability to use SPDIF
  ASoC: wm9081: fix resource reclaim in wm9081_register error path
  ASoC: wm8978: fix a memory leak if a wm8978_register fail
  ASoC: wm8974: fix a memory leak if another WM8974 is registered
  ASoC: wm8961: fix resource reclaim in wm8961_register error path
  ASoC: wm8955: fix resource reclaim in wm8955_register error path
  ASoC: wm8940: fix a memory leak if wm8940_register return error
  ASoC: wm8904: fix resource reclaim in wm8904_register error path
  ...
Linus Torvalds 15 years ago
parent
commit
faa38b5e0e
100 changed files with 3868 additions and 748 deletions
  1. 6 161
      Documentation/kernel-parameters.txt
  2. 6 0
      Documentation/sound/alsa/HD-Audio-Models.txt
  3. 8 0
      Documentation/sound/alsa/Procfile.txt
  4. 135 0
      Documentation/sound/alsa/alsa-parameters.txt
  5. 51 0
      Documentation/sound/oss/oss-parameters.txt
  6. 1 1
      arch/arm/mach-davinci/board-da830-evm.c
  7. 1 1
      arch/arm/mach-davinci/board-da850-evm.c
  8. 2 2
      arch/arm/mach-davinci/board-dm646x-evm.c
  9. 50 1
      arch/arm/mach-davinci/include/mach/asp.h
  10. 66 1
      arch/arm/mach-ep93xx/clock.c
  11. 67 0
      arch/arm/mach-ep93xx/core.c
  12. 10 0
      arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
  13. 3 0
      arch/arm/mach-ep93xx/include/mach/platform.h
  14. 1 0
      arch/arm/mach-ep93xx/snappercl15.c
  15. 38 0
      arch/arm/mach-kirkwood/common.c
  16. 2 0
      arch/arm/mach-kirkwood/common.h
  17. 3 0
      arch/arm/mach-kirkwood/include/mach/kirkwood.h
  18. 13 0
      arch/arm/mach-kirkwood/openrd-setup.c
  19. 5 5
      arch/arm/mach-omap2/mcbsp.c
  20. 3 0
      arch/arm/plat-mxc/include/mach/ssi.h
  21. 2 0
      arch/arm/plat-omap/include/plat/mcbsp.h
  22. 35 16
      arch/arm/plat-omap/mcbsp.c
  23. 11 0
      arch/arm/plat-orion/include/plat/audio.h
  24. 6 0
      arch/um/drivers/hostaudio_kern.c
  25. 3 3
      drivers/usb/gadget/f_audio.c
  26. 1 1
      drivers/usb/gadget/gmidi.c
  27. 16 1
      include/linux/usb/audio-v2.h
  28. 6 6
      include/linux/usb/audio.h
  29. 5 1
      include/sound/asound.h
  30. 5 1
      include/sound/pcm.h
  31. 43 6
      include/sound/sh_fsi.h
  32. 2 0
      include/sound/soc-dapm.h
  33. 21 0
      include/sound/soc.h
  34. 2 0
      include/sound/tlv320dac33-plat.h
  35. 12 0
      include/sound/uda134x.h
  36. 17 8
      sound/core/pcm_lib.c
  37. 16 0
      sound/core/pcm_misc.c
  38. 21 3
      sound/drivers/Kconfig
  39. 4 1
      sound/isa/msnd/msnd_pinnacle.c
  40. 6 3
      sound/isa/sb/emu8000_pcm.c
  41. 52 39
      sound/oss/au1550_ac97.c
  42. 50 13
      sound/oss/dmasound/dmasound_core.c
  43. 3 1
      sound/oss/midi_synth.c
  44. 24 11
      sound/oss/msnd_pinnacle.c
  45. 22 5
      sound/oss/sh_dac_audio.c
  46. 11 9
      sound/oss/soundcard.c
  47. 35 6
      sound/oss/swarm_cs4297a.c
  48. 0 3
      sound/oss/vidc.c
  49. 21 11
      sound/oss/vwsnd.c
  50. 2 8
      sound/oss/waveartist.c
  51. 2 2
      sound/pci/als4000.c
  52. 9 7
      sound/pci/asihpi/asihpi.c
  53. 48 20
      sound/pci/asihpi/hpi.h
  54. 7 0
      sound/pci/asihpi/hpi6000.c
  55. 22 18
      sound/pci/asihpi/hpi_internal.h
  56. 8 2
      sound/pci/asihpi/hpicmn.c
  57. 1 1
      sound/pci/asihpi/hpidebug.c
  58. 2 2
      sound/pci/asihpi/hpidebug.h
  59. 195 132
      sound/pci/asihpi/hpifunc.c
  60. 1 1
      sound/pci/asihpi/hpimsgx.c
  61. 14 7
      sound/pci/asihpi/hpioctl.c
  62. 2 0
      sound/pci/echoaudio/echoaudio.c
  63. 61 36
      sound/pci/hda/hda_codec.c
  64. 30 2
      sound/pci/hda/hda_codec.h
  65. 3 1
      sound/pci/hda/hda_hwdep.c
  66. 3 2
      sound/pci/hda/hda_intel.c
  67. 6 1
      sound/pci/hda/hda_proc.c
  68. 6 1
      sound/pci/hda/patch_analog.c
  69. 90 5
      sound/pci/hda/patch_conexant.c
  70. 42 1
      sound/pci/hda/patch_hdmi.c
  71. 1 2
      sound/pci/hda/patch_intelhdmi.c
  72. 1 2
      sound/pci/hda/patch_nvhdmi.c
  73. 627 92
      sound/pci/hda/patch_realtek.c
  74. 11 1
      sound/pci/hda/patch_sigmatel.c
  75. 25 7
      sound/pci/hda/patch_via.c
  76. 12 6
      sound/pci/riptide/riptide.c
  77. 9 7
      sound/pci/sis7019.c
  78. 7 2
      sound/pci/via82xx.c
  79. 4 0
      sound/soc/Kconfig
  80. 4 0
      sound/soc/Makefile
  81. 0 1
      sound/soc/atmel/atmel-pcm.c
  82. 0 1
      sound/soc/atmel/atmel_ssc_dai.c
  83. 5 8
      sound/soc/au1x/psc-ac97.c
  84. 5 8
      sound/soc/au1x/psc-i2s.c
  85. 0 1
      sound/soc/au1x/psc.h
  86. 2 4
      sound/soc/blackfin/bf5xx-ac97.c
  87. 2 4
      sound/soc/blackfin/bf5xx-tdm.c
  88. 16 4
      sound/soc/codecs/Kconfig
  89. 6 0
      sound/soc/codecs/Makefile
  90. 1 0
      sound/soc/codecs/ad1836.c
  91. 40 1
      sound/soc/codecs/ad193x.c
  92. 5 0
      sound/soc/codecs/ad193x.h
  93. 24 12
      sound/soc/codecs/ak4642.c
  94. 763 0
      sound/soc/codecs/cs42l51.c
  95. 163 0
      sound/soc/codecs/cs42l51.h
  96. 33 15
      sound/soc/codecs/da7210.c
  97. 511 0
      sound/soc/codecs/jz4740.c
  98. 20 0
      sound/soc/codecs/jz4740.h
  99. 93 1
      sound/soc/codecs/spdif_transciever.c
  100. 1 0
      sound/soc/codecs/spdif_transciever.h

+ 6 - 161
Documentation/kernel-parameters.txt

@@ -281,19 +281,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			no: ACPI OperationRegions are not marked as reserved,
 			no: ACPI OperationRegions are not marked as reserved,
 			no further checks are performed.
 			no further checks are performed.
 
 
-	ad1848=		[HW,OSS]
-			Format: <io>,<irq>,<dma>,<dma2>,<type>
-
 	add_efi_memmap	[EFI; X86] Include EFI memory map in
 	add_efi_memmap	[EFI; X86] Include EFI memory map in
 			kernel's map of available physical RAM.
 			kernel's map of available physical RAM.
 
 
 	advansys=	[HW,SCSI]
 	advansys=	[HW,SCSI]
 			See header of drivers/scsi/advansys.c.
 			See header of drivers/scsi/advansys.c.
 
 
-	aedsp16=	[HW,OSS] Audio Excel DSP 16
-			Format: <io>,<irq>,<dma>,<mss_io>,<mpu_io>,<mpu_irq>
-			See also header of sound/oss/aedsp16.c.
-
 	agp=		[AGP]
 	agp=		[AGP]
 			{ off | try_unsupported }
 			{ off | try_unsupported }
 			off: disable AGP support
 			off: disable AGP support
@@ -312,6 +305,9 @@ and is between 256 and 4096 characters. It is defined in the file
 	aic79xx=	[HW,SCSI]
 	aic79xx=	[HW,SCSI]
 			See Documentation/scsi/aic79xx.txt.
 			See Documentation/scsi/aic79xx.txt.
 
 
+	ALSA		[HW,ALSA]
+			See Documentation/sound/alsa/alsa-parameters.txt
+
 	alignment=	[KNL,ARM]
 	alignment=	[KNL,ARM]
 			Allow the default userspace alignment fault handler
 			Allow the default userspace alignment fault handler
 			behaviour to be specified.  Bit 0 enables warnings,
 			behaviour to be specified.  Bit 0 enables warnings,
@@ -656,8 +652,6 @@ and is between 256 and 4096 characters. It is defined in the file
 			Disable PIN 1 of APIC timer
 			Disable PIN 1 of APIC timer
 			Can be useful to work around chipset bugs.
 			Can be useful to work around chipset bugs.
 
 
-	dmasound=	[HW,OSS] Sound subsystem buffers
-
 	dma_debug=off	If the kernel is compiled with DMA_API_DEBUG support,
 	dma_debug=off	If the kernel is compiled with DMA_API_DEBUG support,
 			this option disables the debugging code at boot.
 			this option disables the debugging code at boot.
 
 
@@ -1527,9 +1521,6 @@ and is between 256 and 4096 characters. It is defined in the file
 			that the amount of memory usable for all allocations
 			that the amount of memory usable for all allocations
 			is not too small.
 			is not too small.
 
 
-	mpu401=		[HW,OSS]
-			Format: <io>,<irq>
-
 	MTD_Partition=	[MTD]
 	MTD_Partition=	[MTD]
 			Format: <name>,<region-number>,<size>,<offset>
 			Format: <name>,<region-number>,<size>,<offset>
 
 
@@ -1854,9 +1845,6 @@ and is between 256 and 4096 characters. It is defined in the file
 			For example, to override I2C bus2:
 			For example, to override I2C bus2:
 			omap_mux=i2c2_scl.i2c2_scl=0x100,i2c2_sda.i2c2_sda=0x100
 			omap_mux=i2c2_scl.i2c2_scl=0x100,i2c2_sda.i2c2_sda=0x100
 
 
-	opl3=		[HW,OSS]
-			Format: <io>
-
 	oprofile.timer=	[HW]
 	oprofile.timer=	[HW]
 			Use timer interrupt instead of performance counters
 			Use timer interrupt instead of performance counters
 
 
@@ -1868,6 +1856,9 @@ and is between 256 and 4096 characters. It is defined in the file
 				perfmon on Intel CPUs instead of the
 				perfmon on Intel CPUs instead of the
 				CPU specific event set.
 				CPU specific event set.
 
 
+	OSS		[HW,OSS]
+			See Documentation/sound/oss/oss-parameters.txt
+
 	osst=		[HW,SCSI] SCSI Tape Driver
 	osst=		[HW,SCSI] SCSI Tape Driver
 			Format: <buffer_size>,<write_threshold>
 			Format: <buffer_size>,<write_threshold>
 			See also Documentation/scsi/st.txt.
 			See also Documentation/scsi/st.txt.
@@ -1904,9 +1895,6 @@ and is between 256 and 4096 characters. It is defined in the file
 			Currently this function knows 686a and 8231 chips.
 			Currently this function knows 686a and 8231 chips.
 			Format: [spp|ps2|epp|ecp|ecpepp]
 			Format: [spp|ps2|epp|ecp|ecpepp]
 
 
-	pas2=		[HW,OSS] Format:
-			<io>,<irq>,<dma>,<dma16>,<sb_io>,<sb_irq>,<sb_dma>,<sb_dma16>
-
 	pas16=		[HW,SCSI]
 	pas16=		[HW,SCSI]
 			See header of drivers/scsi/pas16.c.
 			See header of drivers/scsi/pas16.c.
 
 
@@ -2178,10 +2166,6 @@ and is between 256 and 4096 characters. It is defined in the file
 			[HW,MOUSE] Controls Logitech smartscroll autorepeat.
 			[HW,MOUSE] Controls Logitech smartscroll autorepeat.
 			0 = disabled, 1 = enabled (default).
 			0 = disabled, 1 = enabled (default).
 
 
-	pss=		[HW,OSS] Personal Sound System (ECHO ESC614)
-			Format:
-			<io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq>
-
 	pt.		[PARIDE]
 	pt.		[PARIDE]
 			See Documentation/blockdev/paride.txt.
 			See Documentation/blockdev/paride.txt.
 
 
@@ -2397,128 +2381,6 @@ and is between 256 and 4096 characters. It is defined in the file
 				1: Fast pin select (default)
 				1: Fast pin select (default)
 				2: ATC IRMode
 				2: ATC IRMode
 
 
-	snd-ad1816a=	[HW,ALSA]
-
-	snd-ad1848=	[HW,ALSA]
-
-	snd-ali5451=	[HW,ALSA]
-
-	snd-als100=	[HW,ALSA]
-
-	snd-als4000=	[HW,ALSA]
-
-	snd-azt2320=	[HW,ALSA]
-
-	snd-cmi8330=	[HW,ALSA]
-
-	snd-cmipci=	[HW,ALSA]
-
-	snd-cs4231=	[HW,ALSA]
-
-	snd-cs4232=	[HW,ALSA]
-
-	snd-cs4236=	[HW,ALSA]
-
-	snd-cs4281=	[HW,ALSA]
-
-	snd-cs46xx=	[HW,ALSA]
-
-	snd-dt019x=	[HW,ALSA]
-
-	snd-dummy=	[HW,ALSA]
-
-	snd-emu10k1=	[HW,ALSA]
-
-	snd-ens1370=	[HW,ALSA]
-
-	snd-ens1371=	[HW,ALSA]
-
-	snd-es968=	[HW,ALSA]
-
-	snd-es1688=	[HW,ALSA]
-
-	snd-es18xx=	[HW,ALSA]
-
-	snd-es1938=	[HW,ALSA]
-
-	snd-es1968=	[HW,ALSA]
-
-	snd-fm801=	[HW,ALSA]
-
-	snd-gusclassic=	[HW,ALSA]
-
-	snd-gusextreme=	[HW,ALSA]
-
-	snd-gusmax=	[HW,ALSA]
-
-	snd-hdsp=	[HW,ALSA]
-
-	snd-ice1712=	[HW,ALSA]
-
-	snd-intel8x0=	[HW,ALSA]
-
-	snd-interwave=	[HW,ALSA]
-
-	snd-interwave-stb=
-			[HW,ALSA]
-
-	snd-korg1212=	[HW,ALSA]
-
-	snd-maestro3=	[HW,ALSA]
-
-	snd-mpu401=	[HW,ALSA]
-
-	snd-mtpav=	[HW,ALSA]
-
-	snd-nm256=	[HW,ALSA]
-
-	snd-opl3sa2=	[HW,ALSA]
-
-	snd-opti92x-ad1848=
-			[HW,ALSA]
-
-	snd-opti92x-cs4231=
-			[HW,ALSA]
-
-	snd-opti93x=	[HW,ALSA]
-
-	snd-pmac=	[HW,ALSA]
-
-	snd-rme32=	[HW,ALSA]
-
-	snd-rme96=	[HW,ALSA]
-
-	snd-rme9652=	[HW,ALSA]
-
-	snd-sb8=	[HW,ALSA]
-
-	snd-sb16=	[HW,ALSA]
-
-	snd-sbawe=	[HW,ALSA]
-
-	snd-serial=	[HW,ALSA]
-
-	snd-sgalaxy=	[HW,ALSA]
-
-	snd-sonicvibes=	[HW,ALSA]
-
-	snd-sun-amd7930=
-			[HW,ALSA]
-
-	snd-sun-cs4231=	[HW,ALSA]
-
-	snd-trident=	[HW,ALSA]
-
-	snd-usb-audio=	[HW,ALSA,USB]
-
-	snd-via82xx=	[HW,ALSA]
-
-	snd-virmidi=	[HW,ALSA]
-
-	snd-wavefront=	[HW,ALSA]
-
-	snd-ymfpci=	[HW,ALSA]
-
 	softlockup_panic=
 	softlockup_panic=
 			[KNL] Should the soft-lockup detector generate panics.
 			[KNL] Should the soft-lockup detector generate panics.
 
 
@@ -2533,9 +2395,6 @@ and is between 256 and 4096 characters. It is defined in the file
 	spia_pedr=
 	spia_pedr=
 	spia_peddr=
 	spia_peddr=
 
 
-	sscape=		[HW,OSS]
-			Format: <io>,<irq>,<dma>,<mpu_io>,<mpu_irq>
-
 	st=		[HW,SCSI] SCSI tape parameters (buffers, etc.)
 	st=		[HW,SCSI] SCSI tape parameters (buffers, etc.)
 			See Documentation/scsi/st.txt.
 			See Documentation/scsi/st.txt.
 
 
@@ -2675,10 +2534,6 @@ and is between 256 and 4096 characters. It is defined in the file
 			to facilitate early boot debugging.
 			to facilitate early boot debugging.
 			See also Documentation/trace/events.txt
 			See also Documentation/trace/events.txt
 
 
-	trix=		[HW,OSS] MediaTrix AudioTrix Pro
-			Format:
-			<io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
-
 	tsc=		Disable clocksource-must-verify flag for TSC.
 	tsc=		Disable clocksource-must-verify flag for TSC.
 			Format: <string>
 			Format: <string>
 			[x86] reliable: mark tsc clocksource as reliable, this
 			[x86] reliable: mark tsc clocksource as reliable, this
@@ -2695,12 +2550,6 @@ and is between 256 and 4096 characters. It is defined in the file
 	u14-34f=	[HW,SCSI] UltraStor 14F/34F SCSI host adapter
 	u14-34f=	[HW,SCSI] UltraStor 14F/34F SCSI host adapter
 			See header of drivers/scsi/u14-34f.c.
 			See header of drivers/scsi/u14-34f.c.
 
 
-	uart401=	[HW,OSS]
-			Format: <io>,<irq>
-
-	uart6850=	[HW,OSS]
-			Format: <io>,<irq>
-
 	uhash_entries=	[KNL,NET]
 	uhash_entries=	[KNL,NET]
 			Set number of hash buckets for UDP/UDP-Lite connections
 			Set number of hash buckets for UDP/UDP-Lite connections
 
 
@@ -2866,9 +2715,6 @@ and is between 256 and 4096 characters. It is defined in the file
 			overridden by individual drivers. 0 will hide
 			overridden by individual drivers. 0 will hide
 			cursors, 1 will display them.
 			cursors, 1 will display them.
 
 
-	waveartist=	[HW,OSS]
-			Format: <io>,<irq>,<dma>,<dma2>
-
 	wd33c93=	[HW,SCSI]
 	wd33c93=	[HW,SCSI]
 			See header of drivers/scsi/wd33c93.c.
 			See header of drivers/scsi/wd33c93.c.
 
 
@@ -2911,5 +2757,4 @@ ______________________________________________________________________
 
 
 TODO:
 TODO:
 
 
-	Add documentation for ALSA options.
 	Add more DRM drivers.
 	Add more DRM drivers.

+ 6 - 0
Documentation/sound/alsa/HD-Audio-Models.txt

@@ -114,6 +114,11 @@ ALC662/663/272
   samsung-nc10	Samsung NC10 mini notebook
   samsung-nc10	Samsung NC10 mini notebook
   auto		auto-config reading BIOS (default)
   auto		auto-config reading BIOS (default)
 
 
+ALC680
+======
+  base		Base model (ASUS NX90)
+  auto		auto-config reading BIOS (default)
+
 ALC882/883/885/888/889
 ALC882/883/885/888/889
 ======================
 ======================
   3stack-dig	3-jack with SPDIF I/O
   3stack-dig	3-jack with SPDIF I/O
@@ -282,6 +287,7 @@ Conexant 5051
   hp		HP Spartan laptop
   hp		HP Spartan laptop
   hp-dv6736	HP dv6736
   hp-dv6736	HP dv6736
   hp-f700	HP Compaq Presario F700
   hp-f700	HP Compaq Presario F700
+  ideapad	Lenovo IdeaPad laptop
   lenovo-x200	Lenovo X200 laptop
   lenovo-x200	Lenovo X200 laptop
   toshiba	Toshiba Satellite M300
   toshiba	Toshiba Satellite M300
 
 

+ 8 - 0
Documentation/sound/alsa/Procfile.txt

@@ -103,6 +103,8 @@ card*/pcm*/xrun_debug
 	  bit 2 = Enable additional jiffies check
 	  bit 2 = Enable additional jiffies check
 	  bit 3 = Log hwptr update at each period interrupt
 	  bit 3 = Log hwptr update at each period interrupt
 	  bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr()
 	  bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr()
+	  bit 5 = Show last 10 positions on error
+	  bit 6 = Do above only once
 
 
 	When the bit 0 is set, the driver will show the messages to
 	When the bit 0 is set, the driver will show the messages to
 	kernel log when an xrun is detected.  The debug message is
 	kernel log when an xrun is detected.  The debug message is
@@ -122,6 +124,12 @@ card*/pcm*/xrun_debug
 	Bits 3 and 4 are for logging the hwptr records.  Note that
 	Bits 3 and 4 are for logging the hwptr records.  Note that
 	these will give flood of kernel messages.
 	these will give flood of kernel messages.
 
 
+	When bit 5 is set, the driver logs the last 10 xrun errors and
+	the proc file shows each jiffies, position, period_size,
+	buffer_size, old_hw_ptr, and hw_ptr_base values.
+
+	When bit 6 is set, the full xrun log is shown only once.
+
 card*/pcm*/sub*/info
 card*/pcm*/sub*/info
 	The general information of this PCM sub-stream.
 	The general information of this PCM sub-stream.
 
 

+ 135 - 0
Documentation/sound/alsa/alsa-parameters.txt

@@ -0,0 +1,135 @@
+                          ALSA Kernel Parameters
+                          ~~~~~~~~~~~~~~~~~~~~~~
+
+See Documentation/kernel-parameters.txt for general information on
+specifying module parameters.
+
+This document may not be entirely up to date and comprehensive. The command
+"modinfo -p ${modulename}" shows a current list of all parameters of a loadable
+module. Loadable modules, after being loaded into the running kernel, also
+reveal their parameters in /sys/module/${modulename}/parameters/. Some of these
+parameters may be changed at runtime by the command
+"echo -n ${value} > /sys/module/${modulename}/parameters/${parm}".
+
+
+	snd-ad1816a=	[HW,ALSA]
+
+	snd-ad1848=	[HW,ALSA]
+
+	snd-ali5451=	[HW,ALSA]
+
+	snd-als100=	[HW,ALSA]
+
+	snd-als4000=	[HW,ALSA]
+
+	snd-azt2320=	[HW,ALSA]
+
+	snd-cmi8330=	[HW,ALSA]
+
+	snd-cmipci=	[HW,ALSA]
+
+	snd-cs4231=	[HW,ALSA]
+
+	snd-cs4232=	[HW,ALSA]
+
+	snd-cs4236=	[HW,ALSA]
+
+	snd-cs4281=	[HW,ALSA]
+
+	snd-cs46xx=	[HW,ALSA]
+
+	snd-dt019x=	[HW,ALSA]
+
+	snd-dummy=	[HW,ALSA]
+
+	snd-emu10k1=	[HW,ALSA]
+
+	snd-ens1370=	[HW,ALSA]
+
+	snd-ens1371=	[HW,ALSA]
+
+	snd-es968=	[HW,ALSA]
+
+	snd-es1688=	[HW,ALSA]
+
+	snd-es18xx=	[HW,ALSA]
+
+	snd-es1938=	[HW,ALSA]
+
+	snd-es1968=	[HW,ALSA]
+
+	snd-fm801=	[HW,ALSA]
+
+	snd-gusclassic=	[HW,ALSA]
+
+	snd-gusextreme=	[HW,ALSA]
+
+	snd-gusmax=	[HW,ALSA]
+
+	snd-hdsp=	[HW,ALSA]
+
+	snd-ice1712=	[HW,ALSA]
+
+	snd-intel8x0=	[HW,ALSA]
+
+	snd-interwave=	[HW,ALSA]
+
+	snd-interwave-stb=
+			[HW,ALSA]
+
+	snd-korg1212=	[HW,ALSA]
+
+	snd-maestro3=	[HW,ALSA]
+
+	snd-mpu401=	[HW,ALSA]
+
+	snd-mtpav=	[HW,ALSA]
+
+	snd-nm256=	[HW,ALSA]
+
+	snd-opl3sa2=	[HW,ALSA]
+
+	snd-opti92x-ad1848=
+			[HW,ALSA]
+
+	snd-opti92x-cs4231=
+			[HW,ALSA]
+
+	snd-opti93x=	[HW,ALSA]
+
+	snd-pmac=	[HW,ALSA]
+
+	snd-rme32=	[HW,ALSA]
+
+	snd-rme96=	[HW,ALSA]
+
+	snd-rme9652=	[HW,ALSA]
+
+	snd-sb8=	[HW,ALSA]
+
+	snd-sb16=	[HW,ALSA]
+
+	snd-sbawe=	[HW,ALSA]
+
+	snd-serial=	[HW,ALSA]
+
+	snd-sgalaxy=	[HW,ALSA]
+
+	snd-sonicvibes=	[HW,ALSA]
+
+	snd-sun-amd7930=
+			[HW,ALSA]
+
+	snd-sun-cs4231=	[HW,ALSA]
+
+	snd-trident=	[HW,ALSA]
+
+	snd-usb-audio=	[HW,ALSA,USB]
+
+	snd-via82xx=	[HW,ALSA]
+
+	snd-virmidi=	[HW,ALSA]
+
+	snd-wavefront=	[HW,ALSA]
+
+	snd-ymfpci=	[HW,ALSA]

+ 51 - 0
Documentation/sound/oss/oss-parameters.txt

@@ -0,0 +1,51 @@
+                          OSS Kernel Parameters
+                          ~~~~~~~~~~~~~~~~~~~~~
+
+See Documentation/kernel-parameters.txt for general information on
+specifying module parameters.
+
+This document may not be entirely up to date and comprehensive. The command
+"modinfo -p ${modulename}" shows a current list of all parameters of a loadable
+module. Loadable modules, after being loaded into the running kernel, also
+reveal their parameters in /sys/module/${modulename}/parameters/. Some of these
+parameters may be changed at runtime by the command
+"echo -n ${value} > /sys/module/${modulename}/parameters/${parm}".
+
+
+	ad1848=		[HW,OSS]
+			Format: <io>,<irq>,<dma>,<dma2>,<type>
+
+	aedsp16=	[HW,OSS] Audio Excel DSP 16
+			Format: <io>,<irq>,<dma>,<mss_io>,<mpu_io>,<mpu_irq>
+			See also header of sound/oss/aedsp16.c.
+
+	dmasound=	[HW,OSS] Sound subsystem buffers
+
+	mpu401=		[HW,OSS]
+			Format: <io>,<irq>
+
+	opl3=		[HW,OSS]
+			Format: <io>
+
+	pas2=		[HW,OSS] Format:
+			<io>,<irq>,<dma>,<dma16>,<sb_io>,<sb_irq>,<sb_dma>,<sb_dma16>
+
+	pss=		[HW,OSS] Personal Sound System (ECHO ESC614)
+			Format:
+			<io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq>
+
+	sscape=		[HW,OSS]
+			Format: <io>,<irq>,<dma>,<mpu_io>,<mpu_irq>
+
+	trix=		[HW,OSS] MediaTrix AudioTrix Pro
+			Format:
+			<io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
+
+	uart401=	[HW,OSS]
+			Format: <io>,<irq>
+
+	uart6850=	[HW,OSS]
+			Format: <io>,<irq>
+
+	waveartist=	[HW,OSS]
+			Format: <io>,<irq>,<dma>,<dma2>

+ 1 - 1
arch/arm/mach-davinci/board-da830-evm.c

@@ -208,7 +208,7 @@ static struct snd_platform_data da830_evm_snd_data = {
 	.num_serializer = ARRAY_SIZE(da830_iis_serializer_direction),
 	.num_serializer = ARRAY_SIZE(da830_iis_serializer_direction),
 	.tdm_slots      = 2,
 	.tdm_slots      = 2,
 	.serial_dir     = da830_iis_serializer_direction,
 	.serial_dir     = da830_iis_serializer_direction,
-	.eventq_no      = EVENTQ_0,
+	.asp_chan_q     = EVENTQ_0,
 	.version	= MCASP_VERSION_2,
 	.version	= MCASP_VERSION_2,
 	.txnumevt	= 1,
 	.txnumevt	= 1,
 	.rxnumevt	= 1,
 	.rxnumevt	= 1,

+ 1 - 1
arch/arm/mach-davinci/board-da850-evm.c

@@ -343,7 +343,7 @@ static struct snd_platform_data da850_evm_snd_data = {
 	.num_serializer	= ARRAY_SIZE(da850_iis_serializer_direction),
 	.num_serializer	= ARRAY_SIZE(da850_iis_serializer_direction),
 	.tdm_slots	= 2,
 	.tdm_slots	= 2,
 	.serial_dir	= da850_iis_serializer_direction,
 	.serial_dir	= da850_iis_serializer_direction,
-	.eventq_no	= EVENTQ_1,
+	.asp_chan_q	= EVENTQ_1,
 	.version	= MCASP_VERSION_2,
 	.version	= MCASP_VERSION_2,
 	.txnumevt	= 1,
 	.txnumevt	= 1,
 	.rxnumevt	= 1,
 	.rxnumevt	= 1,

+ 2 - 2
arch/arm/mach-davinci/board-dm646x-evm.c

@@ -323,7 +323,7 @@ static struct snd_platform_data dm646x_evm_snd_data[] = {
 		.num_serializer = ARRAY_SIZE(dm646x_iis_serializer_direction),
 		.num_serializer = ARRAY_SIZE(dm646x_iis_serializer_direction),
 		.tdm_slots      = 2,
 		.tdm_slots      = 2,
 		.serial_dir     = dm646x_iis_serializer_direction,
 		.serial_dir     = dm646x_iis_serializer_direction,
-		.eventq_no      = EVENTQ_0,
+		.asp_chan_q     = EVENTQ_0,
 	},
 	},
 	{
 	{
 		.tx_dma_offset  = 0x400,
 		.tx_dma_offset  = 0x400,
@@ -332,7 +332,7 @@ static struct snd_platform_data dm646x_evm_snd_data[] = {
 		.num_serializer = ARRAY_SIZE(dm646x_dit_serializer_direction),
 		.num_serializer = ARRAY_SIZE(dm646x_dit_serializer_direction),
 		.tdm_slots      = 32,
 		.tdm_slots      = 32,
 		.serial_dir     = dm646x_dit_serializer_direction,
 		.serial_dir     = dm646x_dit_serializer_direction,
-		.eventq_no      = EVENTQ_0,
+		.asp_chan_q     = EVENTQ_0,
 	},
 	},
 };
 };
 
 

+ 50 - 1
arch/arm/mach-davinci/include/mach/asp.h

@@ -52,7 +52,8 @@
 struct snd_platform_data {
 struct snd_platform_data {
 	u32 tx_dma_offset;
 	u32 tx_dma_offset;
 	u32 rx_dma_offset;
 	u32 rx_dma_offset;
-	enum dma_event_q eventq_no;	/* event queue number */
+	enum dma_event_q asp_chan_q;	/* event queue number for ASP channel */
+	enum dma_event_q ram_chan_q;	/* event queue number for RAM channel */
 	unsigned int codec_fmt;
 	unsigned int codec_fmt;
 	/*
 	/*
 	 * Allowing this is more efficient and eliminates left and right swaps
 	 * Allowing this is more efficient and eliminates left and right swaps
@@ -63,6 +64,49 @@ struct snd_platform_data {
 	unsigned sram_size_playback;
 	unsigned sram_size_playback;
 	unsigned sram_size_capture;
 	unsigned sram_size_capture;
 
 
+	/*
+	 * If McBSP peripheral gets the clock from an external pin,
+	 * there are three chooses, that are MCBSP_CLKX, MCBSP_CLKR
+	 * and MCBSP_CLKS.
+	 * Depending on different hardware connections it is possible
+	 * to use this setting to change the behaviour of McBSP
+	 * driver. The dm365_clk_input_pin enum is available for dm365
+	 */
+	int clk_input_pin;
+
+	/*
+	 * This flag works when both clock and FS are outputs for the cpu
+	 * and makes clock more accurate (FS is not symmetrical and the
+	 * clock is very fast.
+	 * The clock becoming faster is named
+	 * i2s continuous serial clock (I2S_SCK) and it is an externally
+	 * visible bit clock.
+	 *
+	 * first line : WordSelect
+	 * second line : ContinuousSerialClock
+	 * third line: SerialData
+	 *
+	 * SYMMETRICAL APPROACH:
+	 *   _______________________          LEFT
+	 * _|         RIGHT         |______________________|
+	 *     _   _         _   _   _   _         _   _
+	 *   _| |_| |_ x16 _| |_| |_| |_| |_ x16 _| |_| |_
+	 *     _   _         _   _   _   _         _   _
+	 *   _/ \_/ \_ ... _/ \_/ \_/ \_/ \_ ... _/ \_/ \_
+	 *    \_/ \_/       \_/ \_/ \_/ \_/       \_/ \_/
+	 *
+	 * ACCURATE CLOCK APPROACH:
+	 *   ______________          LEFT
+	 * _|     RIGHT    |_______________________________|
+	 *     _         _   _         _   _   _   _   _   _
+	 *   _| |_ x16 _| |_| |_ x16 _| |_| |_| |_| |_| |_| |
+	 *     _         _   _          _      dummy cycles
+	 *   _/ \_ ... _/ \_/ \_  ... _/ \__________________
+	 *    \_/       \_/ \_/        \_/
+	 *
+	 */
+	bool i2s_accurate_sck;
+
 	/* McASP specific fields */
 	/* McASP specific fields */
 	int tdm_slots;
 	int tdm_slots;
 	u8 op_mode;
 	u8 op_mode;
@@ -78,6 +122,11 @@ enum {
 	MCASP_VERSION_2,	/* DA8xx/OMAPL1x */
 	MCASP_VERSION_2,	/* DA8xx/OMAPL1x */
 };
 };
 
 
+enum dm365_clk_input_pin {
+	MCBSP_CLKR = 0,		/* DM365 */
+	MCBSP_CLKS,
+};
+
 #define INACTIVE_MODE	0
 #define INACTIVE_MODE	0
 #define TX_MODE		1
 #define TX_MODE		1
 #define RX_MODE		2
 #define RX_MODE		2

+ 66 - 1
arch/arm/mach-ep93xx/clock.c

@@ -43,7 +43,8 @@ static unsigned long get_uart_rate(struct clk *clk);
 
 
 static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
 static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
 static int set_div_rate(struct clk *clk, unsigned long rate);
 static int set_div_rate(struct clk *clk, unsigned long rate);
-
+static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate);
+static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate);
 
 
 static struct clk clk_xtali = {
 static struct clk clk_xtali = {
 	.rate		= EP93XX_EXT_CLK_RATE,
 	.rate		= EP93XX_EXT_CLK_RATE,
@@ -112,6 +113,29 @@ static struct clk clk_video = {
 	.set_rate	= set_div_rate,
 	.set_rate	= set_div_rate,
 };
 };
 
 
+static struct clk clk_i2s_mclk = {
+	.sw_locked	= 1,
+	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
+	.enable_mask	= EP93XX_SYSCON_CLKDIV_ENABLE,
+	.set_rate	= set_div_rate,
+};
+
+static struct clk clk_i2s_sclk = {
+	.sw_locked	= 1,
+	.parent		= &clk_i2s_mclk,
+	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
+	.enable_mask	= EP93XX_SYSCON_I2SCLKDIV_SENA,
+	.set_rate	= set_i2s_sclk_rate,
+};
+
+static struct clk clk_i2s_lrclk = {
+	.sw_locked	= 1,
+	.parent		= &clk_i2s_sclk,
+	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
+	.enable_mask	= EP93XX_SYSCON_I2SCLKDIV_SENA,
+	.set_rate	= set_i2s_lrclk_rate,
+};
+
 /* DMA Clocks */
 /* DMA Clocks */
 static struct clk clk_m2p0 = {
 static struct clk clk_m2p0 = {
 	.parent		= &clk_h,
 	.parent		= &clk_h,
@@ -191,6 +215,9 @@ static struct clk_lookup clocks[] = {
 	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
 	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
 	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
 	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
 	INIT_CK("ep93xx-spi.0",		NULL,		&clk_spi),
 	INIT_CK("ep93xx-spi.0",		NULL,		&clk_spi),
+	INIT_CK("ep93xx-i2s",		"mclk",		&clk_i2s_mclk),
+	INIT_CK("ep93xx-i2s",		"sclk",		&clk_i2s_sclk),
+	INIT_CK("ep93xx-i2s",		"lrclk",	&clk_i2s_lrclk),
 	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
 	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
 	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
 	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
 	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
 	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
@@ -401,6 +428,44 @@ static int set_div_rate(struct clk *clk, unsigned long rate)
 	return 0;
 	return 0;
 }
 }
 
 
+static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned val = __raw_readl(clk->enable_reg);
+
+	if (rate == clk_i2s_mclk.rate / 2)
+		ep93xx_syscon_swlocked_write(val & ~EP93XX_I2SCLKDIV_SDIV, 
+					     clk->enable_reg);
+	else if (rate == clk_i2s_mclk.rate / 4)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_SDIV, 
+					     clk->enable_reg);
+	else
+		return -EINVAL;
+
+	clk_i2s_sclk.rate = rate;
+	return 0;
+}
+
+static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned val = __raw_readl(clk->enable_reg) & 
+		~EP93XX_I2SCLKDIV_LRDIV_MASK;
+	
+	if (rate == clk_i2s_sclk.rate / 32)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV32,
+					     clk->enable_reg);
+	else if (rate == clk_i2s_sclk.rate / 64)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV64,
+					     clk->enable_reg);
+	else if (rate == clk_i2s_sclk.rate / 128)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV128,
+					     clk->enable_reg);
+	else
+		return -EINVAL;
+
+	clk_i2s_lrclk.rate = rate;
+	return 0;
+}
+
 int clk_set_rate(struct clk *clk, unsigned long rate)
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
 {
 	if (clk->set_rate)
 	if (clk->set_rate)

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

@@ -758,6 +758,73 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev)
 }
 }
 EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
 EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
 
 
+/*************************************************************************
+ * EP93xx I2S audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_i2s_resource[] = {
+	{
+		.start	= EP93XX_I2S_PHYS_BASE,
+		.end	= EP93XX_I2S_PHYS_BASE + 0x100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device ep93xx_i2s_device = {
+	.name		= "ep93xx-i2s",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_i2s_resource),
+	.resource	= ep93xx_i2s_resource,
+};
+
+void __init ep93xx_register_i2s(void)
+{
+	platform_device_register(&ep93xx_i2s_device);
+}
+
+#define EP93XX_SYSCON_DEVCFG_I2S_MASK	(EP93XX_SYSCON_DEVCFG_I2SONSSP | \
+					 EP93XX_SYSCON_DEVCFG_I2SONAC97)
+
+#define EP93XX_I2SCLKDIV_MASK		(EP93XX_SYSCON_I2SCLKDIV_ORIDE | \
+					 EP93XX_SYSCON_I2SCLKDIV_SPOL)
+
+int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config)
+{
+	unsigned val;
+
+	/* Sanity check */
+	if (i2s_pins & ~EP93XX_SYSCON_DEVCFG_I2S_MASK)
+		return -EINVAL;
+	if (i2s_config & ~EP93XX_I2SCLKDIV_MASK)
+		return -EINVAL;
+
+	/* Must have only one of I2SONSSP/I2SONAC97 set */
+	if ((i2s_pins & EP93XX_SYSCON_DEVCFG_I2SONSSP) ==
+	    (i2s_pins & EP93XX_SYSCON_DEVCFG_I2SONAC97))
+		return -EINVAL;
+
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK);
+	ep93xx_devcfg_set_bits(i2s_pins);
+
+	/*
+	 * This is potentially racy with the clock api for i2s_mclk, sclk and 
+	 * lrclk. Since the i2s driver is the only user of those clocks we
+	 * rely on it to prevent parallel use of this function and the 
+	 * clock api for the i2s clocks.
+	 */
+	val = __raw_readl(EP93XX_SYSCON_I2SCLKDIV);
+	val &= ~EP93XX_I2SCLKDIV_MASK;
+	val |= i2s_config;
+	ep93xx_syscon_swlocked_write(val, EP93XX_SYSCON_I2SCLKDIV);
+
+	return 0;
+}
+EXPORT_SYMBOL(ep93xx_i2s_acquire);
+
+void ep93xx_i2s_release(void)
+{
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK);
+}
+EXPORT_SYMBOL(ep93xx_i2s_release);
 
 
 extern void ep93xx_gpio_init(void);
 extern void ep93xx_gpio_init(void);
 
 

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

@@ -93,6 +93,7 @@
 /* APB peripherals */
 /* APB peripherals */
 #define EP93XX_TIMER_BASE		EP93XX_APB_IOMEM(0x00010000)
 #define EP93XX_TIMER_BASE		EP93XX_APB_IOMEM(0x00010000)
 
 
+#define EP93XX_I2S_PHYS_BASE		EP93XX_APB_PHYS(0x00020000)
 #define EP93XX_I2S_BASE			EP93XX_APB_IOMEM(0x00020000)
 #define EP93XX_I2S_BASE			EP93XX_APB_IOMEM(0x00020000)
 
 
 #define EP93XX_SECURITY_BASE		EP93XX_APB_IOMEM(0x00030000)
 #define EP93XX_SECURITY_BASE		EP93XX_APB_IOMEM(0x00030000)
@@ -194,6 +195,15 @@
 #define EP93XX_SYSCON_CLKDIV_ESEL	(1<<14)
 #define EP93XX_SYSCON_CLKDIV_ESEL	(1<<14)
 #define EP93XX_SYSCON_CLKDIV_PSEL	(1<<13)
 #define EP93XX_SYSCON_CLKDIV_PSEL	(1<<13)
 #define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT	8
 #define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT	8
+#define EP93XX_SYSCON_I2SCLKDIV		EP93XX_SYSCON_REG(0x8c)
+#define EP93XX_SYSCON_I2SCLKDIV_SENA	(1<<31)
+#define EP93XX_SYSCON_I2SCLKDIV_ORIDE   (1<<29)
+#define EP93XX_SYSCON_I2SCLKDIV_SPOL	(1<<19)
+#define EP93XX_I2SCLKDIV_SDIV		(1 << 16)
+#define EP93XX_I2SCLKDIV_LRDIV32	(0 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV64	(1 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV128 	(2 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV_MASK 	(3 << 17)
 #define EP93XX_SYSCON_KEYTCHCLKDIV	EP93XX_SYSCON_REG(0x90)
 #define EP93XX_SYSCON_KEYTCHCLKDIV	EP93XX_SYSCON_REG(0x90)
 #define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN	(1<<31)
 #define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN	(1<<31)
 #define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV	(1<<16)
 #define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV	(1<<16)

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

@@ -58,6 +58,9 @@ void ep93xx_pwm_release_gpio(struct platform_device *pdev);
 void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
 void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
 int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
 int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
 void ep93xx_keypad_release_gpio(struct platform_device *pdev);
 void ep93xx_keypad_release_gpio(struct platform_device *pdev);
+void ep93xx_register_i2s(void);
+int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
+void ep93xx_i2s_release(void);
 
 
 void ep93xx_init_devices(void);
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
 extern struct sys_timer ep93xx_timer;

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

@@ -157,6 +157,7 @@ static void __init snappercl15_init_machine(void)
 	ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data,
 	ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data,
 			    ARRAY_SIZE(snappercl15_i2c_data));
 			    ARRAY_SIZE(snappercl15_i2c_data));
 	ep93xx_register_fb(&snappercl15_fb_info);
 	ep93xx_register_fb(&snappercl15_fb_info);
+	ep93xx_register_i2s();
 	platform_device_register(&snappercl15_nand_device);
 	platform_device_register(&snappercl15_nand_device);
 }
 }
 
 

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

@@ -25,6 +25,7 @@
 #include <asm/mach/time.h>
 #include <asm/mach/time.h>
 #include <mach/kirkwood.h>
 #include <mach/kirkwood.h>
 #include <mach/bridge-regs.h>
 #include <mach/bridge-regs.h>
+#include <plat/audio.h>
 #include <plat/cache-feroceon-l2.h>
 #include <plat/cache-feroceon-l2.h>
 #include <plat/ehci-orion.h>
 #include <plat/ehci-orion.h>
 #include <plat/mvsdio.h>
 #include <plat/mvsdio.h>
@@ -871,6 +872,42 @@ struct sys_timer kirkwood_timer = {
 	.init = kirkwood_timer_init,
 	.init = kirkwood_timer_init,
 };
 };
 
 
+/*****************************************************************************
+ * Audio
+ ****************************************************************************/
+static struct resource kirkwood_i2s_resources[] = {
+	[0] = {
+		.start  = AUDIO_PHYS_BASE,
+		.end    = AUDIO_PHYS_BASE + SZ_16K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = IRQ_KIRKWOOD_I2S,
+		.end    = IRQ_KIRKWOOD_I2S,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
+	.dram        = &kirkwood_mbus_dram_info,
+	.burst       = 128,
+};
+
+static struct platform_device kirkwood_i2s_device = {
+	.name		= "kirkwood-i2s",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(kirkwood_i2s_resources),
+	.resource	= kirkwood_i2s_resources,
+	.dev		= {
+		.platform_data	= &kirkwood_i2s_data,
+	},
+};
+
+void __init kirkwood_audio_init(void)
+{
+	kirkwood_clk_ctrl |= CGC_AUDIO;
+	platform_device_register(&kirkwood_i2s_device);
+}
 
 
 /*****************************************************************************
 /*****************************************************************************
  * General
  * General
@@ -939,6 +976,7 @@ void __init kirkwood_init(void)
 	kirkwood_spi_plat_data.tclk = kirkwood_tclk;
 	kirkwood_spi_plat_data.tclk = kirkwood_tclk;
 	kirkwood_uart0_data[0].uartclk = kirkwood_tclk;
 	kirkwood_uart0_data[0].uartclk = kirkwood_tclk;
 	kirkwood_uart1_data[0].uartclk = kirkwood_tclk;
 	kirkwood_uart1_data[0].uartclk = kirkwood_tclk;
+	kirkwood_i2s_data.tclk = kirkwood_tclk;
 
 
 	/*
 	/*
 	 * Disable propagation of mbus errors to the CPU local bus,
 	 * Disable propagation of mbus errors to the CPU local bus,

+ 2 - 0
arch/arm/mach-kirkwood/common.h

@@ -17,6 +17,7 @@ struct mv_sata_platform_data;
 struct mvsdio_platform_data;
 struct mvsdio_platform_data;
 struct mtd_partition;
 struct mtd_partition;
 struct mtd_info;
 struct mtd_info;
+struct kirkwood_asoc_platform_data;
 
 
 #define KW_PCIE0	(1 << 0)
 #define KW_PCIE0	(1 << 0)
 #define KW_PCIE1	(1 << 1)
 #define KW_PCIE1	(1 << 1)
@@ -46,6 +47,7 @@ void kirkwood_uart0_init(void);
 void kirkwood_uart1_init(void);
 void kirkwood_uart1_init(void);
 void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
 void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
 void kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *));
 void kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *));
+void kirkwood_audio_init(void);
 
 
 extern int kirkwood_tclk;
 extern int kirkwood_tclk;
 extern struct sys_timer kirkwood_timer;
 extern struct sys_timer kirkwood_timer;

+ 3 - 0
arch/arm/mach-kirkwood/include/mach/kirkwood.h

@@ -111,6 +111,9 @@
 
 
 #define SDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0x90000)
 #define SDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0x90000)
 
 
+#define AUDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0xA0000)
+#define AUDIO_VIRT_BASE		(KIRKWOOD_REGS_VIRT_BASE | 0xA0000)
+
 /*
 /*
  * Supported devices and revisions.
  * Supported devices and revisions.
  */
  */

+ 13 - 0
arch/arm/mach-kirkwood/openrd-setup.c

@@ -15,6 +15,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/partitions.h>
 #include <linux/ata_platform.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/mv643xx_eth.h>
+#include <linux/i2c.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
 #include <mach/kirkwood.h>
@@ -60,6 +61,12 @@ static unsigned int openrd_mpp_config[] __initdata = {
 	0
 	0
 };
 };
 
 
+static struct i2c_board_info i2c_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("cs42l51", 0x4a),
+	},
+};
+
 static void __init openrd_init(void)
 static void __init openrd_init(void)
 {
 {
 	/*
 	/*
@@ -86,6 +93,12 @@ static void __init openrd_init(void)
 	kirkwood_sdio_init(&openrd_mvsdio_data);
 	kirkwood_sdio_init(&openrd_mvsdio_data);
 
 
 	kirkwood_i2c_init();
 	kirkwood_i2c_init();
+
+	if (machine_is_openrd_client()) {
+		i2c_register_board_info(0, i2c_board_info,
+			ARRAY_SIZE(i2c_board_info));
+		kirkwood_audio_init();
+	}
 }
 }
 
 
 static int __init openrd_pci_init(void)
 static int __init openrd_pci_init(void)

+ 5 - 5
arch/arm/mach-omap2/mcbsp.c

@@ -133,7 +133,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
 		.rx_irq		= INT_24XX_MCBSP1_IRQ_RX,
 		.rx_irq		= INT_24XX_MCBSP1_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP1_IRQ_TX,
 		.tx_irq		= INT_24XX_MCBSP1_IRQ_TX,
 		.ops		= &omap2_mcbsp_ops,
 		.ops		= &omap2_mcbsp_ops,
-		.buffer_size	= 0x6F,
+		.buffer_size	= 0x80, /* The FIFO has 128 locations */
 	},
 	},
 	{
 	{
 		.phys_base	= OMAP34XX_MCBSP2_BASE,
 		.phys_base	= OMAP34XX_MCBSP2_BASE,
@@ -143,7 +143,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
 		.rx_irq		= INT_24XX_MCBSP2_IRQ_RX,
 		.rx_irq		= INT_24XX_MCBSP2_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP2_IRQ_TX,
 		.tx_irq		= INT_24XX_MCBSP2_IRQ_TX,
 		.ops		= &omap2_mcbsp_ops,
 		.ops		= &omap2_mcbsp_ops,
-		.buffer_size	= 0x3FF,
+		.buffer_size	= 0x500, /* The FIFO has 1024 + 256 locations */
 	},
 	},
 	{
 	{
 		.phys_base	= OMAP34XX_MCBSP3_BASE,
 		.phys_base	= OMAP34XX_MCBSP3_BASE,
@@ -153,7 +153,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
 		.rx_irq		= INT_24XX_MCBSP3_IRQ_RX,
 		.rx_irq		= INT_24XX_MCBSP3_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP3_IRQ_TX,
 		.tx_irq		= INT_24XX_MCBSP3_IRQ_TX,
 		.ops		= &omap2_mcbsp_ops,
 		.ops		= &omap2_mcbsp_ops,
-		.buffer_size	= 0x6F,
+		.buffer_size	= 0x80, /* The FIFO has 128 locations */
 	},
 	},
 	{
 	{
 		.phys_base	= OMAP34XX_MCBSP4_BASE,
 		.phys_base	= OMAP34XX_MCBSP4_BASE,
@@ -162,7 +162,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
 		.rx_irq		= INT_24XX_MCBSP4_IRQ_RX,
 		.rx_irq		= INT_24XX_MCBSP4_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP4_IRQ_TX,
 		.tx_irq		= INT_24XX_MCBSP4_IRQ_TX,
 		.ops		= &omap2_mcbsp_ops,
 		.ops		= &omap2_mcbsp_ops,
-		.buffer_size	= 0x6F,
+		.buffer_size	= 0x80, /* The FIFO has 128 locations */
 	},
 	},
 	{
 	{
 		.phys_base	= OMAP34XX_MCBSP5_BASE,
 		.phys_base	= OMAP34XX_MCBSP5_BASE,
@@ -171,7 +171,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
 		.rx_irq		= INT_24XX_MCBSP5_IRQ_RX,
 		.rx_irq		= INT_24XX_MCBSP5_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP5_IRQ_TX,
 		.tx_irq		= INT_24XX_MCBSP5_IRQ_TX,
 		.ops		= &omap2_mcbsp_ops,
 		.ops		= &omap2_mcbsp_ops,
-		.buffer_size	= 0x6F,
+		.buffer_size	= 0x80, /* The FIFO has 128 locations */
 	},
 	},
 };
 };
 #define OMAP34XX_MCBSP_PDATA_SZ		ARRAY_SIZE(omap34xx_mcbsp_pdata)
 #define OMAP34XX_MCBSP_PDATA_SZ		ARRAY_SIZE(omap34xx_mcbsp_pdata)

+ 3 - 0
arch/arm/plat-mxc/include/mach/ssi.h

@@ -10,6 +10,9 @@ struct imx_ssi_platform_data {
 	unsigned int flags;
 	unsigned int flags;
 #define IMX_SSI_DMA            (1 << 0)
 #define IMX_SSI_DMA            (1 << 0)
 #define IMX_SSI_USE_AC97       (1 << 1)
 #define IMX_SSI_USE_AC97       (1 << 1)
+#define IMX_SSI_NET            (1 << 2)
+#define IMX_SSI_SYN            (1 << 3)
+#define IMX_SSI_USE_I2S_SLAVE  (1 << 4)
 	void (*ac97_reset) (struct snd_ac97 *ac97);
 	void (*ac97_reset) (struct snd_ac97 *ac97);
 	void (*ac97_warm_reset)(struct snd_ac97 *ac97);
 	void (*ac97_warm_reset)(struct snd_ac97 *ac97);
 };
 };

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

@@ -473,6 +473,7 @@ 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_fifo_size(unsigned int id);
 u16 omap_mcbsp_get_tx_delay(unsigned int id);
 u16 omap_mcbsp_get_tx_delay(unsigned int id);
 u16 omap_mcbsp_get_rx_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);
@@ -483,6 +484,7 @@ 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_fifo_size(unsigned int id) { return 0; }
 static inline u16 omap_mcbsp_get_tx_delay(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 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; }

+ 35 - 16
arch/arm/plat-omap/mcbsp.c

@@ -481,9 +481,9 @@ int omap_st_is_enabled(unsigned int id)
 EXPORT_SYMBOL(omap_st_is_enabled);
 EXPORT_SYMBOL(omap_st_is_enabled);
 
 
 /*
 /*
- * omap_mcbsp_set_tx_threshold configures how to deal
- * with transmit threshold. the threshold value and handler can be
- * configure in here.
+ * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH2 register.
  */
  */
 void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
 void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
 {
 {
@@ -498,14 +498,15 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
 	}
 	}
 	mcbsp = id_to_mcbsp_ptr(id);
 	mcbsp = id_to_mcbsp_ptr(id);
 
 
-	MCBSP_WRITE(mcbsp, THRSH2, threshold);
+	if (threshold && threshold <= mcbsp->max_tx_thres)
+		MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
 }
 }
 EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold);
 EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold);
 
 
 /*
 /*
- * omap_mcbsp_set_rx_threshold configures how to deal
- * with receive threshold. the threshold value and handler can be
- * configure in here.
+ * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH1 register.
  */
  */
 void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
 void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
 {
 {
@@ -520,7 +521,8 @@ void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
 	}
 	}
 	mcbsp = id_to_mcbsp_ptr(id);
 	mcbsp = id_to_mcbsp_ptr(id);
 
 
-	MCBSP_WRITE(mcbsp, THRSH1, threshold);
+	if (threshold && threshold <= mcbsp->max_rx_thres)
+		MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
 }
 }
 EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold);
 EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold);
 
 
@@ -560,8 +562,20 @@ 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 */
+u16 omap_mcbsp_get_fifo_size(unsigned int id)
+{
+	struct omap_mcbsp *mcbsp;
+
+	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);
+
+	return mcbsp->pdata->buffer_size;
+}
+EXPORT_SYMBOL(omap_mcbsp_get_fifo_size);
+
 /*
 /*
  * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
  * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
  */
  */
@@ -580,10 +594,7 @@ u16 omap_mcbsp_get_tx_delay(unsigned int id)
 	buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
 	buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
 
 
 	/* Number of slots are different in McBSP ports */
 	/* Number of slots are different in McBSP ports */
-	if (mcbsp->id == 2)
-		return MCBSP2_FIFO_SIZE - buffstat;
-	else
-		return MCBSP1345_FIFO_SIZE - buffstat;
+	return mcbsp->pdata->buffer_size - buffstat;
 }
 }
 EXPORT_SYMBOL(omap_mcbsp_get_tx_delay);
 EXPORT_SYMBOL(omap_mcbsp_get_tx_delay);
 
 
@@ -1683,8 +1694,16 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp)
 {
 {
 	mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
 	mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
 	if (cpu_is_omap34xx()) {
 	if (cpu_is_omap34xx()) {
-		mcbsp->max_tx_thres = max_thres(mcbsp);
-		mcbsp->max_rx_thres = max_thres(mcbsp);
+		/*
+		 * Initially configure the maximum thresholds to a safe value.
+		 * The McBSP FIFO usage with these values should not go under
+		 * 16 locations.
+		 * If the whole FIFO without safety buffer is used, than there
+		 * is a possibility that the DMA will be not able to push the
+		 * new data on time, causing channel shifts in runtime.
+		 */
+		mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
+		mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
 		/*
 		/*
 		 * REVISIT: Set dmap_op_mode to THRESHOLD as default
 		 * REVISIT: Set dmap_op_mode to THRESHOLD as default
 		 * for mcbsp2 instances.
 		 * for mcbsp2 instances.

+ 11 - 0
arch/arm/plat-orion/include/plat/audio.h

@@ -0,0 +1,11 @@
+#ifndef __PLAT_AUDIO_H
+#define __PLAT_AUDIO_H
+
+#include <linux/mbus.h>
+
+struct kirkwood_asoc_platform_data {
+	u32 tclk;
+	struct mbus_dram_target_info *dram;
+	int burst;
+};
+#endif

+ 6 - 0
arch/um/drivers/hostaudio_kern.c

@@ -8,6 +8,7 @@
 #include "linux/slab.h"
 #include "linux/slab.h"
 #include "linux/sound.h"
 #include "linux/sound.h"
 #include "linux/soundcard.h"
 #include "linux/soundcard.h"
+#include "linux/smp_lock.h"
 #include "asm/uaccess.h"
 #include "asm/uaccess.h"
 #include "init.h"
 #include "init.h"
 #include "os.h"
 #include "os.h"
@@ -198,7 +199,10 @@ static int hostaudio_open(struct inode *inode, struct file *file)
 	if (file->f_mode & FMODE_WRITE)
 	if (file->f_mode & FMODE_WRITE)
 		w = 1;
 		w = 1;
 
 
+	lock_kernel();
 	ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
 	ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
+	unlock_kernel();
+
 	if (ret < 0) {
 	if (ret < 0) {
 		kfree(state);
 		kfree(state);
 		return ret;
 		return ret;
@@ -254,7 +258,9 @@ static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
 	if (file->f_mode & FMODE_WRITE)
 	if (file->f_mode & FMODE_WRITE)
 		w = 1;
 		w = 1;
 
 
+	lock_kernel();
 	ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
 	ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
+	unlock_kernel();
 
 
 	if (ret < 0) {
 	if (ret < 0) {
 		printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', "
 		printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', "

+ 3 - 3
drivers/usb/gadget/f_audio.c

@@ -61,7 +61,7 @@ DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
 #define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
 #define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
 	+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
 	+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
 /* B.3.2  Class-Specific AC Interface Descriptor */
 /* B.3.2  Class-Specific AC Interface Descriptor */
-static struct uac_ac_header_descriptor_v1_2 ac_header_desc = {
+static struct uac1_ac_header_descriptor_2 ac_header_desc = {
 	.bLength =		UAC_DT_AC_HEADER_LENGTH,
 	.bLength =		UAC_DT_AC_HEADER_LENGTH,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubtype =	UAC_HEADER,
 	.bDescriptorSubtype =	UAC_HEADER,
@@ -125,7 +125,7 @@ static struct usb_audio_control_selector feature_unit = {
 };
 };
 
 
 #define OUTPUT_TERMINAL_ID	3
 #define OUTPUT_TERMINAL_ID	3
-static struct uac_output_terminal_descriptor_v1 output_terminal_desc = {
+static struct uac1_output_terminal_descriptor output_terminal_desc = {
 	.bLength		= UAC_DT_OUTPUT_TERMINAL_SIZE,
 	.bLength		= UAC_DT_OUTPUT_TERMINAL_SIZE,
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
 	.bDescriptorSubtype	= UAC_OUTPUT_TERMINAL,
 	.bDescriptorSubtype	= UAC_OUTPUT_TERMINAL,
@@ -155,7 +155,7 @@ static struct usb_interface_descriptor as_interface_alt_1_desc = {
 };
 };
 
 
 /* B.4.2  Class-Specific AS Interface Descriptor */
 /* B.4.2  Class-Specific AS Interface Descriptor */
-static struct uac_as_header_descriptor_v1 as_header_desc = {
+static struct uac1_as_header_descriptor as_header_desc = {
 	.bLength =		UAC_DT_AS_HEADER_SIZE,
 	.bLength =		UAC_DT_AS_HEADER_SIZE,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubtype =	UAC_AS_GENERAL,
 	.bDescriptorSubtype =	UAC_AS_GENERAL,

+ 1 - 1
drivers/usb/gadget/gmidi.c

@@ -238,7 +238,7 @@ static const struct usb_interface_descriptor ac_interface_desc = {
 };
 };
 
 
 /* B.3.2  Class-Specific AC Interface Descriptor */
 /* B.3.2  Class-Specific AC Interface Descriptor */
-static const struct uac_ac_header_descriptor_v1_1 ac_header_desc = {
+static const struct uac1_ac_header_descriptor_1 ac_header_desc = {
 	.bLength =		UAC_DT_AC_HEADER_SIZE(1),
 	.bLength =		UAC_DT_AC_HEADER_SIZE(1),
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubtype =	USB_MS_HEADER,
 	.bDescriptorSubtype =	USB_MS_HEADER,

+ 16 - 1
include/linux/usb/audio-v2.h

@@ -18,6 +18,21 @@
 /* v1.0 and v2.0 of this standard have many things in common. For the rest
 /* v1.0 and v2.0 of this standard have many things in common. For the rest
  * of the definitions, please refer to audio.h */
  * of the definitions, please refer to audio.h */
 
 
+/*
+ * bmControl field decoders
+ *
+ * From the USB Audio spec v2.0:
+ *
+ *   bmaControls() is a (ch+1)-element array of 4-byte bitmaps,
+ *   each containing a set of bit pairs. If a Control is present,
+ *   it must be Host readable. If a certain Control is not
+ *   present then the bit pair must be set to 0b00.
+ *   If a Control is present but read-only, the bit pair must be
+ *   set to 0b01. If a Control is also Host programmable, the bit
+ *   pair must be set to 0b11. The value 0b10 is not allowed.
+ *
+ */
+
 static inline bool uac2_control_is_readable(u32 bmControls, u8 control)
 static inline bool uac2_control_is_readable(u32 bmControls, u8 control)
 {
 {
 	return (bmControls >> (control * 2)) & 0x1;
 	return (bmControls >> (control * 2)) & 0x1;
@@ -121,7 +136,7 @@ struct uac2_feature_unit_descriptor {
 
 
 /* 4.9.2 Class-Specific AS Interface Descriptor */
 /* 4.9.2 Class-Specific AS Interface Descriptor */
 
 
-struct uac_as_header_descriptor_v2 {
+struct uac2_as_header_descriptor {
 	__u8 bLength;
 	__u8 bLength;
 	__u8 bDescriptorType;
 	__u8 bDescriptorType;
 	__u8 bDescriptorSubtype;
 	__u8 bDescriptorSubtype;

+ 6 - 6
include/linux/usb/audio.h

@@ -39,8 +39,8 @@
 #define UAC_MIXER_UNIT			0x04
 #define UAC_MIXER_UNIT			0x04
 #define UAC_SELECTOR_UNIT		0x05
 #define UAC_SELECTOR_UNIT		0x05
 #define UAC_FEATURE_UNIT		0x06
 #define UAC_FEATURE_UNIT		0x06
-#define UAC_PROCESSING_UNIT_V1		0x07
-#define UAC_EXTENSION_UNIT_V1		0x08
+#define UAC1_PROCESSING_UNIT		0x07
+#define UAC1_EXTENSION_UNIT		0x08
 
 
 /* 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
@@ -151,7 +151,7 @@
 
 
 /* Terminal Control Selectors */
 /* Terminal Control Selectors */
 /* 4.3.2  Class-Specific AC Interface Descriptor */
 /* 4.3.2  Class-Specific AC Interface Descriptor */
-struct uac_ac_header_descriptor_v1 {
+struct uac1_ac_header_descriptor {
 	__u8  bLength;			/* 8 + n */
 	__u8  bLength;			/* 8 + n */
 	__u8  bDescriptorType;		/* USB_DT_CS_INTERFACE */
 	__u8  bDescriptorType;		/* USB_DT_CS_INTERFACE */
 	__u8  bDescriptorSubtype;	/* UAC_MS_HEADER */
 	__u8  bDescriptorSubtype;	/* UAC_MS_HEADER */
@@ -165,7 +165,7 @@ struct uac_ac_header_descriptor_v1 {
 
 
 /* As above, but more useful for defining your own descriptors: */
 /* As above, but more useful for defining your own descriptors: */
 #define DECLARE_UAC_AC_HEADER_DESCRIPTOR(n)			\
 #define DECLARE_UAC_AC_HEADER_DESCRIPTOR(n)			\
-struct uac_ac_header_descriptor_v1_##n {			\
+struct uac1_ac_header_descriptor_##n {			\
 	__u8  bLength;						\
 	__u8  bLength;						\
 	__u8  bDescriptorType;					\
 	__u8  bDescriptorType;					\
 	__u8  bDescriptorSubtype;				\
 	__u8  bDescriptorSubtype;				\
@@ -205,7 +205,7 @@ struct uac_input_terminal_descriptor {
 #define UAC_TERMINAL_CS_COPY_PROTECT_CONTROL		0x01
 #define UAC_TERMINAL_CS_COPY_PROTECT_CONTROL		0x01
 
 
 /* 4.3.2.2 Output Terminal Descriptor */
 /* 4.3.2.2 Output Terminal Descriptor */
-struct uac_output_terminal_descriptor_v1 {
+struct uac1_output_terminal_descriptor {
 	__u8  bLength;			/* in bytes: 9 */
 	__u8  bLength;			/* in bytes: 9 */
 	__u8  bDescriptorType;		/* CS_INTERFACE descriptor type */
 	__u8  bDescriptorType;		/* CS_INTERFACE descriptor type */
 	__u8  bDescriptorSubtype;	/* OUTPUT_TERMINAL descriptor subtype */
 	__u8  bDescriptorSubtype;	/* OUTPUT_TERMINAL descriptor subtype */
@@ -395,7 +395,7 @@ static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_desc
 }
 }
 
 
 /* 4.5.2 Class-Specific AS Interface Descriptor */
 /* 4.5.2 Class-Specific AS Interface Descriptor */
-struct uac_as_header_descriptor_v1 {
+struct uac1_as_header_descriptor {
 	__u8  bLength;			/* in bytes: 7 */
 	__u8  bLength;			/* in bytes: 7 */
 	__u8  bDescriptorType;		/* USB_DT_CS_INTERFACE */
 	__u8  bDescriptorType;		/* USB_DT_CS_INTERFACE */
 	__u8  bDescriptorSubtype;	/* AS_GENERAL */
 	__u8  bDescriptorSubtype;	/* AS_GENERAL */

+ 5 - 1
include/sound/asound.h

@@ -212,7 +212,11 @@ typedef int __bitwise snd_pcm_format_t;
 #define	SNDRV_PCM_FORMAT_S18_3BE	((__force snd_pcm_format_t) 41)	/* in three bytes */
 #define	SNDRV_PCM_FORMAT_S18_3BE	((__force snd_pcm_format_t) 41)	/* in three bytes */
 #define	SNDRV_PCM_FORMAT_U18_3LE	((__force snd_pcm_format_t) 42)	/* in three bytes */
 #define	SNDRV_PCM_FORMAT_U18_3LE	((__force snd_pcm_format_t) 42)	/* in three bytes */
 #define	SNDRV_PCM_FORMAT_U18_3BE	((__force snd_pcm_format_t) 43)	/* in three bytes */
 #define	SNDRV_PCM_FORMAT_U18_3BE	((__force snd_pcm_format_t) 43)	/* in three bytes */
-#define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_U18_3BE
+#define	SNDRV_PCM_FORMAT_G723_24	((__force snd_pcm_format_t) 44) /* 8 samples in 3 bytes */
+#define	SNDRV_PCM_FORMAT_G723_24_1B	((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */
+#define	SNDRV_PCM_FORMAT_G723_40	((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */
+#define	SNDRV_PCM_FORMAT_G723_40_1B	((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
+#define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_G723_40_1B
 
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #ifdef SNDRV_LITTLE_ENDIAN
 #define	SNDRV_PCM_FORMAT_S16		SNDRV_PCM_FORMAT_S16_LE
 #define	SNDRV_PCM_FORMAT_S16		SNDRV_PCM_FORMAT_S16_LE

+ 5 - 1
include/sound/pcm.h

@@ -174,6 +174,10 @@ struct snd_pcm_ops {
 #define SNDRV_PCM_FMTBIT_U18_3LE	(1ULL << SNDRV_PCM_FORMAT_U18_3LE)
 #define SNDRV_PCM_FMTBIT_U18_3LE	(1ULL << SNDRV_PCM_FORMAT_U18_3LE)
 #define SNDRV_PCM_FMTBIT_S18_3BE	(1ULL << SNDRV_PCM_FORMAT_S18_3BE)
 #define SNDRV_PCM_FMTBIT_S18_3BE	(1ULL << SNDRV_PCM_FORMAT_S18_3BE)
 #define SNDRV_PCM_FMTBIT_U18_3BE	(1ULL << SNDRV_PCM_FORMAT_U18_3BE)
 #define SNDRV_PCM_FMTBIT_U18_3BE	(1ULL << SNDRV_PCM_FORMAT_U18_3BE)
+#define SNDRV_PCM_FMTBIT_G723_24	(1ULL << SNDRV_PCM_FORMAT_G723_24)
+#define SNDRV_PCM_FMTBIT_G723_24_1B	(1ULL << SNDRV_PCM_FORMAT_G723_24_1B)
+#define SNDRV_PCM_FMTBIT_G723_40	(1ULL << SNDRV_PCM_FORMAT_G723_40)
+#define SNDRV_PCM_FMTBIT_G723_40_1B	(1ULL << SNDRV_PCM_FORMAT_G723_40_1B)
 
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #ifdef SNDRV_LITTLE_ENDIAN
 #define SNDRV_PCM_FMTBIT_S16		SNDRV_PCM_FMTBIT_S16_LE
 #define SNDRV_PCM_FMTBIT_S16		SNDRV_PCM_FMTBIT_S16_LE
@@ -313,7 +317,7 @@ struct snd_pcm_runtime {
 	struct snd_pcm_mmap_control *control;
 	struct snd_pcm_mmap_control *control;
 
 
 	/* -- locking / scheduling -- */
 	/* -- locking / scheduling -- */
-	unsigned int twake: 1;		/* do transfer (!poll) wakeup */
+	snd_pcm_uframes_t twake; 	/* do transfer (!poll) wakeup if non-zero */
 	wait_queue_head_t sleep;	/* poll sleep */
 	wait_queue_head_t sleep;	/* poll sleep */
 	wait_queue_head_t tsleep;	/* transfer sleep */
 	wait_queue_head_t tsleep;	/* transfer sleep */
 	struct fasync_struct *fasync;
 	struct fasync_struct *fasync;

+ 43 - 6
include/sound/sh_fsi.h

@@ -12,6 +12,9 @@
  * published by the Free Software Foundation.
  * published by the Free Software Foundation.
  */
  */
 
 
+#define FSI_PORT_A	0
+#define FSI_PORT_B	1
+
 /* flags format
 /* flags format
 
 
  * 0xABCDEEFF
  * 0xABCDEEFF
@@ -55,12 +58,14 @@
 #define SH_FSI_GET_IFMT(x)	((x >> 8) & SH_FSI_FMT_MASK)
 #define SH_FSI_GET_IFMT(x)	((x >> 8) & SH_FSI_FMT_MASK)
 #define SH_FSI_GET_OFMT(x)	((x >> 0) & SH_FSI_FMT_MASK)
 #define SH_FSI_GET_OFMT(x)	((x >> 0) & SH_FSI_FMT_MASK)
 
 
-#define SH_FSI_FMT_MONO		(1 << 0)
-#define SH_FSI_FMT_MONO_DELAY	(1 << 1)
-#define SH_FSI_FMT_PCM		(1 << 2)
-#define SH_FSI_FMT_I2S		(1 << 3)
-#define SH_FSI_FMT_TDM		(1 << 4)
-#define SH_FSI_FMT_TDM_DELAY	(1 << 5)
+#define SH_FSI_FMT_MONO		0
+#define SH_FSI_FMT_MONO_DELAY	1
+#define SH_FSI_FMT_PCM		2
+#define SH_FSI_FMT_I2S		3
+#define SH_FSI_FMT_TDM		4
+#define SH_FSI_FMT_TDM_DELAY	5
+#define SH_FSI_FMT_SPDIF	6
+
 
 
 #define SH_FSI_IFMT_TDM_CH(x) \
 #define SH_FSI_IFMT_TDM_CH(x) \
 	(SH_FSI_IFMT(TDM)	| SH_FSI_SET_CH_I(x))
 	(SH_FSI_IFMT(TDM)	| SH_FSI_SET_CH_I(x))
@@ -72,9 +77,41 @@
 #define SH_FSI_OFMT_TDM_DELAY_CH(x) \
 #define SH_FSI_OFMT_TDM_DELAY_CH(x) \
 	(SH_FSI_OFMT(TDM_DELAY)	| SH_FSI_SET_CH_O(x))
 	(SH_FSI_OFMT(TDM_DELAY)	| SH_FSI_SET_CH_O(x))
 
 
+
+/*
+ * set_rate return value
+ *
+ * see ACKMD/BPFMD on
+ *     ACK_MD (FSI2)
+ *     CKG1   (FSI)
+ *
+ * err:  return value < 0
+ *
+ * 0x-00000AB
+ *
+ * A:  ACKMD value
+ * B:  BPFMD value
+ */
+
+#define SH_FSI_ACKMD_MASK	(0xF << 0)
+#define SH_FSI_ACKMD_512	(1 << 0)
+#define SH_FSI_ACKMD_256	(2 << 0)
+#define SH_FSI_ACKMD_128	(3 << 0)
+#define SH_FSI_ACKMD_64		(4 << 0)
+#define SH_FSI_ACKMD_32		(5 << 0)
+
+#define SH_FSI_BPFMD_MASK	(0xF << 4)
+#define SH_FSI_BPFMD_512	(1 << 4)
+#define SH_FSI_BPFMD_256	(2 << 4)
+#define SH_FSI_BPFMD_128	(3 << 4)
+#define SH_FSI_BPFMD_64		(4 << 4)
+#define SH_FSI_BPFMD_32		(5 << 4)
+#define SH_FSI_BPFMD_16		(6 << 4)
+
 struct sh_fsi_platform_info {
 struct sh_fsi_platform_info {
 	unsigned long porta_flags;
 	unsigned long porta_flags;
 	unsigned long portb_flags;
 	unsigned long portb_flags;
+	int (*set_rate)(int is_porta, int rate); /* for master mode */
 };
 };
 
 
 extern struct snd_soc_dai fsi_soc_dai[2];
 extern struct snd_soc_dai fsi_soc_dai[2];

+ 2 - 0
include/sound/soc-dapm.h

@@ -273,6 +273,8 @@
 #define SND_SOC_DAPM_POST_PMD	0x8		/* after widget power down */
 #define SND_SOC_DAPM_POST_PMD	0x8		/* after widget power down */
 #define SND_SOC_DAPM_PRE_REG	0x10	/* before audio path setup */
 #define SND_SOC_DAPM_PRE_REG	0x10	/* before audio path setup */
 #define SND_SOC_DAPM_POST_REG	0x20	/* after audio path setup */
 #define SND_SOC_DAPM_POST_REG	0x20	/* after audio path setup */
+#define SND_SOC_DAPM_PRE_POST_PMD \
+				(SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
 
 
 /* convenience event type detection */
 /* convenience event type detection */
 #define SND_SOC_DAPM_EVENT_ON(e)	\
 #define SND_SOC_DAPM_EVENT_ON(e)	\

+ 21 - 0
include/sound/soc.h

@@ -170,6 +170,21 @@
 	.get = xhandler_get, .put = xhandler_put, \
 	.get = xhandler_get, .put = xhandler_put, \
 	.private_value = (unsigned long)&xenum }
 	.private_value = (unsigned long)&xenum }
 
 
+#define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\
+		xmin, xmax, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		  SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p = (tlv_array), \
+	.info = snd_soc_info_volsw_2r_sx, \
+	.get = snd_soc_get_volsw_2r_sx, \
+	.put = snd_soc_put_volsw_2r_sx, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+		{.reg = xreg_left, \
+		 .rreg = xreg_right, .shift = xshift, \
+		 .min = xmin, .max = xmax} }
+
+
 /*
 /*
  * Simplified versions of above macros, declaring a struct and calculating
  * Simplified versions of above macros, declaring a struct and calculating
  * ARRAY_SIZE internally
  * ARRAY_SIZE internally
@@ -329,6 +344,12 @@ 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,
 int snd_soc_limit_volume(struct snd_soc_codec *codec,
 	const char *name, int max);
 	const char *name, int max);
+int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
 
 
 /**
 /**
  * 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

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

@@ -15,6 +15,8 @@
 
 
 struct tlv320dac33_platform_data {
 struct tlv320dac33_platform_data {
 	int power_gpio;
 	int power_gpio;
+	int mode1_latency; /* latency caused by the i2c writes in us */
+	int auto_fifo_config; /* FIFO config based on the period size */
 	int keep_bclk;	/* Keep the BCLK running in FIFO modes */
 	int keep_bclk;	/* Keep the BCLK running in FIFO modes */
 	u8 burst_bclkdiv;
 	u8 burst_bclkdiv;
 };
 };

+ 12 - 0
include/sound/uda134x.h

@@ -18,6 +18,18 @@ struct uda134x_platform_data {
 	struct l3_pins l3;
 	struct l3_pins l3;
 	void (*power) (int);
 	void (*power) (int);
 	int model;
 	int model;
+	/*
+	  ALSA SOC usually puts the device in standby mode when it's not used
+	  for sometime. If you unset is_powered_on_standby the driver will
+	  turn off the ADC/DAC when this callback is invoked and turn it back
+	  on when needed. Unfortunately this will result in a very light bump
+	  (it can be audible only with good earphones). If this bothers you
+	  set is_powered_on_standby, you will have slightly higher power
+	  consumption. Please note that sending the L3 command for ADC is
+	  enough to make the bump, so it doesn't make difference if you
+	  completely take off power from the codec.
+	*/
+	int is_powered_on_standby;
 #define UDA134X_UDA1340 1
 #define UDA134X_UDA1340 1
 #define UDA134X_UDA1341 2
 #define UDA134X_UDA1341 2
 #define UDA134X_UDA1344 3
 #define UDA134X_UDA1344 3

+ 17 - 8
sound/core/pcm_lib.c

@@ -67,6 +67,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
 	} else {
 	} else {
 		if (new_hw_ptr == ULONG_MAX) {	/* initialization */
 		if (new_hw_ptr == ULONG_MAX) {	/* initialization */
 			snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
 			snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
+			if (avail > runtime->buffer_size)
+				avail = runtime->buffer_size;
 			runtime->silence_filled = avail > 0 ? avail : 0;
 			runtime->silence_filled = avail > 0 ? avail : 0;
 			runtime->silence_start = (runtime->status->hw_ptr +
 			runtime->silence_start = (runtime->status->hw_ptr +
 						  runtime->silence_filled) %
 						  runtime->silence_filled) %
@@ -287,8 +289,11 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
 			return -EPIPE;
 			return -EPIPE;
 		}
 		}
 	}
 	}
-	if (avail >= runtime->control->avail_min)
-		wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep);
+	if (runtime->twake) {
+		if (avail >= runtime->twake)
+			wake_up(&runtime->tsleep);
+	} else if (avail >= runtime->control->avail_min)
+		wake_up(&runtime->sleep);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1707,7 +1712,7 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed);
  * The available space is stored on availp.  When err = 0 and avail = 0
  * The available space is stored on availp.  When err = 0 and avail = 0
  * on the capture stream, it indicates the stream is in DRAINING state.
  * on the capture stream, it indicates the stream is in DRAINING state.
  */
  */
-static int wait_for_avail_min(struct snd_pcm_substream *substream,
+static int wait_for_avail(struct snd_pcm_substream *substream,
 			      snd_pcm_uframes_t *availp)
 			      snd_pcm_uframes_t *availp)
 {
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1757,7 +1762,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream,
 			avail = snd_pcm_playback_avail(runtime);
 			avail = snd_pcm_playback_avail(runtime);
 		else
 		else
 			avail = snd_pcm_capture_avail(runtime);
 			avail = snd_pcm_capture_avail(runtime);
-		if (avail >= runtime->control->avail_min)
+		if (avail >= runtime->twake)
 			break;
 			break;
 	}
 	}
  _endloop:
  _endloop:
@@ -1820,7 +1825,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
 		goto _end_unlock;
 		goto _end_unlock;
 	}
 	}
 
 
-	runtime->twake = 1;
+	runtime->twake = runtime->control->avail_min ? : 1;
 	while (size > 0) {
 	while (size > 0) {
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
 		snd_pcm_uframes_t avail;
 		snd_pcm_uframes_t avail;
@@ -1833,7 +1838,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
 				err = -EAGAIN;
 				err = -EAGAIN;
 				goto _end_unlock;
 				goto _end_unlock;
 			}
 			}
-			err = wait_for_avail_min(substream, &avail);
+			runtime->twake = min_t(snd_pcm_uframes_t, size,
+					runtime->control->avail_min ? : 1);
+			err = wait_for_avail(substream, &avail);
 			if (err < 0)
 			if (err < 0)
 				goto _end_unlock;
 				goto _end_unlock;
 		}
 		}
@@ -2042,7 +2049,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 		goto _end_unlock;
 		goto _end_unlock;
 	}
 	}
 
 
-	runtime->twake = 1;
+	runtime->twake = runtime->control->avail_min ? : 1;
 	while (size > 0) {
 	while (size > 0) {
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
 		snd_pcm_uframes_t avail;
 		snd_pcm_uframes_t avail;
@@ -2060,7 +2067,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 				err = -EAGAIN;
 				err = -EAGAIN;
 				goto _end_unlock;
 				goto _end_unlock;
 			}
 			}
-			err = wait_for_avail_min(substream, &avail);
+			runtime->twake = min_t(snd_pcm_uframes_t, size,
+					runtime->control->avail_min ? : 1);
+			err = wait_for_avail(substream, &avail);
 			if (err < 0)
 			if (err < 0)
 				goto _end_unlock;
 				goto _end_unlock;
 			if (!avail)
 			if (!avail)

+ 16 - 0
sound/core/pcm_misc.c

@@ -128,6 +128,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
 		.width = 4, .phys = 4, .le = -1, .signd = -1,
 		.width = 4, .phys = 4, .le = -1, .signd = -1,
 		.silence = {},
 		.silence = {},
 	},
 	},
+	[SNDRV_PCM_FORMAT_G723_24] = {
+		.width = 3, .phys = 3, .le = -1, .signd = -1,
+		.silence = {},
+	},
+	[SNDRV_PCM_FORMAT_G723_40] = {
+		.width = 5, .phys = 5, .le = -1, .signd = -1,
+		.silence = {},
+	},
 	/* FIXME: the following three formats are not defined properly yet */
 	/* FIXME: the following three formats are not defined properly yet */
 	[SNDRV_PCM_FORMAT_MPEG] = {
 	[SNDRV_PCM_FORMAT_MPEG] = {
 		.le = -1, .signd = -1,
 		.le = -1, .signd = -1,
@@ -186,6 +194,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
 		.width = 18, .phys = 24, .le = 0, .signd = 0,
 		.width = 18, .phys = 24, .le = 0, .signd = 0,
 		.silence = { 0x02, 0x00, 0x00 },
 		.silence = { 0x02, 0x00, 0x00 },
 	},
 	},
+	[SNDRV_PCM_FORMAT_G723_24_1B] = {
+		.width = 3, .phys = 8, .le = -1, .signd = -1,
+		.silence = {},
+	},
+	[SNDRV_PCM_FORMAT_G723_40_1B] = {
+		.width = 5, .phys = 8, .le = -1, .signd = -1,
+		.silence = {},
+	},
 };
 };
 
 
 
 

+ 21 - 3
sound/drivers/Kconfig

@@ -170,9 +170,25 @@ config SND_AC97_POWER_SAVE
 	  AC97 codecs.  In this mode, the power-mode is dynamically
 	  AC97 codecs.  In this mode, the power-mode is dynamically
 	  controlled at each open/close.
 	  controlled at each open/close.
 
 
-	  The mode is activated by passing power_save=1 option to
-	  snd-ac97-codec driver.  You can toggle it dynamically over
-	  sysfs, too.
+	  The mode is activated by passing 'power_save=X' to the
+	  snd-ac97-codec driver module, where 'X' is the time-out
+	  value, a nonnegative integer that specifies how many
+	  seconds of idle time the driver must count before it may
+	  put the AC97 into power-save mode;  a value of 0 (zero)
+	  disables the use of this power-save mode.
+
+	  After the snd-ac97-codec driver module has been loaded,
+	  the 'power_save' parameter can be set via sysfs as follows:
+
+	    echo 10 > /sys/module/snd_ac97_codec/parameters/power_save
+
+	  In this case, the time-out is set to 10 seconds; setting
+	  the time-out to 1 second (the minimum activation value)
+	  isn't recommended because many applications try to reopen
+	  the device frequently.  A value of 10 seconds would be a
+	  good choice for normal operations.
+
+	  See Documentation/sound/alsa/powersave.txt for more details.
 
 
 config SND_AC97_POWER_SAVE_DEFAULT
 config SND_AC97_POWER_SAVE_DEFAULT
 	int "Default time-out for AC97 power-save mode"
 	int "Default time-out for AC97 power-save mode"
@@ -182,4 +198,6 @@ config SND_AC97_POWER_SAVE_DEFAULT
 	  The default time-out value in seconds for AC97 automatic
 	  The default time-out value in seconds for AC97 automatic
 	  power-save mode.  0 means to disable the power-save mode.
 	  power-save mode.  0 means to disable the power-save mode.
 
 
+	  See SND_AC97_POWER_SAVE for more details.
+
 endif	# SND_DRIVERS
 endif	# SND_DRIVERS

+ 4 - 1
sound/isa/msnd/msnd_pinnacle.c

@@ -549,7 +549,10 @@ static int __devinit snd_msnd_attach(struct snd_card *card)
 		printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
 		printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
 		return err;
 		return err;
 	}
 	}
-	request_region(chip->io, DSP_NUMIO, card->shortname);
+	if (request_region(chip->io, DSP_NUMIO, card->shortname) == NULL) {
+		free_irq(chip->irq, chip);
+		return -EBUSY;
+	}
 
 
 	if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) {
 	if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) {
 		printk(KERN_ERR LOGNAME
 		printk(KERN_ERR LOGNAME

+ 6 - 3
sound/isa/sb/emu8000_pcm.c

@@ -433,7 +433,8 @@ static int emu8k_transfer_block(struct snd_emu8000 *emu, int offset, unsigned sh
 	while (count > 0) {
 	while (count > 0) {
 		unsigned short sval;
 		unsigned short sval;
 		CHECK_SCHEDULER();
 		CHECK_SCHEDULER();
-		get_user(sval, buf);
+		if (get_user(sval, buf))
+			return -EFAULT;
 		EMU8000_SMLD_WRITE(emu, sval);
 		EMU8000_SMLD_WRITE(emu, sval);
 		buf++;
 		buf++;
 		count--;
 		count--;
@@ -525,12 +526,14 @@ static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
 	while (count-- > 0) {
 	while (count-- > 0) {
 		unsigned short sval;
 		unsigned short sval;
 		CHECK_SCHEDULER();
 		CHECK_SCHEDULER();
-		get_user(sval, buf);
+		if (get_user(sval, buf))
+			return -EFAULT;
 		EMU8000_SMLD_WRITE(emu, sval);
 		EMU8000_SMLD_WRITE(emu, sval);
 		buf++;
 		buf++;
 		if (rec->voices > 1) {
 		if (rec->voices > 1) {
 			CHECK_SCHEDULER();
 			CHECK_SCHEDULER();
-			get_user(sval, buf);
+			if (get_user(sval, buf))
+				return -EFAULT;
 			EMU8000_SMRD_WRITE(emu, sval);
 			EMU8000_SMRD_WRITE(emu, sval);
 			buf++;
 			buf++;
 		}
 		}

+ 52 - 39
sound/oss/au1550_ac97.c

@@ -43,6 +43,7 @@
 #include <linux/sound.h>
 #include <linux/sound.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/soundcard.h>
 #include <linux/soundcard.h>
+#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -162,19 +163,10 @@ ld2(unsigned int x)
 static void
 static void
 au1550_delay(int msec)
 au1550_delay(int msec)
 {
 {
-	unsigned long   tmo;
-	signed long     tmo2;
-
 	if (in_interrupt())
 	if (in_interrupt())
 		return;
 		return;
 
 
-	tmo = jiffies + (msec * HZ) / 1000;
-	for (;;) {
-		tmo2 = tmo - jiffies;
-		if (tmo2 <= 0)
-			break;
-		schedule_timeout(tmo2);
-	}
+	schedule_timeout_uninterruptible(msecs_to_jiffies(msec));
 }
 }
 
 
 static u16
 static u16
@@ -807,7 +799,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin)
 static int
 static int
 au1550_open_mixdev(struct inode *inode, struct file *file)
 au1550_open_mixdev(struct inode *inode, struct file *file)
 {
 {
+	lock_kernel();
 	file->private_data = &au1550_state;
 	file->private_data = &au1550_state;
+	unlock_kernel();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -824,22 +818,26 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
 	return codec->mixer_ioctl(codec, cmd, arg);
 	return codec->mixer_ioctl(codec, cmd, arg);
 }
 }
 
 
-static int
-au1550_ioctl_mixdev(struct inode *inode, struct file *file,
-			       unsigned int cmd, unsigned long arg)
+static long
+au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
 {
 {
 	struct au1550_state *s = (struct au1550_state *)file->private_data;
 	struct au1550_state *s = (struct au1550_state *)file->private_data;
 	struct ac97_codec *codec = s->codec;
 	struct ac97_codec *codec = s->codec;
+	int ret;
 
 
-	return mixdev_ioctl(codec, cmd, arg);
+	lock_kernel();
+	ret = mixdev_ioctl(codec, cmd, arg);
+	unlock_kernel();
+
+	return ret;
 }
 }
 
 
 static /*const */ struct file_operations au1550_mixer_fops = {
 static /*const */ struct file_operations au1550_mixer_fops = {
-	owner:THIS_MODULE,
-	llseek:au1550_llseek,
-	ioctl:au1550_ioctl_mixdev,
-	open:au1550_open_mixdev,
-	release:au1550_release_mixdev,
+	.owner		= THIS_MODULE,
+	.llseek		= au1550_llseek,
+	.unlocked_ioctl	= au1550_ioctl_mixdev,
+	.open		= au1550_open_mixdev,
+	.release	= au1550_release_mixdev,
 };
 };
 
 
 static int
 static int
@@ -1343,8 +1341,7 @@ dma_count_done(struct dmabuf *db)
 
 
 
 
 static int
 static int
-au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-							unsigned long arg)
+au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 {
 	struct au1550_state *s = (struct au1550_state *)file->private_data;
 	struct au1550_state *s = (struct au1550_state *)file->private_data;
 	unsigned long   flags;
 	unsigned long   flags;
@@ -1780,6 +1777,17 @@ au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 	return mixdev_ioctl(s->codec, cmd, arg);
 	return mixdev_ioctl(s->codec, cmd, arg);
 }
 }
 
 
+static long
+au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int ret;
+
+	lock_kernel();
+	ret = au1550_ioctl(file, cmd, arg);
+	unlock_kernel();
+
+	return ret;
+}
 
 
 static int
 static int
 au1550_open(struct inode *inode, struct file *file)
 au1550_open(struct inode *inode, struct file *file)
@@ -1797,21 +1805,22 @@ au1550_open(struct inode *inode, struct file *file)
 #endif
 #endif
 
 
 	file->private_data = s;
 	file->private_data = s;
+	lock_kernel();
 	/* wait for device to become free */
 	/* wait for device to become free */
 	mutex_lock(&s->open_mutex);
 	mutex_lock(&s->open_mutex);
 	while (s->open_mode & file->f_mode) {
 	while (s->open_mode & file->f_mode) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
+		ret = -EBUSY;
+		if (file->f_flags & O_NONBLOCK)
+			goto out;
 		add_wait_queue(&s->open_wait, &wait);
 		add_wait_queue(&s->open_wait, &wait);
 		__set_current_state(TASK_INTERRUPTIBLE);
 		__set_current_state(TASK_INTERRUPTIBLE);
 		mutex_unlock(&s->open_mutex);
 		mutex_unlock(&s->open_mutex);
 		schedule();
 		schedule();
 		remove_wait_queue(&s->open_wait, &wait);
 		remove_wait_queue(&s->open_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		set_current_state(TASK_RUNNING);
+		ret = -ERESTARTSYS;
 		if (signal_pending(current))
 		if (signal_pending(current))
-			return -ERESTARTSYS;
+			goto out2;
 		mutex_lock(&s->open_mutex);
 		mutex_lock(&s->open_mutex);
 	}
 	}
 
 
@@ -1840,17 +1849,21 @@ au1550_open(struct inode *inode, struct file *file)
 
 
 	if (file->f_mode & FMODE_READ) {
 	if (file->f_mode & FMODE_READ) {
 		if ((ret = prog_dmabuf_adc(s)))
 		if ((ret = prog_dmabuf_adc(s)))
-			return ret;
+			goto out;
 	}
 	}
 	if (file->f_mode & FMODE_WRITE) {
 	if (file->f_mode & FMODE_WRITE) {
 		if ((ret = prog_dmabuf_dac(s)))
 		if ((ret = prog_dmabuf_dac(s)))
-			return ret;
+			goto out;
 	}
 	}
 
 
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	mutex_unlock(&s->open_mutex);
 	mutex_init(&s->sem);
 	mutex_init(&s->sem);
-	return 0;
+	ret = 0;
+out:
+	mutex_unlock(&s->open_mutex);
+out2:
+	unlock_kernel();
+	return ret;
 }
 }
 
 
 static int
 static int
@@ -1885,15 +1898,15 @@ au1550_release(struct inode *inode, struct file *file)
 }
 }
 
 
 static /*const */ struct file_operations au1550_audio_fops = {
 static /*const */ struct file_operations au1550_audio_fops = {
-	owner:		THIS_MODULE,
-	llseek:		au1550_llseek,
-	read:		au1550_read,
-	write:		au1550_write,
-	poll:		au1550_poll,
-	ioctl:		au1550_ioctl,
-	mmap:		au1550_mmap,
-	open:		au1550_open,
-	release:	au1550_release,
+	.owner		= THIS_MODULE,
+	.llseek		= au1550_llseek,
+	.read		= au1550_read,
+	.write		= au1550_write,
+	.poll		= au1550_poll,
+	.unlocked_ioctl	= au1550_unlocked_ioctl,
+	.mmap		= au1550_mmap,
+	.open		= au1550_open,
+	.release	= au1550_release,
 };
 };
 
 
 MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
 MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");

+ 50 - 13
sound/oss/dmasound/dmasound_core.c

@@ -323,9 +323,13 @@ static struct {
 
 
 static int mixer_open(struct inode *inode, struct file *file)
 static int mixer_open(struct inode *inode, struct file *file)
 {
 {
-	if (!try_module_get(dmasound.mach.owner))
+	lock_kernel();
+	if (!try_module_get(dmasound.mach.owner)) {
+		unlock_kernel();
 		return -ENODEV;
 		return -ENODEV;
+	}
 	mixer.busy = 1;
 	mixer.busy = 1;
+	unlock_kernel();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -337,8 +341,8 @@ static int mixer_release(struct inode *inode, struct file *file)
 	unlock_kernel();
 	unlock_kernel();
 	return 0;
 	return 0;
 }
 }
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg)
+
+static int mixer_ioctl(struct file *file, u_int cmd, u_long arg)
 {
 {
 	if (_SIOC_DIR(cmd) & _SIOC_WRITE)
 	if (_SIOC_DIR(cmd) & _SIOC_WRITE)
 	    mixer.modify_counter++;
 	    mixer.modify_counter++;
@@ -362,11 +366,22 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
+static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+	int ret;
+
+	lock_kernel();
+	ret = mixer_ioctl(file, cmd, arg);
+	unlock_kernel();
+
+	return ret;
+}
+
 static const struct file_operations mixer_fops =
 static const struct file_operations mixer_fops =
 {
 {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.llseek		= no_llseek,
 	.llseek		= no_llseek,
-	.ioctl		= mixer_ioctl,
+	.unlocked_ioctl	= mixer_unlocked_ioctl,
 	.open		= mixer_open,
 	.open		= mixer_open,
 	.release	= mixer_release,
 	.release	= mixer_release,
 };
 };
@@ -737,8 +752,11 @@ static int sq_open(struct inode *inode, struct file *file)
 {
 {
 	int rc;
 	int rc;
 
 
-	if (!try_module_get(dmasound.mach.owner))
+	lock_kernel();
+	if (!try_module_get(dmasound.mach.owner)) {
+		unlock_kernel();
 		return -ENODEV;
 		return -ENODEV;
+	}
 
 
 	rc = write_sq_open(file); /* checks the f_mode */
 	rc = write_sq_open(file); /* checks the f_mode */
 	if (rc)
 	if (rc)
@@ -781,10 +799,11 @@ static int sq_open(struct inode *inode, struct file *file)
 		sound_set_format(AFMT_MU_LAW);
 		sound_set_format(AFMT_MU_LAW);
 	}
 	}
 #endif
 #endif
-
+	unlock_kernel();
 	return 0;
 	return 0;
  out:
  out:
 	module_put(dmasound.mach.owner);
 	module_put(dmasound.mach.owner);
+	unlock_kernel();
 	return rc;
 	return rc;
 }
 }
 
 
@@ -955,8 +974,7 @@ printk("dmasound_core: tried to set_queue_frags on a locked queue\n") ;
 	return 0 ;
 	return 0 ;
 }
 }
 
 
-static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		    u_long arg)
+static int sq_ioctl(struct file *file, u_int cmd, u_long arg)
 {
 {
 	int val, result;
 	int val, result;
 	u_long fmt;
 	u_long fmt;
@@ -1114,18 +1132,29 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
 		return IOCTL_OUT(arg,val);
 		return IOCTL_OUT(arg,val);
 
 
 	default:
 	default:
-		return mixer_ioctl(inode, file, cmd, arg);
+		return mixer_ioctl(file, cmd, arg);
 	}
 	}
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
+static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+	int ret;
+
+	lock_kernel();
+	ret = sq_ioctl(file, cmd, arg);
+	unlock_kernel();
+
+	return ret;
+}
+
 static const struct file_operations sq_fops =
 static const struct file_operations sq_fops =
 {
 {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.llseek		= no_llseek,
 	.llseek		= no_llseek,
 	.write		= sq_write,
 	.write		= sq_write,
 	.poll		= sq_poll,
 	.poll		= sq_poll,
-	.ioctl		= sq_ioctl,
+	.unlocked_ioctl	= sq_unlocked_ioctl,
 	.open		= sq_open,
 	.open		= sq_open,
 	.release	= sq_release,
 	.release	= sq_release,
 };
 };
@@ -1226,12 +1255,17 @@ static int state_open(struct inode *inode, struct file *file)
 {
 {
 	char *buffer = state.buf;
 	char *buffer = state.buf;
 	int len = 0;
 	int len = 0;
+	int ret;
 
 
+	lock_kernel();
+	ret = -EBUSY;
 	if (state.busy)
 	if (state.busy)
-		return -EBUSY;
+		goto out;
 
 
+	ret = -ENODEV;
 	if (!try_module_get(dmasound.mach.owner))
 	if (!try_module_get(dmasound.mach.owner))
-		return -ENODEV;
+		goto out;
+
 	state.ptr = 0;
 	state.ptr = 0;
 	state.busy = 1;
 	state.busy = 1;
 
 
@@ -1293,7 +1327,10 @@ printk("dmasound: stat buffer used %d bytes\n", len) ;
 		printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n");
 		printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n");
 
 
 	state.len = len;
 	state.len = len;
-	return 0;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 }
 
 
 static int state_release(struct inode *inode, struct file *file)
 static int state_release(struct inode *inode, struct file *file)

+ 3 - 1
sound/oss/midi_synth.c

@@ -523,7 +523,9 @@ midi_synth_load_patch(int dev, int format, const char __user *addr,
 	{
 	{
 		unsigned char   data;
 		unsigned char   data;
 
 
-		get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i]));
+		if (get_user(data,
+		    (unsigned char __user *)(addr + hdr_size + i)))
+			return -EFAULT;
 
 
 		eox_seen = (i > 0 && data & 0x80);	/* End of sysex */
 		eox_seen = (i > 0 && data & 0x80);	/* End of sysex */
 
 

+ 24 - 11
sound/oss/msnd_pinnacle.c

@@ -639,21 +639,26 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg)
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
-static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 {
-	int minor = iminor(inode);
+	int minor = iminor(file->f_path.dentry->d_inode);
+	int ret;
 
 
 	if (cmd == OSS_GETVERSION) {
 	if (cmd == OSS_GETVERSION) {
 		int sound_version = SOUND_VERSION;
 		int sound_version = SOUND_VERSION;
 		return put_user(sound_version, (int __user *)arg);
 		return put_user(sound_version, (int __user *)arg);
 	}
 	}
 
 
+	ret = -EINVAL;
+
+	lock_kernel();
 	if (minor == dev.dsp_minor)
 	if (minor == dev.dsp_minor)
-		return dsp_ioctl(file, cmd, arg);
+		ret = dsp_ioctl(file, cmd, arg);
 	else if (minor == dev.mixer_minor)
 	else if (minor == dev.mixer_minor)
-		return mixer_ioctl(cmd, arg);
+		ret = mixer_ioctl(cmd, arg);
+	unlock_kernel();
 
 
-	return -EINVAL;
+	return ret;
 }
 }
 
 
 static void dsp_write_flush(void)
 static void dsp_write_flush(void)
@@ -756,12 +761,15 @@ static int dev_open(struct inode *inode, struct file *file)
 	int minor = iminor(inode);
 	int minor = iminor(inode);
 	int err = 0;
 	int err = 0;
 
 
+	lock_kernel();
 	if (minor == dev.dsp_minor) {
 	if (minor == dev.dsp_minor) {
 		if ((file->f_mode & FMODE_WRITE &&
 		if ((file->f_mode & FMODE_WRITE &&
 		     test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
 		     test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
 		    (file->f_mode & FMODE_READ &&
 		    (file->f_mode & FMODE_READ &&
-		     test_bit(F_AUDIO_READ_INUSE, &dev.flags)))
-			return -EBUSY;
+		     test_bit(F_AUDIO_READ_INUSE, &dev.flags))) {
+			err = -EBUSY;
+			goto out;
+		}
 
 
 		if ((err = dsp_open(file)) >= 0) {
 		if ((err = dsp_open(file)) >= 0) {
 			dev.nresets = 0;
 			dev.nresets = 0;
@@ -782,7 +790,8 @@ static int dev_open(struct inode *inode, struct file *file)
 		/* nothing */
 		/* nothing */
 	} else
 	} else
 		err = -EINVAL;
 		err = -EINVAL;
-
+out:
+	unlock_kernel();
 	return err;
 	return err;
 }
 }
 
 
@@ -1105,7 +1114,7 @@ static const struct file_operations dev_fileops = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.read		= dev_read,
 	.read		= dev_read,
 	.write		= dev_write,
 	.write		= dev_write,
-	.ioctl		= dev_ioctl,
+	.unlocked_ioctl	= dev_ioctl,
 	.open		= dev_open,
 	.open		= dev_open,
 	.release	= dev_release,
 	.release	= dev_release,
 };
 };
@@ -1391,9 +1400,13 @@ static int __init attach_multisound(void)
 		printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
 		printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
 		return err;
 		return err;
 	}
 	}
-	request_region(dev.io, dev.numio, dev.name);
+	if (request_region(dev.io, dev.numio, dev.name) == NULL) {
+		free_irq(dev.irq, &dev);
+		return -EBUSY;
+	}
 
 
-        if ((err = dsp_full_reset()) < 0) {
+	err = dsp_full_reset();
+	if (err < 0) {
 		release_region(dev.io, dev.numio);
 		release_region(dev.io, dev.numio);
 		free_irq(dev.irq, &dev);
 		free_irq(dev.irq, &dev);
 		return err;
 		return err;

+ 22 - 5
sound/oss/sh_dac_audio.c

@@ -15,7 +15,9 @@
 #include <linux/linkage.h>
 #include <linux/linkage.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/fs.h>
+#include <linux/smp_lock.h>
 #include <linux/sound.h>
 #include <linux/sound.h>
+#include <linux/smp_lock.h>
 #include <linux/soundcard.h>
 #include <linux/soundcard.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/hrtimer.h>
 #include <linux/hrtimer.h>
@@ -92,7 +94,7 @@ static void dac_audio_set_rate(void)
 	wakeups_per_second = ktime_set(0, 1000000000 / rate);
 	wakeups_per_second = ktime_set(0, 1000000000 / rate);
 }
 }
 
 
-static int dac_audio_ioctl(struct inode *inode, struct file *file,
+static int dac_audio_ioctl(struct file *file,
 			   unsigned int cmd, unsigned long arg)
 			   unsigned int cmd, unsigned long arg)
 {
 {
 	int val;
 	int val;
@@ -158,6 +160,17 @@ static int dac_audio_ioctl(struct inode *inode, struct file *file,
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
+static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+	int ret;
+
+	lock_kernel();
+	ret = dac_audio_ioctl(file, cmd, arg);
+	unlock_kernel();
+
+	return ret;
+}
+
 static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
 static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
 			       loff_t * ppos)
 			       loff_t * ppos)
 {
 {
@@ -216,13 +229,17 @@ static int dac_audio_open(struct inode *inode, struct file *file)
 {
 {
 	if (file->f_mode & FMODE_READ)
 	if (file->f_mode & FMODE_READ)
 		return -ENODEV;
 		return -ENODEV;
-	if (in_use)
+
+	lock_kernel();
+	if (in_use) {
+		unlock_kernel();
 		return -EBUSY;
 		return -EBUSY;
+	}
 
 
 	in_use = 1;
 	in_use = 1;
 
 
 	dac_audio_start();
 	dac_audio_start();
-
+	unlock_kernel();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -237,8 +254,8 @@ static int dac_audio_release(struct inode *inode, struct file *file)
 
 
 const struct file_operations dac_audio_fops = {
 const struct file_operations dac_audio_fops = {
       .read =		dac_audio_read,
       .read =		dac_audio_read,
-      .write =	dac_audio_write,
-      .ioctl =	dac_audio_ioctl,
+      .write =		dac_audio_write,
+      .unlocked_ioctl =	dac_audio_unlocked_ioctl,
       .open =		dac_audio_open,
       .open =		dac_audio_open,
       .release =	dac_audio_release,
       .release =	dac_audio_release,
 };
 };

+ 11 - 9
sound/oss/soundcard.c

@@ -210,42 +210,44 @@ static int sound_open(struct inode *inode, struct file *file)
 		printk(KERN_ERR "Invalid minor device %d\n", dev);
 		printk(KERN_ERR "Invalid minor device %d\n", dev);
 		return -ENXIO;
 		return -ENXIO;
 	}
 	}
+	lock_kernel();
 	switch (dev & 0x0f) {
 	switch (dev & 0x0f) {
 	case SND_DEV_CTL:
 	case SND_DEV_CTL:
 		dev >>= 4;
 		dev >>= 4;
 		if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {
 		if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {
 			request_module("mixer%d", dev);
 			request_module("mixer%d", dev);
 		}
 		}
+		retval = -ENXIO;
 		if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL))
 		if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL))
-			return -ENXIO;
+			break;
 	
 	
 		if (!try_module_get(mixer_devs[dev]->owner))
 		if (!try_module_get(mixer_devs[dev]->owner))
-			return -ENXIO;
+			break;
+
+		retval = 0;
 		break;
 		break;
 
 
 	case SND_DEV_SEQ:
 	case SND_DEV_SEQ:
 	case SND_DEV_SEQ2:
 	case SND_DEV_SEQ2:
-		if ((retval = sequencer_open(dev, file)) < 0)
-			return retval;
+		retval = sequencer_open(dev, file);
 		break;
 		break;
 
 
 	case SND_DEV_MIDIN:
 	case SND_DEV_MIDIN:
-		if ((retval = MIDIbuf_open(dev, file)) < 0)
-			return retval;
+		retval = MIDIbuf_open(dev, file);
 		break;
 		break;
 
 
 	case SND_DEV_DSP:
 	case SND_DEV_DSP:
 	case SND_DEV_DSP16:
 	case SND_DEV_DSP16:
 	case SND_DEV_AUDIO:
 	case SND_DEV_AUDIO:
-		if ((retval = audio_open(dev, file)) < 0)
-			return retval;
+		retval = audio_open(dev, file);
 		break;
 		break;
 
 
 	default:
 	default:
 		printk(KERN_ERR "Invalid minor device %d\n", dev);
 		printk(KERN_ERR "Invalid minor device %d\n", dev);
-		return -ENXIO;
+		retval = -ENXIO;
 	}
 	}
 
 
+	unlock_kernel();
 	return 0;
 	return 0;
 }
 }
 
 

+ 35 - 6
sound/oss/swarm_cs4297a.c

@@ -68,6 +68,7 @@
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/sound.h>
 #include <linux/sound.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/soundcard.h>
 #include <linux/soundcard.h>
 #include <linux/ac97_codec.h>
 #include <linux/ac97_codec.h>
 #include <linux/pci.h>
 #include <linux/pci.h>
@@ -1534,6 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
 	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
 	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
 		  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
 		  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
 
 
+	lock_kernel();
 	list_for_each(entry, &cs4297a_devs)
 	list_for_each(entry, &cs4297a_devs)
 	{
 	{
 		s = list_entry(entry, struct cs4297a_state, list);
 		s = list_entry(entry, struct cs4297a_state, list);
@@ -1544,6 +1546,8 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
 	{
 	{
 		CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
 		CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
 			printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
 			printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
+
+		unlock_kernel();
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 	VALIDATE_STATE(s);
 	VALIDATE_STATE(s);
@@ -1551,6 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
 
 
 	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
 	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
 		  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
 		  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
+	unlock_kernel();
 
 
 	return nonseekable_open(inode, file);
 	return nonseekable_open(inode, file);
 }
 }
@@ -1566,11 +1571,15 @@ static int cs4297a_release_mixdev(struct inode *inode, struct file *file)
 }
 }
 
 
 
 
-static int cs4297a_ioctl_mixdev(struct inode *inode, struct file *file,
+static int cs4297a_ioctl_mixdev(struct file *file,
 			       unsigned int cmd, unsigned long arg)
 			       unsigned int cmd, unsigned long arg)
 {
 {
-	return mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
+	int ret;
+	lock_kernel();
+	ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
 			   arg);
 			   arg);
+	unlock_kernel();
+	return ret;
 }
 }
 
 
 
 
@@ -1580,7 +1589,7 @@ static int cs4297a_ioctl_mixdev(struct inode *inode, struct file *file,
 static const struct file_operations cs4297a_mixer_fops = {
 static const struct file_operations cs4297a_mixer_fops = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
 	.llseek		= no_llseek,
 	.llseek		= no_llseek,
-	.ioctl		= cs4297a_ioctl_mixdev,
+	.unlocked_ioctl	= cs4297a_ioctl_mixdev,
 	.open		= cs4297a_open_mixdev,
 	.open		= cs4297a_open_mixdev,
 	.release	= cs4297a_release_mixdev,
 	.release	= cs4297a_release_mixdev,
 };
 };
@@ -1944,7 +1953,7 @@ static int cs4297a_mmap(struct file *file, struct vm_area_struct *vma)
 }
 }
 
 
 
 
-static int cs4297a_ioctl(struct inode *inode, struct file *file,
+static int cs4297a_ioctl(struct file *file,
 			unsigned int cmd, unsigned long arg)
 			unsigned int cmd, unsigned long arg)
 {
 {
 	struct cs4297a_state *s =
 	struct cs4297a_state *s =
@@ -2337,6 +2346,16 @@ static int cs4297a_ioctl(struct inode *inode, struct file *file,
 	return mixer_ioctl(s, cmd, arg);
 	return mixer_ioctl(s, cmd, arg);
 }
 }
 
 
+static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+	int ret;
+
+	lock_kernel();
+	ret = cs4297a_ioctl(file, cmd, arg);
+	unlock_kernel();
+
+	return ret;
+}
 
 
 static int cs4297a_release(struct inode *inode, struct file *file)
 static int cs4297a_release(struct inode *inode, struct file *file)
 {
 {
@@ -2369,7 +2388,7 @@ static int cs4297a_release(struct inode *inode, struct file *file)
 	return 0;
 	return 0;
 }
 }
 
 
-static int cs4297a_open(struct inode *inode, struct file *file)
+static int cs4297a_locked_open(struct inode *inode, struct file *file)
 {
 {
 	int minor = iminor(inode);
 	int minor = iminor(inode);
 	struct cs4297a_state *s=NULL;
 	struct cs4297a_state *s=NULL;
@@ -2486,6 +2505,16 @@ static int cs4297a_open(struct inode *inode, struct file *file)
 	return nonseekable_open(inode, file);
 	return nonseekable_open(inode, file);
 }
 }
 
 
+static int cs4297a_open(struct inode *inode, struct file *file)
+{
+	int ret;
+
+	lock_kernel();
+	ret = cs4297a_open(inode, file);
+	unlock_kernel();
+
+	return ret;
+}
 
 
 // ******************************************************************************************
 // ******************************************************************************************
 //   Wave (audio) file operations struct.
 //   Wave (audio) file operations struct.
@@ -2496,7 +2525,7 @@ static const struct file_operations cs4297a_audio_fops = {
 	.read		= cs4297a_read,
 	.read		= cs4297a_read,
 	.write		= cs4297a_write,
 	.write		= cs4297a_write,
 	.poll		= cs4297a_poll,
 	.poll		= cs4297a_poll,
-	.ioctl		= cs4297a_ioctl,
+	.unlocked_ioctl	= cs4297a_unlocked_ioctl,
 	.mmap		= cs4297a_mmap,
 	.mmap		= cs4297a_mmap,
 	.open		= cs4297a_open,
 	.open		= cs4297a_open,
 	.release	= cs4297a_release,
 	.release	= cs4297a_release,

+ 0 - 3
sound/oss/vidc.c

@@ -491,9 +491,6 @@ static void __init attach_vidc(struct address_info *hw_config)
 	vidc_adev = adev;
 	vidc_adev = adev;
 	vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8));
 	vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8));
 
 
-#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE)
-	softoss_dev = adev;
-#endif
 	return;
 	return;
 
 
 irq_failed:
 irq_failed:

+ 21 - 11
sound/oss/vwsnd.c

@@ -2429,8 +2429,7 @@ static unsigned int vwsnd_audio_poll(struct file *file,
 	return mask;
 	return mask;
 }
 }
 
 
-static int vwsnd_audio_do_ioctl(struct inode *inode,
-				struct file *file,
+static int vwsnd_audio_do_ioctl(struct file *file,
 				unsigned int cmd,
 				unsigned int cmd,
 				unsigned long arg)
 				unsigned long arg)
 {
 {
@@ -2446,8 +2445,8 @@ static int vwsnd_audio_do_ioctl(struct inode *inode,
 	int ival;
 	int ival;
 
 
 	
 	
-	DBGEV("(inode=0x%p, file=0x%p, cmd=0x%x, arg=0x%lx)\n",
-	      inode, file, cmd, arg);
+	DBGEV("(file=0x%p, cmd=0x%x, arg=0x%lx)\n",
+	      file, cmd, arg);
 	switch (cmd) {
 	switch (cmd) {
 	case OSS_GETVERSION:		/* _SIOR ('M', 118, int) */
 	case OSS_GETVERSION:		/* _SIOR ('M', 118, int) */
 		DBGX("OSS_GETVERSION\n");
 		DBGX("OSS_GETVERSION\n");
@@ -2885,17 +2884,19 @@ static int vwsnd_audio_do_ioctl(struct inode *inode,
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
-static int vwsnd_audio_ioctl(struct inode *inode,
-				struct file *file,
+static long vwsnd_audio_ioctl(struct file *file,
 				unsigned int cmd,
 				unsigned int cmd,
 				unsigned long arg)
 				unsigned long arg)
 {
 {
 	vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
 	vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
 	int ret;
 	int ret;
 
 
+	lock_kernel();
 	mutex_lock(&devc->io_mutex);
 	mutex_lock(&devc->io_mutex);
-	ret = vwsnd_audio_do_ioctl(inode, file, cmd, arg);
+	ret = vwsnd_audio_do_ioctl(file, cmd, arg);
 	mutex_unlock(&devc->io_mutex);
 	mutex_unlock(&devc->io_mutex);
+	unlock_kernel();
+
 	return ret;
 	return ret;
 }
 }
 
 
@@ -2921,6 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
 
 	DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
 	DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
 
 
+	lock_kernel();
 	INC_USE_COUNT;
 	INC_USE_COUNT;
 	for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
 	for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
 		if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
 		if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
@@ -2928,6 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
 
 	if (devc == NULL) {
 	if (devc == NULL) {
 		DEC_USE_COUNT;
 		DEC_USE_COUNT;
+		unlock_kernel();
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -2936,11 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 		mutex_unlock(&devc->open_mutex);
 		mutex_unlock(&devc->open_mutex);
 		if (file->f_flags & O_NONBLOCK) {
 		if (file->f_flags & O_NONBLOCK) {
 			DEC_USE_COUNT;
 			DEC_USE_COUNT;
+			unlock_kernel();
 			return -EBUSY;
 			return -EBUSY;
 		}
 		}
 		interruptible_sleep_on(&devc->open_wait);
 		interruptible_sleep_on(&devc->open_wait);
 		if (signal_pending(current)) {
 		if (signal_pending(current)) {
 			DEC_USE_COUNT;
 			DEC_USE_COUNT;
+			unlock_kernel();
 			return -ERESTARTSYS;
 			return -ERESTARTSYS;
 		}
 		}
 		mutex_lock(&devc->open_mutex);
 		mutex_lock(&devc->open_mutex);
@@ -2993,6 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
 
 	file->private_data = devc;
 	file->private_data = devc;
 	DBGRV();
 	DBGRV();
+	unlock_kernel();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3044,7 +3050,7 @@ static const struct file_operations vwsnd_audio_fops = {
 	.read =		vwsnd_audio_read,
 	.read =		vwsnd_audio_read,
 	.write =	vwsnd_audio_write,
 	.write =	vwsnd_audio_write,
 	.poll =		vwsnd_audio_poll,
 	.poll =		vwsnd_audio_poll,
-	.ioctl =	vwsnd_audio_ioctl,
+	.unlocked_ioctl = vwsnd_audio_ioctl,
 	.mmap =		vwsnd_audio_mmap,
 	.mmap =		vwsnd_audio_mmap,
 	.open =		vwsnd_audio_open,
 	.open =		vwsnd_audio_open,
 	.release =	vwsnd_audio_release,
 	.release =	vwsnd_audio_release,
@@ -3062,15 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file)
 	DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
 	DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
 
 
 	INC_USE_COUNT;
 	INC_USE_COUNT;
+	lock_kernel();
 	for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
 	for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
 		if (devc->mixer_minor == iminor(inode))
 		if (devc->mixer_minor == iminor(inode))
 			break;
 			break;
 
 
 	if (devc == NULL) {
 	if (devc == NULL) {
 		DEC_USE_COUNT;
 		DEC_USE_COUNT;
+		unlock_kernel();
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 	file->private_data = devc;
 	file->private_data = devc;
+	unlock_kernel();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3203,8 +3212,7 @@ static int mixer_write_ioctl(vwsnd_dev_t *devc, unsigned int nr, void __user *ar
 
 
 /* This is the ioctl entry to the mixer driver. */
 /* This is the ioctl entry to the mixer driver. */
 
 
-static int vwsnd_mixer_ioctl(struct inode *ioctl,
-			      struct file *file,
+static long vwsnd_mixer_ioctl(struct file *file,
 			      unsigned int cmd,
 			      unsigned int cmd,
 			      unsigned long arg)
 			      unsigned long arg)
 {
 {
@@ -3215,6 +3223,7 @@ static int vwsnd_mixer_ioctl(struct inode *ioctl,
 
 
 	DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
 	DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
 
 
+	lock_kernel();
 	mutex_lock(&devc->mix_mutex);
 	mutex_lock(&devc->mix_mutex);
 	{
 	{
 		if ((cmd & ~nrmask) == MIXER_READ(0))
 		if ((cmd & ~nrmask) == MIXER_READ(0))
@@ -3225,13 +3234,14 @@ static int vwsnd_mixer_ioctl(struct inode *ioctl,
 			retval = -EINVAL;
 			retval = -EINVAL;
 	}
 	}
 	mutex_unlock(&devc->mix_mutex);
 	mutex_unlock(&devc->mix_mutex);
+	unlock_kernel();
 	return retval;
 	return retval;
 }
 }
 
 
 static const struct file_operations vwsnd_mixer_fops = {
 static const struct file_operations vwsnd_mixer_fops = {
 	.owner =	THIS_MODULE,
 	.owner =	THIS_MODULE,
 	.llseek =	no_llseek,
 	.llseek =	no_llseek,
-	.ioctl =	vwsnd_mixer_ioctl,
+	.unlocked_ioctl = vwsnd_mixer_ioctl,
 	.open =		vwsnd_mixer_open,
 	.open =		vwsnd_mixer_open,
 	.release =	vwsnd_mixer_release,
 	.release =	vwsnd_mixer_release,
 };
 };

+ 2 - 8
sound/oss/waveartist.c

@@ -184,14 +184,8 @@ waveartist_iack(wavnc_info *devc)
 static inline int
 static inline int
 waveartist_sleep(int timeout_ms)
 waveartist_sleep(int timeout_ms)
 {
 {
-	unsigned int timeout = timeout_ms * 10 * HZ / 100;
-
-	do {
-		set_current_state(TASK_INTERRUPTIBLE);
-		timeout = schedule_timeout(timeout);
-	} while (timeout);
-
-	return 0;
+	unsigned int timeout = msecs_to_jiffies(timeout_ms*100);
+	return schedule_timeout_interruptible(timeout);
 }
 }
 
 
 static int
 static int

+ 2 - 2
sound/pci/als4000.c

@@ -763,9 +763,9 @@ static void snd_als4000_configure(struct snd_sb *chip)
 	/* SPECS_PAGE: 39 */
 	/* SPECS_PAGE: 39 */
 	for (i = ALS4K_GCR91_DMA0_ADDR; i <= ALS4K_GCR96_DMA3_MODE_COUNT; ++i)
 	for (i = ALS4K_GCR91_DMA0_ADDR; i <= ALS4K_GCR96_DMA3_MODE_COUNT; ++i)
 		snd_als4k_gcr_write(chip, i, 0);
 		snd_als4k_gcr_write(chip, i, 0);
-	
+	/* enable burst mode to prevent dropouts during high PCI bus usage */
 	snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL,
 	snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL,
-		snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL));
+		(snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL) & ~0x07) | 0x04);
 	spin_unlock_irq(&chip->reg_lock);
 	spin_unlock_irq(&chip->reg_lock);
 }
 }
 
 

+ 9 - 7
sound/pci/asihpi/asihpi.c

@@ -460,6 +460,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
 	struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
 	int err;
 	int err;
 	u16 format;
 	u16 format;
+	int width;
 	unsigned int bytes_per_sec;
 	unsigned int bytes_per_sec;
 
 
 	print_hwparams(params);
 	print_hwparams(params);
@@ -512,9 +513,10 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 				dpcm->hpi_buffer_attached);
 				dpcm->hpi_buffer_attached);
 	}
 	}
 	bytes_per_sec = params_rate(params) * params_channels(params);
 	bytes_per_sec = params_rate(params) * params_channels(params);
-	bytes_per_sec *= snd_pcm_format_width(params_format(params));
+	width = snd_pcm_format_width(params_format(params));
+	bytes_per_sec *= width;
 	bytes_per_sec /= 8;
 	bytes_per_sec /= 8;
-	if (bytes_per_sec <= 0)
+	if (width < 0 || bytes_per_sec == 0)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	dpcm->bytes_per_sec = bytes_per_sec;
 	dpcm->bytes_per_sec = bytes_per_sec;
@@ -1383,7 +1385,7 @@ static char *asihpi_src_names[] =
 
 
 compile_time_assert(
 compile_time_assert(
 	(ARRAY_SIZE(asihpi_src_names) ==
 	(ARRAY_SIZE(asihpi_src_names) ==
-		(HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)),
+		(HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
 	assert_src_names_size);
 	assert_src_names_size);
 
 
 #if ASI_STYLE_NAMES
 #if ASI_STYLE_NAMES
@@ -1414,7 +1416,7 @@ static char *asihpi_dst_names[] =
 
 
 compile_time_assert(
 compile_time_assert(
 	(ARRAY_SIZE(asihpi_dst_names) ==
 	(ARRAY_SIZE(asihpi_dst_names) ==
-		(HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)),
+		(HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),
 	assert_dst_names_size);
 	assert_dst_names_size);
 
 
 static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
 static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
@@ -2171,7 +2173,7 @@ static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
 					&src_node_type, &src_node_index);
 					&src_node_type, &src_node_index);
 
 
 	sprintf(uinfo->value.enumerated.name, "%s %d",
 	sprintf(uinfo->value.enumerated.name, "%s %d",
-		asihpi_src_names[src_node_type - HPI_SOURCENODE_BASE],
+		asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE],
 		src_node_index);
 		src_node_index);
 	return 0;
 	return 0;
 }
 }
@@ -2603,8 +2605,8 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
 
 
 		}
 		}
 
 
-		hpi_ctl.src_node_type -= HPI_SOURCENODE_BASE;
-		hpi_ctl.dst_node_type -= HPI_DESTNODE_BASE;
+		hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE;
+		hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE;
 
 
 		/* ASI50xx in SSX mode has multiple meters on the same node.
 		/* ASI50xx in SSX mode has multiple meters on the same node.
 		   Use subindex to create distinct ALSA controls
 		   Use subindex to create distinct ALSA controls

+ 48 - 20
sound/pci/asihpi/hpi.h

@@ -50,7 +50,8 @@ i.e 3.05.02 is a development version
 #define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
 #define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
 
 
 /* Use single digits for versions less that 10 to avoid octal. */
 /* Use single digits for versions less that 10 to avoid octal. */
-#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 25)
+#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 4, 1)
+#define HPI_VER_STRING "4.04.01"
 
 
 /* Library version as documented in hpi-api-versions.txt */
 /* Library version as documented in hpi-api-versions.txt */
 #define HPI_LIB_VER  HPI_VERSION_CONSTRUCTOR(9, 0, 0)
 #define HPI_LIB_VER  HPI_VERSION_CONSTRUCTOR(9, 0, 0)
@@ -203,8 +204,6 @@ enum HPI_SOURCENODES {
 	exists on a destination node can be searched for using a source
 	exists on a destination node can be searched for using a source
 	node value of either 0, or HPI_SOURCENODE_NONE */
 	node value of either 0, or HPI_SOURCENODE_NONE */
 	HPI_SOURCENODE_NONE = 100,
 	HPI_SOURCENODE_NONE = 100,
-	/** \deprecated Use HPI_SOURCENODE_NONE instead. */
-	HPI_SOURCENODE_BASE = 100,
 	/** Out Stream (Play) node. */
 	/** Out Stream (Play) node. */
 	HPI_SOURCENODE_OSTREAM = 101,
 	HPI_SOURCENODE_OSTREAM = 101,
 	/** Line in node - could be analog, AES/EBU or network. */
 	/** Line in node - could be analog, AES/EBU or network. */
@@ -235,8 +234,6 @@ enum HPI_DESTNODES {
 	exists on a source node can be searched for using a destination
 	exists on a source node can be searched for using a destination
 	node value of either 0, or HPI_DESTNODE_NONE */
 	node value of either 0, or HPI_DESTNODE_NONE */
 	HPI_DESTNODE_NONE = 200,
 	HPI_DESTNODE_NONE = 200,
-	/** \deprecated Use HPI_DESTNODE_NONE instead. */
-	HPI_DESTNODE_BASE = 200,
 	/** In Stream (Record) node. */
 	/** In Stream (Record) node. */
 	HPI_DESTNODE_ISTREAM = 201,
 	HPI_DESTNODE_ISTREAM = 201,
 	HPI_DESTNODE_LINEOUT = 202,	    /**< line out node. */
 	HPI_DESTNODE_LINEOUT = 202,	    /**< line out node. */
@@ -432,7 +429,18 @@ Property 2 - adapter can do stream grouping (supports SSX2)
 Property 1 - adapter can do samplerate conversion (MRX)
 Property 1 - adapter can do samplerate conversion (MRX)
 Property 2 - adapter can do timestretch (TSX)
 Property 2 - adapter can do timestretch (TSX)
 */
 */
-	HPI_ADAPTER_PROPERTY_CAPS2 = 269
+	HPI_ADAPTER_PROPERTY_CAPS2 = 269,
+
+/** Readonly adapter sync header connection count.
+*/
+	HPI_ADAPTER_PROPERTY_SYNC_HEADER_CONNECTIONS = 270,
+/** Readonly supports SSX2 property.
+Indicates the adapter supports SSX2 in some mode setting. The
+return value is true (1) or false (0). If the current adapter
+mode is MONO SSX2 is disabled, even though this property will
+return true.
+*/
+	HPI_ADAPTER_PROPERTY_SUPPORTS_SSX2 = 271
 };
 };
 
 
 /** Adapter mode commands
 /** Adapter mode commands
@@ -813,8 +821,6 @@ enum HPI_SAMPLECLOCK_SOURCES {
 /** The sampleclock output is derived from its local samplerate generator.
 /** The sampleclock output is derived from its local samplerate generator.
     The local samplerate may be set using HPI_SampleClock_SetLocalRate(). */
     The local samplerate may be set using HPI_SampleClock_SetLocalRate(). */
 	HPI_SAMPLECLOCK_SOURCE_LOCAL = 1,
 	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.*/
 /** The adapter is clocked from a dedicated AES/EBU SampleClock input.*/
 	HPI_SAMPLECLOCK_SOURCE_AESEBU_SYNC = 2,
 	HPI_SAMPLECLOCK_SOURCE_AESEBU_SYNC = 2,
 /** From external wordclock connector */
 /** From external wordclock connector */
@@ -825,10 +831,6 @@ enum HPI_SAMPLECLOCK_SOURCES {
 	HPI_SAMPLECLOCK_SOURCE_SMPTE = 5,
 	HPI_SAMPLECLOCK_SOURCE_SMPTE = 5,
 /** One of the aesebu inputs */
 /** One of the aesebu inputs */
 	HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT = 6,
 	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 */
 /** From a network interface e.g. Cobranet or Livewire at either 48 or 96kHz */
 	HPI_SAMPLECLOCK_SOURCE_NETWORK = 8,
 	HPI_SAMPLECLOCK_SOURCE_NETWORK = 8,
 /** From previous adjacent module (ASI2416 only)*/
 /** From previous adjacent module (ASI2416 only)*/
@@ -1015,8 +1017,6 @@ enum HPI_ERROR_CODES {
 	HPI_ERROR_CONTROL_DISABLED = 404,
 	HPI_ERROR_CONTROL_DISABLED = 404,
 	/** I2C transaction failed due to a missing ACK. */
 	/** I2C transaction failed due to a missing ACK. */
 	HPI_ERROR_CONTROL_I2C_MISSING_ACK = 405,
 	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
 	/** Control is busy, or coming out of
 	reset and cannot be accessed at this time. */
 	reset and cannot be accessed at this time. */
 	HPI_ERROR_CONTROL_NOT_READY = 407,
 	HPI_ERROR_CONTROL_NOT_READY = 407,
@@ -1827,13 +1827,41 @@ u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys,
   Compressor Expander control
   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_set_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 on);
+
+u16 hpi_compander_get_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *pon);
+
+u16 hpi_compander_set_makeup_gain(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, short makeup_gain0_01dB);
+
+u16 hpi_compander_get_makeup_gain(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, short *pn_makeup_gain0_01dB);
+
+u16 hpi_compander_set_attack_time_constant(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, u32 index, u32 attack);
+
+u16 hpi_compander_get_attack_time_constant(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, u32 index, u32 *pw_attack);
+
+u16 hpi_compander_set_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 index, u32 decay);
+
+u16 hpi_compander_get_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 index, u32 *pw_decay);
+
+u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 index, short threshold0_01dB);
+
+u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 index, short *pn_threshold0_01dB);
+
+u16 hpi_compander_set_ratio(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 index, u32 ratio100);
 
 
-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);
+u16 hpi_compander_get_ratio(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 index, u32 *pw_ratio100);
 
 
 /*******************************
 /*******************************
   Cobranet HMI control
   Cobranet HMI control

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

@@ -687,6 +687,7 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
 	switch (pao->pci.subsys_device_id) {
 	switch (pao->pci.subsys_device_id) {
 	case 0x5100:
 	case 0x5100:
 	case 0x5110:	/* ASI5100 revB or higher with C6711D */
 	case 0x5110:	/* ASI5100 revB or higher with C6711D */
+	case 0x5200:	/* ASI5200 PC_ie version of ASI5100 */
 	case 0x6100:
 	case 0x6100:
 	case 0x6200:
 	case 0x6200:
 		boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200);
 		boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200);
@@ -1133,6 +1134,12 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
 						subsys_device_id) ==
 						subsys_device_id) ==
 					HPI_ADAPTER_FAMILY_ASI(0x5100))
 					HPI_ADAPTER_FAMILY_ASI(0x5100))
 					mask = 0x00000000L;
 					mask = 0x00000000L;
+				/* ASI5200 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(0x5200))
+					mask = 0x00000000L;
 				break;
 				break;
 			case HPI_ADAPTER_FAMILY_ASI(0x8800):
 			case HPI_ADAPTER_FAMILY_ASI(0x8800):
 				/* ASI8800 has 16bit path to FPGA */
 				/* ASI8800 has 16bit path to FPGA */

+ 22 - 18
sound/pci/asihpi/hpi_internal.h

@@ -104,9 +104,9 @@ typedef void hpi_handler_func(struct hpi_message *, struct hpi_response *);
 #define STR_ROLE_FIELD_MAX 255U
 #define STR_ROLE_FIELD_MAX 255U
 
 
 struct hpi_entity_str {
 struct hpi_entity_str {
-	uint16_t size;
-	uint8_t type;
-	uint8_t role;
+	u16 size;
+	u8 type;
+	u8 role;
 };
 };
 
 
 #if defined(_MSC_VER)
 #if defined(_MSC_VER)
@@ -119,11 +119,11 @@ struct hpi_entity {
 #if ! defined(HPI_OS_DSP_C6000) || (defined(HPI_OS_DSP_C6000) && (__TI_COMPILER_VERSION__ > 6000008))
 #if ! defined(HPI_OS_DSP_C6000) || (defined(HPI_OS_DSP_C6000) && (__TI_COMPILER_VERSION__ > 6000008))
 	/* DSP C6000 compiler v6.0.8 and lower
 	/* DSP C6000 compiler v6.0.8 and lower
 	   do not support  flexible array member */
 	   do not support  flexible array member */
-	uint8_t value[];
+	u8 value[];
 #else
 #else
 	/* NOTE! Using sizeof(struct hpi_entity) will give erroneous results */
 	/* NOTE! Using sizeof(struct hpi_entity) will give erroneous results */
 #define HPI_INTERNAL_WARN_ABOUT_ENTITY_VALUE
 #define HPI_INTERNAL_WARN_ABOUT_ENTITY_VALUE
-	uint8_t value[1];
+	u8 value[1];
 #endif
 #endif
 };
 };
 
 
@@ -142,12 +142,15 @@ enum HPI_BUSES {
 /******************************************* CONTROL ATTRIBUTES ****/
 /******************************************* CONTROL ATTRIBUTES ****/
 /* (in order of control type ID */
 /* (in order of control type ID */
 
 
-	/* This allows for 255 control types, 256 unique attributes each */
+/* This allows for 255 control types, 256 unique attributes each */
 #define HPI_CTL_ATTR(ctl, ai) (HPI_CONTROL_##ctl * 0x100 + ai)
 #define HPI_CTL_ATTR(ctl, ai) (HPI_CONTROL_##ctl * 0x100 + ai)
 
 
 /* Get the sub-index of the attribute for a control type */
 /* Get the sub-index of the attribute for a control type */
 #define HPI_CTL_ATTR_INDEX(i) (i&0xff)
 #define HPI_CTL_ATTR_INDEX(i) (i&0xff)
 
 
+/* Extract the control from the control attribute */
+#define HPI_CTL_ATTR_CONTROL(i) (i>>8)
+
 /* Generic control attributes.  */
 /* Generic control attributes.  */
 
 
 /** Enable a control.
 /** Enable a control.
@@ -311,8 +314,7 @@ Used for HPI_ChannelModeSet/Get()
 /* Microphone control attributes */
 /* Microphone control attributes */
 #define HPI_MICROPHONE_PHANTOM_POWER HPI_CTL_ATTR(MICROPHONE, 1)
 #define HPI_MICROPHONE_PHANTOM_POWER HPI_CTL_ATTR(MICROPHONE, 1)
 
 
-/** Equalizer control attributes
-*/
+/** Equalizer control attributes */
 /** Used to get number of filters in an EQ. (Can't set) */
 /** Used to get number of filters in an EQ. (Can't set) */
 #define HPI_EQUALIZER_NUM_FILTERS HPI_CTL_ATTR(EQUALIZER, 1)
 #define HPI_EQUALIZER_NUM_FILTERS HPI_CTL_ATTR(EQUALIZER, 1)
 /** Set/get the filter by type, freq, Q, gain */
 /** Set/get the filter by type, freq, Q, gain */
@@ -320,13 +322,15 @@ Used for HPI_ChannelModeSet/Get()
 /** Get the biquad coefficients */
 /** Get the biquad coefficients */
 #define HPI_EQUALIZER_COEFFICIENTS HPI_CTL_ATTR(EQUALIZER, 3)
 #define HPI_EQUALIZER_COEFFICIENTS HPI_CTL_ATTR(EQUALIZER, 3)
 
 
-#define HPI_COMPANDER_PARAMS HPI_CTL_ATTR(COMPANDER, 1)
+/* Note compander also uses HPI_GENERIC_ENABLE */
+#define HPI_COMPANDER_PARAMS     HPI_CTL_ATTR(COMPANDER, 1)
+#define HPI_COMPANDER_MAKEUPGAIN HPI_CTL_ATTR(COMPANDER, 2)
+#define HPI_COMPANDER_THRESHOLD  HPI_CTL_ATTR(COMPANDER, 3)
+#define HPI_COMPANDER_RATIO      HPI_CTL_ATTR(COMPANDER, 4)
+#define HPI_COMPANDER_ATTACK     HPI_CTL_ATTR(COMPANDER, 5)
+#define HPI_COMPANDER_DECAY      HPI_CTL_ATTR(COMPANDER, 6)
 
 
-/* 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.
-*/
+/* Cobranet control attributes. */
 #define HPI_COBRANET_SET         HPI_CTL_ATTR(COBRANET, 1)
 #define HPI_COBRANET_SET         HPI_CTL_ATTR(COBRANET, 1)
 #define HPI_COBRANET_GET         HPI_CTL_ATTR(COBRANET, 2)
 #define HPI_COBRANET_GET         HPI_CTL_ATTR(COBRANET, 2)
 #define HPI_COBRANET_SET_DATA    HPI_CTL_ATTR(COBRANET, 3)
 #define HPI_COBRANET_SET_DATA    HPI_CTL_ATTR(COBRANET, 3)
@@ -1512,11 +1516,11 @@ struct hpi_control_cache_single {
 	struct hpi_control_cache_info i;
 	struct hpi_control_cache_info i;
 	union {
 	union {
 		struct {	/* volume */
 		struct {	/* volume */
-			u16 an_log[2];
+			short an_log[2];
 		} v;
 		} v;
 		struct {	/* peak meter */
 		struct {	/* peak meter */
-			u16 an_log_peak[2];
-			u16 an_logRMS[2];
+			short an_log_peak[2];
+			short an_logRMS[2];
 		} p;
 		} p;
 		struct {	/* channel mode */
 		struct {	/* channel mode */
 			u16 mode;
 			u16 mode;
@@ -1526,7 +1530,7 @@ struct hpi_control_cache_single {
 			u16 source_node_index;
 			u16 source_node_index;
 		} x;
 		} x;
 		struct {	/* level/trim */
 		struct {	/* level/trim */
-			u16 an_log[2];
+			short an_log[2];
 		} l;
 		} l;
 		struct {	/* tuner - partial caching.
 		struct {	/* tuner - partial caching.
 				   some attributes go to the DSP. */
 				   some attributes go to the DSP. */

+ 8 - 2
sound/pci/asihpi/hpicmn.c

@@ -353,7 +353,12 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
 			phr->u.c.param1 = pC->u.t.band;
 			phr->u.c.param1 = pC->u.t.band;
 		else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
 		else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
 			&& (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE))
 			&& (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE))
-			phr->u.c.param1 = pC->u.t.level;
+			if (pC->u.t.level == HPI_ERROR_ILLEGAL_CACHE_VALUE) {
+				phr->u.c.param1 = 0;
+				phr->error =
+					HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
+			} else
+				phr->u.c.param1 = pC->u.t.level;
 		else
 		else
 			found = 0;
 			found = 0;
 		break;
 		break;
@@ -397,7 +402,8 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
 			if (pC->u.clk.source_index ==
 			if (pC->u.clk.source_index ==
 				HPI_ERROR_ILLEGAL_CACHE_VALUE) {
 				HPI_ERROR_ILLEGAL_CACHE_VALUE) {
 				phr->u.c.param1 = 0;
 				phr->u.c.param1 = 0;
-				phr->error = HPI_ERROR_INVALID_OPERATION;
+				phr->error =
+					HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
 			} else
 			} else
 				phr->u.c.param1 = pC->u.clk.source_index;
 				phr->u.c.param1 = pC->u.clk.source_index;
 		} else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
 		} else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)

+ 1 - 1
sound/pci/asihpi/hpidebug.c

@@ -111,7 +111,7 @@ make_treenode_from_array(hpi_control_type_strings, HPI_CONTROL_TYPE_STRINGS)
   &hpi_profile_strings,\
   &hpi_profile_strings,\
   &hpi_control_strings, \
   &hpi_control_strings, \
   &hpi_asyncevent_strings \
   &hpi_asyncevent_strings \
-};
+}
 	make_treenode_from_array(hpi_function_strings, HPI_FUNCTION_STRINGS)
 	make_treenode_from_array(hpi_function_strings, HPI_FUNCTION_STRINGS)
 
 
 	compile_time_assert(HPI_OBJ_MAXINDEX == 14, obj_list_doesnt_match);
 	compile_time_assert(HPI_OBJ_MAXINDEX == 14, obj_list_doesnt_match);

+ 2 - 2
sound/pci/asihpi/hpidebug.h

@@ -356,7 +356,7 @@ compile_time_assert((HPI_CONTROL_LAST_INDEX + 1 == 27),
 	"HPI_SOURCENODE_ADAPTER" \
 	"HPI_SOURCENODE_ADAPTER" \
 }
 }
 
 
-compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) ==
+compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_NONE + 1) ==
 	(12), sourcenode_strings_match_defs);
 	(12), sourcenode_strings_match_defs);
 
 
 #define HPI_DESTNODE_STRINGS \
 #define HPI_DESTNODE_STRINGS \
@@ -370,7 +370,7 @@ compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) ==
 	"HPI_DESTNODE_COBRANET", \
 	"HPI_DESTNODE_COBRANET", \
 	"HPI_DESTNODE_ANALOG" \
 	"HPI_DESTNODE_ANALOG" \
 }
 }
-compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_BASE + 1) == (8),
+compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_NONE + 1) == (8),
 	destnode_strings_match_defs);
 	destnode_strings_match_defs);
 
 
 #define HPI_CONTROL_CHANNEL_MODE_STRINGS \
 #define HPI_CONTROL_CHANNEL_MODE_STRINGS \

+ 195 - 132
sound/pci/asihpi/hpifunc.c

@@ -96,8 +96,7 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR)
 
 
 static struct hpi_hsubsys gh_subsys;
 static struct hpi_hsubsys gh_subsys;
 
 
-struct hpi_hsubsys *hpi_subsys_create(void
-	)
+struct hpi_hsubsys *hpi_subsys_create(void)
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
@@ -302,6 +301,7 @@ u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
 		HPI_ADAPTER_SET_MODE);
 		HPI_ADAPTER_SET_MODE);
 	hm.adapter_index = adapter_index;
 	hm.adapter_index = adapter_index;
@@ -510,7 +510,7 @@ u16 hpi_adapter_debug_read(const struct hpi_hsubsys *ph_subsys,
 	hm.adapter_index = adapter_index;
 	hm.adapter_index = adapter_index;
 	hm.u.ax.debug_read.dsp_address = dsp_address;
 	hm.u.ax.debug_read.dsp_address = dsp_address;
 
 
-	if (*count_bytes > sizeof(hr.u.bytes))
+	if (*count_bytes > (int)sizeof(hr.u.bytes))
 		*count_bytes = sizeof(hr.u.bytes);
 		*count_bytes = sizeof(hr.u.bytes);
 
 
 	hm.u.ax.debug_read.count_bytes = *count_bytes;
 	hm.u.ax.debug_read.count_bytes = *count_bytes;
@@ -976,6 +976,7 @@ u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
 		HPI_OSTREAM_ANC_READ);
 		HPI_OSTREAM_ANC_READ);
 	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
@@ -1581,6 +1582,7 @@ u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_SET_STATE);
 		HPI_CONTROL_SET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -1591,6 +1593,22 @@ u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys,
 	return hr.error;
 	return hr.error;
 }
 }
 
 
+static u16 hpi_control_log_set2(u32 h_control, u16 attrib, short sv0,
+	short sv1)
+{
+	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.an_log_value[0] = sv0;
+	hm.u.c.an_log_value[1] = sv1;
+	hpi_send_recv(&hm, &hr);
+	return hr.error;
+}
+
 static
 static
 u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
 	const u32 h_control, const u16 attrib, u32 param1, u32 param2,
 	const u32 h_control, const u16 attrib, u32 param1, u32 param2,
@@ -1598,6 +1616,7 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -1605,8 +1624,8 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
 	hm.u.c.param1 = param1;
 	hm.u.c.param1 = param1;
 	hm.u.c.param2 = param2;
 	hm.u.c.param2 = param2;
 	hpi_send_recv(&hm, &hr);
 	hpi_send_recv(&hm, &hr);
-	if (pparam1)
-		*pparam1 = hr.u.c.param1;
+
+	*pparam1 = hr.u.c.param1;
 	if (pparam2)
 	if (pparam2)
 		*pparam2 = hr.u.c.param2;
 		*pparam2 = hr.u.c.param2;
 
 
@@ -1617,10 +1636,23 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
 		hpi_control_param_get(s, h, a, 0, 0, p1, NULL)
 		hpi_control_param_get(s, h, a, 0, 0, p1, NULL)
 #define hpi_control_param2_get(s, h, a, p1, p2) \
 #define hpi_control_param2_get(s, h, a, p1, p2) \
 		hpi_control_param_get(s, h, a, 0, 0, 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_log_get2(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u16 attrib, short *sv0, short *sv1)
+{
+	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;
+
+	hpi_send_recv(&hm, &hr);
+	*sv0 = hr.u.c.an_log_value[0];
+	if (sv1)
+		*sv1 = hr.u.c.an_log_value[1];
+	return hr.error;
+}
 
 
 static
 static
 u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys,
@@ -1629,6 +1661,7 @@ u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_GET_INFO);
 		HPI_CONTROL_GET_INFO);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -1643,9 +1676,8 @@ u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys,
 	return hr.error;
 	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)
+static u16 hpi_control_get_string(const u32 h_control, const u16 attribute,
+	char *psz_string, const u32 string_length)
 {
 {
 	unsigned int sub_string_index = 0, j = 0;
 	unsigned int sub_string_index = 0, j = 0;
 	char c = 0;
 	char c = 0;
@@ -1916,6 +1948,7 @@ u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
 		HPI_CONTROL_SET_STATE);
 		HPI_CONTROL_SET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -1941,6 +1974,7 @@ u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -1980,6 +2014,7 @@ u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2006,6 +2041,7 @@ u16 hpi_cobranet_getI_paddress(const struct hpi_hsubsys *ph_subsys,
 	u32 byte_count;
 	u32 byte_count;
 	u32 iP;
 	u32 iP;
 	u16 error;
 	u16 error;
+
 	error = hpi_cobranet_hmi_read(ph_subsys, h_control,
 	error = hpi_cobranet_hmi_read(ph_subsys, h_control,
 		HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, &byte_count,
 		HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, &byte_count,
 		(u8 *)&iP);
 		(u8 *)&iP);
@@ -2082,6 +2118,7 @@ u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys,
 	u32 byte_count;
 	u32 byte_count;
 	u16 error;
 	u16 error;
 	u32 mAC;
 	u32 mAC;
+
 	error = hpi_cobranet_hmi_read(ph_subsys, h_control,
 	error = hpi_cobranet_hmi_read(ph_subsys, h_control,
 		HPI_COBRANET_HMI_cobra_if_phy_address, 4, &byte_count,
 		HPI_COBRANET_HMI_cobra_if_phy_address, 4, &byte_count,
 		(u8 *)&mAC);
 		(u8 *)&mAC);
@@ -2103,53 +2140,111 @@ u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys,
 	return error;
 	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)
+u16 hpi_compander_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,
+		enable, 0);
+}
+
+u16 hpi_compander_get_enable(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 *enable)
+{
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_GENERIC_ENABLE, enable);
+}
+
+u16 hpi_compander_set_makeup_gain(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, short makeup_gain0_01dB)
+{
+	return hpi_control_log_set2(h_control, HPI_COMPANDER_MAKEUPGAIN,
+		makeup_gain0_01dB, 0);
+}
+
+u16 hpi_compander_get_makeup_gain(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, short *makeup_gain0_01dB)
+{
+	return hpi_control_log_get2(ph_subsys, h_control,
+		HPI_COMPANDER_MAKEUPGAIN, makeup_gain0_01dB, NULL);
+}
+
+u16 hpi_compander_set_attack_time_constant(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, unsigned int index, u32 attack)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_COMPANDER_ATTACK, attack, index);
+}
+
+u16 hpi_compander_get_attack_time_constant(const struct hpi_hsubsys
+	*ph_subsys, u32 h_control, unsigned int index, u32 *attack)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_COMPANDER_ATTACK, 0, index, attack, NULL);
+}
+
+u16 hpi_compander_set_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, unsigned int index, u32 decay)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_COMPANDER_DECAY, decay, index);
+}
+
+u16 hpi_compander_get_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, unsigned int index, u32 *decay)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_COMPANDER_DECAY, 0, index, decay, NULL);
+
+}
+
+u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, unsigned int index, short threshold0_01dB)
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_SET_STATE);
 		HPI_CONTROL_SET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	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.attribute = HPI_COMPANDER_THRESHOLD;
+	hm.u.c.param2 = index;
 	hm.u.c.an_log_value[0] = threshold0_01dB;
 	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);
 	hpi_send_recv(&hm, &hr);
 
 
 	return hr.error;
 	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)
+u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, unsigned int index, short *threshold0_01dB)
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
-	hm.u.c.attribute = HPI_COMPANDER_PARAMS;
+	hm.u.c.attribute = HPI_COMPANDER_THRESHOLD;
+	hm.u.c.param2 = index;
 
 
 	hpi_send_recv(&hm, &hr);
 	hpi_send_recv(&hm, &hr);
+	*threshold0_01dB = hr.u.c.an_log_value[0];
 
 
-	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);
+	return hr.error;
+}
 
 
-	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];
+u16 hpi_compander_set_ratio(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 index, u32 ratio100)
+{
+	return hpi_control_param_set(ph_subsys, h_control,
+		HPI_COMPANDER_RATIO, ratio100, index);
+}
 
 
-	return hr.error;
+u16 hpi_compander_get_ratio(const struct hpi_hsubsys *ph_subsys,
+	u32 h_control, u32 index, u32 *ratio100)
+{
+	return hpi_control_param_get(ph_subsys, h_control,
+		HPI_COMPANDER_RATIO, 0, index, ratio100, NULL);
 }
 }
 
 
 u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
@@ -2157,6 +2252,7 @@ u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2181,37 +2277,16 @@ u16 hpi_level_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 	short an_gain0_01dB[HPI_MAX_CHANNELS]
 	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;
+	return hpi_control_log_set2(h_control, HPI_LEVEL_GAIN,
+		an_gain0_01dB[0], an_gain0_01dB[1]);
 }
 }
 
 
 u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 	short an_gain0_01dB[HPI_MAX_CHANNELS]
 	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;
+	return hpi_control_log_get2(ph_subsys, h_control, HPI_LEVEL_GAIN,
+		&an_gain0_01dB[0], &an_gain0_01dB[1]);
 }
 }
 
 
 u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys,
@@ -2413,6 +2488,7 @@ u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2439,6 +2515,7 @@ u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_SET_STATE);
 		HPI_CONTROL_SET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2460,6 +2537,7 @@ u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2623,8 +2701,8 @@ u16 hpi_tone_detector_get_frequency(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 *state)
 	u32 h_control, u32 *state)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control,
-		HPI_TONEDETECTOR_STATE, 0, 0, (u32 *)state, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_TONEDETECTOR_STATE, state);
 }
 }
 
 
 u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
@@ -2637,8 +2715,8 @@ u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 *enable)
 	u32 h_control, u32 *enable)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE,
-		0, 0, (u32 *)enable, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_GENERIC_ENABLE, enable);
 }
 }
 
 
 u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
@@ -2651,8 +2729,8 @@ u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 *event_enable)
 	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);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_GENERIC_EVENT_ENABLE, event_enable);
 }
 }
 
 
 u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
@@ -2665,15 +2743,15 @@ u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, int *threshold)
 	u32 h_control, int *threshold)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control,
-		HPI_TONEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_TONEDETECTOR_THRESHOLD, (u32 *)threshold);
 }
 }
 
 
 u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 *state)
 	u32 h_control, u32 *state)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control,
-		HPI_SILENCEDETECTOR_STATE, 0, 0, (u32 *)state, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_SILENCEDETECTOR_STATE, state);
 }
 }
 
 
 u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
@@ -2686,50 +2764,50 @@ u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 *enable)
 	u32 h_control, u32 *enable)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE,
-		0, 0, (u32 *)enable, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_GENERIC_ENABLE, enable);
 }
 }
 
 
 u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 event_enable)
 	u32 h_control, u32 event_enable)
 {
 {
 	return hpi_control_param_set(ph_subsys, h_control,
 	return hpi_control_param_set(ph_subsys, h_control,
-		HPI_GENERIC_EVENT_ENABLE, (u32)event_enable, 0);
+		HPI_GENERIC_EVENT_ENABLE, event_enable, 0);
 }
 }
 
 
 u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 *event_enable)
 	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);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_GENERIC_EVENT_ENABLE, event_enable);
 }
 }
 
 
 u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 delay)
 	u32 h_control, u32 delay)
 {
 {
 	return hpi_control_param_set(ph_subsys, h_control,
 	return hpi_control_param_set(ph_subsys, h_control,
-		HPI_SILENCEDETECTOR_DELAY, (u32)delay, 0);
+		HPI_SILENCEDETECTOR_DELAY, delay, 0);
 }
 }
 
 
 u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 *delay)
 	u32 h_control, u32 *delay)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control,
-		HPI_SILENCEDETECTOR_DELAY, 0, 0, (u32 *)delay, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_SILENCEDETECTOR_DELAY, delay);
 }
 }
 
 
 u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, int threshold)
 	u32 h_control, int threshold)
 {
 {
 	return hpi_control_param_set(ph_subsys, h_control,
 	return hpi_control_param_set(ph_subsys, h_control,
-		HPI_SILENCEDETECTOR_THRESHOLD, (u32)threshold, 0);
+		HPI_SILENCEDETECTOR_THRESHOLD, threshold, 0);
 }
 }
 
 
 u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, int *threshold)
 	u32 h_control, int *threshold)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control,
-		HPI_SILENCEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_SILENCEDETECTOR_THRESHOLD, (u32 *)threshold);
 }
 }
 
 
 u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys,
@@ -2822,6 +2900,7 @@ u16 hpi_tuner_getRF_level(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2838,6 +2917,7 @@ u16 hpi_tuner_get_rawRF_level(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2894,14 +2974,14 @@ u16 hpi_tuner_get_program(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys,
 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)
 	u32 h_control, char *psz_dsp_version, const u32 string_size)
 {
 {
-	return hpi_control_get_string(ph_subsys, h_control,
+	return hpi_control_get_string(h_control,
 		HPI_TUNER_HDRADIO_DSP_VERSION, psz_dsp_version, string_size);
 		HPI_TUNER_HDRADIO_DSP_VERSION, psz_dsp_version, string_size);
 }
 }
 
 
 u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys,
 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)
 	u32 h_control, char *psz_sdk_version, const u32 string_size)
 {
 {
-	return hpi_control_get_string(ph_subsys, h_control,
+	return hpi_control_get_string(h_control,
 		HPI_TUNER_HDRADIO_SDK_VERSION, psz_sdk_version, string_size);
 		HPI_TUNER_HDRADIO_SDK_VERSION, psz_sdk_version, string_size);
 }
 }
 
 
@@ -2942,15 +3022,15 @@ u16 hpi_tuner_get_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 *pquality)
 	u32 h_control, u32 *pquality)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control,
-		HPI_TUNER_HDRADIO_SIGNAL_QUALITY, 0, 0, pquality, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_TUNER_HDRADIO_SIGNAL_QUALITY, pquality);
 }
 }
 
 
 u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 *pblend)
 	u32 h_control, u32 *pblend)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control,
-		HPI_TUNER_HDRADIO_BLEND, 0, 0, pblend, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_TUNER_HDRADIO_BLEND, pblend);
 }
 }
 
 
 u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
@@ -2965,6 +3045,7 @@ u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2981,43 +3062,43 @@ u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys,
 u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, char *psz_string, const u32 data_length)
 	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);
+	return hpi_control_get_string(h_control, HPI_PAD_CHANNEL_NAME,
+		psz_string, data_length);
 }
 }
 
 
 u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 	char *psz_string, const u32 data_length)
 	char *psz_string, const u32 data_length)
 {
 {
-	return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_ARTIST,
-		psz_string, data_length);
+	return hpi_control_get_string(h_control, HPI_PAD_ARTIST, psz_string,
+		data_length);
 }
 }
 
 
 u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 	char *psz_string, const u32 data_length)
 	char *psz_string, const u32 data_length)
 {
 {
-	return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_TITLE,
-		psz_string, data_length);
+	return hpi_control_get_string(h_control, HPI_PAD_TITLE, psz_string,
+		data_length);
 }
 }
 
 
 u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 	char *psz_string, const u32 data_length)
 	char *psz_string, const u32 data_length)
 {
 {
-	return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_COMMENT,
-		psz_string, data_length);
+	return hpi_control_get_string(h_control, HPI_PAD_COMMENT, psz_string,
+		data_length);
 }
 }
 
 
 u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys,
 u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys,
 	u32 h_control, u32 *ppTY)
 	u32 h_control, u32 *ppTY)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control,
-		HPI_PAD_PROGRAM_TYPE, 0, 0, ppTY, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_PAD_PROGRAM_TYPE, ppTY);
 }
 }
 
 
 u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 	u32 *ppI)
 	u32 *ppI)
 {
 {
-	return hpi_control_param_get(ph_subsys, h_control, HPI_PAD_PROGRAM_ID,
-		0, 0, ppI, NULL);
+	return hpi_control_param1_get(ph_subsys, h_control,
+		HPI_PAD_PROGRAM_ID, ppI);
 }
 }
 
 
 u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys,
 u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys,
@@ -3031,36 +3112,16 @@ u16 hpi_volume_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 	short an_log_gain[HPI_MAX_CHANNELS]
 	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;
+	return hpi_control_log_set2(h_control, HPI_VOLUME_GAIN,
+		an_log_gain[0], an_log_gain[1]);
 }
 }
 
 
 u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 	short an_log_gain[HPI_MAX_CHANNELS]
 	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;
+	return hpi_control_log_get2(ph_subsys, h_control, HPI_VOLUME_GAIN,
+		&an_log_gain[0], &an_log_gain[1]);
 }
 }
 
 
 u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
@@ -3068,6 +3129,7 @@ u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_GET_STATE);
 		HPI_CONTROL_GET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -3094,6 +3156,7 @@ u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys,
 {
 {
 	struct hpi_message hm;
 	struct hpi_message hm;
 	struct hpi_response hr;
 	struct hpi_response hr;
+
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
 		HPI_CONTROL_SET_STATE);
 		HPI_CONTROL_SET_STATE);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
 	u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -3170,43 +3233,42 @@ static size_t entity_type_to_size[LAST_ENTITY_TYPE] = {
 	6 * sizeof(char),
 	6 * sizeof(char),
 };
 };
 
 
-inline size_t hpi_entity_size(struct hpi_entity *entity_ptr)
+static inline size_t hpi_entity_size(struct hpi_entity *entity_ptr)
 {
 {
 	return entity_ptr->header.size;
 	return entity_ptr->header.size;
 }
 }
 
 
-inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr)
+static inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr)
 {
 {
 	return sizeof(entity_ptr->header);
 	return sizeof(entity_ptr->header);
 }
 }
 
 
-inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr)
+static inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr)
 {
 {
 	return hpi_entity_size(entity_ptr) -
 	return hpi_entity_size(entity_ptr) -
 		hpi_entity_header_size(entity_ptr);
 		hpi_entity_header_size(entity_ptr);
 }
 }
 
 
-inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr)
+static inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr)
 {
 {
 	return hpi_entity_value_size(entity_ptr) /
 	return hpi_entity_value_size(entity_ptr) /
 		entity_type_to_size[entity_ptr->header.type];
 		entity_type_to_size[entity_ptr->header.type];
 }
 }
 
 
-inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity
+static inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity
 	*entity_ptr)
 	*entity_ptr)
 {
 {
-	return (void *)(((uint8_t *) entity_ptr) +
-		hpi_entity_size(entity_ptr));
+	return (void *)(((u8 *)entity_ptr) + hpi_entity_size(entity_ptr));
 }
 }
 
 
-inline u16 hpi_entity_check_type(const enum e_entity_type t)
+static inline u16 hpi_entity_check_type(const enum e_entity_type t)
 {
 {
 	if (t >= 0 && t < STR_TYPE_FIELD_MAX)
 	if (t >= 0 && t < STR_TYPE_FIELD_MAX)
 		return 0;
 		return 0;
 	return HPI_ERROR_ENTITY_TYPE_INVALID;
 	return HPI_ERROR_ENTITY_TYPE_INVALID;
 }
 }
 
 
-inline u16 hpi_entity_check_role(const enum e_entity_role r)
+static inline u16 hpi_entity_check_role(const enum e_entity_role r)
 {
 {
 	if (r >= 0 && r < STR_ROLE_FIELD_MAX)
 	if (r >= 0 && r < STR_ROLE_FIELD_MAX)
 		return 0;
 		return 0;
@@ -3624,6 +3686,7 @@ u16 hpi_async_event_wait(const struct hpi_hsubsys *ph_subsys, u32 h_async,
 	u16 maximum_events, struct hpi_async_event *p_events,
 	u16 maximum_events, struct hpi_async_event *p_events,
 	u16 *pw_number_returned)
 	u16 *pw_number_returned)
 {
 {
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
sound/pci/asihpi/hpimsgx.c

@@ -741,7 +741,7 @@ static void HPIMSGX__reset(u16 adapter_index)
 		hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM,
 		hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM,
 			HPI_SUBSYS_FIND_ADAPTERS, 0);
 			HPI_SUBSYS_FIND_ADAPTERS, 0);
 		memcpy(&gRESP_HPI_SUBSYS_FIND_ADAPTERS, &hr,
 		memcpy(&gRESP_HPI_SUBSYS_FIND_ADAPTERS, &hr,
-			sizeof(&gRESP_HPI_SUBSYS_FIND_ADAPTERS));
+			sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS));
 
 
 		for (adapter = 0; adapter < HPI_MAX_ADAPTERS; adapter++) {
 		for (adapter = 0; adapter < HPI_MAX_ADAPTERS; adapter++) {
 
 

+ 14 - 7
sound/pci/asihpi/hpioctl.c

@@ -121,11 +121,17 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg;
 	phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg;
 
 
 	/* Read the message and response pointers from user space.  */
 	/* Read the message and response pointers from user space.  */
-	get_user(puhm, &phpi_ioctl_data->phm);
-	get_user(puhr, &phpi_ioctl_data->phr);
+	if (get_user(puhm, &phpi_ioctl_data->phm) ||
+	    get_user(puhr, &phpi_ioctl_data->phr)) {
+		err = -EFAULT;
+		goto out;
+	}
 
 
 	/* Now read the message size and data from user space.  */
 	/* Now read the message size and data from user space.  */
-	get_user(hm->h.size, (u16 __user *)puhm);
+	if (get_user(hm->h.size, (u16 __user *)puhm)) {
+		err = -EFAULT;
+		goto out;
+	}
 	if (hm->h.size > sizeof(*hm))
 	if (hm->h.size > sizeof(*hm))
 		hm->h.size = sizeof(*hm);
 		hm->h.size = sizeof(*hm);
 
 
@@ -138,7 +144,10 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	get_user(res_max_size, (u16 __user *)puhr);
+	if (get_user(res_max_size, (u16 __user *)puhr)) {
+		err = -EFAULT;
+		goto out;
+	}
 	/* printk(KERN_INFO "user response size %d\n", res_max_size); */
 	/* printk(KERN_INFO "user response size %d\n", res_max_size); */
 	if (res_max_size < sizeof(struct hpi_response_header)) {
 	if (res_max_size < sizeof(struct hpi_response_header)) {
 		HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size);
 		HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size);
@@ -464,9 +473,7 @@ void __init asihpi_init(void)
 
 
 	memset(adapters, 0, sizeof(adapters));
 	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));
+	printk(KERN_INFO "ASIHPI driver " HPI_VER_STRING "\n");
 
 
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
 	hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
 		HPI_SUBSYS_DRIVER_LOAD);
 		HPI_SUBSYS_DRIVER_LOAD);

+ 2 - 0
sound/pci/echoaudio/echoaudio.c

@@ -2250,6 +2250,8 @@ static int snd_echo_resume(struct pci_dev *pci)
 	DE_INIT(("resume start\n"));
 	DE_INIT(("resume start\n"));
 	pci_restore_state(pci);
 	pci_restore_state(pci);
 	commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
 	commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
+	if (commpage_bak == NULL)
+		return -ENOMEM;
 	commpage = chip->comm_page;
 	commpage = chip->comm_page;
 	memcpy(commpage_bak, commpage, sizeof(struct comm_page));
 	memcpy(commpage_bak, commpage, sizeof(struct comm_page));
 
 

+ 61 - 36
sound/pci/hda/hda_codec.c

@@ -396,15 +396,18 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 			}
 			}
 			for (n = prev_nid + 1; n <= val; n++) {
 			for (n = prev_nid + 1; n <= val; n++) {
 				if (conns >= max_conns) {
 				if (conns >= max_conns) {
-					snd_printk(KERN_ERR
-						   "Too many connections\n");
+					snd_printk(KERN_ERR "hda_codec: "
+						   "Too many connections %d for NID 0x%x\n",
+						   conns, nid);
 					return -EINVAL;
 					return -EINVAL;
 				}
 				}
 				conn_list[conns++] = n;
 				conn_list[conns++] = n;
 			}
 			}
 		} else {
 		} else {
 			if (conns >= max_conns) {
 			if (conns >= max_conns) {
-				snd_printk(KERN_ERR "Too many connections\n");
+				snd_printk(KERN_ERR "hda_codec: "
+					   "Too many connections %d for NID 0x%x\n",
+					   conns, nid);
 				return -EINVAL;
 				return -EINVAL;
 			}
 			}
 			conn_list[conns++] = val;
 			conn_list[conns++] = val;
@@ -730,15 +733,17 @@ static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec)
 	total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
 	total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
 	for (i = 0; i < total_nodes; i++, nid++) {
 	for (i = 0; i < total_nodes; i++, nid++) {
 		function_id = snd_hda_param_read(codec, nid,
 		function_id = snd_hda_param_read(codec, nid,
-						AC_PAR_FUNCTION_TYPE) & 0xff;
-		switch (function_id) {
+						AC_PAR_FUNCTION_TYPE);
+		switch (function_id & 0xff) {
 		case AC_GRP_AUDIO_FUNCTION:
 		case AC_GRP_AUDIO_FUNCTION:
 			codec->afg = nid;
 			codec->afg = nid;
-			codec->function_id = function_id;
+			codec->afg_function_id = function_id & 0xff;
+			codec->afg_unsol = (function_id >> 8) & 1;
 			break;
 			break;
 		case AC_GRP_MODEM_FUNCTION:
 		case AC_GRP_MODEM_FUNCTION:
 			codec->mfg = nid;
 			codec->mfg = nid;
-			codec->function_id = function_id;
+			codec->mfg_function_id = function_id & 0xff;
+			codec->mfg_unsol = (function_id >> 8) & 1;
 			break;
 			break;
 		default:
 		default:
 			break;
 			break;
@@ -1565,6 +1570,17 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
 EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
 EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
 #endif /* SND_HDA_NEEDS_RESUME */
 #endif /* SND_HDA_NEEDS_RESUME */
 
 
+static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
+			     unsigned int ofs)
+{
+	u32 caps = query_amp_caps(codec, nid, dir);
+	/* get num steps */
+	caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+	if (ofs < caps)
+		caps -= ofs;
+	return caps;
+}
+
 /**
 /**
  * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer
  * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer
  *
  *
@@ -1579,23 +1595,17 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
 	u8 chs = get_amp_channels(kcontrol);
 	u8 chs = get_amp_channels(kcontrol);
 	int dir = get_amp_direction(kcontrol);
 	int dir = get_amp_direction(kcontrol);
 	unsigned int ofs = get_amp_offset(kcontrol);
 	unsigned int ofs = get_amp_offset(kcontrol);
-	u32 caps;
 
 
-	caps = query_amp_caps(codec, nid, dir);
-	/* num steps */
-	caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
-	if (!caps) {
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = chs == 3 ? 2 : 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs);
+	if (!uinfo->value.integer.max) {
 		printk(KERN_WARNING "hda_codec: "
 		printk(KERN_WARNING "hda_codec: "
 		       "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
 		       "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
 		       kcontrol->id.name);
 		       kcontrol->id.name);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
-	if (ofs < caps)
-		caps -= ofs;
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = chs == 3 ? 2 : 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = caps;
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
@@ -1620,8 +1630,14 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
 		 int ch, int dir, int idx, unsigned int ofs,
 		 int ch, int dir, int idx, unsigned int ofs,
 		 unsigned int val)
 		 unsigned int val)
 {
 {
+	unsigned int maxval;
+
 	if (val > 0)
 	if (val > 0)
 		val += ofs;
 		val += ofs;
+	/* ofs = 0: raw max value */
+	maxval = get_amp_max_value(codec, nid, dir, 0);
+	if (val > maxval)
+		val = maxval;
 	return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
 	return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
 					HDA_AMP_VOLMASK, val);
 					HDA_AMP_VOLMASK, val);
 }
 }
@@ -2999,26 +3015,31 @@ struct hda_rate_tbl {
 	unsigned int hda_fmt;
 	unsigned int hda_fmt;
 };
 };
 
 
+/* rate = base * mult / div */
+#define HDA_RATE(base, mult, div) \
+	(AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \
+	 (((div) - 1) << AC_FMT_DIV_SHIFT))
+
 static struct hda_rate_tbl rate_bits[] = {
 static struct hda_rate_tbl rate_bits[] = {
 	/* rate in Hz, ALSA rate bitmask, HDA format value */
 	/* rate in Hz, ALSA rate bitmask, HDA format value */
 
 
 	/* autodetected value used in snd_hda_query_supported_pcm */
 	/* autodetected value used in snd_hda_query_supported_pcm */
-	{ 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */
-	{ 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */
-	{ 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */
-	{ 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */
-	{ 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */
-	{ 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */
-	{ 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */
-	{ 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */
-	{ 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */
-	{ 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */
-	{ 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */
+	{ 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) },
+	{ 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) },
+	{ 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) },
+	{ 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) },
+	{ 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) },
+	{ 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) },
+	{ 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) },
+	{ 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) },
+	{ 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) },
+	{ 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) },
+	{ 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) },
 #define AC_PAR_PCM_RATE_BITS	11
 #define AC_PAR_PCM_RATE_BITS	11
 	/* up to bits 10, 384kHZ isn't supported properly */
 	/* up to bits 10, 384kHZ isn't supported properly */
 
 
 	/* not autodetected value */
 	/* not autodetected value */
-	{ 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */
+	{ 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) },
 
 
 	{ 0 } /* terminator */
 	{ 0 } /* terminator */
 };
 };
@@ -3037,7 +3058,8 @@ static struct hda_rate_tbl rate_bits[] = {
 unsigned int snd_hda_calc_stream_format(unsigned int rate,
 unsigned int snd_hda_calc_stream_format(unsigned int rate,
 					unsigned int channels,
 					unsigned int channels,
 					unsigned int format,
 					unsigned int format,
-					unsigned int maxbps)
+					unsigned int maxbps,
+					unsigned short spdif_ctls)
 {
 {
 	int i;
 	int i;
 	unsigned int val = 0;
 	unsigned int val = 0;
@@ -3060,20 +3082,20 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
 
 
 	switch (snd_pcm_format_width(format)) {
 	switch (snd_pcm_format_width(format)) {
 	case 8:
 	case 8:
-		val |= 0x00;
+		val |= AC_FMT_BITS_8;
 		break;
 		break;
 	case 16:
 	case 16:
-		val |= 0x10;
+		val |= AC_FMT_BITS_16;
 		break;
 		break;
 	case 20:
 	case 20:
 	case 24:
 	case 24:
 	case 32:
 	case 32:
 		if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE)
 		if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE)
-			val |= 0x40;
+			val |= AC_FMT_BITS_32;
 		else if (maxbps >= 24)
 		else if (maxbps >= 24)
-			val |= 0x30;
+			val |= AC_FMT_BITS_24;
 		else
 		else
-			val |= 0x20;
+			val |= AC_FMT_BITS_20;
 		break;
 		break;
 	default:
 	default:
 		snd_printdd("invalid format width %d\n",
 		snd_printdd("invalid format width %d\n",
@@ -3081,6 +3103,9 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
 		return 0;
 		return 0;
 	}
 	}
 
 
+	if (spdif_ctls & AC_DIG1_NONAUDIO)
+		val |= AC_FMT_TYPE_NON_PCM;
+
 	return val;
 	return val;
 }
 }
 EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
 EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);

+ 30 - 2
sound/pci/hda/hda_codec.h

@@ -224,6 +224,27 @@ enum {
 /* Input converter SDI select */
 /* Input converter SDI select */
 #define AC_SDI_SELECT			(0xf<<0)
 #define AC_SDI_SELECT			(0xf<<0)
 
 
+/* stream format id */
+#define AC_FMT_CHAN_SHIFT		0
+#define AC_FMT_CHAN_MASK		(0x0f << 0)
+#define AC_FMT_BITS_SHIFT		4
+#define AC_FMT_BITS_MASK		(7 << 4)
+#define AC_FMT_BITS_8			(0 << 4)
+#define AC_FMT_BITS_16			(1 << 4)
+#define AC_FMT_BITS_20			(2 << 4)
+#define AC_FMT_BITS_24			(3 << 4)
+#define AC_FMT_BITS_32			(4 << 4)
+#define AC_FMT_DIV_SHIFT		8
+#define AC_FMT_DIV_MASK			(7 << 8)
+#define AC_FMT_MULT_SHIFT		11
+#define AC_FMT_MULT_MASK		(7 << 11)
+#define AC_FMT_BASE_SHIFT		14
+#define AC_FMT_BASE_48K			(0 << 14)
+#define AC_FMT_BASE_44K			(1 << 14)
+#define AC_FMT_TYPE_SHIFT		15
+#define AC_FMT_TYPE_PCM			(0 << 15)
+#define AC_FMT_TYPE_NON_PCM		(1 << 15)
+
 /* Unsolicited response control */
 /* Unsolicited response control */
 #define AC_UNSOL_TAG			(0x3f<<0)
 #define AC_UNSOL_TAG			(0x3f<<0)
 #define AC_UNSOL_ENABLED		(1<<7)
 #define AC_UNSOL_ENABLED		(1<<7)
@@ -364,6 +385,9 @@ enum {
 #define AC_DIG2_CC			(0x7f<<0)
 #define AC_DIG2_CC			(0x7f<<0)
 
 
 /* Pin widget control - 8bit */
 /* Pin widget control - 8bit */
+#define AC_PINCTL_EPT			(0x3<<0)
+#define AC_PINCTL_EPT_NATIVE		0
+#define AC_PINCTL_EPT_HBR		3
 #define AC_PINCTL_VREFEN		(0x7<<0)
 #define AC_PINCTL_VREFEN		(0x7<<0)
 #define AC_PINCTL_VREF_HIZ		0	/* Hi-Z */
 #define AC_PINCTL_VREF_HIZ		0	/* Hi-Z */
 #define AC_PINCTL_VREF_50		1	/* 50% */
 #define AC_PINCTL_VREF_50		1	/* 50% */
@@ -760,7 +784,10 @@ struct hda_codec {
 	hda_nid_t mfg;	/* MFG node id */
 	hda_nid_t mfg;	/* MFG node id */
 
 
 	/* ids */
 	/* ids */
-	u32 function_id;
+	u8 afg_function_id;
+	u8 mfg_function_id;
+	u8 afg_unsol;
+	u8 mfg_unsol;
 	u32 vendor_id;
 	u32 vendor_id;
 	u32 subsystem_id;
 	u32 subsystem_id;
 	u32 revision_id;
 	u32 revision_id;
@@ -928,7 +955,8 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid);
 unsigned int snd_hda_calc_stream_format(unsigned int rate,
 unsigned int snd_hda_calc_stream_format(unsigned int rate,
 					unsigned int channels,
 					unsigned int channels,
 					unsigned int format,
 					unsigned int format,
-					unsigned int maxbps);
+					unsigned int maxbps,
+					unsigned short spdif_ctls);
 int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
 int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
 				unsigned int format);
 				unsigned int format);
 
 

+ 3 - 1
sound/pci/hda/hda_hwdep.c

@@ -649,7 +649,9 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus,
 	*codecp = NULL;
 	*codecp = NULL;
 	if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
 	if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
 		list_for_each_entry(codec, &bus->codec_list, list) {
 		list_for_each_entry(codec, &bus->codec_list, list) {
-			if (codec->addr == caddr) {
+			if (codec->vendor_id == vendorid &&
+			    codec->subsystem_id == subid &&
+			    codec->addr == caddr) {
 				*codecp = codec;
 				*codecp = codec;
 				break;
 				break;
 			}
 			}

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

@@ -1653,7 +1653,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 	format_val = snd_hda_calc_stream_format(runtime->rate,
 	format_val = snd_hda_calc_stream_format(runtime->rate,
 						runtime->channels,
 						runtime->channels,
 						runtime->format,
 						runtime->format,
-						hinfo->maxbps);
+						hinfo->maxbps,
+						apcm->codec->spdif_ctls);
 	if (!format_val) {
 	if (!format_val) {
 		snd_printk(KERN_ERR SFX
 		snd_printk(KERN_ERR SFX
 			   "invalid format_val, rate=%d, ch=%d, format=%d\n",
 			   "invalid format_val, rate=%d, ch=%d, format=%d\n",
@@ -1960,7 +1961,7 @@ static void azx_irq_pending_work(struct work_struct *work)
 		spin_unlock_irq(&chip->reg_lock);
 		spin_unlock_irq(&chip->reg_lock);
 		if (!pending)
 		if (!pending)
 			return;
 			return;
-		cond_resched();
+		msleep(1);
 	}
 	}
 }
 }
 
 

+ 6 - 1
sound/pci/hda/hda_proc.c

@@ -557,7 +557,12 @@ static void print_codec_info(struct snd_info_entry *entry,
 	else
 	else
 		snd_iprintf(buffer, "Not Set\n");
 		snd_iprintf(buffer, "Not Set\n");
 	snd_iprintf(buffer, "Address: %d\n", codec->addr);
 	snd_iprintf(buffer, "Address: %d\n", codec->addr);
-	snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id);
+	if (codec->afg)
+		snd_iprintf(buffer, "AFG Function Id: 0x%x (unsol %u)\n",
+			codec->afg_function_id, codec->afg_unsol);
+	if (codec->mfg)
+		snd_iprintf(buffer, "MFG Function Id: 0x%x (unsol %u)\n",
+			codec->mfg_function_id, codec->mfg_unsol);
 	snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id);
 	snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id);
 	snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id);
 	snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id);
 	snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
 	snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);

+ 6 - 1
sound/pci/hda/patch_analog.c

@@ -3662,7 +3662,12 @@ static int patch_ad1984(struct hda_codec *codec)
 		codec->patch_ops.build_pcms = ad1984_build_pcms;
 		codec->patch_ops.build_pcms = ad1984_build_pcms;
 		break;
 		break;
 	case AD1984_THINKPAD:
 	case AD1984_THINKPAD:
-		spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
+		if (codec->subsystem_id == 0x17aa20fb) {
+			/* Thinpad X300 does not have the ability to do SPDIF,
+			   or attach to docking station to use SPDIF */
+			spec->multiout.dig_out_nid = 0;
+		} else
+			spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
 		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;

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

@@ -131,6 +131,8 @@ struct conexant_spec {
 	unsigned int dc_enable;
 	unsigned int dc_enable;
 	unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */
 	unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */
 	unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
 	unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
+
+	unsigned int beep_amp;
 };
 };
 
 
 static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
 static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -515,6 +517,15 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = {
 	{}
 	{}
 };
 };
 
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/* additional beep mixers; the actual parameters are overwritten at build */
+static struct snd_kcontrol_new cxt_beep_mixer[] = {
+	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
+	{ } /* end */
+};
+#endif
+
 static const char *slave_vols[] = {
 static const char *slave_vols[] = {
 	"Headphone Playback Volume",
 	"Headphone Playback Volume",
 	"Speaker Playback Volume",
 	"Speaker Playback Volume",
@@ -580,16 +591,52 @@ static int conexant_build_controls(struct hda_codec *codec)
 			return err;
 			return err;
 	}
 	}
 
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+	/* create beep controls if needed */
+	if (spec->beep_amp) {
+		struct snd_kcontrol_new *knew;
+		for (knew = cxt_beep_mixer; knew->name; knew++) {
+			struct snd_kcontrol *kctl;
+			kctl = snd_ctl_new1(knew, codec);
+			if (!kctl)
+				return -ENOMEM;
+			kctl->private_value = spec->beep_amp;
+			err = snd_hda_ctl_add(codec, 0, kctl);
+			if (err < 0)
+				return err;
+		}
+	}
+#endif
+
+	return 0;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int conexant_suspend(struct hda_codec *codec, pm_message_t state)
+{
+	snd_hda_shutup_pins(codec);
 	return 0;
 	return 0;
 }
 }
+#endif
 
 
 static struct hda_codec_ops conexant_patch_ops = {
 static struct hda_codec_ops conexant_patch_ops = {
 	.build_controls = conexant_build_controls,
 	.build_controls = conexant_build_controls,
 	.build_pcms = conexant_build_pcms,
 	.build_pcms = conexant_build_pcms,
 	.init = conexant_init,
 	.init = conexant_init,
 	.free = conexant_free,
 	.free = conexant_free,
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	.suspend = conexant_suspend,
+#endif
+	.reboot_notify = snd_hda_shutup_pins,
 };
 };
 
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+#define set_beep_amp(spec, nid, idx, dir) \
+	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
+#else
+#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#endif
+
 /*
 /*
  * EAPD control
  * EAPD control
  * the private value = nid | (invert << 8)
  * the private value = nid | (invert << 8)
@@ -1130,9 +1177,10 @@ static int patch_cxt5045(struct hda_codec *codec)
 	spec->num_init_verbs = 1;
 	spec->num_init_verbs = 1;
 	spec->init_verbs[0] = cxt5045_init_verbs;
 	spec->init_verbs[0] = cxt5045_init_verbs;
 	spec->spdif_route = 0;
 	spec->spdif_route = 0;
-	spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes),
-	spec->channel_mode = cxt5045_modes,
+	spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes);
+	spec->channel_mode = cxt5045_modes;
 
 
+	set_beep_amp(spec, 0x16, 0, 1);
 
 
 	codec->patch_ops = conexant_patch_ops;
 	codec->patch_ops = conexant_patch_ops;
 
 
@@ -1211,6 +1259,9 @@ static int patch_cxt5045(struct hda_codec *codec)
 		break;
 		break;
 	}
 	}
 
 
+	if (spec->beep_amp)
+		snd_hda_attach_beep_device(codec, spec->beep_amp);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1632,6 +1683,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec)
 	pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
 	pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
 	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 			    pinctl);
 			    pinctl);
+	/* on ideapad there is an aditional speaker (subwoofer) to mute */
+	if (spec->ideapad)
+		snd_hda_codec_write(codec, 0x1b, 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL,
+				    pinctl);
 }
 }
 
 
 /* turn on/off EAPD (+ mute HP) as a master switch */
 /* turn on/off EAPD (+ mute HP) as a master switch */
@@ -1888,6 +1944,13 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
 #endif
 #endif
 }
 }
 
 
+static struct hda_verb cxt5051_ideapad_init_verbs[] = {
+	/* Subwoofer */
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ } /* end */
+};
+
 /* initialize jack-sensing, too */
 /* initialize jack-sensing, too */
 static int cxt5051_init(struct hda_codec *codec)
 static int cxt5051_init(struct hda_codec *codec)
 {
 {
@@ -1917,6 +1980,7 @@ enum {
 	CXT5051_LENOVO_X200,	/* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */
 	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_IDEAPAD,	/* Lenovo IdeaPad Y430 */
 	CXT5051_MODELS
 	CXT5051_MODELS
 };
 };
 
 
@@ -1927,6 +1991,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = {
 	[CXT5051_LENOVO_X200]	= "lenovo-x200",
 	[CXT5051_LENOVO_X200]	= "lenovo-x200",
 	[CXT5051_F700]          = "hp-700",
 	[CXT5051_F700]          = "hp-700",
 	[CXT5051_TOSHIBA]	= "toshiba",
 	[CXT5051_TOSHIBA]	= "toshiba",
+	[CXT5051_IDEAPAD]	= "ideapad",
 };
 };
 
 
 static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
 static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
@@ -1938,6 +2003,7 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
 		      CXT5051_LAPTOP),
 		      CXT5051_LAPTOP),
 	SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
 	SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
+	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD),
 	{}
 	{}
 };
 };
 
 
@@ -1972,6 +2038,8 @@ static int patch_cxt5051(struct hda_codec *codec)
 	spec->cur_adc = 0;
 	spec->cur_adc = 0;
 	spec->cur_adc_idx = 0;
 	spec->cur_adc_idx = 0;
 
 
+	set_beep_amp(spec, 0x13, 0, HDA_OUTPUT);
+
 	codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
 	codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
 
 
 	board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
 	board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
@@ -1989,6 +2057,10 @@ static int patch_cxt5051(struct hda_codec *codec)
 		break;
 		break;
 	case CXT5051_LENOVO_X200:
 	case CXT5051_LENOVO_X200:
 		spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
 		spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
+		/* Thinkpad X301 does not have S/PDIF wired and no ability
+		   to use a docking station. */
+		if (codec->subsystem_id == 0x17aa211f)
+			spec->multiout.dig_out_nid = 0;
 		break;
 		break;
 	case CXT5051_F700:
 	case CXT5051_F700:
 		spec->init_verbs[0] = cxt5051_f700_init_verbs;
 		spec->init_verbs[0] = cxt5051_f700_init_verbs;
@@ -1999,8 +2071,16 @@ static int patch_cxt5051(struct hda_codec *codec)
 		spec->mixers[0] = cxt5051_toshiba_mixers;
 		spec->mixers[0] = cxt5051_toshiba_mixers;
 		spec->auto_mic = AUTO_MIC_PORTB;
 		spec->auto_mic = AUTO_MIC_PORTB;
 		break;
 		break;
+	case CXT5051_IDEAPAD:
+		spec->init_verbs[spec->num_init_verbs++] =
+			cxt5051_ideapad_init_verbs;
+		spec->ideapad = 1;
+		break;
 	}
 	}
 
 
+	if (spec->beep_amp)
+		snd_hda_attach_beep_device(codec, spec->beep_amp);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2616,7 +2696,6 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
 		.put = cxt5066_mic_boost_mux_enum_put,
 		.put = cxt5066_mic_boost_mux_enum_put,
 		.private_value = 0x23 | 0x100,
 		.private_value = 0x23 | 0x100,
 	},
 	},
-	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
 	{}
 	{}
 };
 };
 
 
@@ -2977,8 +3056,10 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
 	SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
+ 	SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
+ 	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD),
+	SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", 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),
 	{}
 	{}
 };
 };
 
 
@@ -3014,6 +3095,8 @@ static int patch_cxt5066(struct hda_codec *codec)
 	spec->cur_adc = 0;
 	spec->cur_adc = 0;
 	spec->cur_adc_idx = 0;
 	spec->cur_adc_idx = 0;
 
 
+	set_beep_amp(spec, 0x13, 0, HDA_OUTPUT);
+
 	board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
 	board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
 						  cxt5066_models, cxt5066_cfg_tbl);
 						  cxt5066_models, cxt5066_cfg_tbl);
 	switch (board_config) {
 	switch (board_config) {
@@ -3062,7 +3145,6 @@ static int patch_cxt5066(struct hda_codec *codec)
 		spec->port_d_mode = 0;
 		spec->port_d_mode = 0;
 		spec->dell_vostro = 1;
 		spec->dell_vostro = 1;
 		spec->mic_boost = 3; /* default 30dB gain */
 		spec->mic_boost = 3; /* default 30dB gain */
-		snd_hda_attach_beep_device(codec, 0x13);
 
 
 		/* no S/PDIF out */
 		/* no S/PDIF out */
 		spec->multiout.dig_out_nid = 0;
 		spec->multiout.dig_out_nid = 0;
@@ -3104,6 +3186,9 @@ static int patch_cxt5066(struct hda_codec *codec)
 		break;
 		break;
 	}
 	}
 
 
+	if (spec->beep_amp)
+		snd_hda_attach_beep_device(codec, spec->beep_amp);
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 42 - 1
sound/pci/hda/patch_hdmi.c

@@ -698,11 +698,51 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
  * Callbacks
  * Callbacks
  */
  */
 
 
-static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
+/* HBR should be Non-PCM, 8 channels */
+#define is_hbr_format(format) \
+	((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
+
+static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 			      u32 stream_tag, int format)
 			      u32 stream_tag, int format)
 {
 {
+	struct hdmi_spec *spec = codec->spec;
 	int tag;
 	int tag;
 	int fmt;
 	int fmt;
+	int pinctl;
+	int new_pinctl = 0;
+	int i;
+
+	for (i = 0; i < spec->num_pins; i++) {
+		if (spec->pin_cvt[i] != nid)
+			continue;
+		if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR))
+			continue;
+
+		pinctl = snd_hda_codec_read(codec, spec->pin[i], 0,
+					    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+		new_pinctl = pinctl & ~AC_PINCTL_EPT;
+		if (is_hbr_format(format))
+			new_pinctl |= AC_PINCTL_EPT_HBR;
+		else
+			new_pinctl |= AC_PINCTL_EPT_NATIVE;
+
+		snd_printdd("hdmi_setup_stream: "
+			    "NID=0x%x, %spinctl=0x%x\n",
+			    spec->pin[i],
+			    pinctl == new_pinctl ? "" : "new-",
+			    new_pinctl);
+
+		if (pinctl != new_pinctl)
+			snd_hda_codec_write(codec, spec->pin[i], 0,
+					    AC_VERB_SET_PIN_WIDGET_CONTROL,
+					    new_pinctl);
+	}
+
+	if (is_hbr_format(format) && !new_pinctl) {
+		snd_printdd("hdmi_setup_stream: HBR is not supported\n");
+		return -EINVAL;
+	}
 
 
 	tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4;
 	tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4;
 	fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0);
 	fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0);
@@ -722,6 +762,7 @@ static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 	if (fmt != format)
 	if (fmt != format)
 		snd_hda_codec_write(codec, nid, 0,
 		snd_hda_codec_write(codec, nid, 0,
 				    AC_VERB_SET_STREAM_FORMAT, format);
 				    AC_VERB_SET_STREAM_FORMAT, format);
+	return 0;
 }
 }
 
 
 /*
 /*

+ 1 - 2
sound/pci/hda/patch_intelhdmi.c

@@ -66,8 +66,7 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 
 
 	hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
 	hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
 
 
-	hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
-	return 0;
+	return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
 }
 }
 
 
 static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
 static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,

+ 1 - 2
sound/pci/hda/patch_nvhdmi.c

@@ -202,8 +202,7 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo,
 
 
 	hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
 	hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
 
 
-	hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
-	return 0;
+	return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
 }
 }
 
 
 static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
 static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,

File diff suppressed because it is too large
+ 627 - 92
sound/pci/hda/patch_realtek.c


+ 11 - 1
sound/pci/hda/patch_sigmatel.c

@@ -202,6 +202,7 @@ struct sigmatel_spec {
 	unsigned int spdif_mute: 1;
 	unsigned int spdif_mute: 1;
 	unsigned int check_volume_offset:1;
 	unsigned int check_volume_offset:1;
 	unsigned int auto_mic:1;
 	unsigned int auto_mic:1;
+	unsigned int linear_tone_beep:1;
 
 
 	/* gpio lines */
 	/* gpio lines */
 	unsigned int eapd_mask;
 	unsigned int eapd_mask;
@@ -3802,7 +3803,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
 			return err;
 			return err;
 		if (codec->beep) {
 		if (codec->beep) {
 			/* IDT/STAC codecs have linear beep tone parameter */
 			/* IDT/STAC codecs have linear beep tone parameter */
-			codec->beep->linear_tone = 1;
+			codec->beep->linear_tone = spec->linear_tone_beep;
 			/* if no beep switch is available, make its own one */
 			/* if no beep switch is available, make its own one */
 			caps = query_amp_caps(codec, nid, HDA_OUTPUT);
 			caps = query_amp_caps(codec, nid, HDA_OUTPUT);
 			if (!(caps & AC_AMPCAP_MUTE)) {
 			if (!(caps & AC_AMPCAP_MUTE)) {
@@ -5005,6 +5006,7 @@ static int patch_stac9200(struct hda_codec *codec)
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
 	codec->spec = spec;
 	codec->spec = spec;
+	spec->linear_tone_beep = 1;
 	spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
 	spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
 	spec->pin_nids = stac9200_pin_nids;
 	spec->pin_nids = stac9200_pin_nids;
 	spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
 	spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
@@ -5068,6 +5070,7 @@ static int patch_stac925x(struct hda_codec *codec)
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
 	codec->spec = spec;
 	codec->spec = spec;
+	spec->linear_tone_beep = 1;
 	spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
 	spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
 	spec->pin_nids = stac925x_pin_nids;
 	spec->pin_nids = stac925x_pin_nids;
 
 
@@ -5153,6 +5156,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
 	codec->spec = spec;
 	codec->spec = spec;
+	spec->linear_tone_beep = 0;
 	codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
 	codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
 	spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
 	spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
 	spec->pin_nids = stac92hd73xx_pin_nids;
 	spec->pin_nids = stac92hd73xx_pin_nids;
@@ -5300,6 +5304,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
 	codec->spec = spec;
 	codec->spec = spec;
+	spec->linear_tone_beep = 1;
 	codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
 	codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
 	spec->digbeep_nid = 0x21;
 	spec->digbeep_nid = 0x21;
 	spec->mux_nids = stac92hd83xxx_mux_nids;
 	spec->mux_nids = stac92hd83xxx_mux_nids;
@@ -5522,6 +5527,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
 	codec->spec = spec;
 	codec->spec = spec;
+	spec->linear_tone_beep = 0;
 	codec->patch_ops = stac92xx_patch_ops;
 	codec->patch_ops = stac92xx_patch_ops;
 	spec->num_pins = STAC92HD71BXX_NUM_PINS;
 	spec->num_pins = STAC92HD71BXX_NUM_PINS;
 	switch (codec->vendor_id) {
 	switch (codec->vendor_id) {
@@ -5779,6 +5785,7 @@ static int patch_stac922x(struct hda_codec *codec)
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
 	codec->spec = spec;
 	codec->spec = spec;
+	spec->linear_tone_beep = 1;
 	spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
 	spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
 	spec->pin_nids = stac922x_pin_nids;
 	spec->pin_nids = stac922x_pin_nids;
 	spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
 	spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
@@ -5883,6 +5890,7 @@ static int patch_stac927x(struct hda_codec *codec)
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
 	codec->spec = spec;
 	codec->spec = spec;
+	spec->linear_tone_beep = 1;
 	codec->slave_dig_outs = stac927x_slave_dig_outs;
 	codec->slave_dig_outs = stac927x_slave_dig_outs;
 	spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
 	spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
 	spec->pin_nids = stac927x_pin_nids;
 	spec->pin_nids = stac927x_pin_nids;
@@ -6018,6 +6026,7 @@ static int patch_stac9205(struct hda_codec *codec)
 
 
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
 	codec->spec = spec;
 	codec->spec = spec;
+	spec->linear_tone_beep = 1;
 	spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
 	spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
 	spec->pin_nids = stac9205_pin_nids;
 	spec->pin_nids = stac9205_pin_nids;
 	spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
 	spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
@@ -6174,6 +6183,7 @@ static int patch_stac9872(struct hda_codec *codec)
 		return -ENOMEM;
 		return -ENOMEM;
 	codec->no_trigger_sense = 1;
 	codec->no_trigger_sense = 1;
 	codec->spec = spec;
 	codec->spec = spec;
+	spec->linear_tone_beep = 1;
 	spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
 	spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
 	spec->pin_nids = stac9872_pin_nids;
 	spec->pin_nids = stac9872_pin_nids;
 
 

+ 25 - 7
sound/pci/hda/patch_via.c

@@ -552,24 +552,30 @@ static void via_auto_init_hp_out(struct hda_codec *codec)
 	}
 	}
 }
 }
 
 
+static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
+
 static void via_auto_init_analog_input(struct hda_codec *codec)
 static void via_auto_init_analog_input(struct hda_codec *codec)
 {
 {
 	struct via_spec *spec = codec->spec;
 	struct via_spec *spec = codec->spec;
+	unsigned int ctl;
 	int i;
 	int i;
 
 
 	for (i = 0; i < AUTO_PIN_LAST; i++) {
 	for (i = 0; i < AUTO_PIN_LAST; i++) {
 		hda_nid_t nid = spec->autocfg.input_pins[i];
 		hda_nid_t nid = spec->autocfg.input_pins[i];
+		if (!nid)
+			continue;
 
 
+		if (spec->smart51_enabled && is_smart51_pins(spec, nid))
+			ctl = PIN_OUT;
+		else if (i <= AUTO_PIN_FRONT_MIC)
+			ctl = PIN_VREF50;
+		else
+			ctl = PIN_IN;
 		snd_hda_codec_write(codec, nid, 0,
 		snd_hda_codec_write(codec, nid, 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    (i <= AUTO_PIN_FRONT_MIC ?
-				     PIN_VREF50 : PIN_IN));
-
+				    AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
 	}
 	}
 }
 }
 
 
-static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
-
 static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
 static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
 				unsigned int *affected_parm)
 				unsigned int *affected_parm)
 {
 {
@@ -658,6 +664,8 @@ static void set_jack_power_state(struct hda_codec *codec)
 		/* PW0 (19h), SW1 (18h), AOW1 (11h) */
 		/* PW0 (19h), SW1 (18h), AOW1 (11h) */
 		parm = AC_PWRST_D3;
 		parm = AC_PWRST_D3;
 		set_pin_power_state(codec, 0x19, &parm);
 		set_pin_power_state(codec, 0x19, &parm);
+		if (spec->smart51_enabled)
+			parm = AC_PWRST_D0;
 		snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
 		snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
 				    parm);
 				    parm);
 		snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
 		snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
@@ -667,6 +675,8 @@ static void set_jack_power_state(struct hda_codec *codec)
 		if (is_8ch) {
 		if (is_8ch) {
 			parm = AC_PWRST_D3;
 			parm = AC_PWRST_D3;
 			set_pin_power_state(codec, 0x22, &parm);
 			set_pin_power_state(codec, 0x22, &parm);
+			if (spec->smart51_enabled)
+				parm = AC_PWRST_D0;
 			snd_hda_codec_write(codec, 0x26, 0,
 			snd_hda_codec_write(codec, 0x26, 0,
 					    AC_VERB_SET_POWER_STATE, parm);
 					    AC_VERB_SET_POWER_STATE, parm);
 			snd_hda_codec_write(codec, 0x24, 0,
 			snd_hda_codec_write(codec, 0x24, 0,
@@ -3915,6 +3925,13 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
 		}
 		}
 	}
 	}
 
 
+	/* for Smart 5.1, line/mic inputs double as output pins */
+	if (cfg->line_outs == 1) {
+		spec->multiout.num_dacs = 3;
+		spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11;
+		spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24;
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3932,7 +3949,8 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
 		nid = cfg->line_out_pins[i];
 		nid = cfg->line_out_pins[i];
 
 
-		if (!nid)
+		/* for Smart 5.1, there are always at least six channels */
+		if (!nid && i > AUTO_SEQ_CENLFE)
 			continue;
 			continue;
 
 
 		nid_vol = nid_vols[i];
 		nid_vol = nid_vols[i];

+ 12 - 6
sound/pci/riptide/riptide.c

@@ -97,6 +97,7 @@
 #include <linux/gameport.h>
 #include <linux/gameport.h>
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/firmware.h>
+#include <linux/kernel.h>
 #include <asm/io.h>
 #include <asm/io.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/info.h>
@@ -667,13 +668,12 @@ static u32 atoh(const unsigned char *in, unsigned int len)
 	unsigned char c;
 	unsigned char c;
 
 
 	while (len) {
 	while (len) {
+		int value;
+
 		c = in[len - 1];
 		c = in[len - 1];
-		if ((c >= '0') && (c <= '9'))
-			sum += mult * (c - '0');
-		else if ((c >= 'A') && (c <= 'F'))
-			sum += mult * (c - ('A' - 10));
-		else if ((c >= 'a') && (c <= 'f'))
-			sum += mult * (c - ('a' - 10));
+		value = hex_to_bin(c);
+		if (value >= 0)
+			sum += mult * value;
 		mult *= 16;
 		mult *= 16;
 		--len;
 		--len;
 	}
 	}
@@ -1615,7 +1615,10 @@ static int snd_riptide_playback_open(struct snd_pcm_substream *substream)
 
 
 	chip->playback_substream[sub_num] = substream;
 	chip->playback_substream[sub_num] = substream;
 	runtime->hw = snd_riptide_playback;
 	runtime->hw = snd_riptide_playback;
+
 	data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);
 	data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
 	data->paths = lbus_play_paths[sub_num];
 	data->paths = lbus_play_paths[sub_num];
 	data->id = play_ids[sub_num];
 	data->id = play_ids[sub_num];
 	data->source = play_sources[sub_num];
 	data->source = play_sources[sub_num];
@@ -1635,7 +1638,10 @@ static int snd_riptide_capture_open(struct snd_pcm_substream *substream)
 
 
 	chip->capture_substream = substream;
 	chip->capture_substream = substream;
 	runtime->hw = snd_riptide_capture;
 	runtime->hw = snd_riptide_capture;
+
 	data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);
 	data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
 	data->paths = lbus_rec_path;
 	data->paths = lbus_rec_path;
 	data->id = PADC;
 	data->id = PADC;
 	data->source = ACLNK2PADC;
 	data->source = ACLNK2PADC;

+ 9 - 7
sound/pci/sis7019.c

@@ -264,11 +264,13 @@ static void sis_update_voice(struct voice *voice)
 		 * if using small periods.
 		 * if using small periods.
 		 *
 		 *
 		 * If we're less than 9 samples behind, we're on target.
 		 * If we're less than 9 samples behind, we're on target.
+		 * Otherwise, shorten the next vperiod by the amount we've
+		 * been delayed.
 		 */
 		 */
 		if (sync > -9)
 		if (sync > -9)
 			voice->vperiod = voice->sync_period_size + 1;
 			voice->vperiod = voice->sync_period_size + 1;
 		else
 		else
-			voice->vperiod = voice->sync_period_size - 4;
+			voice->vperiod = voice->sync_period_size + sync + 10;
 
 
 		if (voice->vperiod < voice->buffer_size) {
 		if (voice->vperiod < voice->buffer_size) {
 			sis_update_sso(voice, voice->vperiod);
 			sis_update_sso(voice, voice->vperiod);
@@ -736,7 +738,7 @@ static void sis_prepare_timing_voice(struct voice *voice,
 	period_size = buffer_size;
 	period_size = buffer_size;
 
 
 	/* Initially, we want to interrupt just a bit behind the end of
 	/* Initially, we want to interrupt just a bit behind the end of
-	 * the period we're clocking out. 10 samples seems to give a good
+	 * the period we're clocking out. 12 samples seems to give a good
 	 * delay.
 	 * delay.
 	 *
 	 *
 	 * We want to spread our interrupts throughout the virtual period,
 	 * We want to spread our interrupts throughout the virtual period,
@@ -747,7 +749,7 @@ static void sis_prepare_timing_voice(struct voice *voice,
 	 *
 	 *
 	 * This is all moot if we don't need to use virtual periods.
 	 * This is all moot if we don't need to use virtual periods.
 	 */
 	 */
-	vperiod = runtime->period_size + 10;
+	vperiod = runtime->period_size + 12;
 	if (vperiod > period_size) {
 	if (vperiod > period_size) {
 		u16 tail = vperiod % period_size;
 		u16 tail = vperiod % period_size;
 		u16 quarter_period = period_size / 4;
 		u16 quarter_period = period_size / 4;
@@ -776,7 +778,7 @@ static void sis_prepare_timing_voice(struct voice *voice,
 	 */
 	 */
 	timing->flags |= VOICE_SYNC_TIMING;
 	timing->flags |= VOICE_SYNC_TIMING;
 	timing->sync_base = voice->ctrl_base;
 	timing->sync_base = voice->ctrl_base;
-	timing->sync_cso = runtime->period_size - 1;
+	timing->sync_cso = runtime->period_size;
 	timing->sync_period_size = runtime->period_size;
 	timing->sync_period_size = runtime->period_size;
 	timing->sync_buffer_size = runtime->buffer_size;
 	timing->sync_buffer_size = runtime->buffer_size;
 	timing->period_size = period_size;
 	timing->period_size = period_size;
@@ -1047,7 +1049,7 @@ static int sis_chip_free(struct sis7019 *sis)
 	/* Reset the chip, and disable all interrputs.
 	/* Reset the chip, and disable all interrputs.
 	 */
 	 */
 	outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR);
 	outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR);
-	udelay(10);
+	udelay(25);
 	outl(0, sis->ioport + SIS_GCR);
 	outl(0, sis->ioport + SIS_GCR);
 	outl(0, sis->ioport + SIS_GIER);
 	outl(0, sis->ioport + SIS_GIER);
 
 
@@ -1083,7 +1085,7 @@ static int sis_chip_init(struct sis7019 *sis)
 	/* Reset the audio controller
 	/* Reset the audio controller
 	 */
 	 */
 	outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR);
 	outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR);
-	udelay(10);
+	udelay(25);
 	outl(0, io + SIS_GCR);
 	outl(0, io + SIS_GCR);
 
 
 	/* Get the AC-link semaphore, and reset the codecs
 	/* Get the AC-link semaphore, and reset the codecs
@@ -1096,7 +1098,7 @@ static int sis_chip_init(struct sis7019 *sis)
 		return -EIO;
 		return -EIO;
 
 
 	outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD);
 	outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD);
-	udelay(10);
+	udelay(250);
 
 
 	count = 0xffff;
 	count = 0xffff;
 	while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count)
 	while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count)

+ 7 - 2
sound/pci/via82xx.c

@@ -85,6 +85,7 @@ static int joystick;
 static int ac97_clock = 48000;
 static int ac97_clock = 48000;
 static char *ac97_quirk;
 static char *ac97_quirk;
 static int dxs_support;
 static int dxs_support;
+static int dxs_init_volume = 31;
 static int nodelay;
 static int nodelay;
 
 
 module_param(index, int, 0444);
 module_param(index, int, 0444);
@@ -103,6 +104,8 @@ module_param(ac97_quirk, charp, 0444);
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
 module_param(dxs_support, int, 0444);
 module_param(dxs_support, int, 0444);
 MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)");
 MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)");
+module_param(dxs_init_volume, int, 0644);
+MODULE_PARM_DESC(dxs_init_volume, "initial DXS volume (0-31)");
 module_param(nodelay, int, 0444);
 module_param(nodelay, int, 0444);
 MODULE_PARM_DESC(nodelay, "Disable 500ms init delay");
 MODULE_PARM_DESC(nodelay, "Disable 500ms init delay");
 
 
@@ -1245,8 +1248,10 @@ static int snd_via8233_playback_open(struct snd_pcm_substream *substream)
 		return err;
 		return err;
 	stream = viadev->reg_offset / 0x10;
 	stream = viadev->reg_offset / 0x10;
 	if (chip->dxs_controls[stream]) {
 	if (chip->dxs_controls[stream]) {
-		chip->playback_volume[stream][0] = 0;
-		chip->playback_volume[stream][1] = 0;
+		chip->playback_volume[stream][0] =
+				VIA_DXS_MAX_VOLUME - (dxs_init_volume & 31);
+		chip->playback_volume[stream][1] =
+				VIA_DXS_MAX_VOLUME - (dxs_init_volume & 31);
 		chip->dxs_controls[stream]->vd[0].access &=
 		chip->dxs_controls[stream]->vd[0].access &=
 			~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
 			~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
 		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
 		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |

+ 4 - 0
sound/soc/Kconfig

@@ -28,9 +28,13 @@ source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/blackfin/Kconfig"
 source "sound/soc/blackfin/Kconfig"
 source "sound/soc/davinci/Kconfig"
 source "sound/soc/davinci/Kconfig"
+source "sound/soc/ep93xx/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/imx/Kconfig"
 source "sound/soc/imx/Kconfig"
+source "sound/soc/jz4740/Kconfig"
+source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
 source "sound/soc/omap/Kconfig"
+source "sound/soc/kirkwood/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/s6000/Kconfig"
 source "sound/soc/s6000/Kconfig"

+ 4 - 0
sound/soc/Makefile

@@ -6,9 +6,13 @@ obj-$(CONFIG_SND_SOC)	+= atmel/
 obj-$(CONFIG_SND_SOC)	+= au1x/
 obj-$(CONFIG_SND_SOC)	+= au1x/
 obj-$(CONFIG_SND_SOC)	+= blackfin/
 obj-$(CONFIG_SND_SOC)	+= blackfin/
 obj-$(CONFIG_SND_SOC)	+= davinci/
 obj-$(CONFIG_SND_SOC)	+= davinci/
+obj-$(CONFIG_SND_SOC)	+= ep93xx/
 obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)   += imx/
 obj-$(CONFIG_SND_SOC)   += imx/
+obj-$(CONFIG_SND_SOC)	+= jz4740/
+obj-$(CONFIG_SND_SOC)	+= nuc900/
 obj-$(CONFIG_SND_SOC)	+= omap/
 obj-$(CONFIG_SND_SOC)	+= omap/
+obj-$(CONFIG_SND_SOC)	+= kirkwood/
 obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= s3c24xx/
 obj-$(CONFIG_SND_SOC)	+= s3c24xx/
 obj-$(CONFIG_SND_SOC)	+= s6000/
 obj-$(CONFIG_SND_SOC)	+= s6000/

+ 0 - 1
sound/soc/atmel/atmel-pcm.c

@@ -77,7 +77,6 @@ struct atmel_runtime_data {
 	size_t period_size;
 	size_t period_size;
 
 
 	dma_addr_t period_ptr;		/* physical address of next period */
 	dma_addr_t period_ptr;		/* physical address of next period */
-	int periods;			/* period index of period_ptr */
 
 
 	/* PDC register save */
 	/* PDC register save */
 	u32 pdc_xpr_save;
 	u32 pdc_xpr_save;

+ 0 - 1
sound/soc/atmel/atmel_ssc_dai.c

@@ -549,7 +549,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 		printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
 		printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
 			ssc_p->daifmt);
 			ssc_p->daifmt);
 		return -EINVAL;
 		return -EINVAL;
-		break;
 	}
 	}
 	pr_debug("atmel_ssc_hw_params: "
 	pr_debug("atmel_ssc_hw_params: "
 			"RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
 			"RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",

+ 5 - 8
sound/soc/au1x/psc-ac97.c

@@ -375,12 +375,10 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 	}
 	}
 
 
 	ret = -EBUSY;
 	ret = -EBUSY;
-	wd->ioarea = request_mem_region(r->start, r->end - r->start + 1,
-					"au1xpsc_ac97");
-	if (!wd->ioarea)
+	if (!request_mem_region(r->start, resource_size(r), pdev->name))
 		goto out0;
 		goto out0;
 
 
-	wd->mmio = ioremap(r->start, 0xffff);
+	wd->mmio = ioremap(r->start, resource_size(r));
 	if (!wd->mmio)
 	if (!wd->mmio)
 		goto out1;
 		goto out1;
 
 
@@ -410,8 +408,7 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 
 
 	snd_soc_unregister_dai(&au1xpsc_ac97_dai);
 	snd_soc_unregister_dai(&au1xpsc_ac97_dai);
 out1:
 out1:
-	release_resource(wd->ioarea);
-	kfree(wd->ioarea);
+	release_mem_region(r->start, resource_size(r));
 out0:
 out0:
 	kfree(wd);
 	kfree(wd);
 	return ret;
 	return ret;
@@ -420,6 +417,7 @@ out0:
 static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
 static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
 {
 {
 	struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
 	struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
+	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 
 	if (wd->dmapd)
 	if (wd->dmapd)
 		au1xpsc_pcm_destroy(wd->dmapd);
 		au1xpsc_pcm_destroy(wd->dmapd);
@@ -433,8 +431,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
 	au_sync();
 	au_sync();
 
 
 	iounmap(wd->mmio);
 	iounmap(wd->mmio);
-	release_resource(wd->ioarea);
-	kfree(wd->ioarea);
+	release_mem_region(r->start, resource_size(r));
 	kfree(wd);
 	kfree(wd);
 
 
 	au1xpsc_ac97_workdata = NULL;	/* MDEV */
 	au1xpsc_ac97_workdata = NULL;	/* MDEV */

+ 5 - 8
sound/soc/au1x/psc-i2s.c

@@ -321,12 +321,10 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 	}
 	}
 
 
 	ret = -EBUSY;
 	ret = -EBUSY;
-	wd->ioarea = request_mem_region(r->start, r->end - r->start + 1,
-					"au1xpsc_i2s");
-	if (!wd->ioarea)
+	if (!request_mem_region(r->start, resource_size(r), pdev->name))
 		goto out0;
 		goto out0;
 
 
-	wd->mmio = ioremap(r->start, 0xffff);
+	wd->mmio = ioremap(r->start, resource_size(r));
 	if (!wd->mmio)
 	if (!wd->mmio)
 		goto out1;
 		goto out1;
 
 
@@ -362,8 +360,7 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 
 
 	snd_soc_unregister_dai(&au1xpsc_i2s_dai);
 	snd_soc_unregister_dai(&au1xpsc_i2s_dai);
 out1:
 out1:
-	release_resource(wd->ioarea);
-	kfree(wd->ioarea);
+	release_mem_region(r->start, resource_size(r));
 out0:
 out0:
 	kfree(wd);
 	kfree(wd);
 	return ret;
 	return ret;
@@ -372,6 +369,7 @@ out0:
 static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
 static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
 {
 {
 	struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
 	struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
+	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 
 	if (wd->dmapd)
 	if (wd->dmapd)
 		au1xpsc_pcm_destroy(wd->dmapd);
 		au1xpsc_pcm_destroy(wd->dmapd);
@@ -384,8 +382,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
 	au_sync();
 	au_sync();
 
 
 	iounmap(wd->mmio);
 	iounmap(wd->mmio);
-	release_resource(wd->ioarea);
-	kfree(wd->ioarea);
+	release_mem_region(r->start, resource_size(r));
 	kfree(wd);
 	kfree(wd);
 
 
 	au1xpsc_i2s_workdata = NULL;	/* MDEV */
 	au1xpsc_i2s_workdata = NULL;	/* MDEV */

+ 0 - 1
sound/soc/au1x/psc.h

@@ -32,7 +32,6 @@ struct au1xpsc_audio_data {
 	unsigned long rate;
 	unsigned long rate;
 
 
 	unsigned long pm[2];
 	unsigned long pm[2];
-	struct resource *ioarea;
 	struct mutex lock;
 	struct mutex lock;
 	struct platform_device *dmapd;
 	struct platform_device *dmapd;
 };
 };

+ 2 - 4
sound/soc/blackfin/bf5xx-ac97.c

@@ -255,8 +255,7 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops);
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
 static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
 {
 {
-	struct sport_device *sport =
-		(struct sport_device *)dai->private_data;
+	struct sport_device *sport = dai->private_data;
 
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 	if (!dai->active)
 	if (!dai->active)
@@ -271,8 +270,7 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
 static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 {
 {
 	int ret;
 	int ret;
-	struct sport_device *sport =
-		(struct sport_device *)dai->private_data;
+	struct sport_device *sport = dai->private_data;
 
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 	if (!dai->active)
 	if (!dai->active)

+ 2 - 4
sound/soc/blackfin/bf5xx-tdm.c

@@ -210,8 +210,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 {
 {
-	struct sport_device *sport =
-		(struct sport_device *)dai->private_data;
+	struct sport_device *sport = dai->private_data;
 
 
 	if (!dai->active)
 	if (!dai->active)
 		return 0;
 		return 0;
@@ -225,8 +224,7 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 {
 {
 	int ret;
 	int ret;
-	struct sport_device *sport =
-		(struct sport_device *)dai->private_data;
+	struct sport_device *sport = dai->private_data;
 
 
 	if (!dai->active)
 	if (!dai->active)
 		return 0;
 		return 0;

+ 16 - 4
sound/soc/codecs/Kconfig

@@ -22,9 +22,11 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4671 if I2C
 	select SND_SOC_AK4671 if I2C
 	select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
 	select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
+	select SND_SOC_CS42L51 if I2C
 	select SND_SOC_CS4270 if I2C
 	select SND_SOC_CS4270 if I2C
-	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_DA7210 if I2C
 	select SND_SOC_DA7210 if I2C
+	select SND_SOC_JZ4740 if SOC_JZ4740
+	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_PCM3008
 	select SND_SOC_PCM3008
 	select SND_SOC_SPDIF
 	select SND_SOC_SPDIF
 	select SND_SOC_SSM2602 if I2C
 	select SND_SOC_SSM2602 if I2C
@@ -48,6 +50,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_WM8727
 	select SND_SOC_WM8727
 	select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
@@ -120,13 +123,13 @@ config SND_SOC_AK4671
 config SND_SOC_CQ0093VC
 config SND_SOC_CQ0093VC
 	tristate
 	tristate
 
 
+config SND_SOC_CS42L51
+	tristate
+
 # Cirrus Logic CS4270 Codec
 # Cirrus Logic CS4270 Codec
 config SND_SOC_CS4270
 config SND_SOC_CS4270
 	tristate
 	tristate
 
 
-config SND_SOC_DA7210
-        tristate
-
 # Cirrus Logic CS4270 Codec VD = 3.3V Errata
 # Cirrus Logic CS4270 Codec VD = 3.3V Errata
 # Select if you are affected by the errata where the part will not function
 # Select if you are affected by the errata where the part will not function
 # if MCLK divide-by-1.5 is selected and VD is set to 3.3V.  The driver will
 # if MCLK divide-by-1.5 is selected and VD is set to 3.3V.  The driver will
@@ -138,9 +141,15 @@ config SND_SOC_CS4270_VD33_ERRATA
 config SND_SOC_CX20442
 config SND_SOC_CX20442
 	tristate
 	tristate
 
 
+config SND_SOC_JZ4740_CODEC
+	tristate
+
 config SND_SOC_L3
 config SND_SOC_L3
        tristate
        tristate
 
 
+config SND_SOC_DA7210
+        tristate
+
 config SND_SOC_PCM3008
 config SND_SOC_PCM3008
        tristate
        tristate
 
 
@@ -206,6 +215,9 @@ config SND_SOC_WM8728
 config SND_SOC_WM8731
 config SND_SOC_WM8731
 	tristate
 	tristate
 
 
+config SND_SOC_WM8741
+	tristate
+
 config SND_SOC_WM8750
 config SND_SOC_WM8750
 	tristate
 	tristate
 
 

+ 6 - 0
sound/soc/codecs/Makefile

@@ -9,6 +9,7 @@ snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cq93vc-objs := cq93vc.o
+snd-soc-cs42l51-objs := cs42l51.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-da7210-objs := da7210.o
@@ -34,6 +35,7 @@ snd-soc-wm8711-objs := wm8711.o
 snd-soc-wm8727-objs := wm8727.o
 snd-soc-wm8727-objs := wm8727.o
 snd-soc-wm8728-objs := wm8728.o
 snd-soc-wm8728-objs := wm8728.o
 snd-soc-wm8731-objs := wm8731.o
 snd-soc-wm8731-objs := wm8731.o
+snd-soc-wm8741-objs := wm8741.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8776-objs := wm8776.o
 snd-soc-wm8776-objs := wm8776.o
@@ -56,6 +58,7 @@ snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
 snd-soc-wm-hubs-objs := wm_hubs.o
+snd-soc-jz4740-codec-objs := jz4740.o
 
 
 # Amp
 # Amp
 snd-soc-max9877-objs := max9877.o
 snd-soc-max9877-objs := max9877.o
@@ -74,10 +77,12 @@ obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
+obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
@@ -99,6 +104,7 @@ obj-$(CONFIG_SND_SOC_WM8711)	+= snd-soc-wm8711.o
 obj-$(CONFIG_SND_SOC_WM8727)	+= snd-soc-wm8727.o
 obj-$(CONFIG_SND_SOC_WM8727)	+= snd-soc-wm8727.o
 obj-$(CONFIG_SND_SOC_WM8728)	+= snd-soc-wm8728.o
 obj-$(CONFIG_SND_SOC_WM8728)	+= snd-soc-wm8728.o
 obj-$(CONFIG_SND_SOC_WM8731)	+= snd-soc-wm8731.o
 obj-$(CONFIG_SND_SOC_WM8731)	+= snd-soc-wm8731.o
+obj-$(CONFIG_SND_SOC_WM8741)	+= snd-soc-wm8741.o
 obj-$(CONFIG_SND_SOC_WM8750)	+= snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8750)	+= snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)	+= snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8753)	+= snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8776)	+= snd-soc-wm8776.o
 obj-$(CONFIG_SND_SOC_WM8776)	+= snd-soc-wm8776.o

+ 1 - 0
sound/soc/codecs/ad1836.c

@@ -272,6 +272,7 @@ static int ad1836_register(struct ad1836_priv *ad1836)
 
 
 	if (ad1836_codec) {
 	if (ad1836_codec) {
 		dev_err(codec->dev, "Another ad1836 is registered\n");
 		dev_err(codec->dev, "Another ad1836 is registered\n");
+		kfree(ad1836);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 

+ 40 - 1
sound/soc/codecs/ad193x.c

@@ -24,6 +24,7 @@
 
 
 /* codec private data */
 /* codec private data */
 struct ad193x_priv {
 struct ad193x_priv {
+	unsigned int sysclk;
 	struct snd_soc_codec codec;
 	struct snd_soc_codec codec;
 	u8 reg_cache[AD193X_NUM_REGS];
 	u8 reg_cache[AD193X_NUM_REGS];
 };
 };
@@ -251,15 +252,32 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	return 0;
 	return 0;
 }
 }
 
 
+static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+	switch (freq) {
+	case 12288000:
+	case 18432000:
+	case 24576000:
+	case 36864000:
+		ad193x->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
 static int ad193x_hw_params(struct snd_pcm_substream *substream,
 static int ad193x_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params,
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *dai)
 		struct snd_soc_dai *dai)
 {
 {
-	int word_len = 0, reg = 0;
+	int word_len = 0, reg = 0, master_rate = 0;
 
 
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
 	struct snd_soc_codec *codec = socdev->card->codec;
+	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
 
 
 	/* bit size */
 	/* bit size */
 	switch (params_format(params)) {
 	switch (params_format(params)) {
@@ -275,6 +293,25 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
 		break;
 		break;
 	}
 	}
 
 
+	switch (ad193x->sysclk) {
+	case 12288000:
+		master_rate = AD193X_PLL_INPUT_256;
+		break;
+	case 18432000:
+		master_rate = AD193X_PLL_INPUT_384;
+		break;
+	case 24576000:
+		master_rate = AD193X_PLL_INPUT_512;
+		break;
+	case 36864000:
+		master_rate = AD193X_PLL_INPUT_768;
+		break;
+	}
+
+	reg = snd_soc_read(codec, AD193X_PLL_CLK_CTRL0);
+	reg = (reg & AD193X_PLL_INPUT_MASK) | master_rate;
+	snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg);
+
 	reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
 	reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
 	reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len;
 	reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len;
 	snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
 	snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
@@ -348,6 +385,7 @@ static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
 	/* pll input: mclki/xi */
 	/* pll input: mclki/xi */
 	snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
 	snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
 	snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
 	snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
+	ad193x->sysclk = 12288000;
 
 
 	ret = snd_soc_register_codec(codec);
 	ret = snd_soc_register_codec(codec);
 	if (ret != 0) {
 	if (ret != 0) {
@@ -383,6 +421,7 @@ static struct snd_soc_dai_ops ad193x_dai_ops = {
 	.hw_params = ad193x_hw_params,
 	.hw_params = ad193x_hw_params,
 	.digital_mute = ad193x_mute,
 	.digital_mute = ad193x_mute,
 	.set_tdm_slot = ad193x_set_tdm_slot,
 	.set_tdm_slot = ad193x_set_tdm_slot,
+	.set_sysclk	= ad193x_set_dai_sysclk,
 	.set_fmt = ad193x_set_dai_fmt,
 	.set_fmt = ad193x_set_dai_fmt,
 };
 };
 
 

+ 5 - 0
sound/soc/codecs/ad193x.h

@@ -11,6 +11,11 @@
 
 
 #define AD193X_PLL_CLK_CTRL0    0x800
 #define AD193X_PLL_CLK_CTRL0    0x800
 #define AD193X_PLL_POWERDOWN           0x01
 #define AD193X_PLL_POWERDOWN           0x01
+#define AD193X_PLL_INPUT_MASK   (~0x6)
+#define AD193X_PLL_INPUT_256    (0 << 1)
+#define AD193X_PLL_INPUT_384    (1 << 1)
+#define AD193X_PLL_INPUT_512    (2 << 1)
+#define AD193X_PLL_INPUT_768    (3 << 1)
 #define AD193X_PLL_CLK_CTRL1    0x801
 #define AD193X_PLL_CLK_CTRL1    0x801
 #define AD193X_DAC_CTRL0        0x802
 #define AD193X_DAC_CTRL0        0x802
 #define AD193X_DAC_POWERDOWN           0x01
 #define AD193X_DAC_POWERDOWN           0x01

+ 24 - 12
sound/soc/codecs/ak4642.c

@@ -22,20 +22,13 @@
  * AK4643 is tested.
  * AK4643 is tested.
  */
  */
 
 
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
-#include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
 #include <sound/initval.h>
+#include <sound/tlv.h>
 
 
 #include "ak4642.h"
 #include "ak4642.h"
 
 
@@ -111,6 +104,23 @@
 
 
 struct snd_soc_codec_device soc_codec_dev_ak4642;
 struct snd_soc_codec_device soc_codec_dev_ak4642;
 
 
+/*
+ * Playback Volume (table 39)
+ *
+ * max : 0x00 : +12.0 dB
+ *       ( 0.5 dB step )
+ * min : 0xFE : -115.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(out_tlv, -11500, 50, 1);
+
+static const struct snd_kcontrol_new ak4642_snd_controls[] = {
+
+	SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC,
+			 0, 0xFF, 1, out_tlv),
+};
+
+
 /* codec private data */
 /* codec private data */
 struct ak4642_priv {
 struct ak4642_priv {
 	struct snd_soc_codec codec;
 	struct snd_soc_codec codec;
@@ -204,7 +214,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
 		 *
 		 *
 		 * PLL, Master Mode
 		 * PLL, Master Mode
 		 * Audio I/F Format :MSB justified (ADC & DAC)
 		 * Audio I/F Format :MSB justified (ADC & DAC)
-		 * Digital Volume: -8dB
 		 * Bass Boost Level : Middle
 		 * Bass Boost Level : Middle
 		 *
 		 *
 		 * This operation came from example code of
 		 * This operation came from example code of
@@ -214,8 +223,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
 		ak4642_write(codec, 0x0e, 0x19);
 		ak4642_write(codec, 0x0e, 0x19);
 		ak4642_write(codec, 0x09, 0x91);
 		ak4642_write(codec, 0x09, 0x91);
 		ak4642_write(codec, 0x0c, 0x91);
 		ak4642_write(codec, 0x0c, 0x91);
-		ak4642_write(codec, 0x0a, 0x28);
-		ak4642_write(codec, 0x0d, 0x28);
 		ak4642_write(codec, 0x00, 0x64);
 		ak4642_write(codec, 0x00, 0x64);
 		snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK,	PMHP);
 		snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK,	PMHP);
 		snd_soc_update_bits(codec, PW_MGMT2, HPMTN,	HPMTN);
 		snd_soc_update_bits(codec, PW_MGMT2, HPMTN,	HPMTN);
@@ -491,8 +498,10 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
 	codec->control_data = i2c;
 	codec->control_data = i2c;
 
 
 	ret = ak4642_init(ak4642);
 	ret = ak4642_init(ak4642);
-	if (ret < 0)
+	if (ret < 0) {
 		printk(KERN_ERR "failed to initialise AK4642\n");
 		printk(KERN_ERR "failed to initialise AK4642\n");
+		kfree(ak4642);
+	}
 
 
 	return ret;
 	return ret;
 }
 }
@@ -548,6 +557,9 @@ static int ak4642_probe(struct platform_device *pdev)
 		goto pcm_err;
 		goto pcm_err;
 	}
 	}
 
 
+	snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
+			     ARRAY_SIZE(ak4642_snd_controls));
+
 	dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
 	dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
 	return ret;
 	return ret;
 
 

+ 763 - 0
sound/soc/codecs/cs42l51.c

@@ -0,0 +1,763 @@
+/*
+ * cs42l51.c
+ *
+ * ASoC Driver for Cirrus Logic CS42L51 codecs
+ *
+ * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * Based on cs4270.c - Copyright (c) Freescale Semiconductor
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * For now:
+ *  - Only I2C is support. Not SPI
+ *  - master mode *NOT* supported
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <linux/i2c.h>
+
+#include "cs42l51.h"
+
+enum master_slave_mode {
+	MODE_SLAVE,
+	MODE_SLAVE_AUTO,
+	MODE_MASTER,
+};
+
+struct cs42l51_private {
+	unsigned int mclk;
+	unsigned int audio_mode;	/* The mode (I2S or left-justified) */
+	enum master_slave_mode func;
+	struct snd_soc_codec codec;
+	u8 reg_cache[CS42L51_NUMREGS];
+};
+
+static struct snd_soc_codec *cs42l51_codec;
+
+#define CS42L51_FORMATS ( \
+		SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+		SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+		SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+		SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
+
+static int cs42l51_fill_cache(struct snd_soc_codec *codec)
+{
+	u8 *cache = codec->reg_cache + 1;
+	struct i2c_client *i2c_client = codec->control_data;
+	s32 length;
+
+	length = i2c_smbus_read_i2c_block_data(i2c_client,
+			CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache);
+	if (length != CS42L51_NUMREGS) {
+		dev_err(&i2c_client->dev,
+				"I2C read failure, addr=0x%x (ret=%d vs %d)\n",
+				i2c_client->addr, length, CS42L51_NUMREGS);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
+	const struct i2c_device_id *id)
+{
+	struct snd_soc_codec *codec;
+	struct cs42l51_private *cs42l51;
+	int ret = 0;
+	int reg;
+
+	if (cs42l51_codec)
+		return -EBUSY;
+
+	/* Verify that we have a CS42L51 */
+	ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "failed to read I2C\n");
+		goto error;
+	}
+
+	if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+	    (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+		dev_err(&i2c_client->dev, "Invalid chip id\n");
+		ret = -ENODEV;
+		goto error;
+	}
+
+	dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
+				ret & 7);
+
+	cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
+	if (!cs42l51) {
+		dev_err(&i2c_client->dev, "could not allocate codec\n");
+		return -ENOMEM;
+	}
+	codec = &cs42l51->codec;
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->dev = &i2c_client->dev;
+	codec->name = "CS42L51";
+	codec->owner = THIS_MODULE;
+	codec->dai = &cs42l51_dai;
+	codec->num_dai = 1;
+	snd_soc_codec_set_drvdata(codec, cs42l51);
+
+	codec->control_data = i2c_client;
+	codec->reg_cache = cs42l51->reg_cache;
+	codec->reg_cache_size = CS42L51_NUMREGS;
+	i2c_set_clientdata(i2c_client, codec);
+
+	ret = cs42l51_fill_cache(codec);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "failed to fill register cache\n");
+		goto error_alloc;
+	}
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
+		goto error_alloc;
+	}
+
+	/*
+	 * DAC configuration
+	 * - Use signal processor
+	 * - auto mute
+	 * - vol changes immediate
+	 * - no de-emphasize
+	 */
+	reg = CS42L51_DAC_CTL_DATA_SEL(1)
+		| CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
+	ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
+	if (ret < 0)
+		goto error_alloc;
+
+	cs42l51_dai.dev = codec->dev;
+	cs42l51_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		goto error_alloc;
+	}
+
+	ret = snd_soc_register_dai(&cs42l51_dai);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "failed to register DAIe\n");
+		goto error_reg;
+	}
+
+	return 0;
+
+error_reg:
+	snd_soc_unregister_codec(codec);
+error_alloc:
+	kfree(cs42l51);
+error:
+	return ret;
+}
+
+static int cs42l51_i2c_remove(struct i2c_client *client)
+{
+	struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
+	snd_soc_unregister_dai(&cs42l51_dai);
+	snd_soc_unregister_codec(cs42l51_codec);
+	cs42l51_codec = NULL;
+	kfree(cs42l51);
+	return 0;
+}
+
+
+static const struct i2c_device_id cs42l51_id[] = {
+	{"cs42l51", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+
+static struct i2c_driver cs42l51_i2c_driver = {
+	.driver = {
+		.name = "CS42L51 I2C",
+		.owner = THIS_MODULE,
+	},
+	.id_table = cs42l51_id,
+	.probe = cs42l51_i2c_probe,
+	.remove = cs42l51_i2c_remove,
+};
+
+static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
+
+	switch (value) {
+	default:
+	case 0:
+		ucontrol->value.integer.value[0] = 0;
+		break;
+	/* same value : (L+R)/2 and (R+L)/2 */
+	case 1:
+	case 2:
+		ucontrol->value.integer.value[0] = 1;
+		break;
+	case 3:
+		ucontrol->value.integer.value[0] = 2;
+		break;
+	}
+
+	return 0;
+}
+
+#define CHAN_MIX_NORMAL	0x00
+#define CHAN_MIX_BOTH	0x55
+#define CHAN_MIX_SWAP	0xFF
+
+static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned char val;
+
+	switch (ucontrol->value.integer.value[0]) {
+	default:
+	case 0:
+		val = CHAN_MIX_NORMAL;
+		break;
+	case 1:
+		val = CHAN_MIX_BOTH;
+		break;
+	case 2:
+		val = CHAN_MIX_SWAP;
+		break;
+	}
+
+	snd_soc_write(codec, CS42L51_PCM_MIXER, val);
+
+	return 1;
+}
+
+static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
+static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
+/* This is a lie. after -102 db, it stays at -102 */
+/* maybe a range would be better */
+static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
+static const char *chan_mix[] = {
+	"L R",
+	"L+R",
+	"R L",
+};
+
+static const struct soc_enum cs42l51_chan_mix =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix);
+
+static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
+	SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
+			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
+			7, 0xffffff99, 0x18, adc_pcm_tlv),
+	SOC_DOUBLE_R("PCM Playback Switch",
+			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
+	SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
+			CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
+			8, 0xffffff19, 0x18, aout_tlv),
+	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
+			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
+			7, 0xffffff99, 0x18, adc_pcm_tlv),
+	SOC_DOUBLE_R("ADC Mixer Switch",
+			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
+	SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
+	SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
+	SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
+	SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
+	SOC_DOUBLE_TLV("Mic Boost Volume",
+			CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
+	SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
+	SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
+	SOC_ENUM_EXT("PCM channel mixer",
+			cs42l51_chan_mix,
+			cs42l51_get_chan_mix, cs42l51_set_chan_mix),
+};
+
+/*
+ * to power down, one must:
+ * 1.) Enable the PDN bit
+ * 2.) enable power-down for the select channels
+ * 3.) disable the PDN bit.
+ */
+static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	unsigned long value;
+
+	value = snd_soc_read(w->codec, CS42L51_POWER_CTL1);
+	value &= ~CS42L51_POWER_CTL1_PDN;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMD:
+		value |= CS42L51_POWER_CTL1_PDN;
+		break;
+	default:
+	case SND_SOC_DAPM_POST_PMD:
+		break;
+	}
+	snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
+		CS42L51_POWER_CTL1_PDN, value);
+
+	return 0;
+}
+
+static const char *cs42l51_dac_names[] = {"Direct PCM",
+	"DSP PCM", "ADC"};
+static const struct soc_enum cs42l51_dac_mux_enum =
+	SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names);
+static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
+	SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
+
+static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
+	"MIC Left", "MIC+preamp Left"};
+static const struct soc_enum cs42l51_adcl_mux_enum =
+	SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names);
+static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
+	SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
+
+static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
+	"MIC Right", "MIC+preamp Right"};
+static const struct soc_enum cs42l51_adcr_mux_enum =
+	SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names);
+static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
+	SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
+
+static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
+	SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
+	SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
+		CS42L51_POWER_CTL1, 1, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
+		CS42L51_POWER_CTL1, 2, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
+		CS42L51_POWER_CTL1, 5, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
+		CS42L51_POWER_CTL1, 6, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+
+	/* analog/mic */
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+	SND_SOC_DAPM_INPUT("MICL"),
+	SND_SOC_DAPM_INPUT("MICR"),
+
+	SND_SOC_DAPM_MIXER("Mic Preamp Left",
+		CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mic Preamp Right",
+		CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
+
+	/* HP */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+
+	/* mux */
+	SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
+		&cs42l51_dac_mux_controls),
+	SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
+		&cs42l51_adcl_mux_controls),
+	SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
+		&cs42l51_adcr_mux_controls),
+};
+
+static const struct snd_soc_dapm_route cs42l51_routes[] = {
+	{"HPL", NULL, "Left DAC"},
+	{"HPR", NULL, "Right DAC"},
+
+	{"Left ADC", NULL, "Left PGA"},
+	{"Right ADC", NULL, "Right PGA"},
+
+	{"Mic Preamp Left",  NULL,  "MICL"},
+	{"Mic Preamp Right", NULL,  "MICR"},
+
+	{"PGA-ADC Mux Left",  "AIN1 Left",        "AIN1L" },
+	{"PGA-ADC Mux Left",  "AIN2 Left",        "AIN2L" },
+	{"PGA-ADC Mux Left",  "MIC Left",         "MICL"  },
+	{"PGA-ADC Mux Left",  "MIC+preamp Left",  "Mic Preamp Left" },
+	{"PGA-ADC Mux Right", "AIN1 Right",       "AIN1R" },
+	{"PGA-ADC Mux Right", "AIN2 Right",       "AIN2R" },
+	{"PGA-ADC Mux Right", "MIC Right",        "MICR" },
+	{"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
+
+	{"Left PGA", NULL, "PGA-ADC Mux Left"},
+	{"Right PGA", NULL, "PGA-ADC Mux Right"},
+};
+
+static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int format)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+		cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
+		break;
+	default:
+		dev_err(codec->dev, "invalid DAI format\n");
+		ret = -EINVAL;
+	}
+
+	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs42l51->func = MODE_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs42l51->func = MODE_SLAVE_AUTO;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+struct cs42l51_ratios {
+	unsigned int ratio;
+	unsigned char speed_mode;
+	unsigned char mclk;
+};
+
+static struct cs42l51_ratios slave_ratios[] = {
+	{  512, CS42L51_QSM_MODE, 0 }, {  768, CS42L51_QSM_MODE, 0 },
+	{ 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
+	{ 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
+	{  256, CS42L51_HSM_MODE, 0 }, {  384, CS42L51_HSM_MODE, 0 },
+	{  512, CS42L51_HSM_MODE, 0 }, {  768, CS42L51_HSM_MODE, 0 },
+	{ 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
+	{  128, CS42L51_SSM_MODE, 0 }, {  192, CS42L51_SSM_MODE, 0 },
+	{  256, CS42L51_SSM_MODE, 0 }, {  384, CS42L51_SSM_MODE, 0 },
+	{  512, CS42L51_SSM_MODE, 0 }, {  768, CS42L51_SSM_MODE, 0 },
+	{  128, CS42L51_DSM_MODE, 0 }, {  192, CS42L51_DSM_MODE, 0 },
+	{  256, CS42L51_DSM_MODE, 0 }, {  384, CS42L51_DSM_MODE, 0 },
+};
+
+static struct cs42l51_ratios slave_auto_ratios[] = {
+	{ 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
+	{ 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
+	{  512, CS42L51_HSM_MODE, 0 }, {  768, CS42L51_HSM_MODE, 0 },
+	{ 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
+	{  256, CS42L51_SSM_MODE, 0 }, {  384, CS42L51_SSM_MODE, 0 },
+	{  512, CS42L51_SSM_MODE, 1 }, {  768, CS42L51_SSM_MODE, 1 },
+	{  128, CS42L51_DSM_MODE, 0 }, {  192, CS42L51_DSM_MODE, 0 },
+	{  256, CS42L51_DSM_MODE, 1 }, {  384, CS42L51_DSM_MODE, 1 },
+};
+
+static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l51_ratios *ratios = NULL;
+	int nr_ratios = 0;
+	unsigned int rates = 0;
+	unsigned int rate_min = -1;
+	unsigned int rate_max = 0;
+	int i;
+
+	cs42l51->mclk = freq;
+
+	switch (cs42l51->func) {
+	case MODE_MASTER:
+		return -EINVAL;
+	case MODE_SLAVE:
+		ratios = slave_ratios;
+		nr_ratios = ARRAY_SIZE(slave_ratios);
+		break;
+	case MODE_SLAVE_AUTO:
+		ratios = slave_auto_ratios;
+		nr_ratios = ARRAY_SIZE(slave_auto_ratios);
+		break;
+	}
+
+	for (i = 0; i < nr_ratios; i++) {
+		unsigned int rate = freq / ratios[i].ratio;
+		rates |= snd_pcm_rate_to_rate_bit(rate);
+		if (rate < rate_min)
+			rate_min = rate;
+		if (rate > rate_max)
+			rate_max = rate;
+	}
+	rates &= ~SNDRV_PCM_RATE_KNOT;
+
+	if (!rates) {
+		dev_err(codec->dev, "could not find a valid sample rate\n");
+		return -EINVAL;
+	}
+
+	codec_dai->playback.rates = rates;
+	codec_dai->playback.rate_min = rate_min;
+	codec_dai->playback.rate_max = rate_max;
+
+	codec_dai->capture.rates = rates;
+	codec_dai->capture.rate_min = rate_min;
+	codec_dai->capture.rate_max = rate_max;
+
+	return 0;
+}
+
+static int cs42l51_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+	unsigned int i;
+	unsigned int rate;
+	unsigned int ratio;
+	struct cs42l51_ratios *ratios = NULL;
+	int nr_ratios = 0;
+	int intf_ctl, power_ctl, fmt;
+
+	switch (cs42l51->func) {
+	case MODE_MASTER:
+		return -EINVAL;
+	case MODE_SLAVE:
+		ratios = slave_ratios;
+		nr_ratios = ARRAY_SIZE(slave_ratios);
+		break;
+	case MODE_SLAVE_AUTO:
+		ratios = slave_auto_ratios;
+		nr_ratios = ARRAY_SIZE(slave_auto_ratios);
+		break;
+	}
+
+	/* Figure out which MCLK/LRCK ratio to use */
+	rate = params_rate(params);     /* Sampling rate, in Hz */
+	ratio = cs42l51->mclk / rate;    /* MCLK/LRCK ratio */
+	for (i = 0; i < nr_ratios; i++) {
+		if (ratios[i].ratio == ratio)
+			break;
+	}
+
+	if (i == nr_ratios) {
+		/* We did not find a matching ratio */
+		dev_err(codec->dev, "could not find matching ratio\n");
+		return -EINVAL;
+	}
+
+	intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
+	power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);
+
+	intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
+			| CS42L51_INTF_CTL_DAC_FORMAT(7));
+	power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
+			| CS42L51_MIC_POWER_CTL_MCLK_DIV2);
+
+	switch (cs42l51->func) {
+	case MODE_MASTER:
+		intf_ctl |= CS42L51_INTF_CTL_MASTER;
+		power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+		break;
+	case MODE_SLAVE:
+		power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+		break;
+	case MODE_SLAVE_AUTO:
+		power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
+		break;
+	}
+
+	switch (cs42l51->audio_mode) {
+	case SND_SOC_DAIFMT_I2S:
+		intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
+		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (params_format(params)) {
+		case SNDRV_PCM_FORMAT_S16_LE:
+		case SNDRV_PCM_FORMAT_S16_BE:
+			fmt = CS42L51_DAC_DIF_RJ16;
+			break;
+		case SNDRV_PCM_FORMAT_S18_3LE:
+		case SNDRV_PCM_FORMAT_S18_3BE:
+			fmt = CS42L51_DAC_DIF_RJ18;
+			break;
+		case SNDRV_PCM_FORMAT_S20_3LE:
+		case SNDRV_PCM_FORMAT_S20_3BE:
+			fmt = CS42L51_DAC_DIF_RJ20;
+			break;
+		case SNDRV_PCM_FORMAT_S24_LE:
+		case SNDRV_PCM_FORMAT_S24_BE:
+			fmt = CS42L51_DAC_DIF_RJ24;
+			break;
+		default:
+			dev_err(codec->dev, "unknown format\n");
+			return -EINVAL;
+		}
+		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
+		break;
+	default:
+		dev_err(codec->dev, "unknown format\n");
+		return -EINVAL;
+	}
+
+	if (ratios[i].mclk)
+		power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
+
+	ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int reg;
+	int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
+
+	reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL);
+
+	if (mute)
+		reg |= mask;
+	else
+		reg &= ~mask;
+
+	return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
+}
+
+static struct snd_soc_dai_ops cs42l51_dai_ops = {
+	.hw_params      = cs42l51_hw_params,
+	.set_sysclk     = cs42l51_set_dai_sysclk,
+	.set_fmt        = cs42l51_set_dai_fmt,
+	.digital_mute   = cs42l51_dai_mute,
+};
+
+struct snd_soc_dai cs42l51_dai = {
+	.name = "CS42L51 HiFi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = CS42L51_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = CS42L51_FORMATS,
+	},
+	.ops = &cs42l51_dai_ops,
+};
+EXPORT_SYMBOL_GPL(cs42l51_dai);
+
+
+static int cs42l51_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	if (!cs42l51_codec) {
+		dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
+		return -EINVAL;
+	}
+
+	socdev->card->codec = cs42l51_codec;
+	codec = socdev->card->codec;
+
+	/* Register PCMs */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to create PCMs\n");
+		return ret;
+	}
+
+	snd_soc_add_controls(codec, cs42l51_snd_controls,
+		ARRAY_SIZE(cs42l51_snd_controls));
+	snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
+		ARRAY_SIZE(cs42l51_dapm_widgets));
+	snd_soc_dapm_add_routes(codec, cs42l51_routes,
+		ARRAY_SIZE(cs42l51_routes));
+
+	return 0;
+}
+
+
+static int cs42l51_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_device_cs42l51 = {
+	.probe =	cs42l51_probe,
+	.remove =	cs42l51_remove
+};
+EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
+
+static int __init cs42l51_init(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&cs42l51_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "%s: can't add i2c driver\n", __func__);
+		return ret;
+	}
+	return 0;
+}
+module_init(cs42l51_init);
+
+static void __exit cs42l51_exit(void)
+{
+	i2c_del_driver(&cs42l51_i2c_driver);
+}
+module_exit(cs42l51_exit);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");

+ 163 - 0
sound/soc/codecs/cs42l51.h

@@ -0,0 +1,163 @@
+/*
+ * cs42l51.h
+ *
+ * ASoC Driver for Cirrus Logic CS42L51 codecs
+ *
+ * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.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.
+ */
+#ifndef _CS42L51_H
+#define _CS42L51_H
+
+#define CS42L51_CHIP_ID			0x1B
+#define CS42L51_CHIP_REV_A		0x00
+#define CS42L51_CHIP_REV_B		0x01
+
+#define CS42L51_CHIP_REV_ID		0x01
+#define CS42L51_MK_CHIP_REV(a, b)	((a)<<3|(b))
+
+#define CS42L51_POWER_CTL1		0x02
+#define CS42L51_POWER_CTL1_PDN_DACB	(1<<6)
+#define CS42L51_POWER_CTL1_PDN_DACA	(1<<5)
+#define CS42L51_POWER_CTL1_PDN_PGAB	(1<<4)
+#define CS42L51_POWER_CTL1_PDN_PGAA	(1<<3)
+#define CS42L51_POWER_CTL1_PDN_ADCB	(1<<2)
+#define CS42L51_POWER_CTL1_PDN_ADCA	(1<<1)
+#define CS42L51_POWER_CTL1_PDN		(1<<0)
+
+#define CS42L51_MIC_POWER_CTL		0x03
+#define CS42L51_MIC_POWER_CTL_AUTO	(1<<7)
+#define CS42L51_MIC_POWER_CTL_SPEED(x)	(((x)&3)<<5)
+#define CS42L51_QSM_MODE		3
+#define CS42L51_HSM_MODE		2
+#define	CS42L51_SSM_MODE		1
+#define CS42L51_DSM_MODE		0
+#define CS42L51_MIC_POWER_CTL_3ST_SP	(1<<4)
+#define CS42L51_MIC_POWER_CTL_PDN_MICB	(1<<3)
+#define CS42L51_MIC_POWER_CTL_PDN_MICA	(1<<2)
+#define CS42L51_MIC_POWER_CTL_PDN_BIAS	(1<<1)
+#define CS42L51_MIC_POWER_CTL_MCLK_DIV2	(1<<0)
+
+#define CS42L51_INTF_CTL		0x04
+#define CS42L51_INTF_CTL_LOOPBACK	(1<<7)
+#define CS42L51_INTF_CTL_MASTER		(1<<6)
+#define CS42L51_INTF_CTL_DAC_FORMAT(x)	(((x)&7)<<3)
+#define CS42L51_DAC_DIF_LJ24		0x00
+#define CS42L51_DAC_DIF_I2S		0x01
+#define CS42L51_DAC_DIF_RJ24		0x02
+#define CS42L51_DAC_DIF_RJ20		0x03
+#define CS42L51_DAC_DIF_RJ18		0x04
+#define CS42L51_DAC_DIF_RJ16		0x05
+#define CS42L51_INTF_CTL_ADC_I2S	(1<<2)
+#define CS42L51_INTF_CTL_DIGMIX		(1<<1)
+#define CS42L51_INTF_CTL_MICMIX		(1<<0)
+
+#define CS42L51_MIC_CTL			0x05
+#define CS42L51_MIC_CTL_ADC_SNGVOL	(1<<7)
+#define CS42L51_MIC_CTL_ADCD_DBOOST	(1<<6)
+#define CS42L51_MIC_CTL_ADCA_DBOOST	(1<<5)
+#define CS42L51_MIC_CTL_MICBIAS_SEL	(1<<4)
+#define CS42L51_MIC_CTL_MICBIAS_LVL(x)	(((x)&3)<<2)
+#define CS42L51_MIC_CTL_MICB_BOOST	(1<<1)
+#define CS42L51_MIC_CTL_MICA_BOOST	(1<<0)
+
+#define CS42L51_ADC_CTL			0x06
+#define CS42L51_ADC_CTL_ADCB_HPFEN	(1<<7)
+#define CS42L51_ADC_CTL_ADCB_HPFRZ	(1<<6)
+#define CS42L51_ADC_CTL_ADCA_HPFEN	(1<<5)
+#define CS42L51_ADC_CTL_ADCA_HPFRZ	(1<<4)
+#define CS42L51_ADC_CTL_SOFTB		(1<<3)
+#define CS42L51_ADC_CTL_ZCROSSB		(1<<2)
+#define CS42L51_ADC_CTL_SOFTA		(1<<1)
+#define CS42L51_ADC_CTL_ZCROSSA		(1<<0)
+
+#define CS42L51_ADC_INPUT		0x07
+#define CS42L51_ADC_INPUT_AINB_MUX(x)	(((x)&3)<<6)
+#define CS42L51_ADC_INPUT_AINA_MUX(x)	(((x)&3)<<4)
+#define CS42L51_ADC_INPUT_INV_ADCB	(1<<3)
+#define CS42L51_ADC_INPUT_INV_ADCA	(1<<2)
+#define CS42L51_ADC_INPUT_ADCB_MUTE	(1<<1)
+#define CS42L51_ADC_INPUT_ADCA_MUTE	(1<<0)
+
+#define CS42L51_DAC_OUT_CTL		0x08
+#define CS42L51_DAC_OUT_CTL_HP_GAIN(x)	(((x)&7)<<5)
+#define CS42L51_DAC_OUT_CTL_DAC_SNGVOL	(1<<4)
+#define CS42L51_DAC_OUT_CTL_INV_PCMB	(1<<3)
+#define CS42L51_DAC_OUT_CTL_INV_PCMA	(1<<2)
+#define CS42L51_DAC_OUT_CTL_DACB_MUTE	(1<<1)
+#define CS42L51_DAC_OUT_CTL_DACA_MUTE	(1<<0)
+
+#define CS42L51_DAC_CTL			0x09
+#define CS42L51_DAC_CTL_DATA_SEL(x)	(((x)&3)<<6)
+#define CS42L51_DAC_CTL_FREEZE		(1<<5)
+#define CS42L51_DAC_CTL_DEEMPH		(1<<3)
+#define CS42L51_DAC_CTL_AMUTE		(1<<2)
+#define CS42L51_DAC_CTL_DACSZ(x)	(((x)&3)<<0)
+
+#define CS42L51_ALC_PGA_CTL		0x0A
+#define CS42L51_ALC_PGB_CTL		0x0B
+#define CS42L51_ALC_PGX_ALCX_SRDIS	(1<<7)
+#define CS42L51_ALC_PGX_ALCX_ZCDIS	(1<<6)
+#define CS42L51_ALC_PGX_PGX_VOL(x)	(((x)&0x1f)<<0)
+
+#define CS42L51_ADCA_ATT		0x0C
+#define CS42L51_ADCB_ATT		0x0D
+
+#define CS42L51_ADCA_VOL		0x0E
+#define CS42L51_ADCB_VOL		0x0F
+#define CS42L51_PCMA_VOL		0x10
+#define CS42L51_PCMB_VOL		0x11
+#define CS42L51_MIX_MUTE_ADCMIX		(1<<7)
+#define CS42L51_MIX_VOLUME(x)		(((x)&0x7f)<<0)
+
+#define CS42L51_BEEP_FREQ		0x12
+#define CS42L51_BEEP_VOL		0x13
+#define CS42L51_BEEP_CONF		0x14
+
+#define CS42L51_TONE_CTL		0x15
+#define CS42L51_TONE_CTL_TREB(x)	(((x)&0xf)<<4)
+#define CS42L51_TONE_CTL_BASS(x)	(((x)&0xf)<<0)
+
+#define CS42L51_AOUTA_VOL		0x16
+#define CS42L51_AOUTB_VOL		0x17
+#define CS42L51_PCM_MIXER		0x18
+#define CS42L51_LIMIT_THRES_DIS		0x19
+#define CS42L51_LIMIT_REL		0x1A
+#define CS42L51_LIMIT_ATT		0x1B
+#define CS42L51_ALC_EN			0x1C
+#define CS42L51_ALC_REL			0x1D
+#define CS42L51_ALC_THRES		0x1E
+#define CS42L51_NOISE_CONF		0x1F
+
+#define CS42L51_STATUS			0x20
+#define CS42L51_STATUS_SP_CLKERR	(1<<6)
+#define CS42L51_STATUS_SPEA_OVFL	(1<<5)
+#define CS42L51_STATUS_SPEB_OVFL	(1<<4)
+#define CS42L51_STATUS_PCMA_OVFL	(1<<3)
+#define CS42L51_STATUS_PCMB_OVFL	(1<<2)
+#define CS42L51_STATUS_ADCA_OVFL	(1<<1)
+#define CS42L51_STATUS_ADCB_OVFL	(1<<0)
+
+#define CS42L51_CHARGE_FREQ		0x21
+
+#define CS42L51_FIRSTREG	0x01
+/*
+ * Hack: with register 0x21, it makes 33 registers. Looks like someone in the
+ * i2c layer doesn't like i2c smbus block read of 33 regs. Workaround by using
+ * 32 regs
+ */
+#define CS42L51_LASTREG		0x20
+#define CS42L51_NUMREGS		(CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
+
+extern struct snd_soc_dai cs42l51_dai;
+extern struct snd_soc_codec_device soc_codec_device_cs42l51;
+#endif

+ 33 - 15
sound/soc/codecs/da7210.c

@@ -15,23 +15,15 @@
  * option) any later version.
  * option) any later version.
  */
  */
 
 
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
-#include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
-#include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/pcm_params.h>
-#include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/soc-dapm.h>
-#include <sound/tlv.h>
 #include <sound/initval.h>
 #include <sound/initval.h>
-#include <asm/div64.h>
+#include <sound/tlv.h>
 
 
 #include "da7210.h"
 #include "da7210.h"
 
 
@@ -145,6 +137,29 @@
 
 
 #define DA7210_VERSION "0.0.1"
 #define DA7210_VERSION "0.0.1"
 
 
+/*
+ * Playback Volume
+ *
+ * max		: 0x3F (+15.0 dB)
+ *		   (1.5 dB step)
+ * min		: 0x11 (-54.0 dB)
+ * mute		: 0x10
+ * reserved	: 0x00 - 0x0F
+ *
+ * ** FIXME **
+ *
+ * Reserved area are considered as "mute".
+ * -> min = -79.5 dB
+ */
+static const DECLARE_TLV_DB_SCALE(hp_out_tlv, -7950, 150, 1);
+
+static const struct snd_kcontrol_new da7210_snd_controls[] = {
+
+	SOC_DOUBLE_R_TLV("HeadPhone Playback Volume",
+			 DA7210_HP_L_VOL, DA7210_HP_R_VOL,
+			 0, 0x3F, 0, hp_out_tlv),
+};
+
 /* Codec private data */
 /* Codec private data */
 struct da7210_priv {
 struct da7210_priv {
 	struct snd_soc_codec codec;
 	struct snd_soc_codec codec;
@@ -227,10 +242,6 @@ static int da7210_startup(struct snd_pcm_substream *substream,
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_soc_codec *codec = dai->codec;
 
 
 	if (is_play) {
 	if (is_play) {
-		/* PlayBack Volume 40 */
-		snd_soc_update_bits(codec, DA7210_HP_L_VOL, 0x3F, 40);
-		snd_soc_update_bits(codec, DA7210_HP_R_VOL, 0x3F, 40);
-
 		/* Enable Out */
 		/* Enable Out */
 		snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10);
 		snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10);
 		snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10);
 		snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10);
@@ -488,7 +499,7 @@ static int da7210_init(struct da7210_priv *da7210)
 	ret = snd_soc_register_dai(&da7210_dai);
 	ret = snd_soc_register_dai(&da7210_dai);
 	if (ret) {
 	if (ret) {
 		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
 		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-		goto init_err;
+		goto codec_err;
 	}
 	}
 
 
 	/* FIXME
 	/* FIXME
@@ -574,6 +585,8 @@ static int da7210_init(struct da7210_priv *da7210)
 
 
 	return ret;
 	return ret;
 
 
+codec_err:
+	snd_soc_unregister_codec(codec);
 init_err:
 init_err:
 	kfree(codec->reg_cache);
 	kfree(codec->reg_cache);
 	codec->reg_cache = NULL;
 	codec->reg_cache = NULL;
@@ -601,8 +614,10 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
 	codec->control_data = i2c;
 	codec->control_data = i2c;
 
 
 	ret = da7210_init(da7210);
 	ret = da7210_init(da7210);
-	if (ret < 0)
+	if (ret < 0) {
 		pr_err("Failed to initialise da7210 audio codec\n");
 		pr_err("Failed to initialise da7210 audio codec\n");
+		kfree(da7210);
+	}
 
 
 	return ret;
 	return ret;
 }
 }
@@ -656,6 +671,9 @@ static int da7210_probe(struct platform_device *pdev)
 	if (ret < 0)
 	if (ret < 0)
 		goto pcm_err;
 		goto pcm_err;
 
 
+	snd_soc_add_controls(da7210_codec, da7210_snd_controls,
+			     ARRAY_SIZE(da7210_snd_controls));
+
 	dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
 	dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
 
 
 pcm_err:
 pcm_err:

+ 511 - 0
sound/soc/codecs/jz4740.c

@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * 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.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+
+#define JZ4740_REG_CODEC_1 0x0
+#define JZ4740_REG_CODEC_2 0x1
+
+#define JZ4740_CODEC_1_LINE_ENABLE BIT(29)
+#define JZ4740_CODEC_1_MIC_ENABLE BIT(28)
+#define JZ4740_CODEC_1_SW1_ENABLE BIT(27)
+#define JZ4740_CODEC_1_ADC_ENABLE BIT(26)
+#define JZ4740_CODEC_1_SW2_ENABLE BIT(25)
+#define JZ4740_CODEC_1_DAC_ENABLE BIT(24)
+#define JZ4740_CODEC_1_VREF_DISABLE BIT(20)
+#define JZ4740_CODEC_1_VREF_AMP_DISABLE BIT(19)
+#define JZ4740_CODEC_1_VREF_PULLDOWN BIT(18)
+#define JZ4740_CODEC_1_VREF_LOW_CURRENT BIT(17)
+#define JZ4740_CODEC_1_VREF_HIGH_CURRENT BIT(16)
+#define JZ4740_CODEC_1_HEADPHONE_DISABLE BIT(14)
+#define JZ4740_CODEC_1_HEADPHONE_AMP_CHANGE_ANY BIT(13)
+#define JZ4740_CODEC_1_HEADPHONE_CHARGE BIT(12)
+#define JZ4740_CODEC_1_HEADPHONE_PULLDOWN (BIT(11) | BIT(10))
+#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M BIT(9)
+#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN BIT(8)
+#define JZ4740_CODEC_1_SUSPEND BIT(1)
+#define JZ4740_CODEC_1_RESET BIT(0)
+
+#define JZ4740_CODEC_1_LINE_ENABLE_OFFSET 29
+#define JZ4740_CODEC_1_MIC_ENABLE_OFFSET 28
+#define JZ4740_CODEC_1_SW1_ENABLE_OFFSET 27
+#define JZ4740_CODEC_1_ADC_ENABLE_OFFSET 26
+#define JZ4740_CODEC_1_SW2_ENABLE_OFFSET 25
+#define JZ4740_CODEC_1_DAC_ENABLE_OFFSET 24
+#define JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET 14
+#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET 8
+
+#define JZ4740_CODEC_2_INPUT_VOLUME_MASK		0x1f0000
+#define JZ4740_CODEC_2_SAMPLE_RATE_MASK			0x000f00
+#define JZ4740_CODEC_2_MIC_BOOST_GAIN_MASK		0x000030
+#define JZ4740_CODEC_2_HEADPHONE_VOLUME_MASK	0x000003
+
+#define JZ4740_CODEC_2_INPUT_VOLUME_OFFSET		16
+#define JZ4740_CODEC_2_SAMPLE_RATE_OFFSET		 8
+#define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET	 4
+#define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET	 0
+
+static const uint32_t jz4740_codec_regs[] = {
+	0x021b2302, 0x00170803,
+};
+
+struct jz4740_codec {
+	void __iomem *base;
+	struct resource *mem;
+
+	uint32_t reg_cache[2];
+	struct snd_soc_codec codec;
+};
+
+static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec)
+{
+	return container_of(codec, struct jz4740_codec, codec);
+}
+
+static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+	return readl(jz4740_codec->base + (reg << 2));
+}
+
+static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int val)
+{
+	struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+
+	jz4740_codec->reg_cache[reg] = val;
+	writel(val, jz4740_codec->base + (reg << 2));
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new jz4740_codec_controls[] = {
+	SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2,
+			JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0),
+	SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2,
+			JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0),
+	SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1),
+	SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2,
+			JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0),
+};
+
+static const struct snd_kcontrol_new jz4740_codec_output_controls[] = {
+	SOC_DAPM_SINGLE("Bypass Switch", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_SW1_ENABLE_OFFSET, 1, 0),
+	SOC_DAPM_SINGLE("DAC Switch", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_SW2_ENABLE_OFFSET, 1, 0),
+};
+
+static const struct snd_kcontrol_new jz4740_codec_input_controls[] = {
+	SOC_DAPM_SINGLE("Line Capture Switch", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_LINE_ENABLE_OFFSET, 1, 0),
+	SOC_DAPM_SINGLE("Mic Capture Switch", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_MIC_ENABLE_OFFSET, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget jz4740_codec_dapm_widgets[] = {
+	SND_SOC_DAPM_ADC("ADC", "Capture", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_ADC_ENABLE_OFFSET, 0),
+	SND_SOC_DAPM_DAC("DAC", "Playback", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_DAC_ENABLE_OFFSET, 0),
+
+	SND_SOC_DAPM_MIXER("Output Mixer", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET, 1,
+			jz4740_codec_output_controls,
+			ARRAY_SIZE(jz4740_codec_output_controls)),
+
+	SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0,
+			jz4740_codec_input_controls,
+			ARRAY_SIZE(jz4740_codec_input_controls)),
+	SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+
+	SND_SOC_DAPM_INPUT("MIC"),
+	SND_SOC_DAPM_INPUT("LIN"),
+	SND_SOC_DAPM_INPUT("RIN"),
+};
+
+static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = {
+	{"Line Input", NULL, "LIN"},
+	{"Line Input", NULL, "RIN"},
+
+	{"Input Mixer", "Line Capture Switch", "Line Input"},
+	{"Input Mixer", "Mic Capture Switch", "MIC"},
+
+	{"ADC", NULL, "Input Mixer"},
+
+	{"Output Mixer", "Bypass Switch", "Input Mixer"},
+	{"Output Mixer", "DAC Switch", "DAC"},
+
+	{"LOUT", NULL, "Output Mixer"},
+	{"ROUT", NULL, "Output Mixer"},
+};
+
+static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	uint32_t val;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	switch (params_rate(params)) {
+	case 8000:
+		val = 0;
+		break;
+	case 11025:
+		val = 1;
+		break;
+	case 12000:
+		val = 2;
+		break;
+	case 16000:
+		val = 3;
+		break;
+	case 22050:
+		val = 4;
+		break;
+	case 24000:
+		val = 5;
+		break;
+	case 32000:
+		val = 6;
+		break;
+	case 44100:
+		val = 7;
+		break;
+	case 48000:
+		val = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET;
+
+	snd_soc_update_bits(codec, JZ4740_REG_CODEC_2,
+				JZ4740_CODEC_2_SAMPLE_RATE_MASK, val);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops jz4740_codec_dai_ops = {
+	.hw_params = jz4740_codec_hw_params,
+};
+
+struct snd_soc_dai jz4740_codec_dai = {
+	.name = "jz4740",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
+	},
+	.ops = &jz4740_codec_dai_ops,
+	.symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(jz4740_codec_dai);
+
+static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
+{
+	int i;
+	uint32_t *cache = codec->reg_cache;
+
+	snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+		JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET);
+	udelay(2);
+
+	snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+		JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0);
+
+	for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i)
+		jz4740_codec_write(codec, i, cache[i]);
+}
+
+static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	unsigned int mask;
+	unsigned int value;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		mask = JZ4740_CODEC_1_VREF_DISABLE |
+				JZ4740_CODEC_1_VREF_AMP_DISABLE |
+				JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+		value = 0;
+
+		snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* The only way to clear the suspend flag is to reset the codec */
+		if (codec->bias_level == SND_SOC_BIAS_OFF)
+			jz4740_codec_wakeup(codec);
+
+		mask = JZ4740_CODEC_1_VREF_DISABLE |
+			JZ4740_CODEC_1_VREF_AMP_DISABLE |
+			JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+		value = JZ4740_CODEC_1_VREF_DISABLE |
+			JZ4740_CODEC_1_VREF_AMP_DISABLE |
+			JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+
+		snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
+		break;
+	case SND_SOC_BIAS_OFF:
+		mask = JZ4740_CODEC_1_SUSPEND;
+		value = JZ4740_CODEC_1_SUSPEND;
+
+		snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
+		break;
+	default:
+		break;
+	}
+
+	codec->bias_level = level;
+
+	return 0;
+}
+
+static struct snd_soc_codec *jz4740_codec_codec;
+
+static int jz4740_codec_dev_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = jz4740_codec_codec;
+
+	BUG_ON(!codec);
+
+	socdev->card->codec = codec;
+
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret);
+		return ret;
+	}
+
+	snd_soc_add_controls(codec, jz4740_codec_controls,
+		ARRAY_SIZE(jz4740_codec_controls));
+
+	snd_soc_dapm_new_controls(codec, jz4740_codec_dapm_widgets,
+		ARRAY_SIZE(jz4740_codec_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, jz4740_codec_dapm_routes,
+		ARRAY_SIZE(jz4740_codec_dapm_routes));
+
+	snd_soc_dapm_new_widgets(codec);
+
+	return 0;
+}
+
+static int jz4740_codec_dev_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static int jz4740_codec_resume(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec = socdev->card->codec;
+
+	return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+}
+
+#else
+#define jz4740_codec_suspend NULL
+#define jz4740_codec_resume NULL
+#endif
+
+struct snd_soc_codec_device soc_codec_dev_jz4740_codec = {
+	.probe = jz4740_codec_dev_probe,
+	.remove = jz4740_codec_dev_remove,
+	.suspend = jz4740_codec_suspend,
+	.resume = jz4740_codec_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec);
+
+static int __devinit jz4740_codec_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct jz4740_codec *jz4740_codec;
+	struct snd_soc_codec *codec;
+	struct resource *mem;
+
+	jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL);
+	if (!jz4740_codec)
+		return -ENOMEM;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "Failed to get mmio memory resource\n");
+		ret = -ENOENT;
+		goto err_free_codec;
+	}
+
+	mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
+	if (!mem) {
+		dev_err(&pdev->dev, "Failed to request mmio memory region\n");
+		ret = -EBUSY;
+		goto err_free_codec;
+	}
+
+	jz4740_codec->base = ioremap(mem->start, resource_size(mem));
+	if (!jz4740_codec->base) {
+		dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
+		ret = -EBUSY;
+		goto err_release_mem_region;
+	}
+	jz4740_codec->mem = mem;
+
+	jz4740_codec_dai.dev = &pdev->dev;
+
+	codec = &jz4740_codec->codec;
+
+	codec->dev		= &pdev->dev;
+	codec->name		= "jz4740";
+	codec->owner		= THIS_MODULE;
+
+	codec->read		= jz4740_codec_read;
+	codec->write		= jz4740_codec_write;
+	codec->set_bias_level	= jz4740_codec_set_bias_level;
+	codec->bias_level	= SND_SOC_BIAS_OFF;
+
+	codec->dai		= &jz4740_codec_dai;
+	codec->num_dai		= 1;
+
+	codec->reg_cache	= jz4740_codec->reg_cache;
+	codec->reg_cache_size	= 2;
+	memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs));
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	jz4740_codec_codec = codec;
+
+	snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
+
+	platform_set_drvdata(pdev, jz4740_codec);
+
+	ret = snd_soc_register_codec(codec);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register codec\n");
+		goto err_iounmap;
+	}
+
+	ret = snd_soc_register_dai(&jz4740_codec_dai);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register codec dai\n");
+		goto err_unregister_codec;
+	}
+
+	jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+
+err_unregister_codec:
+	snd_soc_unregister_codec(codec);
+err_iounmap:
+	iounmap(jz4740_codec->base);
+err_release_mem_region:
+	release_mem_region(mem->start, resource_size(mem));
+err_free_codec:
+	kfree(jz4740_codec);
+
+	return ret;
+}
+
+static int __devexit jz4740_codec_remove(struct platform_device *pdev)
+{
+	struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
+	struct resource *mem = jz4740_codec->mem;
+
+	snd_soc_unregister_dai(&jz4740_codec_dai);
+	snd_soc_unregister_codec(&jz4740_codec->codec);
+
+	iounmap(jz4740_codec->base);
+	release_mem_region(mem->start, resource_size(mem));
+
+	platform_set_drvdata(pdev, NULL);
+	kfree(jz4740_codec);
+
+	return 0;
+}
+
+static struct platform_driver jz4740_codec_driver = {
+	.probe = jz4740_codec_probe,
+	.remove = __devexit_p(jz4740_codec_remove),
+	.driver = {
+		.name = "jz4740-codec",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init jz4740_codec_init(void)
+{
+	return platform_driver_register(&jz4740_codec_driver);
+}
+module_init(jz4740_codec_init);
+
+static void __exit jz4740_codec_exit(void)
+{
+	platform_driver_unregister(&jz4740_codec_driver);
+}
+module_exit(jz4740_codec_exit);
+
+MODULE_DESCRIPTION("JZ4740 SoC internal codec driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:jz4740-codec");

+ 20 - 0
sound/soc/codecs/jz4740.h

@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * 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.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __SND_SOC_CODECS_JZ4740_CODEC_H__
+#define __SND_SOC_CODECS_JZ4740_CODEC_H__
+
+extern struct snd_soc_dai jz4740_codec_dai;
+extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec;
+
+#endif

+ 93 - 1
sound/soc/codecs/spdif_transciever.c

@@ -16,8 +16,10 @@
 
 
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
+#include <linux/slab.h>
 #include <sound/soc.h>
 #include <sound/soc.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
+#include <sound/initval.h>
 
 
 #include "spdif_transciever.h"
 #include "spdif_transciever.h"
 
 
@@ -26,6 +28,48 @@ MODULE_LICENSE("GPL");
 #define STUB_RATES	SNDRV_PCM_RATE_8000_96000
 #define STUB_RATES	SNDRV_PCM_RATE_8000_96000
 #define STUB_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
 #define STUB_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
 
 
+static struct snd_soc_codec *spdif_dit_codec;
+
+static int spdif_dit_codec_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret;
+
+	if (spdif_dit_codec == NULL) {
+		dev_err(&pdev->dev, "Codec device not registered\n");
+		return -ENODEV;
+	}
+
+	socdev->card->codec = spdif_dit_codec;
+	codec = spdif_dit_codec;
+
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+		goto err_create_pcms;
+	}
+
+	return 0;
+
+err_create_pcms:
+	return ret;
+}
+
+static int spdif_dit_codec_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_spdif_dit = {
+	.probe		= spdif_dit_codec_probe,
+	.remove		= spdif_dit_codec_remove,
+}; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit);
+
 struct snd_soc_dai dit_stub_dai = {
 struct snd_soc_dai dit_stub_dai = {
 	.name		= "DIT",
 	.name		= "DIT",
 	.playback 	= {
 	.playback 	= {
@@ -40,13 +84,61 @@ EXPORT_SYMBOL_GPL(dit_stub_dai);
 
 
 static int spdif_dit_probe(struct platform_device *pdev)
 static int spdif_dit_probe(struct platform_device *pdev)
 {
 {
+	struct snd_soc_codec *codec;
+	int ret;
+
+	if (spdif_dit_codec) {
+		dev_err(&pdev->dev, "Another Codec is registered\n");
+		ret = -EINVAL;
+		goto err_reg_codec;
+	}
+
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	codec->dev = &pdev->dev;
+
+	mutex_init(&codec->mutex);
+
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->name = "spdif-dit";
+	codec->owner = THIS_MODULE;
+	codec->dai = &dit_stub_dai;
+	codec->num_dai = 1;
+
+	spdif_dit_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		goto err_reg_codec;
+	}
+
 	dit_stub_dai.dev = &pdev->dev;
 	dit_stub_dai.dev = &pdev->dev;
-	return snd_soc_register_dai(&dit_stub_dai);
+	ret = snd_soc_register_dai(&dit_stub_dai);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to register dai: %d\n", ret);
+		goto err_reg_dai;
+	}
+
+	return 0;
+
+err_reg_dai:
+	snd_soc_unregister_codec(codec);
+err_reg_codec:
+	kfree(spdif_dit_codec);
+	return ret;
 }
 }
 
 
 static int spdif_dit_remove(struct platform_device *pdev)
 static int spdif_dit_remove(struct platform_device *pdev)
 {
 {
 	snd_soc_unregister_dai(&dit_stub_dai);
 	snd_soc_unregister_dai(&dit_stub_dai);
+	snd_soc_unregister_codec(spdif_dit_codec);
+	kfree(spdif_dit_codec);
+	spdif_dit_codec = NULL;
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 0
sound/soc/codecs/spdif_transciever.h

@@ -12,6 +12,7 @@
 #ifndef CODEC_STUBS_H
 #ifndef CODEC_STUBS_H
 #define CODEC_STUBS_H
 #define CODEC_STUBS_H
 
 
+extern struct snd_soc_codec_device soc_codec_dev_spdif_dit;
 extern struct snd_soc_dai dit_stub_dai;
 extern struct snd_soc_dai dit_stub_dai;
 
 
 #endif /* CODEC_STUBS_H */
 #endif /* CODEC_STUBS_H */

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