Merge branch 'topic/hda' into for-linus
This commit is contained in:
commit
6de15b2a93
|
@ -1,6 +1,6 @@
|
|||
snd-hda-intel-objs := hda_intel.o
|
||||
|
||||
snd-hda-codec-y := hda_codec.o hda_jack.o
|
||||
snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
|
||||
snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
|
||||
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
|
||||
|
|
760
sound/pci/hda/hda_auto_parser.c
Normal file
760
sound/pci/hda/hda_auto_parser.c
Normal file
|
@ -0,0 +1,760 @@
|
|||
/*
|
||||
* BIOS auto-parser helper functions for HD-audio
|
||||
*
|
||||
* Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
|
||||
*
|
||||
* This driver is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
|
||||
#define SFX "hda_codec: "
|
||||
|
||||
/*
|
||||
* Helper for automatic pin configuration
|
||||
*/
|
||||
|
||||
static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list)
|
||||
{
|
||||
for (; *list; list++)
|
||||
if (*list == nid)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sort an associated group of pins according to their sequence numbers.
|
||||
*/
|
||||
static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
|
||||
int num_pins)
|
||||
{
|
||||
int i, j;
|
||||
short seq;
|
||||
hda_nid_t nid;
|
||||
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
for (j = i + 1; j < num_pins; j++) {
|
||||
if (sequences[i] > sequences[j]) {
|
||||
seq = sequences[i];
|
||||
sequences[i] = sequences[j];
|
||||
sequences[j] = seq;
|
||||
nid = pins[i];
|
||||
pins[i] = pins[j];
|
||||
pins[j] = nid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* add the found input-pin to the cfg->inputs[] table */
|
||||
static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
|
||||
int type)
|
||||
{
|
||||
if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
|
||||
cfg->inputs[cfg->num_inputs].pin = nid;
|
||||
cfg->inputs[cfg->num_inputs].type = type;
|
||||
cfg->num_inputs++;
|
||||
}
|
||||
}
|
||||
|
||||
/* sort inputs in the order of AUTO_PIN_* type */
|
||||
static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
for (j = i + 1; j < cfg->num_inputs; j++) {
|
||||
if (cfg->inputs[i].type > cfg->inputs[j].type) {
|
||||
struct auto_pin_cfg_item tmp;
|
||||
tmp = cfg->inputs[i];
|
||||
cfg->inputs[i] = cfg->inputs[j];
|
||||
cfg->inputs[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reorder the surround channels
|
||||
* ALSA sequence is front/surr/clfe/side
|
||||
* HDA sequence is:
|
||||
* 4-ch: front/surr => OK as it is
|
||||
* 6-ch: front/clfe/surr
|
||||
* 8-ch: front/clfe/rear/side|fc
|
||||
*/
|
||||
static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
|
||||
{
|
||||
hda_nid_t nid;
|
||||
|
||||
switch (nums) {
|
||||
case 3:
|
||||
case 4:
|
||||
nid = pins[1];
|
||||
pins[1] = pins[2];
|
||||
pins[2] = nid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse all pin widgets and store the useful pin nids to cfg
|
||||
*
|
||||
* The number of line-outs or any primary output is stored in line_outs,
|
||||
* and the corresponding output pins are assigned to line_out_pins[],
|
||||
* in the order of front, rear, CLFE, side, ...
|
||||
*
|
||||
* If more extra outputs (speaker and headphone) are found, the pins are
|
||||
* assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack
|
||||
* is detected, one of speaker of HP pins is assigned as the primary
|
||||
* output, i.e. to line_out_pins[0]. So, line_outs is always positive
|
||||
* if any analog output exists.
|
||||
*
|
||||
* The analog input pins are assigned to inputs array.
|
||||
* The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
|
||||
* respectively.
|
||||
*/
|
||||
int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
|
||||
struct auto_pin_cfg *cfg,
|
||||
const hda_nid_t *ignore_nids,
|
||||
unsigned int cond_flags)
|
||||
{
|
||||
hda_nid_t nid, end_nid;
|
||||
short seq, assoc_line_out;
|
||||
short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
|
||||
short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
|
||||
short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
|
||||
int i;
|
||||
|
||||
memset(cfg, 0, sizeof(*cfg));
|
||||
|
||||
memset(sequences_line_out, 0, sizeof(sequences_line_out));
|
||||
memset(sequences_speaker, 0, sizeof(sequences_speaker));
|
||||
memset(sequences_hp, 0, sizeof(sequences_hp));
|
||||
assoc_line_out = 0;
|
||||
|
||||
codec->ignore_misc_bit = true;
|
||||
end_nid = codec->start_nid + codec->num_nodes;
|
||||
for (nid = codec->start_nid; nid < end_nid; nid++) {
|
||||
unsigned int wid_caps = get_wcaps(codec, nid);
|
||||
unsigned int wid_type = get_wcaps_type(wid_caps);
|
||||
unsigned int def_conf;
|
||||
short assoc, loc, conn, dev;
|
||||
|
||||
/* read all default configuration for pin complex */
|
||||
if (wid_type != AC_WID_PIN)
|
||||
continue;
|
||||
/* ignore the given nids (e.g. pc-beep returns error) */
|
||||
if (ignore_nids && is_in_nid_list(nid, ignore_nids))
|
||||
continue;
|
||||
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
|
||||
AC_DEFCFG_MISC_NO_PRESENCE))
|
||||
codec->ignore_misc_bit = false;
|
||||
conn = get_defcfg_connect(def_conf);
|
||||
if (conn == AC_JACK_PORT_NONE)
|
||||
continue;
|
||||
loc = get_defcfg_location(def_conf);
|
||||
dev = get_defcfg_device(def_conf);
|
||||
|
||||
/* workaround for buggy BIOS setups */
|
||||
if (dev == AC_JACK_LINE_OUT) {
|
||||
if (conn == AC_JACK_PORT_FIXED)
|
||||
dev = AC_JACK_SPEAKER;
|
||||
}
|
||||
|
||||
switch (dev) {
|
||||
case AC_JACK_LINE_OUT:
|
||||
seq = get_defcfg_sequence(def_conf);
|
||||
assoc = get_defcfg_association(def_conf);
|
||||
|
||||
if (!(wid_caps & AC_WCAP_STEREO))
|
||||
if (!cfg->mono_out_pin)
|
||||
cfg->mono_out_pin = nid;
|
||||
if (!assoc)
|
||||
continue;
|
||||
if (!assoc_line_out)
|
||||
assoc_line_out = assoc;
|
||||
else if (assoc_line_out != assoc)
|
||||
continue;
|
||||
if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
|
||||
continue;
|
||||
cfg->line_out_pins[cfg->line_outs] = nid;
|
||||
sequences_line_out[cfg->line_outs] = seq;
|
||||
cfg->line_outs++;
|
||||
break;
|
||||
case AC_JACK_SPEAKER:
|
||||
seq = get_defcfg_sequence(def_conf);
|
||||
assoc = get_defcfg_association(def_conf);
|
||||
if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
|
||||
continue;
|
||||
cfg->speaker_pins[cfg->speaker_outs] = nid;
|
||||
sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq;
|
||||
cfg->speaker_outs++;
|
||||
break;
|
||||
case AC_JACK_HP_OUT:
|
||||
seq = get_defcfg_sequence(def_conf);
|
||||
assoc = get_defcfg_association(def_conf);
|
||||
if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
|
||||
continue;
|
||||
cfg->hp_pins[cfg->hp_outs] = nid;
|
||||
sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
|
||||
cfg->hp_outs++;
|
||||
break;
|
||||
case AC_JACK_MIC_IN:
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
|
||||
break;
|
||||
case AC_JACK_LINE_IN:
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
|
||||
break;
|
||||
case AC_JACK_CD:
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
|
||||
break;
|
||||
case AC_JACK_AUX:
|
||||
add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
|
||||
break;
|
||||
case AC_JACK_SPDIF_OUT:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIX-UP:
|
||||
* If no line-out is defined but multiple HPs are found,
|
||||
* some of them might be the real line-outs.
|
||||
*/
|
||||
if (!cfg->line_outs && cfg->hp_outs > 1 &&
|
||||
!(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) {
|
||||
int i = 0;
|
||||
while (i < cfg->hp_outs) {
|
||||
/* The real HPs should have the sequence 0x0f */
|
||||
if ((sequences_hp[i] & 0x0f) == 0x0f) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
/* Move it to the line-out table */
|
||||
cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i];
|
||||
sequences_line_out[cfg->line_outs] = sequences_hp[i];
|
||||
cfg->line_outs++;
|
||||
cfg->hp_outs--;
|
||||
memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1,
|
||||
sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i));
|
||||
memmove(sequences_hp + i, sequences_hp + i + 1,
|
||||
sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
|
||||
}
|
||||
memset(cfg->hp_pins + cfg->hp_outs, 0,
|
||||
sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
|
||||
if (!cfg->hp_outs)
|
||||
cfg->line_out_type = AUTO_PIN_HP_OUT;
|
||||
|
||||
}
|
||||
|
||||
/* sort by sequence */
|
||||
sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out,
|
||||
cfg->line_outs);
|
||||
sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker,
|
||||
cfg->speaker_outs);
|
||||
sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
|
||||
cfg->hp_outs);
|
||||
|
||||
/*
|
||||
* FIX-UP: if no line-outs are detected, try to use speaker or HP pin
|
||||
* as a primary output
|
||||
*/
|
||||
if (!cfg->line_outs &&
|
||||
!(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) {
|
||||
if (cfg->speaker_outs) {
|
||||
cfg->line_outs = cfg->speaker_outs;
|
||||
memcpy(cfg->line_out_pins, cfg->speaker_pins,
|
||||
sizeof(cfg->speaker_pins));
|
||||
cfg->speaker_outs = 0;
|
||||
memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
|
||||
cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
|
||||
} else if (cfg->hp_outs) {
|
||||
cfg->line_outs = cfg->hp_outs;
|
||||
memcpy(cfg->line_out_pins, cfg->hp_pins,
|
||||
sizeof(cfg->hp_pins));
|
||||
cfg->hp_outs = 0;
|
||||
memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
|
||||
cfg->line_out_type = AUTO_PIN_HP_OUT;
|
||||
}
|
||||
}
|
||||
|
||||
reorder_outputs(cfg->line_outs, cfg->line_out_pins);
|
||||
reorder_outputs(cfg->hp_outs, cfg->hp_pins);
|
||||
reorder_outputs(cfg->speaker_outs, cfg->speaker_pins);
|
||||
|
||||
sort_autocfg_input_pins(cfg);
|
||||
|
||||
/*
|
||||
* debug prints of the parsed results
|
||||
*/
|
||||
snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
|
||||
cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
|
||||
cfg->line_out_pins[2], cfg->line_out_pins[3],
|
||||
cfg->line_out_pins[4],
|
||||
cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
|
||||
(cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
|
||||
"speaker" : "line"));
|
||||
snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
|
||||
cfg->speaker_outs, cfg->speaker_pins[0],
|
||||
cfg->speaker_pins[1], cfg->speaker_pins[2],
|
||||
cfg->speaker_pins[3], cfg->speaker_pins[4]);
|
||||
snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
|
||||
cfg->hp_outs, cfg->hp_pins[0],
|
||||
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:");
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
snd_printd(" %s=0x%x",
|
||||
hda_get_autocfg_input_label(codec, cfg, i),
|
||||
cfg->inputs[i].pin);
|
||||
}
|
||||
snd_printd("\n");
|
||||
if (cfg->dig_in_pin)
|
||||
snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg);
|
||||
|
||||
int snd_hda_get_input_pin_attr(unsigned int def_conf)
|
||||
{
|
||||
unsigned int loc = get_defcfg_location(def_conf);
|
||||
unsigned int conn = get_defcfg_connect(def_conf);
|
||||
if (conn == AC_JACK_PORT_NONE)
|
||||
return INPUT_PIN_ATTR_UNUSED;
|
||||
/* Windows may claim the internal mic to be BOTH, too */
|
||||
if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
|
||||
return INPUT_PIN_ATTR_INT;
|
||||
if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
|
||||
return INPUT_PIN_ATTR_INT;
|
||||
if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
|
||||
return INPUT_PIN_ATTR_DOCK;
|
||||
if (loc == AC_JACK_LOC_REAR)
|
||||
return INPUT_PIN_ATTR_REAR;
|
||||
if (loc == AC_JACK_LOC_FRONT)
|
||||
return INPUT_PIN_ATTR_FRONT;
|
||||
return INPUT_PIN_ATTR_NORMAL;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
|
||||
|
||||
/**
|
||||
* hda_get_input_pin_label - Give a label for the given input pin
|
||||
*
|
||||
* When check_location is true, the function checks the pin location
|
||||
* for mic and line-in pins, and set an appropriate prefix like "Front",
|
||||
* "Rear", "Internal".
|
||||
*/
|
||||
|
||||
static const char *hda_get_input_pin_label(struct hda_codec *codec,
|
||||
hda_nid_t pin, bool check_location)
|
||||
{
|
||||
unsigned int def_conf;
|
||||
static const char * const mic_names[] = {
|
||||
"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
|
||||
};
|
||||
int attr;
|
||||
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, pin);
|
||||
|
||||
switch (get_defcfg_device(def_conf)) {
|
||||
case AC_JACK_MIC_IN:
|
||||
if (!check_location)
|
||||
return "Mic";
|
||||
attr = snd_hda_get_input_pin_attr(def_conf);
|
||||
if (!attr)
|
||||
return "None";
|
||||
return mic_names[attr - 1];
|
||||
case AC_JACK_LINE_IN:
|
||||
if (!check_location)
|
||||
return "Line";
|
||||
attr = snd_hda_get_input_pin_attr(def_conf);
|
||||
if (!attr)
|
||||
return "None";
|
||||
if (attr == INPUT_PIN_ATTR_DOCK)
|
||||
return "Dock Line";
|
||||
return "Line";
|
||||
case AC_JACK_AUX:
|
||||
return "Aux";
|
||||
case AC_JACK_CD:
|
||||
return "CD";
|
||||
case AC_JACK_SPDIF_IN:
|
||||
return "SPDIF In";
|
||||
case AC_JACK_DIG_OTHER_IN:
|
||||
return "Digital In";
|
||||
default:
|
||||
return "Misc";
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether the location prefix needs to be added to the label.
|
||||
* If all mic-jacks are in the same location (e.g. rear panel), we don't
|
||||
* have to put "Front" prefix to each label. In such a case, returns false.
|
||||
*/
|
||||
static int check_mic_location_need(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
int input)
|
||||
{
|
||||
unsigned int defc;
|
||||
int i, attr, attr2;
|
||||
|
||||
defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
|
||||
attr = snd_hda_get_input_pin_attr(defc);
|
||||
/* for internal or docking mics, we need locations */
|
||||
if (attr <= INPUT_PIN_ATTR_NORMAL)
|
||||
return 1;
|
||||
|
||||
attr = 0;
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
|
||||
attr2 = snd_hda_get_input_pin_attr(defc);
|
||||
if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
|
||||
if (attr && attr != attr2)
|
||||
return 1; /* different locations found */
|
||||
attr = attr2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hda_get_autocfg_input_label - Get a label for the given input
|
||||
*
|
||||
* Get a label for the given input pin defined by the autocfg item.
|
||||
* Unlike hda_get_input_pin_label(), this function checks all inputs
|
||||
* defined in autocfg and avoids the redundant mic/line prefix as much as
|
||||
* possible.
|
||||
*/
|
||||
const char *hda_get_autocfg_input_label(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
int input)
|
||||
{
|
||||
int type = cfg->inputs[input].type;
|
||||
int has_multiple_pins = 0;
|
||||
|
||||
if ((input > 0 && cfg->inputs[input - 1].type == type) ||
|
||||
(input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
|
||||
has_multiple_pins = 1;
|
||||
if (has_multiple_pins && type == AUTO_PIN_MIC)
|
||||
has_multiple_pins &= check_mic_location_need(codec, cfg, input);
|
||||
return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
|
||||
has_multiple_pins);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
|
||||
|
||||
/* return the position of NID in the list, or -1 if not found */
|
||||
static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nums; i++)
|
||||
if (list[i] == nid)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get a unique suffix or an index number */
|
||||
static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
|
||||
int num_pins, int *indexp)
|
||||
{
|
||||
static const char * const channel_sfx[] = {
|
||||
" Front", " Surround", " CLFE", " Side"
|
||||
};
|
||||
int i;
|
||||
|
||||
i = find_idx_in_nid_list(nid, pins, num_pins);
|
||||
if (i < 0)
|
||||
return NULL;
|
||||
if (num_pins == 1)
|
||||
return "";
|
||||
if (num_pins > ARRAY_SIZE(channel_sfx)) {
|
||||
if (indexp)
|
||||
*indexp = i;
|
||||
return "";
|
||||
}
|
||||
return channel_sfx[i];
|
||||
}
|
||||
|
||||
static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
const char *name, char *label, int maxlen,
|
||||
int *indexp)
|
||||
{
|
||||
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
int attr = snd_hda_get_input_pin_attr(def_conf);
|
||||
const char *pfx = "", *sfx = "";
|
||||
|
||||
/* handle as a speaker if it's a fixed line-out */
|
||||
if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT)
|
||||
name = "Speaker";
|
||||
/* check the location */
|
||||
switch (attr) {
|
||||
case INPUT_PIN_ATTR_DOCK:
|
||||
pfx = "Dock ";
|
||||
break;
|
||||
case INPUT_PIN_ATTR_FRONT:
|
||||
pfx = "Front ";
|
||||
break;
|
||||
}
|
||||
if (cfg) {
|
||||
/* try to give a unique suffix if needed */
|
||||
sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
|
||||
indexp);
|
||||
if (!sfx)
|
||||
sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs,
|
||||
indexp);
|
||||
if (!sfx) {
|
||||
/* don't add channel suffix for Headphone controls */
|
||||
int idx = find_idx_in_nid_list(nid, cfg->hp_pins,
|
||||
cfg->hp_outs);
|
||||
if (idx >= 0)
|
||||
*indexp = idx;
|
||||
sfx = "";
|
||||
}
|
||||
}
|
||||
snprintf(label, maxlen, "%s%s%s", pfx, name, sfx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_get_pin_label - Get a label for the given I/O pin
|
||||
*
|
||||
* Get a label for the given pin. This function works for both input and
|
||||
* output pins. When @cfg is given as non-NULL, the function tries to get
|
||||
* an optimized label using hda_get_autocfg_input_label().
|
||||
*
|
||||
* This function tries to give a unique label string for the pin as much as
|
||||
* possible. For example, when the multiple line-outs are present, it adds
|
||||
* the channel suffix like "Front", "Surround", etc (only when @cfg is given).
|
||||
* If no unique name with a suffix is available and @indexp is non-NULL, the
|
||||
* index number is stored in the pointer.
|
||||
*/
|
||||
int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
char *label, int maxlen, int *indexp)
|
||||
{
|
||||
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
const char *name = NULL;
|
||||
int i;
|
||||
|
||||
if (indexp)
|
||||
*indexp = 0;
|
||||
if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
|
||||
return 0;
|
||||
|
||||
switch (get_defcfg_device(def_conf)) {
|
||||
case AC_JACK_LINE_OUT:
|
||||
return fill_audio_out_name(codec, nid, cfg, "Line Out",
|
||||
label, maxlen, indexp);
|
||||
case AC_JACK_SPEAKER:
|
||||
return fill_audio_out_name(codec, nid, cfg, "Speaker",
|
||||
label, maxlen, indexp);
|
||||
case AC_JACK_HP_OUT:
|
||||
return fill_audio_out_name(codec, nid, cfg, "Headphone",
|
||||
label, maxlen, indexp);
|
||||
case AC_JACK_SPDIF_OUT:
|
||||
case AC_JACK_DIG_OTHER_OUT:
|
||||
if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
|
||||
name = "HDMI";
|
||||
else
|
||||
name = "SPDIF";
|
||||
if (cfg && indexp) {
|
||||
i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
|
||||
cfg->dig_outs);
|
||||
if (i >= 0)
|
||||
*indexp = i;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (cfg) {
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
if (cfg->inputs[i].pin != nid)
|
||||
continue;
|
||||
name = hda_get_autocfg_input_label(codec, cfg, i);
|
||||
if (name)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!name)
|
||||
name = hda_get_input_pin_label(codec, nid, true);
|
||||
break;
|
||||
}
|
||||
if (!name)
|
||||
return 0;
|
||||
strlcpy(label, name, maxlen);
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
|
||||
|
||||
int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
|
||||
const struct hda_verb *list)
|
||||
{
|
||||
const struct hda_verb **v;
|
||||
snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8);
|
||||
v = snd_array_new(&spec->verbs);
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
*v = list;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs);
|
||||
|
||||
void snd_hda_gen_apply_verbs(struct hda_codec *codec)
|
||||
{
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
int i;
|
||||
for (i = 0; i < spec->verbs.used; i++) {
|
||||
struct hda_verb **v = snd_array_elem(&spec->verbs, i);
|
||||
snd_hda_sequence_write(codec, *v);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs);
|
||||
|
||||
void snd_hda_apply_pincfgs(struct hda_codec *codec,
|
||||
const struct hda_pintbl *cfg)
|
||||
{
|
||||
for (; cfg->nid; cfg++)
|
||||
snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs);
|
||||
|
||||
void snd_hda_apply_fixup(struct hda_codec *codec, int action)
|
||||
{
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
int id = spec->fixup_id;
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
const char *modelname = spec->fixup_name;
|
||||
#endif
|
||||
int depth = 0;
|
||||
|
||||
if (!spec->fixup_list)
|
||||
return;
|
||||
|
||||
while (id >= 0) {
|
||||
const struct hda_fixup *fix = spec->fixup_list + id;
|
||||
|
||||
switch (fix->type) {
|
||||
case HDA_FIXUP_PINS:
|
||||
if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins)
|
||||
break;
|
||||
snd_printdd(KERN_INFO SFX
|
||||
"%s: Apply pincfg for %s\n",
|
||||
codec->chip_name, modelname);
|
||||
snd_hda_apply_pincfgs(codec, fix->v.pins);
|
||||
break;
|
||||
case HDA_FIXUP_VERBS:
|
||||
if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs)
|
||||
break;
|
||||
snd_printdd(KERN_INFO SFX
|
||||
"%s: Apply fix-verbs for %s\n",
|
||||
codec->chip_name, modelname);
|
||||
snd_hda_gen_add_verbs(codec->spec, fix->v.verbs);
|
||||
break;
|
||||
case HDA_FIXUP_FUNC:
|
||||
if (!fix->v.func)
|
||||
break;
|
||||
snd_printdd(KERN_INFO SFX
|
||||
"%s: Apply fix-func for %s\n",
|
||||
codec->chip_name, modelname);
|
||||
fix->v.func(codec, fix, action);
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_ERR SFX
|
||||
"%s: Invalid fixup type %d\n",
|
||||
codec->chip_name, fix->type);
|
||||
break;
|
||||
}
|
||||
if (!fix->chained)
|
||||
break;
|
||||
if (++depth > 10)
|
||||
break;
|
||||
id = fix->chain_id;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_apply_fixup);
|
||||
|
||||
void snd_hda_pick_fixup(struct hda_codec *codec,
|
||||
const struct hda_model_fixup *models,
|
||||
const struct snd_pci_quirk *quirk,
|
||||
const struct hda_fixup *fixlist)
|
||||
{
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
const struct snd_pci_quirk *q;
|
||||
int id = -1;
|
||||
const char *name = NULL;
|
||||
|
||||
/* when model=nofixup is given, don't pick up any fixups */
|
||||
if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
|
||||
spec->fixup_list = NULL;
|
||||
spec->fixup_id = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (codec->modelname && models) {
|
||||
while (models->name) {
|
||||
if (!strcmp(codec->modelname, models->name)) {
|
||||
id = models->id;
|
||||
name = models->name;
|
||||
break;
|
||||
}
|
||||
models++;
|
||||
}
|
||||
}
|
||||
if (id < 0) {
|
||||
q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
|
||||
if (q) {
|
||||
id = q->value;
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
name = q->name;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (id < 0) {
|
||||
for (q = quirk; q->subvendor; q++) {
|
||||
unsigned int vendorid =
|
||||
q->subdevice | (q->subvendor << 16);
|
||||
if (vendorid == codec->subsystem_id) {
|
||||
id = q->value;
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
name = q->name;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spec->fixup_id = id;
|
||||
if (id >= 0) {
|
||||
spec->fixup_list = fixlist;
|
||||
spec->fixup_name = name;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_pick_fixup);
|
160
sound/pci/hda/hda_auto_parser.h
Normal file
160
sound/pci/hda/hda_auto_parser.h
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* BIOS auto-parser helper functions for HD-audio
|
||||
*
|
||||
* Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
|
||||
*
|
||||
* This driver is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_HDA_AUTO_PARSER_H
|
||||
#define __SOUND_HDA_AUTO_PARSER_H
|
||||
|
||||
/*
|
||||
* Helper for automatic pin configuration
|
||||
*/
|
||||
|
||||
enum {
|
||||
AUTO_PIN_MIC,
|
||||
AUTO_PIN_LINE_IN,
|
||||
AUTO_PIN_CD,
|
||||
AUTO_PIN_AUX,
|
||||
AUTO_PIN_LAST
|
||||
};
|
||||
|
||||
enum {
|
||||
AUTO_PIN_LINE_OUT,
|
||||
AUTO_PIN_SPEAKER_OUT,
|
||||
AUTO_PIN_HP_OUT
|
||||
};
|
||||
|
||||
#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS
|
||||
#define AUTO_CFG_MAX_INS 8
|
||||
|
||||
struct auto_pin_cfg_item {
|
||||
hda_nid_t pin;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct auto_pin_cfg;
|
||||
const char *hda_get_autocfg_input_label(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
int input);
|
||||
int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
char *label, int maxlen, int *indexp);
|
||||
|
||||
enum {
|
||||
INPUT_PIN_ATTR_UNUSED, /* pin not connected */
|
||||
INPUT_PIN_ATTR_INT, /* internal mic/line-in */
|
||||
INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
|
||||
INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
|
||||
INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
|
||||
INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
|
||||
};
|
||||
|
||||
int snd_hda_get_input_pin_attr(unsigned int def_conf);
|
||||
|
||||
struct auto_pin_cfg {
|
||||
int line_outs;
|
||||
/* sorted in the order of Front/Surr/CLFE/Side */
|
||||
hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS];
|
||||
int speaker_outs;
|
||||
hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS];
|
||||
int hp_outs;
|
||||
int line_out_type; /* AUTO_PIN_XXX_OUT */
|
||||
hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
|
||||
int num_inputs;
|
||||
struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
|
||||
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 */
|
||||
};
|
||||
|
||||
/* bit-flags for snd_hda_parse_pin_def_config() behavior */
|
||||
#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */
|
||||
#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */
|
||||
|
||||
int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
|
||||
struct auto_pin_cfg *cfg,
|
||||
const hda_nid_t *ignore_nids,
|
||||
unsigned int cond_flags);
|
||||
|
||||
/* older function */
|
||||
#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
|
||||
snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
struct hda_gen_spec {
|
||||
/* fix-up list */
|
||||
int fixup_id;
|
||||
const struct hda_fixup *fixup_list;
|
||||
const char *fixup_name;
|
||||
|
||||
/* additional init verbs */
|
||||
struct snd_array verbs;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Fix-up pin default configurations and add default verbs
|
||||
*/
|
||||
|
||||
struct hda_pintbl {
|
||||
hda_nid_t nid;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
struct hda_model_fixup {
|
||||
const int id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct hda_fixup {
|
||||
int type;
|
||||
bool chained;
|
||||
int chain_id;
|
||||
union {
|
||||
const struct hda_pintbl *pins;
|
||||
const struct hda_verb *verbs;
|
||||
void (*func)(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix,
|
||||
int action);
|
||||
} v;
|
||||
};
|
||||
|
||||
/* fixup types */
|
||||
enum {
|
||||
HDA_FIXUP_INVALID,
|
||||
HDA_FIXUP_PINS,
|
||||
HDA_FIXUP_VERBS,
|
||||
HDA_FIXUP_FUNC,
|
||||
};
|
||||
|
||||
/* fixup action definitions */
|
||||
enum {
|
||||
HDA_FIXUP_ACT_PRE_PROBE,
|
||||
HDA_FIXUP_ACT_PROBE,
|
||||
HDA_FIXUP_ACT_INIT,
|
||||
HDA_FIXUP_ACT_BUILD,
|
||||
};
|
||||
|
||||
int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
|
||||
const struct hda_verb *list);
|
||||
void snd_hda_gen_apply_verbs(struct hda_codec *codec);
|
||||
void snd_hda_apply_pincfgs(struct hda_codec *codec,
|
||||
const struct hda_pintbl *cfg);
|
||||
void snd_hda_apply_fixup(struct hda_codec *codec, int action);
|
||||
void snd_hda_pick_fixup(struct hda_codec *codec,
|
||||
const struct hda_model_fixup *models,
|
||||
const struct snd_pci_quirk *quirk,
|
||||
const struct hda_fixup *fixlist);
|
||||
|
||||
#endif /* __SOUND_HDA_AUTO_PARSER_H */
|
File diff suppressed because it is too large
Load diff
|
@ -704,8 +704,6 @@ struct hda_codec_ops {
|
|||
unsigned int power_state);
|
||||
#ifdef CONFIG_PM
|
||||
int (*suspend)(struct hda_codec *codec, pm_message_t state);
|
||||
int (*post_suspend)(struct hda_codec *codec);
|
||||
int (*pre_resume)(struct hda_codec *codec);
|
||||
int (*resume)(struct hda_codec *codec);
|
||||
#endif
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
|
@ -829,6 +827,7 @@ struct hda_codec {
|
|||
|
||||
struct mutex spdif_mutex;
|
||||
struct mutex control_mutex;
|
||||
struct mutex hash_mutex;
|
||||
struct snd_array spdif_out;
|
||||
unsigned int spdif_in_enable; /* SPDIF input enable? */
|
||||
const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
|
||||
|
@ -861,12 +860,13 @@ struct hda_codec {
|
|||
unsigned int no_jack_detect:1; /* Machine has no jack-detection */
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
unsigned int power_on :1; /* current (global) power-state */
|
||||
unsigned int power_transition :1; /* power-state in transition */
|
||||
int power_transition; /* power-state in transition */
|
||||
int power_count; /* current (global) power refcount */
|
||||
struct delayed_work power_work; /* delayed task for powerdown */
|
||||
unsigned long power_on_acct;
|
||||
unsigned long power_off_acct;
|
||||
unsigned long power_jiffies;
|
||||
spinlock_t power_lock;
|
||||
#endif
|
||||
|
||||
/* codec-specific additional proc output */
|
||||
|
@ -911,10 +911,13 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
|
|||
hda_nid_t *start_id);
|
||||
int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns);
|
||||
static inline int
|
||||
snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
return snd_hda_get_connections(codec, nid, NULL, 0);
|
||||
}
|
||||
int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns);
|
||||
int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
|
||||
const hda_nid_t **listp);
|
||||
int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
|
||||
const hda_nid_t *list);
|
||||
int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
|
||||
|
@ -1051,12 +1054,10 @@ const char *snd_hda_get_jack_location(u32 cfg);
|
|||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
void snd_hda_power_up(struct hda_codec *codec);
|
||||
void snd_hda_power_down(struct hda_codec *codec);
|
||||
#define snd_hda_codec_needs_resume(codec) codec->power_count
|
||||
void snd_hda_update_power_acct(struct hda_codec *codec);
|
||||
#else
|
||||
static inline void snd_hda_power_up(struct hda_codec *codec) {}
|
||||
static inline void snd_hda_power_down(struct hda_codec *codec) {}
|
||||
#define snd_hda_codec_needs_resume(codec) 1
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||
|
|
|
@ -497,6 +497,7 @@ enum {
|
|||
AZX_DRIVER_NVIDIA,
|
||||
AZX_DRIVER_TERA,
|
||||
AZX_DRIVER_CTX,
|
||||
AZX_DRIVER_CTHDA,
|
||||
AZX_DRIVER_GENERIC,
|
||||
AZX_NUM_DRIVERS, /* keep this as last entry */
|
||||
};
|
||||
|
@ -518,6 +519,7 @@ enum {
|
|||
#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
|
||||
#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */
|
||||
#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */
|
||||
#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
|
||||
|
||||
/* quirks for ATI SB / AMD Hudson */
|
||||
#define AZX_DCAPS_PRESET_ATI_SB \
|
||||
|
@ -533,6 +535,9 @@ enum {
|
|||
(AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
|
||||
AZX_DCAPS_ALIGN_BUFSIZE)
|
||||
|
||||
#define AZX_DCAPS_PRESET_CTHDA \
|
||||
(AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY)
|
||||
|
||||
static char *driver_short_names[] __devinitdata = {
|
||||
[AZX_DRIVER_ICH] = "HDA Intel",
|
||||
[AZX_DRIVER_PCH] = "HDA Intel PCH",
|
||||
|
@ -546,6 +551,7 @@ static char *driver_short_names[] __devinitdata = {
|
|||
[AZX_DRIVER_NVIDIA] = "HDA NVidia",
|
||||
[AZX_DRIVER_TERA] = "HDA Teradici",
|
||||
[AZX_DRIVER_CTX] = "HDA Creative",
|
||||
[AZX_DRIVER_CTHDA] = "HDA Creative",
|
||||
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
|
||||
};
|
||||
|
||||
|
@ -1285,7 +1291,8 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
|
|||
/*
|
||||
* set up a BDL entry
|
||||
*/
|
||||
static int setup_bdle(struct snd_pcm_substream *substream,
|
||||
static int setup_bdle(struct azx *chip,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct azx_dev *azx_dev, u32 **bdlp,
|
||||
int ofs, int size, int with_ioc)
|
||||
{
|
||||
|
@ -1304,6 +1311,12 @@ static int setup_bdle(struct snd_pcm_substream *substream,
|
|||
bdl[1] = cpu_to_le32(upper_32_bits(addr));
|
||||
/* program the size field of the BDL entry */
|
||||
chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
|
||||
/* one BDLE cannot cross 4K boundary on CTHDA chips */
|
||||
if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
|
||||
u32 remain = 0x1000 - (ofs & 0xfff);
|
||||
if (chunk > remain)
|
||||
chunk = remain;
|
||||
}
|
||||
bdl[2] = cpu_to_le32(chunk);
|
||||
/* program the IOC to enable interrupt
|
||||
* only when the whole fragment is processed
|
||||
|
@ -1356,7 +1369,7 @@ static int azx_setup_periods(struct azx *chip,
|
|||
bdl_pos_adj[chip->dev_index]);
|
||||
pos_adj = 0;
|
||||
} else {
|
||||
ofs = setup_bdle(substream, azx_dev,
|
||||
ofs = setup_bdle(chip, substream, azx_dev,
|
||||
&bdl, ofs, pos_adj,
|
||||
!substream->runtime->no_period_wakeup);
|
||||
if (ofs < 0)
|
||||
|
@ -1366,10 +1379,10 @@ static int azx_setup_periods(struct azx *chip,
|
|||
pos_adj = 0;
|
||||
for (i = 0; i < periods; i++) {
|
||||
if (i == periods - 1 && pos_adj)
|
||||
ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
|
||||
ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
|
||||
period_bytes - pos_adj, 0);
|
||||
else
|
||||
ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
|
||||
ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
|
||||
period_bytes,
|
||||
!substream->runtime->no_period_wakeup);
|
||||
if (ofs < 0)
|
||||
|
@ -2353,17 +2366,6 @@ static void azx_power_notify(struct hda_bus *bus)
|
|||
* power management
|
||||
*/
|
||||
|
||||
static int snd_hda_codecs_inuse(struct hda_bus *bus)
|
||||
{
|
||||
struct hda_codec *codec;
|
||||
|
||||
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||
if (snd_hda_codec_needs_resume(codec))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int azx_suspend(struct pci_dev *pci, pm_message_t state)
|
||||
{
|
||||
struct snd_card *card = pci_get_drvdata(pci);
|
||||
|
@ -2410,8 +2412,7 @@ static int azx_resume(struct pci_dev *pci)
|
|||
return -EIO;
|
||||
azx_init_pci(chip);
|
||||
|
||||
if (snd_hda_codecs_inuse(chip->bus))
|
||||
azx_init_chip(chip, 1);
|
||||
azx_init_chip(chip, 1);
|
||||
|
||||
snd_hda_resume(chip->bus);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
|
@ -3130,6 +3131,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
|
|||
.driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
|
||||
AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
|
||||
#endif
|
||||
/* CTHDA chips */
|
||||
{ PCI_DEVICE(0x1102, 0x0010),
|
||||
.driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
|
||||
{ PCI_DEVICE(0x1102, 0x0012),
|
||||
.driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
|
||||
/* Vortex86MX */
|
||||
{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
|
||||
/* VMware HDAudio */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <sound/jack.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
||||
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#ifndef __SOUND_HDA_JACK_H
|
||||
#define __SOUND_HDA_JACK_H
|
||||
|
||||
struct auto_pin_cfg;
|
||||
|
||||
struct hda_jack_tbl {
|
||||
hda_nid_t nid;
|
||||
unsigned char action; /* event action (0 = none) */
|
||||
|
|
|
@ -262,6 +262,8 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
|
|||
const struct hda_input_mux *imux,
|
||||
struct snd_ctl_elem_value *ucontrol, hda_nid_t nid,
|
||||
unsigned int *cur_val);
|
||||
int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
|
||||
int index, int *type_index_ret);
|
||||
|
||||
/*
|
||||
* Channel mode helper
|
||||
|
@ -393,72 +395,7 @@ struct hda_bus_unsolicited {
|
|||
struct hda_bus *bus;
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper for automatic pin configuration
|
||||
*/
|
||||
|
||||
enum {
|
||||
AUTO_PIN_MIC,
|
||||
AUTO_PIN_LINE_IN,
|
||||
AUTO_PIN_CD,
|
||||
AUTO_PIN_AUX,
|
||||
AUTO_PIN_LAST
|
||||
};
|
||||
|
||||
enum {
|
||||
AUTO_PIN_LINE_OUT,
|
||||
AUTO_PIN_SPEAKER_OUT,
|
||||
AUTO_PIN_HP_OUT
|
||||
};
|
||||
|
||||
#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS
|
||||
#define AUTO_CFG_MAX_INS 8
|
||||
|
||||
struct auto_pin_cfg_item {
|
||||
hda_nid_t pin;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct auto_pin_cfg;
|
||||
const char *hda_get_autocfg_input_label(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
int input);
|
||||
int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
|
||||
const struct auto_pin_cfg *cfg,
|
||||
char *label, int maxlen, int *indexp);
|
||||
int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
|
||||
int index, int *type_index_ret);
|
||||
|
||||
enum {
|
||||
INPUT_PIN_ATTR_UNUSED, /* pin not connected */
|
||||
INPUT_PIN_ATTR_INT, /* internal mic/line-in */
|
||||
INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
|
||||
INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
|
||||
INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
|
||||
INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
|
||||
};
|
||||
|
||||
int snd_hda_get_input_pin_attr(unsigned int def_conf);
|
||||
|
||||
struct auto_pin_cfg {
|
||||
int line_outs;
|
||||
/* sorted in the order of Front/Surr/CLFE/Side */
|
||||
hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS];
|
||||
int speaker_outs;
|
||||
hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS];
|
||||
int hp_outs;
|
||||
int line_out_type; /* AUTO_PIN_XXX_OUT */
|
||||
hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
|
||||
int num_inputs;
|
||||
struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
|
||||
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 */
|
||||
};
|
||||
|
||||
/* helper macros to retrieve pin default-config values */
|
||||
#define get_defcfg_connect(cfg) \
|
||||
((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
|
||||
#define get_defcfg_association(cfg) \
|
||||
|
@ -472,19 +409,6 @@ struct auto_pin_cfg {
|
|||
#define get_defcfg_misc(cfg) \
|
||||
((cfg & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT)
|
||||
|
||||
/* bit-flags for snd_hda_parse_pin_def_config() behavior */
|
||||
#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */
|
||||
#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */
|
||||
|
||||
int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
|
||||
struct auto_pin_cfg *cfg,
|
||||
const hda_nid_t *ignore_nids,
|
||||
unsigned int cond_flags);
|
||||
|
||||
/* older function */
|
||||
#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
|
||||
snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
|
||||
|
||||
/* amp values */
|
||||
#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8))
|
||||
#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8))
|
||||
|
@ -502,6 +426,46 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
|
|||
#define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
|
||||
#define PIN_HP_AMP (AC_PINCTL_HP_EN)
|
||||
|
||||
unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin);
|
||||
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
|
||||
unsigned int val, bool cached);
|
||||
|
||||
/**
|
||||
* _snd_hda_set_pin_ctl - Set a pin-control value safely
|
||||
* @codec: the codec instance
|
||||
* @pin: the pin NID to set the control
|
||||
* @val: the pin-control value (AC_PINCTL_* bits)
|
||||
*
|
||||
* This function sets the pin-control value to the given pin, but
|
||||
* filters out the invalid pin-control bits when the pin has no such
|
||||
* capabilities. For example, when PIN_HP is passed but the pin has no
|
||||
* HP-drive capability, the HP bit is omitted.
|
||||
*
|
||||
* The function doesn't check the input VREF capability bits, though.
|
||||
* Use snd_hda_get_default_vref() to guess the right value.
|
||||
* Also, this function is only for analog pins, not for HDMI pins.
|
||||
*/
|
||||
static inline int
|
||||
snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, unsigned int val)
|
||||
{
|
||||
return _snd_hda_set_pin_ctl(codec, pin, val, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_set_pin_ctl_cache - Set a pin-control value safely
|
||||
* @codec: the codec instance
|
||||
* @pin: the pin NID to set the control
|
||||
* @val: the pin-control value (AC_PINCTL_* bits)
|
||||
*
|
||||
* Just like snd_hda_set_pin_ctl() but write to cache as well.
|
||||
*/
|
||||
static inline int
|
||||
snd_hda_set_pin_ctl_cache(struct hda_codec *codec, hda_nid_t pin,
|
||||
unsigned int val)
|
||||
{
|
||||
return _snd_hda_set_pin_ctl(codec, pin, val, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* get widget capabilities
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_beep.h"
|
||||
#include "hda_jack.h"
|
||||
|
||||
|
@ -1742,9 +1743,7 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
|
|||
if (! ad198x_eapd_put(kcontrol, ucontrol))
|
||||
return 0;
|
||||
/* change speaker pin appropriately */
|
||||
snd_hda_codec_write(codec, 0x05, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
spec->cur_eapd ? PIN_OUT : 0);
|
||||
snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0);
|
||||
/* toggle HP mute appropriately */
|
||||
snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE,
|
||||
|
@ -3103,7 +3102,7 @@ static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
|
|||
int dac_idx)
|
||||
{
|
||||
/* set as output */
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
|
||||
snd_hda_set_pin_ctl(codec, nid, pin_type);
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
|
||||
switch (nid) {
|
||||
case 0x11: /* port-A - DAC 03 */
|
||||
|
@ -3157,6 +3156,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
|
|||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
int type = cfg->inputs[i].type;
|
||||
int val;
|
||||
switch (nid) {
|
||||
case 0x15: /* port-C */
|
||||
snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
|
||||
|
@ -3165,8 +3165,10 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
|
|||
snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
|
||||
break;
|
||||
}
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
|
||||
val = PIN_IN;
|
||||
if (type == AUTO_PIN_MIC)
|
||||
val |= snd_hda_get_default_vref(codec, nid);
|
||||
snd_hda_set_pin_ctl(codec, nid, val);
|
||||
if (nid != AD1988_PIN_CD_NID)
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AMP_OUT_MUTE);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
|
||||
/*
|
||||
*/
|
||||
|
@ -341,8 +342,7 @@ static int ca0110_build_pcms(struct hda_codec *codec)
|
|||
static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
|
||||
{
|
||||
if (pin) {
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
|
||||
snd_hda_set_pin_ctl(codec, pin, PIN_HP);
|
||||
if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
|
@ -356,8 +356,8 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
|
|||
static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
|
||||
{
|
||||
if (pin) {
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80);
|
||||
snd_hda_set_pin_ctl(codec, pin, PIN_IN |
|
||||
snd_hda_get_default_vref(codec, pin));
|
||||
if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
|
||||
#define WIDGET_CHIP_CTRL 0x15
|
||||
#define WIDGET_DSP_CTRL 0x16
|
||||
|
@ -239,8 +240,7 @@ enum get_set {
|
|||
static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
|
||||
{
|
||||
if (pin) {
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
|
||||
snd_hda_set_pin_ctl(codec, pin, PIN_HP);
|
||||
if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
|
@ -254,9 +254,8 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
|
|||
static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
|
||||
{
|
||||
if (pin) {
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
PIN_VREF80);
|
||||
snd_hda_set_pin_ctl(codec, pin, PIN_IN |
|
||||
snd_hda_get_default_vref(codec, pin));
|
||||
if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
#include <sound/tlv.h>
|
||||
|
||||
|
@ -933,8 +934,7 @@ static void cs_automute(struct hda_codec *codec)
|
|||
pin_ctl = 0;
|
||||
|
||||
nid = cfg->speaker_pins[i];
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl);
|
||||
snd_hda_set_pin_ctl(codec, nid, pin_ctl);
|
||||
}
|
||||
if (spec->gpio_eapd_hp) {
|
||||
unsigned int gpio = hp_present ?
|
||||
|
@ -948,16 +948,14 @@ static void cs_automute(struct hda_codec *codec)
|
|||
/* mute HPs if spdif jack (SENSE_B) is present */
|
||||
for (i = 0; i < cfg->hp_outs; i++) {
|
||||
nid = cfg->hp_pins[i];
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
snd_hda_set_pin_ctl(codec, nid,
|
||||
(spdif_present && spec->sense_b) ? 0 : PIN_HP);
|
||||
}
|
||||
|
||||
/* SPDIF TX on/off */
|
||||
if (cfg->dig_outs) {
|
||||
nid = cfg->dig_out_pins[0];
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
snd_hda_set_pin_ctl(codec, nid,
|
||||
spdif_present ? PIN_OUT : 0);
|
||||
|
||||
}
|
||||
|
@ -1024,13 +1022,11 @@ static void init_output(struct hda_codec *codec)
|
|||
|
||||
/* set appropriate pin controls */
|
||||
for (i = 0; i < cfg->line_outs; i++)
|
||||
snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
snd_hda_set_pin_ctl(codec, cfg->line_out_pins[i], PIN_OUT);
|
||||
/* HP */
|
||||
for (i = 0; i < cfg->hp_outs; i++) {
|
||||
hda_nid_t nid = cfg->hp_pins[i];
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
|
||||
snd_hda_set_pin_ctl(codec, nid, PIN_HP);
|
||||
if (!cfg->speaker_outs)
|
||||
continue;
|
||||
if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
|
||||
|
@ -1041,8 +1037,7 @@ static void init_output(struct hda_codec *codec)
|
|||
|
||||
/* Speaker */
|
||||
for (i = 0; i < cfg->speaker_outs; i++)
|
||||
snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
snd_hda_set_pin_ctl(codec, cfg->speaker_pins[i], PIN_OUT);
|
||||
|
||||
/* SPDIF is enabled on presence detect for CS421x */
|
||||
if (spec->hp_detect || spec->spdif_detect)
|
||||
|
@ -1063,14 +1058,9 @@ static void init_input(struct hda_codec *codec)
|
|||
continue;
|
||||
/* set appropriate pin control and mute first */
|
||||
ctl = PIN_IN;
|
||||
if (cfg->inputs[i].type == AUTO_PIN_MIC) {
|
||||
unsigned int caps = snd_hda_query_pin_caps(codec, pin);
|
||||
caps >>= AC_PINCAP_VREF_SHIFT;
|
||||
if (caps & AC_PINCAP_VREF_80)
|
||||
ctl = PIN_VREF80;
|
||||
}
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
|
||||
if (cfg->inputs[i].type == AUTO_PIN_MIC)
|
||||
ctl |= snd_hda_get_default_vref(codec, pin);
|
||||
snd_hda_set_pin_ctl(codec, pin, ctl);
|
||||
snd_hda_codec_write(codec, spec->adc_nid[i], 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AMP_IN_MUTE(spec->adc_idx[i]));
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#define NUM_PINS 11
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_beep.h"
|
||||
#include "hda_jack.h"
|
||||
|
||||
|
@ -66,6 +67,7 @@ struct imux_info {
|
|||
};
|
||||
|
||||
struct conexant_spec {
|
||||
struct hda_gen_spec gen;
|
||||
|
||||
const struct snd_kcontrol_new *mixers[5];
|
||||
int num_mixers;
|
||||
|
@ -141,6 +143,7 @@ struct conexant_spec {
|
|||
unsigned int hp_laptop:1;
|
||||
unsigned int asus:1;
|
||||
unsigned int pin_eapd_ctrls:1;
|
||||
unsigned int fixup_stereo_dmic:1;
|
||||
|
||||
unsigned int adc_switching:1;
|
||||
|
||||
|
@ -1601,17 +1604,13 @@ static void cxt5051_update_speaker(struct hda_codec *codec)
|
|||
unsigned int pinctl;
|
||||
/* headphone pin */
|
||||
pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0;
|
||||
snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
snd_hda_set_pin_ctl(codec, 0x16, pinctl);
|
||||
/* speaker pin */
|
||||
pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
|
||||
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
snd_hda_set_pin_ctl(codec, 0x1a, pinctl);
|
||||
/* on ideapad there is an additional speaker (subwoofer) to mute */
|
||||
if (spec->ideapad)
|
||||
snd_hda_codec_write(codec, 0x1b, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
snd_hda_set_pin_ctl(codec, 0x1b, pinctl);
|
||||
}
|
||||
|
||||
/* turn on/off EAPD (+ mute HP) as a master switch */
|
||||
|
@ -1996,8 +1995,7 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
|
|||
|
||||
/* Port A (HP) */
|
||||
pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0;
|
||||
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
snd_hda_set_pin_ctl(codec, 0x19, pinctl);
|
||||
|
||||
/* Port D (HP/LO) */
|
||||
pinctl = spec->cur_eapd ? spec->port_d_mode : 0;
|
||||
|
@ -2010,13 +2008,11 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
|
|||
if (!hp_port_d_present(spec))
|
||||
pinctl = 0;
|
||||
}
|
||||
snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
snd_hda_set_pin_ctl(codec, 0x1c, pinctl);
|
||||
|
||||
/* CLASS_D AMP */
|
||||
pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
|
||||
snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinctl);
|
||||
snd_hda_set_pin_ctl(codec, 0x1f, pinctl);
|
||||
}
|
||||
|
||||
/* turn on/off EAPD (+ mute HP) as a master switch */
|
||||
|
@ -2047,8 +2043,7 @@ static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
|
|||
/* Even though port F is the DC input, the bias is controlled on port B.
|
||||
* we also leave that port as an active input (but unselected) in DC mode
|
||||
* just in case that is necessary to make the bias setting take effect. */
|
||||
return snd_hda_codec_write_cache(codec, 0x1a, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
return snd_hda_set_pin_ctl_cache(codec, 0x1a,
|
||||
cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
|
||||
}
|
||||
|
||||
|
@ -2081,14 +2076,14 @@ static void cxt5066_olpc_select_mic(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
/* disable DC (port F) */
|
||||
snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
|
||||
snd_hda_set_pin_ctl(codec, 0x1e, 0);
|
||||
|
||||
/* external mic, port B */
|
||||
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
snd_hda_set_pin_ctl(codec, 0x1a,
|
||||
spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
|
||||
|
||||
/* internal mic, port C */
|
||||
snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
snd_hda_set_pin_ctl(codec, 0x1b,
|
||||
spec->ext_mic_present ? 0 : PIN_VREF80);
|
||||
}
|
||||
|
||||
|
@ -3357,9 +3352,7 @@ static void do_automute(struct hda_codec *codec, int num_pins,
|
|||
struct conexant_spec *spec = codec->spec;
|
||||
int i;
|
||||
for (i = 0; i < num_pins; i++)
|
||||
snd_hda_codec_write(codec, pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
on ? PIN_OUT : 0);
|
||||
snd_hda_set_pin_ctl(codec, pins[i], on ? PIN_OUT : 0);
|
||||
if (spec->pin_eapd_ctrls)
|
||||
cx_auto_turn_eapd(codec, num_pins, pins, on);
|
||||
}
|
||||
|
@ -3976,8 +3969,7 @@ static void cx_auto_init_output(struct hda_codec *codec)
|
|||
if (snd_hda_query_pin_caps(codec, cfg->hp_pins[i]) &
|
||||
AC_PINCAP_HP_DRV)
|
||||
val |= AC_PINCTL_HP_EN;
|
||||
snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, val);
|
||||
snd_hda_set_pin_ctl(codec, cfg->hp_pins[i], val);
|
||||
}
|
||||
mute_outputs(codec, cfg->hp_outs, cfg->hp_pins);
|
||||
mute_outputs(codec, cfg->line_outs, cfg->line_out_pins);
|
||||
|
@ -4030,13 +4022,11 @@ static void cx_auto_init_input(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
unsigned int type;
|
||||
hda_nid_t pin = cfg->inputs[i].pin;
|
||||
unsigned int type = PIN_IN;
|
||||
if (cfg->inputs[i].type == AUTO_PIN_MIC)
|
||||
type = PIN_VREF80;
|
||||
else
|
||||
type = PIN_IN;
|
||||
snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, type);
|
||||
type |= snd_hda_get_default_vref(codec, pin);
|
||||
snd_hda_set_pin_ctl(codec, pin, type);
|
||||
}
|
||||
|
||||
if (spec->auto_mic) {
|
||||
|
@ -4063,11 +4053,9 @@ static void cx_auto_init_digital(struct hda_codec *codec)
|
|||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
|
||||
if (spec->multiout.dig_out_nid)
|
||||
snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
snd_hda_set_pin_ctl(codec, cfg->dig_out_pins[0], PIN_OUT);
|
||||
if (spec->dig_in_nid)
|
||||
snd_hda_codec_write(codec, cfg->dig_in_pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
|
||||
snd_hda_set_pin_ctl(codec, cfg->dig_in_pin, PIN_IN);
|
||||
}
|
||||
|
||||
static int cx_auto_init(struct hda_codec *codec)
|
||||
|
@ -4084,9 +4072,9 @@ static int cx_auto_init(struct hda_codec *codec)
|
|||
|
||||
static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
|
||||
const char *dir, int cidx,
|
||||
hda_nid_t nid, int hda_dir, int amp_idx)
|
||||
hda_nid_t nid, int hda_dir, int amp_idx, int chs)
|
||||
{
|
||||
static char name[32];
|
||||
static char name[44];
|
||||
static struct snd_kcontrol_new knew[] = {
|
||||
HDA_CODEC_VOLUME(name, 0, 0, 0),
|
||||
HDA_CODEC_MUTE(name, 0, 0, 0),
|
||||
|
@ -4096,7 +4084,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
|
|||
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct snd_kcontrol *kctl;
|
||||
knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
|
||||
knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx,
|
||||
hda_dir);
|
||||
knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
|
||||
knew[i].index = cidx;
|
||||
|
@ -4115,7 +4103,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
|
|||
}
|
||||
|
||||
#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \
|
||||
cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
|
||||
cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3)
|
||||
|
||||
#define cx_auto_add_pb_volume(codec, nid, str, idx) \
|
||||
cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
|
||||
|
@ -4185,6 +4173,36 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Returns zero if this is a normal stereo channel, and non-zero if it should
|
||||
be split in two independent channels.
|
||||
dest_label must be at least 44 characters. */
|
||||
static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label,
|
||||
char *dest_label, int nid)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
int i;
|
||||
|
||||
if (!spec->fixup_stereo_dmic)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < AUTO_CFG_MAX_INS; i++) {
|
||||
int def_conf;
|
||||
if (spec->autocfg.inputs[i].pin != nid)
|
||||
continue;
|
||||
|
||||
if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC)
|
||||
return 0;
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT)
|
||||
return 0;
|
||||
|
||||
/* Finally found the inverted internal mic! */
|
||||
snprintf(dest_label, 44, "Inverted %s", label);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
|
||||
const char *label, const char *pfx,
|
||||
int cidx)
|
||||
|
@ -4193,14 +4211,25 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
|
|||
int i;
|
||||
|
||||
for (i = 0; i < spec->num_adc_nids; i++) {
|
||||
char rightch_label[44];
|
||||
hda_nid_t adc_nid = spec->adc_nids[i];
|
||||
int idx = get_input_connection(codec, adc_nid, nid);
|
||||
if (idx < 0)
|
||||
continue;
|
||||
if (codec->single_adc_amp)
|
||||
idx = 0;
|
||||
|
||||
if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
|
||||
/* Make two independent kcontrols for left and right */
|
||||
int err = cx_auto_add_volume_idx(codec, label, pfx,
|
||||
cidx, adc_nid, HDA_INPUT, idx, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return cx_auto_add_volume_idx(codec, rightch_label, pfx,
|
||||
cidx, adc_nid, HDA_INPUT, idx, 2);
|
||||
}
|
||||
return cx_auto_add_volume_idx(codec, label, pfx,
|
||||
cidx, adc_nid, HDA_INPUT, idx);
|
||||
cidx, adc_nid, HDA_INPUT, idx, 3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -4213,9 +4242,19 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
|
|||
int i, con;
|
||||
|
||||
nid = spec->imux_info[idx].pin;
|
||||
if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
|
||||
if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
|
||||
char rightch_label[44];
|
||||
if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
|
||||
int err = cx_auto_add_volume_idx(codec, label, " Boost",
|
||||
cidx, nid, HDA_INPUT, 0, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return cx_auto_add_volume_idx(codec, rightch_label, " Boost",
|
||||
cidx, nid, HDA_INPUT, 0, 2);
|
||||
}
|
||||
return cx_auto_add_volume(codec, label, " Boost", cidx,
|
||||
nid, HDA_INPUT);
|
||||
}
|
||||
con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
|
||||
&mux, false, 0);
|
||||
if (con < 0)
|
||||
|
@ -4370,37 +4409,21 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
|
|||
/*
|
||||
* pin fix-up
|
||||
*/
|
||||
struct cxt_pincfg {
|
||||
hda_nid_t nid;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg)
|
||||
{
|
||||
for (; cfg->nid; cfg++)
|
||||
snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
|
||||
|
||||
}
|
||||
|
||||
static void apply_pin_fixup(struct hda_codec *codec,
|
||||
const struct snd_pci_quirk *quirk,
|
||||
const struct cxt_pincfg **table)
|
||||
{
|
||||
quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
|
||||
if (quirk) {
|
||||
snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n",
|
||||
quirk->name);
|
||||
apply_pincfg(codec, table[quirk->value]);
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
CXT_PINCFG_LENOVO_X200,
|
||||
CXT_PINCFG_LENOVO_TP410,
|
||||
CXT_FIXUP_STEREO_DMIC,
|
||||
};
|
||||
|
||||
static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
spec->fixup_stereo_dmic = 1;
|
||||
}
|
||||
|
||||
/* ThinkPad X200 & co with cxt5051 */
|
||||
static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
|
||||
static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
|
||||
{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
|
||||
{ 0x17, 0x21a11000 }, /* dock-mic */
|
||||
{ 0x19, 0x2121103f }, /* dock-HP */
|
||||
|
@ -4409,16 +4432,26 @@ static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
|
|||
};
|
||||
|
||||
/* ThinkPad 410/420/510/520, X201 & co with cxt5066 */
|
||||
static const struct cxt_pincfg cxt_pincfg_lenovo_tp410[] = {
|
||||
static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = {
|
||||
{ 0x19, 0x042110ff }, /* HP (seq# overridden) */
|
||||
{ 0x1a, 0x21a190f0 }, /* dock-mic */
|
||||
{ 0x1c, 0x212140ff }, /* dock-HP */
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct cxt_pincfg *cxt_pincfg_tbl[] = {
|
||||
[CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
|
||||
[CXT_PINCFG_LENOVO_TP410] = cxt_pincfg_lenovo_tp410,
|
||||
static const struct hda_fixup cxt_fixups[] = {
|
||||
[CXT_PINCFG_LENOVO_X200] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = cxt_pincfg_lenovo_x200,
|
||||
},
|
||||
[CXT_PINCFG_LENOVO_TP410] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = cxt_pincfg_lenovo_tp410,
|
||||
},
|
||||
[CXT_FIXUP_STEREO_DMIC] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = cxt_fixup_stereo_dmic,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk cxt5051_fixups[] = {
|
||||
|
@ -4432,6 +4465,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
|
|||
SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -4471,13 +4505,16 @@ static int patch_conexant_auto(struct hda_codec *codec)
|
|||
case 0x14f15051:
|
||||
add_cx5051_fake_mutes(codec);
|
||||
codec->pin_amp_workaround = 1;
|
||||
apply_pin_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
|
||||
snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups);
|
||||
break;
|
||||
default:
|
||||
codec->pin_amp_workaround = 1;
|
||||
apply_pin_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
|
||||
snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups);
|
||||
break;
|
||||
}
|
||||
|
||||
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
|
||||
|
||||
/* Show mute-led control only on HP laptops
|
||||
* This is a sort of white-list: on HP laptops, EAPD corresponds
|
||||
* only to the mute-LED without actualy amp function. Meanwhile,
|
||||
|
@ -4556,6 +4593,12 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = {
|
|||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f150b9, .name = "CX20665",
|
||||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f1510f, .name = "CX20751/2",
|
||||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f15110, .name = "CX20751/2",
|
||||
.patch = patch_conexant_auto },
|
||||
{ .id = 0x14f15111, .name = "CX20753/4",
|
||||
.patch = patch_conexant_auto },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
|
@ -4576,6 +4619,9 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab");
|
|||
MODULE_ALIAS("snd-hda-codec-id:14f150ac");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f150b8");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f150b9");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f1510f");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f15110");
|
||||
MODULE_ALIAS("snd-hda-codec-id:14f15111");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Conexant HD-audio codec");
|
||||
|
|
|
@ -1592,10 +1592,10 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|||
unsigned int dataDCC2, channel_id;
|
||||
int i;
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
struct hda_spdif_out *spdif =
|
||||
snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
|
||||
struct hda_spdif_out *spdif;
|
||||
|
||||
mutex_lock(&codec->spdif_mutex);
|
||||
spdif = snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
|
||||
|
||||
chs = substream->runtime->channels;
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <sound/jack.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_beep.h"
|
||||
#include "hda_jack.h"
|
||||
|
||||
|
@ -66,8 +67,6 @@ struct alc_customize_define {
|
|||
unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
|
||||
};
|
||||
|
||||
struct alc_fixup;
|
||||
|
||||
struct alc_multi_io {
|
||||
hda_nid_t pin; /* multi-io widget pin NID */
|
||||
hda_nid_t dac; /* DAC to be connected */
|
||||
|
@ -82,19 +81,33 @@ enum {
|
|||
|
||||
#define MAX_VOL_NIDS 0x40
|
||||
|
||||
/* make compatible with old code */
|
||||
#define alc_apply_pincfgs snd_hda_apply_pincfgs
|
||||
#define alc_apply_fixup snd_hda_apply_fixup
|
||||
#define alc_pick_fixup snd_hda_pick_fixup
|
||||
#define alc_fixup hda_fixup
|
||||
#define alc_pincfg hda_pintbl
|
||||
#define alc_model_fixup hda_model_fixup
|
||||
|
||||
#define ALC_FIXUP_PINS HDA_FIXUP_PINS
|
||||
#define ALC_FIXUP_VERBS HDA_FIXUP_VERBS
|
||||
#define ALC_FIXUP_FUNC HDA_FIXUP_FUNC
|
||||
|
||||
#define ALC_FIXUP_ACT_PRE_PROBE HDA_FIXUP_ACT_PRE_PROBE
|
||||
#define ALC_FIXUP_ACT_PROBE HDA_FIXUP_ACT_PROBE
|
||||
#define ALC_FIXUP_ACT_INIT HDA_FIXUP_ACT_INIT
|
||||
#define ALC_FIXUP_ACT_BUILD HDA_FIXUP_ACT_BUILD
|
||||
|
||||
|
||||
struct alc_spec {
|
||||
struct hda_gen_spec gen;
|
||||
|
||||
/* codec parameterization */
|
||||
const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
|
||||
unsigned int num_mixers;
|
||||
const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
|
||||
unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
|
||||
|
||||
const struct hda_verb *init_verbs[10]; /* initialization verbs
|
||||
* don't forget NULL
|
||||
* termination!
|
||||
*/
|
||||
unsigned int num_init_verbs;
|
||||
|
||||
char stream_name_analog[32]; /* analog PCM stream */
|
||||
const struct hda_pcm_stream *stream_analog_playback;
|
||||
const struct hda_pcm_stream *stream_analog_capture;
|
||||
|
@ -210,11 +223,6 @@ struct alc_spec {
|
|||
unsigned int pll_coef_idx, pll_coef_bit;
|
||||
unsigned int coef0;
|
||||
|
||||
/* fix-up list */
|
||||
int fixup_id;
|
||||
const struct alc_fixup *fixup_list;
|
||||
const char *fixup_name;
|
||||
|
||||
/* multi-io */
|
||||
int multi_ios;
|
||||
struct alc_multi_io multi_io[4];
|
||||
|
@ -319,13 +327,16 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
|
|||
|
||||
/* for shared I/O, change the pin-control accordingly */
|
||||
if (spec->shared_mic_hp) {
|
||||
unsigned int val;
|
||||
hda_nid_t pin = spec->autocfg.inputs[1].pin;
|
||||
/* NOTE: this assumes that there are only two inputs, the
|
||||
* first is the real internal mic and the second is HP jack.
|
||||
*/
|
||||
snd_hda_codec_write(codec, spec->autocfg.inputs[1].pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
spec->cur_mux[adc_idx] ?
|
||||
PIN_VREF80 : PIN_HP);
|
||||
if (spec->cur_mux[adc_idx])
|
||||
val = snd_hda_get_default_vref(codec, pin) | PIN_IN;
|
||||
else
|
||||
val = PIN_HP;
|
||||
snd_hda_set_pin_ctl(codec, pin, val);
|
||||
spec->automute_speaker = !spec->cur_mux[adc_idx];
|
||||
call_update_outputs(codec);
|
||||
}
|
||||
|
@ -338,7 +349,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
|
|||
nid = get_capsrc(spec, adc_idx);
|
||||
|
||||
/* no selection? */
|
||||
num_conns = snd_hda_get_conn_list(codec, nid, NULL);
|
||||
num_conns = snd_hda_get_num_conns(codec, nid);
|
||||
if (num_conns <= 1)
|
||||
return 1;
|
||||
|
||||
|
@ -376,25 +387,9 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
|
|||
int auto_pin_type)
|
||||
{
|
||||
unsigned int val = PIN_IN;
|
||||
|
||||
if (auto_pin_type == AUTO_PIN_MIC) {
|
||||
unsigned int pincap;
|
||||
unsigned int oldval;
|
||||
oldval = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
pincap = snd_hda_query_pin_caps(codec, nid);
|
||||
pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
|
||||
/* if the default pin setup is vref50, we give it priority */
|
||||
if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
|
||||
val = PIN_VREF80;
|
||||
else if (pincap & AC_PINCAP_VREF_50)
|
||||
val = PIN_VREF50;
|
||||
else if (pincap & AC_PINCAP_VREF_100)
|
||||
val = PIN_VREF100;
|
||||
else if (pincap & AC_PINCAP_VREF_GRD)
|
||||
val = PIN_VREFGRD;
|
||||
}
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
|
||||
if (auto_pin_type == AUTO_PIN_MIC)
|
||||
val |= snd_hda_get_default_vref(codec, nid);
|
||||
snd_hda_set_pin_ctl(codec, nid, val);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -409,13 +404,6 @@ static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
|
|||
spec->mixers[spec->num_mixers++] = mix;
|
||||
}
|
||||
|
||||
static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
|
||||
{
|
||||
if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
|
||||
return;
|
||||
spec->init_verbs[spec->num_init_verbs++] = verb;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPIO setup tables, used in initialization
|
||||
*/
|
||||
|
@ -517,9 +505,7 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
|
|||
} else
|
||||
val = 0;
|
||||
val |= pin_bits;
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
val);
|
||||
snd_hda_set_pin_ctl(codec, nid, val);
|
||||
break;
|
||||
case ALC_AUTOMUTE_AMP:
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
||||
|
@ -1200,6 +1186,16 @@ static void alc_auto_check_switches(struct hda_codec *codec)
|
|||
*/
|
||||
#define ALC_FIXUP_SKU_IGNORE (2)
|
||||
|
||||
static void alc_fixup_sku_ignore(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
|
||||
spec->cdefine.fixup = 1;
|
||||
spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
|
||||
}
|
||||
}
|
||||
|
||||
static int alc_auto_parse_customize_define(struct hda_codec *codec)
|
||||
{
|
||||
unsigned int ass, tmp, i;
|
||||
|
@ -1402,178 +1398,6 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix-up pin default configurations and add default verbs
|
||||
*/
|
||||
|
||||
struct alc_pincfg {
|
||||
hda_nid_t nid;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
struct alc_model_fixup {
|
||||
const int id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct alc_fixup {
|
||||
int type;
|
||||
bool chained;
|
||||
int chain_id;
|
||||
union {
|
||||
unsigned int sku;
|
||||
const struct alc_pincfg *pins;
|
||||
const struct hda_verb *verbs;
|
||||
void (*func)(struct hda_codec *codec,
|
||||
const struct alc_fixup *fix,
|
||||
int action);
|
||||
} v;
|
||||
};
|
||||
|
||||
enum {
|
||||
ALC_FIXUP_INVALID,
|
||||
ALC_FIXUP_SKU,
|
||||
ALC_FIXUP_PINS,
|
||||
ALC_FIXUP_VERBS,
|
||||
ALC_FIXUP_FUNC,
|
||||
};
|
||||
|
||||
enum {
|
||||
ALC_FIXUP_ACT_PRE_PROBE,
|
||||
ALC_FIXUP_ACT_PROBE,
|
||||
ALC_FIXUP_ACT_INIT,
|
||||
ALC_FIXUP_ACT_BUILD,
|
||||
};
|
||||
|
||||
static void alc_apply_pincfgs(struct hda_codec *codec,
|
||||
const struct alc_pincfg *cfg)
|
||||
{
|
||||
for (; cfg->nid; cfg++)
|
||||
snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
|
||||
}
|
||||
|
||||
static void alc_apply_fixup(struct hda_codec *codec, int action)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
int id = spec->fixup_id;
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
const char *modelname = spec->fixup_name;
|
||||
#endif
|
||||
int depth = 0;
|
||||
|
||||
if (!spec->fixup_list)
|
||||
return;
|
||||
|
||||
while (id >= 0) {
|
||||
const struct alc_fixup *fix = spec->fixup_list + id;
|
||||
const struct alc_pincfg *cfg;
|
||||
|
||||
switch (fix->type) {
|
||||
case ALC_FIXUP_SKU:
|
||||
if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
|
||||
break;
|
||||
snd_printdd(KERN_INFO "hda_codec: %s: "
|
||||
"Apply sku override for %s\n",
|
||||
codec->chip_name, modelname);
|
||||
spec->cdefine.sku_cfg = fix->v.sku;
|
||||
spec->cdefine.fixup = 1;
|
||||
break;
|
||||
case ALC_FIXUP_PINS:
|
||||
cfg = fix->v.pins;
|
||||
if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
|
||||
break;
|
||||
snd_printdd(KERN_INFO "hda_codec: %s: "
|
||||
"Apply pincfg for %s\n",
|
||||
codec->chip_name, modelname);
|
||||
alc_apply_pincfgs(codec, cfg);
|
||||
break;
|
||||
case ALC_FIXUP_VERBS:
|
||||
if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
|
||||
break;
|
||||
snd_printdd(KERN_INFO "hda_codec: %s: "
|
||||
"Apply fix-verbs for %s\n",
|
||||
codec->chip_name, modelname);
|
||||
add_verb(codec->spec, fix->v.verbs);
|
||||
break;
|
||||
case ALC_FIXUP_FUNC:
|
||||
if (!fix->v.func)
|
||||
break;
|
||||
snd_printdd(KERN_INFO "hda_codec: %s: "
|
||||
"Apply fix-func for %s\n",
|
||||
codec->chip_name, modelname);
|
||||
fix->v.func(codec, fix, action);
|
||||
break;
|
||||
default:
|
||||
snd_printk(KERN_ERR "hda_codec: %s: "
|
||||
"Invalid fixup type %d\n",
|
||||
codec->chip_name, fix->type);
|
||||
break;
|
||||
}
|
||||
if (!fix->chained)
|
||||
break;
|
||||
if (++depth > 10)
|
||||
break;
|
||||
id = fix->chain_id;
|
||||
}
|
||||
}
|
||||
|
||||
static void alc_pick_fixup(struct hda_codec *codec,
|
||||
const struct alc_model_fixup *models,
|
||||
const struct snd_pci_quirk *quirk,
|
||||
const struct alc_fixup *fixlist)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
const struct snd_pci_quirk *q;
|
||||
int id = -1;
|
||||
const char *name = NULL;
|
||||
|
||||
/* when model=nofixup is given, don't pick up any fixups */
|
||||
if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
|
||||
spec->fixup_list = NULL;
|
||||
spec->fixup_id = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (codec->modelname && models) {
|
||||
while (models->name) {
|
||||
if (!strcmp(codec->modelname, models->name)) {
|
||||
id = models->id;
|
||||
name = models->name;
|
||||
break;
|
||||
}
|
||||
models++;
|
||||
}
|
||||
}
|
||||
if (id < 0) {
|
||||
q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
|
||||
if (q) {
|
||||
id = q->value;
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
name = q->name;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (id < 0) {
|
||||
for (q = quirk; q->subvendor; q++) {
|
||||
unsigned int vendorid =
|
||||
q->subdevice | (q->subvendor << 16);
|
||||
if (vendorid == codec->subsystem_id) {
|
||||
id = q->value;
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
name = q->name;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spec->fixup_id = id;
|
||||
if (id >= 0) {
|
||||
spec->fixup_list = fixlist;
|
||||
spec->fixup_name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* COEF access helper functions
|
||||
*/
|
||||
|
@ -1621,8 +1445,7 @@ static void alc_auto_init_digital(struct hda_codec *codec)
|
|||
pin = spec->autocfg.dig_out_pins[i];
|
||||
if (!pin)
|
||||
continue;
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
snd_hda_set_pin_ctl(codec, pin, PIN_OUT);
|
||||
if (!i)
|
||||
dac = spec->multiout.dig_out_nid;
|
||||
else
|
||||
|
@ -1635,9 +1458,7 @@ static void alc_auto_init_digital(struct hda_codec *codec)
|
|||
}
|
||||
pin = spec->autocfg.dig_in_pin;
|
||||
if (pin)
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
PIN_IN);
|
||||
snd_hda_set_pin_ctl(codec, pin, PIN_IN);
|
||||
}
|
||||
|
||||
/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
|
||||
|
@ -2068,7 +1889,6 @@ static void alc_auto_init_std(struct hda_codec *codec);
|
|||
static int alc_init(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
unsigned int i;
|
||||
|
||||
if (spec->init_hook)
|
||||
spec->init_hook(codec);
|
||||
|
@ -2076,8 +1896,6 @@ static int alc_init(struct hda_codec *codec)
|
|||
alc_fix_pll(codec);
|
||||
alc_auto_init_amp(codec, spec->init_amp);
|
||||
|
||||
for (i = 0; i < spec->num_init_verbs; i++)
|
||||
snd_hda_sequence_write(codec, spec->init_verbs[i]);
|
||||
alc_init_special_input_src(codec);
|
||||
alc_auto_init_std(codec);
|
||||
|
||||
|
@ -2725,7 +2543,6 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec)
|
|||
nid = codec->start_nid;
|
||||
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
||||
hda_nid_t src;
|
||||
const hda_nid_t *list;
|
||||
unsigned int caps = get_wcaps(codec, nid);
|
||||
int type = get_wcaps_type(caps);
|
||||
|
||||
|
@ -2743,13 +2560,14 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec)
|
|||
cap_nids[nums] = src;
|
||||
break;
|
||||
}
|
||||
n = snd_hda_get_conn_list(codec, src, &list);
|
||||
n = snd_hda_get_num_conns(codec, src);
|
||||
if (n > 1) {
|
||||
cap_nids[nums] = src;
|
||||
break;
|
||||
} else if (n != 1)
|
||||
break;
|
||||
src = *list;
|
||||
if (snd_hda_get_connections(codec, src, &src, 1) != 1)
|
||||
break;
|
||||
}
|
||||
if (++nums >= max_nums)
|
||||
break;
|
||||
|
@ -2856,8 +2674,7 @@ static int alc_auto_create_shared_input(struct hda_codec *codec)
|
|||
static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
|
||||
unsigned int pin_type)
|
||||
{
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pin_type);
|
||||
snd_hda_set_pin_ctl(codec, nid, pin_type);
|
||||
/* unmute pin */
|
||||
if (nid_has_mute(codec, nid, HDA_OUTPUT))
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
|
@ -2891,7 +2708,7 @@ static void alc_auto_init_analog_input(struct hda_codec *codec)
|
|||
|
||||
/* mute all loopback inputs */
|
||||
if (spec->mixer_nid) {
|
||||
int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
|
||||
int nums = snd_hda_get_num_conns(codec, spec->mixer_nid);
|
||||
for (i = 0; i < nums; i++)
|
||||
snd_hda_codec_write(codec, spec->mixer_nid, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
|
@ -3521,7 +3338,7 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
|
|||
if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
|
||||
type = ALC_CTL_WIDGET_MUTE;
|
||||
val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
|
||||
} else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
|
||||
} else if (snd_hda_get_num_conns(codec, nid) == 1) {
|
||||
type = ALC_CTL_WIDGET_MUTE;
|
||||
val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
|
||||
} else {
|
||||
|
@ -3998,9 +3815,7 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
|
|||
snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
if (output) {
|
||||
snd_hda_codec_update_cache(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
PIN_OUT);
|
||||
snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT);
|
||||
if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, 0);
|
||||
|
@ -4009,9 +3824,8 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
|
|||
if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
||||
HDA_AMP_MUTE, HDA_AMP_MUTE);
|
||||
snd_hda_codec_update_cache(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
spec->multi_io[idx].ctl_in);
|
||||
snd_hda_set_pin_ctl_cache(codec, nid,
|
||||
spec->multi_io[idx].ctl_in);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -4084,7 +3898,7 @@ static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
|
|||
nums = 0;
|
||||
for (n = 0; n < spec->num_adc_nids; n++) {
|
||||
hda_nid_t cap = spec->private_capsrc_nids[n];
|
||||
int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
|
||||
int num_conns = snd_hda_get_num_conns(codec, cap);
|
||||
for (i = 0; i < imux->num_items; i++) {
|
||||
hda_nid_t pin = spec->imux_pins[i];
|
||||
if (pin) {
|
||||
|
@ -4213,7 +4027,7 @@ static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
|
|||
if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
|
||||
snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
|
||||
HDA_AMP_MUTE, 0);
|
||||
} else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
|
||||
} else if (snd_hda_get_num_conns(codec, cap) > 1) {
|
||||
snd_hda_codec_write_cache(codec, cap, 0,
|
||||
AC_VERB_SET_CONNECT_SEL, idx);
|
||||
}
|
||||
|
@ -4427,6 +4241,25 @@ static int alc_parse_auto_config(struct hda_codec *codec,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* common preparation job for alc_spec */
|
||||
static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
|
||||
{
|
||||
struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
int err;
|
||||
|
||||
if (!spec)
|
||||
return -ENOMEM;
|
||||
codec->spec = spec;
|
||||
spec->mixer_nid = mixer_nid;
|
||||
|
||||
err = alc_codec_rename_from_preset(codec);
|
||||
if (err < 0) {
|
||||
kfree(spec);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alc880_parse_auto_config(struct hda_codec *codec)
|
||||
{
|
||||
static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
|
||||
|
@ -4808,13 +4641,11 @@ static int patch_alc880(struct hda_codec *codec)
|
|||
struct alc_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
err = alc_alloc_spec(codec, 0x0b);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->mixer_nid = 0x0b;
|
||||
spec = codec->spec;
|
||||
spec->need_dac_fix = 1;
|
||||
|
||||
alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
|
||||
|
@ -4890,7 +4721,7 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
|
|||
spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
|
||||
snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT);
|
||||
spec->unsol_event = alc_sku_unsol_event;
|
||||
add_verb(codec->spec, alc_gpio1_init_verbs);
|
||||
snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5001,13 +4832,11 @@ static int patch_alc260(struct hda_codec *codec)
|
|||
struct alc_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
err = alc_alloc_spec(codec, 0x07);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->mixer_nid = 0x07;
|
||||
spec = codec->spec;
|
||||
|
||||
alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
|
||||
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
|
||||
|
@ -5171,8 +5000,7 @@ static void alc889_fixup_mbp_vref(struct hda_codec *codec,
|
|||
val = snd_hda_codec_read(codec, nids[i], 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
val |= AC_PINCTL_VREF_80;
|
||||
snd_hda_codec_write(codec, nids[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, val);
|
||||
snd_hda_set_pin_ctl(codec, nids[i], val);
|
||||
spec->keep_vref_in_automute = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -5193,8 +5021,7 @@ static void alc889_fixup_imac91_vref(struct hda_codec *codec,
|
|||
val = snd_hda_codec_read(codec, nids[i], 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
val |= AC_PINCTL_VREF_50;
|
||||
snd_hda_codec_write(codec, nids[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, val);
|
||||
snd_hda_set_pin_ctl(codec, nids[i], val);
|
||||
}
|
||||
spec->keep_vref_in_automute = 1;
|
||||
}
|
||||
|
@ -5225,8 +5052,8 @@ static const struct alc_fixup alc882_fixups[] = {
|
|||
}
|
||||
},
|
||||
[ALC882_FIXUP_ACER_ASPIRE_7736] = {
|
||||
.type = ALC_FIXUP_SKU,
|
||||
.v.sku = ALC_FIXUP_SKU_IGNORE,
|
||||
.type = ALC_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_sku_ignore,
|
||||
},
|
||||
[ALC882_FIXUP_ASUS_W90V] = {
|
||||
.type = ALC_FIXUP_PINS,
|
||||
|
@ -5476,13 +5303,11 @@ static int patch_alc882(struct hda_codec *codec)
|
|||
struct alc_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
err = alc_alloc_spec(codec, 0x0b);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->mixer_nid = 0x0b;
|
||||
spec = codec->spec;
|
||||
|
||||
switch (codec->vendor_id) {
|
||||
case 0x10ec0882:
|
||||
|
@ -5494,10 +5319,6 @@ static int patch_alc882(struct hda_codec *codec)
|
|||
break;
|
||||
}
|
||||
|
||||
err = alc_codec_rename_from_preset(codec);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
alc_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
|
||||
alc882_fixups);
|
||||
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
|
||||
|
@ -5621,13 +5442,11 @@ static int patch_alc262(struct hda_codec *codec)
|
|||
struct alc_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
err = alc_alloc_spec(codec, 0x0b);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->mixer_nid = 0x0b;
|
||||
spec = codec->spec;
|
||||
|
||||
#if 0
|
||||
/* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
|
||||
|
@ -5710,7 +5529,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
|
|||
if (err > 0) {
|
||||
if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
|
||||
add_mixer(spec, alc268_beep_mixer);
|
||||
add_verb(spec, alc268_beep_init_verbs);
|
||||
snd_hda_gen_add_verbs(&spec->gen, alc268_beep_init_verbs);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
|
@ -5723,13 +5542,12 @@ static int patch_alc268(struct hda_codec *codec)
|
|||
struct alc_spec *spec;
|
||||
int i, has_beep, err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
/* ALC268 has no aa-loopback mixer */
|
||||
err = alc_alloc_spec(codec, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
spec = codec->spec;
|
||||
|
||||
/* automatic parse from the BIOS config */
|
||||
err = alc268_parse_auto_config(codec);
|
||||
|
@ -5946,9 +5764,7 @@ static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled)
|
|||
{
|
||||
struct hda_codec *codec = private_data;
|
||||
unsigned int pinval = enabled ? 0x20 : 0x24;
|
||||
snd_hda_codec_update_cache(codec, 0x19, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pinval);
|
||||
snd_hda_set_pin_ctl_cache(codec, 0x19, pinval);
|
||||
}
|
||||
|
||||
static void alc269_fixup_mic2_mute(struct hda_codec *codec,
|
||||
|
@ -6015,8 +5831,8 @@ static const struct alc_fixup alc269_fixups[] = {
|
|||
}
|
||||
},
|
||||
[ALC269_FIXUP_SKU_IGNORE] = {
|
||||
.type = ALC_FIXUP_SKU,
|
||||
.v.sku = ALC_FIXUP_SKU_IGNORE,
|
||||
.type = ALC_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_sku_ignore,
|
||||
},
|
||||
[ALC269_FIXUP_ASUS_G73JW] = {
|
||||
.type = ALC_FIXUP_PINS,
|
||||
|
@ -6242,19 +6058,13 @@ static void alc269_fill_coef(struct hda_codec *codec)
|
|||
static int patch_alc269(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec;
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->mixer_nid = 0x0b;
|
||||
|
||||
err = alc_codec_rename_from_preset(codec);
|
||||
err = alc_alloc_spec(codec, 0x0b);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
return err;
|
||||
|
||||
spec = codec->spec;
|
||||
|
||||
if (codec->vendor_id == 0x10ec0269) {
|
||||
spec->codec_variant = ALC269_TYPE_ALC269VA;
|
||||
|
@ -6346,8 +6156,7 @@ static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
|
|||
if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
|
||||
val |= AC_PINCTL_IN_EN;
|
||||
val |= AC_PINCTL_VREF_50;
|
||||
snd_hda_codec_write(codec, 0x0f, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, val);
|
||||
snd_hda_set_pin_ctl(codec, 0x0f, val);
|
||||
spec->keep_vref_in_automute = 1;
|
||||
}
|
||||
|
||||
|
@ -6401,13 +6210,11 @@ static int patch_alc861(struct hda_codec *codec)
|
|||
struct alc_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
err = alc_alloc_spec(codec, 0x15);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->mixer_nid = 0x15;
|
||||
spec = codec->spec;
|
||||
|
||||
alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
|
||||
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
|
||||
|
@ -6504,13 +6311,11 @@ static int patch_alc861vd(struct hda_codec *codec)
|
|||
struct alc_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
err = alc_alloc_spec(codec, 0x0b);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->mixer_nid = 0x0b;
|
||||
spec = codec->spec;
|
||||
|
||||
alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
|
||||
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
|
||||
|
@ -6522,7 +6327,7 @@ static int patch_alc861vd(struct hda_codec *codec)
|
|||
|
||||
if (codec->vendor_id == 0x10ec0660) {
|
||||
/* always turn on EAPD */
|
||||
add_verb(spec, alc660vd_eapd_verbs);
|
||||
snd_hda_gen_add_verbs(&spec->gen, alc660vd_eapd_verbs);
|
||||
}
|
||||
|
||||
if (!spec->no_analog) {
|
||||
|
@ -6635,8 +6440,8 @@ static const struct alc_fixup alc662_fixups[] = {
|
|||
}
|
||||
},
|
||||
[ALC662_FIXUP_SKU_IGNORE] = {
|
||||
.type = ALC_FIXUP_SKU,
|
||||
.v.sku = ALC_FIXUP_SKU_IGNORE,
|
||||
.type = ALC_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_sku_ignore,
|
||||
},
|
||||
[ALC662_FIXUP_HP_RP5800] = {
|
||||
.type = ALC_FIXUP_PINS,
|
||||
|
@ -6849,25 +6654,19 @@ static const struct alc_model_fixup alc662_fixup_models[] = {
|
|||
static int patch_alc662(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec;
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (!spec)
|
||||
return -ENOMEM;
|
||||
err = alc_alloc_spec(codec, 0x0b);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
spec->mixer_nid = 0x0b;
|
||||
spec = codec->spec;
|
||||
|
||||
/* handle multiple HPs as is */
|
||||
spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
|
||||
|
||||
alc_fix_pll_init(codec, 0x20, 0x04, 15);
|
||||
|
||||
err = alc_codec_rename_from_preset(codec);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
if ((alc_get_coef0(codec) & (1 << 14)) &&
|
||||
codec->bus->pci->subsystem_vendor == 0x1025 &&
|
||||
spec->cdefine.platform_type == 1) {
|
||||
|
@ -6930,16 +6729,12 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
|
|||
*/
|
||||
static int patch_alc680(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec->spec = spec;
|
||||
|
||||
/* ALC680 has no aa-loopback mixer */
|
||||
err = alc_alloc_spec(codec, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* automatic parse from the BIOS config */
|
||||
err = alc680_parse_auto_config(codec);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <sound/tlv.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_beep.h"
|
||||
#include "hda_jack.h"
|
||||
|
||||
|
@ -221,6 +222,7 @@ struct sigmatel_spec {
|
|||
unsigned char aloopback_shift;
|
||||
|
||||
/* power management */
|
||||
unsigned int power_map_bits;
|
||||
unsigned int num_pwrs;
|
||||
const hda_nid_t *pwr_nids;
|
||||
const hda_nid_t *dac_list;
|
||||
|
@ -314,6 +316,9 @@ struct sigmatel_spec {
|
|||
struct hda_vmaster_mute_hook vmaster_mute;
|
||||
};
|
||||
|
||||
#define AC_VERB_IDT_SET_POWER_MAP 0x7ec
|
||||
#define AC_VERB_IDT_GET_POWER_MAP 0xfec
|
||||
|
||||
static const hda_nid_t stac9200_adc_nids[1] = {
|
||||
0x03,
|
||||
};
|
||||
|
@ -681,8 +686,7 @@ static int stac_vrefout_set(struct hda_codec *codec,
|
|||
pinctl &= ~AC_PINCTL_VREFEN;
|
||||
pinctl |= (new_vref & AC_PINCTL_VREFEN);
|
||||
|
||||
error = snd_hda_codec_write_cache(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
|
||||
error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
|
@ -706,8 +710,7 @@ static unsigned int stac92xx_vref_set(struct hda_codec *codec,
|
|||
else
|
||||
pincfg |= AC_PINCTL_IN_EN;
|
||||
|
||||
error = snd_hda_codec_write_cache(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg);
|
||||
error = snd_hda_set_pin_ctl_cache(codec, nid, pincfg);
|
||||
if (error < 0)
|
||||
return error;
|
||||
else
|
||||
|
@ -2505,27 +2508,10 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int stac92xx_get_default_vref(struct hda_codec *codec,
|
||||
hda_nid_t nid)
|
||||
{
|
||||
unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
|
||||
pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
|
||||
if (pincap & AC_PINCAP_VREF_100)
|
||||
return AC_PINCTL_VREF_100;
|
||||
if (pincap & AC_PINCAP_VREF_80)
|
||||
return AC_PINCTL_VREF_80;
|
||||
if (pincap & AC_PINCAP_VREF_50)
|
||||
return AC_PINCTL_VREF_50;
|
||||
if (pincap & AC_PINCAP_VREF_GRD)
|
||||
return AC_PINCTL_VREF_GRD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
|
||||
|
||||
{
|
||||
snd_hda_codec_write_cache(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
|
||||
snd_hda_set_pin_ctl_cache(codec, nid, pin_type);
|
||||
}
|
||||
|
||||
#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
|
||||
|
@ -2594,7 +2580,7 @@ static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
|
|||
hda_nid_t nid = kcontrol->private_value;
|
||||
unsigned int vref = stac92xx_vref_get(codec, nid);
|
||||
|
||||
if (vref == stac92xx_get_default_vref(codec, nid))
|
||||
if (vref == snd_hda_get_default_vref(codec, nid))
|
||||
ucontrol->value.enumerated.item[0] = 0;
|
||||
else if (vref == AC_PINCTL_VREF_GRD)
|
||||
ucontrol->value.enumerated.item[0] = 1;
|
||||
|
@ -2613,7 +2599,7 @@ static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
|
|||
hda_nid_t nid = kcontrol->private_value;
|
||||
|
||||
if (ucontrol->value.enumerated.item[0] == 0)
|
||||
new_vref = stac92xx_get_default_vref(codec, nid);
|
||||
new_vref = snd_hda_get_default_vref(codec, nid);
|
||||
else if (ucontrol->value.enumerated.item[0] == 1)
|
||||
new_vref = AC_PINCTL_VREF_GRD;
|
||||
else if (ucontrol->value.enumerated.item[0] == 2)
|
||||
|
@ -2679,7 +2665,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
|
|||
else {
|
||||
unsigned int pinctl = AC_PINCTL_IN_EN;
|
||||
if (io_idx) /* set VREF for mic */
|
||||
pinctl |= stac92xx_get_default_vref(codec, nid);
|
||||
pinctl |= snd_hda_get_default_vref(codec, nid);
|
||||
stac92xx_auto_set_pinctl(codec, nid, pinctl);
|
||||
}
|
||||
|
||||
|
@ -2847,7 +2833,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
|
|||
char name[22];
|
||||
|
||||
if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
|
||||
if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
|
||||
if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
|
||||
&& nid == spec->line_switch)
|
||||
control = STAC_CTL_WIDGET_IO_SWITCH;
|
||||
else if (snd_hda_query_pin_caps(codec, nid)
|
||||
|
@ -4250,13 +4236,6 @@ static void stac_store_hints(struct hda_codec *codec)
|
|||
val = snd_hda_get_bool_hint(codec, "eapd_switch");
|
||||
if (val >= 0)
|
||||
spec->eapd_switch = val;
|
||||
get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity);
|
||||
if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
|
||||
spec->gpio_mask |= spec->gpio_led;
|
||||
spec->gpio_dir |= spec->gpio_led;
|
||||
if (spec->gpio_led_polarity)
|
||||
spec->gpio_data |= spec->gpio_led;
|
||||
}
|
||||
}
|
||||
|
||||
static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins,
|
||||
|
@ -4354,7 +4333,7 @@ static int stac92xx_init(struct hda_codec *codec)
|
|||
unsigned int pinctl, conf;
|
||||
if (type == AUTO_PIN_MIC) {
|
||||
/* for mic pins, force to initialize */
|
||||
pinctl = stac92xx_get_default_vref(codec, nid);
|
||||
pinctl = snd_hda_get_default_vref(codec, nid);
|
||||
pinctl |= AC_PINCTL_IN_EN;
|
||||
stac92xx_auto_set_pinctl(codec, nid, pinctl);
|
||||
} else {
|
||||
|
@ -4390,10 +4369,18 @@ static int stac92xx_init(struct hda_codec *codec)
|
|||
hda_nid_t nid = spec->pwr_nids[i];
|
||||
int pinctl, def_conf;
|
||||
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
def_conf = get_defcfg_connect(def_conf);
|
||||
if (def_conf == AC_JACK_PORT_NONE) {
|
||||
/* power off unused ports */
|
||||
stac_toggle_power_map(codec, nid, 0);
|
||||
continue;
|
||||
}
|
||||
/* power on when no jack detection is available */
|
||||
/* or when the VREF is used for controlling LED */
|
||||
if (!spec->hp_detect ||
|
||||
spec->vref_mute_led_nid == nid) {
|
||||
spec->vref_mute_led_nid == nid ||
|
||||
!is_jack_detectable(codec, nid)) {
|
||||
stac_toggle_power_map(codec, nid, 1);
|
||||
continue;
|
||||
}
|
||||
|
@ -4411,15 +4398,6 @@ static int stac92xx_init(struct hda_codec *codec)
|
|||
stac_toggle_power_map(codec, nid, 1);
|
||||
continue;
|
||||
}
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
def_conf = get_defcfg_connect(def_conf);
|
||||
/* skip any ports that don't have jacks since presence
|
||||
* detection is useless */
|
||||
if (def_conf != AC_JACK_PORT_NONE &&
|
||||
!is_jack_detectable(codec, nid)) {
|
||||
stac_toggle_power_map(codec, nid, 1);
|
||||
continue;
|
||||
}
|
||||
if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) {
|
||||
stac_issue_unsol_event(codec, nid);
|
||||
continue;
|
||||
|
@ -4432,6 +4410,12 @@ static int stac92xx_init(struct hda_codec *codec)
|
|||
|
||||
/* sync mute LED */
|
||||
snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
|
||||
|
||||
/* sync the power-map */
|
||||
if (spec->num_pwrs)
|
||||
snd_hda_codec_write(codec, codec->afg, 0,
|
||||
AC_VERB_IDT_SET_POWER_MAP,
|
||||
spec->power_map_bits);
|
||||
if (spec->dac_list)
|
||||
stac92xx_power_down(codec);
|
||||
return 0;
|
||||
|
@ -4460,8 +4444,7 @@ static void stac92xx_shutup_pins(struct hda_codec *codec)
|
|||
struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, pin->nid);
|
||||
if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
|
||||
snd_hda_codec_write(codec, pin->nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
|
||||
snd_hda_set_pin_ctl(codec, pin->nid, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4517,9 +4500,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
|
|||
|
||||
pin_ctl |= flag;
|
||||
if (old_ctl != pin_ctl)
|
||||
snd_hda_codec_write_cache(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pin_ctl);
|
||||
snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl);
|
||||
}
|
||||
|
||||
static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
|
||||
|
@ -4528,9 +4509,7 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
|
|||
unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
|
||||
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
|
||||
if (pin_ctl & flag)
|
||||
snd_hda_codec_write_cache(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pin_ctl & ~flag);
|
||||
snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl & ~flag);
|
||||
}
|
||||
|
||||
static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
|
||||
|
@ -4682,14 +4661,18 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
|
|||
|
||||
idx = 1 << idx;
|
||||
|
||||
val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
|
||||
val = spec->power_map_bits;
|
||||
if (enable)
|
||||
val &= ~idx;
|
||||
else
|
||||
val |= idx;
|
||||
|
||||
/* power down unused output ports */
|
||||
snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
|
||||
if (val != spec->power_map_bits) {
|
||||
spec->power_map_bits = val;
|
||||
snd_hda_codec_write(codec, codec->afg, 0,
|
||||
AC_VERB_IDT_SET_POWER_MAP, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
|
||||
|
@ -4866,6 +4849,11 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
|
|||
struct sigmatel_spec *spec = codec->spec;
|
||||
const struct dmi_device *dev = NULL;
|
||||
|
||||
if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
|
||||
get_int_hint(codec, "gpio_led_polarity",
|
||||
&spec->gpio_led_polarity);
|
||||
return 1;
|
||||
}
|
||||
if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
|
||||
while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
|
||||
NULL, dev))) {
|
||||
|
@ -4952,7 +4940,8 @@ static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
|
|||
{
|
||||
if (nid == codec->afg)
|
||||
snd_iprintf(buffer, "Power-Map: 0x%02x\n",
|
||||
snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0));
|
||||
snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_IDT_GET_POWER_MAP, 0));
|
||||
}
|
||||
|
||||
static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
|
||||
|
@ -5009,20 +4998,6 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stac92xx_pre_resume(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
|
||||
/* sync mute LED */
|
||||
if (spec->vref_mute_led_nid)
|
||||
stac_vrefout_set(codec, spec->vref_mute_led_nid,
|
||||
spec->vref_led);
|
||||
else if (spec->gpio_led)
|
||||
stac_gpio_set(codec, spec->gpio_mask,
|
||||
spec->gpio_dir, spec->gpio_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state)
|
||||
{
|
||||
|
@ -5046,7 +5021,6 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
|||
#else
|
||||
#define stac92xx_suspend NULL
|
||||
#define stac92xx_resume NULL
|
||||
#define stac92xx_pre_resume NULL
|
||||
#define stac92xx_set_power_state NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
|
@ -5592,9 +5566,6 @@ again:
|
|||
codec->patch_ops.set_power_state =
|
||||
stac92xx_set_power_state;
|
||||
}
|
||||
#ifdef CONFIG_PM
|
||||
codec->patch_ops.pre_resume = stac92xx_pre_resume;
|
||||
#endif
|
||||
}
|
||||
|
||||
err = stac92xx_parse_auto_config(codec);
|
||||
|
@ -5901,9 +5872,6 @@ again:
|
|||
codec->patch_ops.set_power_state =
|
||||
stac92xx_set_power_state;
|
||||
}
|
||||
#ifdef CONFIG_PM
|
||||
codec->patch_ops.pre_resume = stac92xx_pre_resume;
|
||||
#endif
|
||||
}
|
||||
|
||||
spec->multiout.dac_nids = spec->dac_nids;
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include <sound/asoundef.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
#include "hda_jack.h"
|
||||
|
||||
/* Pin Widget NID */
|
||||
|
@ -484,7 +485,7 @@ static void activate_output_mix(struct hda_codec *codec, struct nid_path *path,
|
|||
|
||||
if (!path)
|
||||
return;
|
||||
num = snd_hda_get_conn_list(codec, mix_nid, NULL);
|
||||
num = snd_hda_get_num_conns(codec, mix_nid);
|
||||
for (i = 0; i < num; i++) {
|
||||
if (i == idx)
|
||||
val = AMP_IN_UNMUTE(i);
|
||||
|
@ -532,8 +533,7 @@ static void init_output_pin(struct hda_codec *codec, hda_nid_t pin,
|
|||
{
|
||||
if (!pin)
|
||||
return;
|
||||
snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pin_type);
|
||||
snd_hda_set_pin_ctl(codec, pin, pin_type);
|
||||
if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)
|
||||
snd_hda_codec_write(codec, pin, 0,
|
||||
AC_VERB_SET_EAPD_BTLENABLE, 0x02);
|
||||
|
@ -662,12 +662,12 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
|
|||
hda_nid_t nid = cfg->inputs[i].pin;
|
||||
if (spec->smart51_enabled && is_smart51_pins(codec, nid))
|
||||
ctl = PIN_OUT;
|
||||
else if (cfg->inputs[i].type == AUTO_PIN_MIC)
|
||||
ctl = PIN_VREF50;
|
||||
else
|
||||
else {
|
||||
ctl = PIN_IN;
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
|
||||
if (cfg->inputs[i].type == AUTO_PIN_MIC)
|
||||
ctl |= snd_hda_get_default_vref(codec, nid);
|
||||
}
|
||||
snd_hda_set_pin_ctl(codec, nid, ctl);
|
||||
}
|
||||
|
||||
/* init input-src */
|
||||
|
@ -1006,9 +1006,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
|
|||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
|
||||
parm |= out_in;
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
parm);
|
||||
snd_hda_set_pin_ctl(codec, nid, parm);
|
||||
if (out_in == AC_PINCTL_OUT_EN) {
|
||||
mute_aa_path(codec, 1);
|
||||
notify_aa_path_ctls(codec);
|
||||
|
@ -1647,8 +1645,7 @@ static void toggle_output_mutes(struct hda_codec *codec, int num_pins,
|
|||
parm &= ~AC_PINCTL_OUT_EN;
|
||||
else
|
||||
parm |= AC_PINCTL_OUT_EN;
|
||||
snd_hda_codec_write(codec, pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, parm);
|
||||
snd_hda_set_pin_ctl(codec, pins[i], parm);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1709,8 +1706,7 @@ static void via_gpio_control(struct hda_codec *codec)
|
|||
|
||||
if (gpio_data == 0x02) {
|
||||
/* unmute line out */
|
||||
snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0],
|
||||
PIN_OUT);
|
||||
if (vol_counter & 0x20) {
|
||||
/* decrease volume */
|
||||
|
@ -1728,9 +1724,7 @@ static void via_gpio_control(struct hda_codec *codec)
|
|||
}
|
||||
} else if (!(gpio_data & 0x02)) {
|
||||
/* mute line out */
|
||||
snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
0);
|
||||
snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0], 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2757,8 +2751,7 @@ static void via_auto_init_dig_in(struct hda_codec *codec)
|
|||
struct via_spec *spec = codec->spec;
|
||||
if (!spec->dig_in_nid)
|
||||
return;
|
||||
snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
|
||||
snd_hda_set_pin_ctl(codec, spec->autocfg.dig_in_pin, PIN_IN);
|
||||
}
|
||||
|
||||
/* initialize the unsolicited events */
|
||||
|
|
Loading…
Reference in a new issue