mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 19:26:25 +00:00
Merge branch 'topic/hda' into for-linus
* topic/hda: (92 commits) ALSA: hda - Use auto model for HP laptops with ALC268 codec ALSA: hda/realtek: Added support for CLEVO M540R subsystem, 6 channel + digital ALSA: hda - Add support of Alienware M17x laptop ALSA: hda - Remove dead codes from patch_sigmatel.c ALSA: hda - Fix input source selection of IDT92HD73xx ALSA: hda - Fix obsolete CONFIG_SND_DEBUG_DETECT ALSA: hda - Unmute docking line-out as default with AD1984A codec ALSA: hda - Add another entry for Nvidia HDMI device ALSA: hda - Add missing GPIO initialization for AD1984A laptop model ALSA: hda - Add support of docking auto-mute/mic for AD1984A laptop model ALSA: hda - Fix ALC268/ALC269 headphone pin routing ALSA: hda - Create "Digital Mic Capture Volume" correctly for IDT codecs ALSA: hda - Add more quirk for HP laptops with AD1984A ALSA: hda - Add / fix model entries for HD-audio driver ALSA: hda - Add full audio support on Acer Aspire 7730G notebook ALSA: hda - Improve auto-cfg mixer name for ALC662 ALSA: hda - Improve auto-cfg mixer name for ALC861-VD ALSA: hda - Improve auto-cfg mixer name for ALC262 ALSA: hda - Improve auto-cfg mixer name for ALC260 ALSA: hda - Improve auto-cfg mixer name for ALC880 ...
This commit is contained in:
commit
2d4ff66ad7
24 changed files with 4937 additions and 2928 deletions
|
@ -788,6 +788,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
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.
|
||||
patch - Specifies the early "patch" files to modify the HD-audio
|
||||
setup before initializing the codecs. This option is
|
||||
available only when CONFIG_SND_HDA_PATCH_LOADER=y is set.
|
||||
See HD-Audio.txt for details.
|
||||
|
||||
[Single (global) options]
|
||||
single_cmd - Use single immediate commands to communicate with
|
||||
|
|
|
@ -114,8 +114,8 @@ ALC662/663/272
|
|||
samsung-nc10 Samsung NC10 mini notebook
|
||||
auto auto-config reading BIOS (default)
|
||||
|
||||
ALC882/885
|
||||
==========
|
||||
ALC882/883/885/888/889
|
||||
======================
|
||||
3stack-dig 3-jack with SPDIF I/O
|
||||
6stack-dig 6-jack digital with SPDIF I/O
|
||||
arima Arima W820Di1
|
||||
|
@ -127,12 +127,8 @@ ALC882/885
|
|||
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-2ch-dig 3-jack with SPDIF I/O (ALC883)
|
||||
alc883-6stack-dig 6-jack digital with SPDIF I/O (ALC883)
|
||||
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
|
||||
|
@ -140,6 +136,7 @@ ALC883/888
|
|||
acer-aspire Acer Aspire 9810
|
||||
acer-aspire-4930g Acer Aspire 4930G
|
||||
acer-aspire-6530g Acer Aspire 6530G
|
||||
acer-aspire-7730g Acer Aspire 7730G
|
||||
acer-aspire-8930g Acer Aspire 8930G
|
||||
medion Medion Laptops
|
||||
medion-md2 Medion MD2
|
||||
|
@ -155,10 +152,13 @@ ALC883/888
|
|||
3stack-hp HP machines with 3stack (Lucknow, Samba boards)
|
||||
6stack-dell Dell machines with 6stack (Inspiron 530)
|
||||
mitac Mitac 8252D
|
||||
clevo-m540r Clevo M540R (6ch + digital)
|
||||
clevo-m720 Clevo M720 laptop series
|
||||
fujitsu-pi2515 Fujitsu AMILO Pi2515
|
||||
fujitsu-xa3530 Fujitsu AMILO XA3530
|
||||
3stack-6ch-intel Intel DG33* boards
|
||||
intel-alc889a Intel IbexPeak with ALC889A
|
||||
intel-x58 Intel DX58 with ALC889
|
||||
asus-p5q ASUS P5Q-EM boards
|
||||
mb31 MacBook 3,1
|
||||
sony-vaio-tt Sony VAIO TT
|
||||
|
@ -229,7 +229,7 @@ AD1984
|
|||
======
|
||||
basic default configuration
|
||||
thinkpad Lenovo Thinkpad T61/X61
|
||||
dell Dell T3400
|
||||
dell_desktop Dell T3400
|
||||
|
||||
AD1986A
|
||||
=======
|
||||
|
@ -258,6 +258,7 @@ Conexant 5045
|
|||
laptop-micsense Laptop with Mic sense (old model fujitsu)
|
||||
laptop-hpmicsense Laptop with HP and Mic senses
|
||||
benq Benq R55E
|
||||
laptop-hp530 HP 530 laptop
|
||||
test for testing/debugging purpose, almost all controls
|
||||
can be adjusted. Appearing only when compiled with
|
||||
$CONFIG_SND_DEBUG=y
|
||||
|
@ -278,9 +279,16 @@ Conexant 5051
|
|||
hp-dv6736 HP dv6736
|
||||
lenovo-x200 Lenovo X200 laptop
|
||||
|
||||
Conexant 5066
|
||||
=============
|
||||
laptop Basic Laptop config (default)
|
||||
dell-laptop Dell laptops
|
||||
olpc-xo-1_5 OLPC XO 1.5
|
||||
|
||||
STAC9200
|
||||
========
|
||||
ref Reference board
|
||||
oqo OQO Model 2
|
||||
dell-d21 Dell (unknown)
|
||||
dell-d22 Dell (unknown)
|
||||
dell-d23 Dell (unknown)
|
||||
|
@ -368,10 +376,12 @@ STAC92HD73*
|
|||
===========
|
||||
ref Reference board
|
||||
no-jd BIOS setup but without jack-detection
|
||||
intel Intel DG45* mobos
|
||||
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
|
||||
dell-eq Dell desktops/laptops
|
||||
alienware Alienware M17x
|
||||
auto BIOS setup (default)
|
||||
|
||||
STAC92HD83*
|
||||
|
@ -385,3 +395,8 @@ STAC9872
|
|||
========
|
||||
vaio VAIO laptop without SPDIF
|
||||
auto BIOS setup (default)
|
||||
|
||||
Cirrus Logic CS4206/4207
|
||||
========================
|
||||
mbp55 MacBook Pro 5,5
|
||||
auto BIOS setup (default)
|
||||
|
|
|
@ -138,6 +138,10 @@ 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: ALC880: BIOS auto-probing.
|
||||
------------------------------------------------------------------------
|
||||
Meanwhile, in the earlier versions, you would see a message like:
|
||||
------------------------------------------------------------------------
|
||||
hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...
|
||||
------------------------------------------------------------------------
|
||||
|
@ -403,6 +407,66 @@ re-configure based on that state, run like below:
|
|||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
Early Patching
|
||||
~~~~~~~~~~~~~~
|
||||
When CONFIG_SND_HDA_PATCH_LOADER=y is set, you can pass a "patch" as a
|
||||
firmware file for modifying the HD-audio setup before initializing the
|
||||
codec. This can work basically like the reconfiguration via sysfs in
|
||||
the above, but it does it before the first codec configuration.
|
||||
|
||||
A patch file is a plain text file which looks like below:
|
||||
|
||||
------------------------------------------------------------------------
|
||||
[codec]
|
||||
0x12345678 0xabcd1234 2
|
||||
|
||||
[model]
|
||||
auto
|
||||
|
||||
[pincfg]
|
||||
0x12 0x411111f0
|
||||
|
||||
[verb]
|
||||
0x20 0x500 0x03
|
||||
0x20 0x400 0xff
|
||||
|
||||
[hint]
|
||||
hp_detect = yes
|
||||
------------------------------------------------------------------------
|
||||
|
||||
The file needs to have a line `[codec]`. The next line should contain
|
||||
three numbers indicating the codec vendor-id (0x12345678 in the
|
||||
example), the codec subsystem-id (0xabcd1234) and the address (2) of
|
||||
the codec. The rest patch entries are applied to this specified codec
|
||||
until another codec entry is given.
|
||||
|
||||
The `[model]` line allows to change the model name of the each codec.
|
||||
In the example above, it will be changed to model=auto.
|
||||
Note that this overrides the module option.
|
||||
|
||||
After the `[pincfg]` line, the contents are parsed as the initial
|
||||
default pin-configurations just like `user_pin_configs` sysfs above.
|
||||
The values can be shown in user_pin_configs sysfs file, too.
|
||||
|
||||
Similarly, the lines after `[verb]` are parsed as `init_verbs`
|
||||
sysfs entries, and the lines after `[hint]` are parsed as `hints`
|
||||
sysfs entries, respectively.
|
||||
|
||||
The hd-audio driver reads the file via request_firmware(). Thus,
|
||||
a patch file has to be located on the appropriate firmware path,
|
||||
typically, /lib/firmware. For example, when you pass the option
|
||||
`patch=hda-init.fw`, the file /lib/firmware/hda-init-fw must be
|
||||
present.
|
||||
|
||||
The patch module option is specific to each card instance, and you
|
||||
need to give one file name for each instance, separated by commas.
|
||||
For example, if you have two cards, one for an on-board analog and one
|
||||
for an HDMI video board, you may pass patch option like below:
|
||||
------------------------------------------------------------------------
|
||||
options snd-hda-intel patch=on-board-patch,hdmi-patch
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
Power-Saving
|
||||
~~~~~~~~~~~~
|
||||
The power-saving is a kind of auto-suspend of the device. When the
|
||||
|
|
|
@ -46,6 +46,20 @@ config SND_HDA_INPUT_JACK
|
|||
Say Y here to enable the jack plugging notification via
|
||||
input layer.
|
||||
|
||||
config SND_HDA_PATCH_LOADER
|
||||
bool "Support initialization patch loading for HD-audio"
|
||||
depends on EXPERIMENTAL
|
||||
select FW_LOADER
|
||||
select SND_HDA_HWDEP
|
||||
select SND_HDA_RECONFIG
|
||||
help
|
||||
Say Y here to allow the HD-audio driver to load a pseudo
|
||||
firmware file ("patch") for overriding the BIOS setup at
|
||||
start up. The "patch" file can be specified via patch module
|
||||
option, such as patch=hda-init.
|
||||
|
||||
This option turns on hwdep and reconfig features automatically.
|
||||
|
||||
config SND_HDA_CODEC_REALTEK
|
||||
bool "Build Realtek HD-audio codec support"
|
||||
default y
|
||||
|
@ -134,6 +148,19 @@ config SND_HDA_ELD
|
|||
def_bool y
|
||||
depends on SND_HDA_CODEC_INTELHDMI
|
||||
|
||||
config SND_HDA_CODEC_CIRRUS
|
||||
bool "Build Cirrus Logic codec support"
|
||||
depends on SND_HDA_INTEL
|
||||
default y
|
||||
help
|
||||
Say Y here to include Cirrus Logic codec support in
|
||||
snd-hda-intel driver, such as CS4206.
|
||||
|
||||
When the HD-audio driver is built as a module, the codec
|
||||
support code is also built as another module,
|
||||
snd-hda-codec-cirrus.
|
||||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_CODEC_CONEXANT
|
||||
bool "Build Conexant HD-audio codec support"
|
||||
default y
|
||||
|
|
|
@ -13,6 +13,7 @@ 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-cirrus-objs := patch_cirrus.o
|
||||
snd-hda-codec-ca0110-objs := patch_ca0110.o
|
||||
snd-hda-codec-conexant-objs := patch_conexant.o
|
||||
snd-hda-codec-via-objs := patch_via.o
|
||||
|
@ -41,6 +42,9 @@ endif
|
|||
ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_CIRRUS
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
|
||||
endif
|
||||
ifdef CONFIG_SND_HDA_CODEC_CA0110
|
||||
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o
|
||||
endif
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_beep.h"
|
||||
#include "hda_local.h"
|
||||
|
||||
enum {
|
||||
DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */
|
||||
|
@ -118,6 +119,9 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
|
|||
struct hda_beep *beep;
|
||||
int err;
|
||||
|
||||
if (!snd_hda_get_bool_hint(codec, "beep"))
|
||||
return 0; /* disabled explicitly */
|
||||
|
||||
beep = kzalloc(sizeof(*beep), GFP_KERNEL);
|
||||
if (beep == NULL)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -44,6 +44,7 @@ struct hda_vendor_id {
|
|||
/* codec vendor labels */
|
||||
static struct hda_vendor_id hda_vendor_ids[] = {
|
||||
{ 0x1002, "ATI" },
|
||||
{ 0x1013, "Cirrus Logic" },
|
||||
{ 0x1057, "Motorola" },
|
||||
{ 0x1095, "Silicon Image" },
|
||||
{ 0x10de, "Nvidia" },
|
||||
|
@ -150,7 +151,14 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
|
|||
{
|
||||
u32 val;
|
||||
|
||||
val = (u32)(codec->addr & 0x0f) << 28;
|
||||
if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) ||
|
||||
(verb & ~0xfff) || (parm & ~0xffff)) {
|
||||
printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n",
|
||||
codec->addr, direct, nid, verb, parm);
|
||||
return ~0;
|
||||
}
|
||||
|
||||
val = (u32)codec->addr << 28;
|
||||
val |= (u32)direct << 27;
|
||||
val |= (u32)nid << 20;
|
||||
val |= verb << 8;
|
||||
|
@ -167,6 +175,9 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
|
|||
struct hda_bus *bus = codec->bus;
|
||||
int err;
|
||||
|
||||
if (cmd == ~0)
|
||||
return -1;
|
||||
|
||||
if (res)
|
||||
*res = -1;
|
||||
again:
|
||||
|
@ -291,11 +302,20 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
|||
unsigned int parm;
|
||||
int i, conn_len, conns;
|
||||
unsigned int shift, num_elems, mask;
|
||||
unsigned int wcaps;
|
||||
hda_nid_t prev_nid;
|
||||
|
||||
if (snd_BUG_ON(!conn_list || max_conns <= 0))
|
||||
return -EINVAL;
|
||||
|
||||
wcaps = get_wcaps(codec, nid);
|
||||
if (!(wcaps & AC_WCAP_CONN_LIST) &&
|
||||
get_wcaps_type(wcaps) != AC_WID_VOL_KNB) {
|
||||
snd_printk(KERN_WARNING "hda_codec: "
|
||||
"connection list not available for 0x%x\n", nid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
|
||||
if (parm & AC_CLIST_LONG) {
|
||||
/* long form */
|
||||
|
@ -316,6 +336,8 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
|||
/* single connection */
|
||||
parm = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_CONNECT_LIST, 0);
|
||||
if (parm == -1 && codec->bus->rirb_error)
|
||||
return -EIO;
|
||||
conn_list[0] = parm & mask;
|
||||
return 1;
|
||||
}
|
||||
|
@ -327,9 +349,12 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
|||
int range_val;
|
||||
hda_nid_t val, n;
|
||||
|
||||
if (i % num_elems == 0)
|
||||
if (i % num_elems == 0) {
|
||||
parm = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_CONNECT_LIST, i);
|
||||
if (parm == -1 && codec->bus->rirb_error)
|
||||
return -EIO;
|
||||
}
|
||||
range_val = !!(parm & (1 << (shift-1))); /* ranges */
|
||||
val = parm & mask;
|
||||
if (val == 0) {
|
||||
|
@ -727,8 +752,7 @@ static int read_pin_defaults(struct hda_codec *codec)
|
|||
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
||||
struct hda_pincfg *pin;
|
||||
unsigned int wcaps = get_wcaps(codec, nid);
|
||||
unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
|
||||
AC_WCAP_TYPE_SHIFT;
|
||||
unsigned int wid_type = get_wcaps_type(wcaps);
|
||||
if (wid_type != AC_WID_PIN)
|
||||
continue;
|
||||
pin = snd_array_new(&codec->init_pins);
|
||||
|
@ -891,7 +915,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
|||
* Returns 0 if successful, or a negative error code.
|
||||
*/
|
||||
int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
|
||||
int do_init, struct hda_codec **codecp)
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
struct hda_codec *codec;
|
||||
char component[31];
|
||||
|
@ -984,11 +1008,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
|
|||
codec->afg ? codec->afg : codec->mfg,
|
||||
AC_PWRST_D0);
|
||||
|
||||
if (do_init) {
|
||||
err = snd_hda_codec_configure(codec);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
snd_hda_codec_proc_new(codec);
|
||||
|
||||
snd_hda_create_hwdep(codec);
|
||||
|
@ -1042,6 +1061,7 @@ int snd_hda_codec_configure(struct hda_codec *codec)
|
|||
err = init_unsol_queue(codec->bus);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_codec_configure);
|
||||
|
||||
/**
|
||||
* snd_hda_codec_setup_stream - set up the codec for streaming
|
||||
|
@ -2356,16 +2376,20 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
|||
hda_nid_t nid;
|
||||
int i;
|
||||
|
||||
snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE,
|
||||
/* this delay seems necessary to avoid click noise at power-down */
|
||||
if (power_state == AC_PWRST_D3)
|
||||
msleep(100);
|
||||
snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
|
||||
power_state);
|
||||
msleep(10); /* partial workaround for "azx_get_response timeout" */
|
||||
/* partial workaround for "azx_get_response timeout" */
|
||||
if (power_state == AC_PWRST_D0)
|
||||
msleep(10);
|
||||
|
||||
nid = codec->start_nid;
|
||||
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
||||
unsigned int wcaps = get_wcaps(codec, nid);
|
||||
if (wcaps & AC_WCAP_POWER) {
|
||||
unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
|
||||
AC_WCAP_TYPE_SHIFT;
|
||||
unsigned int wid_type = get_wcaps_type(wcaps);
|
||||
if (power_state == AC_PWRST_D3 &&
|
||||
wid_type == AC_WID_PIN) {
|
||||
unsigned int pincap;
|
||||
|
@ -2573,7 +2597,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
|
|||
case 20:
|
||||
case 24:
|
||||
case 32:
|
||||
if (maxbps >= 32)
|
||||
if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE)
|
||||
val |= 0x40;
|
||||
else if (maxbps >= 24)
|
||||
val |= 0x30;
|
||||
|
@ -2700,11 +2724,12 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
|||
bps = 20;
|
||||
}
|
||||
}
|
||||
else if (streams == AC_SUPFMT_FLOAT32) {
|
||||
/* should be exclusive */
|
||||
if (streams & AC_SUPFMT_FLOAT32) {
|
||||
formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
|
||||
bps = 32;
|
||||
} else if (streams == AC_SUPFMT_AC3) {
|
||||
if (!bps)
|
||||
bps = 32;
|
||||
}
|
||||
if (streams == AC_SUPFMT_AC3) {
|
||||
/* should be exclusive */
|
||||
/* temporary hack: we have still no proper support
|
||||
* for the direct AC3 stream...
|
||||
|
@ -3102,7 +3127,7 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
|
|||
tbl = q;
|
||||
|
||||
if (tbl->value >= 0 && tbl->value < num_configs) {
|
||||
#ifdef CONFIG_SND_DEBUG_DETECT
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
char tmp[10];
|
||||
const char *model = NULL;
|
||||
if (models)
|
||||
|
@ -3655,8 +3680,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
end_nid = codec->start_nid + codec->num_nodes;
|
||||
for (nid = codec->start_nid; nid < end_nid; nid++) {
|
||||
unsigned int wid_caps = get_wcaps(codec, nid);
|
||||
unsigned int wid_type =
|
||||
(wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
|
||||
unsigned int wid_type = get_wcaps_type(wid_caps);
|
||||
unsigned int def_conf;
|
||||
short assoc, loc;
|
||||
|
||||
|
|
|
@ -830,7 +830,8 @@ 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,
|
||||
int do_init, struct hda_codec **codecp);
|
||||
struct hda_codec **codecp);
|
||||
int snd_hda_codec_configure(struct hda_codec *codec);
|
||||
|
||||
/*
|
||||
* low level functions
|
||||
|
@ -938,6 +939,13 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {}
|
|||
#define snd_hda_codec_needs_resume(codec) 1
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||
/*
|
||||
* patch firmware
|
||||
*/
|
||||
int snd_hda_load_patch(struct hda_bus *bus, const char *patch);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Codec modularization
|
||||
*/
|
||||
|
|
|
@ -121,11 +121,17 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
|
|||
if (node == NULL)
|
||||
return -ENOMEM;
|
||||
node->nid = nid;
|
||||
nconns = snd_hda_get_connections(codec, nid, conn_list,
|
||||
HDA_MAX_CONNECTIONS);
|
||||
if (nconns < 0) {
|
||||
kfree(node);
|
||||
return nconns;
|
||||
node->wid_caps = get_wcaps(codec, nid);
|
||||
node->type = get_wcaps_type(node->wid_caps);
|
||||
if (node->wid_caps & AC_WCAP_CONN_LIST) {
|
||||
nconns = snd_hda_get_connections(codec, nid, conn_list,
|
||||
HDA_MAX_CONNECTIONS);
|
||||
if (nconns < 0) {
|
||||
kfree(node);
|
||||
return nconns;
|
||||
}
|
||||
} else {
|
||||
nconns = 0;
|
||||
}
|
||||
if (nconns <= ARRAY_SIZE(node->slist))
|
||||
node->conn_list = node->slist;
|
||||
|
@ -140,8 +146,6 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
|
|||
}
|
||||
memcpy(node->conn_list, conn_list, nconns * sizeof(hda_nid_t));
|
||||
node->nconns = nconns;
|
||||
node->wid_caps = get_wcaps(codec, nid);
|
||||
node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
|
||||
|
||||
if (node->type == AC_WID_PIN) {
|
||||
node->pin_caps = snd_hda_query_pin_caps(codec, node->nid);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/compat.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
|
@ -312,12 +313,8 @@ static ssize_t init_verbs_show(struct device *dev,
|
|||
return len;
|
||||
}
|
||||
|
||||
static ssize_t init_verbs_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static int parse_init_verbs(struct hda_codec *codec, const char *buf)
|
||||
{
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||
struct hda_codec *codec = hwdep->private_data;
|
||||
struct hda_verb *v;
|
||||
int nid, verb, param;
|
||||
|
||||
|
@ -331,6 +328,18 @@ static ssize_t init_verbs_store(struct device *dev,
|
|||
v->nid = nid;
|
||||
v->verb = verb;
|
||||
v->param = param;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
int err = parse_init_verbs(codec, buf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -376,19 +385,15 @@ static void remove_trail_spaces(char *str)
|
|||
|
||||
#define MAX_HINTS 1024
|
||||
|
||||
static ssize_t hints_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static int parse_hints(struct hda_codec *codec, const char *buf)
|
||||
{
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||
struct hda_codec *codec = hwdep->private_data;
|
||||
char *key, *val;
|
||||
struct hda_hint *hint;
|
||||
|
||||
while (isspace(*buf))
|
||||
buf++;
|
||||
if (!*buf || *buf == '#' || *buf == '\n')
|
||||
return count;
|
||||
return 0;
|
||||
if (*buf == '=')
|
||||
return -EINVAL;
|
||||
key = kstrndup_noeol(buf, 1024);
|
||||
|
@ -411,7 +416,7 @@ static ssize_t hints_store(struct device *dev,
|
|||
kfree(hint->key);
|
||||
hint->key = key;
|
||||
hint->val = val;
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
/* allocate a new hint entry */
|
||||
if (codec->hints.used >= MAX_HINTS)
|
||||
|
@ -424,6 +429,18 @@ static ssize_t hints_store(struct device *dev,
|
|||
}
|
||||
hint->key = key;
|
||||
hint->val = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
int err = parse_hints(codec, buf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -469,20 +486,24 @@ static ssize_t driver_pin_configs_show(struct device *dev,
|
|||
|
||||
#define MAX_PIN_CONFIGS 32
|
||||
|
||||
static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
|
||||
{
|
||||
int nid, cfg;
|
||||
|
||||
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
|
||||
return -EINVAL;
|
||||
if (!nid)
|
||||
return -EINVAL;
|
||||
return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
|
||||
}
|
||||
|
||||
static ssize_t user_pin_configs_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 nid, cfg;
|
||||
int err;
|
||||
|
||||
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
|
||||
return -EINVAL;
|
||||
if (!nid)
|
||||
return -EINVAL;
|
||||
err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
|
||||
int err = parse_user_pin_configs(codec, buf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return count;
|
||||
|
@ -553,3 +574,180 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
|
|||
EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
|
||||
|
||||
#endif /* CONFIG_SND_HDA_RECONFIG */
|
||||
|
||||
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||
|
||||
/* parser mode */
|
||||
enum {
|
||||
LINE_MODE_NONE,
|
||||
LINE_MODE_CODEC,
|
||||
LINE_MODE_MODEL,
|
||||
LINE_MODE_PINCFG,
|
||||
LINE_MODE_VERB,
|
||||
LINE_MODE_HINT,
|
||||
NUM_LINE_MODES,
|
||||
};
|
||||
|
||||
static inline int strmatch(const char *a, const char *b)
|
||||
{
|
||||
return strnicmp(a, b, strlen(b)) == 0;
|
||||
}
|
||||
|
||||
/* parse the contents after the line "[codec]"
|
||||
* accept only the line with three numbers, and assign the current codec
|
||||
*/
|
||||
static void parse_codec_mode(char *buf, struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
unsigned int vendorid, subid, caddr;
|
||||
struct hda_codec *codec;
|
||||
|
||||
*codecp = NULL;
|
||||
if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
|
||||
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||
if (codec->addr == caddr) {
|
||||
*codecp = codec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* parse the contents after the other command tags, [pincfg], [verb],
|
||||
* [hint] and [model]
|
||||
* just pass to the sysfs helper (only when any codec was specified)
|
||||
*/
|
||||
static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
if (!*codecp)
|
||||
return;
|
||||
parse_user_pin_configs(*codecp, buf);
|
||||
}
|
||||
|
||||
static void parse_verb_mode(char *buf, struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
if (!*codecp)
|
||||
return;
|
||||
parse_init_verbs(*codecp, buf);
|
||||
}
|
||||
|
||||
static void parse_hint_mode(char *buf, struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
if (!*codecp)
|
||||
return;
|
||||
parse_hints(*codecp, buf);
|
||||
}
|
||||
|
||||
static void parse_model_mode(char *buf, struct hda_bus *bus,
|
||||
struct hda_codec **codecp)
|
||||
{
|
||||
if (!*codecp)
|
||||
return;
|
||||
kfree((*codecp)->modelname);
|
||||
(*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
|
||||
}
|
||||
|
||||
struct hda_patch_item {
|
||||
const char *tag;
|
||||
void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
|
||||
};
|
||||
|
||||
static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
|
||||
[LINE_MODE_CODEC] = { "[codec]", parse_codec_mode },
|
||||
[LINE_MODE_MODEL] = { "[model]", parse_model_mode },
|
||||
[LINE_MODE_VERB] = { "[verb]", parse_verb_mode },
|
||||
[LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode },
|
||||
[LINE_MODE_HINT] = { "[hint]", parse_hint_mode },
|
||||
};
|
||||
|
||||
/* check the line starting with '[' -- change the parser mode accodingly */
|
||||
static int parse_line_mode(char *buf, struct hda_bus *bus)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
|
||||
if (!patch_items[i].tag)
|
||||
continue;
|
||||
if (strmatch(buf, patch_items[i].tag))
|
||||
return i;
|
||||
}
|
||||
return LINE_MODE_NONE;
|
||||
}
|
||||
|
||||
/* copy one line from the buffer in fw, and update the fields in fw
|
||||
* return zero if it reaches to the end of the buffer, or non-zero
|
||||
* if successfully copied a line
|
||||
*
|
||||
* the spaces at the beginning and the end of the line are stripped
|
||||
*/
|
||||
static int get_line_from_fw(char *buf, int size, struct firmware *fw)
|
||||
{
|
||||
int len;
|
||||
const char *p = fw->data;
|
||||
while (isspace(*p) && fw->size) {
|
||||
p++;
|
||||
fw->size--;
|
||||
}
|
||||
if (!fw->size)
|
||||
return 0;
|
||||
if (size < fw->size)
|
||||
size = fw->size;
|
||||
|
||||
for (len = 0; len < fw->size; len++) {
|
||||
if (!*p)
|
||||
break;
|
||||
if (*p == '\n') {
|
||||
p++;
|
||||
len++;
|
||||
break;
|
||||
}
|
||||
if (len < size)
|
||||
*buf++ = *p++;
|
||||
}
|
||||
*buf = 0;
|
||||
fw->size -= len;
|
||||
fw->data = p;
|
||||
remove_trail_spaces(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* load a "patch" firmware file and parse it
|
||||
*/
|
||||
int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
|
||||
{
|
||||
int err;
|
||||
const struct firmware *fw;
|
||||
struct firmware tmp;
|
||||
char buf[128];
|
||||
struct hda_codec *codec;
|
||||
int line_mode;
|
||||
struct device *dev = bus->card->dev;
|
||||
|
||||
if (snd_BUG_ON(!dev))
|
||||
return -ENODEV;
|
||||
err = request_firmware(&fw, patch, dev);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n",
|
||||
patch);
|
||||
return err;
|
||||
}
|
||||
|
||||
tmp = *fw;
|
||||
line_mode = LINE_MODE_NONE;
|
||||
codec = NULL;
|
||||
while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) {
|
||||
if (!*buf || *buf == '#' || *buf == '\n')
|
||||
continue;
|
||||
if (*buf == '[')
|
||||
line_mode = parse_line_mode(buf, bus);
|
||||
else if (patch_items[line_mode].parser)
|
||||
patch_items[line_mode].parser(buf, bus, &codec);
|
||||
}
|
||||
release_firmware(fw);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_load_patch);
|
||||
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
|
||||
|
|
|
@ -61,6 +61,9 @@ 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;
|
||||
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||
static char *patch[SNDRV_CARDS];
|
||||
#endif
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
|
||||
|
@ -84,6 +87,10 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
|
|||
"(for debugging only).");
|
||||
module_param(enable_msi, int, 0444);
|
||||
MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
|
||||
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||
module_param_array(patch, charp, NULL, 0444);
|
||||
MODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface.");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
|
||||
|
@ -1331,8 +1338,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
|
|||
[AZX_DRIVER_TERA] = 1,
|
||||
};
|
||||
|
||||
static int __devinit azx_codec_create(struct azx *chip, const char *model,
|
||||
int no_init)
|
||||
static int __devinit azx_codec_create(struct azx *chip, const char *model)
|
||||
{
|
||||
struct hda_bus_template bus_temp;
|
||||
int c, codecs, err;
|
||||
|
@ -1391,7 +1397,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
|
|||
for (c = 0; c < max_slots; c++) {
|
||||
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
|
||||
struct hda_codec *codec;
|
||||
err = snd_hda_codec_new(chip->bus, c, !no_init, &codec);
|
||||
err = snd_hda_codec_new(chip->bus, c, &codec);
|
||||
if (err < 0)
|
||||
continue;
|
||||
codecs++;
|
||||
|
@ -1401,7 +1407,16 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
|
|||
snd_printk(KERN_ERR SFX "no codecs initialized\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* configure each codec instance */
|
||||
static int __devinit azx_codec_configure(struct azx *chip)
|
||||
{
|
||||
struct hda_codec *codec;
|
||||
list_for_each_entry(codec, &chip->bus->codec_list, list) {
|
||||
snd_hda_codec_configure(codec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2284,6 +2299,30 @@ static void __devinit check_probe_mask(struct azx *chip, int dev)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* white-list for enable_msi
|
||||
*/
|
||||
static struct snd_pci_quirk msi_white_list[] __devinitdata = {
|
||||
SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1),
|
||||
{}
|
||||
};
|
||||
|
||||
static void __devinit check_msi(struct azx *chip)
|
||||
{
|
||||
const struct snd_pci_quirk *q;
|
||||
|
||||
chip->msi = enable_msi;
|
||||
if (chip->msi)
|
||||
return;
|
||||
q = snd_pci_quirk_lookup(chip->pci, msi_white_list);
|
||||
if (q) {
|
||||
printk(KERN_INFO
|
||||
"hda_intel: msi for device %04x:%04x set to %d\n",
|
||||
q->subvendor, q->subdevice, q->value);
|
||||
chip->msi = q->value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* constructor
|
||||
|
@ -2318,7 +2357,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
|
|||
chip->pci = pci;
|
||||
chip->irq = -1;
|
||||
chip->driver_type = driver_type;
|
||||
chip->msi = enable_msi;
|
||||
check_msi(chip);
|
||||
chip->dev_index = dev;
|
||||
INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
|
||||
|
||||
|
@ -2526,15 +2565,32 @@ static int __devinit azx_probe(struct pci_dev *pci,
|
|||
return err;
|
||||
}
|
||||
|
||||
/* set this here since it's referred in snd_hda_load_patch() */
|
||||
snd_card_set_dev(card, &pci->dev);
|
||||
|
||||
err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
card->private_data = chip;
|
||||
|
||||
/* create codec instances */
|
||||
err = azx_codec_create(chip, model[dev], probe_only[dev]);
|
||||
err = azx_codec_create(chip, model[dev]);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||
if (patch[dev]) {
|
||||
snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
|
||||
patch[dev]);
|
||||
err = snd_hda_load_patch(chip->bus, patch[dev]);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
}
|
||||
#endif
|
||||
if (!probe_only[dev]) {
|
||||
err = azx_codec_configure(chip);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* create PCM streams */
|
||||
err = snd_hda_build_pcms(chip->bus);
|
||||
|
@ -2546,8 +2602,6 @@ static int __devinit azx_probe(struct pci_dev *pci,
|
|||
if (err < 0)
|
||||
goto out_free;
|
||||
|
||||
snd_card_set_dev(card, &pci->dev);
|
||||
|
||||
err = snd_card_register(card);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
|
@ -2649,11 +2703,15 @@ static struct pci_device_id azx_ids[] = {
|
|||
/* this entry seems still valid -- i.e. without emu20kx chip */
|
||||
{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
|
||||
#endif
|
||||
/* AMD Generic, PCI class code and Vendor ID for HD Audio */
|
||||
/* AMD/ATI 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 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 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);
|
||||
|
|
|
@ -99,7 +99,6 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
|
|||
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
||||
unsigned int *tlv, const char **slaves);
|
||||
int 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
|
||||
|
@ -408,6 +407,19 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
|
|||
return codec->wcaps[nid - codec->start_nid];
|
||||
}
|
||||
|
||||
/* get the widget type from widget capability bits */
|
||||
#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT)
|
||||
|
||||
static inline unsigned int get_wcaps_channels(u32 wcaps)
|
||||
{
|
||||
unsigned int chans;
|
||||
|
||||
chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13;
|
||||
chans = ((chans << 1) | 1) + 1;
|
||||
|
||||
return chans;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -508,17 +508,14 @@ static void print_codec_info(struct snd_info_entry *entry,
|
|||
unsigned int wid_caps =
|
||||
snd_hda_param_read(codec, nid,
|
||||
AC_PAR_AUDIO_WIDGET_CAP);
|
||||
unsigned int wid_type =
|
||||
(wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
|
||||
unsigned int wid_type = get_wcaps_type(wid_caps);
|
||||
hda_nid_t conn[HDA_MAX_CONNECTIONS];
|
||||
int conn_len = 0;
|
||||
|
||||
snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
|
||||
get_wid_type_name(wid_type), wid_caps);
|
||||
if (wid_caps & AC_WCAP_STEREO) {
|
||||
unsigned int chans;
|
||||
chans = (wid_caps & AC_WCAP_CHAN_CNT_EXT) >> 13;
|
||||
chans = ((chans << 1) | 1) + 1;
|
||||
unsigned int chans = get_wcaps_channels(wid_caps);
|
||||
if (chans == 2)
|
||||
snd_iprintf(buffer, " Stereo");
|
||||
else
|
||||
|
|
|
@ -2982,7 +2982,8 @@ static int patch_ad1988(struct hda_codec *codec)
|
|||
board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
|
||||
ad1988_models, ad1988_cfg_tbl);
|
||||
if (board_config < 0) {
|
||||
printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n");
|
||||
printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
|
||||
codec->chip_name);
|
||||
board_config = AD1988_AUTO;
|
||||
}
|
||||
|
||||
|
@ -3702,19 +3703,29 @@ static struct hda_amp_list ad1884a_loopbacks[] = {
|
|||
* Port F: Internal speakers
|
||||
*/
|
||||
|
||||
static struct hda_input_mux ad1884a_laptop_capture_source = {
|
||||
.num_items = 4,
|
||||
.items = {
|
||||
{ "Mic", 0x0 }, /* port-B */
|
||||
{ "Internal Mic", 0x1 }, /* port-C */
|
||||
{ "Dock Mic", 0x4 }, /* port-E */
|
||||
{ "Mix", 0x3 },
|
||||
},
|
||||
};
|
||||
static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
|
||||
int mute = (!ucontrol->value.integer.value[0] &&
|
||||
!ucontrol->value.integer.value[1]);
|
||||
/* toggle GPIO1 according to the mute state */
|
||||
snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
|
||||
mute ? 0x02 : 0x0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.info = snd_hda_mixer_amp_switch_info,
|
||||
.get = snd_hda_mixer_amp_switch_get,
|
||||
.put = ad1884a_mobile_master_sw_put,
|
||||
.private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
|
||||
},
|
||||
HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
|
||||
|
@ -3729,36 +3740,9 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
|
|||
HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
/* The multiple "Capture Source" controls confuse alsamixer
|
||||
* So call somewhat different..
|
||||
*/
|
||||
/* .name = "Capture Source", */
|
||||
.name = "Input Source",
|
||||
.count = 2,
|
||||
.info = ad198x_mux_enum_info,
|
||||
.get = ad198x_mux_enum_get,
|
||||
.put = ad198x_mux_enum_put,
|
||||
},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
|
||||
int mute = (!ucontrol->value.integer.value[0] &&
|
||||
!ucontrol->value.integer.value[1]);
|
||||
/* toggle GPIO1 according to the mute state */
|
||||
snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
|
||||
mute ? 0x02 : 0x0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
|
||||
/*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
|
||||
|
@ -3828,6 +3812,63 @@ static int ad1884a_hp_init(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* mute internal speaker if HP or docking HP is plugged */
|
||||
static void ad1884a_laptop_automute(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int present;
|
||||
|
||||
present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0);
|
||||
present &= AC_PINSENSE_PRESENCE;
|
||||
if (!present) {
|
||||
present = snd_hda_codec_read(codec, 0x12, 0,
|
||||
AC_VERB_GET_PIN_SENSE, 0);
|
||||
present &= AC_PINSENSE_PRESENCE;
|
||||
}
|
||||
snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
|
||||
snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
|
||||
present ? 0x00 : 0x02);
|
||||
}
|
||||
|
||||
/* switch to external mic if plugged */
|
||||
static void ad1884a_laptop_automic(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int idx;
|
||||
|
||||
if (snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) &
|
||||
AC_PINSENSE_PRESENCE)
|
||||
idx = 0;
|
||||
else if (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) &
|
||||
AC_PINSENSE_PRESENCE)
|
||||
idx = 4;
|
||||
else
|
||||
idx = 1;
|
||||
snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
|
||||
}
|
||||
|
||||
/* unsolicited event for HP jack sensing */
|
||||
static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
switch (res >> 26) {
|
||||
case AD1884A_HP_EVENT:
|
||||
ad1884a_laptop_automute(codec);
|
||||
break;
|
||||
case AD1884A_MIC_EVENT:
|
||||
ad1884a_laptop_automic(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize jack-sensing, too */
|
||||
static int ad1884a_laptop_init(struct hda_codec *codec)
|
||||
{
|
||||
ad198x_init(codec);
|
||||
ad1884a_laptop_automute(codec);
|
||||
ad1884a_laptop_automic(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* additional verbs for laptop model */
|
||||
static struct hda_verb ad1884a_laptop_verbs[] = {
|
||||
/* Port-A (HP) pin - always unmuted */
|
||||
|
@ -3844,11 +3885,19 @@ static struct hda_verb ad1884a_laptop_verbs[] = {
|
|||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
|
||||
/* Port-D (docking line-out) pin - default unmuted */
|
||||
{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
/* analog mix */
|
||||
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
|
||||
/* unsolicited event for pin-sense */
|
||||
{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
|
||||
{0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
|
||||
{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
|
||||
{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
|
||||
/* allow to touch GPIO1 (for mute control) */
|
||||
{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
|
||||
{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
|
||||
{0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
|
@ -4008,6 +4057,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
|
|||
SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
|
||||
SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
|
||||
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
|
||||
SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
|
||||
SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
|
||||
{}
|
||||
};
|
||||
|
@ -4057,9 +4107,8 @@ static int patch_ad1884a(struct hda_codec *codec)
|
|||
spec->mixers[0] = ad1884a_laptop_mixers;
|
||||
spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
|
||||
spec->multiout.dig_out_nid = 0;
|
||||
spec->input_mux = &ad1884a_laptop_capture_source;
|
||||
codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
|
||||
codec->patch_ops.init = ad1884a_hp_init;
|
||||
codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
|
||||
codec->patch_ops.init = ad1884a_laptop_init;
|
||||
/* set the upper-limit for mixer amp to 0dB for avoiding the
|
||||
* possible damage by overloading
|
||||
*/
|
||||
|
|
|
@ -141,8 +141,7 @@ static int atihdmi_build_pcms(struct hda_codec *codec)
|
|||
/* FIXME: we must check ELD and change the PCM parameters dynamically
|
||||
*/
|
||||
chans = get_wcaps(codec, CVT_NID);
|
||||
chans = (chans & AC_WCAP_CHAN_CNT_EXT) >> 13;
|
||||
chans = ((chans << 1) | 1) + 1;
|
||||
chans = get_wcaps_channels(chans);
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -459,8 +459,7 @@ static void parse_input(struct hda_codec *codec)
|
|||
nid = codec->start_nid;
|
||||
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
||||
unsigned int wcaps = get_wcaps(codec, nid);
|
||||
unsigned int type = (wcaps & AC_WCAP_TYPE) >>
|
||||
AC_WCAP_TYPE_SHIFT;
|
||||
unsigned int type = get_wcaps_type(wcaps);
|
||||
if (type != AC_WID_AUD_IN)
|
||||
continue;
|
||||
if (snd_hda_get_connections(codec, nid, &pin, 1) != 1)
|
||||
|
|
1194
sound/pci/hda/patch_cirrus.c
Normal file
1194
sound/pci/hda/patch_cirrus.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -635,7 +635,8 @@ static int patch_cmi9880(struct hda_codec *codec)
|
|||
cmi9880_models,
|
||||
cmi9880_cfg_tbl);
|
||||
if (spec->board_config < 0) {
|
||||
snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
|
||||
snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
|
||||
codec->chip_name);
|
||||
spec->board_config = CMI_AUTO; /* try everything */
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,8 @@ struct conexant_spec {
|
|||
struct hda_input_mux private_imux;
|
||||
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
|
||||
|
||||
unsigned int dell_automute;
|
||||
unsigned int port_d_mode;
|
||||
};
|
||||
|
||||
static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
||||
|
@ -1908,6 +1910,480 @@ static int patch_cxt5051(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Conexant 5066 specific */
|
||||
|
||||
static hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
|
||||
static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
|
||||
static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
|
||||
#define CXT5066_SPDIF_OUT 0x21
|
||||
|
||||
static struct hda_channel_mode cxt5066_modes[1] = {
|
||||
{ 2, NULL },
|
||||
};
|
||||
|
||||
static void cxt5066_update_speaker(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
unsigned int pinctl;
|
||||
|
||||
snd_printdd("CXT5066: update speaker, hp_present=%d\n",
|
||||
spec->hp_present);
|
||||
|
||||
/* Port A (HP) */
|
||||
pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0;
|
||||
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
|
||||
/* Port D (HP/LO) */
|
||||
pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
|
||||
? spec->port_d_mode : 0;
|
||||
snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
|
||||
/* CLASS_D AMP */
|
||||
pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
|
||||
snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
|
||||
if (spec->dell_automute) {
|
||||
/* DELL AIO Port Rule: PortA > PortD > IntSpk */
|
||||
pinctl = (!(spec->hp_present & 1) && spec->cur_eapd)
|
||||
? PIN_OUT : 0;
|
||||
snd_hda_codec_write(codec, 0x1c, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
|
||||
}
|
||||
}
|
||||
|
||||
/* turn on/off EAPD (+ mute HP) as a master switch */
|
||||
static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
if (!cxt_eapd_put(kcontrol, ucontrol))
|
||||
return 0;
|
||||
|
||||
cxt5066_update_speaker(codec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* toggle input of built-in and mic jack appropriately */
|
||||
static void cxt5066_automic(struct hda_codec *codec)
|
||||
{
|
||||
static struct hda_verb ext_mic_present[] = {
|
||||
/* enable external mic, port B */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
|
||||
/* switch to external mic input */
|
||||
{0x17, AC_VERB_SET_CONNECT_SEL, 0},
|
||||
|
||||
/* disable internal mic, port C */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
{}
|
||||
};
|
||||
static struct hda_verb ext_mic_absent[] = {
|
||||
/* enable internal mic, port C */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
|
||||
/* switch to internal mic input */
|
||||
{0x17, AC_VERB_SET_CONNECT_SEL, 1},
|
||||
|
||||
/* disable external mic, port B */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
{}
|
||||
};
|
||||
unsigned int present;
|
||||
|
||||
present = snd_hda_codec_read(codec, 0x1a, 0,
|
||||
AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
|
||||
if (present) {
|
||||
snd_printdd("CXT5066: external microphone detected\n");
|
||||
snd_hda_sequence_write(codec, ext_mic_present);
|
||||
} else {
|
||||
snd_printdd("CXT5066: external microphone absent\n");
|
||||
snd_hda_sequence_write(codec, ext_mic_absent);
|
||||
}
|
||||
}
|
||||
|
||||
/* mute internal speaker if HP is plugged */
|
||||
static void cxt5066_hp_automute(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
unsigned int portA, portD;
|
||||
|
||||
/* Port A */
|
||||
portA = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0)
|
||||
& AC_PINSENSE_PRESENCE;
|
||||
|
||||
/* Port D */
|
||||
portD = (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0)
|
||||
& AC_PINSENSE_PRESENCE) << 1;
|
||||
|
||||
spec->hp_present = !!(portA | portD);
|
||||
snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
|
||||
portA, portD, spec->hp_present);
|
||||
cxt5066_update_speaker(codec);
|
||||
}
|
||||
|
||||
/* unsolicited event for jack sensing */
|
||||
static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
|
||||
{
|
||||
snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
|
||||
switch (res >> 26) {
|
||||
case CONEXANT_HP_EVENT:
|
||||
cxt5066_hp_automute(codec);
|
||||
break;
|
||||
case CONEXANT_MIC_EVENT:
|
||||
cxt5066_automic(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hda_input_mux cxt5066_analog_mic_boost = {
|
||||
.num_items = 5,
|
||||
.items = {
|
||||
{ "0dB", 0 },
|
||||
{ "10dB", 1 },
|
||||
{ "20dB", 2 },
|
||||
{ "30dB", 3 },
|
||||
{ "40dB", 4 },
|
||||
},
|
||||
};
|
||||
|
||||
static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo);
|
||||
}
|
||||
|
||||
static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
int val;
|
||||
|
||||
val = snd_hda_codec_read(codec, 0x17, 0,
|
||||
AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_OUTPUT);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
|
||||
unsigned int idx;
|
||||
|
||||
if (!imux->num_items)
|
||||
return 0;
|
||||
idx = ucontrol->value.enumerated.item[0];
|
||||
if (idx >= imux->num_items)
|
||||
idx = imux->num_items - 1;
|
||||
|
||||
snd_hda_codec_write_cache(codec, 0x17, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
|
||||
imux->items[idx].index);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct hda_input_mux cxt5066_capture_source = {
|
||||
.num_items = 4,
|
||||
.items = {
|
||||
{ "Mic B", 0 },
|
||||
{ "Mic C", 1 },
|
||||
{ "Mic E", 2 },
|
||||
{ "Mic F", 3 },
|
||||
},
|
||||
};
|
||||
|
||||
static struct hda_bind_ctls cxt5066_bind_capture_vol_others = {
|
||||
.ops = &snd_hda_bind_vol,
|
||||
.values = {
|
||||
HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
|
||||
HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT),
|
||||
0
|
||||
},
|
||||
};
|
||||
|
||||
static struct hda_bind_ctls cxt5066_bind_capture_sw_others = {
|
||||
.ops = &snd_hda_bind_sw,
|
||||
.values = {
|
||||
HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
|
||||
HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT),
|
||||
0
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5066_mixer_master[] = {
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Volume",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
|
||||
.info = snd_hda_mixer_amp_volume_info,
|
||||
.get = snd_hda_mixer_amp_volume_get,
|
||||
.put = snd_hda_mixer_amp_volume_put,
|
||||
.tlv = { .c = snd_hda_mixer_amp_tlv },
|
||||
/* offset by 28 volume steps to limit minimum gain to -46dB */
|
||||
.private_value =
|
||||
HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5066_mixers[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.info = cxt_eapd_info,
|
||||
.get = cxt_eapd_get,
|
||||
.put = cxt5066_hp_master_sw_put,
|
||||
.private_value = 0x1d,
|
||||
},
|
||||
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog Mic Boost Capture Enum",
|
||||
.info = cxt5066_mic_boost_mux_enum_info,
|
||||
.get = cxt5066_mic_boost_mux_enum_get,
|
||||
.put = cxt5066_mic_boost_mux_enum_put,
|
||||
},
|
||||
|
||||
HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others),
|
||||
HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5066_init_verbs[] = {
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
|
||||
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
|
||||
|
||||
/* Speakers */
|
||||
{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
|
||||
|
||||
/* HP, Amp */
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
|
||||
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
|
||||
|
||||
/* DAC1 */
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
|
||||
/* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
|
||||
|
||||
/* no digital microphone support yet */
|
||||
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* Audio input selector */
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
|
||||
|
||||
/* SPDIF route: PCM */
|
||||
{0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
|
||||
{0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
|
||||
|
||||
{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
|
||||
/* EAPD */
|
||||
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
|
||||
/* not handling these yet */
|
||||
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
|
||||
{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
|
||||
{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
|
||||
{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
|
||||
{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
|
||||
{0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
|
||||
{0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
|
||||
{0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5066_init_verbs_olpc[] = {
|
||||
/* Port A: headphones */
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
|
||||
|
||||
/* Port B: external microphone */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
|
||||
/* Port C: internal microphone */
|
||||
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
|
||||
/* Port D: unused */
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* Port E: unused, but has primary EAPD */
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
|
||||
/* Port F: unused */
|
||||
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* Port G: internal speakers */
|
||||
{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
|
||||
|
||||
/* DAC1 */
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
|
||||
/* DAC2: unused */
|
||||
{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
|
||||
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
|
||||
|
||||
/* Disable digital microphone port */
|
||||
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* Audio input selectors */
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
|
||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
|
||||
|
||||
/* Disable SPDIF */
|
||||
{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
|
||||
|
||||
/* enable unsolicited events for Port A and B */
|
||||
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
|
||||
{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/* initialize jack-sensing, too */
|
||||
static int cxt5066_init(struct hda_codec *codec)
|
||||
{
|
||||
snd_printdd("CXT5066: init\n");
|
||||
conexant_init(codec);
|
||||
if (codec->patch_ops.unsol_event) {
|
||||
cxt5066_hp_automute(codec);
|
||||
cxt5066_automic(codec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
CXT5066_LAPTOP, /* Laptops w/ EAPD support */
|
||||
CXT5066_DELL_LAPTOP, /* Dell Laptop */
|
||||
CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
|
||||
CXT5066_MODELS
|
||||
};
|
||||
|
||||
static const char *cxt5066_models[CXT5066_MODELS] = {
|
||||
[CXT5066_LAPTOP] = "laptop",
|
||||
[CXT5066_DELL_LAPTOP] = "dell-laptop",
|
||||
[CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
|
||||
};
|
||||
|
||||
static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
|
||||
CXT5066_LAPTOP),
|
||||
SND_PCI_QUIRK(0x1028, 0x02f5, "Dell",
|
||||
CXT5066_DELL_LAPTOP),
|
||||
{}
|
||||
};
|
||||
|
||||
static int patch_cxt5066(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec;
|
||||
int board_config;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (!spec)
|
||||
return -ENOMEM;
|
||||
codec->spec = spec;
|
||||
|
||||
codec->patch_ops = conexant_patch_ops;
|
||||
codec->patch_ops.init = cxt5066_init;
|
||||
|
||||
spec->dell_automute = 0;
|
||||
spec->multiout.max_channels = 2;
|
||||
spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids);
|
||||
spec->multiout.dac_nids = cxt5066_dac_nids;
|
||||
spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT;
|
||||
spec->num_adc_nids = 1;
|
||||
spec->adc_nids = cxt5066_adc_nids;
|
||||
spec->capsrc_nids = cxt5066_capsrc_nids;
|
||||
spec->input_mux = &cxt5066_capture_source;
|
||||
|
||||
spec->port_d_mode = PIN_HP;
|
||||
|
||||
spec->num_init_verbs = 1;
|
||||
spec->init_verbs[0] = cxt5066_init_verbs;
|
||||
spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes);
|
||||
spec->channel_mode = cxt5066_modes;
|
||||
spec->cur_adc = 0;
|
||||
spec->cur_adc_idx = 0;
|
||||
|
||||
board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
|
||||
cxt5066_models, cxt5066_cfg_tbl);
|
||||
switch (board_config) {
|
||||
default:
|
||||
case CXT5066_LAPTOP:
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
|
||||
break;
|
||||
case CXT5066_DELL_LAPTOP:
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
|
||||
|
||||
spec->port_d_mode = PIN_OUT;
|
||||
spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo;
|
||||
spec->num_init_verbs++;
|
||||
spec->dell_automute = 1;
|
||||
break;
|
||||
case CXT5066_OLPC_XO_1_5:
|
||||
codec->patch_ops.unsol_event = cxt5066_unsol_event;
|
||||
spec->init_verbs[0] = cxt5066_init_verbs_olpc;
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
|
||||
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
|
||||
spec->port_d_mode = 0;
|
||||
|
||||
/* no S/PDIF out */
|
||||
spec->multiout.dig_out_nid = 0;
|
||||
|
||||
/* input source automatically selected */
|
||||
spec->input_mux = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
|
@ -1919,12 +2395,15 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
|
|||
.patch = patch_cxt5047 },
|
||||
{ .id = 0x14f15051, .name = "CX20561 (Hermosa)",
|
||||
.patch = patch_cxt5051 },
|
||||
{ .id = 0x14f15066, .name = "CX20582 (Pebble)",
|
||||
.patch = patch_cxt5066 },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f15045");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f15047");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f15051");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f15066");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Conexant HD-audio codec");
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
|
||||
#define CVT_NID 0x02 /* audio converter */
|
||||
#define PIN_NID 0x03 /* HDMI output pin */
|
||||
static hda_nid_t cvt_nid; /* audio converter */
|
||||
static hda_nid_t pin_nid; /* HDMI output pin */
|
||||
|
||||
#define INTEL_HDMI_EVENT_TAG 0x08
|
||||
|
||||
|
@ -44,30 +44,6 @@ struct intel_hdmi_spec {
|
|||
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 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 */
|
||||
|
@ -244,11 +220,12 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid,
|
|||
static void hdmi_enable_output(struct hda_codec *codec)
|
||||
{
|
||||
/* Unmute */
|
||||
if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
|
||||
snd_hda_codec_write(codec, PIN_NID, 0,
|
||||
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);
|
||||
snd_hda_codec_write(codec, pin_nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -256,8 +233,8 @@ static void hdmi_enable_output(struct hda_codec *codec)
|
|||
*/
|
||||
static void hdmi_start_infoframe_trans(struct hda_codec *codec)
|
||||
{
|
||||
hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
|
||||
snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -266,20 +243,20 @@ static void hdmi_start_infoframe_trans(struct hda_codec *codec)
|
|||
*/
|
||||
static void hdmi_stop_infoframe_trans(struct hda_codec *codec)
|
||||
{
|
||||
hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
|
||||
snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT,
|
||||
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_DISABLE);
|
||||
}
|
||||
|
||||
static int hdmi_get_channel_count(struct hda_codec *codec)
|
||||
{
|
||||
return 1 + snd_hda_codec_read(codec, CVT_NID, 0,
|
||||
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,
|
||||
snd_hda_codec_write(codec, cvt_nid, 0,
|
||||
AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
|
||||
|
||||
if (chs != hdmi_get_channel_count(codec))
|
||||
|
@ -294,7 +271,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec)
|
|||
int slot;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
slot = snd_hda_codec_read(codec, CVT_NID, 0,
|
||||
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);
|
||||
|
@ -307,7 +284,7 @@ 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))
|
||||
if (!snd_hdmi_get_eld(eld, codec, pin_nid))
|
||||
snd_hdmi_show_eld(eld);
|
||||
}
|
||||
|
||||
|
@ -322,11 +299,11 @@ static void hdmi_debug_dip_size(struct hda_codec *codec)
|
|||
int i;
|
||||
int size;
|
||||
|
||||
size = snd_hdmi_get_eld_size(codec, PIN_NID);
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
@ -340,15 +317,15 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec)
|
|||
int size;
|
||||
int pi, bi;
|
||||
for (i = 0; i < 8; i++) {
|
||||
size = snd_hda_codec_read(codec, PIN_NID, 0,
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
@ -376,9 +353,9 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
|
|||
sum += params[i];
|
||||
ai->checksum = - sum;
|
||||
|
||||
hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
|
||||
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]);
|
||||
hdmi_write_dip_byte(codec, pin_nid, params[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -465,6 +442,8 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec,
|
|||
static void hdmi_setup_channel_mapping(struct hda_codec *codec,
|
||||
struct hdmi_audio_infoframe *ai)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ai->CA)
|
||||
return;
|
||||
|
||||
|
@ -473,7 +452,11 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec,
|
|||
* ALSA sequence is front/surr/clfe/side?
|
||||
*/
|
||||
|
||||
snd_hda_sequence_write(codec, def_chan_map);
|
||||
for (i = 0; i < 8; i++)
|
||||
snd_hda_codec_write(codec, cvt_nid, 0,
|
||||
AC_VERB_SET_HDMI_CHAN_SLOT,
|
||||
(i << 4) | i);
|
||||
|
||||
hdmi_debug_channel_mapping(codec);
|
||||
}
|
||||
|
||||
|
@ -597,7 +580,6 @@ 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,
|
||||
|
@ -613,6 +595,9 @@ static int intel_hdmi_build_pcms(struct hda_codec *codec)
|
|||
codec->num_pcms = 1;
|
||||
codec->pcm_info = info;
|
||||
|
||||
/* NID to query formats and rates and setup streams */
|
||||
intel_hdmi_pcm_playback.nid = cvt_nid;
|
||||
|
||||
info->name = "INTEL HDMI";
|
||||
info->pcm_type = HDA_PCM_TYPE_HDMI;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback;
|
||||
|
@ -636,8 +621,9 @@ static int intel_hdmi_init(struct hda_codec *codec)
|
|||
{
|
||||
hdmi_enable_output(codec);
|
||||
|
||||
snd_hda_sequence_write(codec, unsolicited_response_verb);
|
||||
|
||||
snd_hda_codec_write(codec, pin_nid, 0,
|
||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | INTEL_HDMI_EVENT_TAG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -657,7 +643,7 @@ static struct hda_codec_ops intel_hdmi_patch_ops = {
|
|||
.unsol_event = intel_hdmi_unsol_event,
|
||||
};
|
||||
|
||||
static int patch_intel_hdmi(struct hda_codec *codec)
|
||||
static int do_patch_intel_hdmi(struct hda_codec *codec)
|
||||
{
|
||||
struct intel_hdmi_spec *spec;
|
||||
|
||||
|
@ -667,7 +653,7 @@ static int patch_intel_hdmi(struct hda_codec *codec)
|
|||
|
||||
spec->multiout.num_dacs = 0; /* no analog */
|
||||
spec->multiout.max_channels = 8;
|
||||
spec->multiout.dig_out_nid = CVT_NID;
|
||||
spec->multiout.dig_out_nid = cvt_nid;
|
||||
|
||||
codec->spec = spec;
|
||||
codec->patch_ops = intel_hdmi_patch_ops;
|
||||
|
@ -679,12 +665,27 @@ static int patch_intel_hdmi(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int patch_intel_hdmi(struct hda_codec *codec)
|
||||
{
|
||||
cvt_nid = 0x02;
|
||||
pin_nid = 0x03;
|
||||
return do_patch_intel_hdmi(codec);
|
||||
}
|
||||
|
||||
static int patch_intel_hdmi_ibexpeak(struct hda_codec *codec)
|
||||
{
|
||||
cvt_nid = 0x02;
|
||||
pin_nid = 0x04;
|
||||
return do_patch_intel_hdmi(codec);
|
||||
}
|
||||
|
||||
static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
|
||||
{ .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi },
|
||||
{ .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi_ibexpeak },
|
||||
{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
@ -694,6 +695,7 @@ 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:80862804");
|
||||
MODULE_ALIAS("snd-hda-codec-id:80860054");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10951392");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -377,6 +377,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
|
|||
*/
|
||||
static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
|
||||
{ .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
|
||||
{ .id = 0x10de0003, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
|
||||
{ .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
|
||||
{ .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch },
|
||||
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
|
||||
|
@ -385,6 +386,7 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
|
|||
};
|
||||
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0002");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0003");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0006");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0007");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0067");
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1339,8 +1339,7 @@ static int get_mux_nids(struct hda_codec *codec)
|
|||
for (i = 0; i < spec->num_adc_nids; i++) {
|
||||
nid = spec->adc_nids[i];
|
||||
while (nid) {
|
||||
type = (get_wcaps(codec, nid) & AC_WCAP_TYPE)
|
||||
>> AC_WCAP_TYPE_SHIFT;
|
||||
type = get_wcaps_type(get_wcaps(codec, nid));
|
||||
if (type == AC_WID_PIN)
|
||||
break;
|
||||
n = snd_hda_get_connections(codec, nid, conn,
|
||||
|
|
Loading…
Reference in a new issue