mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
Merge branch 'topic/hda' into to-push
This commit is contained in:
commit
a65056205c
30 changed files with 5773 additions and 2361 deletions
|
@ -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
Documentation/sound/alsa/HD-Audio-Models.txt
Normal file
348
Documentation/sound/alsa/HD-Audio-Models.txt
Normal file
|
@ -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
Documentation/sound/alsa/HD-Audio.txt
Normal file
577
Documentation/sound/alsa/HD-Audio.txt
Normal file
|
@ -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.
|
|
@ -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
|
||||
---------------------
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
sound/pci/hda/Kconfig
Normal file
188
sound/pci/hda/Kconfig
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
Load diff
|
@ -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
sound/pci/hda/hda_eld.c
Normal file
590
sound/pci/hda/hda_eld.c
Normal file
|
@ -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 */
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
struct azx *chip = bus->private_data;
|
||||
|
||||
val = (u32)(codec->addr & 0x0f) << 28;
|
||||
val |= (u32)direct << 27;
|
||||
val |= (u32)nid << 20;
|
||||
val |= verb << 8;
|
||||
val |= para;
|
||||
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
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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[];
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_kctls(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_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);
|
||||
}
|
||||
|
||||
static void ad198x_free(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)
|
||||
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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
sound/pci/hda/patch_intelhdmi.c
Normal file
711
sound/pci/hda/patch_intelhdmi.c
Normal file
|
@ -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)
|
|
@ -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
Load diff
|
@ -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
Load diff
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue