Commit 2d4ff66a authored by Takashi Iwai's avatar Takashi Iwai

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
  ...
parents 6a0f4021 33d78674
...@@ -788,6 +788,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ...@@ -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. bdl_pos_adj - Specifies the DMA IRQ timing delay in samples.
Passing -1 will make the driver to choose the appropriate Passing -1 will make the driver to choose the appropriate
value based on the controller chip. 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 (global) options]
single_cmd - Use single immediate commands to communicate with single_cmd - Use single immediate commands to communicate with
......
...@@ -114,8 +114,8 @@ ALC662/663/272 ...@@ -114,8 +114,8 @@ ALC662/663/272
samsung-nc10 Samsung NC10 mini notebook samsung-nc10 Samsung NC10 mini notebook
auto auto-config reading BIOS (default) auto auto-config reading BIOS (default)
ALC882/885 ALC882/883/885/888/889
========== ======================
3stack-dig 3-jack with SPDIF I/O 3stack-dig 3-jack with SPDIF I/O
6stack-dig 6-jack digital with SPDIF I/O 6stack-dig 6-jack digital with SPDIF I/O
arima Arima W820Di1 arima Arima W820Di1
...@@ -127,12 +127,8 @@ ALC882/885 ...@@ -127,12 +127,8 @@ ALC882/885
mbp3 Macbook Pro rev3 mbp3 Macbook Pro rev3
imac24 iMac 24'' with jack detection imac24 iMac 24'' with jack detection
w2jc ASUS W2JC w2jc ASUS W2JC
auto auto-config reading BIOS (default) 3stack-2ch-dig 3-jack with SPDIF I/O (ALC883)
alc883-6stack-dig 6-jack digital with SPDIF I/O (ALC883)
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 3-jack 6-channel
3stack-6ch-dig 3-jack 6-channel with SPDIF I/O 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O
6stack-dig-demo 6-jack digital for Intel demo board 6stack-dig-demo 6-jack digital for Intel demo board
...@@ -140,6 +136,7 @@ ALC883/888 ...@@ -140,6 +136,7 @@ ALC883/888
acer-aspire Acer Aspire 9810 acer-aspire Acer Aspire 9810
acer-aspire-4930g Acer Aspire 4930G acer-aspire-4930g Acer Aspire 4930G
acer-aspire-6530g Acer Aspire 6530G acer-aspire-6530g Acer Aspire 6530G
acer-aspire-7730g Acer Aspire 7730G
acer-aspire-8930g Acer Aspire 8930G acer-aspire-8930g Acer Aspire 8930G
medion Medion Laptops medion Medion Laptops
medion-md2 Medion MD2 medion-md2 Medion MD2
...@@ -155,10 +152,13 @@ ALC883/888 ...@@ -155,10 +152,13 @@ ALC883/888
3stack-hp HP machines with 3stack (Lucknow, Samba boards) 3stack-hp HP machines with 3stack (Lucknow, Samba boards)
6stack-dell Dell machines with 6stack (Inspiron 530) 6stack-dell Dell machines with 6stack (Inspiron 530)
mitac Mitac 8252D mitac Mitac 8252D
clevo-m540r Clevo M540R (6ch + digital)
clevo-m720 Clevo M720 laptop series clevo-m720 Clevo M720 laptop series
fujitsu-pi2515 Fujitsu AMILO Pi2515 fujitsu-pi2515 Fujitsu AMILO Pi2515
fujitsu-xa3530 Fujitsu AMILO XA3530 fujitsu-xa3530 Fujitsu AMILO XA3530
3stack-6ch-intel Intel DG33* boards 3stack-6ch-intel Intel DG33* boards
intel-alc889a Intel IbexPeak with ALC889A
intel-x58 Intel DX58 with ALC889
asus-p5q ASUS P5Q-EM boards asus-p5q ASUS P5Q-EM boards
mb31 MacBook 3,1 mb31 MacBook 3,1
sony-vaio-tt Sony VAIO TT sony-vaio-tt Sony VAIO TT
...@@ -229,7 +229,7 @@ AD1984 ...@@ -229,7 +229,7 @@ AD1984
====== ======
basic default configuration basic default configuration
thinkpad Lenovo Thinkpad T61/X61 thinkpad Lenovo Thinkpad T61/X61
dell Dell T3400 dell_desktop Dell T3400
AD1986A AD1986A
======= =======
...@@ -258,6 +258,7 @@ Conexant 5045 ...@@ -258,6 +258,7 @@ Conexant 5045
laptop-micsense Laptop with Mic sense (old model fujitsu) laptop-micsense Laptop with Mic sense (old model fujitsu)
laptop-hpmicsense Laptop with HP and Mic senses laptop-hpmicsense Laptop with HP and Mic senses
benq Benq R55E benq Benq R55E
laptop-hp530 HP 530 laptop
test for testing/debugging purpose, almost all controls test for testing/debugging purpose, almost all controls
can be adjusted. Appearing only when compiled with can be adjusted. Appearing only when compiled with
$CONFIG_SND_DEBUG=y $CONFIG_SND_DEBUG=y
...@@ -278,9 +279,16 @@ Conexant 5051 ...@@ -278,9 +279,16 @@ Conexant 5051
hp-dv6736 HP dv6736 hp-dv6736 HP dv6736
lenovo-x200 Lenovo X200 laptop 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 STAC9200
======== ========
ref Reference board ref Reference board
oqo OQO Model 2
dell-d21 Dell (unknown) dell-d21 Dell (unknown)
dell-d22 Dell (unknown) dell-d22 Dell (unknown)
dell-d23 Dell (unknown) dell-d23 Dell (unknown)
...@@ -368,10 +376,12 @@ STAC92HD73* ...@@ -368,10 +376,12 @@ STAC92HD73*
=========== ===========
ref Reference board ref Reference board
no-jd BIOS setup but without jack-detection no-jd BIOS setup but without jack-detection
intel Intel DG45* mobos
dell-m6-amic Dell desktops/laptops with analog mics dell-m6-amic Dell desktops/laptops with analog mics
dell-m6-dmic Dell desktops/laptops with digital mics dell-m6-dmic Dell desktops/laptops with digital mics
dell-m6 Dell desktops/laptops with both type of mics dell-m6 Dell desktops/laptops with both type of mics
dell-eq Dell desktops/laptops dell-eq Dell desktops/laptops
alienware Alienware M17x
auto BIOS setup (default) auto BIOS setup (default)
STAC92HD83* STAC92HD83*
...@@ -385,3 +395,8 @@ STAC9872 ...@@ -385,3 +395,8 @@ STAC9872
======== ========
vaio VAIO laptop without SPDIF vaio VAIO laptop without SPDIF
auto BIOS setup (default) 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. ...@@ -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 The driver checks PCI SSID and looks through the static configuration
table until any matching entry is found. If you have a new machine, table until any matching entry is found. If you have a new machine,
you may see a message like below: 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... hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...
------------------------------------------------------------------------ ------------------------------------------------------------------------
...@@ -403,6 +407,66 @@ re-configure based on that state, run like below: ...@@ -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 Power-Saving
~~~~~~~~~~~~ ~~~~~~~~~~~~
The power-saving is a kind of auto-suspend of the device. When the The power-saving is a kind of auto-suspend of the device. When the
......
...@@ -46,6 +46,20 @@ config SND_HDA_INPUT_JACK ...@@ -46,6 +46,20 @@ config SND_HDA_INPUT_JACK
Say Y here to enable the jack plugging notification via Say Y here to enable the jack plugging notification via
input layer. 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 config SND_HDA_CODEC_REALTEK
bool "Build Realtek HD-audio codec support" bool "Build Realtek HD-audio codec support"
default y default y
...@@ -134,6 +148,19 @@ config SND_HDA_ELD ...@@ -134,6 +148,19 @@ config SND_HDA_ELD
def_bool y def_bool y
depends on SND_HDA_CODEC_INTELHDMI 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 config SND_HDA_CODEC_CONEXANT
bool "Build Conexant HD-audio codec support" bool "Build Conexant HD-audio codec support"
default y default y
......
...@@ -13,6 +13,7 @@ snd-hda-codec-analog-objs := patch_analog.o ...@@ -13,6 +13,7 @@ snd-hda-codec-analog-objs := patch_analog.o
snd-hda-codec-idt-objs := patch_sigmatel.o snd-hda-codec-idt-objs := patch_sigmatel.o
snd-hda-codec-si3054-objs := patch_si3054.o snd-hda-codec-si3054-objs := patch_si3054.o
snd-hda-codec-atihdmi-objs := patch_atihdmi.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-ca0110-objs := patch_ca0110.o
snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-conexant-objs := patch_conexant.o
snd-hda-codec-via-objs := patch_via.o snd-hda-codec-via-objs := patch_via.o
...@@ -41,6 +42,9 @@ endif ...@@ -41,6 +42,9 @@ endif
ifdef CONFIG_SND_HDA_CODEC_ATIHDMI ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
endif endif
ifdef CONFIG_SND_HDA_CODEC_CIRRUS
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
endif
ifdef CONFIG_SND_HDA_CODEC_CA0110 ifdef CONFIG_SND_HDA_CODEC_CA0110
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o
endif endif
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <sound/core.h> #include <sound/core.h>
#include "hda_beep.h" #include "hda_beep.h"
#include "hda_local.h"
enum { enum {
DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */ DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */
...@@ -118,6 +119,9 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) ...@@ -118,6 +119,9 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
struct hda_beep *beep; struct hda_beep *beep;
int err; int err;
if (!snd_hda_get_bool_hint(codec, "beep"))
return 0; /* disabled explicitly */
beep = kzalloc(sizeof(*beep), GFP_KERNEL); beep = kzalloc(sizeof(*beep), GFP_KERNEL);
if (beep == NULL) if (beep == NULL)
return -ENOMEM; return -ENOMEM;
......
...@@ -44,6 +44,7 @@ struct hda_vendor_id { ...@@ -44,6 +44,7 @@ struct hda_vendor_id {
/* codec vendor labels */ /* codec vendor labels */
static struct hda_vendor_id hda_vendor_ids[] = { static struct hda_vendor_id hda_vendor_ids[] = {
{ 0x1002, "ATI" }, { 0x1002, "ATI" },
{ 0x1013, "Cirrus Logic" },
{ 0x1057, "Motorola" }, { 0x1057, "Motorola" },
{ 0x1095, "Silicon Image" }, { 0x1095, "Silicon Image" },
{ 0x10de, "Nvidia" }, { 0x10de, "Nvidia" },
...@@ -150,7 +151,14 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, ...@@ -150,7 +151,14 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
{ {
u32 val; 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)direct << 27;
val |= (u32)nid << 20; val |= (u32)nid << 20;
val |= verb << 8; val |= verb << 8;
...@@ -167,6 +175,9 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, ...@@ -167,6 +175,9 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
struct hda_bus *bus = codec->bus; struct hda_bus *bus = codec->bus;
int err; int err;
if (cmd == ~0)
return -1;
if (res) if (res)
*res = -1; *res = -1;
again: again:
...@@ -291,11 +302,20 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, ...@@ -291,11 +302,20 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
unsigned int parm; unsigned int parm;
int i, conn_len, conns; int i, conn_len, conns;
unsigned int shift, num_elems, mask; unsigned int shift, num_elems, mask;
unsigned int wcaps;
hda_nid_t prev_nid; hda_nid_t prev_nid;
if (snd_BUG_ON(!conn_list || max_conns <= 0)) if (snd_BUG_ON(!conn_list || max_conns <= 0))
return -EINVAL; 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); parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
if (parm & AC_CLIST_LONG) { if (parm & AC_CLIST_LONG) {
/* long form */ /* long form */
...@@ -316,6 +336,8 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, ...@@ -316,6 +336,8 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
/* single connection */ /* single connection */
parm = snd_hda_codec_read(codec, nid, 0, parm = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONNECT_LIST, 0); AC_VERB_GET_CONNECT_LIST, 0);
if (parm == -1 && codec->bus->rirb_error)
return -EIO;
conn_list[0] = parm & mask; conn_list[0] = parm & mask;
return 1; return 1;
} }
...@@ -327,9 +349,12 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, ...@@ -327,9 +349,12 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
int range_val; int range_val;
hda_nid_t val, n; hda_nid_t val, n;
if (i % num_elems == 0) if (i % num_elems == 0) {
parm = snd_hda_codec_read(codec, nid, 0, parm = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONNECT_LIST, i); AC_VERB_GET_CONNECT_LIST, i);
if (parm == -1 && codec->bus->rirb_error)
return -EIO;
}
range_val = !!(parm & (1 << (shift-1))); /* ranges */ range_val = !!(parm & (1 << (shift-1))); /* ranges */
val = parm & mask; val = parm & mask;
if (val == 0) { if (val == 0) {
...@@ -727,8 +752,7 @@ static int read_pin_defaults(struct hda_codec *codec) ...@@ -727,8 +752,7 @@ static int read_pin_defaults(struct hda_codec *codec)
for (i = 0; i < codec->num_nodes; i++, nid++) { for (i = 0; i < codec->num_nodes; i++, nid++) {
struct hda_pincfg *pin; struct hda_pincfg *pin;
unsigned int wcaps = get_wcaps(codec, nid); unsigned int wcaps = get_wcaps(codec, nid);
unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> unsigned int wid_type = get_wcaps_type(wcaps);
AC_WCAP_TYPE_SHIFT;
if (wid_type != AC_WID_PIN) if (wid_type != AC_WID_PIN)
continue; continue;
pin = snd_array_new(&codec->init_pins); 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, ...@@ -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. * Returns 0 if successful, or a negative error code.
*/ */
int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, 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; struct hda_codec *codec;
char component[31]; char component[31];
...@@ -984,11 +1008,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr ...@@ -984,11 +1008,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
codec->afg ? codec->afg : codec->mfg, codec->afg ? codec->afg : codec->mfg,
AC_PWRST_D0); 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_codec_proc_new(codec);
snd_hda_create_hwdep(codec); snd_hda_create_hwdep(codec);
...@@ -1042,6 +1061,7 @@ int snd_hda_codec_configure(struct hda_codec *codec) ...@@ -1042,6 +1061,7 @@ int snd_hda_codec_configure(struct hda_codec *codec)
err = init_unsol_queue(codec->bus); err = init_unsol_queue(codec->bus);
return err; return err;
} }
EXPORT_SYMBOL_HDA(snd_hda_codec_configure);
/** /**
* snd_hda_codec_setup_stream - set up the codec for streaming * 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, ...@@ -2356,16 +2376,20 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
hda_nid_t nid; hda_nid_t nid;
int i; 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); 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; nid = codec->start_nid;
for (i = 0; i < codec->num_nodes; i++, nid++) { for (i = 0; i < codec->num_nodes; i++, nid++) {
unsigned int wcaps = get_wcaps(codec, nid); unsigned int wcaps = get_wcaps(codec, nid);
if (wcaps & AC_WCAP_POWER) { if (wcaps & AC_WCAP_POWER) {
unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> unsigned int wid_type = get_wcaps_type(wcaps);
AC_WCAP_TYPE_SHIFT;
if (power_state == AC_PWRST_D3 && if (power_state == AC_PWRST_D3 &&
wid_type == AC_WID_PIN) { wid_type == AC_WID_PIN) {
unsigned int pincap; unsigned int pincap;
...@@ -2573,7 +2597,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, ...@@ -2573,7 +2597,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
case 20: case 20:
case 24: case 24:
case 32: case 32:
if (maxbps >= 32) if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE)
val |= 0x40; val |= 0x40;
else if (maxbps >= 24) else if (maxbps >= 24)
val |= 0x30; val |= 0x30;
...@@ -2700,11 +2724,12 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, ...@@ -2700,11 +2724,12 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
bps = 20; bps = 20;
} }
} }
else if (streams == AC_SUPFMT_FLOAT32) { if (streams & AC_SUPFMT_FLOAT32) {
/* should be exclusive */
formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
bps = 32; if (!bps)
} else if (streams == AC_SUPFMT_AC3) { bps = 32;
}
if (streams == AC_SUPFMT_AC3) {
/* should be exclusive */ /* should be exclusive */
/* temporary hack: we have still no proper support /* temporary hack: we have still no proper support
* for the direct AC3 stream... * for the direct AC3 stream...
...@@ -3102,7 +3127,7 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, ...@@ -3102,7 +3127,7 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
tbl = q; tbl = q;
if (tbl->value >= 0 && tbl->value < num_configs) { if (tbl->value >= 0 && tbl->value < num_configs) {
#ifdef CONFIG_SND_DEBUG_DETECT #ifdef CONFIG_SND_DEBUG_VERBOSE
char tmp[10]; char tmp[10];
const char *model = NULL; const char *model = NULL;
if (models) if (models)
...@@ -3655,8 +3680,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, ...@@ -3655,8 +3680,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
end_nid = codec->start_nid + codec->num_nodes; end_nid = codec->start_nid + codec->num_nodes;
for (nid = codec->start_nid; nid < end_nid; nid++) { for (nid = codec->start_nid; nid < end_nid; nid++) {
unsigned int wid_caps = get_wcaps(codec, nid); unsigned int wid_caps = get_wcaps(codec, nid);
unsigned int wid_type = unsigned int wid_type = get_wcaps_type(wid_caps);
(wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
unsigned int def_conf; unsigned int def_conf;
short assoc, loc; short assoc, loc;
......
...@@ -830,7 +830,8 @@ enum { ...@@ -830,7 +830,8 @@ enum {
int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
struct hda_bus **busp); struct hda_bus **busp);
int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, 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 * low level functions
...@@ -938,6 +939,13 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {} ...@@ -938,6 +939,13 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {}
#define snd_hda_codec_needs_resume(codec) 1 #define snd_hda_codec_needs_resume(codec) 1
#endif #endif
#ifdef CONFIG_SND_HDA_PATCH_LOADER
/*
* patch firmware
*/
int snd_hda_load_patch(struct hda_bus *bus, const char *patch);
#endif
/* /*
* Codec modularization * Codec modularization
*/ */
......
...@@ -121,11 +121,17 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid ...@@ -121,11 +121,17 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
if (node == NULL) if (node == NULL)
return -ENOMEM; return -ENOMEM;
node->nid = nid; node->nid = nid;
nconns = snd_hda_get_connections(codec, nid, conn_list, node->wid_caps = get_wcaps(codec, nid);
HDA_MAX_CONNECTIONS); node->type = get_wcaps_type(node->wid_caps);
if (nconns < 0) { if (node->wid_caps & AC_WCAP_CONN_LIST) {
kfree(node); nconns = snd_hda_get_connections(codec, nid, conn_list,
return nconns; HDA_MAX_CONNECTIONS);
if (nconns < 0) {
kfree(node);
return nconns;
}
} else {
nconns = 0;
} }
if (nconns <= ARRAY_SIZE(node->slist)) if (nconns <= ARRAY_SIZE(node->slist))
node->conn_list = 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 ...@@ -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)); memcpy(node->conn_list, conn_list, nconns * sizeof(hda_nid_t));
node->nconns = nconns; 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) { if (node->type == AC_WID_PIN) {
node->pin_caps = snd_hda_query_pin_caps(codec, node->nid); node->pin_caps = snd_hda_query_pin_caps(codec, node->nid);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/firmware.h>
#include <sound/core.h> #include <sound/core.h>
#include "hda_codec.h" #include "hda_codec.h"
#include "hda_local.h" #include "hda_local.h"
...@@ -312,12 +313,8 @@ static ssize_t init_verbs_show(struct device *dev, ...@@ -312,12 +313,8 @@ static ssize_t init_verbs_show(struct device *dev,
return len; return len;
} }
static ssize_t init_verbs_store(struct device *dev, static int parse_init_verbs(struct hda_codec *codec, const char *buf)
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;
struct hda_verb *v; struct hda_verb *v;
int nid, verb, param; int nid, verb, param;
...@@ -331,6 +328,18 @@ static ssize_t init_verbs_store(struct device *dev, ...@@ -331,6 +328,18 @@ static ssize_t init_verbs_store(struct device *dev,
v->nid = nid; v->nid = nid;
v->verb = verb; v->verb = verb;
v->param = param; 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; return count;
} }
...@@ -376,19 +385,15 @@ static void remove_trail_spaces(char *str) ...@@ -376,19 +385,15 @@ static void remove_trail_spaces(char *str)
#define MAX_HINTS 1024 #define MAX_HINTS 1024
static ssize_t hints_store(struct device *dev, static int parse_hints(struct hda_codec *codec, const char *buf)
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 *key, *val; char *key, *val;
struct hda_hint *hint; struct hda_hint *hint;
while (isspace(*buf)) while (isspace(*buf))
buf++; buf++;
if (!*buf || *buf == '#' || *buf == '\n') if (!*buf || *buf == '#' || *buf == '\n')
return count; return 0;
if (*buf == '=') if (*buf == '=')
return -EINVAL; return -EINVAL;
key = kstrndup_noeol(buf, 1024); key = kstrndup_noeol(buf, 1024);
...@@ -411,7 +416,7 @@ static ssize_t hints_store(struct device *dev, ...@@ -411,7 +416,7 @@ static ssize_t hints_store(struct device *dev,
kfree(hint->key); kfree(hint->key);
hint->key = key; hint->key = key;
hint->val = val; hint->val = val;
return count; return 0;
} }
/* allocate a new hint entry */ /* allocate a new hint entry */
if (codec->hints.used >= MAX_HINTS) if (codec->hints.used >= MAX_HINTS)
...@@ -424,6 +429,18 @@ static ssize_t hints_store(struct device *dev, ...@@ -424,6 +429,18 @@ static ssize_t hints_store(struct device *dev,
} }
hint->key = key; hint->key = key;
hint->val = val; 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; return count;
} }
...@@ -469,20 +486,24 @@ static ssize_t driver_pin_configs_show(struct device *dev, ...@@ -469,20 +486,24 @@ static ssize_t driver_pin_configs_show(struct device *dev,
#define MAX_PIN_CONFIGS 32 #define MAX_PIN_CONFIGS 32
static ssize_t user_pin_configs_store(struct device *dev, static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
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 nid, cfg;
int err;
if (sscanf(buf, "%i %i", &nid, &cfg) != 2) if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
return -EINVAL; return -EINVAL;
if (!nid) if (!nid)
return -EINVAL; return -EINVAL;
err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); 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 err = parse_user_pin_configs(codec, buf);
if (err < 0) if (err < 0)
return err; return err;
return count; return count;
...@@ -553,3 +574,180 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) ...@@ -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); EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
#endif /* CONFIG_SND_HDA_RECONFIG */ #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}; ...@@ -61,6 +61,9 @@ static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_only[SNDRV_CARDS]; static int probe_only[SNDRV_CARDS];
static int single_cmd; static int single_cmd;
static int enable_msi; static int enable_msi;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
static char *patch[SNDRV_CARDS];
#endif
module_param_array(index, int, NULL, 0444); module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); 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 " ...@@ -84,6 +87,10 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
"(for debugging only)."); "(for debugging only).");
module_param(enable_msi, int, 0444); module_param(enable_msi, int, 0444);
MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); 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 #ifdef CONFIG_SND_HDA_POWER_SAVE
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
...@@ -1331,8 +1338,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { ...@@ -1331,8 +1338,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
[AZX_DRIVER_TERA] = 1, [AZX_DRIVER_TERA] = 1,
}; };
static int __devinit azx_codec_create(struct azx *chip, const char *model, static int __devinit azx_codec_create(struct azx *chip, const char *model)
int no_init)
{ {
struct hda_bus_template bus_temp; struct hda_bus_template bus_temp;
int c, codecs, err; int c, codecs, err;
...@@ -1391,7 +1397,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, ...@@ -1391,7 +1397,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
for (c = 0; c < max_slots; c++) { for (c = 0; c < max_slots; c++) {
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
struct hda_codec *codec; 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) if (err < 0)
continue; continue;
codecs++; codecs++;
...@@ -1401,7 +1407,16 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, ...@@ -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"); snd_printk(KERN_ERR SFX "no codecs initialized\n");
return -ENXIO; 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; return 0;
} }
...@@ -2284,6 +2299,30 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) ...@@ -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 * constructor
...@@ -2318,7 +2357,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, ...@@ -2318,7 +2357,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->pci = pci; chip->pci = pci;
chip->irq = -1; chip->irq = -1;
chip->driver_type = driver_type; chip->driver_type = driver_type;
chip->msi = enable_msi; check_msi(chip);
chip->dev_index = dev; chip->dev_index = dev;
INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
...@@ -2526,15 +2565,32 @@ static int __devinit azx_probe(struct pci_dev *pci, ...@@ -2526,15 +2565,32 @@ static int __devinit azx_probe(struct pci_dev *pci,
return err; 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); err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
if (err < 0) if (err < 0)
goto out_free; goto out_free;
card->private_data = chip; card->private_data = chip;
/* create codec instances */ /* create codec instances */
err = azx_codec_create(chip, model[dev], probe_only[dev]); err = azx_codec_create(chip, model[dev]);
if (err < 0) if (err < 0)
goto out_free; 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 */ /* create PCM streams */
err = snd_hda_build_pcms(chip->bus); err = snd_hda_build_pcms(chip->bus);
...@@ -2546,8 +2602,6 @@ static int __devinit azx_probe(struct pci_dev *pci, ...@@ -2546,8 +2602,6 @@ static int __devinit azx_probe(struct pci_dev *pci,
if (err < 0) if (err < 0)
goto out_free; goto out_free;
snd_card_set_dev(card, &pci->dev);
err = snd_card_register(card); err = snd_card_register(card);
if (err < 0) if (err < 0)
goto out_free; goto out_free;
...@@ -2649,11 +2703,15 @@ static struct pci_device_id azx_ids[] = { ...@@ -2649,11 +2703,15 @@ static struct pci_device_id azx_ids[] = {
/* this entry seems still valid -- i.e. without emu20kx chip */ /* this entry seems still valid -- i.e. without emu20kx chip */
{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC }, { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
#endif #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), { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff, .class_mask = 0xffffff,
.driver_data = AZX_DRIVER_GENERIC }, .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, } { 0, }
}; };
MODULE_DEVICE_TABLE(pci, azx_ids); MODULE_DEVICE_TABLE(pci, azx_ids);
......
...@@ -99,7 +99,6 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, ...@@ -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, int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char **slaves); unsigned int *tlv, const char **slaves);
int snd_hda_codec_reset(struct hda_codec *codec); int snd_hda_codec_reset(struct hda_codec *codec);
int snd_hda_codec_configure(struct hda_codec *codec);
/* amp value bits */ /* amp value bits */
#define HDA_AMP_MUTE 0x80 #define HDA_AMP_MUTE 0x80
...@@ -408,6 +407,19 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) ...@@ -408,6 +407,19 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
return codec->wcaps[nid - codec->start_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); 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, int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int caps); unsigned int caps);
......
...@@ -508,17 +508,14 @@ static void print_codec_info(struct snd_info_entry *entry, ...@@ -508,17 +508,14 @@ static void print_codec_info(struct snd_info_entry *entry,
unsigned int wid_caps = unsigned int wid_caps =
snd_hda_param_read(codec, nid, snd_hda_param_read(codec, nid,
AC_PAR_AUDIO_WIDGET_CAP); AC_PAR_AUDIO_WIDGET_CAP);
unsigned int wid_type = unsigned int wid_type = get_wcaps_type(wid_caps);
(wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
hda_nid_t conn[HDA_MAX_CONNECTIONS]; hda_nid_t conn[HDA_MAX_CONNECTIONS];
int conn_len = 0; int conn_len = 0;
snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
get_wid_type_name(wid_type), wid_caps); get_wid_type_name(wid_type), wid_caps);
if (wid_caps & AC_WCAP_STEREO) { if (wid_caps & AC_WCAP_STEREO) {
unsigned int chans; unsigned int chans = get_wcaps_channels(wid_caps);
chans = (wid_caps & AC_WCAP_CHAN_CNT_EXT) >> 13;
chans = ((chans << 1) | 1) + 1;
if (chans == 2) if (chans == 2)
snd_iprintf(buffer, " Stereo"); snd_iprintf(buffer, " Stereo");
else else
......
...@@ -2982,7 +2982,8 @@ static int patch_ad1988(struct hda_codec *codec) ...@@ -2982,7 +2982,8 @@ static int patch_ad1988(struct hda_codec *codec)
board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
ad1988_models, ad1988_cfg_tbl); ad1988_models, ad1988_cfg_tbl);
if (board_config < 0) { 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; board_config = AD1988_AUTO;
} }
...@@ -3702,19 +3703,29 @@ static struct hda_amp_list ad1884a_loopbacks[] = { ...@@ -3702,19 +3703,29 @@ static struct hda_amp_list ad1884a_loopbacks[] = {
* Port F: Internal speakers * Port F: Internal speakers
*/ */
static struct hda_input_mux ad1884a_laptop_capture_source = { static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
.num_items = 4, struct snd_ctl_elem_value *ucontrol)
.items = { {
{ "Mic", 0x0 }, /* port-B */ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
{ "Internal Mic", 0x1 }, /* port-C */ int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
{ "Dock Mic", 0x4 }, /* port-E */ int mute = (!ucontrol->value.integer.value[0] &&
{ "Mix", 0x3 }, !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[] = { static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), 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_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
HDA_CODEC_MUTE("PCM Playback Switch", 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[] = { ...@@ -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("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 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 */ { } /* 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[] = { static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
/*HDA_CODEC_MUTE("Master Playback Switch", 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) ...@@ -3828,6 +3812,63 @@ static int ad1884a_hp_init(struct hda_codec *codec)
return 0; 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 */ /* additional verbs for laptop model */
static struct hda_verb ad1884a_laptop_verbs[] = { static struct hda_verb ad1884a_laptop_verbs[] = {
/* Port-A (HP) pin - always unmuted */ /* Port-A (HP) pin - always unmuted */
...@@ -3844,11 +3885,19 @@ static struct hda_verb ad1884a_laptop_verbs[] = { ...@@ -3844,11 +3885,19 @@ static struct hda_verb ad1884a_laptop_verbs[] = {
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
{0x15, 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 */ /* analog mix */
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
/* unsolicited event for pin-sense */ /* unsolicited event for pin-sense */
{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, {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}, {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 */ { } /* end */
}; };
...@@ -4008,6 +4057,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = { ...@@ -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, 0x30d0, "HP laptop", AD1884A_LAPTOP),
SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "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, 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), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
{} {}
}; };
...@@ -4057,9 +4107,8 @@ static int patch_ad1884a(struct hda_codec *codec) ...@@ -4057,9 +4107,8 @@ static int patch_ad1884a(struct hda_codec *codec)
spec->mixers[0] = ad1884a_laptop_mixers; spec->mixers[0] = ad1884a_laptop_mixers;
spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
spec->multiout.dig_out_nid = 0; spec->multiout.dig_out_nid = 0;
spec->input_mux = &ad1884a_laptop_capture_source; codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; codec->patch_ops.init = ad1884a_laptop_init;
codec->patch_ops.init = ad1884a_hp_init;
/* set the upper-limit for mixer amp to 0dB for avoiding the /* set the upper-limit for mixer amp to 0dB for avoiding the
* possible damage by overloading * possible damage by overloading
*/ */
......
...@@ -141,8 +141,7 @@ static int atihdmi_build_pcms(struct hda_codec *codec) ...@@ -141,8 +141,7 @@ static int atihdmi_build_pcms(struct hda_codec *codec)
/* FIXME: we must check ELD and change the PCM parameters dynamically /* FIXME: we must check ELD and change the PCM parameters dynamically
*/ */
chans = get_wcaps(codec, CVT_NID); chans = get_wcaps(codec, CVT_NID);
chans = (chans & AC_WCAP_CHAN_CNT_EXT) >> 13; chans = get_wcaps_channels(chans);
chans = ((chans << 1) | 1) + 1;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
return 0; return 0;
......
...@@ -459,8 +459,7 @@ static void parse_input(struct hda_codec *codec) ...@@ -459,8 +459,7 @@ static void parse_input(struct hda_codec *codec)
nid = codec->start_nid; nid = codec->start_nid;
for (i = 0; i < codec->num_nodes; i++, nid++) { for (i = 0; i < codec->num_nodes; i++, nid++) {
unsigned int wcaps = get_wcaps(codec, nid); unsigned int wcaps = get_wcaps(codec, nid);
unsigned int type = (wcaps & AC_WCAP_TYPE) >> unsigned int type = get_wcaps_type(wcaps);
AC_WCAP_TYPE_SHIFT;
if (type != AC_WID_AUD_IN) if (type != AC_WID_AUD_IN)
continue; continue;
if (snd_hda_get_connections(codec, nid, &pin, 1) != 1) if (snd_hda_get_connections(codec, nid, &pin, 1) != 1)
......
This diff is collapsed.
...@@ -635,7 +635,8 @@ static int patch_cmi9880(struct hda_codec *codec) ...@@ -635,7 +635,8 @@ static int patch_cmi9880(struct hda_codec *codec)
cmi9880_models, cmi9880_models,
cmi9880_cfg_tbl); cmi9880_cfg_tbl);
if (spec->board_config < 0) { 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 */ spec->board_config = CMI_AUTO; /* try everything */
} }
......
This diff is collapsed.
...@@ -33,8 +33,8 @@ ...@@ -33,8 +33,8 @@
#include "hda_codec.h" #include "hda_codec.h"
#include "hda_local.h" #include "hda_local.h"
#define CVT_NID 0x02 /* audio converter */ static hda_nid_t cvt_nid; /* audio converter */
#define PIN_NID 0x03 /* HDMI output pin */ static hda_nid_t pin_nid; /* HDMI output pin */
#define INTEL_HDMI_EVENT_TAG 0x08 #define INTEL_HDMI_EVENT_TAG 0x08
...@@ -44,30 +44,6 @@ struct intel_hdmi_spec { ...@@ -44,30 +44,6 @@ struct intel_hdmi_spec {
struct hdmi_eld sink_eld; 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 { struct hdmi_audio_infoframe {
u8 type; /* 0x84 */ u8 type; /* 0x84 */
u8 ver; /* 0x01 */ u8 ver; /* 0x01 */
...@@ -244,11 +220,12 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, ...@@ -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) static void hdmi_enable_output(struct hda_codec *codec)
{ {
/* Unmute */ /* Unmute */
if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, PIN_NID, 0, snd_hda_codec_write(codec, pin_nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
/* Enable pin out */ /* 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) ...@@ -256,8 +233,8 @@ static void hdmi_enable_output(struct hda_codec *codec)
*/ */
static void hdmi_start_infoframe_trans(struct hda_codec *codec) static void hdmi_start_infoframe_trans(struct hda_codec *codec)
{ {
hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
AC_DIPXMIT_BEST); AC_DIPXMIT_BEST);
} }
...@@ -266,20 +243,20 @@ static void hdmi_start_infoframe_trans(struct hda_codec *codec) ...@@ -266,20 +243,20 @@ static void hdmi_start_infoframe_trans(struct hda_codec *codec)
*/ */
static void hdmi_stop_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); hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
AC_DIPXMIT_DISABLE); AC_DIPXMIT_DISABLE);
} }
static int hdmi_get_channel_count(struct hda_codec *codec) 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); AC_VERB_GET_CVT_CHAN_COUNT, 0);
} }
static void hdmi_set_channel_count(struct hda_codec *codec, int chs) 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); AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
if (chs != hdmi_get_channel_count(codec)) if (chs != hdmi_get_channel_count(codec))
...@@ -294,7 +271,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec) ...@@ -294,7 +271,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec)
int slot; int slot;
for (i = 0; i < 8; i++) { 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); AC_VERB_GET_HDMI_CHAN_SLOT, i);
printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
slot >> 4, slot & 0x7); slot >> 4, slot & 0x7);
...@@ -307,7 +284,7 @@ static void hdmi_parse_eld(struct hda_codec *codec) ...@@ -307,7 +284,7 @@ static void hdmi_parse_eld(struct hda_codec *codec)
struct intel_hdmi_spec *spec = codec->spec; struct intel_hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld = &spec->sink_eld; 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); snd_hdmi_show_eld(eld);
} }
...@@ -322,11 +299,11 @@ static void hdmi_debug_dip_size(struct hda_codec *codec) ...@@ -322,11 +299,11 @@ static void hdmi_debug_dip_size(struct hda_codec *codec)
int i; int i;
int size; 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); printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size);
for (i = 0; i < 8; i++) { 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); AC_VERB_GET_HDMI_DIP_SIZE, i);
printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); 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) ...@@ -340,15 +317,15 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec)
int size; int size;
int pi, bi; int pi, bi;
for (i = 0; i < 8; i++) { 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); AC_VERB_GET_HDMI_DIP_SIZE, i);
if (size == 0) if (size == 0)
continue; 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++) { for (j = 1; j < 1000; j++) {
hdmi_write_dip_byte(codec, PIN_NID, 0x0); hdmi_write_dip_byte(codec, pin_nid, 0x0);
hdmi_get_dip_index(codec, PIN_NID, &pi, &bi); hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
if (pi != i) if (pi != i)
snd_printd(KERN_INFO "dip index %d: %d != %d\n", snd_printd(KERN_INFO "dip index %d: %d != %d\n",
bi, pi, i); bi, pi, i);
...@@ -376,9 +353,9 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec, ...@@ -376,9 +353,9 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
sum += params[i]; sum += params[i];
ai->checksum = - sum; 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++) 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, ...@@ -465,6 +442,8 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec,
static void hdmi_setup_channel_mapping(struct hda_codec *codec, static void hdmi_setup_channel_mapping(struct hda_codec *codec,
struct hdmi_audio_infoframe *ai) struct hdmi_audio_infoframe *ai)
{ {
int i;
if (!ai->CA) if (!ai->CA)
return; return;
...@@ -473,7 +452,11 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, ...@@ -473,7 +452,11 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec,
* ALSA sequence is front/surr/clfe/side? * 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); hdmi_debug_channel_mapping(codec);
} }
...@@ -597,7 +580,6 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = { ...@@ -597,7 +580,6 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = {
.substreams = 1, .substreams = 1,
.channels_min = 2, .channels_min = 2,
.channels_max = 8, .channels_max = 8,
.nid = CVT_NID, /* NID to query formats and rates and setup streams */
.ops = { .ops = {
.open = intel_hdmi_playback_pcm_open, .open = intel_hdmi_playback_pcm_open,
.close = intel_hdmi_playback_pcm_close, .close = intel_hdmi_playback_pcm_close,
...@@ -613,6 +595,9 @@ static int intel_hdmi_build_pcms(struct hda_codec *codec) ...@@ -613,6 +595,9 @@ static int intel_hdmi_build_pcms(struct hda_codec *codec)
codec->num_pcms = 1; codec->num_pcms = 1;
codec->pcm_info = info; 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->name = "INTEL HDMI";
info->pcm_type = HDA_PCM_TYPE_HDMI; info->pcm_type = HDA_PCM_TYPE_HDMI;
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback;
...@@ -636,8 +621,9 @@ static int intel_hdmi_init(struct hda_codec *codec) ...@@ -636,8 +621,9 @@ static int intel_hdmi_init(struct hda_codec *codec)
{ {
hdmi_enable_output(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; return 0;
} }
...@@ -657,7 +643,7 @@ static struct hda_codec_ops intel_hdmi_patch_ops = { ...@@ -657,7 +643,7 @@ static struct hda_codec_ops intel_hdmi_patch_ops = {
.unsol_event = intel_hdmi_unsol_event, .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; struct intel_hdmi_spec *spec;
...@@ -667,7 +653,7 @@ static int patch_intel_hdmi(struct hda_codec *codec) ...@@ -667,7 +653,7 @@ static int patch_intel_hdmi(struct hda_codec *codec)
spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.num_dacs = 0; /* no analog */
spec->multiout.max_channels = 8; spec->multiout.max_channels = 8;
spec->multiout.dig_out_nid = CVT_NID; spec->multiout.dig_out_nid = cvt_nid;
codec->spec = spec; codec->spec = spec;
codec->patch_ops = intel_hdmi_patch_ops; codec->patch_ops = intel_hdmi_patch_ops;
...@@ -679,12 +665,27 @@ static int patch_intel_hdmi(struct hda_codec *codec) ...@@ -679,12 +665,27 @@ static int patch_intel_hdmi(struct hda_codec *codec)
return 0; 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[] = { static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
{ .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi },
{ .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi },
{ .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi },
{ .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi },
{ .id = 0x80862804, .name = "G45 DEVIBX", .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 }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
{} /* terminator */ {} /* terminator */
}; };
...@@ -694,6 +695,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862801"); ...@@ -694,6 +695,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862801");
MODULE_ALIAS("snd-hda-codec-id:80862802"); MODULE_ALIAS("snd-hda-codec-id:80862802");
MODULE_ALIAS("snd-hda-codec-id:80862803"); MODULE_ALIAS("snd-hda-codec-id:80862803");
MODULE_ALIAS("snd-hda-codec-id:80862804"); MODULE_ALIAS("snd-hda-codec-id:80862804");
MODULE_ALIAS("snd-hda-codec-id:80860054");
MODULE_ALIAS("snd-hda-codec-id:10951392"); MODULE_ALIAS("snd-hda-codec-id:10951392");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -377,6 +377,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) ...@@ -377,6 +377,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
*/ */
static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
{ .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, { .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 = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch },
{ .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch },
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
...@@ -385,6 +386,7 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { ...@@ -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:10de0002");
MODULE_ALIAS("snd-hda-codec-id:10de0003");
MODULE_ALIAS("snd-hda-codec-id:10de0006"); MODULE_ALIAS("snd-hda-codec-id:10de0006");
MODULE_ALIAS("snd-hda-codec-id:10de0007"); MODULE_ALIAS("snd-hda-codec-id:10de0007");
MODULE_ALIAS("snd-hda-codec-id:10de0067"); MODULE_ALIAS("snd-hda-codec-id:10de0067");
......
This diff is collapsed.
This diff is collapsed.
...@@ -1339,8 +1339,7 @@ static int get_mux_nids(struct hda_codec *codec) ...@@ -1339,8 +1339,7 @@ static int get_mux_nids(struct hda_codec *codec)
for (i = 0; i < spec->num_adc_nids; i++) { for (i = 0; i < spec->num_adc_nids; i++) {
nid = spec->adc_nids[i]; nid = spec->adc_nids[i];
while (nid) { while (nid) {
type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) type = get_wcaps_type(get_wcaps(codec, nid));
>> AC_WCAP_TYPE_SHIFT;
if (type == AC_WID_PIN) if (type == AC_WID_PIN)
break; break;
n = snd_hda_get_connections(codec, nid, conn, n = snd_hda_get_connections(codec, nid, conn,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment