Browse Source

Merge branch 'topic/hda' into to-push

Takashi Iwai 16 years ago
parent
commit
a65056205c

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

@@ -757,6 +757,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     model	- force the model name
     position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF)
     probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
+    probe_only	- Only probing and no codec initialization (default=off);
+		  Useful to check the initial codec status for debugging
     bdl_pos_adj	- Specifies the DMA IRQ timing delay in samples.
 		Passing -1 will make the driver to choose the appropriate
 		value based on the controller chip.
@@ -772,327 +774,23 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     This module supports multiple cards and autoprobe.
     
+    See Documentation/sound/alsa/HD-Audio.txt for more details about
+    HD-audio driver.
+
     Each codec may have a model table for different configurations.
     If your machine isn't listed there, the default (usually minimal)
     configuration is set up.  You can pass "model=<name>" option to
     specify a certain model in such a case.  There are different
-    models depending on the codec chip.
-
-	  Model name	Description
-	  ----------    -----------
-	ALC880
-	  3stack	3-jack in back and a headphone out
-	  3stack-digout	3-jack in back, a HP out and a SPDIF out
-	  5stack	5-jack in back, 2-jack in front
-	  5stack-digout	5-jack in back, 2-jack in front, a SPDIF out
-	  6stack	6-jack in back, 2-jack in front
-	  6stack-digout	6-jack with a SPDIF out
-	  w810		3-jack
-	  z71v		3-jack (HP shared SPDIF)
-	  asus		3-jack (ASUS Mobo)
-	  asus-w1v	ASUS W1V
-	  asus-dig	ASUS with SPDIF out
-	  asus-dig2	ASUS with SPDIF out (using GPIO2)
-	  uniwill	3-jack
-	  fujitsu	Fujitsu Laptops (Pi1536)
-	  F1734		2-jack
-	  lg		LG laptop (m1 express dual)
-	  lg-lw		LG LW20/LW25 laptop
-	  tcl		TCL S700
-	  clevo		Clevo laptops (m520G, m665n)
-	  medion	Medion Rim 2150
-	  test		for testing/debugging purpose, almost all controls can be
-			adjusted.  Appearing only when compiled with
-			$CONFIG_SND_DEBUG=y
-	  auto		auto-config reading BIOS (default)
-
-	ALC260
-	  hp		HP machines
-	  hp-3013	HP machines (3013-variant)
-	  hp-dc7600	HP DC7600
-	  fujitsu	Fujitsu S7020
-	  acer		Acer TravelMate
-	  will		Will laptops (PB V7900)
-	  replacer	Replacer 672V
-	  basic		fixed pin assignment (old default model)
-	  test		for testing/debugging purpose, almost all controls can
-			adjusted.  Appearing only when compiled with
-			$CONFIG_SND_DEBUG=y
-	  auto		auto-config reading BIOS (default)
-
-	ALC262
-	  fujitsu	Fujitsu Laptop
-	  hp-bpc	HP xw4400/6400/8400/9400 laptops
-	  hp-bpc-d7000	HP BPC D7000
-	  hp-tc-t5735	HP Thin Client T5735
-	  hp-rp5700	HP RP5700
-	  benq		Benq ED8
-	  benq-t31	Benq T31
-	  hippo		Hippo (ATI) with jack detection, Sony UX-90s
-	  hippo_1	Hippo (Benq) with jack detection
-	  sony-assamd	Sony ASSAMD
-	  toshiba-s06	Toshiba S06
-	  toshiba-rx1	Toshiba RX1
-	  ultra		Samsung Q1 Ultra Vista model
-	  lenovo-3000	Lenovo 3000 y410
-	  nec		NEC Versa S9100
-	  basic		fixed pin assignment w/o SPDIF
-	  auto		auto-config reading BIOS (default)
-
-	ALC267/268
-	  quanta-il1	Quanta IL1 mini-notebook
-	  3stack	3-stack model
-	  toshiba	Toshiba A205
-	  acer		Acer laptops
-	  acer-aspire	Acer Aspire One
-	  dell		Dell OEM laptops (Vostro 1200)
-	  zepto		Zepto laptops
-	  test		for testing/debugging purpose, almost all controls can
-			adjusted.  Appearing only when compiled with
-			$CONFIG_SND_DEBUG=y
-	  auto		auto-config reading BIOS (default)
-
-	ALC269
-	  basic		Basic preset
-	  quanta	Quanta FL1
-	  eeepc-p703	ASUS Eeepc P703 P900A
-	  eeepc-p901	ASUS Eeepc P901 S101
-
-	ALC662/663
-	  3stack-dig	3-stack (2-channel) with SPDIF
-	  3stack-6ch	 3-stack (6-channel)
-	  3stack-6ch-dig 3-stack (6-channel) with SPDIF
-	  6stack-dig	 6-stack with SPDIF
-	  lenovo-101e	 Lenovo laptop
-	  eeepc-p701	ASUS Eeepc P701
-	  eeepc-ep20	ASUS Eeepc EP20
-	  ecs		ECS/Foxconn mobo
-	  m51va		ASUS M51VA
-	  g71v		ASUS G71V
-	  h13		ASUS H13
-	  g50v		ASUS G50V
-	  asus-mode1	ASUS
-	  asus-mode2	ASUS
-	  asus-mode3	ASUS
-	  asus-mode4	ASUS
-	  asus-mode5	ASUS
-	  asus-mode6	ASUS
-	  auto		auto-config reading BIOS (default)
-
-	ALC882/885
-	  3stack-dig	3-jack with SPDIF I/O
-	  6stack-dig	6-jack digital with SPDIF I/O
-	  arima		Arima W820Di1
-	  targa		Targa T8, MSI-1049 T8
-	  asus-a7j	ASUS A7J
-	  asus-a7m	ASUS A7M
-	  macpro	MacPro support
-	  mbp3		Macbook Pro rev3
-	  imac24	iMac 24'' with jack detection
-	  w2jc		ASUS W2JC
-	  auto		auto-config reading BIOS (default)
-
-	ALC883/888
-	  3stack-dig	3-jack with SPDIF I/O
-	  6stack-dig	6-jack digital with SPDIF I/O
-	  3stack-6ch    3-jack 6-channel
-	  3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
-	  6stack-dig-demo  6-jack digital for Intel demo board
-	  acer		Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
-	  acer-aspire	Acer Aspire 9810
-	  medion	Medion Laptops
-	  medion-md2	Medion MD2
-	  targa-dig	Targa/MSI
-	  targa-2ch-dig	Targs/MSI with 2-channel
-	  laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
-	  lenovo-101e	Lenovo 101E
-	  lenovo-nb0763	Lenovo NB0763
-	  lenovo-ms7195-dig Lenovo MS7195
-	  lenovo-sky	Lenovo Sky
-	  haier-w66	Haier W66
-	  3stack-hp	HP machines with 3stack (Lucknow, Samba boards)
-	  6stack-dell	Dell machines with 6stack (Inspiron 530)
-	  mitac		Mitac 8252D
-	  clevo-m720	Clevo M720 laptop series
-	  fujitsu-pi2515 Fujitsu AMILO Pi2515
-	  3stack-6ch-intel Intel DG33* boards
-	  auto		auto-config reading BIOS (default)
-
-	ALC861/660
-	  3stack	3-jack
-	  3stack-dig	3-jack with SPDIF I/O
-	  6stack-dig	6-jack with SPDIF I/O
-	  3stack-660	3-jack (for ALC660)
-	  uniwill-m31	Uniwill M31 laptop
-	  toshiba	Toshiba laptop support
-	  asus		Asus laptop support
-	  asus-laptop	ASUS F2/F3 laptops
-	  auto		auto-config reading BIOS (default)
-
-	ALC861VD/660VD
-	  3stack	3-jack
-	  3stack-dig	3-jack with SPDIF OUT
-	  6stack-dig	6-jack with SPDIF OUT
-	  3stack-660	3-jack (for ALC660VD)
-	  3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD)
-	  lenovo	Lenovo 3000 C200
-	  dallas	Dallas laptops
-	  hp		HP TX1000
-	  auto		auto-config reading BIOS (default)
-
-	CMI9880
-	  minimal	3-jack in back
-	  min_fp	3-jack in back, 2-jack in front
-	  full		6-jack in back, 2-jack in front
-	  full_dig	6-jack in back, 2-jack in front, SPDIF I/O
-	  allout	5-jack in back, 2-jack in front, SPDIF out
-	  auto		auto-config reading BIOS (default)
-
-	AD1882 / AD1882A
-	  3stack	3-stack mode (default)
-	  6stack	6-stack mode
-
-	AD1884A / AD1883 / AD1984A / AD1984B
-	  desktop	3-stack desktop (default)
-	  laptop	laptop with HP jack sensing
-	  mobile	mobile devices with HP jack sensing
-	  thinkpad	Lenovo Thinkpad X300
-
-	AD1884
-	  N/A
-
-	AD1981
-	  basic		3-jack (default)
-	  hp		HP nx6320
-	  thinkpad	Lenovo Thinkpad T60/X60/Z60
-	  toshiba	Toshiba U205
-
-	AD1983
-	  N/A
-
-	AD1984
-	  basic		default configuration
-	  thinkpad	Lenovo Thinkpad T61/X61
-	  dell		Dell T3400
-
-	AD1986A
-	  6stack	6-jack, separate surrounds (default)
-	  3stack	3-stack, shared surrounds
-	  laptop	2-channel only (FSC V2060, Samsung M50)
-	  laptop-eapd	2-channel with EAPD (Samsung R65, ASUS A6J)
-	  laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100)
-	  ultra		2-channel with EAPD (Samsung Ultra tablet PC)
-
-	AD1988/AD1988B/AD1989A/AD1989B
-	  6stack	6-jack
-	  6stack-dig	ditto with SPDIF
-	  3stack	3-jack
-	  3stack-dig	ditto with SPDIF
-	  laptop	3-jack with hp-jack automute
-	  laptop-dig	ditto with SPDIF
-	  auto		auto-config reading BIOS (default)
-	
-	Conexant 5045
-	  laptop-hpsense    Laptop with HP sense (old model laptop)
-	  laptop-micsense   Laptop with Mic sense (old model fujitsu)
-	  laptop-hpmicsense Laptop with HP and Mic senses
-	  benq		Benq R55E
-	  test		for testing/debugging purpose, almost all controls
-			can be adjusted.  Appearing only when compiled with
-			$CONFIG_SND_DEBUG=y
-
-	Conexant 5047
-	  laptop	Basic Laptop config 
-	  laptop-hp	Laptop config for some HP models (subdevice 30A5)
-	  laptop-eapd	Laptop config with EAPD support
-	  test		for testing/debugging purpose, almost all controls
-			can be adjusted.  Appearing only when compiled with
-			$CONFIG_SND_DEBUG=y
-
-	Conexant 5051
-	  laptop	Basic Laptop config (default)
-	  hp		HP Spartan laptop
-
-	STAC9200
-	  ref		Reference board
-	  dell-d21	Dell (unknown)
-	  dell-d22	Dell (unknown)
-	  dell-d23	Dell (unknown)
-	  dell-m21	Dell Inspiron 630m, Dell Inspiron 640m
-	  dell-m22	Dell Latitude D620, Dell Latitude D820
-	  dell-m23	Dell XPS M1710, Dell Precision M90
-	  dell-m24	Dell Latitude 120L
-	  dell-m25	Dell Inspiron E1505n
-	  dell-m26	Dell Inspiron 1501
-	  dell-m27	Dell Inspiron E1705/9400
-	  gateway	Gateway laptops with EAPD control
-	  panasonic	Panasonic CF-74
-
-	STAC9205/9254
-	  ref		Reference board
-	  dell-m42	Dell (unknown)
-	  dell-m43	Dell Precision
-	  dell-m44	Dell Inspiron
-
-	STAC9220/9221
-	  ref		Reference board
-	  3stack	D945 3stack
-	  5stack	D945 5stack + SPDIF
-	  intel-mac-v1	Intel Mac Type 1
-	  intel-mac-v2	Intel Mac Type 2
-	  intel-mac-v3	Intel Mac Type 3
-	  intel-mac-v4	Intel Mac Type 4
-	  intel-mac-v5	Intel Mac Type 5
-	  intel-mac-auto Intel Mac (detect type according to subsystem id)
-	  macmini	Intel Mac Mini (equivalent with type 3)
-	  macbook	Intel Mac Book (eq. type 5)
-	  macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)
-	  macbook-pro	Intel Mac Book Pro 2nd generation (eq. type 3)
-	  imac-intel	Intel iMac (eq. type 2)
-	  imac-intel-20	Intel iMac (newer version) (eq. type 3)
-	  dell-d81	Dell (unknown)
-	  dell-d82	Dell (unknown)
-	  dell-m81	Dell (unknown)
-	  dell-m82	Dell XPS M1210
-
-	STAC9202/9250/9251
-	  ref		Reference board, base config
-	  m2-2		Some Gateway MX series laptops
-	  m6		Some Gateway NX series laptops
-	  pa6		Gateway NX860 series
-
-	STAC9227/9228/9229/927x
-	  ref		Reference board
-	  ref-no-jd	Reference board without HP/Mic jack detection
-	  3stack	D965 3stack
-	  5stack	D965 5stack + SPDIF
-	  dell-3stack	Dell Dimension E520
-	  dell-bios	Fixes with Dell BIOS setup
-
-	STAC92HD71B*
-	  ref		Reference board
-	  dell-m4-1	Dell desktops
-	  dell-m4-2	Dell desktops
-	  dell-m4-3	Dell desktops
-
-	STAC92HD73*
-	  ref		Reference board
-	  no-jd		BIOS setup but without jack-detection
-	  dell-m6-amic	Dell desktops/laptops with analog mics
-	  dell-m6-dmic	Dell desktops/laptops with digital mics
-	  dell-m6	Dell desktops/laptops with both type of mics
-
-	STAC9872
-	  vaio		Setup for VAIO FE550G/SZ110
-	  vaio-ar Setup for VAIO AR
+    models depending on the codec chip.  The list of available models
+    is found in HD-Audio-Models.txt
 
     The model name "genric" is treated as a special case.  When this
     model is given, the driver uses the generic codec parser without
     "codec-patch".  It's sometimes good for testing and debugging.
 
     If the default configuration doesn't work and one of the above
-    matches with your device, report it together with the PCI
-    subsystem ID (output of "lspci -nv") to ALSA BTS or alsa-devel
+    matches with your device, report it together with alsa-info.sh
+    output (with --no-upload option) to kernel bugzilla or alsa-devel
     ML (see the section "Links and Addresses").
 
     power_save and power_save_controller options are for power-saving
@@ -2409,8 +2107,11 @@ Links and Addresses
   ALSA project homepage
        http://www.alsa-project.org
 
-  ALSA Bug Tracking System
-       https://bugtrack.alsa-project.org/bugs/
+  Kernel Bugzilla
+       http://bugzilla.kernel.org/
 
   ALSA Developers ML
        mailto:alsa-devel@alsa-project.org
+
+  alsa-info.sh script
+       http://www.alsa-project.org/alsa-info.sh

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

@@ -0,0 +1,348 @@
+  Model name	Description
+  ----------    -----------
+ALC880
+======
+  3stack	3-jack in back and a headphone out
+  3stack-digout	3-jack in back, a HP out and a SPDIF out
+  5stack	5-jack in back, 2-jack in front
+  5stack-digout	5-jack in back, 2-jack in front, a SPDIF out
+  6stack	6-jack in back, 2-jack in front
+  6stack-digout	6-jack with a SPDIF out
+  w810		3-jack
+  z71v		3-jack (HP shared SPDIF)
+  asus		3-jack (ASUS Mobo)
+  asus-w1v	ASUS W1V
+  asus-dig	ASUS with SPDIF out
+  asus-dig2	ASUS with SPDIF out (using GPIO2)
+  uniwill	3-jack
+  fujitsu	Fujitsu Laptops (Pi1536)
+  F1734		2-jack
+  lg		LG laptop (m1 express dual)
+  lg-lw		LG LW20/LW25 laptop
+  tcl		TCL S700
+  clevo		Clevo laptops (m520G, m665n)
+  medion	Medion Rim 2150
+  test		for testing/debugging purpose, almost all controls can be
+		adjusted.  Appearing only when compiled with
+		$CONFIG_SND_DEBUG=y
+  auto		auto-config reading BIOS (default)
+
+ALC260
+======
+  hp		HP machines
+  hp-3013	HP machines (3013-variant)
+  hp-dc7600	HP DC7600
+  fujitsu	Fujitsu S7020
+  acer		Acer TravelMate
+  will		Will laptops (PB V7900)
+  replacer	Replacer 672V
+  basic		fixed pin assignment (old default model)
+  test		for testing/debugging purpose, almost all controls can
+		adjusted.  Appearing only when compiled with
+		$CONFIG_SND_DEBUG=y
+  auto		auto-config reading BIOS (default)
+
+ALC262
+======
+  fujitsu	Fujitsu Laptop
+  hp-bpc	HP xw4400/6400/8400/9400 laptops
+  hp-bpc-d7000	HP BPC D7000
+  hp-tc-t5735	HP Thin Client T5735
+  hp-rp5700	HP RP5700
+  benq		Benq ED8
+  benq-t31	Benq T31
+  hippo		Hippo (ATI) with jack detection, Sony UX-90s
+  hippo_1	Hippo (Benq) with jack detection
+  sony-assamd	Sony ASSAMD
+  toshiba-s06	Toshiba S06
+  toshiba-rx1	Toshiba RX1
+  ultra		Samsung Q1 Ultra Vista model
+  lenovo-3000	Lenovo 3000 y410
+  nec		NEC Versa S9100
+  basic		fixed pin assignment w/o SPDIF
+  auto		auto-config reading BIOS (default)
+
+ALC267/268
+==========
+  quanta-il1	Quanta IL1 mini-notebook
+  3stack	3-stack model
+  toshiba	Toshiba A205
+  acer		Acer laptops
+  acer-dmic	Acer laptops with digital-mic
+  acer-aspire	Acer Aspire One
+  dell		Dell OEM laptops (Vostro 1200)
+  zepto		Zepto laptops
+  test		for testing/debugging purpose, almost all controls can
+		adjusted.  Appearing only when compiled with
+		$CONFIG_SND_DEBUG=y
+  auto		auto-config reading BIOS (default)
+
+ALC269
+======
+  basic		Basic preset
+  quanta	Quanta FL1
+  eeepc-p703	ASUS Eeepc P703 P900A
+  eeepc-p901	ASUS Eeepc P901 S101
+  fujitsu	FSC Amilo
+  auto		auto-config reading BIOS (default)
+
+ALC662/663
+==========
+  3stack-dig	3-stack (2-channel) with SPDIF
+  3stack-6ch	 3-stack (6-channel)
+  3stack-6ch-dig 3-stack (6-channel) with SPDIF
+  6stack-dig	 6-stack with SPDIF
+  lenovo-101e	 Lenovo laptop
+  eeepc-p701	ASUS Eeepc P701
+  eeepc-ep20	ASUS Eeepc EP20
+  ecs		ECS/Foxconn mobo
+  m51va		ASUS M51VA
+  g71v		ASUS G71V
+  h13		ASUS H13
+  g50v		ASUS G50V
+  asus-mode1	ASUS
+  asus-mode2	ASUS
+  asus-mode3	ASUS
+  asus-mode4	ASUS
+  asus-mode5	ASUS
+  asus-mode6	ASUS
+  auto		auto-config reading BIOS (default)
+
+ALC882/885
+==========
+  3stack-dig	3-jack with SPDIF I/O
+  6stack-dig	6-jack digital with SPDIF I/O
+  arima		Arima W820Di1
+  targa		Targa T8, MSI-1049 T8
+  asus-a7j	ASUS A7J
+  asus-a7m	ASUS A7M
+  macpro	MacPro support
+  mbp3		Macbook Pro rev3
+  imac24	iMac 24'' with jack detection
+  w2jc		ASUS W2JC
+  auto		auto-config reading BIOS (default)
+
+ALC883/888
+==========
+  3stack-dig	3-jack with SPDIF I/O
+  6stack-dig	6-jack digital with SPDIF I/O
+  3stack-6ch    3-jack 6-channel
+  3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
+  6stack-dig-demo  6-jack digital for Intel demo board
+  acer		Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
+  acer-aspire	Acer Aspire 9810
+  acer-aspire-4930g Acer Aspire 4930G
+  medion	Medion Laptops
+  medion-md2	Medion MD2
+  targa-dig	Targa/MSI
+  targa-2ch-dig	Targs/MSI with 2-channel
+  laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
+  lenovo-101e	Lenovo 101E
+  lenovo-nb0763	Lenovo NB0763
+  lenovo-ms7195-dig Lenovo MS7195
+  lenovo-sky	Lenovo Sky
+  haier-w66	Haier W66
+  3stack-hp	HP machines with 3stack (Lucknow, Samba boards)
+  6stack-dell	Dell machines with 6stack (Inspiron 530)
+  mitac		Mitac 8252D
+  clevo-m720	Clevo M720 laptop series
+  fujitsu-pi2515 Fujitsu AMILO Pi2515
+  fujitsu-xa3530 Fujitsu AMILO XA3530
+  3stack-6ch-intel Intel DG33* boards
+  auto		auto-config reading BIOS (default)
+
+ALC861/660
+==========
+  3stack	3-jack
+  3stack-dig	3-jack with SPDIF I/O
+  6stack-dig	6-jack with SPDIF I/O
+  3stack-660	3-jack (for ALC660)
+  uniwill-m31	Uniwill M31 laptop
+  toshiba	Toshiba laptop support
+  asus		Asus laptop support
+  asus-laptop	ASUS F2/F3 laptops
+  auto		auto-config reading BIOS (default)
+
+ALC861VD/660VD
+==============
+  3stack	3-jack
+  3stack-dig	3-jack with SPDIF OUT
+  6stack-dig	6-jack with SPDIF OUT
+  3stack-660	3-jack (for ALC660VD)
+  3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD)
+  lenovo	Lenovo 3000 C200
+  dallas	Dallas laptops
+  hp		HP TX1000
+  asus-v1s	ASUS V1Sn
+  auto		auto-config reading BIOS (default)
+
+CMI9880
+=======
+  minimal	3-jack in back
+  min_fp	3-jack in back, 2-jack in front
+  full		6-jack in back, 2-jack in front
+  full_dig	6-jack in back, 2-jack in front, SPDIF I/O
+  allout	5-jack in back, 2-jack in front, SPDIF out
+  auto		auto-config reading BIOS (default)
+
+AD1882 / AD1882A
+================
+  3stack	3-stack mode (default)
+  6stack	6-stack mode
+
+AD1884A / AD1883 / AD1984A / AD1984B
+====================================
+  desktop	3-stack desktop (default)
+  laptop	laptop with HP jack sensing
+  mobile	mobile devices with HP jack sensing
+  thinkpad	Lenovo Thinkpad X300
+
+AD1884
+======
+  N/A
+
+AD1981
+======
+  basic		3-jack (default)
+  hp		HP nx6320
+  thinkpad	Lenovo Thinkpad T60/X60/Z60
+  toshiba	Toshiba U205
+
+AD1983
+======
+  N/A
+
+AD1984
+======
+  basic		default configuration
+  thinkpad	Lenovo Thinkpad T61/X61
+  dell		Dell T3400
+
+AD1986A
+=======
+  6stack	6-jack, separate surrounds (default)
+  3stack	3-stack, shared surrounds
+  laptop	2-channel only (FSC V2060, Samsung M50)
+  laptop-eapd	2-channel with EAPD (ASUS A6J)
+  laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100)
+  ultra		2-channel with EAPD (Samsung Ultra tablet PC)
+  samsung	2-channel with EAPD (Samsung R65)
+
+AD1988/AD1988B/AD1989A/AD1989B
+==============================
+  6stack	6-jack
+  6stack-dig	ditto with SPDIF
+  3stack	3-jack
+  3stack-dig	ditto with SPDIF
+  laptop	3-jack with hp-jack automute
+  laptop-dig	ditto with SPDIF
+  auto		auto-config reading BIOS (default)
+
+Conexant 5045
+=============
+  laptop-hpsense    Laptop with HP sense (old model laptop)
+  laptop-micsense   Laptop with Mic sense (old model fujitsu)
+  laptop-hpmicsense Laptop with HP and Mic senses
+  benq		Benq R55E
+  test		for testing/debugging purpose, almost all controls
+		can be adjusted.  Appearing only when compiled with
+		$CONFIG_SND_DEBUG=y
+
+Conexant 5047
+=============
+  laptop	Basic Laptop config 
+  laptop-hp	Laptop config for some HP models (subdevice 30A5)
+  laptop-eapd	Laptop config with EAPD support
+  test		for testing/debugging purpose, almost all controls
+		can be adjusted.  Appearing only when compiled with
+		$CONFIG_SND_DEBUG=y
+
+Conexant 5051
+=============
+  laptop	Basic Laptop config (default)
+  hp		HP Spartan laptop
+
+STAC9200
+========
+  ref		Reference board
+  dell-d21	Dell (unknown)
+  dell-d22	Dell (unknown)
+  dell-d23	Dell (unknown)
+  dell-m21	Dell Inspiron 630m, Dell Inspiron 640m
+  dell-m22	Dell Latitude D620, Dell Latitude D820
+  dell-m23	Dell XPS M1710, Dell Precision M90
+  dell-m24	Dell Latitude 120L
+  dell-m25	Dell Inspiron E1505n
+  dell-m26	Dell Inspiron 1501
+  dell-m27	Dell Inspiron E1705/9400
+  gateway	Gateway laptops with EAPD control
+  panasonic	Panasonic CF-74
+
+STAC9205/9254
+=============
+  ref		Reference board
+  dell-m42	Dell (unknown)
+  dell-m43	Dell Precision
+  dell-m44	Dell Inspiron
+
+STAC9220/9221
+=============
+  ref		Reference board
+  3stack	D945 3stack
+  5stack	D945 5stack + SPDIF
+  intel-mac-v1	Intel Mac Type 1
+  intel-mac-v2	Intel Mac Type 2
+  intel-mac-v3	Intel Mac Type 3
+  intel-mac-v4	Intel Mac Type 4
+  intel-mac-v5	Intel Mac Type 5
+  intel-mac-auto Intel Mac (detect type according to subsystem id)
+  macmini	Intel Mac Mini (equivalent with type 3)
+  macbook	Intel Mac Book (eq. type 5)
+  macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)
+  macbook-pro	Intel Mac Book Pro 2nd generation (eq. type 3)
+  imac-intel	Intel iMac (eq. type 2)
+  imac-intel-20	Intel iMac (newer version) (eq. type 3)
+  dell-d81	Dell (unknown)
+  dell-d82	Dell (unknown)
+  dell-m81	Dell (unknown)
+  dell-m82	Dell XPS M1210
+
+STAC9202/9250/9251
+==================
+  ref		Reference board, base config
+  m2-2		Some Gateway MX series laptops
+  m6		Some Gateway NX series laptops
+  pa6		Gateway NX860 series
+
+STAC9227/9228/9229/927x
+=======================
+  ref		Reference board
+  ref-no-jd	Reference board without HP/Mic jack detection
+  3stack	D965 3stack
+  5stack	D965 5stack + SPDIF
+  dell-3stack	Dell Dimension E520
+  dell-bios	Fixes with Dell BIOS setup
+
+STAC92HD71B*
+============
+  ref		Reference board
+  dell-m4-1	Dell desktops
+  dell-m4-2	Dell desktops
+  dell-m4-3	Dell desktops
+
+STAC92HD73*
+===========
+  ref		Reference board
+  no-jd		BIOS setup but without jack-detection
+  dell-m6-amic	Dell desktops/laptops with analog mics
+  dell-m6-dmic	Dell desktops/laptops with digital mics
+  dell-m6	Dell desktops/laptops with both type of mics
+
+STAC92HD83*
+===========
+  ref		Reference board
+
+STAC9872
+========
+  vaio		Setup for VAIO FE550G/SZ110
+  vaio-ar Setup for VAIO AR

+ 577 - 0
Documentation/sound/alsa/HD-Audio.txt

@@ -0,0 +1,577 @@
+MORE NOTES ON HD-AUDIO DRIVER
+=============================
+					Takashi Iwai <tiwai@suse.de>
+
+
+GENERAL
+-------
+
+HD-audio is the new standard on-board audio component on modern PCs
+after AC97.  Although Linux has been supporting HD-audio since long
+time ago, there are often problems with new machines.  A part of the
+problem is broken BIOS, and the rest is the driver implementation.
+This document explains the brief trouble-shooting and debugging
+methods for the	HD-audio hardware.
+
+The HD-audio component consists of two parts: the controller chip and 
+the codec chips on the HD-audio bus.  Linux provides a single driver
+for all controllers, snd-hda-intel.  Although the driver name contains
+a word of a well-known harware vendor, it's not specific to it but for
+all controller chips by other companies.  Since the HD-audio
+controllers are supposed to be compatible, the single snd-hda-driver
+should work in most cases.  But, not surprisingly, there are known
+bugs and issues specific to each controller type.  The snd-hda-intel
+driver has a bunch of workarounds for these as described below.
+
+A controller may have multiple codecs.  Usually you have one audio
+codec and optionally one modem codec.  In theory, there might be
+multiple audio codecs, e.g. for analog and digital outputs, and the
+driver might not work properly because of conflict of mixer elements.
+This should be fixed in future if such hardware really exists.
+
+The snd-hda-intel driver has several different codec parsers depending
+on the codec.  It has a generic parser as a fallback, but this
+functionality is fairly limited until now.  Instead of the generic
+parser, usually the codec-specific parser (coded in patch_*.c) is used
+for the codec-specific implementations.  The details about the
+codec-specific problems are explained in the later sections.
+
+If you are interested in the deep debugging of HD-audio, read the
+HD-audio specification at first.  The specification is found on
+Intel's web page, for example:
+
+- http://www.intel.com/standards/hdaudio/
+
+
+HD-AUDIO CONTROLLER
+-------------------
+
+DMA-Position Problem
+~~~~~~~~~~~~~~~~~~~~
+The most common problem of the controller is the inaccurate DMA
+pointer reporting.  The DMA pointer for playback and capture can be
+read in two ways, either via a LPIB register or via a position-buffer
+map.  As default the driver tries to read from the io-mapped
+position-buffer, and falls back to LPIB if the position-buffer appears
+dead.  However, this detection isn't perfect on some devices.  In such
+a case, you can change the default method via `position_fix` option.
+
+`position_fix=1` means to use LPIB method explicitly.
+`position_fix=2` means to use the position-buffer.  0 is the default
+value, the automatic check and fallback to LPIB as described in the
+above.  If you get a problem of repeated sounds, this option might
+help.
+
+In addition to that, every controller is known to be broken regarding
+the wake-up timing.  It wakes up a few samples before actually
+processing the data on the buffer.  This caused a lot of problems, for
+example, with ALSA dmix or JACK.  Since 2.6.27 kernel, the driver puts
+an artificial delay to the wake up timing.  This delay is controlled
+via `bdl_pos_adj` option. 
+
+When `bdl_pos_adj` is a negative value (as default), it's assigned to
+an appropriate value depending on the controller chip.  For Intel
+chips, it'd be 1 while it'd be 32 for others.  Usually this works.
+Only in case it doesn't work and you get warning messages, you should
+change this parameter to other values.
+
+
+Codec-Probing Problem
+~~~~~~~~~~~~~~~~~~~~~
+A less often but a more severe problem is the codec probing.  When
+BIOS reports the available codec slots wrongly, the driver gets
+confused and tries to access the non-existing codec slot.  This often
+results in the total screw-up, and destructs the further communication
+with the codec chips.  The symptom appears usually as error messages
+like:
+------------------------------------------------------------------------
+  hda_intel: azx_get_response timeout, switching to polling mode:
+        last cmd=0x12345678
+  hda_intel: azx_get_response timeout, switching to single_cmd mode:
+        last cmd=0x12345678
+------------------------------------------------------------------------
+
+The first line is a warning, and this is usually relatively harmless.
+It means that the codec response isn't notified via an IRQ.  The
+driver uses explicit polling method to read the response.  It gives
+very slight CPU overhead, but you'd unlikely notice it.
+
+The second line is, however, a fatal error.  If this happens, usually
+it means that something is really wrong.  Most likely you are
+accessing a non-existing codec slot.
+
+Thus, if the second error message appears, try to narrow the probed
+codec slots via `probe_mask` option.  It's a bitmask, and each bit
+corresponds to the codec slot.  For example, to probe only the first
+slot, pass `probe_mask=1`.  For the first and the third slots, pass
+`probe_mask=5` (where 5 = 1 | 4), and so on.
+
+Since 2.6.29 kernel, the driver has a more robust probing method, so
+this error might happen rarely, though.
+
+
+Interrupt Handling
+~~~~~~~~~~~~~~~~~~
+In rare but some cases, the interrupt isn't properly handled as
+default.  You would notice this by the DMA transfer error reported by
+ALSA PCM core, for example.  Using MSI might help in such a case.
+Pass `enable_msi=1` option for enabling MSI.
+
+
+HD-AUDIO CODEC
+--------------
+
+Model Option
+~~~~~~~~~~~~
+The most common problem regarding the HD-audio driver is the
+unsupported codec features or the mismatched device configuration.
+Most of codec-specific code has several preset models, either to
+override the BIOS setup or to provide more comprehensive features.
+
+The driver checks PCI SSID and looks through the static configuration
+table until any matching entry is found.  If you have a new machine,
+you may see a message like below:
+------------------------------------------------------------------------
+    hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...
+------------------------------------------------------------------------
+Even if you see such a message, DON'T PANIC.  Take a deep breath and
+keep your towel.  First of all, it's an informational message, no
+warning, no error.  This means that the PCI SSID of your device isn't
+listed in the known preset model (white-)list.  But, this doesn't mean
+that the driver is broken.  Many codec-drivers provide the automatic
+configuration mechanism based on the BIOS setup.
+
+The HD-audio codec has usually "pin" widgets, and BIOS sets the default
+configuration of each pin, which indicates the location, the
+connection type, the jack color, etc.  The HD-audio driver can guess
+the right connection judging from these default configuration values.
+However -- some codec-support codes, such as patch_analog.c, don't
+support the automatic probing (yet as of 2.6.28).  And, BIOS is often,
+yes, pretty often broken.  It sets up wrong values and screws up the
+driver.
+
+The preset model is provided basically to overcome such a situation.
+When the matching preset model is found in the white-list, the driver
+assumes the static configuration of that preset and builds the mixer
+elements and PCM streams based on the static information.  Thus, if
+you have a newer machine with a slightly different PCI SSID from the
+existing one, you may have a good chance to re-use the same model.
+You can pass the `model` option to specify the preset model instead of
+PCI SSID look-up.
+
+What `model` option values are available depends on the codec chip.
+Check your codec chip from the codec proc file (see "Codec Proc-File"
+section below).  It will show the vendor/product name of your codec
+chip.  Then, see Documentation/sound/alsa/HD-Audio-Modelstxt file,
+the section of HD-audio driver.  You can find a list of codecs
+and `model` options belonging to each codec.  For example, for Realtek
+ALC262 codec chip, pass `model=ultra` for devices that are compatible
+with Samsung Q1 Ultra.
+
+Thus, the first thing you can do for any brand-new, unsupported and
+non-working HD-audio hardware is to check HD-audio codec and several
+different `model` option values.  If you have a luck, some of them
+might suit with your device well.
+
+Some codecs such as ALC880 have a special model option `model=test`.
+This configures the driver to provide as many mixer controls as
+possible for every single pin feature except for the unsolicited
+events (and maybe some other specials).  Adjust each mixer element and
+try the I/O in the way of trial-and-error until figuring out the whole
+I/O pin mappings.
+
+Note that `model=generic` has a special meaning.  It means to use the
+generic parser regardless of the codec.  Usually the codec-specific
+parser is much better than the generic parser (as now).  Thus this
+option is more about the debugging purpose.
+
+
+Speaker and Headphone Output
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+One of the most frequent (and obvious) bugs with HD-audio is the
+silent output from either or both of a built-in speaker and a
+headphone jack.  In general, you should try a headphone output at
+first.  A speaker output often requires more additional controls like
+the external amplifier bits.  Thus a headphone output has a slightly
+better chance.
+
+Before making a bug report, double-check whether the mixer is set up
+correctly.  The recent version of snd-hda-intel driver provides mostly
+"Master" volume control as well as "Front" volume (where Front
+indicates the front-channels).  In addition, there can be individual
+"Headphone" and "Speaker" controls.
+
+Ditto for the speaker output.  There can be "External Amplifier"
+switch on some codecs.  Turn on this if present.
+
+Another related problem is the automatic mute of speaker output by
+headphone plugging.  This feature is implemented in most cases, but
+not on every preset model or codec-support code.
+
+In anyway, try a different model option if you have such a problem.
+Some other models may match better and give you more matching
+functionality.  If none of the available models works, send a bug
+report.  See the bug report section for details.
+
+If you are masochistic enough to debug the driver problem, note the
+following:
+
+- The speaker (and the headphone, too) output often requires the
+  external amplifier.  This can be set usually via EAPD verb or a
+  certain GPIO.  If the codec pin supports EAPD, you have a better
+  chance via SET_EAPD_BTL verb (0x70c).  On others, GPIO pin (mostly
+  it's either GPIO0 or GPIO1) may turn on/off EAPD.
+- Some Realtek codecs require special vendor-specific coefficients to
+  turn on the amplifier.  See patch_realtek.c.
+- IDT codecs may have extra power-enable/disable controls on each
+  analog pin.  See patch_sigmatel.c.
+- Very rare but some devices don't accept the pin-detection verb until
+  triggered.  Issuing GET_PIN_SENSE verb (0xf09) may result in the
+  codec-communication stall.  Some examples are found in
+  patch_realtek.c.
+
+
+Capture Problems
+~~~~~~~~~~~~~~~~
+The capture problems are often because of missing setups of mixers.
+Thus, before submitting a bug report, make sure that you set up the
+mixer correctly.  For example, both "Capture Volume" and "Capture
+Switch" have to be set properly in addition to the right "Capture
+Source" or "Input Source" selection.  Some devices have "Mic Boost"
+volume or switch.
+
+When the PCM device is opened via "default" PCM (without pulse-audio
+plugin), you'll likely have "Digital Capture Volume" control as well.
+This is provided for the extra gain/attenuation of the signal in
+software, especially for the inputs without the hardware volume
+control such as digital microphones.  Unless really needed, this
+should be set to exactly 50%, corresponding to 0dB -- neither extra
+gain nor attenuation.  When you use "hw" PCM, i.e., a raw access PCM,
+this control will have no influence, though.
+
+It's known that some codecs / devices have fairly bad analog circuits,
+and the recorded sound contains a certain DC-offset.  This is no bug
+of the driver.
+
+Most of modern laptops have no analog CD-input connection.  Thus, the
+recording from CD input won't work in many cases although the driver
+provides it as the capture source.  Use CDDA instead.
+
+The automatic switching of the built-in and external mic per plugging
+is implemented on some codec models but not on every model.  Partly
+because of my laziness but mostly lack of testers.  Feel free to
+submit the improvement patch to the author.
+
+
+Direct Debugging
+~~~~~~~~~~~~~~~~
+If no model option gives you a better result, and you are a tough guy
+to fight against evil, try debugging via hitting the raw HD-audio
+codec verbs to the device.  Some tools are available: hda-emu and
+hda-analyzer.  The detailed description is found in the sections
+below.  You'd need to enable hwdep for using these tools.  See "Kernel
+Configuration" section.
+
+
+OTHER ISSUES
+------------
+
+Kernel Configuration
+~~~~~~~~~~~~~~~~~~~~
+In general, I recommend you to enable the sound debug option,
+`CONFIG_SND_DEBUG=y`, no matter whether you are debugging or not.
+This enables snd_printd() macro and others, and you'll get additional
+kernel messages at probing.
+
+In addition, you can enable `CONFIG_SND_DEBUG_VERBOSE=y`.  But this
+will give you far more messages.  Thus turn this on only when you are
+sure to want it.
+
+Don't forget to turn on the appropriate `CONFIG_SND_HDA_CODEC_*`
+options.  Note that each of them corresponds to the codec chip, not
+the controller chip.  Thus, even if lspci shows the Nvidia controller,
+you may need to choose the option for other vendors.  If you are
+unsure, just select all yes.
+
+`CONFIG_SND_HDA_HWDEP` is a useful option for debugging the driver.
+When this is enabled, the driver creates hardware-dependent devices
+(one per each codec), and you have a raw access to the device via
+these device files.  For example, `hwC0D2` will be created for the
+codec slot #2 of the first card (#0).  For debug-tools such as
+hda-verb and hda-analyzer, the hwdep device has to be enabled.
+Thus, it'd be better to turn this on always.
+
+`CONFIG_SND_HDA_RECONFIG` is a new option, and this depends on the
+hwdep option above.  When enabled, you'll have some sysfs files under
+the corresponding hwdep directory.  See "HD-audio reconfiguration"
+section below.
+
+`CONFIG_SND_HDA_POWER_SAVE` option enables the power-saving feature.
+See "Power-saving" section below.
+
+
+Codec Proc-File
+~~~~~~~~~~~~~~~
+The codec proc-file is a treasure-chest for debugging HD-audio.
+It shows most of useful information of each codec widget.
+
+The proc file is located in /proc/asound/card*/codec#*, one file per
+each codec slot.  You can know the codec vendor, product id and
+names, the type of each widget, capabilities and so on.
+This file, however, doesn't show the jack sensing state, so far.  This
+is because the jack-sensing might be depending on the trigger state.
+
+This file will be picked up by the debug tools, and also it can be fed
+to the emulator as the primary codec information.  See the debug tools
+section below.
+
+This proc file can be also used to check whether the generic parser is
+used.  When the generic parser is used, the vendor/product ID name
+will appear as "Realtek ID 0262", instead of "Realtek ALC262".
+
+
+HD-Audio Reconfiguration
+~~~~~~~~~~~~~~~~~~~~~~~~
+This is an experimental feature to allow you re-configure the HD-audio
+codec dynamically without reloading the driver.  The following sysfs
+files are available under each codec-hwdep device directory (e.g. 
+/sys/class/sound/hwC0D0):
+
+vendor_id::
+  Shows the 32bit codec vendor-id hex number.  You can change the
+  vendor-id value by writing to this file.
+subsystem_id::
+  Shows the 32bit codec subsystem-id hex number.  You can change the
+  subsystem-id value by writing to this file.
+revision_id::
+  Shows the 32bit codec revision-id hex number.  You can change the
+  revision-id value by writing to this file.
+afg::
+  Shows the AFG ID.  This is read-only.
+mfg::
+  Shows the MFG ID.  This is read-only.
+name::
+  Shows the codec name string.  Can be changed by writing to this
+  file.
+modelname::
+  Shows the currently set `model` option.  Can be changed by writing
+  to this file.
+init_verbs::
+  The extra verbs to execute at initialization.  You can add a verb by
+  writing to this file.  Pass tree numbers, nid, verb and parameter.
+hints::
+  Shows hint strings for codec parsers for any use.  Right now it's
+  not used.
+reconfig::
+  Triggers the codec re-configuration.  When any value is written to
+  this file, the driver re-initialize and parses the codec tree
+  again.  All the changes done by the sysfs entries above are taken
+  into account.
+clear::
+  Resets the codec, removes the mixer elements and PCM stuff of the
+  specified codec, and clear all init verbs and hints.
+
+
+Power-Saving
+~~~~~~~~~~~~
+The power-saving is a kind of auto-suspend of the device.  When the
+device is inactive for a certain time, the device is automatically
+turned off to save the power.  The time to go down is specified via
+`power_save` module option, and this option can be changed dynamically
+via sysfs.
+
+The power-saving won't work when the analog loopback is enabled on
+some codecs.  Make sure that you mute all unneeded signal routes when
+you want the power-saving.
+
+The power-saving feature might cause audible click noises at each
+power-down/up depending on the device.  Some of them might be
+solvable, but some are hard, I'm afraid.  Some distros such as
+openSUSE enables the power-saving feature automatically when the power
+cable is unplugged.  Thus, if you hear noises, suspect first the
+power-saving.  See /sys/module/snd_hda_intel/parameters/power_save to
+check the current value.  If it's non-zero, the feature is turned on.
+
+
+Development Tree
+~~~~~~~~~~~~~~~~
+The latest development codes for HD-audio are found on sound git tree:
+
+- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
+
+The master branch or for-next branches can be used as the main
+development branches in general while the HD-audio specific patches
+are committed in topic/hda branch.
+
+If you are using the latest Linus tree, it'd be better to pull the
+above GIT tree onto it.  If you are using the older kernels, an easy
+way to try the latest ALSA code is to build from the snapshot
+tarball.  There are daily tarballs and the latest snapshot tarball.
+All can be built just like normal alsa-driver release packages, that
+is, installed via the usual spells: configure, make and make
+install(-modules).  See INSTALL in the package.  The snapshot tarballs
+are found at:
+
+- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/
+
+
+Sending a Bug Report
+~~~~~~~~~~~~~~~~~~~~
+If any model or module options don't work for your device, it's time
+to send a bug report to the developers.  Give the following in your
+bug report:
+
+- Hardware vendor, product and model names
+- Kernel version (and ALSA-driver version if you built externally)
+- `alsa-info.sh` output; run with `--no-upload` option.  See the
+  section below about alsa-info
+
+If it's a regression, at best, send alsa-info outputs of both working
+and non-working kernels.  This is really helpful because we can
+compare the codec registers directly.
+
+Send a bug report either the followings:
+
+kernel-bugzilla::
+  http://bugme.linux-foundation.org/
+alsa-devel ML::
+  alsa-devel@alsa-project.org
+
+
+DEBUG TOOLS
+-----------
+
+This section describes some tools available for debugging HD-audio
+problems.
+
+alsa-info
+~~~~~~~~~
+The script `alsa-info.sh` is a very useful tool to gather the audio
+device information.  You can fetch the latest version from:
+
+- http://www.alsa-project.org/alsa-info.sh
+
+Run this script as root, and it will gather the important information
+such as the module lists, module parameters, proc file contents
+including the codec proc files, mixer outputs and the control
+elements.  As default, it will store the information onto a web server
+on alsa-project.org.  But, if you send a bug report, it'd be better to
+run with `--no-upload` option, and attach the generated file.
+
+There are some other useful options.  See `--help` option output for
+details.
+
+
+hda-verb
+~~~~~~~~
+hda-verb is a tiny program that allows you to access the HD-audio
+codec directly.  You can execute a raw HD-audio codec verb with this.
+This program accesses the hwdep device, thus you need to enable the
+kernel config `CONFIG_SND_HDA_HWDEP=y` beforehand.
+
+The hda-verb program takes four arguments: the hwdep device file, the
+widget NID, the verb and the parameter.  When you access to the codec
+on the slot 2 of the card 0, pass /dev/snd/hwC0D2 to the first
+argument, typically.  (However, the real path name depends on the
+system.)
+
+The second parameter is the widget number-id to access.  The third
+parameter can be either a hex/digit number or a string corresponding
+to a verb.  Similarly, the last parameter is the value to write, or
+can be a string for the parameter type.
+
+------------------------------------------------------------------------
+  % hda-verb /dev/snd/hwC0D0 0x12 0x701 2
+  nid = 0x12, verb = 0x701, param = 0x2
+  value = 0x0
+
+  % hda-verb /dev/snd/hwC0D0 0x0 PARAMETERS VENDOR_ID
+  nid = 0x0, verb = 0xf00, param = 0x0
+  value = 0x10ec0262
+
+  % hda-verb /dev/snd/hwC0D0 2 set_a 0xb080
+  nid = 0x2, verb = 0x300, param = 0xb080
+  value = 0x0
+------------------------------------------------------------------------
+
+Although you can issue any verbs with this program, the driver state
+won't be always updated.  For example, the volume values are usually
+cached in the driver, and thus changing the widget amp value directly
+via hda-verb won't change the mixer value.
+
+The hda-verb program is found in the ftp directory:
+
+- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/
+
+Also a git repository is available:
+
+- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-verb.git
+
+See README file in the tarball for more details about hda-verb
+program.
+
+
+hda-analyzer
+~~~~~~~~~~~~
+hda-analyzer provides a graphical interface to access the raw HD-audio
+control, based on pyGTK2 binding.  It's a more powerful version of
+hda-verb.  The program gives you an easy-to-use GUI stuff for showing
+the widget information and adjusting the amp values, as well as the
+proc-compatible output.
+
+The hda-analyzer is a part of alsa.git repository in
+alsa-project.org:
+
+- http://git.alsa-project.org/?p=alsa.git;a=tree;f=hda-analyzer
+
+
+Codecgraph
+~~~~~~~~~~
+Codecgraph is a utility program to generate a graph and visualizes the
+codec-node connection of a codec chip.  It's especially useful when
+you analyze or debug a codec without a proper datasheet.  The program
+parses the given codec proc file and converts to SVG via graphiz
+program.
+
+The tarball and GIT trees are found in the web page at:
+
+- http://helllabs.org/codecgraph/
+
+
+hda-emu
+~~~~~~~
+hda-emu is an HD-audio emulator.  The main purpose of this program is
+to debug an HD-audio codec without the real hardware.  Thus, it
+doesn't emulate the behavior with the real audio I/O, but it just
+dumps the codec register changes and the ALSA-driver internal changes
+at probing and operating the HD-audio driver.
+
+The program requires a codec proc-file to simulate.  Get a proc file
+for the target codec beforehand, or pick up an example codec from the
+codec proc collections in the tarball.  Then, run the program with the
+proc file, and the hda-emu program will start parsing the codec file
+and simulates the HD-audio driver:
+
+------------------------------------------------------------------------
+  % hda-emu codecs/stac9200-dell-d820-laptop
+  # Parsing..
+  hda_codec: Unknown model for STAC9200, using BIOS defaults
+  hda_codec: pin nid 08 bios pin config 40c003fa
+  ....
+------------------------------------------------------------------------
+
+The program gives you only a very dumb command-line interface.  You
+can get a proc-file dump at the current state, get a list of control
+(mixer) elements, set/get the control element value, simulate the PCM
+operation, the jack plugging simulation, etc.
+
+The package is found in:
+
+- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/
+
+A git repository is available:
+
+- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-emu.git
+
+See README file in the tarball for more details about hda-emu
+program.

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

@@ -153,6 +153,16 @@ card*/codec#*
 	Shows the general codec information and the attribute of each
 	widget node.
 
+card*/eld#*
+	Available for HDMI or DisplayPort interfaces.
+	Shows ELD(EDID Like Data) info retrieved from the attached HDMI sink,
+	and describes its audio capabilities and configurations.
+
+	Some ELD fields may be modified by doing `echo name hex_value > eld#*`.
+	Only do this if you are sure the HDMI sink provided value is wrong.
+	And if that makes your HDMI audio work, please report to us so that we
+	can fix it in future kernel releases.
+
 
 Sequencer Information
 ---------------------

+ 1 - 0
include/linux/input.h

@@ -659,6 +659,7 @@ struct input_absinfo {
 #define SW_RADIO		SW_RFKILL_ALL	/* deprecated */
 #define SW_MICROPHONE_INSERT	0x04  /* set = inserted */
 #define SW_DOCK			0x05  /* set = plugged into dock */
+#define SW_LINEOUT_INSERT	0x06  /* set = inserted */
 #define SW_MAX			0x0f
 #define SW_CNT			(SW_MAX+1)
 

+ 1 - 0
include/sound/jack.h

@@ -35,6 +35,7 @@ enum snd_jack_types {
 	SND_JACK_HEADPHONE	= 0x0001,
 	SND_JACK_MICROPHONE	= 0x0002,
 	SND_JACK_HEADSET	= SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
+	SND_JACK_LINEOUT	= 0x0004,
 };
 
 struct snd_jack {

+ 8 - 1
sound/core/jack.c

@@ -34,6 +34,7 @@ static int snd_jack_dev_free(struct snd_device *device)
 	else
 		input_free_device(jack->input_dev);
 
+	kfree(jack->id);
 	kfree(jack);
 
 	return 0;
@@ -87,7 +88,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
 	if (jack == NULL)
 		return -ENOMEM;
 
-	jack->id = id;
+	jack->id = kstrdup(id, GFP_KERNEL);
 
 	jack->input_dev = input_allocate_device();
 	if (jack->input_dev == NULL) {
@@ -102,6 +103,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
 	if (type & SND_JACK_HEADPHONE)
 		input_set_capability(jack->input_dev, EV_SW,
 				     SW_HEADPHONE_INSERT);
+	if (type & SND_JACK_LINEOUT)
+		input_set_capability(jack->input_dev, EV_SW,
+				     SW_LINEOUT_INSERT);
 	if (type & SND_JACK_MICROPHONE)
 		input_set_capability(jack->input_dev, EV_SW,
 				     SW_MICROPHONE_INSERT);
@@ -153,6 +157,9 @@ void snd_jack_report(struct snd_jack *jack, int status)
 	if (jack->type & SND_JACK_HEADPHONE)
 		input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT,
 				    status & SND_JACK_HEADPHONE);
+	if (jack->type & SND_JACK_LINEOUT)
+		input_report_switch(jack->input_dev, SW_LINEOUT_INSERT,
+				    status & SND_JACK_LINEOUT);
 	if (jack->type & SND_JACK_MICROPHONE)
 		input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT,
 				    status & SND_JACK_MICROPHONE);

+ 1 - 123
sound/pci/Kconfig

@@ -497,129 +497,7 @@ config SND_FM801_TEA575X
 	depends on SND_FM801_TEA575X_BOOL
 	default SND_FM801
 
-config SND_HDA_INTEL
-	tristate "Intel HD Audio"
-	select SND_PCM
-	select SND_VMASTER
-	help
-	  Say Y here to include support for Intel "High Definition
-	  Audio" (Azalia) motherboard devices.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-hda-intel.
-
-config SND_HDA_HWDEP
-	bool "Build hwdep interface for HD-audio driver"
-	depends on SND_HDA_INTEL
-	select SND_HWDEP
-	help
-	  Say Y here to build a hwdep interface for HD-audio driver.
-	  This interface can be used for out-of-band communication
-	  with codecs for debugging purposes.
-
-config SND_HDA_INPUT_BEEP
-	bool "Support digital beep via input layer"
-	depends on SND_HDA_INTEL
-	depends on INPUT=y || INPUT=SND_HDA_INTEL
-	help
-	  Say Y here to build a digital beep interface for HD-audio
-	  driver. This interface is used to generate digital beeps.
-
-config SND_HDA_CODEC_REALTEK
-	bool "Build Realtek HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include Realtek HD-audio codec support in
-	  snd-hda-intel driver, such as ALC880.
-
-config SND_HDA_CODEC_ANALOG
-	bool "Build Analog Device HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include Analog Device HD-audio codec support in
-	  snd-hda-intel driver, such as AD1986A.
-
-config SND_HDA_CODEC_SIGMATEL
-	bool "Build IDT/Sigmatel HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include IDT (Sigmatel) HD-audio codec support in
-	  snd-hda-intel driver, such as STAC9200.
-
-config SND_HDA_CODEC_VIA
-	bool "Build VIA HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include VIA HD-audio codec support in
-	  snd-hda-intel driver, such as VT1708.
-
-config SND_HDA_CODEC_ATIHDMI
-	bool "Build ATI HDMI HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include ATI HDMI HD-audio codec support in
-	  snd-hda-intel driver, such as ATI RS600 HDMI.
-
-config SND_HDA_CODEC_NVHDMI
-	bool "Build NVIDIA HDMI HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include NVIDIA HDMI HD-audio codec support in
-	  snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
-
-config SND_HDA_CODEC_CONEXANT
-	bool "Build Conexant HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include Conexant HD-audio codec support in
-	  snd-hda-intel driver, such as CX20549.
-
-config SND_HDA_CODEC_CMEDIA
-	bool "Build C-Media HD-audio codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include C-Media HD-audio codec support in
-	  snd-hda-intel driver, such as CMI9880.
-
-config SND_HDA_CODEC_SI3054
-	bool "Build Silicon Labs 3054 HD-modem codec support"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to include Silicon Labs 3054 HD-modem codec
-	  (and compatibles) support in snd-hda-intel driver.
-
-config SND_HDA_GENERIC
-	bool "Enable generic HD-audio codec parser"
-	depends on SND_HDA_INTEL
-	default y
-	help
-	  Say Y here to enable the generic HD-audio codec parser
-	  in snd-hda-intel driver.
-
-config SND_HDA_POWER_SAVE
-	bool "Aggressive power-saving on HD-audio"
-	depends on SND_HDA_INTEL && EXPERIMENTAL
-	help
-	  Say Y here to enable more aggressive power-saving mode on
-	  HD-audio driver.  The power-saving timeout can be configured
-	  via power_save option or over sysfs on-the-fly.
-
-config SND_HDA_POWER_SAVE_DEFAULT
-	int "Default time-out for HD-audio power-save mode"
-	depends on SND_HDA_POWER_SAVE
-	default 0
-	help
-	  The default time-out value in seconds for HD-audio automatic
-	  power-save mode.  0 means to disable the power-save mode.
+source "sound/pci/hda/Kconfig"
 
 config SND_HDSP
 	tristate "RME Hammerfall DSP Audio"

+ 188 - 0
sound/pci/hda/Kconfig

@@ -0,0 +1,188 @@
+menuconfig SND_HDA_INTEL
+	tristate "Intel HD Audio"
+	select SND_PCM
+	select SND_VMASTER
+	select SND_JACK if INPUT=y || INPUT=SND
+	help
+	  Say Y here to include support for Intel "High Definition
+	  Audio" (Azalia) and its compatible devices.
+
+	  This option enables the HD-audio controller.  Don't forget
+	  to choose the appropriate codec options below.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-hda-intel.
+
+if SND_HDA_INTEL
+
+config SND_HDA_HWDEP
+	bool "Build hwdep interface for HD-audio driver"
+	select SND_HWDEP
+	help
+	  Say Y here to build a hwdep interface for HD-audio driver.
+	  This interface can be used for out-of-band communication
+	  with codecs for debugging purposes.
+
+config SND_HDA_RECONFIG
+	bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)"
+	depends on SND_HDA_HWDEP && EXPERIMENTAL
+	help
+	  Say Y here to enable the HD-audio codec re-configuration feature.
+	  This adds the sysfs interfaces to allow user to clear the whole
+	  codec configuration, change the codec setup, add extra verbs,
+	  and re-configure the codec dynamically.
+
+config SND_HDA_INPUT_BEEP
+	bool "Support digital beep via input layer"
+	depends on INPUT=y || INPUT=SND_HDA_INTEL
+	help
+	  Say Y here to build a digital beep interface for HD-audio
+	  driver. This interface is used to generate digital beeps.
+
+config SND_HDA_CODEC_REALTEK
+	bool "Build Realtek HD-audio codec support"
+	default y
+	help
+	  Say Y here to include Realtek HD-audio codec support in
+	  snd-hda-intel driver, such as ALC880.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-realtek.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_ANALOG
+	bool "Build Analog Device HD-audio codec support"
+	default y
+	help
+	  Say Y here to include Analog Device HD-audio codec support in
+	  snd-hda-intel driver, such as AD1986A.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-analog.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_SIGMATEL
+	bool "Build IDT/Sigmatel HD-audio codec support"
+	default y
+	help
+	  Say Y here to include IDT (Sigmatel) HD-audio codec support in
+	  snd-hda-intel driver, such as STAC9200.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-idt.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_VIA
+	bool "Build VIA HD-audio codec support"
+	default y
+	help
+	  Say Y here to include VIA HD-audio codec support in
+	  snd-hda-intel driver, such as VT1708.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-via.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_ATIHDMI
+	bool "Build ATI HDMI HD-audio codec support"
+	default y
+	help
+	  Say Y here to include ATI HDMI HD-audio codec support in
+	  snd-hda-intel driver, such as ATI RS600 HDMI.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-atihdmi.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_NVHDMI
+	bool "Build NVIDIA HDMI HD-audio codec support"
+	default y
+	help
+	  Say Y here to include NVIDIA HDMI HD-audio codec support in
+	  snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-nvhdmi.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_INTELHDMI
+	bool "Build INTEL HDMI HD-audio codec support"
+	default y
+	help
+	  Say Y here to include INTEL HDMI HD-audio codec support in
+	  snd-hda-intel driver, such as Eaglelake integrated HDMI.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-intelhdmi.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_ELD
+	def_bool y
+	depends on SND_HDA_CODEC_INTELHDMI
+
+config SND_HDA_CODEC_CONEXANT
+	bool "Build Conexant HD-audio codec support"
+	default y
+	help
+	  Say Y here to include Conexant HD-audio codec support in
+	  snd-hda-intel driver, such as CX20549.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-conexant.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_CMEDIA
+	bool "Build C-Media HD-audio codec support"
+	default y
+	help
+	  Say Y here to include C-Media HD-audio codec support in
+	  snd-hda-intel driver, such as CMI9880.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-cmedia.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_CODEC_SI3054
+	bool "Build Silicon Labs 3054 HD-modem codec support"
+	default y
+	help
+	  Say Y here to include Silicon Labs 3054 HD-modem codec
+	  (and compatibles) support in snd-hda-intel driver.
+
+	  When the HD-audio driver is built as a module, the codec
+	  support code is also built as another module,
+	  snd-hda-codec-si3054.
+	  This module is automatically loaded at probing.
+
+config SND_HDA_GENERIC
+	bool "Enable generic HD-audio codec parser"
+	default y
+	help
+	  Say Y here to enable the generic HD-audio codec parser
+	  in snd-hda-intel driver.
+
+config SND_HDA_POWER_SAVE
+	bool "Aggressive power-saving on HD-audio"
+	help
+	  Say Y here to enable more aggressive power-saving mode on
+	  HD-audio driver.  The power-saving timeout can be configured
+	  via power_save option or over sysfs on-the-fly.
+
+config SND_HDA_POWER_SAVE_DEFAULT
+	int "Default time-out for HD-audio power-save mode"
+	depends on SND_HDA_POWER_SAVE
+	default 0
+	help
+	  The default time-out value in seconds for HD-audio automatic
+	  power-save mode.  0 means to disable the power-save mode.
+
+endif

+ 57 - 18
sound/pci/hda/Makefile

@@ -1,20 +1,59 @@
-snd-hda-intel-y := hda_intel.o
-# since snd-hda-intel is the only driver using hda-codec,
-# merge it into a single module although it was originally
-# designed to be individual modules
-snd-hda-intel-y += hda_codec.o
-snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
-snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
-snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
-snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += patch_sigmatel.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o
-snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o
+snd-hda-intel-objs := hda_intel.o
 
+snd-hda-codec-y := hda_codec.o
+snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
+snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
+# snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
+snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
+snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
+
+snd-hda-codec-realtek-objs :=	patch_realtek.o
+snd-hda-codec-cmedia-objs :=	patch_cmedia.o
+snd-hda-codec-analog-objs :=	patch_analog.o
+snd-hda-codec-idt-objs :=	patch_sigmatel.o
+snd-hda-codec-si3054-objs :=	patch_si3054.o
+snd-hda-codec-atihdmi-objs :=	patch_atihdmi.o
+snd-hda-codec-conexant-objs :=	patch_conexant.o
+snd-hda-codec-via-objs :=	patch_via.o
+snd-hda-codec-nvhdmi-objs :=	patch_nvhdmi.o
+snd-hda-codec-intelhdmi-objs :=	patch_intelhdmi.o hda_eld.o
+
+# common driver
+obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
+
+# codec drivers (note: CONFIG_SND_HDA_CODEC_XXX are booleans)
+ifdef CONFIG_SND_HDA_CODEC_REALTEK
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-realtek.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_CMEDIA
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cmedia.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_ANALOG
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-analog.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_SIGMATEL
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-idt.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_SI3054
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_CONEXANT
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_VIA
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_NVHDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o
+endif
+ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o
+endif
+
+# this must be the last entry after codec drivers;
+# otherwise the codec patches won't be hooked before the PCI probe
+# when built in kernel
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o

+ 2 - 0
sound/pci/hda/hda_beep.c

@@ -128,6 +128,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
 	INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
 	return 0;
 }
+EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device);
 
 void snd_hda_detach_beep_device(struct hda_codec *codec)
 {
@@ -140,3 +141,4 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
 		kfree(beep);
 	}
 }
+EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);

File diff suppressed because it is too large
+ 359 - 122
sound/pci/hda/hda_codec.c


+ 92 - 15
sound/pci/hda/hda_codec.h

@@ -519,6 +519,36 @@ enum {
 /* max. codec address */
 #define HDA_MAX_CODEC_ADDRESS	0x0f
 
+/*
+ * generic arrays
+ */
+struct snd_array {
+	unsigned int used;
+	unsigned int alloced;
+	unsigned int elem_size;
+	unsigned int alloc_align;
+	void *list;
+};
+
+void *snd_array_new(struct snd_array *array);
+void snd_array_free(struct snd_array *array);
+static inline void snd_array_init(struct snd_array *array, unsigned int size,
+				  unsigned int align)
+{
+	array->elem_size = size;
+	array->alloc_align = align;
+}
+
+static inline void *snd_array_elem(struct snd_array *array, unsigned int idx)
+{
+	return array->list + idx * array->elem_size;
+}
+
+static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
+{
+	return (unsigned long)(ptr - array->list) / array->elem_size;
+}
+
 /*
  * Structures
  */
@@ -536,15 +566,17 @@ typedef u16 hda_nid_t;
 /* bus operators */
 struct hda_bus_ops {
 	/* send a single command */
-	int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct,
-		       unsigned int verb, unsigned int parm);
+	int (*command)(struct hda_bus *bus, unsigned int cmd);
 	/* get a response from the last command */
-	unsigned int (*get_response)(struct hda_codec *codec);
+	unsigned int (*get_response)(struct hda_bus *bus);
 	/* free the private data */
 	void (*private_free)(struct hda_bus *);
+	/* attach a PCM stream */
+	int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec,
+			  struct hda_pcm *pcm);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	/* notify power-up/down from codec to controller */
-	void (*pm_notify)(struct hda_codec *codec);
+	void (*pm_notify)(struct hda_bus *bus);
 #endif
 };
 
@@ -553,6 +585,7 @@ struct hda_bus_template {
 	void *private_data;
 	struct pci_dev *pci;
 	const char *modelname;
+	int *power_save;
 	struct hda_bus_ops ops;
 };
 
@@ -569,6 +602,7 @@ struct hda_bus {
 	void *private_data;
 	struct pci_dev *pci;
 	const char *modelname;
+	int *power_save;
 	struct hda_bus_ops ops;
 
 	/* codec linked list */
@@ -581,10 +615,12 @@ struct hda_bus {
 	/* unsolicited event queue */
 	struct hda_bus_unsolicited *unsol;
 
-	struct snd_info_entry *proc;
+	/* assigned PCMs */
+	DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
 
 	/* misc op flags */
 	unsigned int needs_damn_long_delay :1;
+	unsigned int shutdown :1;	/* being unloaded */
 };
 
 /*
@@ -604,6 +640,16 @@ struct hda_codec_preset {
 	int (*patch)(struct hda_codec *codec);
 };
 	
+struct hda_codec_preset_list {
+	const struct hda_codec_preset *preset;
+	struct module *owner;
+	struct list_head list;
+};
+
+/* initial hook */
+int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset);
+int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset);
+
 /* ops set by the preset patch */
 struct hda_codec_ops {
 	int (*build_controls)(struct hda_codec *codec);
@@ -635,10 +681,7 @@ struct hda_amp_info {
 
 struct hda_cache_rec {
 	u16 hash[64];			/* hash table for index */
-	unsigned int num_entries;	/* number of assigned entries */
-	unsigned int size;		/* allocated size */
-	unsigned int record_size;	/* record size (including header) */
-	void *buffer;			/* hash table entries */
+	struct snd_array buf;		/* record entries */
 };
 
 /* PCM callbacks */
@@ -680,7 +723,8 @@ struct hda_pcm {
 	char *name;
 	struct hda_pcm_stream stream[2];
 	unsigned int pcm_type;	/* HDA_PCM_TYPE_XXX */
-	int device;	/* assigned device number */
+	int device;		/* device number to assign */
+	struct snd_pcm *pcm;	/* assigned PCM instance */
 };
 
 /* codec information */
@@ -699,6 +743,9 @@ struct hda_codec {
 
 	/* detected preset */
 	const struct hda_codec_preset *preset;
+	struct module *owner;
+	const char *name;	/* codec name */
+	const char *modelname;	/* model name for preset */
 
 	/* set by patch */
 	struct hda_codec_ops patch_ops;
@@ -718,6 +765,8 @@ struct hda_codec {
 	hda_nid_t start_nid;
 	u32 *wcaps;
 
+	struct snd_array mixers;	/* list of assigned mixer elements */
+
 	struct hda_cache_rec amp_cache;	/* cache for amp access */
 	struct hda_cache_rec cmd_cache;	/* cache for other commands */
 
@@ -727,7 +776,11 @@ struct hda_codec {
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
 	hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
 
+#ifdef CONFIG_SND_HDA_HWDEP
 	struct snd_hwdep *hwdep;	/* assigned hwdep device */
+	struct snd_array init_verbs;	/* additional init verbs */
+	struct snd_array hints;		/* additional hints */
+#endif
 
 	/* misc flags */
 	unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
@@ -740,6 +793,10 @@ struct hda_codec {
 	int power_count;	/* current (global) power refcount */
 	struct delayed_work power_work; /* delayed task for powerdown */
 #endif
+
+	/* codec-specific additional proc output */
+	void (*proc_widget_hook)(struct snd_info_buffer *buffer,
+				 struct hda_codec *codec, hda_nid_t nid);
 };
 
 /* direction */
@@ -754,7 +811,7 @@ enum {
 int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
 		    struct hda_bus **busp);
 int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
-		      struct hda_codec **codecp);
+		      int do_init, struct hda_codec **codecp);
 
 /*
  * low level functions
@@ -799,11 +856,13 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec);
  * Mixer
  */
 int snd_hda_build_controls(struct hda_bus *bus);
+int snd_hda_codec_build_controls(struct hda_codec *codec);
 
 /*
  * PCM
  */
 int snd_hda_build_pcms(struct hda_bus *bus);
+int snd_hda_codec_build_pcms(struct hda_codec *codec);
 void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 				u32 stream_tag,
 				int channel_id, int format);
@@ -812,8 +871,6 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
 					unsigned int channels,
 					unsigned int format,
 					unsigned int maxbps);
-int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
-				u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
 int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
 				unsigned int format);
 
@@ -830,6 +887,13 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state);
 int snd_hda_resume(struct hda_bus *bus);
 #endif
 
+/*
+ * get widget information
+ */
+const char *snd_hda_get_jack_connectivity(u32 cfg);
+const char *snd_hda_get_jack_type(u32 cfg);
+const char *snd_hda_get_jack_location(u32 cfg);
+
 /*
  * power saving
  */
@@ -837,12 +901,25 @@ int snd_hda_resume(struct hda_bus *bus);
 void snd_hda_power_up(struct hda_codec *codec);
 void snd_hda_power_down(struct hda_codec *codec);
 #define snd_hda_codec_needs_resume(codec) codec->power_count
-int snd_hda_codecs_inuse(struct hda_bus *bus);
 #else
 static inline void snd_hda_power_up(struct hda_codec *codec) {}
 static inline void snd_hda_power_down(struct hda_codec *codec) {}
 #define snd_hda_codec_needs_resume(codec) 1
-#define snd_hda_codecs_inuse(bus) 1
+#endif
+
+/*
+ * Codec modularization
+ */
+
+/* Export symbols only for communication with codec drivers;
+ * When built in kernel, all HD-audio drivers are supposed to be statically
+ * linked to the kernel.  Thus, the symbols don't have to (or shouldn't) be
+ * exported unless it's built as a module.
+ */
+#ifdef MODULE
+#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym)
+#else
+#define EXPORT_SYMBOL_HDA(sym)
 #endif
 
 #endif /* __SOUND_HDA_CODEC_H */

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

@@ -0,0 +1,590 @@
+/*
+ * Generic routines and proc interface for ELD(EDID Like Data) information
+ *
+ * Copyright(c) 2008 Intel Corporation.
+ *
+ * Authors:
+ * 		Wu Fengguang <wfg@linux.intel.com>
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <sound/core.h>
+#include <asm/unaligned.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+enum eld_versions {
+	ELD_VER_CEA_861D	= 2,
+	ELD_VER_PARTIAL		= 31,
+};
+
+enum cea_edid_versions {
+	CEA_EDID_VER_NONE	= 0,
+	CEA_EDID_VER_CEA861	= 1,
+	CEA_EDID_VER_CEA861A	= 2,
+	CEA_EDID_VER_CEA861BCD	= 3,
+	CEA_EDID_VER_RESERVED	= 4,
+};
+
+static char *cea_speaker_allocation_names[] = {
+	/*  0 */ "FL/FR",
+	/*  1 */ "LFE",
+	/*  2 */ "FC",
+	/*  3 */ "RL/RR",
+	/*  4 */ "RC",
+	/*  5 */ "FLC/FRC",
+	/*  6 */ "RLC/RRC",
+	/*  7 */ "FLW/FRW",
+	/*  8 */ "FLH/FRH",
+	/*  9 */ "TC",
+	/* 10 */ "FCH",
+};
+
+static char *eld_connection_type_names[4] = {
+	"HDMI",
+	"DisplayPort",
+	"2-reserved",
+	"3-reserved"
+};
+
+enum cea_audio_coding_types {
+	AUDIO_CODING_TYPE_REF_STREAM_HEADER	=  0,
+	AUDIO_CODING_TYPE_LPCM			=  1,
+	AUDIO_CODING_TYPE_AC3			=  2,
+	AUDIO_CODING_TYPE_MPEG1			=  3,
+	AUDIO_CODING_TYPE_MP3			=  4,
+	AUDIO_CODING_TYPE_MPEG2			=  5,
+	AUDIO_CODING_TYPE_AACLC			=  6,
+	AUDIO_CODING_TYPE_DTS			=  7,
+	AUDIO_CODING_TYPE_ATRAC			=  8,
+	AUDIO_CODING_TYPE_SACD			=  9,
+	AUDIO_CODING_TYPE_EAC3			= 10,
+	AUDIO_CODING_TYPE_DTS_HD		= 11,
+	AUDIO_CODING_TYPE_MLP			= 12,
+	AUDIO_CODING_TYPE_DST			= 13,
+	AUDIO_CODING_TYPE_WMAPRO		= 14,
+	AUDIO_CODING_TYPE_REF_CXT		= 15,
+	/* also include valid xtypes below */
+	AUDIO_CODING_TYPE_HE_AAC		= 15,
+	AUDIO_CODING_TYPE_HE_AAC2		= 16,
+	AUDIO_CODING_TYPE_MPEG_SURROUND		= 17,
+};
+
+enum cea_audio_coding_xtypes {
+	AUDIO_CODING_XTYPE_HE_REF_CT		= 0,
+	AUDIO_CODING_XTYPE_HE_AAC		= 1,
+	AUDIO_CODING_XTYPE_HE_AAC2		= 2,
+	AUDIO_CODING_XTYPE_MPEG_SURROUND	= 3,
+	AUDIO_CODING_XTYPE_FIRST_RESERVED	= 4,
+};
+
+static char *cea_audio_coding_type_names[] = {
+	/*  0 */ "undefined",
+	/*  1 */ "LPCM",
+	/*  2 */ "AC-3",
+	/*  3 */ "MPEG1",
+	/*  4 */ "MP3",
+	/*  5 */ "MPEG2",
+	/*  6 */ "AAC-LC",
+	/*  7 */ "DTS",
+	/*  8 */ "ATRAC",
+	/*  9 */ "DSD (One Bit Audio)",
+	/* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)",
+	/* 11 */ "DTS-HD",
+	/* 12 */ "MLP (Dolby TrueHD)",
+	/* 13 */ "DST",
+	/* 14 */ "WMAPro",
+	/* 15 */ "HE-AAC",
+	/* 16 */ "HE-AACv2",
+	/* 17 */ "MPEG Surround",
+};
+
+/*
+ * The following two lists are shared between
+ * 	- HDMI audio InfoFrame (source to sink)
+ * 	- CEA E-EDID Extension (sink to source)
+ */
+
+/*
+ * SS1:SS0 index => sample size
+ */
+static int cea_sample_sizes[4] = {
+	0,	 		/* 0: Refer to Stream Header */
+	AC_SUPPCM_BITS_16,	/* 1: 16 bits */
+	AC_SUPPCM_BITS_20,	/* 2: 20 bits */
+	AC_SUPPCM_BITS_24,	/* 3: 24 bits */
+};
+
+/*
+ * SF2:SF1:SF0 index => sampling frequency
+ */
+static int cea_sampling_frequencies[8] = {
+	0,			/* 0: Refer to Stream Header */
+	SNDRV_PCM_RATE_32000,	/* 1:  32000Hz */
+	SNDRV_PCM_RATE_44100,	/* 2:  44100Hz */
+	SNDRV_PCM_RATE_48000,	/* 3:  48000Hz */
+	SNDRV_PCM_RATE_88200,	/* 4:  88200Hz */
+	SNDRV_PCM_RATE_96000,	/* 5:  96000Hz */
+	SNDRV_PCM_RATE_176400,	/* 6: 176400Hz */
+	SNDRV_PCM_RATE_192000,	/* 7: 192000Hz */
+};
+
+static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid,
+					int byte_index)
+{
+	unsigned int val;
+
+	val = snd_hda_codec_read(codec, nid, 0,
+					AC_VERB_GET_HDMI_ELDD, byte_index);
+
+#ifdef BE_PARANOID
+	printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
+#endif
+
+	if ((val & AC_ELDD_ELD_VALID) == 0) {
+		snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n",
+								byte_index);
+		val = 0;
+	}
+
+	return val & AC_ELDD_ELD_DATA;
+}
+
+#define GRAB_BITS(buf, byte, lowbit, bits) 		\
+({							\
+	BUILD_BUG_ON(lowbit > 7);			\
+	BUILD_BUG_ON(bits > 8);				\
+	BUILD_BUG_ON(bits <= 0);			\
+							\
+	(buf[byte] >> (lowbit)) & ((1 << (bits)) - 1);	\
+})
+
+static void hdmi_update_short_audio_desc(struct cea_sad *a,
+					 const unsigned char *buf)
+{
+	int i;
+	int val;
+
+	val = GRAB_BITS(buf, 1, 0, 7);
+	a->rates = 0;
+	for (i = 0; i < 7; i++)
+		if (val & (1 << i))
+			a->rates |= cea_sampling_frequencies[i + 1];
+
+	a->channels = GRAB_BITS(buf, 0, 0, 3);
+	a->channels++;
+
+	a->format = GRAB_BITS(buf, 0, 3, 4);
+	switch (a->format) {
+	case AUDIO_CODING_TYPE_REF_STREAM_HEADER:
+		snd_printd(KERN_INFO
+				"HDMI: audio coding type 0 not expected\n");
+		break;
+
+	case AUDIO_CODING_TYPE_LPCM:
+		val = GRAB_BITS(buf, 2, 0, 3);
+		a->sample_bits = 0;
+		for (i = 0; i < 3; i++)
+			if (val & (1 << i))
+				a->sample_bits |= cea_sample_sizes[i + 1];
+		break;
+
+	case AUDIO_CODING_TYPE_AC3:
+	case AUDIO_CODING_TYPE_MPEG1:
+	case AUDIO_CODING_TYPE_MP3:
+	case AUDIO_CODING_TYPE_MPEG2:
+	case AUDIO_CODING_TYPE_AACLC:
+	case AUDIO_CODING_TYPE_DTS:
+	case AUDIO_CODING_TYPE_ATRAC:
+		a->max_bitrate = GRAB_BITS(buf, 2, 0, 8);
+		a->max_bitrate *= 8000;
+		break;
+
+	case AUDIO_CODING_TYPE_SACD:
+		break;
+
+	case AUDIO_CODING_TYPE_EAC3:
+		break;
+
+	case AUDIO_CODING_TYPE_DTS_HD:
+		break;
+
+	case AUDIO_CODING_TYPE_MLP:
+		break;
+
+	case AUDIO_CODING_TYPE_DST:
+		break;
+
+	case AUDIO_CODING_TYPE_WMAPRO:
+		a->profile = GRAB_BITS(buf, 2, 0, 3);
+		break;
+
+	case AUDIO_CODING_TYPE_REF_CXT:
+		a->format = GRAB_BITS(buf, 2, 3, 5);
+		if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT ||
+		    a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) {
+			snd_printd(KERN_INFO
+				"HDMI: audio coding xtype %d not expected\n",
+				a->format);
+			a->format = 0;
+		} else
+			a->format += AUDIO_CODING_TYPE_HE_AAC -
+				     AUDIO_CODING_XTYPE_HE_AAC;
+		break;
+	}
+}
+
+/*
+ * Be careful, ELD buf could be totally rubbish!
+ */
+static int hdmi_update_eld(struct hdmi_eld *e,
+			   const unsigned char *buf, int size)
+{
+	int mnl;
+	int i;
+
+	e->eld_ver = GRAB_BITS(buf, 0, 3, 5);
+	if (e->eld_ver != ELD_VER_CEA_861D &&
+	    e->eld_ver != ELD_VER_PARTIAL) {
+		snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n",
+								e->eld_ver);
+		goto out_fail;
+	}
+
+	e->eld_size = size;
+	e->baseline_len = GRAB_BITS(buf, 2, 0, 8);
+	mnl		= GRAB_BITS(buf, 4, 0, 5);
+	e->cea_edid_ver	= GRAB_BITS(buf, 4, 5, 3);
+
+	e->support_hdcp	= GRAB_BITS(buf, 5, 0, 1);
+	e->support_ai	= GRAB_BITS(buf, 5, 1, 1);
+	e->conn_type	= GRAB_BITS(buf, 5, 2, 2);
+	e->sad_count	= GRAB_BITS(buf, 5, 4, 4);
+
+	e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2;
+	e->spk_alloc	= GRAB_BITS(buf, 7, 0, 7);
+
+	e->port_id	  = get_unaligned_le64(buf + 8);
+
+	/* not specified, but the spec's tendency is little endian */
+	e->manufacture_id = get_unaligned_le16(buf + 16);
+	e->product_id	  = get_unaligned_le16(buf + 18);
+
+	if (mnl > ELD_MAX_MNL) {
+		snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl);
+		goto out_fail;
+	} else if (ELD_FIXED_BYTES + mnl > size) {
+		snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl);
+		goto out_fail;
+	} else
+		strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl);
+
+	for (i = 0; i < e->sad_count; i++) {
+		if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) {
+			snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i);
+			goto out_fail;
+		}
+		hdmi_update_short_audio_desc(e->sad + i,
+					buf + ELD_FIXED_BYTES + mnl + 3 * i);
+	}
+
+	return 0;
+
+out_fail:
+	e->eld_ver = 0;
+	return -EINVAL;
+}
+
+static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid)
+{
+	return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0);
+}
+
+static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid)
+{
+	int eldv;
+	int present;
+
+	present = hdmi_present_sense(codec, nid);
+	eldv    = (present & AC_PINSENSE_ELDV);
+	present = (present & AC_PINSENSE_PRESENCE);
+
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+	printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n",
+			!!present, !!eldv);
+#endif
+
+	return eldv && present;
+}
+
+int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
+{
+	return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
+						 AC_DIPSIZE_ELD_BUF);
+}
+
+int snd_hdmi_get_eld(struct hdmi_eld *eld,
+		     struct hda_codec *codec, hda_nid_t nid)
+{
+	int i;
+	int ret;
+	int size;
+	unsigned char *buf;
+
+	if (!hdmi_eld_valid(codec, nid))
+		return -ENOENT;
+
+	size = snd_hdmi_get_eld_size(codec, nid);
+	if (size == 0) {
+		/* wfg: workaround for ASUS P5E-VM HDMI board */
+		snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n");
+		size = 128;
+	}
+	if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) {
+		snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size);
+		return -ERANGE;
+	}
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < size; i++)
+		buf[i] = hdmi_get_eld_byte(codec, nid, i);
+
+	ret = hdmi_update_eld(eld, buf, size);
+
+	kfree(buf);
+	return ret;
+}
+
+static void hdmi_show_short_audio_desc(struct cea_sad *a)
+{
+	char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
+	char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits =";
+
+	if (!a->format)
+		return;
+
+	snd_print_pcm_rates(a->rates, buf, sizeof(buf));
+
+	if (a->format == AUDIO_CODING_TYPE_LPCM)
+		snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8));
+	else if (a->max_bitrate)
+		snprintf(buf2, sizeof(buf2),
+				", max bitrate = %d", a->max_bitrate);
+	else
+		buf2[0] = '\0';
+
+	printk(KERN_INFO "HDMI: supports coding type %s:"
+			" channels = %d, rates =%s%s\n",
+			cea_audio_coding_type_names[a->format],
+			a->channels,
+			buf,
+			buf2);
+}
+
+void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
+{
+	int i, j;
+
+	for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) {
+		if (spk_alloc & (1 << i))
+			j += snprintf(buf + j, buflen - j,  " %s",
+					cea_speaker_allocation_names[i]);
+	}
+	buf[j] = '\0';	/* necessary when j == 0 */
+}
+
+void snd_hdmi_show_eld(struct hdmi_eld *e)
+{
+	int i;
+
+	printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n",
+			e->monitor_name,
+			eld_connection_type_names[e->conn_type]);
+
+	if (e->spk_alloc) {
+		char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+		snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
+		printk(KERN_INFO "HDMI: available speakers:%s\n", buf);
+	}
+
+	for (i = 0; i < e->sad_count; i++)
+		hdmi_show_short_audio_desc(e->sad + i);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void hdmi_print_sad_info(int i, struct cea_sad *a,
+				struct snd_info_buffer *buffer)
+{
+	char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
+
+	snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n",
+			i, a->format, cea_audio_coding_type_names[a->format]);
+	snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels);
+
+	snd_print_pcm_rates(a->rates, buf, sizeof(buf));
+	snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf);
+
+	if (a->format == AUDIO_CODING_TYPE_LPCM) {
+		snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf));
+		snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n",
+							i, a->sample_bits, buf);
+	}
+
+	if (a->max_bitrate)
+		snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n",
+							i, a->max_bitrate);
+
+	if (a->profile)
+		snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile);
+}
+
+static void hdmi_print_eld_info(struct snd_info_entry *entry,
+				struct snd_info_buffer *buffer)
+{
+	struct hdmi_eld *e = entry->private_data;
+	char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+	int i;
+	static char *eld_versoin_names[32] = {
+		"reserved",
+		"reserved",
+		"CEA-861D or below",
+		[3 ... 30] = "reserved",
+		[31] = "partial"
+	};
+	static char *cea_edid_version_names[8] = {
+		"no CEA EDID Timing Extension block present",
+		"CEA-861",
+		"CEA-861-A",
+		"CEA-861-B, C or D",
+		[4 ... 7] = "reserved"
+	};
+
+	snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
+	snd_iprintf(buffer, "connection_type\t\t%s\n",
+				eld_connection_type_names[e->conn_type]);
+	snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver,
+					eld_versoin_names[e->eld_ver]);
+	snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver,
+				cea_edid_version_names[e->cea_edid_ver]);
+	snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id);
+	snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id);
+	snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id);
+	snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp);
+	snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai);
+	snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay);
+
+	snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
+	snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf);
+
+	snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count);
+
+	for (i = 0; i < e->sad_count; i++)
+		hdmi_print_sad_info(i, e->sad + i, buffer);
+}
+
+static void hdmi_write_eld_info(struct snd_info_entry *entry,
+				struct snd_info_buffer *buffer)
+{
+	struct hdmi_eld *e = entry->private_data;
+	char line[64];
+	char name[64];
+	char *sname;
+	long long val;
+	int n;
+
+	while (!snd_info_get_line(buffer, line, sizeof(line))) {
+		if (sscanf(line, "%s %llx", name, &val) != 2)
+			continue;
+		/*
+		 * We don't allow modification to these fields:
+		 * 	monitor_name manufacture_id product_id
+		 * 	eld_version edid_version
+		 */
+		if (!strcmp(name, "connection_type"))
+			e->conn_type = val;
+		else if (!strcmp(name, "port_id"))
+			e->port_id = val;
+		else if (!strcmp(name, "support_hdcp"))
+			e->support_hdcp = val;
+		else if (!strcmp(name, "support_ai"))
+			e->support_ai = val;
+		else if (!strcmp(name, "audio_sync_delay"))
+			e->aud_synch_delay = val;
+		else if (!strcmp(name, "speakers"))
+			e->spk_alloc = val;
+		else if (!strcmp(name, "sad_count"))
+			e->sad_count = val;
+		else if (!strncmp(name, "sad", 3)) {
+			sname = name + 4;
+			n = name[3] - '0';
+			if (name[4] >= '0' && name[4] <= '9') {
+				sname++;
+				n = 10 * n + name[4] - '0';
+			}
+			if (n < 0 || n > 31) /* double the CEA limit */
+				continue;
+			if (!strcmp(sname, "_coding_type"))
+				e->sad[n].format = val;
+			else if (!strcmp(sname, "_channels"))
+				e->sad[n].channels = val;
+			else if (!strcmp(sname, "_rates"))
+				e->sad[n].rates = val;
+			else if (!strcmp(sname, "_bits"))
+				e->sad[n].sample_bits = val;
+			else if (!strcmp(sname, "_max_bitrate"))
+				e->sad[n].max_bitrate = val;
+			else if (!strcmp(sname, "_profile"))
+				e->sad[n].profile = val;
+			if (n >= e->sad_count)
+				e->sad_count = n + 1;
+		}
+	}
+}
+
+
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld)
+{
+	char name[32];
+	struct snd_info_entry *entry;
+	int err;
+
+	snprintf(name, sizeof(name), "eld#%d", codec->addr);
+	err = snd_card_proc_new(codec->bus->card, name, &entry);
+	if (err < 0)
+		return err;
+
+	snd_info_set_text_ops(entry, eld, hdmi_print_eld_info);
+	entry->c.text.write = hdmi_write_eld_info;
+	entry->mode |= S_IWUSR;
+	eld->proc_entry = entry;
+
+	return 0;
+}
+
+void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
+{
+	if (!codec->bus->shutdown && eld->proc_entry) {
+		snd_device_free(codec->bus->card, eld->proc_entry);
+		eld->proc_entry = NULL;
+	}
+}
+
+#endif /* CONFIG_PROC_FS */

+ 13 - 8
sound/pci/hda/hda_generic.c

@@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
 		if (is_loopback)
 			add_input_loopback(codec, node->nid, HDA_INPUT, index);
 		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
-		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+		if (err < 0)
 			return err;
 		created = 1;
 	} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
@@ -732,7 +733,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
 		if (is_loopback)
 			add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
 		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
-		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+		if (err < 0)
 			return err;
 		created = 1;
 	}
@@ -745,14 +747,16 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
 	    (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
 		knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
 		snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
-		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+		if (err < 0)
 			return err;
 		created = 1;
 	} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
 		   (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
 		knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
 		snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
-		if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+		if (err < 0)
 			return err;
 		created = 1;
 	}
@@ -849,8 +853,8 @@ static int build_input_controls(struct hda_codec *codec)
 	}
 
 	/* create input MUX if multiple sources are available */
-	if ((err = snd_ctl_add(codec->bus->card,
-			       snd_ctl_new1(&cap_sel, codec))) < 0)
+	err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec));
+	if (err < 0)
 		return err;
 
 	/* no volume control? */
@@ -867,8 +871,8 @@ static int build_input_controls(struct hda_codec *codec)
 			HDA_CODEC_VOLUME(name, adc_node->nid,
 					 spec->input_mux.items[i].index,
 					 HDA_INPUT);
-		if ((err = snd_ctl_add(codec->bus->card,
-				       snd_ctl_new1(&knew, codec))) < 0)
+		err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+		if (err < 0)
 			return err;
 	}
 
@@ -1097,3 +1101,4 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec)
 	snd_hda_generic_free(codec);
 	return err;
 }
+EXPORT_SYMBOL(snd_hda_parse_generic_codec);

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

@@ -23,10 +23,12 @@
 #include <linux/pci.h>
 #include <linux/compat.h>
 #include <linux/mutex.h>
+#include <linux/ctype.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include <sound/hda_hwdep.h>
+#include <sound/minors.h>
 
 /*
  * write/read an out-of-bound verb
@@ -95,7 +97,26 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
 	return 0;
 }
 
-int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
+static void clear_hwdep_elements(struct hda_codec *codec)
+{
+	char **head;
+	int i;
+
+	/* clear init verbs */
+	snd_array_free(&codec->init_verbs);
+	/* clear hints */
+	head = codec->hints.list;
+	for (i = 0; i < codec->hints.used; i++, head++)
+		kfree(*head);
+	snd_array_free(&codec->hints);
+}
+
+static void hwdep_free(struct snd_hwdep *hwdep)
+{
+	clear_hwdep_elements(hwdep->private_data);
+}
+
+int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
 {
 	char hwname[16];
 	struct snd_hwdep *hwdep;
@@ -109,6 +130,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
 	sprintf(hwdep->name, "HDA Codec %d", codec->addr);
 	hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
 	hwdep->private_data = codec;
+	hwdep->private_free = hwdep_free;
 	hwdep->exclusive = 1;
 
 	hwdep->ops.open = hda_hwdep_open;
@@ -117,5 +139,215 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
 	hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
 #endif
 
+	snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
+	snd_array_init(&codec->hints, sizeof(char *), 32);
+
 	return 0;
 }
+
+#ifdef CONFIG_SND_HDA_RECONFIG
+
+/*
+ * sysfs interface
+ */
+
+static int clear_codec(struct hda_codec *codec)
+{
+	snd_hda_codec_reset(codec);
+	clear_hwdep_elements(codec);
+	return 0;
+}
+
+static int reconfig_codec(struct hda_codec *codec)
+{
+	int err;
+
+	snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
+	snd_hda_codec_reset(codec);
+	err = snd_hda_codec_configure(codec);
+	if (err < 0)
+		return err;
+	/* rebuild PCMs */
+	err = snd_hda_codec_build_pcms(codec);
+	if (err < 0)
+		return err;
+	/* rebuild mixers */
+	err = snd_hda_codec_build_controls(codec);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+/*
+ * allocate a string at most len chars, and remove the trailing EOL
+ */
+static char *kstrndup_noeol(const char *src, size_t len)
+{
+	char *s = kstrndup(src, len, GFP_KERNEL);
+	char *p;
+	if (!s)
+		return NULL;
+	p = strchr(s, '\n');
+	if (p)
+		*p = 0;
+	return s;
+}
+
+#define CODEC_INFO_SHOW(type)					\
+static ssize_t type##_show(struct device *dev,			\
+			   struct device_attribute *attr,	\
+			   char *buf)				\
+{								\
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
+	struct hda_codec *codec = hwdep->private_data;		\
+	return sprintf(buf, "0x%x\n", codec->type);		\
+}
+
+#define CODEC_INFO_STR_SHOW(type)				\
+static ssize_t type##_show(struct device *dev,			\
+			     struct device_attribute *attr,	\
+					char *buf)		\
+{								\
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
+	struct hda_codec *codec = hwdep->private_data;		\
+	return sprintf(buf, "%s\n",				\
+		       codec->type ? codec->type : "");		\
+}
+
+CODEC_INFO_SHOW(vendor_id);
+CODEC_INFO_SHOW(subsystem_id);
+CODEC_INFO_SHOW(revision_id);
+CODEC_INFO_SHOW(afg);
+CODEC_INFO_SHOW(mfg);
+CODEC_INFO_STR_SHOW(name);
+CODEC_INFO_STR_SHOW(modelname);
+
+#define CODEC_INFO_STORE(type)					\
+static ssize_t type##_store(struct device *dev,			\
+			    struct device_attribute *attr,	\
+			    const char *buf, size_t count)	\
+{								\
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
+	struct hda_codec *codec = hwdep->private_data;		\
+	char *after;						\
+	codec->type = simple_strtoul(buf, &after, 0);		\
+	return count;						\
+}
+
+#define CODEC_INFO_STR_STORE(type)				\
+static ssize_t type##_store(struct device *dev,			\
+			    struct device_attribute *attr,	\
+			    const char *buf, size_t count)	\
+{								\
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
+	struct hda_codec *codec = hwdep->private_data;		\
+	char *s = kstrndup_noeol(buf, 64);			\
+	if (!s)							\
+		return -ENOMEM;					\
+	kfree(codec->type);					\
+	codec->type = s;					\
+	return count;						\
+}
+
+CODEC_INFO_STORE(vendor_id);
+CODEC_INFO_STORE(subsystem_id);
+CODEC_INFO_STORE(revision_id);
+CODEC_INFO_STR_STORE(name);
+CODEC_INFO_STR_STORE(modelname);
+
+#define CODEC_ACTION_STORE(type)				\
+static ssize_t type##_store(struct device *dev,			\
+			    struct device_attribute *attr,	\
+			    const char *buf, size_t count)	\
+{								\
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
+	struct hda_codec *codec = hwdep->private_data;		\
+	int err = 0;						\
+	if (*buf)						\
+		err = type##_codec(codec);			\
+	return err < 0 ? err : count;				\
+}
+
+CODEC_ACTION_STORE(reconfig);
+CODEC_ACTION_STORE(clear);
+
+static ssize_t init_verbs_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+	struct hda_codec *codec = hwdep->private_data;
+	char *p;
+	struct hda_verb verb, *v;
+
+	verb.nid = simple_strtoul(buf, &p, 0);
+	verb.verb = simple_strtoul(p, &p, 0);
+	verb.param = simple_strtoul(p, &p, 0);
+	if (!verb.nid || !verb.verb || !verb.param)
+		return -EINVAL;
+	v = snd_array_new(&codec->init_verbs);
+	if (!v)
+		return -ENOMEM;
+	*v = verb;
+	return count;
+}
+
+static ssize_t hints_store(struct device *dev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+	struct hda_codec *codec = hwdep->private_data;
+	char *p;
+	char **hint;
+
+	if (!*buf || isspace(*buf) || *buf == '#' || *buf == '\n')
+		return count;
+	p = kstrndup_noeol(buf, 1024);
+	if (!p)
+		return -ENOMEM;
+	hint = snd_array_new(&codec->hints);
+	if (!hint) {
+		kfree(p);
+		return -ENOMEM;
+	}
+	*hint = p;
+	return count;
+}
+
+#define CODEC_ATTR_RW(type) \
+	__ATTR(type, 0644, type##_show, type##_store)
+#define CODEC_ATTR_RO(type) \
+	__ATTR_RO(type)
+#define CODEC_ATTR_WO(type) \
+	__ATTR(type, 0200, NULL, type##_store)
+
+static struct device_attribute codec_attrs[] = {
+	CODEC_ATTR_RW(vendor_id),
+	CODEC_ATTR_RW(subsystem_id),
+	CODEC_ATTR_RW(revision_id),
+	CODEC_ATTR_RO(afg),
+	CODEC_ATTR_RO(mfg),
+	CODEC_ATTR_RW(name),
+	CODEC_ATTR_RW(modelname),
+	CODEC_ATTR_WO(init_verbs),
+	CODEC_ATTR_WO(hints),
+	CODEC_ATTR_WO(reconfig),
+	CODEC_ATTR_WO(clear),
+};
+
+/*
+ * create sysfs files on hwdep directory
+ */
+int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
+{
+	struct snd_hwdep *hwdep = codec->hwdep;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(codec_attrs); i++)
+		snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
+					  hwdep->device, &codec_attrs[i]);
+	return 0;
+}
+
+#endif /* CONFIG_SND_HDA_RECONFIG */

+ 176 - 172
sound/pci/hda/hda_intel.c

@@ -58,6 +58,7 @@ static char *model[SNDRV_CARDS];
 static int position_fix[SNDRV_CARDS];
 static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
+static int probe_only[SNDRV_CARDS];
 static int single_cmd;
 static int enable_msi;
 
@@ -76,6 +77,8 @@ module_param_array(bdl_pos_adj, int, NULL, 0644);
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
+module_param_array(probe_only, bool, NULL, 0444);
+MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
 module_param(single_cmd, bool, 0444);
 MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
 		 "(for debugging only).");
@@ -83,7 +86,10 @@ module_param(enable_msi, int, 0444);
 MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-/* power_save option is defined in hda_codec.c */
+static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
+module_param(power_save, int, 0644);
+MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
+		 "(in second, 0 = disable).");
 
 /* reset the HD-audio controller in power save mode.
  * this may give more power-saving, but will take longer time to
@@ -292,6 +298,8 @@ enum {
 /* Define VIA HD Audio Device ID*/
 #define VIA_HDAC_DEVICE_ID		0x3288
 
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO	0x0403
 
 /*
  */
@@ -392,6 +400,7 @@ struct azx {
 	unsigned int msi :1;
 	unsigned int irq_pending_warned :1;
 	unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
+	unsigned int probing :1; /* codec probing phase */
 
 	/* for debugging */
 	unsigned int last_cmd;	/* last issued command (to sync) */
@@ -414,6 +423,7 @@ enum {
 	AZX_DRIVER_ULI,
 	AZX_DRIVER_NVIDIA,
 	AZX_DRIVER_TERA,
+	AZX_DRIVER_GENERIC,
 	AZX_NUM_DRIVERS, /* keep this as last entry */
 };
 
@@ -427,6 +437,7 @@ static char *driver_short_names[] __devinitdata = {
 	[AZX_DRIVER_ULI] = "HDA ULI M5461",
 	[AZX_DRIVER_NVIDIA] = "HDA NVidia",
 	[AZX_DRIVER_TERA] = "HDA Teradici", 
+	[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
 /*
@@ -527,9 +538,9 @@ static void azx_free_cmd_io(struct azx *chip)
 }
 
 /* send a command */
-static int azx_corb_send_cmd(struct hda_codec *codec, u32 val)
+static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	unsigned int wp;
 
 	/* add command to corb */
@@ -577,9 +588,9 @@ static void azx_update_rirb(struct azx *chip)
 }
 
 /* receive a response */
-static unsigned int azx_rirb_get_response(struct hda_codec *codec)
+static unsigned int azx_rirb_get_response(struct hda_bus *bus)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	unsigned long timeout;
 
  again:
@@ -596,7 +607,7 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 		}
 		if (time_after(jiffies, timeout))
 			break;
-		if (codec->bus->needs_damn_long_delay)
+		if (bus->needs_damn_long_delay)
 			msleep(2); /* temporary workaround */
 		else {
 			udelay(10);
@@ -624,6 +635,14 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 		goto again;
 	}
 
+	if (chip->probing) {
+		/* If this critical timeout happens during the codec probing
+		 * phase, this is likely an access to a non-existing codec
+		 * slot.  Better to return an error and reset the system.
+		 */
+		return -1;
+	}
+
 	snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
 		   "switching to single_cmd mode: last cmd=0x%08x\n",
 		   chip->last_cmd);
@@ -646,9 +665,9 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
  */
 
 /* send a command */
-static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
+static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	int timeout = 50;
 
 	while (timeout--) {
@@ -671,9 +690,9 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
 }
 
 /* receive a response */
-static unsigned int azx_single_get_response(struct hda_codec *codec)
+static unsigned int azx_single_get_response(struct hda_bus *bus)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	int timeout = 50;
 
 	while (timeout--) {
@@ -696,38 +715,29 @@ static unsigned int azx_single_get_response(struct hda_codec *codec)
  */
 
 /* send a command */
-static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,
-			int direct, unsigned int verb,
-			unsigned int para)
+static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
 {
-	struct azx *chip = codec->bus->private_data;
-	u32 val;
-
-	val = (u32)(codec->addr & 0x0f) << 28;
-	val |= (u32)direct << 27;
-	val |= (u32)nid << 20;
-	val |= verb << 8;
-	val |= para;
-	chip->last_cmd = val;
+	struct azx *chip = bus->private_data;
 
+	chip->last_cmd = val;
 	if (chip->single_cmd)
-		return azx_single_send_cmd(codec, val);
+		return azx_single_send_cmd(bus, val);
 	else
-		return azx_corb_send_cmd(codec, val);
+		return azx_corb_send_cmd(bus, val);
 }
 
 /* get a response */
-static unsigned int azx_get_response(struct hda_codec *codec)
+static unsigned int azx_get_response(struct hda_bus *bus)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	if (chip->single_cmd)
-		return azx_single_get_response(codec);
+		return azx_single_get_response(bus);
 	else
-		return azx_rirb_get_response(codec);
+		return azx_rirb_get_response(bus);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static void azx_power_notify(struct hda_codec *codec);
+static void azx_power_notify(struct hda_bus *bus);
 #endif
 
 /* reset codec link */
@@ -1184,6 +1194,28 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
 	return 0;
 }
 
+/*
+ * Probe the given codec address
+ */
+static int probe_codec(struct azx *chip, int addr)
+{
+	unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
+		(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
+	unsigned int res;
+
+	chip->probing = 1;
+	azx_send_cmd(chip->bus, cmd);
+	res = azx_get_response(chip->bus);
+	chip->probing = 0;
+	if (res == -1)
+		return -EIO;
+	snd_printdd("hda_intel: codec #%d probed OK\n", addr);
+	return 0;
+}
+
+static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
+				 struct hda_pcm *cpcm);
+static void azx_stop_chip(struct azx *chip);
 
 /*
  * Codec initialization
@@ -1194,21 +1226,13 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
 	[AZX_DRIVER_TERA] = 1,
 };
 
-/* number of slots to probe as default
- * this can be different from azx_max_codecs[] -- e.g. some boards
- * report wrongly the non-existing 4th slot availability
- */
-static unsigned int azx_default_codecs[AZX_NUM_DRIVERS] __devinitdata = {
-	[AZX_DRIVER_ICH] = 3,
-	[AZX_DRIVER_ATI] = 3,
-};
-
 static int __devinit azx_codec_create(struct azx *chip, const char *model,
-				      unsigned int codec_probe_mask)
+				      unsigned int codec_probe_mask,
+				      int no_init)
 {
 	struct hda_bus_template bus_temp;
-	int c, codecs, audio_codecs, err;
-	int def_slots, max_slots;
+	int c, codecs, err;
+	int max_slots;
 
 	memset(&bus_temp, 0, sizeof(bus_temp));
 	bus_temp.private_data = chip;
@@ -1216,7 +1240,9 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
 	bus_temp.pci = chip->pci;
 	bus_temp.ops.command = azx_send_cmd;
 	bus_temp.ops.get_response = azx_get_response;
+	bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
+	bus_temp.power_save = &power_save;
 	bus_temp.ops.pm_notify = azx_power_notify;
 #endif
 
@@ -1227,33 +1253,43 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
 	if (chip->driver_type == AZX_DRIVER_NVIDIA)
 		chip->bus->needs_damn_long_delay = 1;
 
-	codecs = audio_codecs = 0;
+	codecs = 0;
 	max_slots = azx_max_codecs[chip->driver_type];
 	if (!max_slots)
 		max_slots = AZX_MAX_CODECS;
-	def_slots = azx_default_codecs[chip->driver_type];
-	if (!def_slots)
-		def_slots = max_slots;
-	for (c = 0; c < def_slots; c++) {
+
+	/* First try to probe all given codec slots */
+	for (c = 0; c < max_slots; c++) {
+		if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
+			if (probe_codec(chip, c) < 0) {
+				/* Some BIOSen give you wrong codec addresses
+				 * that don't exist
+				 */
+				snd_printk(KERN_WARNING
+					   "hda_intel: Codec #%d probe error; "
+					   "disabling it...\n", c);
+				chip->codec_mask &= ~(1 << c);
+				/* More badly, accessing to a non-existing
+				 * codec often screws up the controller chip,
+				 * and distrubs the further communications.
+				 * Thus if an error occurs during probing,
+				 * better to reset the controller chip to
+				 * get back to the sanity state.
+				 */
+				azx_stop_chip(chip);
+				azx_init_chip(chip);
+			}
+		}
+	}
+
+	/* Then create codec instances */
+	for (c = 0; c < max_slots; c++) {
 		if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
 			struct hda_codec *codec;
-			err = snd_hda_codec_new(chip->bus, c, &codec);
+			err = snd_hda_codec_new(chip->bus, c, !no_init, &codec);
 			if (err < 0)
 				continue;
 			codecs++;
-			if (codec->afg)
-				audio_codecs++;
-		}
-	}
-	if (!audio_codecs) {
-		/* probe additional slots if no codec is found */
-		for (; c < max_slots; c++) {
-			if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
-				err = snd_hda_codec_new(chip->bus, c, NULL);
-				if (err < 0)
-					continue;
-				codecs++;
-			}
 		}
 	}
 	if (!codecs) {
@@ -1722,111 +1758,59 @@ static struct snd_pcm_ops azx_pcm_ops = {
 
 static void azx_pcm_free(struct snd_pcm *pcm)
 {
-	kfree(pcm->private_data);
+	struct azx_pcm *apcm = pcm->private_data;
+	if (apcm) {
+		apcm->chip->pcm[pcm->device] = NULL;
+		kfree(apcm);
+	}
 }
 
-static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
-				      struct hda_pcm *cpcm)
+static int
+azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
+		      struct hda_pcm *cpcm)
 {
-	int err;
+	struct azx *chip = bus->private_data;
 	struct snd_pcm *pcm;
 	struct azx_pcm *apcm;
+	int pcm_dev = cpcm->device;
+	int s, err;
 
-	/* if no substreams are defined for both playback and capture,
-	 * it's just a placeholder.  ignore it.
-	 */
-	if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
-		return 0;
-
-	if (snd_BUG_ON(!cpcm->name))
+	if (pcm_dev >= AZX_MAX_PCMS) {
+		snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
+			   pcm_dev);
 		return -EINVAL;
-
-	err = snd_pcm_new(chip->card, cpcm->name, cpcm->device,
-			  cpcm->stream[0].substreams,
-			  cpcm->stream[1].substreams,
+	}
+	if (chip->pcm[pcm_dev]) {
+		snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
+		return -EBUSY;
+	}
+	err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+			  cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
+			  cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
 			  &pcm);
 	if (err < 0)
 		return err;
 	strcpy(pcm->name, cpcm->name);
-	apcm = kmalloc(sizeof(*apcm), GFP_KERNEL);
+	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
 	if (apcm == NULL)
 		return -ENOMEM;
 	apcm->chip = chip;
 	apcm->codec = codec;
-	apcm->hinfo[0] = &cpcm->stream[0];
-	apcm->hinfo[1] = &cpcm->stream[1];
 	pcm->private_data = apcm;
 	pcm->private_free = azx_pcm_free;
-	if (cpcm->stream[0].substreams)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
-	if (cpcm->stream[1].substreams)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
+	if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
+		pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
+	chip->pcm[pcm_dev] = pcm;
+	cpcm->pcm = pcm;
+	for (s = 0; s < 2; s++) {
+		apcm->hinfo[s] = &cpcm->stream[s];
+		if (cpcm->stream[s].substreams)
+			snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
+	}
+	/* buffer pre-allocation */
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 					      snd_dma_pci_data(chip->pci),
 					      1024 * 64, 32 * 1024 * 1024);
-	chip->pcm[cpcm->device] = pcm;
-	return 0;
-}
-
-static int __devinit azx_pcm_create(struct azx *chip)
-{
-	static const char *dev_name[HDA_PCM_NTYPES] = {
-		"Audio", "SPDIF", "HDMI", "Modem"
-	};
-	/* starting device index for each PCM type */
-	static int dev_idx[HDA_PCM_NTYPES] = {
-		[HDA_PCM_TYPE_AUDIO] = 0,
-		[HDA_PCM_TYPE_SPDIF] = 1,
-		[HDA_PCM_TYPE_HDMI] = 3,
-		[HDA_PCM_TYPE_MODEM] = 6
-	};
-	/* normal audio device indices; not linear to keep compatibility */
-	static int audio_idx[4] = { 0, 2, 4, 5 };
-	struct hda_codec *codec;
-	int c, err;
-	int num_devs[HDA_PCM_NTYPES];
-
-	err = snd_hda_build_pcms(chip->bus);
-	if (err < 0)
-		return err;
-
-	/* create audio PCMs */
-	memset(num_devs, 0, sizeof(num_devs));
-	list_for_each_entry(codec, &chip->bus->codec_list, list) {
-		for (c = 0; c < codec->num_pcms; c++) {
-			struct hda_pcm *cpcm = &codec->pcm_info[c];
-			int type = cpcm->pcm_type;
-			switch (type) {
-			case HDA_PCM_TYPE_AUDIO:
-				if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
-					snd_printk(KERN_WARNING
-						   "Too many audio devices\n");
-					continue;
-				}
-				cpcm->device = audio_idx[num_devs[type]];
-				break;
-			case HDA_PCM_TYPE_SPDIF:
-			case HDA_PCM_TYPE_HDMI:
-			case HDA_PCM_TYPE_MODEM:
-				if (num_devs[type]) {
-					snd_printk(KERN_WARNING
-						   "%s already defined\n",
-						   dev_name[type]);
-					continue;
-				}
-				cpcm->device = dev_idx[type];
-				break;
-			default:
-				snd_printk(KERN_WARNING
-					   "Invalid PCM type %d\n", type);
-				continue;
-			}
-			num_devs[type]++;
-			err = create_codec_pcm(chip, codec, cpcm);
-			if (err < 0)
-				return err;
-		}
-	}
 	return 0;
 }
 
@@ -1903,13 +1887,13 @@ static void azx_stop_chip(struct azx *chip)
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 /* power-up/down the controller */
-static void azx_power_notify(struct hda_codec *codec)
+static void azx_power_notify(struct hda_bus *bus)
 {
-	struct azx *chip = codec->bus->private_data;
+	struct azx *chip = bus->private_data;
 	struct hda_codec *c;
 	int power_on = 0;
 
-	list_for_each_entry(c, &codec->bus->codec_list, list) {
+	list_for_each_entry(c, &bus->codec_list, list) {
 		if (c->power_on) {
 			power_on = 1;
 			break;
@@ -1926,6 +1910,18 @@ static void azx_power_notify(struct hda_codec *codec)
 /*
  * power management
  */
+
+static int snd_hda_codecs_inuse(struct hda_bus *bus)
+{
+	struct hda_codec *codec;
+
+	list_for_each_entry(codec, &bus->codec_list, list) {
+		if (snd_hda_codec_needs_resume(codec))
+			return 1;
+	}
+	return 0;
+}
+
 static int azx_suspend(struct pci_dev *pci, pm_message_t state)
 {
 	struct snd_card *card = pci_get_drvdata(pci);
@@ -1951,13 +1947,16 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
 	return 0;
 }
 
+static int azx_resume_early(struct pci_dev *pci)
+{
+	return pci_restore_state(pci);
+}
+
 static int azx_resume(struct pci_dev *pci)
 {
 	struct snd_card *card = pci_get_drvdata(pci);
 	struct azx *chip = card->private_data;
 
-	pci_set_power_state(pci, PCI_D0);
-	pci_restore_state(pci);
 	if (pci_enable_device(pci) < 0) {
 		printk(KERN_ERR "hda-intel: pci_enable_device failed, "
 		       "disabling device\n");
@@ -2095,6 +2094,10 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
 	SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01),
 	SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01),
 	SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01),
+	/* broken BIOS */
+	SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01),
+	/* including bogus ALC268 in slot#2 that conflicts with ALC888 */
+	SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01),
 	{}
 };
 
@@ -2229,6 +2232,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
 			chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
 			chip->capture_streams = ATIHDMI_NUM_CAPTURE;
 			break;
+		case AZX_DRIVER_GENERIC:
 		default:
 			chip->playback_streams = ICH6_NUM_PLAYBACK;
 			chip->capture_streams = ICH6_NUM_CAPTURE;
@@ -2338,40 +2342,31 @@ static int __devinit azx_probe(struct pci_dev *pci,
 	}
 
 	err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if (err < 0)
+		goto out_free;
 	card->private_data = chip;
 
 	/* create codec instances */
-	err = azx_codec_create(chip, model[dev], probe_mask[dev]);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	err = azx_codec_create(chip, model[dev], probe_mask[dev],
+			       probe_only[dev]);
+	if (err < 0)
+		goto out_free;
 
 	/* create PCM streams */
-	err = azx_pcm_create(chip);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	err = snd_hda_build_pcms(chip->bus);
+	if (err < 0)
+		goto out_free;
 
 	/* create mixer controls */
 	err = azx_mixer_create(chip);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if (err < 0)
+		goto out_free;
 
 	snd_card_set_dev(card, &pci->dev);
 
 	err = snd_card_register(card);
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if (err < 0)
+		goto out_free;
 
 	pci_set_drvdata(pci, card);
 	chip->running = 1;
@@ -2380,6 +2375,9 @@ static int __devinit azx_probe(struct pci_dev *pci,
 
 	dev++;
 	return err;
+out_free:
+	snd_card_free(card);
+	return err;
 }
 
 static void __devexit azx_remove(struct pci_dev *pci)
@@ -2453,6 +2451,11 @@ static struct pci_device_id azx_ids[] = {
 	{ PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA },
 	/* Teradici */
 	{ PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
+	/* AMD Generic, PCI class code and Vendor ID for HD Audio */
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
+	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+	  .class_mask = 0xffffff,
+	  .driver_data = AZX_DRIVER_GENERIC },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
@@ -2465,6 +2468,7 @@ static struct pci_driver driver = {
 	.remove = __devexit_p(azx_remove),
 #ifdef CONFIG_PM
 	.suspend = azx_suspend,
+	.resume_early = azx_resume_early,
 	.resume = azx_resume,
 #endif
 };

+ 93 - 7
sound/pci/hda/hda_local.h

@@ -96,6 +96,8 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
 					    const char *name);
 int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
 			unsigned int *tlv, const char **slaves);
+void snd_hda_codec_reset(struct hda_codec *codec);
+int snd_hda_codec_configure(struct hda_codec *codec);
 
 /* amp value bits */
 #define HDA_AMP_MUTE	0x80
@@ -282,6 +284,12 @@ int snd_hda_codec_proc_new(struct hda_codec *codec);
 static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
 #endif
 
+#define SND_PRINT_RATES_ADVISED_BUFSIZE	80
+void snd_print_pcm_rates(int pcm, char *buf, int buflen);
+
+#define SND_PRINT_BITS_ADVISED_BUFSIZE	16
+void snd_print_pcm_bits(int pcm, char *buf, int buflen);
+
 /*
  * Misc
  */
@@ -364,17 +372,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 /* amp values */
 #define AMP_IN_MUTE(idx)	(0x7080 | ((idx)<<8))
 #define AMP_IN_UNMUTE(idx)	(0x7000 | ((idx)<<8))
-#define AMP_OUT_MUTE	0xb080
-#define AMP_OUT_UNMUTE	0xb000
-#define AMP_OUT_ZERO	0xb000
+#define AMP_OUT_MUTE		0xb080
+#define AMP_OUT_UNMUTE		0xb000
+#define AMP_OUT_ZERO		0xb000
 /* pinctl values */
 #define PIN_IN			(AC_PINCTL_IN_EN)
-#define PIN_VREFHIZ	(AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
+#define PIN_VREFHIZ		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
 #define PIN_VREF50		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_50)
-#define PIN_VREFGRD	(AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
+#define PIN_VREFGRD		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
 #define PIN_VREF80		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_80)
-#define PIN_VREF100	(AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
-#define PIN_OUT		(AC_PINCTL_OUT_EN)
+#define PIN_VREF100		(AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
+#define PIN_OUT			(AC_PINCTL_OUT_EN)
 #define PIN_HP			(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
 #define PIN_HP_AMP		(AC_PINCTL_HP_EN)
 
@@ -393,10 +401,26 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 			      unsigned int caps);
 
+int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
+void snd_hda_ctls_clear(struct hda_codec *codec);
+
 /*
  * hwdep interface
  */
+#ifdef CONFIG_SND_HDA_HWDEP
 int snd_hda_create_hwdep(struct hda_codec *codec);
+#else
+static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
+#endif
+
+#ifdef CONFIG_SND_HDA_RECONFIG
+int snd_hda_hwdep_add_sysfs(struct hda_codec *codec);
+#else
+static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
+{
+	return 0;
+}
+#endif
 
 /*
  * power-management
@@ -430,4 +454,66 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 #define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1)
 #define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf)
 
+/*
+ * CEA Short Audio Descriptor data
+ */
+struct cea_sad {
+	int	channels;
+	int	format;		/* (format == 0) indicates invalid SAD */
+	int	rates;
+	int	sample_bits;	/* for LPCM */
+	int	max_bitrate;	/* for AC3...ATRAC */
+	int	profile;	/* for WMAPRO */
+};
+
+#define ELD_FIXED_BYTES	20
+#define ELD_MAX_MNL	16
+#define ELD_MAX_SAD	16
+
+/*
+ * ELD: EDID Like Data
+ */
+struct hdmi_eld {
+	int	eld_size;
+	int	baseline_len;
+	int	eld_ver;	/* (eld_ver == 0) indicates invalid ELD */
+	int	cea_edid_ver;
+	char	monitor_name[ELD_MAX_MNL + 1];
+	int	manufacture_id;
+	int	product_id;
+	u64	port_id;
+	int	support_hdcp;
+	int	support_ai;
+	int	conn_type;
+	int	aud_synch_delay;
+	int	spk_alloc;
+	int	sad_count;
+	struct cea_sad sad[ELD_MAX_SAD];
+#ifdef CONFIG_PROC_FS
+	struct snd_info_entry *proc_entry;
+#endif
+};
+
+int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
+int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t);
+void snd_hdmi_show_eld(struct hdmi_eld *eld);
+
+#ifdef CONFIG_PROC_FS
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld);
+void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld);
+#else
+static inline int snd_hda_eld_proc_new(struct hda_codec *codec,
+				       struct hdmi_eld *eld)
+{
+	return 0;
+}
+static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
+					 struct hdmi_eld *eld)
+{
+}
+#endif
+
+#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
+void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
+
 #endif /* __SOUND_HDA_LOCAL_H */

+ 0 - 22
sound/pci/hda/hda_patch.h

@@ -1,22 +0,0 @@
-/*
- * HDA Patches - included by hda_codec.c
- */
-
-/* Realtek codecs */
-extern struct hda_codec_preset snd_hda_preset_realtek[];
-/* C-Media codecs */
-extern struct hda_codec_preset snd_hda_preset_cmedia[];
-/* Analog Devices codecs */
-extern struct hda_codec_preset snd_hda_preset_analog[];
-/* SigmaTel codecs */
-extern struct hda_codec_preset snd_hda_preset_sigmatel[];
-/* SiLabs 3054/3055 modem codecs */
-extern struct hda_codec_preset snd_hda_preset_si3054[];
-/* ATI HDMI codecs */
-extern struct hda_codec_preset snd_hda_preset_atihdmi[];
-/* Conexant audio codec */
-extern struct hda_codec_preset snd_hda_preset_conexant[];
-/* VIA codecs */
-extern struct hda_codec_preset snd_hda_preset_via[];
-/* NVIDIA HDMI codecs */
-extern struct hda_codec_preset snd_hda_preset_nvhdmi[];

+ 19 - 72
sound/pci/hda/hda_proc.c

@@ -91,31 +91,21 @@ static void print_amp_vals(struct snd_info_buffer *buffer,
 
 static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
 {
-	static unsigned int rates[] = {
-		8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
-		96000, 176400, 192000, 384000
-	};
-	int i;
+	char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
 
 	pcm &= AC_SUPPCM_RATES;
 	snd_iprintf(buffer, "    rates [0x%x]:", pcm);
-	for (i = 0; i < ARRAY_SIZE(rates); i++) 
-		if (pcm & (1 << i))
-			snd_iprintf(buffer, " %d", rates[i]);
-	snd_iprintf(buffer, "\n");
+	snd_print_pcm_rates(pcm, buf, sizeof(buf));
+	snd_iprintf(buffer, "%s\n", buf);
 }
 
 static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
 {
-	static unsigned int bits[] = { 8, 16, 20, 24, 32 };
-	int i;
+	char buf[SND_PRINT_BITS_ADVISED_BUFSIZE];
 
-	pcm = (pcm >> 16) & 0xff;
-	snd_iprintf(buffer, "    bits [0x%x]:", pcm);
-	for (i = 0; i < ARRAY_SIZE(bits); i++)
-		if (pcm & (1 << i))
-			snd_iprintf(buffer, " %d", bits[i]);
-	snd_iprintf(buffer, "\n");
+	snd_iprintf(buffer, "    bits [0x%x]:", (pcm >> 16) & 0xff);
+	snd_print_pcm_bits(pcm, buf, sizeof(buf));
+	snd_iprintf(buffer, "%s\n", buf);
 }
 
 static void print_pcm_formats(struct snd_info_buffer *buffer,
@@ -145,32 +135,6 @@ static void print_pcm_caps(struct snd_info_buffer *buffer,
 	print_pcm_formats(buffer, stream);
 }
 
-static const char *get_jack_location(u32 cfg)
-{
-	static char *bases[7] = {
-		"N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
-	};
-	static unsigned char specials_idx[] = {
-		0x07, 0x08,
-		0x17, 0x18, 0x19,
-		0x37, 0x38
-	};
-	static char *specials[] = {
-		"Rear Panel", "Drive Bar",
-		"Riser", "HDMI", "ATAPI",
-		"Mobile-In", "Mobile-Out"
-	};
-	int i;
-	cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
-	if ((cfg & 0x0f) < 7)
-		return bases[cfg & 0x0f];
-	for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
-		if (cfg == specials_idx[i])
-			return specials[i];
-	}
-	return "UNKNOWN";
-}
-
 static const char *get_jack_connection(u32 cfg)
 {
 	static char *names[16] = {
@@ -206,13 +170,6 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
 			   int *supports_vref)
 {
 	static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
-	static char *jack_types[16] = {
-		"Line Out", "Speaker", "HP Out", "CD",
-		"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
-		"Line In", "Aux", "Mic", "Telephony",
-		"SPDIF In", "Digitial In", "Reserved", "Other"
-	};
-	static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
 	unsigned int caps, val;
 
 	caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
@@ -274,9 +231,9 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
 	caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
 	snd_iprintf(buffer, "  Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
 		    jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
-		    jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT],
-		    jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3],
-		    get_jack_location(caps));
+		    snd_hda_get_jack_type(caps),
+		    snd_hda_get_jack_connectivity(caps),
+		    snd_hda_get_jack_location(caps));
 	snd_iprintf(buffer, "    Conn = %s, Color = %s\n",
 		    get_jack_connection(caps),
 		    get_jack_color(caps));
@@ -457,17 +414,6 @@ static void print_conn_list(struct snd_info_buffer *buffer,
 	}
 }
 
-static void print_realtek_coef(struct snd_info_buffer *buffer,
-			       struct hda_codec *codec, hda_nid_t nid)
-{
-	int coeff = snd_hda_codec_read(codec, nid, 0,
-				       AC_VERB_GET_PROC_COEF, 0);
-	snd_iprintf(buffer, "  Processing Coefficient: 0x%02x\n", coeff);
-	coeff = snd_hda_codec_read(codec, nid, 0,
-				   AC_VERB_GET_COEF_INDEX, 0);
-	snd_iprintf(buffer, "  Coefficient Index: 0x%02x\n", coeff);
-}
-
 static void print_gpio(struct snd_info_buffer *buffer,
 		       struct hda_codec *codec, hda_nid_t nid)
 {
@@ -500,12 +446,13 @@ static void print_gpio(struct snd_info_buffer *buffer,
 	for (i = 0; i < max; ++i)
 		snd_iprintf(buffer,
 			    "  IO[%d]: enable=%d, dir=%d, wake=%d, "
-			    "sticky=%d, data=%d\n", i,
+			    "sticky=%d, data=%d, unsol=%d\n", i,
 			    (enable & (1<<i)) ? 1 : 0,
 			    (direction & (1<<i)) ? 1 : 0,
 			    (wake & (1<<i)) ? 1 : 0,
 			    (sticky & (1<<i)) ? 1 : 0,
-			    (data & (1<<i)) ? 1 : 0);
+			    (data & (1<<i)) ? 1 : 0,
+			    (unsol & (1<<i)) ? 1 : 0);
 	/* FIXME: add GPO and GPI pin information */
 }
 
@@ -513,12 +460,11 @@ static void print_codec_info(struct snd_info_entry *entry,
 			     struct snd_info_buffer *buffer)
 {
 	struct hda_codec *codec = entry->private_data;
-	char buf[32];
 	hda_nid_t nid;
 	int i, nodes;
 
-	snd_hda_get_codec_name(codec, buf, sizeof(buf));
-	snd_iprintf(buffer, "Codec: %s\n", buf);
+	snd_iprintf(buffer, "Codec: %s\n",
+		    codec->name ? codec->name : "Not Set");
 	snd_iprintf(buffer, "Address: %d\n", codec->addr);
 	snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
 	snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
@@ -547,6 +493,8 @@ static void print_codec_info(struct snd_info_entry *entry,
 	}
 
 	print_gpio(buffer, codec, codec->afg);
+	if (codec->proc_widget_hook)
+		codec->proc_widget_hook(buffer, codec, codec->afg);
 
 	for (i = 0; i < nodes; i++, nid++) {
 		unsigned int wid_caps =
@@ -649,9 +597,8 @@ static void print_codec_info(struct snd_info_entry *entry,
 		if (wid_caps & AC_WCAP_PROC_WID)
 			print_proc_caps(buffer, codec, nid);
 
-		/* NID 0x20 == Realtek Define Registers */
-		if (codec->vendor_id == 0x10ec && nid == 0x20)
-			print_realtek_coef(buffer, codec, nid);
+		if (codec->proc_widget_hook)
+			codec->proc_widget_hook(buffer, codec, nid);
 	}
 	snd_hda_power_down(codec);
 }

+ 98 - 34
sound/pci/hda/patch_analog.c

@@ -27,7 +27,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 struct ad198x_spec {
 	struct snd_kcontrol_new *mixers[5];
@@ -67,8 +66,7 @@ struct ad198x_spec {
 
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
-	unsigned int num_kctl_alloc, num_kctl_used;
-	struct snd_kcontrol_new *kctl_alloc;
+	struct snd_array kctls;
 	struct hda_input_mux private_imux;
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
@@ -154,6 +152,8 @@ static const char *ad_slave_sws[] = {
 	NULL
 };
 
+static void ad198x_free_kctls(struct hda_codec *codec);
+
 static int ad198x_build_controls(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec = codec->spec;
@@ -202,6 +202,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
 			return err;
 	}
 
+	ad198x_free_kctls(codec); /* no longer needed */
 	return 0;
 }
 
@@ -375,16 +376,27 @@ static int ad198x_build_pcms(struct hda_codec *codec)
 	return 0;
 }
 
-static void ad198x_free(struct hda_codec *codec)
+static void ad198x_free_kctls(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec = codec->spec;
-	unsigned int i;
 
-	if (spec->kctl_alloc) {
-		for (i = 0; i < spec->num_kctl_used; i++)
-			kfree(spec->kctl_alloc[i].name);
-		kfree(spec->kctl_alloc);
+	if (spec->kctls.list) {
+		struct snd_kcontrol_new *kctl = spec->kctls.list;
+		int i;
+		for (i = 0; i < spec->kctls.used; i++)
+			kfree(kctl[i].name);
 	}
+	snd_array_free(&spec->kctls);
+}
+
+static void ad198x_free(struct hda_codec *codec)
+{
+	struct ad198x_spec *spec = codec->spec;
+
+	if (!spec)
+		return;
+
+	ad198x_free_kctls(codec);
 	kfree(codec->spec);
 }
 
@@ -625,6 +637,36 @@ static struct hda_input_mux ad1986a_automic_capture_source = {
 };
 
 static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
+	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
+	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "External Amplifier",
+		.info = ad198x_eapd_info,
+		.get = ad198x_eapd_get,
+		.put = ad198x_eapd_put,
+		.private_value = 0x1b | (1 << 8), /* port-D, inversed */
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new ad1986a_samsung_mixers[] = {
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -917,6 +959,7 @@ enum {
 	AD1986A_LAPTOP_EAPD,
 	AD1986A_LAPTOP_AUTOMUTE,
 	AD1986A_ULTRA,
+	AD1986A_SAMSUNG,
 	AD1986A_MODELS
 };
 
@@ -927,6 +970,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = {
 	[AD1986A_LAPTOP_EAPD]	= "laptop-eapd",
 	[AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
 	[AD1986A_ULTRA]		= "ultra",
+	[AD1986A_SAMSUNG]	= "samsung",
 };
 
 static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
@@ -949,9 +993,9 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
-	SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG),
+	SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG),
+	SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG),
 	SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
 	SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
@@ -1033,6 +1077,17 @@ static int patch_ad1986a(struct hda_codec *codec)
 		break;
 	case AD1986A_LAPTOP_EAPD:
 		spec->mixers[0] = ad1986a_laptop_eapd_mixers;
+		spec->num_init_verbs = 2;
+		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
+		spec->multiout.max_channels = 2;
+		spec->multiout.num_dacs = 1;
+		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
+		if (!is_jack_available(codec, 0x25))
+			spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1986a_laptop_eapd_capture_source;
+		break;
+	case AD1986A_SAMSUNG:
+		spec->mixers[0] = ad1986a_samsung_mixers;
 		spec->num_init_verbs = 3;
 		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
 		spec->init_verbs[2] = ad1986a_automic_verbs;
@@ -2452,9 +2507,6 @@ static struct hda_amp_list ad1988_loopbacks[] = {
  * Automatic parse of I/O pins from the BIOS configuration
  */
 
-#define NUM_CONTROL_ALLOC	32
-#define NUM_VERB_ALLOC		32
-
 enum {
 	AD_CTL_WIDGET_VOL,
 	AD_CTL_WIDGET_MUTE,
@@ -2472,27 +2524,15 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
 {
 	struct snd_kcontrol_new *knew;
 
-	if (spec->num_kctl_used >= spec->num_kctl_alloc) {
-		int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
-
-		knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
-		if (! knew)
-			return -ENOMEM;
-		if (spec->kctl_alloc) {
-			memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
-			kfree(spec->kctl_alloc);
-		}
-		spec->kctl_alloc = knew;
-		spec->num_kctl_alloc = num;
-	}
-
-	knew = &spec->kctl_alloc[spec->num_kctl_used];
+	snd_array_init(&spec->kctls, sizeof(*knew), 32);
+	knew = snd_array_new(&spec->kctls);
+	if (!knew)
+		return -ENOMEM;
 	*knew = ad1988_control_templates[type];
 	knew->name = kstrdup(name, GFP_KERNEL);
 	if (! knew->name)
 		return -ENOMEM;
 	knew->private_value = val;
-	spec->num_kctl_used++;
 	return 0;
 }
 
@@ -2846,8 +2886,8 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = AD1988_SPDIF_IN;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
 
@@ -3861,6 +3901,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = {
 static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
 	SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
+	SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP),
 	SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP),
 	SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP),
 	SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
@@ -4267,7 +4308,7 @@ static int patch_ad1882(struct hda_codec *codec)
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_analog[] = {
+static struct hda_codec_preset snd_hda_preset_analog[] = {
 	{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
 	{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
 	{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
@@ -4285,3 +4326,26 @@ struct hda_codec_preset snd_hda_preset_analog[] = {
 	{ .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:11d4*");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Analog Devices HD-audio codec");
+
+static struct hda_codec_preset_list analog_list = {
+	.preset = snd_hda_preset_analog,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_analog_init(void)
+{
+	return snd_hda_add_codec_preset(&analog_list);
+}
+
+static void __exit patch_analog_exit(void)
+{
+	snd_hda_delete_codec_preset(&analog_list);
+}
+
+module_init(patch_analog_init)
+module_exit(patch_analog_exit)

+ 33 - 7
sound/pci/hda/patch_atihdmi.c

@@ -27,7 +27,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 struct atihdmi_spec {
 	struct hda_multi_out multiout;
@@ -187,13 +186,40 @@ static int patch_atihdmi(struct hda_codec *codec)
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_atihdmi[] = {
-	{ .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi },
+static struct hda_codec_preset snd_hda_preset_atihdmi[] = {
+	{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
+	{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
+	{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
+	{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
 	{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x17e80047, .name = "Chrontel HDMI",  .patch = patch_atihdmi },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:1002793c");
+MODULE_ALIAS("snd-hda-codec-id:10027919");
+MODULE_ALIAS("snd-hda-codec-id:1002791a");
+MODULE_ALIAS("snd-hda-codec-id:1002aa01");
+MODULE_ALIAS("snd-hda-codec-id:10951390");
+MODULE_ALIAS("snd-hda-codec-id:17e80047");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ATI HDMI HD-audio codec");
+
+static struct hda_codec_preset_list atihdmi_list = {
+	.preset = snd_hda_preset_atihdmi,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_atihdmi_init(void)
+{
+	return snd_hda_add_codec_preset(&atihdmi_list);
+}
+
+static void __exit patch_atihdmi_exit(void)
+{
+	snd_hda_delete_codec_preset(&atihdmi_list);
+}
+
+module_init(patch_atihdmi_init)
+module_exit(patch_atihdmi_exit)

+ 25 - 2
sound/pci/hda/patch_cmedia.c

@@ -28,7 +28,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 #define NUM_PINS	11
 
 
@@ -736,8 +735,32 @@ static int patch_cmi9880(struct hda_codec *codec)
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_cmedia[] = {
+static struct hda_codec_preset snd_hda_preset_cmedia[] = {
 	{ .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
  	{ .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:13f69880");
+MODULE_ALIAS("snd-hda-codec-id:434d4980");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("C-Media HD-audio codec");
+
+static struct hda_codec_preset_list cmedia_list = {
+	.preset = snd_hda_preset_cmedia,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_cmedia_init(void)
+{
+	return snd_hda_add_codec_preset(&cmedia_list);
+}
+
+static void __exit patch_cmedia_exit(void)
+{
+	snd_hda_delete_codec_preset(&cmedia_list);
+}
+
+module_init(patch_cmedia_init)
+module_exit(patch_cmedia_exit)

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

@@ -27,7 +27,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 #define CXT_PIN_DIR_IN              0x00
 #define CXT_PIN_DIR_OUT             0x01
@@ -86,8 +85,6 @@ struct conexant_spec {
 
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
-	unsigned int num_kctl_alloc, num_kctl_used;
-	struct snd_kcontrol_new *kctl_alloc;
 	struct hda_input_mux private_imux;
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
@@ -344,15 +341,6 @@ static int conexant_init(struct hda_codec *codec)
 
 static void conexant_free(struct hda_codec *codec)
 {
-        struct conexant_spec *spec = codec->spec;
-        unsigned int i;
-
-        if (spec->kctl_alloc) {
-                for (i = 0; i < spec->num_kctl_used; i++)
-                        kfree(spec->kctl_alloc[i].name);
-                kfree(spec->kctl_alloc);
-        }
-
 	kfree(codec->spec);
 }
 
@@ -1782,7 +1770,7 @@ static int patch_cxt5051(struct hda_codec *codec)
 /*
  */
 
-struct hda_codec_preset snd_hda_preset_conexant[] = {
+static struct hda_codec_preset snd_hda_preset_conexant[] = {
 	{ .id = 0x14f15045, .name = "CX20549 (Venice)",
 	  .patch = patch_cxt5045 },
 	{ .id = 0x14f15047, .name = "CX20551 (Waikiki)",
@@ -1791,3 +1779,28 @@ struct hda_codec_preset snd_hda_preset_conexant[] = {
 	  .patch = patch_cxt5051 },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:14f15045");
+MODULE_ALIAS("snd-hda-codec-id:14f15047");
+MODULE_ALIAS("snd-hda-codec-id:14f15051");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Conexant HD-audio codec");
+
+static struct hda_codec_preset_list conexant_list = {
+	.preset = snd_hda_preset_conexant,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_conexant_init(void)
+{
+	return snd_hda_add_codec_preset(&conexant_list);
+}
+
+static void __exit patch_conexant_exit(void)
+{
+	snd_hda_delete_codec_preset(&conexant_list);
+}
+
+module_init(patch_conexant_init)
+module_exit(patch_conexant_exit)

+ 711 - 0
sound/pci/hda/patch_intelhdmi.c

@@ -0,0 +1,711 @@
+/*
+ *
+ *  patch_intelhdmi.c - Patch for Intel HDMI codecs
+ *
+ *  Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ *  Authors:
+ *  			Jiang Zhe <zhe.jiang@intel.com>
+ *  			Wu Fengguang <wfg@linux.intel.com>
+ *
+ *  Maintained by:
+ *  			Wu Fengguang <wfg@linux.intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software Foundation,
+ *  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+#define CVT_NID		0x02	/* audio converter */
+#define PIN_NID		0x03	/* HDMI output pin */
+
+#define INTEL_HDMI_EVENT_TAG		0x08
+
+struct intel_hdmi_spec {
+	struct hda_multi_out multiout;
+	struct hda_pcm pcm_rec;
+	struct hdmi_eld sink_eld;
+};
+
+static struct hda_verb pinout_enable_verb[] = {
+	{PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{} /* terminator */
+};
+
+static struct hda_verb pinout_disable_verb[] = {
+	{PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00},
+	{}
+};
+
+static struct hda_verb unsolicited_response_verb[] = {
+	{PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN |
+						  INTEL_HDMI_EVENT_TAG},
+	{}
+};
+
+static struct hda_verb def_chan_map[] = {
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66},
+	{CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77},
+	{}
+};
+
+
+struct hdmi_audio_infoframe {
+	u8 type; /* 0x84 */
+	u8 ver;  /* 0x01 */
+	u8 len;  /* 0x0a */
+
+	u8 checksum;	/* PB0 */
+	u8 CC02_CT47;	/* CC in bits 0:2, CT in 4:7 */
+	u8 SS01_SF24;
+	u8 CXT04;
+	u8 CA;
+	u8 LFEPBL01_LSV36_DM_INH7;
+	u8 reserved[5];	/* PB6 - PB10 */
+};
+
+/*
+ * CEA speaker placement:
+ *
+ *        FLH       FCH        FRH
+ *  FLW    FL  FLC   FC   FRC   FR   FRW
+ *
+ *                                  LFE
+ *                     TC
+ *
+ *          RL  RLC   RC   RRC   RR
+ *
+ * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
+ * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
+ */
+enum cea_speaker_placement {
+	FL  = (1 <<  0),	/* Front Left           */
+	FC  = (1 <<  1),	/* Front Center         */
+	FR  = (1 <<  2),	/* Front Right          */
+	FLC = (1 <<  3),	/* Front Left Center    */
+	FRC = (1 <<  4),	/* Front Right Center   */
+	RL  = (1 <<  5),	/* Rear Left            */
+	RC  = (1 <<  6),	/* Rear Center          */
+	RR  = (1 <<  7),	/* Rear Right           */
+	RLC = (1 <<  8),	/* Rear Left Center     */
+	RRC = (1 <<  9),	/* Rear Right Center    */
+	LFE = (1 << 10),	/* Low Frequency Effect */
+	FLW = (1 << 11),	/* Front Left Wide      */
+	FRW = (1 << 12),	/* Front Right Wide     */
+	FLH = (1 << 13),	/* Front Left High      */
+	FCH = (1 << 14),	/* Front Center High    */
+	FRH = (1 << 15),	/* Front Right High     */
+	TC  = (1 << 16),	/* Top Center           */
+};
+
+/*
+ * ELD SA bits in the CEA Speaker Allocation data block
+ */
+static int eld_speaker_allocation_bits[] = {
+	[0] = FL | FR,
+	[1] = LFE,
+	[2] = FC,
+	[3] = RL | RR,
+	[4] = RC,
+	[5] = FLC | FRC,
+	[6] = RLC | RRC,
+	/* the following are not defined in ELD yet */
+	[7] = FLW | FRW,
+	[8] = FLH | FRH,
+	[9] = TC,
+	[10] = FCH,
+};
+
+struct cea_channel_speaker_allocation {
+	int ca_index;
+	int speakers[8];
+
+	/* derived values, just for convenience */
+	int channels;
+	int spk_mask;
+};
+
+/*
+ * This is an ordered list!
+ *
+ * The preceding ones have better chances to be selected by
+ * hdmi_setup_channel_allocation().
+ */
+static struct cea_channel_speaker_allocation channel_allocations[] = {
+/* 			  channel:   8     7    6    5    4     3    2    1  */
+{ .ca_index = 0x00,  .speakers = {   0,    0,   0,   0,   0,    0,  FR,  FL } },
+				 /* 2.1 */
+{ .ca_index = 0x01,  .speakers = {   0,    0,   0,   0,   0,  LFE,  FR,  FL } },
+				 /* Dolby Surround */
+{ .ca_index = 0x02,  .speakers = {   0,    0,   0,   0,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x03,  .speakers = {   0,    0,   0,   0,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x04,  .speakers = {   0,    0,   0,  RC,   0,    0,  FR,  FL } },
+{ .ca_index = 0x05,  .speakers = {   0,    0,   0,  RC,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x06,  .speakers = {   0,    0,   0,  RC,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x07,  .speakers = {   0,    0,   0,  RC,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x08,  .speakers = {   0,    0,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x09,  .speakers = {   0,    0,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x0a,  .speakers = {   0,    0,  RR,  RL,  FC,    0,  FR,  FL } },
+				 /* 5.1 */
+{ .ca_index = 0x0b,  .speakers = {   0,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x0c,  .speakers = {   0,   RC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x0d,  .speakers = {   0,   RC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x0e,  .speakers = {   0,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+				 /* 6.1 */
+{ .ca_index = 0x0f,  .speakers = {   0,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x10,  .speakers = { RRC,  RLC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x11,  .speakers = { RRC,  RLC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x12,  .speakers = { RRC,  RLC,  RR,  RL,  FC,    0,  FR,  FL } },
+				 /* 7.1 */
+{ .ca_index = 0x13,  .speakers = { RRC,  RLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x14,  .speakers = { FRC,  FLC,   0,   0,   0,    0,  FR,  FL } },
+{ .ca_index = 0x15,  .speakers = { FRC,  FLC,   0,   0,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x16,  .speakers = { FRC,  FLC,   0,   0,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x17,  .speakers = { FRC,  FLC,   0,   0,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x18,  .speakers = { FRC,  FLC,   0,  RC,   0,    0,  FR,  FL } },
+{ .ca_index = 0x19,  .speakers = { FRC,  FLC,   0,  RC,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x1a,  .speakers = { FRC,  FLC,   0,  RC,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x1b,  .speakers = { FRC,  FLC,   0,  RC,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x1c,  .speakers = { FRC,  FLC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x1d,  .speakers = { FRC,  FLC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x1e,  .speakers = { FRC,  FLC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x1f,  .speakers = { FRC,  FLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x20,  .speakers = {   0,  FCH,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x21,  .speakers = {   0,  FCH,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x22,  .speakers = {  TC,    0,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x23,  .speakers = {  TC,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x24,  .speakers = { FRH,  FLH,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x25,  .speakers = { FRH,  FLH,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x26,  .speakers = { FRW,  FLW,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x27,  .speakers = { FRW,  FLW,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x28,  .speakers = {  TC,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x29,  .speakers = {  TC,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x2a,  .speakers = { FCH,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x2b,  .speakers = { FCH,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x2c,  .speakers = {  TC,  FCH,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x2d,  .speakers = {  TC,  FCH,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x2e,  .speakers = { FRH,  FLH,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x2f,  .speakers = { FRH,  FLH,  RR,  RL,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x30,  .speakers = { FRW,  FLW,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x31,  .speakers = { FRW,  FLW,  RR,  RL,  FC,  LFE,  FR,  FL } },
+};
+
+/*
+ * HDMI routines
+ */
+
+#ifdef BE_PARANOID
+static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid,
+				int *packet_index, int *byte_index)
+{
+	int val;
+
+	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0);
+
+	*packet_index = val >> 5;
+	*byte_index = val & 0x1f;
+}
+#endif
+
+static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid,
+				int packet_index, int byte_index)
+{
+	int val;
+
+	val = (packet_index << 5) | (byte_index & 0x1f);
+
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
+}
+
+static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid,
+				unsigned char val)
+{
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
+}
+
+static void hdmi_enable_output(struct hda_codec *codec)
+{
+	/* Enable Audio InfoFrame Transmission */
+	hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
+	snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+						AC_DIPXMIT_BEST);
+	/* Unmute */
+	if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
+		snd_hda_codec_write(codec, PIN_NID, 0,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+	/* Enable pin out */
+	snd_hda_sequence_write(codec, pinout_enable_verb);
+}
+
+static void hdmi_disable_output(struct hda_codec *codec)
+{
+	snd_hda_sequence_write(codec, pinout_disable_verb);
+	if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
+		snd_hda_codec_write(codec, PIN_NID, 0,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+	/*
+	 * FIXME: noises may arise when playing music after reloading the
+	 * kernel module, until the next X restart or monitor repower.
+	 */
+}
+
+static int hdmi_get_channel_count(struct hda_codec *codec)
+{
+	return 1 + snd_hda_codec_read(codec, CVT_NID, 0,
+					AC_VERB_GET_CVT_CHAN_COUNT, 0);
+}
+
+static void hdmi_set_channel_count(struct hda_codec *codec, int chs)
+{
+	snd_hda_codec_write(codec, CVT_NID, 0,
+					AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
+
+	if (chs != hdmi_get_channel_count(codec))
+		snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n",
+					chs, hdmi_get_channel_count(codec));
+}
+
+static void hdmi_debug_channel_mapping(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+	int i;
+	int slot;
+
+	for (i = 0; i < 8; i++) {
+		slot = snd_hda_codec_read(codec, CVT_NID, 0,
+						AC_VERB_GET_HDMI_CHAN_SLOT, i);
+		printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
+						slot >> 4, slot & 0x7);
+	}
+#endif
+}
+
+static void hdmi_parse_eld(struct hda_codec *codec)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+	struct hdmi_eld *eld = &spec->sink_eld;
+
+	if (!snd_hdmi_get_eld(eld, codec, PIN_NID))
+		snd_hdmi_show_eld(eld);
+}
+
+
+/*
+ * Audio InfoFrame routines
+ */
+
+static void hdmi_debug_dip_size(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+	int i;
+	int size;
+
+	size = snd_hdmi_get_eld_size(codec, PIN_NID);
+	printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size);
+
+	for (i = 0; i < 8; i++) {
+		size = snd_hda_codec_read(codec, PIN_NID, 0,
+						AC_VERB_GET_HDMI_DIP_SIZE, i);
+		printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size);
+	}
+#endif
+}
+
+static void hdmi_clear_dip_buffers(struct hda_codec *codec)
+{
+#ifdef BE_PARANOID
+	int i, j;
+	int size;
+	int pi, bi;
+	for (i = 0; i < 8; i++) {
+		size = snd_hda_codec_read(codec, PIN_NID, 0,
+						AC_VERB_GET_HDMI_DIP_SIZE, i);
+		if (size == 0)
+			continue;
+
+		hdmi_set_dip_index(codec, PIN_NID, i, 0x0);
+		for (j = 1; j < 1000; j++) {
+			hdmi_write_dip_byte(codec, PIN_NID, 0x0);
+			hdmi_get_dip_index(codec, PIN_NID, &pi, &bi);
+			if (pi != i)
+				snd_printd(KERN_INFO "dip index %d: %d != %d\n",
+						bi, pi, i);
+			if (bi == 0) /* byte index wrapped around */
+				break;
+		}
+		snd_printd(KERN_INFO
+			"HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
+			i, size, j);
+	}
+#endif
+}
+
+static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
+					struct hdmi_audio_infoframe *ai)
+{
+	u8 *params = (u8 *)ai;
+	int i;
+
+	hdmi_debug_dip_size(codec);
+	hdmi_clear_dip_buffers(codec); /* be paranoid */
+
+	hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
+	for (i = 0; i < sizeof(ai); i++)
+		hdmi_write_dip_byte(codec, PIN_NID, params[i]);
+}
+
+/*
+ * Compute derived values in channel_allocations[].
+ */
+static void init_channel_allocations(void)
+{
+	int i, j;
+	struct cea_channel_speaker_allocation *p;
+
+	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+		p = channel_allocations + i;
+		p->channels = 0;
+		p->spk_mask = 0;
+		for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
+			if (p->speakers[j]) {
+				p->channels++;
+				p->spk_mask |= p->speakers[j];
+			}
+	}
+}
+
+/*
+ * The transformation takes two steps:
+ *
+ * 	eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
+ * 	      spk_mask => (channel_allocations[])         => ai->CA
+ *
+ * TODO: it could select the wrong CA from multiple candidates.
+*/
+static int hdmi_setup_channel_allocation(struct hda_codec *codec,
+					 struct hdmi_audio_infoframe *ai)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+	struct hdmi_eld *eld = &spec->sink_eld;
+	int i;
+	int spk_mask = 0;
+	int channels = 1 + (ai->CC02_CT47 & 0x7);
+	char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+
+	/*
+	 * CA defaults to 0 for basic stereo audio
+	 */
+	if (!eld->eld_ver)
+		return 0;
+	if (!eld->spk_alloc)
+		return 0;
+	if (channels <= 2)
+		return 0;
+
+	/*
+	 * expand ELD's speaker allocation mask
+	 *
+	 * ELD tells the speaker mask in a compact(paired) form,
+	 * expand ELD's notions to match the ones used by Audio InfoFrame.
+	 */
+	for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
+		if (eld->spk_alloc & (1 << i))
+			spk_mask |= eld_speaker_allocation_bits[i];
+	}
+
+	/* search for the first working match in the CA table */
+	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+		if (channels == channel_allocations[i].channels &&
+		    (spk_mask & channel_allocations[i].spk_mask) ==
+				channel_allocations[i].spk_mask) {
+			ai->CA = channel_allocations[i].ca_index;
+			break;
+		}
+	}
+
+	snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
+	snd_printdd(KERN_INFO
+			"HDMI: select CA 0x%x for %d-channel allocation: %s\n",
+			ai->CA, channels, buf);
+
+	return ai->CA;
+}
+
+static void hdmi_setup_channel_mapping(struct hda_codec *codec,
+					struct hdmi_audio_infoframe *ai)
+{
+	if (!ai->CA)
+		return;
+
+	/*
+	 * TODO: adjust channel mapping if necessary
+	 * ALSA sequence is front/surr/clfe/side?
+	 */
+
+	snd_hda_sequence_write(codec, def_chan_map);
+	hdmi_debug_channel_mapping(codec);
+}
+
+
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
+{
+	struct hdmi_audio_infoframe ai = {
+		.type		= 0x84,
+		.ver		= 0x01,
+		.len		= 0x0a,
+		.CC02_CT47	= substream->runtime->channels - 1,
+	};
+
+	hdmi_setup_channel_allocation(codec, &ai);
+	hdmi_setup_channel_mapping(codec, &ai);
+
+	hdmi_fill_audio_infoframe(codec, &ai);
+}
+
+
+/*
+ * Unsolicited events
+ */
+
+static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
+	int pind = !!(res & AC_UNSOL_RES_PD);
+	int eldv = !!(res & AC_UNSOL_RES_ELDV);
+
+	printk(KERN_INFO
+		"HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n",
+		pind, eldv);
+
+	if (pind && eldv) {
+		hdmi_parse_eld(codec);
+		/* TODO: do real things about ELD */
+	}
+}
+
+static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
+	int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+	int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
+	int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
+
+	printk(KERN_INFO
+		"HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+		subtag,
+		cp_state,
+		cp_ready);
+
+	/* TODO */
+	if (cp_state)
+		;
+	if (cp_ready)
+		;
+}
+
+
+static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+	int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+
+	if (tag != INTEL_HDMI_EVENT_TAG) {
+		snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
+		return;
+	}
+
+	if (subtag == 0)
+		hdmi_intrinsic_event(codec, res);
+	else
+		hdmi_non_intrinsic_event(codec, res);
+}
+
+/*
+ * Callbacks
+ */
+
+static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 struct snd_pcm_substream *substream)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+
+	hdmi_disable_output(codec);
+
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					   struct hda_codec *codec,
+					   unsigned int stream_tag,
+					   unsigned int format,
+					   struct snd_pcm_substream *substream)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+
+	snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+					     format, substream);
+
+	hdmi_set_channel_count(codec, substream->runtime->channels);
+
+	hdmi_setup_audio_infoframe(codec, substream);
+
+	hdmi_enable_output(codec);
+
+	return 0;
+}
+
+static struct hda_pcm_stream intel_hdmi_pcm_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 8,
+	.nid = CVT_NID, /* NID to query formats and rates and setup streams */
+	.ops = {
+		.open    = intel_hdmi_playback_pcm_open,
+		.close   = intel_hdmi_playback_pcm_close,
+		.prepare = intel_hdmi_playback_pcm_prepare
+	},
+};
+
+static int intel_hdmi_build_pcms(struct hda_codec *codec)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+	struct hda_pcm *info = &spec->pcm_rec;
+
+	codec->num_pcms = 1;
+	codec->pcm_info = info;
+
+	info->name = "INTEL HDMI";
+	info->pcm_type = HDA_PCM_TYPE_HDMI;
+	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback;
+
+	return 0;
+}
+
+static int intel_hdmi_build_controls(struct hda_codec *codec)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+	int err;
+
+	err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int intel_hdmi_init(struct hda_codec *codec)
+{
+	/* disable audio output as early as possible */
+	hdmi_disable_output(codec);
+
+	snd_hda_sequence_write(codec, unsolicited_response_verb);
+
+	return 0;
+}
+
+static void intel_hdmi_free(struct hda_codec *codec)
+{
+	struct intel_hdmi_spec *spec = codec->spec;
+
+	snd_hda_eld_proc_free(codec, &spec->sink_eld);
+	kfree(spec);
+}
+
+static struct hda_codec_ops intel_hdmi_patch_ops = {
+	.init			= intel_hdmi_init,
+	.free			= intel_hdmi_free,
+	.build_pcms		= intel_hdmi_build_pcms,
+	.build_controls 	= intel_hdmi_build_controls,
+	.unsol_event		= intel_hdmi_unsol_event,
+};
+
+static int patch_intel_hdmi(struct hda_codec *codec)
+{
+	struct intel_hdmi_spec *spec;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	spec->multiout.num_dacs = 0;	  /* no analog */
+	spec->multiout.max_channels = 8;
+	spec->multiout.dig_out_nid = CVT_NID;
+
+	codec->spec = spec;
+	codec->patch_ops = intel_hdmi_patch_ops;
+
+	snd_hda_eld_proc_new(codec, &spec->sink_eld);
+
+	init_channel_allocations();
+
+	return 0;
+}
+
+static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
+	{ .id = 0x808629fb, .name = "G45 DEVCL",  .patch = patch_intel_hdmi },
+	{ .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi },
+	{ .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi },
+	{ .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi },
+	{ .id = 0x10951392, .name = "SiI1392 HDMI",     .patch = patch_intel_hdmi },
+	{} /* terminator */
+};
+
+MODULE_ALIAS("snd-hda-codec-id:808629fb");
+MODULE_ALIAS("snd-hda-codec-id:80862801");
+MODULE_ALIAS("snd-hda-codec-id:80862802");
+MODULE_ALIAS("snd-hda-codec-id:80862803");
+MODULE_ALIAS("snd-hda-codec-id:10951392");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel HDMI HD-audio codec");
+
+static struct hda_codec_preset_list intel_list = {
+	.preset = snd_hda_preset_intelhdmi,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_intelhdmi_init(void)
+{
+	return snd_hda_add_codec_preset(&intel_list);
+}
+
+static void __exit patch_intelhdmi_exit(void)
+{
+	snd_hda_delete_codec_preset(&intel_list);
+}
+
+module_init(patch_intelhdmi_init)
+module_exit(patch_intelhdmi_exit)

+ 29 - 3
sound/pci/hda/patch_nvhdmi.c

@@ -158,8 +158,34 @@ static int patch_nvhdmi(struct hda_codec *codec)
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
-	{ .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi },
-	{ .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi },
+static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
+	{ .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi },
+	{ .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi },
+	{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi },
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:10de0002");
+MODULE_ALIAS("snd-hda-codec-id:10de0007");
+MODULE_ALIAS("snd-hda-codec-id:10de0067");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec");
+
+static struct hda_codec_preset_list nvhdmi_list = {
+	.preset = snd_hda_preset_nvhdmi,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_nvhdmi_init(void)
+{
+	return snd_hda_add_codec_preset(&nvhdmi_list);
+}
+
+static void __exit patch_nvhdmi_exit(void)
+{
+	snd_hda_delete_codec_preset(&nvhdmi_list);
+}
+
+module_init(patch_nvhdmi_init)
+module_exit(patch_nvhdmi_exit)

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


+ 33 - 2
sound/pci/hda/patch_si3054.c

@@ -28,7 +28,6 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 /* si3054 verbs */
 #define SI3054_VERB_READ_NODE  0x900
@@ -283,7 +282,7 @@ static int patch_si3054(struct hda_codec *codec)
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_si3054[] = {
+static struct hda_codec_preset snd_hda_preset_si3054[] = {
  	{ .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
@@ -301,3 +300,35 @@ struct hda_codec_preset snd_hda_preset_si3054[] = {
 	{}
 };
 
+MODULE_ALIAS("snd-hda-codec-id:163c3055");
+MODULE_ALIAS("snd-hda-codec-id:163c3155");
+MODULE_ALIAS("snd-hda-codec-id:11c13026");
+MODULE_ALIAS("snd-hda-codec-id:11c13055");
+MODULE_ALIAS("snd-hda-codec-id:11c13155");
+MODULE_ALIAS("snd-hda-codec-id:10573055");
+MODULE_ALIAS("snd-hda-codec-id:10573057");
+MODULE_ALIAS("snd-hda-codec-id:10573155");
+MODULE_ALIAS("snd-hda-codec-id:11063288");
+MODULE_ALIAS("snd-hda-codec-id:15433155");
+MODULE_ALIAS("snd-hda-codec-id:18540018");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
+
+static struct hda_codec_preset_list si3054_list = {
+	.preset = snd_hda_preset_si3054,
+	.owner = THIS_MODULE,
+};
+
+static int __init patch_si3054_init(void)
+{
+	return snd_hda_add_codec_preset(&si3054_list);
+}
+
+static void __exit patch_si3054_exit(void)
+{
+	snd_hda_delete_codec_preset(&si3054_list);
+}
+
+module_init(patch_si3054_init)
+module_exit(patch_si3054_exit)

File diff suppressed because it is too large
+ 342 - 273
sound/pci/hda/patch_sigmatel.c


+ 90 - 81
sound/pci/hda/patch_via.c

@@ -47,15 +47,11 @@
 #include <sound/asoundef.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 
 /* amp values */
 #define AMP_VAL_IDX_SHIFT	19
 #define AMP_VAL_IDX_MASK	(0x0f<<19)
 
-#define NUM_CONTROL_ALLOC	32
-#define NUM_VERB_ALLOC		32
-
 /* Pin Widget NID */
 #define VT1708_HP_NID		0x13
 #define VT1708_DIGOUT_NID	0x14
@@ -145,8 +141,6 @@ enum {
 	AUTO_SEQ_SIDE
 };
 
-#define get_amp_nid(kc)	((kc)->private_value & 0xffff)
-
 /* Some VT1708S based boards gets the micboost setting wrong, so we have
  * to apply some brute-force and re-write the TLV's by software. */
 static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag,
@@ -227,8 +221,7 @@ struct via_spec {
 
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
-	unsigned int num_kctl_alloc, num_kctl_used;
-	struct snd_kcontrol_new *kctl_alloc;
+	struct snd_array kctls;
 	struct hda_input_mux private_imux[2];
 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
@@ -272,33 +265,31 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
 {
 	struct snd_kcontrol_new *knew;
 
-	if (spec->num_kctl_used >= spec->num_kctl_alloc) {
-		int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
-
-		/* array + terminator */
-		knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
-		if (!knew)
-			return -ENOMEM;
-		if (spec->kctl_alloc) {
-			memcpy(knew, spec->kctl_alloc,
-			       sizeof(*knew) * spec->num_kctl_alloc);
-			kfree(spec->kctl_alloc);
-		}
-		spec->kctl_alloc = knew;
-		spec->num_kctl_alloc = num;
-	}
-
-	knew = &spec->kctl_alloc[spec->num_kctl_used];
+	snd_array_init(&spec->kctls, sizeof(*knew), 32);
+	knew = snd_array_new(&spec->kctls);
+	if (!knew)
+		return -ENOMEM;
 	*knew = vt1708_control_templates[type];
 	knew->name = kstrdup(name, GFP_KERNEL);
-
 	if (!knew->name)
 		return -ENOMEM;
 	knew->private_value = val;
-	spec->num_kctl_used++;
 	return 0;
 }
 
+static void via_free_kctls(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+
+	if (spec->kctls.list) {
+		struct snd_kcontrol_new *kctl = spec->kctls.list;
+		int i;
+		for (i = 0; i < spec->kctls.used; i++)
+			kfree(kctl[i].name);
+	}
+	snd_array_free(&spec->kctls);
+}
+
 /* create input playback/capture controls for the given pin */
 static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
 				const char *ctlname, int idx, int mix_nid)
@@ -896,6 +887,7 @@ static int via_build_controls(struct hda_codec *codec)
 		if (err < 0)
 			return err;
 	}
+	via_free_kctls(codec); /* no longer needed */
 	return 0;
 }
 
@@ -941,17 +933,11 @@ static int via_build_pcms(struct hda_codec *codec)
 static void via_free(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
-	unsigned int i;
 
 	if (!spec)
 		return;
 
-	if (spec->kctl_alloc) {
-		for (i = 0; i < spec->num_kctl_used; i++)
-			kfree(spec->kctl_alloc[i].name);
-		kfree(spec->kctl_alloc);
-	}
-
+	via_free_kctls(codec);
 	kfree(codec->spec);
 }
 
@@ -1373,8 +1359,8 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = VT1708_DIGIN_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
 
@@ -1846,8 +1832,8 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = VT1709_DIGIN_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->input_mux = &spec->private_imux[0];
 
@@ -2390,8 +2376,8 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
 	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = VT1708B_DIGIN_NID;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->input_mux = &spec->private_imux[0];
 
@@ -2855,8 +2841,8 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
 
 	spec->extra_dig_out_nid = 0x15;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->input_mux = &spec->private_imux[0];
 
@@ -3174,8 +3160,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
 
 	spec->extra_dig_out_nid = 0x1B;
 
-	if (spec->kctl_alloc)
-		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+	if (spec->kctls.list)
+		spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
 	spec->input_mux = &spec->private_imux[0];
 
@@ -3262,74 +3248,97 @@ static int patch_vt1702(struct hda_codec *codec)
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_via[] = {
-	{ .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
-	{ .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
-	{ .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
-	{ .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
-	{ .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
+static struct hda_codec_preset snd_hda_preset_via[] = {
+	{ .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
+	{ .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
+	{ .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
+	{ .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
+	{ .id = 0x1106e710, .name = "VT1709 10-Ch",
 	  .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
+	{ .id = 0x1106e711, .name = "VT1709 10-Ch",
 	  .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
+	{ .id = 0x1106e712, .name = "VT1709 10-Ch",
 	  .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
+	{ .id = 0x1106e713, .name = "VT1709 10-Ch",
 	  .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
+	{ .id = 0x1106e714, .name = "VT1709 6-Ch",
 	  .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
+	{ .id = 0x1106e715, .name = "VT1709 6-Ch",
 	  .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
+	{ .id = 0x1106e716, .name = "VT1709 6-Ch",
 	  .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
+	{ .id = 0x1106e717, .name = "VT1709 6-Ch",
 	  .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
+	{ .id = 0x1106e720, .name = "VT1708B 8-Ch",
 	  .patch = patch_vt1708B_8ch},
-	{ .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
+	{ .id = 0x1106e721, .name = "VT1708B 8-Ch",
 	  .patch = patch_vt1708B_8ch},
-	{ .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
+	{ .id = 0x1106e722, .name = "VT1708B 8-Ch",
 	  .patch = patch_vt1708B_8ch},
-	{ .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
+	{ .id = 0x1106e723, .name = "VT1708B 8-Ch",
 	  .patch = patch_vt1708B_8ch},
-	{ .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
+	{ .id = 0x1106e724, .name = "VT1708B 4-Ch",
 	  .patch = patch_vt1708B_4ch},
-	{ .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
+	{ .id = 0x1106e725, .name = "VT1708B 4-Ch",
 	  .patch = patch_vt1708B_4ch},
-	{ .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
+	{ .id = 0x1106e726, .name = "VT1708B 4-Ch",
 	  .patch = patch_vt1708B_4ch},
-	{ .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
+	{ .id = 0x1106e727, .name = "VT1708B 4-Ch",
 	  .patch = patch_vt1708B_4ch},
-	{ .id = 0x11060397, .name = "VIA VT1708S",
+	{ .id = 0x11060397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11061397, .name = "VIA VT1708S",
+	{ .id = 0x11061397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11062397, .name = "VIA VT1708S",
+	{ .id = 0x11062397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11063397, .name = "VIA VT1708S",
+	{ .id = 0x11063397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11064397, .name = "VIA VT1708S",
+	{ .id = 0x11064397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11065397, .name = "VIA VT1708S",
+	{ .id = 0x11065397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11066397, .name = "VIA VT1708S",
+	{ .id = 0x11066397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11067397, .name = "VIA VT1708S",
+	{ .id = 0x11067397, .name = "VT1708S",
 	  .patch = patch_vt1708S},
-	{ .id = 0x11060398, .name = "VIA VT1702",
+	{ .id = 0x11060398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11061398, .name = "VIA VT1702",
+	{ .id = 0x11061398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11062398, .name = "VIA VT1702",
+	{ .id = 0x11062398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11063398, .name = "VIA VT1702",
+	{ .id = 0x11063398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11064398, .name = "VIA VT1702",
+	{ .id = 0x11064398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11065398, .name = "VIA VT1702",
+	{ .id = 0x11065398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11066398, .name = "VIA VT1702",
+	{ .id = 0x11066398, .name = "VT1702",
 	  .patch = patch_vt1702},
-	{ .id = 0x11067398, .name = "VIA VT1702",
+	{ .id = 0x11067398, .name = "VT1702",
 	  .patch = patch_vt1702},
 	{} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:1106*");
+
+static struct hda_codec_preset_list via_list = {
+	.preset = snd_hda_preset_via,
+	.owner = THIS_MODULE,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VIA HD-audio codec");
+
+static int __init patch_via_init(void)
+{
+	return snd_hda_add_codec_preset(&via_list);
+}
+
+static void __exit patch_via_exit(void)
+{
+	snd_hda_delete_codec_preset(&via_list);
+}
+
+module_init(patch_via_init)
+module_exit(patch_via_exit)

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