aboutsummaryrefslogtreecommitdiff
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c81
-rw-r--r--sound/pci/hda/hda_codec.h5
-rw-r--r--sound/pci/hda/hda_generic.c3
-rw-r--r--sound/pci/hda/hda_hwdep.c60
-rw-r--r--sound/pci/hda/hda_intel.c60
-rw-r--r--sound/pci/hda/hda_local.h14
-rw-r--r--sound/pci/hda/hda_proc.c31
-rw-r--r--sound/pci/hda/patch_analog.c117
-rw-r--r--sound/pci/hda/patch_cirrus.c14
-rw-r--r--sound/pci/hda/patch_cmedia.c11
-rw-r--r--sound/pci/hda/patch_conexant.c592
-rw-r--r--sound/pci/hda/patch_realtek.c1006
-rw-r--r--sound/pci/hda/patch_si3054.c1
-rw-r--r--sound/pci/hda/patch_sigmatel.c271
-rw-r--r--sound/pci/hda/patch_via.c274
15 files changed, 1810 insertions, 730 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index f98b47cd6cf..76d3c4c049d 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -824,6 +824,9 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
struct hda_pincfg *pin;
unsigned int oldcfg;
+ if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+ return -EINVAL;
+
oldcfg = snd_hda_codec_get_pincfg(codec, nid);
pin = look_up_pincfg(codec, list, nid);
if (!pin) {
@@ -899,6 +902,25 @@ static void restore_pincfgs(struct hda_codec *codec)
}
}
+/**
+ * snd_hda_shutup_pins - Shut up all pins
+ * @codec: the HDA codec
+ *
+ * Clear all pin controls to shup up before suspend for avoiding click noise.
+ * The controls aren't cached so that they can be resumed properly.
+ */
+void snd_hda_shutup_pins(struct hda_codec *codec)
+{
+ int i;
+ for (i = 0; i < codec->init_pins.used; i++) {
+ struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
+ /* use read here for syncing after issuing each verb */
+ snd_hda_codec_read(codec, pin->nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+ }
+}
+EXPORT_SYMBOL_HDA(snd_hda_shutup_pins);
+
static void init_hda_cache(struct hda_cache_rec *cache,
unsigned int record_size);
static void free_hda_cache(struct hda_cache_rec *cache);
@@ -931,6 +953,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
#endif
list_del(&codec->list);
snd_array_free(&codec->mixers);
+ snd_array_free(&codec->nids);
codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
@@ -985,7 +1008,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
mutex_init(&codec->control_mutex);
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
- snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60);
+ snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
+ snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
if (codec->bus->modelname) {
@@ -1708,7 +1732,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
/**
- * snd_hda_ctl-add - Add a control element and assign to the codec
+ * snd_hda_ctl_add - Add a control element and assign to the codec
* @codec: HD-audio codec
* @nid: corresponding NID (optional)
* @kctl: the control element to assign
@@ -1723,19 +1747,25 @@ EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
*
* snd_hda_ctl_add() checks the control subdev id field whether
* #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower
- * bits value is taken as the NID to assign.
+ * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit
+ * specifies if kctl->private_value is a HDA amplifier value.
*/
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
struct snd_kcontrol *kctl)
{
int err;
+ unsigned short flags = 0;
struct hda_nid_item *item;
- if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) {
+ if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) {
+ flags |= HDA_NID_ITEM_AMP;
if (nid == 0)
- nid = kctl->id.subdevice & 0xffff;
- kctl->id.subdevice = 0;
+ nid = get_amp_nid_(kctl->private_value);
}
+ if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0)
+ nid = kctl->id.subdevice & 0xffff;
+ if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
+ kctl->id.subdevice = 0;
err = snd_ctl_add(codec->bus->card, kctl);
if (err < 0)
return err;
@@ -1744,11 +1774,41 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
return -ENOMEM;
item->kctl = kctl;
item->nid = nid;
+ item->flags = flags;
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
/**
+ * snd_hda_add_nid - Assign a NID to a control element
+ * @codec: HD-audio codec
+ * @nid: corresponding NID (optional)
+ * @kctl: the control element to assign
+ * @index: index to kctl
+ *
+ * Add the given control element to an array inside the codec instance.
+ * This function is used when #snd_hda_ctl_add cannot be used for 1:1
+ * NID:KCTL mapping - for example "Capture Source" selector.
+ */
+int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
+ unsigned int index, hda_nid_t nid)
+{
+ struct hda_nid_item *item;
+
+ if (nid > 0) {
+ item = snd_array_new(&codec->nids);
+ if (!item)
+ return -ENOMEM;
+ item->kctl = kctl;
+ item->index = index;
+ item->nid = nid;
+ return 0;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_nid);
+
+/**
* snd_hda_ctls_clear - Clear all controls assigned to the given codec
* @codec: HD-audio codec
*/
@@ -1759,6 +1819,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
for (i = 0; i < codec->mixers.used; i++)
snd_ctl_remove(codec->bus->card, items[i].kctl);
snd_array_free(&codec->mixers);
+ snd_array_free(&codec->nids);
}
/* pseudo device locking
@@ -2706,7 +2767,8 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
power_state);
/* partial workaround for "azx_get_response timeout" */
- if (power_state == AC_PWRST_D0)
+ if (power_state == AC_PWRST_D0 &&
+ (codec->vendor_id & 0xffff0000) == 0x14f10000)
msleep(10);
nid = codec->start_nid;
@@ -2740,7 +2802,6 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
if (power_state == AC_PWRST_D0) {
unsigned long end_time;
int state;
- msleep(10);
/* wait until the codec reachs to D0 */
end_time = jiffies + msecs_to_jiffies(500);
do {
@@ -3214,6 +3275,8 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {
/*
* get the empty PCM device number to assign
+ *
+ * note the max device number is limited by HDA_MAX_PCMS, currently 10
*/
static int get_empty_pcm_device(struct hda_bus *bus, int type)
{
@@ -3478,6 +3541,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
for (; knew->name; knew++) {
struct snd_kcontrol *kctl;
+ if (knew->iface == -1) /* skip this codec private value */
+ continue;
kctl = snd_ctl_new1(knew, codec);
if (!kctl)
return -ENOMEM;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 0a770a28e71..b75da47571e 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -527,6 +527,9 @@ enum {
/* max. codec address */
#define HDA_MAX_CODEC_ADDRESS 0x0f
+/* max number of PCM devics per card */
+#define HDA_MAX_PCMS 10
+
/*
* generic arrays
*/
@@ -789,6 +792,7 @@ struct hda_codec {
u32 *wcaps;
struct snd_array mixers; /* list of assigned mixer elements */
+ struct snd_array nids; /* list of mapped mixer elements */
struct hda_cache_rec amp_cache; /* cache for amp access */
struct hda_cache_rec cmd_cache; /* cache for other commands */
@@ -898,6 +902,7 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid,
unsigned int cfg);
int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
hda_nid_t nid, unsigned int cfg); /* for hwdep */
+void snd_hda_shutup_pins(struct hda_codec *codec);
/*
* Mixer
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 092c6a7c2ff..5ea21285ee1 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec)
}
/* create input MUX if multiple sources are available */
- err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec));
+ err = snd_hda_ctl_add(codec, spec->adc_node->nid,
+ snd_ctl_new1(&cap_sel, codec));
if (err < 0)
return err;
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 40ccb419b6e..a1fc83753cc 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -293,8 +293,11 @@ static ssize_t type##_store(struct device *dev, \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
- char *after; \
- codec->type = simple_strtoul(buf, &after, 0); \
+ unsigned long val; \
+ int err = strict_strtoul(buf, 0, &val); \
+ if (err < 0) \
+ return err; \
+ codec->type = val; \
return count; \
}
@@ -622,6 +625,10 @@ enum {
LINE_MODE_PINCFG,
LINE_MODE_VERB,
LINE_MODE_HINT,
+ LINE_MODE_VENDOR_ID,
+ LINE_MODE_SUBSYSTEM_ID,
+ LINE_MODE_REVISION_ID,
+ LINE_MODE_CHIP_NAME,
NUM_LINE_MODES,
};
@@ -651,53 +658,71 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus,
}
/* parse the contents after the other command tags, [pincfg], [verb],
- * [hint] and [model]
+ * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
* just pass to the sysfs helper (only when any codec was specified)
*/
static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
struct hda_codec **codecp)
{
- if (!*codecp)
- return;
parse_user_pin_configs(*codecp, buf);
}
static void parse_verb_mode(char *buf, struct hda_bus *bus,
struct hda_codec **codecp)
{
- if (!*codecp)
- return;
parse_init_verbs(*codecp, buf);
}
static void parse_hint_mode(char *buf, struct hda_bus *bus,
struct hda_codec **codecp)
{
- if (!*codecp)
- return;
parse_hints(*codecp, buf);
}
static void parse_model_mode(char *buf, struct hda_bus *bus,
struct hda_codec **codecp)
{
- if (!*codecp)
- return;
kfree((*codecp)->modelname);
(*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
}
+static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ kfree((*codecp)->chip_name);
+ (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
+}
+
+#define DEFINE_PARSE_ID_MODE(name) \
+static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
+ struct hda_codec **codecp) \
+{ \
+ unsigned long val; \
+ if (!strict_strtoul(buf, 0, &val)) \
+ (*codecp)->name = val; \
+}
+
+DEFINE_PARSE_ID_MODE(vendor_id);
+DEFINE_PARSE_ID_MODE(subsystem_id);
+DEFINE_PARSE_ID_MODE(revision_id);
+
+
struct hda_patch_item {
const char *tag;
void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
+ int need_codec;
};
static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
- [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode },
- [LINE_MODE_MODEL] = { "[model]", parse_model_mode },
- [LINE_MODE_VERB] = { "[verb]", parse_verb_mode },
- [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode },
- [LINE_MODE_HINT] = { "[hint]", parse_hint_mode },
+ [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode, 0 },
+ [LINE_MODE_MODEL] = { "[model]", parse_model_mode, 1 },
+ [LINE_MODE_VERB] = { "[verb]", parse_verb_mode, 1 },
+ [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode, 1 },
+ [LINE_MODE_HINT] = { "[hint]", parse_hint_mode, 1 },
+ [LINE_MODE_VENDOR_ID] = { "[vendor_id]", parse_vendor_id_mode, 1 },
+ [LINE_MODE_SUBSYSTEM_ID] = { "[subsystem_id]", parse_subsystem_id_mode, 1 },
+ [LINE_MODE_REVISION_ID] = { "[revision_id]", parse_revision_id_mode, 1 },
+ [LINE_MODE_CHIP_NAME] = { "[chip_name]", parse_chip_name_mode, 1 },
};
/* check the line starting with '[' -- change the parser mode accodingly */
@@ -780,7 +805,8 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
continue;
if (*buf == '[')
line_mode = parse_line_mode(buf, bus);
- else if (patch_items[line_mode].parser)
+ else if (patch_items[line_mode].parser &&
+ (codec || !patch_items[line_mode].need_codec))
patch_items[line_mode].parser(buf, bus, &codec);
}
release_firmware(fw);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index ff6da6f386d..d5c93ad852e 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -125,6 +125,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, ICH9},"
"{Intel, ICH10},"
"{Intel, PCH},"
+ "{Intel, CPT},"
"{Intel, SCH},"
"{ATI, SB450},"
"{ATI, SB600},"
@@ -259,8 +260,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_MAX_FRAG 32
/* max buffer size - no h/w limit, you can increase as you like */
#define AZX_MAX_BUF_SIZE (1024*1024*1024)
-/* max number of PCM devics per card */
-#define AZX_MAX_PCMS 8
/* RIRB int mask: overrun[2], response[0] */
#define RIRB_INT_RESPONSE 0x01
@@ -408,7 +407,7 @@ struct azx {
struct azx_dev *azx_dev;
/* PCM */
- struct snd_pcm *pcm[AZX_MAX_PCMS];
+ struct snd_pcm *pcm[HDA_MAX_PCMS];
/* HD codec */
unsigned short codec_mask;
@@ -449,6 +448,7 @@ struct azx {
/* driver types */
enum {
AZX_DRIVER_ICH,
+ AZX_DRIVER_PCH,
AZX_DRIVER_SCH,
AZX_DRIVER_ATI,
AZX_DRIVER_ATIHDMI,
@@ -463,6 +463,7 @@ enum {
static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_ICH] = "HDA Intel",
+ [AZX_DRIVER_PCH] = "HDA Intel PCH",
[AZX_DRIVER_SCH] = "HDA Intel MID",
[AZX_DRIVER_ATI] = "HDA ATI SB",
[AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
@@ -968,8 +969,8 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
azx_dev->insufficient = 1;
/* enable SIE */
- azx_writeb(chip, INTCTL,
- azx_readb(chip, INTCTL) | (1 << azx_dev->index));
+ azx_writel(chip, INTCTL,
+ azx_readl(chip, INTCTL) | (1 << azx_dev->index));
/* set DMA start and interrupt mask */
azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
SD_CTL_DMA_START | SD_INT_MASK);
@@ -988,8 +989,8 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
{
azx_stream_clear(chip, azx_dev);
/* disable SIE */
- azx_writeb(chip, INTCTL,
- azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
+ azx_writel(chip, INTCTL,
+ azx_readl(chip, INTCTL) & ~(1 << azx_dev->index));
}
@@ -1065,6 +1066,7 @@ static void azx_init_pci(struct azx *chip)
0x01, NVIDIA_HDA_ENABLE_COHBIT);
break;
case AZX_DRIVER_SCH:
+ case AZX_DRIVER_PCH:
pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
@@ -1350,7 +1352,7 @@ static void azx_bus_reset(struct hda_bus *bus)
if (chip->initialized) {
int i;
- for (i = 0; i < AZX_MAX_PCMS; i++)
+ for (i = 0; i < HDA_MAX_PCMS; i++)
snd_pcm_suspend_all(chip->pcm[i]);
snd_hda_suspend(chip->bus);
snd_hda_resume(chip->bus);
@@ -1412,7 +1414,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
chip->codec_mask &= ~(1 << c);
/* More badly, accessing to a non-existing
* codec often screws up the controller chip,
- * and distrubs the further communications.
+ * and disturbs the further communications.
* Thus if an error occurs during probing,
* better to reset the controller chip to
* get back to the sanity state.
@@ -1983,7 +1985,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
int pcm_dev = cpcm->device;
int s, err;
- if (pcm_dev >= AZX_MAX_PCMS) {
+ if (pcm_dev >= HDA_MAX_PCMS) {
snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
pcm_dev);
return -EINVAL;
@@ -2139,7 +2141,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
azx_clear_irq_pending(chip);
- for (i = 0; i < AZX_MAX_PCMS; i++)
+ for (i = 0; i < HDA_MAX_PCMS; i++)
snd_pcm_suspend_all(chip->pcm[i]);
if (chip->initialized)
snd_hda_suspend(chip->bus);
@@ -2262,6 +2264,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
{}
@@ -2418,6 +2421,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
if (bdl_pos_adj[dev] < 0) {
switch (chip->driver_type) {
case AZX_DRIVER_ICH:
+ case AZX_DRIVER_PCH:
bdl_pos_adj[dev] = 1;
break;
default:
@@ -2683,7 +2687,7 @@ static void __devexit azx_remove(struct pci_dev *pci)
}
/* PCI IDs */
-static struct pci_device_id azx_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* ICH 6..10 */
{ PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
@@ -2696,6 +2700,8 @@ static struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
/* PCH */
{ PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
+ /* CPT */
+ { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
/* SCH */
{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
/* ATI SB 450/600 */
@@ -2723,32 +2729,10 @@ static struct pci_device_id azx_ids[] = {
/* ULI M5461 */
{ PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI },
/* NVIDIA MCP */
- { PCI_DEVICE(0x10de, 0x026c), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0371), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x03e4), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x03f0), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x044a), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0590), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0777), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x07fc), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x07fd), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0ac0), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA },
- { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
+ .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+ .class_mask = 0xffffff,
+ .driver_data = AZX_DRIVER_NVIDIA },
/* Teradici */
{ PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
/* Creative X-Fi (CA0110-IBG) */
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 5778ae882b8..7cee364976f 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -31,6 +31,7 @@
* in snd_hda_ctl_add(), so that this value won't appear in the outside.
*/
#define HDA_SUBDEV_NID_FLAG (1U << 31)
+#define HDA_SUBDEV_AMP_FLAG (1U << 30)
/*
* for mixer controls
@@ -42,7 +43,7 @@
/* mono volume with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
- .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+ .subdevice = HDA_SUBDEV_AMP_FLAG, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
@@ -63,7 +64,7 @@
/* mono mute switch with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
- .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+ .subdevice = HDA_SUBDEV_AMP_FLAG, \
.info = snd_hda_mixer_amp_switch_info, \
.get = snd_hda_mixer_amp_switch_get, \
.put = snd_hda_mixer_amp_switch_put, \
@@ -81,7 +82,7 @@
/* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
- .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+ .subdevice = HDA_SUBDEV_AMP_FLAG, \
.info = snd_hda_mixer_amp_switch_info, \
.get = snd_hda_mixer_amp_switch_get, \
.put = snd_hda_mixer_amp_switch_put_beep, \
@@ -464,13 +465,20 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
+/* flags for hda_nid_item */
+#define HDA_NID_ITEM_AMP (1<<0)
+
struct hda_nid_item {
struct snd_kcontrol *kctl;
+ unsigned int index;
hda_nid_t nid;
+ unsigned short flags;
};
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
struct snd_kcontrol *kctl);
+int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
+ unsigned int index, hda_nid_t nid);
void snd_hda_ctls_clear(struct hda_codec *codec);
/*
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index c9afc04adac..f97d35de66c 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -61,18 +61,29 @@ static const char *get_wid_type_name(unsigned int wid_value)
return "UNKNOWN Widget";
}
-static void print_nid_mixers(struct snd_info_buffer *buffer,
- struct hda_codec *codec, hda_nid_t nid)
+static void print_nid_array(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid,
+ struct snd_array *array)
{
int i;
- struct hda_nid_item *items = codec->mixers.list;
+ struct hda_nid_item *items = array->list, *item;
struct snd_kcontrol *kctl;
- for (i = 0; i < codec->mixers.used; i++) {
- if (items[i].nid == nid) {
- kctl = items[i].kctl;
+ for (i = 0; i < array->used; i++) {
+ item = &items[i];
+ if (item->nid == nid) {
+ kctl = item->kctl;
snd_iprintf(buffer,
" Control: name=\"%s\", index=%i, device=%i\n",
- kctl->id.name, kctl->id.index, kctl->id.device);
+ kctl->id.name, kctl->id.index + item->index,
+ kctl->id.device);
+ if (item->flags & HDA_NID_ITEM_AMP)
+ snd_iprintf(buffer,
+ " ControlAmp: chs=%lu, dir=%s, "
+ "idx=%lu, ofs=%lu\n",
+ get_amp_channels(kctl),
+ get_amp_direction(kctl) ? "Out" : "In",
+ get_amp_index(kctl),
+ get_amp_offset(kctl));
}
}
}
@@ -528,7 +539,8 @@ static void print_gpio(struct snd_info_buffer *buffer,
(data & (1<<i)) ? 1 : 0,
(unsol & (1<<i)) ? 1 : 0);
/* FIXME: add GPO and GPI pin information */
- print_nid_mixers(buffer, codec, nid);
+ print_nid_array(buffer, codec, nid, &codec->mixers);
+ print_nid_array(buffer, codec, nid, &codec->nids);
}
static void print_codec_info(struct snd_info_entry *entry,
@@ -608,7 +620,8 @@ static void print_codec_info(struct snd_info_entry *entry,
snd_iprintf(buffer, " CP");
snd_iprintf(buffer, "\n");
- print_nid_mixers(buffer, codec, nid);
+ print_nid_array(buffer, codec, nid, &codec->mixers);
+ print_nid_array(buffer, codec, nid, &codec->nids);
print_nid_pcms(buffer, codec, nid);
/* volume knob is a special widget that always have connection
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 69a941c7b15..e6d1bdff1b6 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -174,6 +174,7 @@ static struct snd_kcontrol_new ad_beep_mixer[] = {
static int ad198x_build_controls(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
+ struct snd_kcontrol *kctl;
unsigned int i;
int err;
@@ -208,9 +209,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
if (!kctl)
return -ENOMEM;
kctl->private_value = spec->beep_amp;
- err = snd_hda_ctl_add(codec,
- get_amp_nid_(spec->beep_amp),
- kctl);
+ err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0)
return err;
}
@@ -239,6 +238,27 @@ static int ad198x_build_controls(struct hda_codec *codec)
}
ad198x_free_kctls(codec); /* no longer needed */
+
+ /* assign Capture Source enums to NID */
+ kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+ if (!kctl)
+ kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+ for (i = 0; kctl && i < kctl->count; i++) {
+ err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
+ if (err < 0)
+ return err;
+ }
+
+ /* assign IEC958 enums to NID */
+ kctl = snd_hda_find_mixer_ctl(codec,
+ SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
+ if (kctl) {
+ err = snd_hda_add_nid(codec, kctl, 0,
+ spec->multiout.dig_out_nid);
+ if (err < 0)
+ return err;
+ }
+
return 0;
}
@@ -421,6 +441,11 @@ static int ad198x_build_pcms(struct hda_codec *codec)
return 0;
}
+static inline void ad198x_shutup(struct hda_codec *codec)
+{
+ snd_hda_shutup_pins(codec);
+}
+
static void ad198x_free_kctls(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
@@ -434,6 +459,46 @@ static void ad198x_free_kctls(struct hda_codec *codec)
snd_array_free(&spec->kctls);
}
+static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
+ hda_nid_t hp)
+{
+ struct ad198x_spec *spec = codec->spec;
+ snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
+ !spec->inv_eapd ? 0x00 : 0x02);
+ snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
+ !spec->inv_eapd ? 0x00 : 0x02);
+}
+
+static void ad198x_power_eapd(struct hda_codec *codec)
+{
+ /* We currently only handle front, HP */
+ switch (codec->vendor_id) {
+ case 0x11d41882:
+ case 0x11d4882a:
+ case 0x11d41884:
+ case 0x11d41984:
+ case 0x11d41883:
+ case 0x11d4184a:
+ case 0x11d4194a:
+ case 0x11d4194b:
+ ad198x_power_eapd_write(codec, 0x12, 0x11);
+ break;
+ case 0x11d41981:
+ case 0x11d41983:
+ ad198x_power_eapd_write(codec, 0x05, 0x06);
+ break;
+ case 0x11d41986:
+ ad198x_power_eapd_write(codec, 0x1b, 0x1a);
+ break;
+ case 0x11d41988:
+ case 0x11d4198b:
+ case 0x11d4989a:
+ case 0x11d4989b:
+ ad198x_power_eapd_write(codec, 0x29, 0x22);
+ break;
+ }
+}
+
static void ad198x_free(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
@@ -441,11 +506,29 @@ static void ad198x_free(struct hda_codec *codec)
if (!spec)
return;
+ ad198x_shutup(codec);
ad198x_free_kctls(codec);
kfree(spec);
snd_hda_detach_beep_device(codec);
}
+#ifdef SND_HDA_NEEDS_RESUME
+static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
+{
+ ad198x_shutup(codec);
+ ad198x_power_eapd(codec);
+ return 0;
+}
+
+static int ad198x_resume(struct hda_codec *codec)
+{
+ ad198x_init(codec);
+ snd_hda_codec_resume_amp(codec);
+ snd_hda_codec_resume_cache(codec);
+ return 0;
+}
+#endif
+
static struct hda_codec_ops ad198x_patch_ops = {
.build_controls = ad198x_build_controls,
.build_pcms = ad198x_build_pcms,
@@ -454,6 +537,11 @@ static struct hda_codec_ops ad198x_patch_ops = {
#ifdef CONFIG_SND_HDA_POWER_SAVE
.check_power_status = ad198x_check_power_status,
#endif
+#ifdef SND_HDA_NEEDS_RESUME
+ .suspend = ad198x_suspend,
+ .resume = ad198x_resume,
+#endif
+ .reboot_notify = ad198x_shutup,
};
@@ -701,6 +789,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "External Amplifier",
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
.info = ad198x_eapd_info,
.get = ad198x_eapd_get,
.put = ad198x_eapd_put,
@@ -808,6 +897,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = ad1986a_hp_master_sw_put,
@@ -1008,7 +1098,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
- SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
+ SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
@@ -1612,6 +1702,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = {
HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
.name = "Master Playback Switch",
.info = ad198x_eapd_info,
.get = ad198x_eapd_get,
@@ -2136,6 +2227,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "External Amplifier",
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
.info = ad198x_eapd_info,
.get = ad198x_eapd_get,
.put = ad198x_eapd_put,
@@ -2257,6 +2349,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Playback Source",
+ .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
.info = ad1988_spdif_playback_source_info,
.get = ad1988_spdif_playback_source_get,
.put = ad1988_spdif_playback_source_put,
@@ -2372,6 +2465,12 @@ static struct hda_verb ad1988_spdif_init_verbs[] = {
{ }
};
+static struct hda_verb ad1988_spdif_in_init_verbs[] = {
+ /* unmute SPDIF input pin */
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ { }
+};
+
/* AD1989 has no ADC -> SPDIF route */
static struct hda_verb ad1989_spdif_init_verbs[] = {
/* SPDIF-1 out pin */
@@ -2589,7 +2688,7 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
if (! knew->name)
return -ENOMEM;
if (get_amp_nid_(val))
- knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+ knew->subdevice = HDA_SUBDEV_AMP_FLAG;
knew->private_value = val;
return 0;
}
@@ -3107,8 +3206,11 @@ static int patch_ad1988(struct hda_codec *codec)
ad1988_spdif_init_verbs;
}
}
- if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a)
+ if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
+ spec->init_verbs[spec->num_init_verbs++] =
+ ad1988_spdif_in_init_verbs;
+ }
codec->patch_ops = ad198x_patch_ops;
switch (board_config) {
@@ -3747,6 +3849,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = ad1884a_mobile_master_sw_put,
@@ -3775,6 +3878,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.info = snd_hda_mixer_amp_switch_info,
.get = snd_hda_mixer_amp_switch_get,
.put = ad1884a_mobile_master_sw_put,
@@ -4116,6 +4220,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
.name = "Master Playback Switch",
.info = snd_hda_mixer_amp_switch_info,