Merge branch 'topic/hda' into for-linus
This commit is contained in:
commit
e7bfbb0215
|
@ -741,6 +741,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
|||
model - force the model name
|
||||
position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF)
|
||||
probe_mask - Bitmask to probe codecs (default = -1, meaning all slots)
|
||||
When the bit 8 (0x100) is set, the lower 8 bits are used
|
||||
as the "fixed" codec slots; i.e. the driver probes the
|
||||
slots regardless what hardware reports back
|
||||
probe_only - Only probing and no codec initialization (default=off);
|
||||
Useful to check the initial codec status for debugging
|
||||
bdl_pos_adj - Specifies the DMA IRQ timing delay in samples.
|
||||
|
|
|
@ -56,6 +56,7 @@ ALC262
|
|||
sony-assamd Sony ASSAMD
|
||||
toshiba-s06 Toshiba S06
|
||||
toshiba-rx1 Toshiba RX1
|
||||
tyan Tyan Thunder n6650W (S2915-E)
|
||||
ultra Samsung Q1 Ultra Vista model
|
||||
lenovo-3000 Lenovo 3000 y410
|
||||
nec NEC Versa S9100
|
||||
|
@ -261,6 +262,8 @@ Conexant 5051
|
|||
=============
|
||||
laptop Basic Laptop config (default)
|
||||
hp HP Spartan laptop
|
||||
hp-dv6736 HP dv6736
|
||||
lenovo-x200 Lenovo X200 laptop
|
||||
|
||||
STAC9200
|
||||
========
|
||||
|
@ -278,6 +281,7 @@ STAC9200
|
|||
gateway-m4 Gateway laptops with EAPD control
|
||||
gateway-m4-2 Gateway laptops with EAPD control
|
||||
panasonic Panasonic CF-74
|
||||
auto BIOS setup (default)
|
||||
|
||||
STAC9205/9254
|
||||
=============
|
||||
|
@ -285,6 +289,8 @@ STAC9205/9254
|
|||
dell-m42 Dell (unknown)
|
||||
dell-m43 Dell Precision
|
||||
dell-m44 Dell Inspiron
|
||||
eapd Keep EAPD on (e.g. Gateway T1616)
|
||||
auto BIOS setup (default)
|
||||
|
||||
STAC9220/9221
|
||||
=============
|
||||
|
@ -308,6 +314,7 @@ STAC9220/9221
|
|||
dell-d82 Dell (unknown)
|
||||
dell-m81 Dell (unknown)
|
||||
dell-m82 Dell XPS M1210
|
||||
auto BIOS setup (default)
|
||||
|
||||
STAC9202/9250/9251
|
||||
==================
|
||||
|
@ -319,6 +326,7 @@ STAC9202/9250/9251
|
|||
m3 Some Gateway MX series laptops
|
||||
m5 Some Gateway MX series laptops (MP6954)
|
||||
m6 Some Gateway NX series laptops
|
||||
auto BIOS setup (default)
|
||||
|
||||
STAC9227/9228/9229/927x
|
||||
=======================
|
||||
|
@ -328,6 +336,7 @@ STAC9227/9228/9229/927x
|
|||
5stack D965 5stack + SPDIF
|
||||
dell-3stack Dell Dimension E520
|
||||
dell-bios Fixes with Dell BIOS setup
|
||||
auto BIOS setup (default)
|
||||
|
||||
STAC92HD71B*
|
||||
============
|
||||
|
@ -335,7 +344,10 @@ STAC92HD71B*
|
|||
dell-m4-1 Dell desktops
|
||||
dell-m4-2 Dell desktops
|
||||
dell-m4-3 Dell desktops
|
||||
hp-m4 HP dv laptops
|
||||
hp-m4 HP mini 1000
|
||||
hp-dv5 HP dv series
|
||||
hp-hdx HP HDX series
|
||||
auto BIOS setup (default)
|
||||
|
||||
STAC92HD73*
|
||||
===========
|
||||
|
@ -345,13 +357,16 @@ STAC92HD73*
|
|||
dell-m6-dmic Dell desktops/laptops with digital mics
|
||||
dell-m6 Dell desktops/laptops with both type of mics
|
||||
dell-eq Dell desktops/laptops
|
||||
auto BIOS setup (default)
|
||||
|
||||
STAC92HD83*
|
||||
===========
|
||||
ref Reference board
|
||||
mic-ref Reference board with power managment for ports
|
||||
dell-s14 Dell laptop
|
||||
auto BIOS setup (default)
|
||||
|
||||
STAC9872
|
||||
========
|
||||
vaio Setup for VAIO FE550G/SZ110
|
||||
vaio-ar Setup for VAIO AR
|
||||
vaio VAIO laptop without SPDIF
|
||||
auto BIOS setup (default)
|
||||
|
|
|
@ -109,6 +109,13 @@ slot, pass `probe_mask=1`. For the first and the third slots, pass
|
|||
Since 2.6.29 kernel, the driver has a more robust probing method, so
|
||||
this error might happen rarely, though.
|
||||
|
||||
On a machine with a broken BIOS, sometimes you need to force the
|
||||
driver to probe the codec slots the hardware doesn't report for use.
|
||||
In such a case, turn the bit 8 (0x100) of `probe_mask` option on.
|
||||
Then the rest 8 bits are passed as the codec slots to probe
|
||||
unconditionally. For example, `probe_mask=0x103` will force to probe
|
||||
the codec slots 0 and 1 no matter what the hardware reports.
|
||||
|
||||
|
||||
Interrupt Handling
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
@ -358,10 +365,26 @@ modelname::
|
|||
to this file.
|
||||
init_verbs::
|
||||
The extra verbs to execute at initialization. You can add a verb by
|
||||
writing to this file. Pass tree numbers, nid, verb and parameter.
|
||||
writing to this file. Pass three numbers: nid, verb and parameter
|
||||
(separated with a space).
|
||||
hints::
|
||||
Shows hint strings for codec parsers for any use. Right now it's
|
||||
not used.
|
||||
Shows / stores hint strings for codec parsers for any use.
|
||||
Its format is `key = value`. For example, passing `hp_detect = yes`
|
||||
to IDT/STAC codec parser will result in the disablement of the
|
||||
headphone detection.
|
||||
init_pin_configs::
|
||||
Shows the initial pin default config values set by BIOS.
|
||||
driver_pin_configs::
|
||||
Shows the pin default values set by the codec parser explicitly.
|
||||
This doesn't show all pin values but only the changed values by
|
||||
the parser. That is, if the parser doesn't change the pin default
|
||||
config values by itself, this will contain nothing.
|
||||
user_pin_configs::
|
||||
Shows the pin default config values to override the BIOS setup.
|
||||
Writing this (with two numbers, NID and value) appends the new
|
||||
value. The given will be used instead of the initial BIOS value at
|
||||
the next reconfiguration time. Note that this config will override
|
||||
even the driver pin configs, too.
|
||||
reconfig::
|
||||
Triggers the codec re-configuration. When any value is written to
|
||||
this file, the driver re-initialize and parses the codec tree
|
||||
|
@ -371,6 +394,14 @@ clear::
|
|||
Resets the codec, removes the mixer elements and PCM stuff of the
|
||||
specified codec, and clear all init verbs and hints.
|
||||
|
||||
For example, when you want to change the pin default configuration
|
||||
value of the pin widget 0x14 to 0x9993013f, and let the driver
|
||||
re-configure based on that state, run like below:
|
||||
------------------------------------------------------------------------
|
||||
# echo 0x14 0x9993013f > /sys/class/sound/hwC0D0/user_pin_configs
|
||||
# echo 1 > /sys/class/sound/hwC0D0/reconfig
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
Power-Saving
|
||||
~~~~~~~~~~~~
|
||||
|
@ -461,6 +492,16 @@ run with `--no-upload` option, and attach the generated file.
|
|||
There are some other useful options. See `--help` option output for
|
||||
details.
|
||||
|
||||
When a probe error occurs or when the driver obviously assigns a
|
||||
mismatched model, it'd be helpful to load the driver with
|
||||
`probe_only=1` option (at best after the cold reboot) and run
|
||||
alsa-info at this state. With this option, the driver won't configure
|
||||
the mixer and PCM but just tries to probe the codec slot. After
|
||||
probing, the proc file is available, so you can get the raw codec
|
||||
information before modified by the driver. Of course, the driver
|
||||
isn't usable with `probe_only=1`. But you can continue the
|
||||
configuration via hwdep sysfs file if hda-reconfig option is enabled.
|
||||
|
||||
|
||||
hda-verb
|
||||
~~~~~~~~
|
||||
|
|
|
@ -2112,6 +2112,8 @@
|
|||
#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
|
||||
#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274
|
||||
|
||||
#define PCI_VENDOR_ID_DFI 0x15bd
|
||||
|
||||
#define PCI_VENDOR_ID_QUICKNET 0x15e2
|
||||
#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500
|
||||
|
||||
|
|
|
@ -138,6 +138,7 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
|
|||
|
||||
input_unregister_device(beep->dev);
|
||||
kfree(beep);
|
||||
codec->beep = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);
|
||||
|
|
|
@ -39,7 +39,7 @@ struct hda_beep {
|
|||
int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
|
||||
void snd_hda_detach_beep_device(struct hda_codec *codec);
|
||||
#else
|
||||
#define snd_hda_attach_beep_device(...)
|
||||
#define snd_hda_attach_beep_device(...) 0
|
||||
#define snd_hda_detach_beep_device(...)
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -647,9 +647,9 @@ static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec)
|
|||
|
||||
total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
|
||||
for (i = 0; i < total_nodes; i++, nid++) {
|
||||
unsigned int func;
|
||||
func = snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE);
|
||||
switch (func & 0xff) {
|
||||
codec->function_id = snd_hda_param_read(codec, nid,
|
||||
AC_PAR_FUNCTION_TYPE) & 0xff;
|
||||
switch (codec->function_id) {
|
||||
case AC_GRP_AUDIO_FUNCTION:
|
||||
codec->afg = nid;
|
||||
break;
|
||||
|
@ -682,11 +682,140 @@ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* read all pin default configurations and save codec->init_pins */
|
||||
static int read_pin_defaults(struct hda_codec *codec)
|
||||
{
|
||||
int i;
|
||||
hda_nid_t nid = codec->start_nid;
|
||||
|
||||
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;
|
||||
if (wid_type != AC_WID_PIN)
|
||||
continue;
|
||||
pin = snd_array_new(&codec->init_pins);
|
||||
if (!pin)
|
||||
return -ENOMEM;
|
||||
pin->nid = nid;
|
||||
pin->cfg = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* look up the given pin config list and return the item matching with NID */
|
||||
static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec,
|
||||
struct snd_array *array,
|
||||
hda_nid_t nid)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < array->used; i++) {
|
||||
struct hda_pincfg *pin = snd_array_elem(array, i);
|
||||
if (pin->nid == nid)
|
||||
return pin;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* write a config value for the given NID */
|
||||
static void set_pincfg(struct hda_codec *codec, hda_nid_t nid,
|
||||
unsigned int cfg)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
|
||||
cfg & 0xff);
|
||||
cfg >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* set the current pin config value for the given NID.
|
||||
* the value is cached, and read via snd_hda_codec_get_pincfg()
|
||||
*/
|
||||
int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
|
||||
hda_nid_t nid, unsigned int cfg)
|
||||
{
|
||||
struct hda_pincfg *pin;
|
||||
unsigned int oldcfg;
|
||||
|
||||
oldcfg = snd_hda_codec_get_pincfg(codec, nid);
|
||||
pin = look_up_pincfg(codec, list, nid);
|
||||
if (!pin) {
|
||||
pin = snd_array_new(list);
|
||||
if (!pin)
|
||||
return -ENOMEM;
|
||||
pin->nid = nid;
|
||||
}
|
||||
pin->cfg = cfg;
|
||||
|
||||
/* change only when needed; e.g. if the pincfg is already present
|
||||
* in user_pins[], don't write it
|
||||
*/
|
||||
cfg = snd_hda_codec_get_pincfg(codec, nid);
|
||||
if (oldcfg != cfg)
|
||||
set_pincfg(codec, nid, cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_hda_codec_set_pincfg(struct hda_codec *codec,
|
||||
hda_nid_t nid, unsigned int cfg)
|
||||
{
|
||||
return snd_hda_add_pincfg(codec, &codec->driver_pins, nid, cfg);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg);
|
||||
|
||||
/* get the current pin config value of the given pin NID */
|
||||
unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
struct hda_pincfg *pin;
|
||||
|
||||
#ifdef CONFIG_SND_HDA_HWDEP
|
||||
pin = look_up_pincfg(codec, &codec->user_pins, nid);
|
||||
if (pin)
|
||||
return pin->cfg;
|
||||
#endif
|
||||
pin = look_up_pincfg(codec, &codec->driver_pins, nid);
|
||||
if (pin)
|
||||
return pin->cfg;
|
||||
pin = look_up_pincfg(codec, &codec->init_pins, nid);
|
||||
if (pin)
|
||||
return pin->cfg;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg);
|
||||
|
||||
/* restore all current pin configs */
|
||||
static void restore_pincfgs(struct hda_codec *codec)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < codec->init_pins.used; i++) {
|
||||
struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
|
||||
set_pincfg(codec, pin->nid,
|
||||
snd_hda_codec_get_pincfg(codec, pin->nid));
|
||||
}
|
||||
}
|
||||
|
||||
static void init_hda_cache(struct hda_cache_rec *cache,
|
||||
unsigned int record_size);
|
||||
static void free_hda_cache(struct hda_cache_rec *cache);
|
||||
|
||||
/* restore the initial pin cfgs and release all pincfg lists */
|
||||
static void restore_init_pincfgs(struct hda_codec *codec)
|
||||
{
|
||||
/* first free driver_pins and user_pins, then call restore_pincfg
|
||||
* so that only the values in init_pins are restored
|
||||
*/
|
||||
snd_array_free(&codec->driver_pins);
|
||||
#ifdef CONFIG_SND_HDA_HWDEP
|
||||
snd_array_free(&codec->user_pins);
|
||||
#endif
|
||||
restore_pincfgs(codec);
|
||||
snd_array_free(&codec->init_pins);
|
||||
}
|
||||
|
||||
/*
|
||||
* codec destructor
|
||||
*/
|
||||
|
@ -694,6 +823,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
|
|||
{
|
||||
if (!codec)
|
||||
return;
|
||||
restore_init_pincfgs(codec);
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
cancel_delayed_work(&codec->power_work);
|
||||
flush_workqueue(codec->bus->workq);
|
||||
|
@ -712,6 +842,9 @@ static void snd_hda_codec_free(struct hda_codec *codec)
|
|||
kfree(codec);
|
||||
}
|
||||
|
||||
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state);
|
||||
|
||||
/**
|
||||
* snd_hda_codec_new - create a HDA codec
|
||||
* @bus: the bus to assign
|
||||
|
@ -751,6 +884,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
|
|||
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
|
||||
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
|
||||
snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32);
|
||||
snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
|
||||
snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
|
||||
if (codec->bus->modelname) {
|
||||
codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
|
||||
if (!codec->modelname) {
|
||||
|
@ -787,15 +922,18 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
|
|||
setup_fg_nodes(codec);
|
||||
if (!codec->afg && !codec->mfg) {
|
||||
snd_printdd("hda_codec: no AFG or MFG node found\n");
|
||||
snd_hda_codec_free(codec);
|
||||
return -ENODEV;
|
||||
err = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg) < 0) {
|
||||
err = read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
|
||||
snd_hda_codec_free(codec);
|
||||
return -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
err = read_pin_defaults(codec);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
if (!codec->subsystem_id) {
|
||||
hda_nid_t nid = codec->afg ? codec->afg : codec->mfg;
|
||||
|
@ -806,12 +944,15 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
|
|||
if (bus->modelname)
|
||||
codec->modelname = kstrdup(bus->modelname, GFP_KERNEL);
|
||||
|
||||
/* power-up all before initialization */
|
||||
hda_set_power_state(codec,
|
||||
codec->afg ? codec->afg : codec->mfg,
|
||||
AC_PWRST_D0);
|
||||
|
||||
if (do_init) {
|
||||
err = snd_hda_codec_configure(codec);
|
||||
if (err < 0) {
|
||||
snd_hda_codec_free(codec);
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
snd_hda_codec_proc_new(codec);
|
||||
|
||||
|
@ -824,6 +965,10 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
|
|||
if (codecp)
|
||||
*codecp = codec;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
snd_hda_codec_free(codec);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_codec_new);
|
||||
|
||||
|
@ -907,6 +1052,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream);
|
|||
|
||||
/* FIXME: more better hash key? */
|
||||
#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
|
||||
#define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
|
||||
#define INFO_AMP_CAPS (1<<0)
|
||||
#define INFO_AMP_VOL(ch) (1 << (1 + (ch)))
|
||||
|
||||
|
@ -997,6 +1143,21 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
|
|||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
|
||||
|
||||
u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
struct hda_amp_info *info;
|
||||
|
||||
info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
|
||||
if (!info)
|
||||
return 0;
|
||||
if (!info->head.val) {
|
||||
info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
|
||||
info->head.val |= INFO_AMP_CAPS;
|
||||
}
|
||||
return info->amp_caps;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
|
||||
|
||||
/*
|
||||
* read the current volume to info
|
||||
* if the cache exists, read the cache value.
|
||||
|
@ -1120,6 +1281,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
|
|||
u16 nid = get_amp_nid(kcontrol);
|
||||
u8 chs = get_amp_channels(kcontrol);
|
||||
int dir = get_amp_direction(kcontrol);
|
||||
unsigned int ofs = get_amp_offset(kcontrol);
|
||||
u32 caps;
|
||||
|
||||
caps = query_amp_caps(codec, nid, dir);
|
||||
|
@ -1131,6 +1293,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
|
|||
kcontrol->id.name);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ofs < caps)
|
||||
caps -= ofs;
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = chs == 3 ? 2 : 1;
|
||||
uinfo->value.integer.min = 0;
|
||||
|
@ -1139,6 +1303,32 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
|
|||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
|
||||
|
||||
|
||||
static inline unsigned int
|
||||
read_amp_value(struct hda_codec *codec, hda_nid_t nid,
|
||||
int ch, int dir, int idx, unsigned int ofs)
|
||||
{
|
||||
unsigned int val;
|
||||
val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx);
|
||||
val &= HDA_AMP_VOLMASK;
|
||||
if (val >= ofs)
|
||||
val -= ofs;
|
||||
else
|
||||
val = 0;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline int
|
||||
update_amp_value(struct hda_codec *codec, hda_nid_t nid,
|
||||
int ch, int dir, int idx, unsigned int ofs,
|
||||
unsigned int val)
|
||||
{
|
||||
if (val > 0)
|
||||
val += ofs;
|
||||
return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
|
||||
HDA_AMP_VOLMASK, val);
|
||||
}
|
||||
|
||||
int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
|
@ -1147,14 +1337,13 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
|
|||
int chs = get_amp_channels(kcontrol);
|
||||
int dir = get_amp_direction(kcontrol);
|
||||
int idx = get_amp_index(kcontrol);
|
||||
unsigned int ofs = get_amp_offset(kcontrol);
|
||||
long *valp = ucontrol->value.integer.value;
|
||||
|
||||
if (chs & 1)
|
||||
*valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx)
|
||||
& HDA_AMP_VOLMASK;
|
||||
*valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs);
|
||||
if (chs & 2)
|
||||
*valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx)
|
||||
& HDA_AMP_VOLMASK;
|
||||
*valp = read_amp_value(codec, nid, 1, dir, idx, ofs);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get);
|
||||
|
@ -1167,18 +1356,17 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
|
|||
int chs = get_amp_channels(kcontrol);
|
||||
int dir = get_amp_direction(kcontrol);
|
||||
int idx = get_amp_index(kcontrol);
|
||||
unsigned int ofs = get_amp_offset(kcontrol);
|
||||
long *valp = ucontrol->value.integer.value;
|
||||
int change = 0;
|
||||
|
||||
snd_hda_power_up(codec);
|
||||
if (chs & 1) {
|
||||
change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
|
||||
0x7f, *valp);
|
||||
change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
|
||||
valp++;
|
||||
}
|
||||
if (chs & 2)
|
||||
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
|
||||
0x7f, *valp);
|
||||
change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
|
||||
snd_hda_power_down(codec);
|
||||
return change;
|
||||
}
|
||||
|
@ -1190,6 +1378,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
|||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
hda_nid_t nid = get_amp_nid(kcontrol);
|
||||
int dir = get_amp_direction(kcontrol);
|
||||
unsigned int ofs = get_amp_offset(kcontrol);
|
||||
u32 caps, val1, val2;
|
||||
|
||||
if (size < 4 * sizeof(unsigned int))
|
||||
|
@ -1198,6 +1387,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
|||
val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
|
||||
val2 = (val2 + 1) * 25;
|
||||
val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
|
||||
val1 += ofs;
|
||||
val1 = ((int)val1) * ((int)val2);
|
||||
if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
|
||||
return -EFAULT;
|
||||
|
@ -1268,7 +1458,6 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
|
|||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
|
||||
|
||||
#ifdef CONFIG_SND_HDA_RECONFIG
|
||||
/* Clear all controls assigned to the given codec */
|
||||
void snd_hda_ctls_clear(struct hda_codec *codec)
|
||||
{
|
||||
|
@ -1279,9 +1468,52 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
|
|||
snd_array_free(&codec->mixers);
|
||||
}
|
||||
|
||||
void snd_hda_codec_reset(struct hda_codec *codec)
|
||||
/* pseudo device locking
|
||||
* toggle card->shutdown to allow/disallow the device access (as a hack)
|
||||
*/
|
||||
static int hda_lock_devices(struct snd_card *card)
|
||||
{
|
||||
int i;
|
||||
spin_lock(&card->files_lock);
|
||||
if (card->shutdown) {
|
||||
spin_unlock(&card->files_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
card->shutdown = 1;
|
||||
spin_unlock(&card->files_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hda_unlock_devices(struct snd_card *card)
|
||||
{
|
||||
spin_lock(&card->files_lock);
|
||||
card->shutdown = 0;
|
||||
spin_unlock(&card->files_lock);
|
||||
}
|
||||
|
||||
int snd_hda_codec_reset(struct hda_codec *codec)
|
||||
{
|
||||
struct snd_card *card = codec->bus->card;
|
||||
int i, pcm;
|
||||
|
||||
if (hda_lock_devices(card) < 0)
|
||||
return -EBUSY;
|
||||
/* check whether the codec isn't used by any mixer or PCM streams */
|
||||
if (!list_empty(&card->ctl_files)) {
|
||||
hda_unlock_devices(card);
|
||||
return -EBUSY;
|
||||
}
|
||||
for (pcm = 0; pcm < codec->num_pcms; pcm++) {
|
||||
struct hda_pcm *cpcm = &codec->pcm_info[pcm];
|
||||
if (!cpcm->pcm)
|
||||
continue;
|
||||
if (cpcm->pcm->streams[0].substream_opened ||
|
||||
cpcm->pcm->streams[1].substream_opened) {
|
||||
hda_unlock_devices(card);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
/* OK, let it free */
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
cancel_delayed_work(&codec->power_work);
|
||||
|
@ -1291,8 +1523,7 @@ void snd_hda_codec_reset(struct hda_codec *codec)
|
|||
/* relase PCMs */
|
||||
for (i = 0; i < codec->num_pcms; i++) {
|
||||
if (codec->pcm_info[i].pcm) {
|
||||
snd_device_free(codec->bus->card,
|
||||
codec->pcm_info[i].pcm);
|
||||
snd_device_free(card, codec->pcm_info[i].pcm);
|
||||
clear_bit(codec->pcm_info[i].device,
|
||||
codec->bus->pcm_dev_bits);
|
||||
}
|
||||
|
@ -1305,13 +1536,22 @@ void snd_hda_codec_reset(struct hda_codec *codec)
|
|||
free_hda_cache(&codec->cmd_cache);
|
||||
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
|
||||
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
|
||||
/* free only driver_pins so that init_pins + user_pins are restored */
|
||||
snd_array_free(&codec->driver_pins);
|
||||
restore_pincfgs(codec);
|
||||
codec->num_pcms = 0;
|
||||
codec->pcm_info = NULL;
|
||||
codec->preset = NULL;
|
||||
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
|
||||
codec->slave_dig_outs = NULL;
|
||||
codec->spdif_status_reset = 0;
|
||||
module_put(codec->owner);
|
||||
codec->owner = NULL;
|
||||
|
||||
/* allow device access again */
|
||||
hda_unlock_devices(card);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SND_HDA_RECONFIG */
|
||||
|
||||
/* create a virtual master control and add slaves */
|
||||
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
||||
|
@ -1336,15 +1576,20 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
|||
|
||||
for (s = slaves; *s; s++) {
|
||||
struct snd_kcontrol *sctl;
|
||||
|
||||
sctl = snd_hda_find_mixer_ctl(codec, *s);
|
||||
if (!sctl) {
|
||||
snd_printdd("Cannot find slave %s, skipped\n", *s);
|
||||
continue;
|
||||
int i = 0;
|
||||
for (;;) {
|
||||
sctl = _snd_hda_find_mixer_ctl(codec, *s, i);
|
||||
if (!sctl) {
|
||||
if (!i)
|
||||
snd_printdd("Cannot find slave %s, "
|
||||
"skipped\n", *s);
|
||||
break;
|
||||
}
|
||||
err = snd_ctl_add_slave(kctl, sctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
i++;
|
||||
}
|
||||
err = snd_ctl_add_slave(kctl, sctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1955,6 +2200,8 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
|
|||
}
|
||||
for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
|
||||
kctl = snd_ctl_new1(dig_mix, codec);
|
||||
if (!kctl)
|
||||
return -ENOMEM;
|
||||
kctl->private_value = nid;
|
||||
err = snd_hda_ctl_add(codec, kctl);
|
||||
if (err < 0)
|
||||
|
@ -2074,8 +2321,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
|||
* don't power down the widget if it controls
|
||||
* eapd and EAPD_BTLENABLE is set.
|
||||
*/
|
||||
pincap = snd_hda_param_read(codec, nid,
|
||||
AC_PAR_PIN_CAP);
|
||||
pincap = snd_hda_query_pin_caps(codec, nid);
|
||||
if (pincap & AC_PINCAP_EAPD) {
|
||||
int eapd = snd_hda_codec_read(codec,
|
||||
nid, 0,
|
||||
|
@ -2144,6 +2390,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
|
|||
hda_set_power_state(codec,
|
||||
codec->afg ? codec->afg : codec->mfg,
|
||||
AC_PWRST_D0);
|
||||
restore_pincfgs(codec); /* restore all current pin configs */
|
||||
hda_exec_init_verbs(codec);
|
||||
if (codec->patch_ops.resume)
|
||||
codec->patch_ops.resume(codec);
|
||||
|
@ -2171,8 +2418,16 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
|
|||
|
||||
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||
int err = snd_hda_codec_build_controls(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "hda_codec: cannot build controls"
|
||||
"for #%d (error %d)\n", codec->addr, err);
|
||||
err = snd_hda_codec_reset(codec);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR
|
||||
"hda_codec: cannot revert codec\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -2181,19 +2436,12 @@ EXPORT_SYMBOL_HDA(snd_hda_build_controls);
|
|||
int snd_hda_codec_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
int err = 0;
|
||||
/* fake as if already powered-on */
|
||||
hda_keep_power_on(codec);
|
||||
/* then fire up */
|
||||
hda_set_power_state(codec,
|
||||
codec->afg ? codec->afg : codec->mfg,
|
||||
AC_PWRST_D0);
|
||||
hda_exec_init_verbs(codec);
|
||||
/* continue to initialize... */
|
||||
if (codec->patch_ops.init)
|
||||
err = codec->patch_ops.init(codec);
|
||||
if (!err && codec->patch_ops.build_controls)
|
||||
err = codec->patch_ops.build_controls(codec);
|
||||
snd_hda_power_down(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
|
@ -2306,12 +2554,11 @@ EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
|
|||
static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
||||
u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
|
||||
{
|
||||
int i;
|
||||
unsigned int val, streams;
|
||||
unsigned int i, val, wcaps;
|
||||
|
||||
val = 0;
|
||||
if (nid != codec->afg &&
|
||||
(get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
|
||||
wcaps = get_wcaps(codec, nid);
|
||||
if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) {
|
||||
val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
|
||||
if (val == -1)
|
||||
return -EIO;
|
||||
|
@ -2325,15 +2572,20 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
|||
if (val & (1 << i))
|
||||
rates |= rate_bits[i].alsa_bits;
|
||||
}
|
||||
if (rates == 0) {
|
||||
snd_printk(KERN_ERR "hda_codec: rates == 0 "
|
||||
"(nid=0x%x, val=0x%x, ovrd=%i)\n",
|
||||
nid, val,
|
||||
(wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0);
|
||||
return -EIO;
|
||||
}
|
||||
*ratesp = rates;
|
||||
}
|
||||
|
||||
if (formatsp || bpsp) {
|
||||
u64 formats = 0;
|
||||
unsigned int bps;
|
||||
unsigned int wcaps;
|
||||
unsigned int streams, bps;
|
||||
|
||||
wcaps = get_wcaps(codec, nid);
|
||||
streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
|
||||
if (streams == -1)
|
||||
return -EIO;
|
||||
|
@ -2386,6 +2638,15 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
|||
formats |= SNDRV_PCM_FMTBIT_U8;
|
||||
bps = 8;
|
||||
}
|
||||
if (formats == 0) {
|
||||
snd_printk(KERN_ERR "hda_codec: formats == 0 "
|
||||
"(nid=0x%x, val=0x%x, ovrd=%i, "
|
||||
"streams=0x%x)\n",
|
||||
nid, val,
|
||||
(wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0,
|
||||
streams);
|
||||
return -EIO;
|
||||
}
|
||||
if (formatsp)
|
||||
*formatsp = formats;
|
||||
if (bpsp)
|
||||
|
@ -2501,12 +2762,16 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo,
|
|||
static int set_pcm_default_values(struct hda_codec *codec,
|
||||
struct hda_pcm_stream *info)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* query support PCM information from the given NID */
|
||||
if (info->nid && (!info->rates || !info->formats)) {
|
||||
snd_hda_query_supported_pcm(codec, info->nid,
|
||||
err = snd_hda_query_supported_pcm(codec, info->nid,
|
||||
info->rates ? NULL : &info->rates,
|
||||
info->formats ? NULL : &info->formats,
|
||||
info->maxbps ? NULL : &info->maxbps);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (info->ops.open == NULL)
|
||||
info->ops.open = hda_pcm_default_open_close;
|
||||
|
@ -2549,13 +2814,10 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
|
|||
for (i = 0; i < ARRAY_SIZE(audio_idx); i++) {
|
||||
dev = audio_idx[i];
|
||||
if (!test_bit(dev, bus->pcm_dev_bits))
|
||||
break;
|
||||
goto ok;
|
||||
}
|
||||
if (i >= ARRAY_SIZE(audio_idx)) {
|
||||
snd_printk(KERN_WARNING "Too many audio devices\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
break;
|
||||
snd_printk(KERN_WARNING "Too many audio devices\n");
|
||||
return -EAGAIN;
|
||||
case HDA_PCM_TYPE_SPDIF:
|
||||
case HDA_PCM_TYPE_HDMI:
|
||||
case HDA_PCM_TYPE_MODEM:
|
||||
|
@ -2570,6 +2832,7 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
|
|||
snd_printk(KERN_WARNING "Invalid PCM type %d\n", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
ok:
|
||||
set_bit(dev, bus->pcm_dev_bits);
|
||||
return dev;
|
||||
}
|
||||
|
@ -2606,24 +2869,36 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
|
|||
if (!codec->patch_ops.build_pcms)
|
||||
return 0;
|
||||
err = codec->patch_ops.build_pcms(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "hda_codec: cannot build PCMs"
|
||||
"for #%d (error %d)\n", codec->addr, err);
|
||||
err = snd_hda_codec_reset(codec);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR
|
||||
"hda_codec: cannot revert codec\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (pcm = 0; pcm < codec->num_pcms; pcm++) {
|
||||
struct hda_pcm *cpcm = &codec->pcm_info[pcm];
|
||||
int dev;
|
||||
|
||||
if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
|
||||
return 0; /* no substreams assigned */
|
||||
continue; /* no substreams assigned */
|
||||
|
||||
if (!cpcm->pcm) {
|
||||
dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
|
||||
if (dev < 0)
|
||||
return 0;
|
||||
continue; /* no fatal error */
|
||||
cpcm->device = dev;
|
||||
err = snd_hda_attach_pcm(codec, cpcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "hda_codec: cannot attach "
|
||||
"PCM stream %d for codec #%d\n",
|
||||
dev, codec->addr);
|
||||
continue; /* no fatal error */
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -3324,8 +3599,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
if (ignore_nids && is_in_nid_list(nid, ignore_nids))
|
||||
continue;
|
||||
|
||||
def_conf = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
|
||||
continue;
|
||||
loc = get_defcfg_location(def_conf);
|
||||
|
@ -3401,10 +3675,22 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
cfg->input_pins[AUTO_PIN_AUX] = nid;
|
||||
break;
|
||||
case AC_JACK_SPDIF_OUT:
|
||||
cfg->dig_out_pin = nid;
|
||||
case AC_JACK_DIG_OTHER_OUT:
|
||||
if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins))
|
||||
continue;
|
||||
cfg->dig_out_pins[cfg->dig_outs] = nid;
|
||||
cfg->dig_out_type[cfg->dig_outs] =
|
||||
(loc == AC_JACK_LOC_HDMI) ?
|
||||
HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF;
|
||||
cfg->dig_outs++;
|
||||
break;
|
||||
case AC_JACK_SPDIF_IN:
|
||||
case AC_JACK_DIG_OTHER_IN:
|
||||
cfg->dig_in_pin = nid;
|
||||
if (loc == AC_JACK_LOC_HDMI)
|
||||
cfg->dig_in_type = HDA_PCM_TYPE_HDMI;
|
||||
else
|
||||
cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3510,6 +3796,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
cfg->hp_pins[1], cfg->hp_pins[2],
|
||||
cfg->hp_pins[3], cfg->hp_pins[4]);
|
||||
snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin);
|
||||
if (cfg->dig_outs)
|
||||
snd_printd(" dig-out=0x%x/0x%x\n",
|
||||
cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
|
||||
snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
|
||||
" cd=0x%x, aux=0x%x\n",
|
||||
cfg->input_pins[AUTO_PIN_MIC],
|
||||
|
@ -3518,6 +3807,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
|
|||
cfg->input_pins[AUTO_PIN_FRONT_LINE],
|
||||
cfg->input_pins[AUTO_PIN_CD],
|
||||
cfg->input_pins[AUTO_PIN_AUX]);
|
||||
if (cfg->dig_in_pin)
|
||||
snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -739,6 +739,7 @@ struct hda_codec {
|
|||
hda_nid_t mfg; /* MFG node id */
|
||||
|
||||
/* ids */
|
||||
u32 function_id;
|
||||
u32 vendor_id;
|
||||
u32 subsystem_id;
|
||||
u32 revision_id;
|
||||
|
@ -778,11 +779,14 @@ struct hda_codec {
|
|||
unsigned short spdif_ctls; /* SPDIF control bits */
|
||||
unsigned int spdif_in_enable; /* SPDIF input enable? */
|
||||
hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
|
||||
struct snd_array init_pins; /* initial (BIOS) pin configurations */
|
||||
struct snd_array driver_pins; /* pin configs set by codec parser */
|
||||
|
||||
#ifdef CONFIG_SND_HDA_HWDEP
|
||||
struct snd_hwdep *hwdep; /* assigned hwdep device */
|
||||
struct snd_array init_verbs; /* additional init verbs */
|
||||
struct snd_array hints; /* additional hints */
|
||||
struct snd_array user_pins; /* default pin configs to override */
|
||||
#endif
|
||||
|
||||
/* misc flags */
|
||||
|
@ -790,6 +794,9 @@ struct hda_codec {
|
|||
* status change
|
||||
* (e.g. Realtek codecs)
|
||||
*/
|
||||
unsigned int pin_amp_workaround:1; /* pin out-amp takes index
|
||||
* (e.g. Conexant codecs)
|
||||
*/
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
unsigned int power_on :1; /* current (global) power-state */
|
||||
unsigned int power_transition :1; /* power-state in transition */
|
||||
|
@ -855,6 +862,18 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec);
|
|||
#define snd_hda_sequence_write_cache snd_hda_sequence_write
|
||||
#endif
|
||||
|
||||
/* the struct for codec->pin_configs */
|
||||
struct hda_pincfg {
|
||||
hda_nid_t nid;
|
||||
unsigned int cfg;
|
||||
};
|
||||
|
||||
unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid);
|
||||
int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid,
|
||||
unsigned int cfg);
|
||||
int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
|
||||
hda_nid_t nid, unsigned int cfg); /* for hwdep */
|
||||
|
||||
/*
|
||||
* Mixer
|
||||
*/
|
||||
|
|
|
@ -144,9 +144,9 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
|
|||
node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
|
||||
|
||||
if (node->type == AC_WID_PIN) {
|
||||
node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP);
|
||||
node->pin_caps = snd_hda_query_pin_caps(codec, node->nid);
|
||||
node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
node->def_cfg = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
node->def_cfg = snd_hda_codec_get_pincfg(codec, node->nid);
|
||||
}
|
||||
|
||||
if (node->wid_caps & AC_WCAP_OUT_AMP) {
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
#include <sound/hda_hwdep.h>
|
||||
#include <sound/minors.h>
|
||||
|
||||
/* hint string pair */
|
||||
struct hda_hint {
|
||||
const char *key;
|
||||
const char *val; /* contained in the same alloc as key */
|
||||
};
|
||||
|
||||
/*
|
||||
* write/read an out-of-bound verb
|
||||
*/
|
||||
|
@ -99,16 +105,17 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
|
|||
|
||||
static void clear_hwdep_elements(struct hda_codec *codec)
|
||||
{
|
||||
char **head;
|
||||
int i;
|
||||
|
||||
/* clear init verbs */
|
||||
snd_array_free(&codec->init_verbs);
|
||||
/* clear hints */
|
||||
head = codec->hints.list;
|
||||
for (i = 0; i < codec->hints.used; i++, head++)
|
||||
kfree(*head);
|
||||
for (i = 0; i < codec->hints.used; i++) {
|
||||
struct hda_hint *hint = snd_array_elem(&codec->hints, i);
|
||||
kfree(hint->key); /* we don't need to free hint->val */
|
||||
}
|
||||
snd_array_free(&codec->hints);
|
||||
snd_array_free(&codec->user_pins);
|
||||
}
|
||||
|
||||
static void hwdep_free(struct snd_hwdep *hwdep)
|
||||
|
@ -140,7 +147,8 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
|
|||
#endif
|
||||
|
||||
snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
|
||||
snd_array_init(&codec->hints, sizeof(char *), 32);
|
||||
snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
|
||||
snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -153,7 +161,13 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
|
|||
|
||||
static int clear_codec(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_codec_reset(codec);
|
||||
int err;
|
||||
|
||||
err = snd_hda_codec_reset(codec);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR "The codec is being used, can't free.\n");
|
||||
return err;
|
||||
}
|
||||
clear_hwdep_elements(codec);
|
||||
return 0;
|
||||
}
|
||||
|
@ -162,20 +176,29 @@ static int reconfig_codec(struct hda_codec *codec)
|
|||
{
|
||||
int err;
|
||||
|
||||
snd_hda_power_up(codec);
|
||||
snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
|
||||
snd_hda_codec_reset(codec);
|
||||
err = snd_hda_codec_reset(codec);
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR
|
||||
"The codec is being used, can't reconfigure.\n");
|
||||
goto error;
|
||||
}
|
||||
err = snd_hda_codec_configure(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto error;
|
||||
/* rebuild PCMs */
|
||||
err = snd_hda_codec_build_pcms(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto error;
|
||||
/* rebuild mixers */
|
||||
err = snd_hda_codec_build_controls(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return snd_card_register(codec->bus->card);
|
||||
goto error;
|
||||
err = snd_card_register(codec->bus->card);
|
||||
error:
|
||||
snd_hda_power_down(codec);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -271,6 +294,22 @@ static ssize_t type##_store(struct device *dev, \
|
|||
CODEC_ACTION_STORE(reconfig);
|
||||
CODEC_ACTION_STORE(clear);
|
||||
|
||||
static ssize_t init_verbs_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||
struct hda_codec *codec = hwdep->private_data;
|
||||
int i, len = 0;
|
||||
for (i = 0; i < codec->init_verbs.used; i++) {
|
||||
struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
|
||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||
"0x%02x 0x%03x 0x%04x\n",
|
||||
v->nid, v->verb, v->param);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t init_verbs_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
|
@ -293,26 +332,157 @@ static ssize_t init_verbs_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t hints_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||
struct hda_codec *codec = hwdep->private_data;
|
||||
int i, len = 0;
|
||||
for (i = 0; i < codec->hints.used; i++) {
|
||||
struct hda_hint *hint = snd_array_elem(&codec->hints, i);
|
||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||
"%s = %s\n", hint->key, hint->val);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < codec->hints.used; i++) {
|
||||
struct hda_hint *hint = snd_array_elem(&codec->hints, i);
|
||||
if (!strcmp(hint->key, key))
|
||||
return hint;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void remove_trail_spaces(char *str)
|
||||
{
|
||||
char *p;
|
||||
if (!*str)
|
||||
return;
|
||||
p = str + strlen(str) - 1;
|
||||
for (; isspace(*p); p--) {
|
||||
*p = 0;
|
||||
if (p == str)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_HINTS 1024
|
||||
|
||||
static ssize_t hints_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||
struct hda_codec *codec = hwdep->private_data;
|
||||
char *p;
|
||||
char **hint;
|
||||
char *key, *val;
|
||||
struct hda_hint *hint;
|
||||
|
||||
if (!*buf || isspace(*buf) || *buf == '#' || *buf == '\n')
|
||||
while (isspace(*buf))
|
||||
buf++;
|
||||
if (!*buf || *buf == '#' || *buf == '\n')
|
||||
return count;
|
||||
p = kstrndup_noeol(buf, 1024);
|
||||
if (!p)
|
||||
if (*buf == '=')
|
||||
return -EINVAL;
|
||||
key = kstrndup_noeol(buf, 1024);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
hint = snd_array_new(&codec->hints);
|
||||
/* extract key and val */
|
||||
val = strchr(key, '=');
|
||||
if (!val) {
|
||||
kfree(key);
|
||||
return -EINVAL;
|
||||
}
|
||||
*val++ = 0;
|
||||
while (isspace(*val))
|
||||
val++;
|
||||
remove_trail_spaces(key);
|
||||
remove_trail_spaces(val);
|
||||
hint = get_hint(codec, key);
|
||||
if (hint) {
|
||||
/* replace */
|
||||
kfree(hint->key);
|
||||
hint->key = key;
|
||||
hint->val = val;
|
||||
return count;
|
||||
}
|
||||
/* allocate a new hint entry */
|
||||
if (codec->hints.used >= MAX_HINTS)
|
||||
hint = NULL;
|
||||
else
|
||||
hint = snd_array_new(&codec->hints);
|
||||
if (!hint) {
|
||||
kfree(p);
|
||||
kfree(key);
|
||||
return -ENOMEM;
|
||||
}
|
||||
*hint = p;
|
||||
hint->key = key;
|
||||
hint->val = val;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t pin_configs_show(struct hda_codec *codec,
|
||||
struct snd_array *list,
|
||||
char *buf)
|
||||
{
|
||||
int i, len = 0;
|
||||
for (i = 0; i < list->used; i++) {
|
||||
struct hda_pincfg *pin = snd_array_elem(list, i);
|
||||
len += sprintf(buf + len, "0x%02x 0x%08x\n",
|
||||
pin->nid, pin->cfg);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t init_pin_configs_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||
struct hda_codec *codec = hwdep->private_data;
|
||||
return pin_configs_show(codec, &codec->init_pins, buf);
|
||||
}
|
||||
|
||||
static ssize_t user_pin_configs_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||
struct hda_codec *codec = hwdep->private_data;
|
||||
return pin_configs_show(codec, &codec->user_pins, buf);
|
||||
}
|
||||
|
||||
static ssize_t driver_pin_configs_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
|
||||
struct hda_codec *codec = hwdep->private_data;
|
||||
return pin_configs_show(codec, &codec->driver_pins, buf);
|
||||
}
|
||||
|
||||
#define MAX_PIN_CONFIGS 32
|
||||
|
||||
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);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -331,8 +501,11 @@ static struct device_attribute codec_attrs[] = {
|
|||
CODEC_ATTR_RO(mfg),
|
||||
CODEC_ATTR_RW(name),
|
||||
CODEC_ATTR_RW(modelname),
|
||||
CODEC_ATTR_WO(init_verbs),
|
||||
CODEC_ATTR_WO(hints),
|
||||
CODEC_ATTR_RW(init_verbs),
|
||||
CODEC_ATTR_RW(hints),
|
||||
CODEC_ATTR_RO(init_pin_configs),
|
||||
CODEC_ATTR_RW(user_pin_configs),
|
||||
CODEC_ATTR_RO(driver_pin_configs),
|
||||
CODEC_ATTR_WO(reconfig),
|
||||
CODEC_ATTR_WO(clear),
|
||||
};
|
||||
|
@ -351,4 +524,29 @@ int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for hint string
|
||||
*/
|
||||
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
|
||||
{
|
||||
struct hda_hint *hint = get_hint(codec, key);
|
||||
return hint ? hint->val : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_hint);
|
||||
|
||||
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
|
||||
{
|
||||
const char *p = snd_hda_get_hint(codec, key);
|
||||
if (!p || !*p)
|
||||
return -ENOENT;
|
||||
switch (toupper(*p)) {
|
||||
case 'T': /* true */
|
||||
case 'Y': /* yes */
|
||||
case '1':
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
|
||||
|
||||
#endif /* CONFIG_SND_HDA_RECONFIG */
|
||||
|
|
|
@ -381,6 +381,7 @@ struct azx {
|
|||
|
||||
/* HD codec */
|
||||
unsigned short codec_mask;
|
||||
int codec_probe_mask; /* copied from probe_mask option */
|
||||
struct hda_bus *bus;
|
||||
|
||||
/* CORB/RIRB */
|
||||
|
@ -858,13 +859,18 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
|
|||
SD_CTL_DMA_START | SD_INT_MASK);
|
||||
}
|
||||
|
||||
/* stop a stream */
|
||||
static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
|
||||
/* stop DMA */
|
||||
static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev)
|
||||
{
|
||||
/* stop DMA */
|
||||
azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
|
||||
~(SD_CTL_DMA_START | SD_INT_MASK));
|
||||
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
|
||||
}
|
||||
|
||||
/* stop a stream */
|
||||
static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
|
||||
{
|
||||
azx_stream_clear(chip, azx_dev);
|
||||
/* disable SIE */
|
||||
azx_writeb(chip, INTCTL,
|
||||
azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
|
||||
|
@ -1075,8 +1081,7 @@ static int azx_setup_periods(struct azx *chip,
|
|||
azx_sd_writel(azx_dev, SD_BDLPL, 0);
|
||||
azx_sd_writel(azx_dev, SD_BDLPU, 0);
|
||||
|
||||
period_bytes = snd_pcm_lib_period_bytes(substream);
|
||||
azx_dev->period_bytes = period_bytes;
|
||||
period_bytes = azx_dev->period_bytes;
|
||||
periods = azx_dev->bufsize / period_bytes;
|
||||
|
||||
/* program the initial BDL entries */
|
||||
|
@ -1123,24 +1128,17 @@ static int azx_setup_periods(struct azx *chip,
|
|||
error:
|
||||
snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n",
|
||||
azx_dev->bufsize, period_bytes);
|
||||
/* reset */
|
||||
azx_sd_writel(azx_dev, SD_BDLPL, 0);
|
||||
azx_sd_writel(azx_dev, SD_BDLPU, 0);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* set up the SD for streaming
|
||||
*/
|
||||
static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
|
||||
/* reset stream */
|
||||
static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
|
||||
{
|
||||
unsigned char val;
|
||||
int timeout;
|
||||
|
||||
/* make sure the run bit is zero for SD */
|
||||
azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
|
||||
~SD_CTL_DMA_START);
|
||||
/* reset stream */
|
||||
azx_stream_clear(chip, azx_dev);
|
||||
|
||||
azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
|
||||
SD_CTL_STREAM_RESET);
|
||||
udelay(3);
|
||||
|
@ -1157,7 +1155,15 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
|
|||
while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
|
||||
--timeout)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* set up the SD for streaming
|
||||
*/
|
||||
static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
|
||||
{
|
||||
/* make sure the run bit is zero for SD */
|
||||
azx_stream_clear(chip, azx_dev);
|
||||
/* program the stream_tag */
|
||||
azx_sd_writel(azx_dev, SD_CTL,
|
||||
(azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)|
|
||||
|
@ -1228,7 +1234,6 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = {
|
|||
};
|
||||
|
||||
static int __devinit azx_codec_create(struct azx *chip, const char *model,
|
||||
unsigned int codec_probe_mask,
|
||||
int no_init)
|
||||
{
|
||||
struct hda_bus_template bus_temp;
|
||||
|
@ -1261,7 +1266,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
|
|||
|
||||
/* First try to probe all given codec slots */
|
||||
for (c = 0; c < max_slots; c++) {
|
||||
if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
|
||||
if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
|
||||
if (probe_codec(chip, c) < 0) {
|
||||
/* Some BIOSen give you wrong codec addresses
|
||||
* that don't exist
|
||||
|
@ -1285,7 +1290,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
|
|||
|
||||
/* Then create codec instances */
|
||||
for (c = 0; c < max_slots; c++) {
|
||||
if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
|
||||
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);
|
||||
if (err < 0)
|
||||
|
@ -1403,6 +1408,8 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
|
|||
runtime->private_data = azx_dev;
|
||||
snd_pcm_set_sync(substream);
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
|
||||
azx_stream_reset(chip, azx_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1429,6 +1436,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
|
|||
static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||||
|
||||
azx_dev->bufsize = 0;
|
||||
azx_dev->period_bytes = 0;
|
||||
azx_dev->format_val = 0;
|
||||
return snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
}
|
||||
|
@ -1443,6 +1455,9 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
|
|||
azx_sd_writel(azx_dev, SD_BDLPL, 0);
|
||||
azx_sd_writel(azx_dev, SD_BDLPU, 0);
|
||||
azx_sd_writel(azx_dev, SD_CTL, 0);
|
||||
azx_dev->bufsize = 0;
|
||||
azx_dev->period_bytes = 0;
|
||||
azx_dev->format_val = 0;
|
||||
|
||||
hinfo->ops.cleanup(hinfo, apcm->codec, substream);
|
||||
|
||||
|
@ -1456,23 +1471,37 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||||
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int bufsize, period_bytes, format_val;
|
||||
int err;
|
||||
|
||||
azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);
|
||||
azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,
|
||||
runtime->channels,
|
||||
runtime->format,
|
||||
hinfo->maxbps);
|
||||
if (!azx_dev->format_val) {
|
||||
format_val = snd_hda_calc_stream_format(runtime->rate,
|
||||
runtime->channels,
|
||||
runtime->format,
|
||||
hinfo->maxbps);
|
||||
if (!format_val) {
|
||||
snd_printk(KERN_ERR SFX
|
||||
"invalid format_val, rate=%d, ch=%d, format=%d\n",
|
||||
runtime->rate, runtime->channels, runtime->format);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bufsize = snd_pcm_lib_buffer_bytes(substream);
|
||||
period_bytes = snd_pcm_lib_period_bytes(substream);
|
||||
|
||||
snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
|
||||
azx_dev->bufsize, azx_dev->format_val);
|
||||
if (azx_setup_periods(chip, substream, azx_dev) < 0)
|
||||
return -EINVAL;
|
||||
bufsize, format_val);
|
||||
|
||||
if (bufsize != azx_dev->bufsize ||
|
||||
period_bytes != azx_dev->period_bytes ||
|
||||
format_val != azx_dev->format_val) {
|
||||
azx_dev->bufsize = bufsize;
|
||||
azx_dev->period_bytes = period_bytes;
|
||||
azx_dev->format_val = format_val;
|
||||
err = azx_setup_periods(chip, substream, azx_dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
azx_setup_controller(chip, azx_dev);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
|
||||
|
@ -2100,25 +2129,36 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
|
|||
SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01),
|
||||
/* including bogus ALC268 in slot#2 that conflicts with ALC888 */
|
||||
SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01),
|
||||
/* conflict of ALC268 in slot#3 (digital I/O); a temporary fix */
|
||||
SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba laptop", 0x03),
|
||||
/* forced codec slots */
|
||||
SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103),
|
||||
{}
|
||||
};
|
||||
|
||||
#define AZX_FORCE_CODEC_MASK 0x100
|
||||
|
||||
static void __devinit check_probe_mask(struct azx *chip, int dev)
|
||||
{
|
||||
const struct snd_pci_quirk *q;
|
||||
|
||||
if (probe_mask[dev] == -1) {
|
||||
chip->codec_probe_mask = probe_mask[dev];
|
||||
if (chip->codec_probe_mask == -1) {
|
||||
q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
|
||||
if (q) {
|
||||
printk(KERN_INFO
|
||||
"hda_intel: probe_mask set to 0x%x "
|
||||
"for device %04x:%04x\n",
|
||||
q->value, q->subvendor, q->subdevice);
|
||||
probe_mask[dev] = q->value;
|
||||
chip->codec_probe_mask = q->value;
|
||||
}
|
||||
}
|
||||
|
||||
/* check forced option */
|
||||
if (chip->codec_probe_mask != -1 &&
|
||||
(chip->codec_probe_mask & AZX_FORCE_CODEC_MASK)) {
|
||||
chip->codec_mask = chip->codec_probe_mask & 0xff;
|
||||
printk(KERN_INFO "hda_intel: codec_mask forced to 0x%x\n",
|
||||
chip->codec_mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -2359,8 +2399,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
|
|||
card->private_data = chip;
|
||||
|
||||
/* create codec instances */
|
||||
err = azx_codec_create(chip, model[dev], probe_mask[dev],
|
||||
probe_only[dev]);
|
||||
err = azx_codec_create(chip, model[dev], probe_only[dev]);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
|
||||
|
@ -2457,10 +2496,10 @@ static struct pci_device_id azx_ids[] = {
|
|||
{ PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0bd4), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
{ PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA },
|
||||
/* Teradici */
|
||||
{ PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
|
||||
/* AMD Generic, PCI class code and Vendor ID for HD Audio */
|
||||
|
|
|
@ -26,8 +26,10 @@
|
|||
/*
|
||||
* for mixer controls
|
||||
*/
|
||||
#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \
|
||||
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
|
||||
#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
|
||||
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19))
|
||||
HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
|
||||
/* mono volume with index (index=0,1,...) (channel=1,2) */
|
||||
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
||||
|
@ -96,7 +98,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
|
|||
const char *name);
|
||||
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
||||
unsigned int *tlv, const char **slaves);
|
||||
void snd_hda_codec_reset(struct hda_codec *codec);
|
||||
int snd_hda_codec_reset(struct hda_codec *codec);
|
||||
int snd_hda_codec_configure(struct hda_codec *codec);
|
||||
|
||||
/* amp value bits */
|
||||
|
@ -134,7 +136,7 @@ extern struct hda_ctl_ops snd_hda_bind_sw; /* for bind-switch */
|
|||
|
||||
struct hda_bind_ctls {
|
||||
struct hda_ctl_ops *ops;
|
||||
long values[];
|
||||
unsigned long values[];
|
||||
};
|
||||
|
||||
int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol,
|
||||
|
@ -227,6 +229,7 @@ struct hda_multi_out {
|
|||
hda_nid_t hp_nid; /* optional DAC for HP, 0 when not exists */
|
||||
hda_nid_t extra_out_nid[3]; /* optional DACs, 0 when not exists */
|
||||
hda_nid_t dig_out_nid; /* digital out audio widget */
|
||||
hda_nid_t *slave_dig_outs;
|
||||
int max_channels; /* currently supported analog channels */
|
||||
int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */
|
||||
int no_share_stream; /* don't share a stream with multiple pins */
|
||||
|
@ -354,9 +357,12 @@ struct auto_pin_cfg {
|
|||
int line_out_type; /* AUTO_PIN_XXX_OUT */
|
||||
hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
|
||||
hda_nid_t input_pins[AUTO_PIN_LAST];
|
||||
hda_nid_t dig_out_pin;
|
||||
int dig_outs;
|
||||
hda_nid_t dig_out_pins[2];
|
||||
hda_nid_t dig_in_pin;
|
||||
hda_nid_t mono_out_pin;
|
||||
int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */
|
||||
int dig_in_type; /* HDA_PCM_TYPE_XXX */
|
||||
};
|
||||
|
||||
#define get_defcfg_connect(cfg) \
|
||||
|
@ -405,6 +411,7 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
|
|||
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);
|
||||
u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
|
||||
|
||||
int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
|
||||
void snd_hda_ctls_clear(struct hda_codec *codec);
|
||||
|
@ -427,6 +434,23 @@ static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SND_HDA_RECONFIG
|
||||
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key);
|
||||
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key);
|
||||
#else
|
||||
static inline
|
||||
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline
|
||||
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* power-management
|
||||
*/
|
||||
|
@ -458,6 +482,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
|
|||
#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3)
|
||||
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
|
||||
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
|
||||
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
|
||||
|
||||
/*
|
||||
* CEA Short Audio Descriptor data
|
||||
|
|
|
@ -399,8 +399,10 @@ static void print_conn_list(struct snd_info_buffer *buffer,
|
|||
{
|
||||
int c, curr = -1;
|
||||
|
||||
if (conn_len > 1 && wid_type != AC_WID_AUD_MIX &&
|
||||
wid_type != AC_WID_VOL_KNB)
|
||||
if (conn_len > 1 &&
|
||||
wid_type != AC_WID_AUD_MIX &&
|
||||
wid_type != AC_WID_VOL_KNB &&
|
||||
wid_type != AC_WID_POWER)
|
||||
curr = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_CONNECT_SEL, 0);
|
||||
snd_iprintf(buffer, " Connection: %d\n", conn_len);
|
||||
|
@ -467,8 +469,9 @@ static void print_codec_info(struct snd_info_entry *entry,
|
|||
snd_iprintf(buffer, "Codec: %s\n",
|
||||
codec->name ? codec->name : "Not Set");
|
||||
snd_iprintf(buffer, "Address: %d\n", codec->addr);
|
||||
snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
|
||||
snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
|
||||
snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id);
|
||||
snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id);
|
||||
snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id);
|
||||
snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
|
||||
|
||||
if (codec->mfg)
|
||||
|
@ -554,8 +557,14 @@ static void print_codec_info(struct snd_info_entry *entry,
|
|||
snd_iprintf(buffer, " Amp-Out caps: ");
|
||||
print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
|
||||
snd_iprintf(buffer, " Amp-Out vals: ");
|
||||
print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
|
||||
wid_caps & AC_WCAP_STEREO, 1);
|
||||
if (wid_type == AC_WID_PIN &&
|
||||
codec->pin_amp_workaround)
|
||||
print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
|
||||
wid_caps & AC_WCAP_STEREO,
|
||||
conn_len);
|
||||
else
|
||||
print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
|
||||
wid_caps & AC_WCAP_STEREO, 1);
|
||||
}
|
||||
|
||||
switch (wid_type) {
|
||||
|
|
|
@ -27,11 +27,12 @@
|
|||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_beep.h"
|
||||
|
||||
struct ad198x_spec {
|
||||
struct snd_kcontrol_new *mixers[5];
|
||||
int num_mixers;
|
||||
|
||||
unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
|
||||
const struct hda_verb *init_verbs[5]; /* initialization verbs
|
||||
* don't forget NULL termination!
|
||||
*/
|
||||
|
@ -154,6 +155,16 @@ static const char *ad_slave_sws[] = {
|
|||
|
||||
static void ad198x_free_kctls(struct hda_codec *codec);
|
||||
|
||||
/* additional beep mixers; the actual parameters are overwritten at build */
|
||||
static struct snd_kcontrol_new ad_beep_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_OUTPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
#define set_beep_amp(spec, nid, idx, dir) \
|
||||
((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
|
||||
|
||||
static int ad198x_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec = codec->spec;
|
||||
|
@ -181,6 +192,21 @@ static int ad198x_build_controls(struct hda_codec *codec)
|
|||
return err;
|
||||
}
|
||||
|
||||
/* create beep controls if needed */
|
||||
if (spec->beep_amp) {
|
||||
struct snd_kcontrol_new *knew;
|
||||
for (knew = ad_beep_mixer; knew->name; knew++) {
|
||||
struct snd_kcontrol *kctl;
|
||||
kctl = snd_ctl_new1(knew, codec);
|
||||
if (!kctl)
|
||||
return -ENOMEM;
|
||||
kctl->private_value = spec->beep_amp;
|
||||
err = snd_hda_ctl_add(codec, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we have no master control, let's create it */
|
||||
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
|
||||
unsigned int vmaster_tlv[4];
|
||||
|
@ -406,7 +432,8 @@ static void ad198x_free(struct hda_codec *codec)
|
|||
return;
|
||||
|
||||
ad198x_free_kctls(codec);
|
||||
kfree(codec->spec);
|
||||
kfree(spec);
|
||||
snd_hda_detach_beep_device(codec);
|
||||
}
|
||||
|
||||
static struct hda_codec_ops ad198x_patch_ops = {
|
||||
|
@ -545,8 +572,6 @@ static struct snd_kcontrol_new ad1986a_mixers[] = {
|
|||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
|
||||
|
@ -610,8 +635,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
|
|||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
|
||||
/* HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT),
|
||||
/*
|
||||
HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
|
||||
|
@ -809,8 +833,6 @@ static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = {
|
|||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x18, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x18, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
|
||||
{
|
||||
|
@ -1002,10 +1024,8 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
|
||||
SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
|
||||
SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
|
||||
SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG),
|
||||
SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG),
|
||||
SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG),
|
||||
SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
|
||||
SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
|
||||
SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
|
||||
SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
|
||||
SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
|
||||
|
@ -1027,15 +1047,14 @@ static struct hda_amp_list ad1986a_loopbacks[] = {
|
|||
|
||||
static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
unsigned int conf = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
|
||||
}
|
||||
|
||||
static int patch_ad1986a(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec;
|
||||
int board_config;
|
||||
int err, board_config;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
|
@ -1043,6 +1062,13 @@ static int patch_ad1986a(struct hda_codec *codec)
|
|||
|
||||
codec->spec = spec;
|
||||
|
||||
err = snd_hda_attach_beep_device(codec, 0x19);
|
||||
if (err < 0) {
|
||||
ad198x_free(codec);
|
||||
return err;
|
||||
}
|
||||
set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
|
||||
|
||||
spec->multiout.max_channels = 6;
|
||||
spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
|
||||
spec->multiout.dac_nids = ad1986a_dac_nids;
|
||||
|
@ -1222,8 +1248,6 @@ static struct snd_kcontrol_new ad1983_mixers[] = {
|
|||
HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
|
||||
|
@ -1294,6 +1318,7 @@ static struct hda_amp_list ad1983_loopbacks[] = {
|
|||
static int patch_ad1983(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
|
@ -1301,6 +1326,13 @@ static int patch_ad1983(struct hda_codec *codec)
|
|||
|
||||
codec->spec = spec;
|
||||
|
||||
err = snd_hda_attach_beep_device(codec, 0x10);
|
||||
if (err < 0) {
|
||||
ad198x_free(codec);
|
||||
return err;
|
||||
}
|
||||
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
|
||||
|
||||
spec->multiout.max_channels = 2;
|
||||
spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
|
||||
spec->multiout.dac_nids = ad1983_dac_nids;
|
||||
|
@ -1370,8 +1402,6 @@ static struct snd_kcontrol_new ad1981_mixers[] = {
|
|||
HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
|
||||
|
@ -1416,8 +1446,8 @@ static struct hda_verb ad1981_init_verbs[] = {
|
|||
{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
|
||||
{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
|
||||
/* Mic boost: 0dB */
|
||||
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
|
||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
|
||||
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
/* Record selector: Front mic */
|
||||
{0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
|
||||
|
@ -1682,10 +1712,10 @@ static struct snd_pci_quirk ad1981_cfg_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
|
||||
SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
|
||||
/* All HP models */
|
||||
SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
|
||||
SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
|
||||
SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
|
||||
/* Lenovo Thinkpad T60/X60/Z6xx */
|
||||
SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
|
||||
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
|
||||
/* HP nx6320 (reversed SSID, H/W bug) */
|
||||
SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
|
||||
{}
|
||||
|
@ -1694,7 +1724,7 @@ static struct snd_pci_quirk ad1981_cfg_tbl[] = {
|
|||
static int patch_ad1981(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec;
|
||||
int board_config;
|
||||
int err, board_config;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
|
@ -1702,6 +1732,13 @@ static int patch_ad1981(struct hda_codec *codec)
|
|||
|
||||
codec->spec = spec;
|
||||
|
||||
err = snd_hda_attach_beep_device(codec, 0x10);
|
||||
if (err < 0) {
|
||||
ad198x_free(codec);
|
||||
return err;
|
||||
}
|
||||
set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
|
||||
|
||||
spec->multiout.max_channels = 2;
|
||||
spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
|
||||
spec->multiout.dac_nids = ad1981_dac_nids;
|
||||
|
@ -1988,9 +2025,6 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
|
|||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
|
||||
|
||||
|
@ -2034,9 +2068,6 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
|
|||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
|
||||
|
||||
|
@ -2066,9 +2097,6 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
|
|||
HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
|
||||
|
||||
HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
|
||||
|
||||
|
@ -2297,10 +2325,6 @@ static struct hda_verb ad1988_capture_init_verbs[] = {
|
|||
{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
/* ADCs; muted */
|
||||
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
@ -2408,10 +2432,6 @@ static struct hda_verb ad1988_3stack_init_verbs[] = {
|
|||
{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
/* ADCs; muted */
|
||||
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
/* Analog Mix output amp */
|
||||
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
|
||||
{ }
|
||||
|
@ -2483,10 +2503,6 @@ static struct hda_verb ad1988_laptop_init_verbs[] = {
|
|||
{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
/* ADCs; muted */
|
||||
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
/* Analog Mix output amp */
|
||||
{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
|
||||
{ }
|
||||
|
@ -2890,7 +2906,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
|
|||
|
||||
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
||||
|
||||
if (spec->autocfg.dig_out_pin)
|
||||
if (spec->autocfg.dig_outs)
|
||||
spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
|
||||
if (spec->autocfg.dig_in_pin)
|
||||
spec->dig_in_nid = AD1988_SPDIF_IN;
|
||||
|
@ -2940,7 +2956,7 @@ static struct snd_pci_quirk ad1988_cfg_tbl[] = {
|
|||
static int patch_ad1988(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec;
|
||||
int board_config;
|
||||
int err, board_config;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
|
@ -2960,7 +2976,7 @@ static int patch_ad1988(struct hda_codec *codec)
|
|||
|
||||
if (board_config == AD1988_AUTO) {
|
||||
/* automatic parse from the BIOS config */
|
||||
int err = ad1988_parse_auto_config(codec);
|
||||
err = ad1988_parse_auto_config(codec);
|
||||
if (err < 0) {
|
||||
ad198x_free(codec);
|
||||
return err;
|
||||
|
@ -2970,6 +2986,13 @@ static int patch_ad1988(struct hda_codec *codec)
|
|||
}
|
||||
}
|
||||
|
||||
err = snd_hda_attach_beep_device(codec, 0x10);
|
||||
if (err < 0) {
|
||||
ad198x_free(codec);
|
||||
return err;
|
||||
}
|
||||
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
|
||||
|
||||
switch (board_config) {
|
||||
case AD1988_6STACK:
|
||||
case AD1988_6STACK_DIG:
|
||||
|
@ -3126,12 +3149,6 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = {
|
|||
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
|
||||
/*
|
||||
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Digital Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
|
||||
*/
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
|
@ -3204,10 +3221,10 @@ static struct hda_verb ad1884_init_verbs[] = {
|
|||
{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
/* Port-B (front mic) pin */
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
/* Port-C (rear mic) pin */
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
/* Analog mixer; mute as default */
|
||||
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
||||
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
||||
|
@ -3240,7 +3257,7 @@ static const char *ad1884_slave_vols[] = {
|
|||
"CD Playback Volume",
|
||||
"Internal Mic Playback Volume",
|
||||
"Docking Mic Playback Volume"
|
||||
"Beep Playback Volume",
|
||||
/* "Beep Playback Volume", */
|
||||
"IEC958 Playback Volume",
|
||||
NULL
|
||||
};
|
||||
|
@ -3248,6 +3265,7 @@ static const char *ad1884_slave_vols[] = {
|
|||
static int patch_ad1884(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
|
@ -3255,6 +3273,13 @@ static int patch_ad1884(struct hda_codec *codec)
|
|||
|
||||
codec->spec = spec;
|
||||
|
||||
err = snd_hda_attach_beep_device(codec, 0x10);
|
||||
if (err < 0) {
|
||||
ad198x_free(codec);
|
||||
return err;
|
||||
}
|
||||
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
|
||||
|
||||
spec->multiout.max_channels = 2;
|
||||
spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
|
||||
spec->multiout.dac_nids = ad1884_dac_nids;
|
||||
|
@ -3321,8 +3346,6 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
|
|||
HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
|
||||
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),
|
||||
|
@ -3358,7 +3381,7 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = {
|
|||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
/* docking mic boost */
|
||||
{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
||||
/* Analog mixer - docking mic; mute as default */
|
||||
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
|
||||
/* enable EAPD bit */
|
||||
|
@ -3379,10 +3402,6 @@ static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
|
|||
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
|
||||
/*
|
||||
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
|
||||
*/
|
||||
HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
|
@ -3468,7 +3487,7 @@ static const char *ad1984_models[AD1984_MODELS] = {
|
|||
|
||||
static struct snd_pci_quirk ad1984_cfg_tbl[] = {
|
||||
/* Lenovo Thinkpad T61/X61 */
|
||||
SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
|
||||
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
|
||||
SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
|
||||
{}
|
||||
};
|
||||
|
@ -3561,8 +3580,6 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = {
|
|||
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
|
||||
|
@ -3622,10 +3639,10 @@ static struct hda_verb ad1884a_init_verbs[] = {
|
|||
{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
/* Port-B (front mic) pin */
|
||||
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
/* Port-C (rear line-in) pin */
|
||||
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
||||
/* Port-E (rear mic) pin */
|
||||
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
||||
|
@ -3695,8 +3712,6 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
|
|||
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
|
||||
|
@ -3724,8 +3739,6 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
|
|||
HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
|
@ -3836,8 +3849,6 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
|
|||
HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
|
@ -3911,9 +3922,9 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
|
||||
SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
|
||||
SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
|
||||
SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP),
|
||||
SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP),
|
||||
SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP),
|
||||
SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
|
||||
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(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
|
||||
{}
|
||||
};
|
||||
|
@ -3921,7 +3932,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
|
|||
static int patch_ad1884a(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec;
|
||||
int board_config;
|
||||
int err, board_config;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
|
@ -3929,6 +3940,13 @@ static int patch_ad1884a(struct hda_codec *codec)
|
|||
|
||||
codec->spec = spec;
|
||||
|
||||
err = snd_hda_attach_beep_device(codec, 0x10);
|
||||
if (err < 0) {
|
||||
ad198x_free(codec);
|
||||
return err;
|
||||
}
|
||||
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
|
||||
|
||||
spec->multiout.max_channels = 2;
|
||||
spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
|
||||
spec->multiout.dac_nids = ad1884a_dac_nids;
|
||||
|
@ -3966,6 +3984,14 @@ static int patch_ad1884a(struct hda_codec *codec)
|
|||
spec->multiout.dig_out_nid = 0;
|
||||
codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
|
||||
codec->patch_ops.init = ad1884a_hp_init;
|
||||
/* set the upper-limit for mixer amp to 0dB for avoiding the
|
||||
* possible damage by overloading
|
||||
*/
|
||||
snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
|
||||
(0x17 << AC_AMPCAP_OFFSET_SHIFT) |
|
||||
(0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
|
||||
(0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
|
||||
(1 << AC_AMPCAP_MUTE_SHIFT));
|
||||
break;
|
||||
case AD1884A_THINKPAD:
|
||||
spec->mixers[0] = ad1984a_thinkpad_mixers;
|
||||
|
@ -4083,8 +4109,6 @@ static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
|
|||
HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
|
@ -4097,8 +4121,6 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
|
|||
HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
@ -4257,7 +4279,7 @@ static const char *ad1882_models[AD1986A_MODELS] = {
|
|||
static int patch_ad1882(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec;
|
||||
int board_config;
|
||||
int err, board_config;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
|
@ -4265,6 +4287,13 @@ static int patch_ad1882(struct hda_codec *codec)
|
|||
|
||||
codec->spec = spec;
|
||||
|
||||
err = snd_hda_attach_beep_device(codec, 0x10);
|
||||
if (err < 0) {
|
||||
ad198x_free(codec);
|
||||
return err;
|
||||
}
|
||||
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
|
||||
|
||||
spec->multiout.max_channels = 6;
|
||||
spec->multiout.num_dacs = 3;
|
||||
spec->multiout.dac_nids = ad1882_dac_nids;
|
||||
|
|
|
@ -680,13 +680,13 @@ static int patch_cmi9880(struct hda_codec *codec)
|
|||
struct auto_pin_cfg cfg;
|
||||
|
||||
/* collect pin default configuration */
|
||||
port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
port_e = snd_hda_codec_get_pincfg(codec, 0x0f);
|
||||
port_f = snd_hda_codec_get_pincfg(codec, 0x10);
|
||||
spec->front_panel = 1;
|
||||
if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE ||
|
||||
get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) {
|
||||
port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
port_g = snd_hda_codec_get_pincfg(codec, 0x1f);
|
||||
port_h = snd_hda_codec_get_pincfg(codec, 0x20);
|
||||
spec->channel_modes = cmi9880_channel_modes;
|
||||
/* no front panel */
|
||||
if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE ||
|
||||
|
@ -703,8 +703,8 @@ static int patch_cmi9880(struct hda_codec *codec)
|
|||
spec->multiout.max_channels = cmi9880_channel_modes[0].channels;
|
||||
} else {
|
||||
spec->input_mux = &cmi9880_basic_mux;
|
||||
port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
port_spdifi = snd_hda_codec_get_pincfg(codec, 0x13);
|
||||
port_spdifo = snd_hda_codec_get_pincfg(codec, 0x12);
|
||||
if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE)
|
||||
spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
|
||||
if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE)
|
||||
|
|
|
@ -58,6 +58,7 @@ struct conexant_spec {
|
|||
|
||||
struct snd_kcontrol_new *mixers[5];
|
||||
int num_mixers;
|
||||
hda_nid_t vmaster_nid;
|
||||
|
||||
const struct hda_verb *init_verbs[5]; /* initialization verbs
|
||||
* don't forget NULL
|
||||
|
@ -72,6 +73,7 @@ struct conexant_spec {
|
|||
*/
|
||||
unsigned int cur_eapd;
|
||||
unsigned int hp_present;
|
||||
unsigned int no_auto_mic;
|
||||
unsigned int need_dac_fix;
|
||||
|
||||
/* capture */
|
||||
|
@ -461,6 +463,29 @@ static void conexant_free(struct hda_codec *codec)
|
|||
kfree(codec->spec);
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new cxt_capture_mixers[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Capture Source",
|
||||
.info = conexant_mux_enum_info,
|
||||
.get = conexant_mux_enum_get,
|
||||
.put = conexant_mux_enum_put
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const char *slave_vols[] = {
|
||||
"Headphone Playback Volume",
|
||||
"Speaker Playback Volume",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *slave_sws[] = {
|
||||
"Headphone Playback Switch",
|
||||
"Speaker Playback Switch",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int conexant_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
|
@ -488,6 +513,32 @@ static int conexant_build_controls(struct hda_codec *codec)
|
|||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* if we have no master control, let's create it */
|
||||
if (spec->vmaster_nid &&
|
||||
!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
|
||||
unsigned int vmaster_tlv[4];
|
||||
snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
|
||||
HDA_OUTPUT, vmaster_tlv);
|
||||
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
|
||||
vmaster_tlv, slave_vols);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (spec->vmaster_nid &&
|
||||
!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
|
||||
err = snd_hda_add_vmaster(codec, "Master Playback Switch",
|
||||
NULL, slave_sws);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (spec->input_mux) {
|
||||
err = snd_hda_add_new_ctls(codec, cxt_capture_mixers);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -719,13 +770,6 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec,
|
|||
}
|
||||
|
||||
static struct snd_kcontrol_new cxt5045_mixers[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Capture Source",
|
||||
.info = conexant_mux_enum_info,
|
||||
.get = conexant_mux_enum_get,
|
||||
.put = conexant_mux_enum_put
|
||||
},
|
||||
HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
|
||||
|
@ -759,13 +803,6 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
|
|||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Capture Source",
|
||||
.info = conexant_mux_enum_info,
|
||||
.get = conexant_mux_enum_get,
|
||||
.put = conexant_mux_enum_put
|
||||
},
|
||||
HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
|
||||
|
@ -1002,15 +1039,9 @@ static const char *cxt5045_models[CXT5045_MODELS] = {
|
|||
};
|
||||
|
||||
static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x30a5, "HP", CXT5045_LAPTOP_HPSENSE),
|
||||
SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP_HPSENSE),
|
||||
SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP_HPSENSE),
|
||||
SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP_HPSENSE),
|
||||
SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP_HPSENSE),
|
||||
SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP_HPSENSE),
|
||||
SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE),
|
||||
SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
|
||||
SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE),
|
||||
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
|
||||
CXT5045_LAPTOP_HPSENSE),
|
||||
SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE),
|
||||
SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
|
||||
SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
|
||||
|
@ -1020,8 +1051,8 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE),
|
||||
SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE),
|
||||
SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE),
|
||||
SND_PCI_QUIRK(0x1631, 0xc106, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE),
|
||||
SND_PCI_QUIRK(0x1631, 0xc107, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE),
|
||||
SND_PCI_QUIRK_MASK(0x1631, 0xff00, 0xc100, "Packard Bell",
|
||||
CXT5045_LAPTOP_HPMICSENSE),
|
||||
SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE),
|
||||
{}
|
||||
};
|
||||
|
@ -1035,6 +1066,7 @@ static int patch_cxt5045(struct hda_codec *codec)
|
|||
if (!spec)
|
||||
return -ENOMEM;
|
||||
codec->spec = spec;
|
||||
codec->pin_amp_workaround = 1;
|
||||
|
||||
spec->multiout.max_channels = 2;
|
||||
spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids);
|
||||
|
@ -1134,7 +1166,7 @@ static int patch_cxt5045(struct hda_codec *codec)
|
|||
/* Conexant 5047 specific */
|
||||
#define CXT5047_SPDIF_OUT 0x11
|
||||
|
||||
static hda_nid_t cxt5047_dac_nids[2] = { 0x10, 0x1c };
|
||||
static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */
|
||||
static hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
|
||||
static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
|
||||
|
||||
|
@ -1142,20 +1174,6 @@ static struct hda_channel_mode cxt5047_modes[1] = {
|
|||
{ 2, NULL },
|
||||
};
|
||||
|
||||
static struct hda_input_mux cxt5047_capture_source = {
|
||||
.num_items = 1,
|
||||
.items = {
|
||||
{ "Mic", 0x2 },
|
||||
}
|
||||
};
|
||||
|
||||
static struct hda_input_mux cxt5047_hp_capture_source = {
|
||||
.num_items = 1,
|
||||
.items = {
|
||||
{ "ExtMic", 0x2 },
|
||||
}
|
||||
};
|
||||
|
||||
static struct hda_input_mux cxt5047_toshiba_capture_source = {
|
||||
.num_items = 2,
|
||||
.items = {
|
||||
|
@ -1179,7 +1197,11 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol,
|
|||
* the headphone jack
|
||||
*/
|
||||
bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE;
|
||||
snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0,
|
||||
/* NOTE: Conexat codec needs the index for *OUTPUT* amp of
|
||||
* pin widgets unlike other codecs. In this case, we need to
|
||||
* set index 0x01 for the volume from the mixer amp 0x19.
|
||||
*/
|
||||
snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01,
|
||||
HDA_AMP_MUTE, bits);
|
||||
bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE;
|
||||
snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
|
||||
|
@ -1187,16 +1209,6 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */
|
||||
static struct hda_bind_ctls cxt5047_bind_master_vol = {
|
||||
.ops = &snd_hda_bind_vol,
|
||||
.values = {
|
||||
HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT),
|
||||
HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
|
||||
0
|
||||
},
|
||||
};
|
||||
|
||||
/* mute internal speaker if HP is plugged */
|
||||
static void cxt5047_hp_automute(struct hda_codec *codec)
|
||||
{
|
||||
|
@ -1207,27 +1219,8 @@ static void cxt5047_hp_automute(struct hda_codec *codec)
|
|||
AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
|
||||
|
||||
bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0;
|
||||
snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
/* Mute/Unmute PCM 2 for good measure - some systems need this */
|
||||
snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
}
|
||||
|
||||
/* mute internal speaker if HP is plugged */
|
||||
static void cxt5047_hp2_automute(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
unsigned int bits;
|
||||
|
||||
spec->hp_present = snd_hda_codec_read(codec, 0x13, 0,
|
||||
AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
|
||||
|
||||
bits = spec->hp_present ? HDA_AMP_MUTE : 0;
|
||||
snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, bits);
|
||||
/* Mute/Unmute PCM 2 for good measure - some systems need this */
|
||||
snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0,
|
||||
/* See the note in cxt5047_hp_master_sw_put */
|
||||
snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01,
|
||||
HDA_AMP_MUTE, bits);
|
||||
}
|
||||
|
||||
|
@ -1268,90 +1261,35 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec,
|
|||
}
|
||||
}
|
||||
|
||||
/* unsolicited event for HP jack sensing - non-EAPD systems */
|
||||
static void cxt5047_hp2_unsol_event(struct hda_codec *codec,
|
||||
unsigned int res)
|
||||
{
|
||||
res >>= 26;
|
||||
switch (res) {
|
||||
case CONEXANT_HP_EVENT:
|
||||
cxt5047_hp2_automute(codec);
|
||||
break;
|
||||
case CONEXANT_MIC_EVENT:
|
||||
cxt5047_hp_automic(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new cxt5047_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Gain Volume", 0x1a, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Mic Gain Switch", 0x1a, 0x0, HDA_OUTPUT),
|
||||
static struct snd_kcontrol_new cxt5047_base_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x1a, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("PCM-2 Volume", 0x1c, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("PCM-2 Switch", 0x1c, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x00, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.info = cxt_eapd_info,
|
||||
.get = cxt_eapd_get,
|
||||
.put = cxt5047_hp_master_sw_put,
|
||||
.private_value = 0x13,
|
||||
},
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = {
|
||||
/* See the note in cxt5047_hp_master_sw_put */
|
||||
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("Headphone Playback Switch", 0x13, 0x00, HDA_OUTPUT),
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5047_toshiba_mixers[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Capture Source",
|
||||
.info = conexant_mux_enum_info,
|
||||
.get = conexant_mux_enum_get,
|
||||
.put = conexant_mux_enum_put
|
||||
},
|
||||
HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
|
||||
HDA_BIND_VOL("Master Playback Volume", &cxt5047_bind_master_vol),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.info = cxt_eapd_info,
|
||||
.get = cxt_eapd_get,
|
||||
.put = cxt5047_hp_master_sw_put,
|
||||
.private_value = 0x13,
|
||||
},
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5047_hp_mixers[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Capture Source",
|
||||
.info = conexant_mux_enum_info,
|
||||
.get = conexant_mux_enum_get,
|
||||
.put = conexant_mux_enum_put
|
||||
},
|
||||
HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
|
||||
static struct snd_kcontrol_new cxt5047_hp_only_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.info = cxt_eapd_info,
|
||||
.get = cxt_eapd_get,
|
||||
.put = cxt5047_hp_master_sw_put,
|
||||
.private_value = 0x13,
|
||||
},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
|
@ -1362,8 +1300,8 @@ static struct hda_verb cxt5047_init_verbs[] = {
|
|||
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
|
||||
/* HP, Speaker */
|
||||
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
|
||||
{0x13, AC_VERB_SET_CONNECT_SEL,0x1},
|
||||
{0x1d, AC_VERB_SET_CONNECT_SEL,0x0},
|
||||
{0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* mixer(0x19) */
|
||||
{0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mixer(0x19) */
|
||||
/* Record selector: Mic */
|
||||
{0x12, AC_VERB_SET_CONNECT_SEL,0x03},
|
||||
{0x19, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
|
@ -1383,30 +1321,7 @@ static struct hda_verb cxt5047_init_verbs[] = {
|
|||
|
||||
/* configuration for Toshiba Laptops */
|
||||
static struct hda_verb cxt5047_toshiba_init_verbs[] = {
|
||||
{0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */
|
||||
/* pin sensing on HP and Mic jacks */
|
||||
{0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
|
||||
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
|
||||
/* Speaker routing */
|
||||
{0x1d, AC_VERB_SET_CONNECT_SEL,0x1},
|
||||
{}
|
||||
};
|
||||
|
||||
/* configuration for HP Laptops */
|
||||
static struct hda_verb cxt5047_hp_init_verbs[] = {
|
||||
/* pin sensing on HP jack */
|
||||
{0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
|
||||
/* 0x13 is actually shared by both HP and speaker;
|
||||
* setting the connection to 0 (=0x19) makes the master volume control
|
||||
* working mysteriouslly...
|
||||
*/
|
||||
{0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
|
||||
/* Record selector: Ext Mic */
|
||||
{0x12, AC_VERB_SET_CONNECT_SEL,0x03},
|
||||
{0x19, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
|
||||
/* Speaker routing */
|
||||
{0x1d, AC_VERB_SET_CONNECT_SEL,0x1},
|
||||
{0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -1571,11 +1486,9 @@ static const char *cxt5047_models[CXT5047_MODELS] = {
|
|||
};
|
||||
|
||||
static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP),
|
||||
SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
|
||||
SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP),
|
||||
SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP),
|
||||
SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6700", CXT5047_LAPTOP),
|
||||
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
|
||||
CXT5047_LAPTOP),
|
||||
SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD),
|
||||
{}
|
||||
};
|
||||
|
@ -1589,6 +1502,7 @@ static int patch_cxt5047(struct hda_codec *codec)
|
|||
if (!spec)
|
||||
return -ENOMEM;
|
||||
codec->spec = spec;
|
||||
codec->pin_amp_workaround = 1;
|
||||
|
||||
spec->multiout.max_channels = 2;
|
||||
spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids);
|
||||
|
@ -1597,9 +1511,8 @@ static int patch_cxt5047(struct hda_codec *codec)
|
|||
spec->num_adc_nids = 1;
|
||||
spec->adc_nids = cxt5047_adc_nids;
|
||||
spec->capsrc_nids = cxt5047_capsrc_nids;
|
||||
spec->input_mux = &cxt5047_capture_source;
|
||||
spec->num_mixers = 1;
|
||||
spec->mixers[0] = cxt5047_mixers;
|
||||
spec->mixers[0] = cxt5047_base_mixers;
|
||||
spec->num_init_verbs = 1;
|
||||
spec->init_verbs[0] = cxt5047_init_verbs;
|
||||
spec->spdif_route = 0;
|
||||
|
@ -1613,21 +1526,22 @@ static int patch_cxt5047(struct hda_codec *codec)
|
|||
cxt5047_cfg_tbl);
|
||||
switch (board_config) {
|
||||
case CXT5047_LAPTOP:
|
||||
codec->patch_ops.unsol_event = cxt5047_hp2_unsol_event;
|
||||
spec->num_mixers = 2;
|
||||
spec->mixers[1] = cxt5047_hp_spk_mixers;
|
||||
codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
|
||||
break;
|
||||
case CXT5047_LAPTOP_HP:
|
||||
spec->input_mux = &cxt5047_hp_capture_source;
|
||||
spec->num_init_verbs = 2;
|
||||
spec->init_verbs[1] = cxt5047_hp_init_verbs;
|
||||
spec->mixers[0] = cxt5047_hp_mixers;
|
||||
spec->num_mixers = 2;
|
||||
spec->mixers[1] = cxt5047_hp_only_mixers;
|
||||
codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
|
||||
codec->patch_ops.init = cxt5047_hp_init;
|
||||
break;
|
||||
case CXT5047_LAPTOP_EAPD:
|
||||
spec->input_mux = &cxt5047_toshiba_capture_source;
|
||||
spec->num_mixers = 2;
|
||||
spec->mixers[1] = cxt5047_hp_spk_mixers;
|
||||
spec->num_init_verbs = 2;
|
||||
spec->init_verbs[1] = cxt5047_toshiba_init_verbs;
|
||||
spec->mixers[0] = cxt5047_toshiba_mixers;
|
||||
codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
|
||||
break;
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
|
@ -1638,6 +1552,7 @@ static int patch_cxt5047(struct hda_codec *codec)
|
|||
codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
|
||||
#endif
|
||||
}
|
||||
spec->vmaster_nid = 0x13;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1673,8 +1588,11 @@ static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol,
|
|||
/* toggle input of built-in and mic jack appropriately */
|
||||
static void cxt5051_portb_automic(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
unsigned int present;
|
||||
|
||||
if (spec->no_auto_mic)
|
||||
return;
|
||||
present = snd_hda_codec_read(codec, 0x17, 0,
|
||||
AC_VERB_GET_PIN_SENSE, 0) &
|
||||
AC_PINSENSE_PRESENCE;
|
||||
|
@ -1690,6 +1608,8 @@ static void cxt5051_portc_automic(struct hda_codec *codec)
|
|||
unsigned int present;
|
||||
hda_nid_t new_adc;
|
||||
|
||||
if (spec->no_auto_mic)
|
||||
return;
|
||||
present = snd_hda_codec_read(codec, 0x18, 0,
|
||||
AC_VERB_GET_PIN_SENSE, 0) &
|
||||
AC_PINSENSE_PRESENCE;
|
||||
|
@ -1776,6 +1696,22 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
|
||||
HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Switch", 0x14, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Switch",
|
||||
.info = cxt_eapd_info,
|
||||
.get = cxt_eapd_get,
|
||||
.put = cxt5051_hp_master_sw_put,
|
||||
.private_value = 0x1a,
|
||||
},
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5051_init_verbs[] = {
|
||||
/* Line in, Mic */
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
|
||||
|
@ -1806,6 +1742,66 @@ static struct hda_verb cxt5051_init_verbs[] = {
|
|||
{ } /* end */
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
|
||||
/* Line in, Mic */
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
|
||||
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
|
||||
/* SPK */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* HP, Amp */
|
||||
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* DAC1 */
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
/* Record selector: Int mic */
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
|
||||
{0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
|
||||
/* SPDIF route: PCM */
|
||||
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
|
||||
/* EAPD */
|
||||
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
|
||||
{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
|
||||
/* Line in, Mic */
|
||||
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
|
||||
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
|
||||
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
||||
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
||||
{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
|
||||
/* SPK */
|
||||
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
||||
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* HP, Amp */
|
||||
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* Docking HP */
|
||||
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
||||
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00},
|
||||
/* DAC1 */
|
||||
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
||||
/* Record selector: Int mic */
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
|
||||
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
|
||||
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
|
||||
/* SPDIF route: PCM */
|
||||
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
|
||||
/* EAPD */
|
||||
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
|
||||
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
|
||||
{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
|
||||
{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
|
||||
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/* initialize jack-sensing, too */
|
||||
static int cxt5051_init(struct hda_codec *codec)
|
||||
{
|
||||
|
@ -1823,18 +1819,24 @@ static int cxt5051_init(struct hda_codec *codec)
|
|||
enum {
|
||||
CXT5051_LAPTOP, /* Laptops w/ EAPD support */
|
||||
CXT5051_HP, /* no docking */
|
||||
CXT5051_HP_DV6736, /* HP without mic switch */
|
||||
CXT5051_LENOVO_X200, /* Lenovo X200 laptop */
|
||||
CXT5051_MODELS
|
||||
};
|
||||
|
||||
static const char *cxt5051_models[CXT5051_MODELS] = {
|
||||
[CXT5051_LAPTOP] = "laptop",
|
||||
[CXT5051_HP] = "hp",
|
||||
[CXT5051_HP_DV6736] = "hp-dv6736",
|
||||
[CXT5051_LENOVO_X200] = "lenovo-x200",
|
||||
};
|
||||
|
||||
static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736),
|
||||
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
|
||||
CXT5051_LAPTOP),
|
||||
SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
|
||||
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -1847,6 +1849,7 @@ static int patch_cxt5051(struct hda_codec *codec)
|
|||
if (!spec)
|
||||
return -ENOMEM;
|
||||
codec->spec = spec;
|
||||
codec->pin_amp_workaround = 1;
|
||||
|
||||
codec->patch_ops = conexant_patch_ops;
|
||||
codec->patch_ops.init = cxt5051_init;
|
||||
|
@ -1867,17 +1870,22 @@ static int patch_cxt5051(struct hda_codec *codec)
|
|||
spec->cur_adc = 0;
|
||||
spec->cur_adc_idx = 0;
|
||||
|
||||
codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
|
||||
|
||||
board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
|
||||
cxt5051_models,
|
||||
cxt5051_cfg_tbl);
|
||||
switch (board_config) {
|
||||
case CXT5051_HP:
|
||||
codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
|
||||
spec->mixers[0] = cxt5051_hp_mixers;
|
||||
break;
|
||||
default:
|
||||
case CXT5051_LAPTOP:
|
||||
codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
|
||||
case CXT5051_HP_DV6736:
|
||||
spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs;
|
||||
spec->mixers[0] = cxt5051_hp_dv6736_mixers;
|
||||
spec->no_auto_mic = 1;
|
||||
break;
|
||||
case CXT5051_LENOVO_X200:
|
||||
spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1308,16 +1308,13 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
|
|||
unsigned int def_conf;
|
||||
unsigned char seqassoc;
|
||||
|
||||
def_conf = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_CONFIG_DEFAULT, 0);
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
seqassoc = (unsigned char) get_defcfg_association(def_conf);
|
||||
seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
|
||||
if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
|
||||
if (seqassoc == 0xff) {
|
||||
def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
|
||||
def_conf >> 24);
|
||||
snd_hda_codec_set_pincfg(codec, nid, def_conf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1354,7 +1351,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
|
|||
|
||||
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
||||
|
||||
if (spec->autocfg.dig_out_pin)
|
||||
if (spec->autocfg.dig_outs)
|
||||
spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
|
||||
if (spec->autocfg.dig_in_pin)
|
||||
spec->dig_in_nid = VT1708_DIGIN_NID;
|
||||
|
@ -1827,7 +1824,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
|
|||
|
||||
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
||||
|
||||
if (spec->autocfg.dig_out_pin)
|
||||
if (spec->autocfg.dig_outs)
|
||||
spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
|
||||
if (spec->autocfg.dig_in_pin)
|
||||
spec->dig_in_nid = VT1709_DIGIN_NID;
|
||||
|
@ -2371,7 +2368,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
|
|||
|
||||
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
||||
|
||||
if (spec->autocfg.dig_out_pin)
|
||||
if (spec->autocfg.dig_outs)
|
||||
spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
|
||||
if (spec->autocfg.dig_in_pin)
|
||||
spec->dig_in_nid = VT1708B_DIGIN_NID;
|
||||
|
@ -2836,7 +2833,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
|
|||
|
||||
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
||||
|
||||
if (spec->autocfg.dig_out_pin)
|
||||
if (spec->autocfg.dig_outs)
|
||||
spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
|
||||
|
||||
spec->extra_dig_out_nid = 0x15;
|
||||
|
@ -3155,7 +3152,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
|
|||
|
||||
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
||||
|
||||
if (spec->autocfg.dig_out_pin)
|
||||
if (spec->autocfg.dig_outs)
|
||||
spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
|
||||
|
||||
spec->extra_dig_out_nid = 0x1B;
|
||||
|
|
Loading…
Reference in New Issue