Merge branch 'topic/hda' into to-push

This commit is contained in:
Takashi Iwai 2008-12-25 11:40:28 +01:00
commit a65056205c
30 changed files with 5773 additions and 2361 deletions

View file

@ -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

View 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

View 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.

View file

@ -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
---------------------

View file

@ -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)

View file

@ -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 {

View file

@ -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);

View file

@ -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
View 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

View file

@ -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

View file

@ -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

View file

@ -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
View 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 */

View file

@ -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);

View file

@ -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 */

View file

@ -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
};

View file

@ -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 */

View file

@ -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[];

View file

@ -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);
}

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View 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)

View file

@ -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

View file

@ -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

View file

@ -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)