summaryrefslogtreecommitdiff
path: root/sound/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_beep.c1
-rw-r--r--sound/pci/hda/hda_codec.c111
-rw-r--r--sound/pci/hda/hda_codec.h2
-rw-r--r--sound/pci/hda/hda_intel.c6
-rw-r--r--sound/pci/hda/hda_local.h3
-rw-r--r--sound/pci/hda/patch_analog.c5
-rw-r--r--sound/pci/hda/patch_nvhdmi.c4
-rw-r--r--sound/pci/hda/patch_realtek.c19
-rw-r--r--sound/pci/hda/patch_sigmatel.c159
-rw-r--r--sound/pci/oxygen/virtuoso.c17
10 files changed, 261 insertions, 66 deletions
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index e00421c0d8ba..960fd7970384 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -135,7 +135,6 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
struct hda_beep *beep = codec->beep;
if (beep) {
cancel_work_sync(&beep->beep_work);
- flush_scheduled_work();
input_unregister_device(beep->dev);
kfree(beep);
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index e16cf63821ae..b7bba7dc7cf1 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -373,7 +373,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
unsol->queue[wp] = res;
unsol->queue[wp + 1] = res_ex;
- schedule_work(&unsol->work);
+ queue_work(bus->workq, &unsol->work);
return 0;
}
@@ -437,15 +437,17 @@ static int snd_hda_bus_free(struct hda_bus *bus)
if (!bus)
return 0;
- if (bus->unsol) {
- flush_scheduled_work();
+ if (bus->workq)
+ flush_workqueue(bus->workq);
+ if (bus->unsol)
kfree(bus->unsol);
- }
list_for_each_entry_safe(codec, n, &bus->codec_list, list) {
snd_hda_codec_free(codec);
}
if (bus->ops.private_free)
bus->ops.private_free(bus);
+ if (bus->workq)
+ destroy_workqueue(bus->workq);
kfree(bus);
return 0;
}
@@ -485,6 +487,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card,
{
struct hda_bus *bus;
int err;
+ char qname[8];
static struct snd_device_ops dev_ops = {
.dev_register = snd_hda_bus_dev_register,
.dev_free = snd_hda_bus_dev_free,
@@ -514,6 +517,14 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card,
mutex_init(&bus->cmd_mutex);
INIT_LIST_HEAD(&bus->codec_list);
+ snprintf(qname, sizeof(qname), "hda%d", card->number);
+ bus->workq = create_workqueue(qname);
+ if (!bus->workq) {
+ snd_printk(KERN_ERR "cannot create workqueue %s\n", qname);
+ kfree(bus);
+ return -ENOMEM;
+ }
+
err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops);
if (err < 0) {
snd_hda_bus_free(bus);
@@ -684,7 +695,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
return;
#ifdef CONFIG_SND_HDA_POWER_SAVE
cancel_delayed_work(&codec->power_work);
- flush_scheduled_work();
+ flush_workqueue(codec->bus->workq);
#endif
list_del(&codec->list);
snd_array_free(&codec->mixers);
@@ -735,6 +746,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
codec->bus = bus;
codec->addr = codec_addr;
mutex_init(&codec->spdif_mutex);
+ 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 snd_kcontrol *), 32);
@@ -1272,7 +1284,7 @@ void snd_hda_codec_reset(struct hda_codec *codec)
#ifdef CONFIG_SND_HDA_POWER_SAVE
cancel_delayed_work(&codec->power_work);
- flush_scheduled_work();
+ flush_workqueue(codec->bus->workq);
#endif
snd_hda_ctls_clear(codec);
/* relase PCMs */
@@ -1418,12 +1430,12 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol,
unsigned long pval;
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
pval = kcontrol->private_value;
kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
kcontrol->private_value = pval;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get);
@@ -1435,7 +1447,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol,
unsigned long pval;
int i, indices, err = 0, change = 0;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
pval = kcontrol->private_value;
indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
for (i = 0; i < indices; i++) {
@@ -1447,7 +1459,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol,
change |= err;
}
kcontrol->private_value = pval;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err < 0 ? err : change;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put);
@@ -1462,12 +1474,12 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol,
struct hda_bind_ctls *c;
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
c = (struct hda_bind_ctls *)kcontrol->private_value;
kcontrol->private_value = *c->values;
err = c->ops->info(kcontrol, uinfo);
kcontrol->private_value = (long)c;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info);
@@ -1479,12 +1491,12 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol,
struct hda_bind_ctls *c;
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
c = (struct hda_bind_ctls *)kcontrol->private_value;
kcontrol->private_value = *c->values;
err = c->ops->get(kcontrol, ucontrol);
kcontrol->private_value = (long)c;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get);
@@ -1497,7 +1509,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol,
unsigned long *vals;
int err = 0, change = 0;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
c = (struct hda_bind_ctls *)kcontrol->private_value;
for (vals = c->values; *vals; vals++) {
kcontrol->private_value = *vals;
@@ -1507,7 +1519,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol,
change |= err;
}
kcontrol->private_value = (long)c;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err < 0 ? err : change;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put);
@@ -1519,12 +1531,12 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,
struct hda_bind_ctls *c;
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
c = (struct hda_bind_ctls *)kcontrol->private_value;
kcontrol->private_value = *c->values;
err = c->ops->tlv(kcontrol, op_flag, size, tlv);
kcontrol->private_value = (long)c;
- mutex_unlock(&codec->spdif_mutex);
+ mutex_unlock(&codec->control_mutex);
return err;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv);
@@ -2712,6 +2724,67 @@ int snd_hda_check_board_config(struct hda_codec *codec,
EXPORT_SYMBOL_HDA(snd_hda_check_board_config);
/**
+ * snd_hda_check_board_codec_sid_config - compare the current codec
+ subsystem ID with the
+ config table
+
+ This is important for Gateway notebooks with SB450 HDA Audio
+ where the vendor ID of the PCI device is:
+ ATI Technologies Inc SB450 HDA Audio [1002:437b]
+ and the vendor/subvendor are found only at the codec.
+
+ * @codec: the HDA codec
+ * @num_configs: number of config enums
+ * @models: array of model name strings
+ * @tbl: configuration table, terminated by null entries
+ *
+ * Compares the modelname or PCI subsystem id of the current codec with the
+ * given configuration table. If a matching entry is found, returns its
+ * config value (supposed to be 0 or positive).
+ *
+ * If no entries are matching, the function returns a negative value.
+ */
+int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
+ int num_configs, const char **models,
+ const struct snd_pci_quirk *tbl)
+{
+ const struct snd_pci_quirk *q;
+
+ /* Search for codec ID */
+ for (q = tbl; q->subvendor; q++) {
+ unsigned long vendorid = (q->subdevice) | (q->subvendor << 16);
+
+ if (vendorid == codec->subsystem_id)
+ break;
+ }
+
+ if (!q->subvendor)
+ return -1;
+
+ tbl = q;
+
+ if (tbl->value >= 0 && tbl->value < num_configs) {
+#ifdef CONFIG_SND_DEBUG_DETECT
+ char tmp[10];
+ const char *model = NULL;
+ if (models)
+ model = models[tbl->value];
+ if (!model) {
+ sprintf(tmp, "#%d", tbl->value);
+ model = tmp;
+ }
+ snd_printdd(KERN_INFO "hda_codec: model '%s' is selected "
+ "for config %x:%x (%s)\n",
+ model, tbl->subvendor, tbl->subdevice,
+ (tbl->name ? tbl->name : "Unknown device"));
+#endif
+ return tbl->value;
+ }
+ return -1;
+}
+EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config);
+
+/**
* snd_hda_add_new_ctls - create controls from the array
* @codec: the HDA codec
* @knew: the array of struct snd_kcontrol_new
@@ -2803,7 +2876,7 @@ void snd_hda_power_down(struct hda_codec *codec)
return;
if (power_save(codec)) {
codec->power_transition = 1; /* avoid reentrance */
- schedule_delayed_work(&codec->power_work,
+ queue_delayed_work(codec->bus->workq, &codec->power_work,
msecs_to_jiffies(power_save(codec) * 1000));
}
}
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 729fc7642d7f..5810ef588402 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -614,6 +614,7 @@ struct hda_bus {
/* unsolicited event queue */
struct hda_bus_unsolicited *unsol;
+ struct workqueue_struct *workq; /* common workqueue for codecs */
/* assigned PCMs */
DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
@@ -771,6 +772,7 @@ struct hda_codec {
struct hda_cache_rec cmd_cache; /* cache for other commands */
struct mutex spdif_mutex;
+ struct mutex control_mutex;
unsigned int spdif_status; /* IEC958 status bits */
unsigned short spdif_ctls; /* SPDIF control bits */
unsigned int spdif_in_enable; /* SPDIF input enable? */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index f04de115ee11..11e791b965f6 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -996,10 +996,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(azx_dev->substream);
spin_lock(&chip->reg_lock);
- } else {
+ } else if (chip->bus && chip->bus->workq) {
/* bogus IRQ, process it later */
azx_dev->irq_pending = 1;
- schedule_work(&chip->irq_pending_work);
+ queue_work(chip->bus->workq,
+ &chip->irq_pending_work);
}
}
}
@@ -1741,7 +1742,6 @@ static void azx_clear_irq_pending(struct azx *chip)
for (i = 0; i < chip->num_streams; i++)
chip->azx_dev[i].irq_pending = 0;
spin_unlock_irq(&chip->reg_lock);
- flush_scheduled_work();
}
static struct snd_pcm_ops azx_pcm_ops = {
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 6f2fe0f9fdd8..1dd8716c387f 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -296,6 +296,9 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen);
int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
const char **modelnames,
const struct snd_pci_quirk *pci_list);
+int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
+ int num_configs, const char **models,
+ const struct snd_pci_quirk *tbl);
int snd_hda_add_new_ctls(struct hda_codec *codec,
struct snd_kcontrol_new *knew);
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 26247cfe749d..2e7371ec2e23 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -3900,6 +3900,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = {
static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
+ SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP),
SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP),
@@ -4262,13 +4263,13 @@ static int patch_ad1882(struct hda_codec *codec)
spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
spec->adc_nids = ad1882_adc_nids;
spec->capsrc_nids = ad1882_capsrc_nids;
- if (codec->vendor_id == 0x11d1882)
+ if (codec->vendor_id == 0x11d41882)
spec->input_mux = &ad1882_capture_source;
else
spec->input_mux = &ad1882a_capture_source;
spec->num_mixers = 2;
spec->mixers[0] = ad1882_base_mixers;
- if (codec->vendor_id == 0x11d1882)
+ if (codec->vendor_id == 0x11d41882)
spec->mixers[1] = ad1882_loopback_mixers;
else
spec->mixers[1] = ad1882a_loopback_mixers;
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
index 0270fda0bda5..d57d8132a06e 100644
--- a/sound/pci/hda/patch_nvhdmi.c
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -160,14 +160,18 @@ static int patch_nvhdmi(struct hda_codec *codec)
*/
static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
{ .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi },
+ { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi },
{ .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi },
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi },
+ { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi },
{} /* terminator */
};
MODULE_ALIAS("snd-hda-codec-id:10de0002");
+MODULE_ALIAS("snd-hda-codec-id:10de0006");
MODULE_ALIAS("snd-hda-codec-id:10de0007");
MODULE_ALIAS("snd-hda-codec-id:10de0067");
+MODULE_ALIAS("snd-hda-codec-id:10de8001");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 9065ebf9c065..82dd08431970 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1502,11 +1502,11 @@ static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
struct alc_spec *spec = codec->spec;
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
HDA_INPUT);
err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
- mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_unlock(&codec->control_mutex);
return err;
}
@@ -1517,11 +1517,11 @@ static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
struct alc_spec *spec = codec->spec;
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
HDA_INPUT);
err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
- mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_unlock(&codec->control_mutex);
return err;
}
@@ -1537,11 +1537,11 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
int err;
- mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_lock(&codec->control_mutex);
kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
3, 0, HDA_INPUT);
err = func(kcontrol, ucontrol);
- mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
+ mutex_unlock(&codec->control_mutex);
return err;
}
@@ -8461,6 +8461,10 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
ALC888_ACER_ASPIRE_4930G),
+ SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
+ ALC888_ACER_ASPIRE_4930G),
+ SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
+ ALC888_ACER_ASPIRE_4930G),
SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
@@ -8522,6 +8526,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
+ SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
{}
};
@@ -10568,6 +10573,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
+ SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
@@ -11689,6 +11695,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
ALC268_ACER_ASPIRE_ONE),
SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
+ SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 35b83dc6e19e..c39deebb588f 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -55,7 +55,8 @@ enum {
STAC_9200_DELL_M25,
STAC_9200_DELL_M26,
STAC_9200_DELL_M27,
- STAC_9200_GATEWAY,
+ STAC_9200_M4,
+ STAC_9200_M4_2,
STAC_9200_PANASONIC,
STAC_9200_MODELS
};
@@ -89,14 +90,19 @@ enum {
STAC_DELL_M4_2,
STAC_DELL_M4_3,
STAC_HP_M4,
+ STAC_HP_DV5,
STAC_92HD71BXX_MODELS
};
enum {
STAC_925x_REF,
+ STAC_M1,
+ STAC_M1_2,
+ STAC_M2,
STAC_M2_2,
- STAC_MA6,
- STAC_PA6,
+ STAC_M3,
+ STAC_M5,
+ STAC_M6,
STAC_925x_MODELS
};
@@ -331,6 +337,10 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = {
0x03, 0x0c, 0x10, 0x40,
};
+static hda_nid_t stac92hd83xxx_amp_nids[1] = {
+ 0xc,
+};
+
static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
0x0a, 0x0d, 0x0f
};
@@ -875,6 +885,8 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = {
static struct hda_verb stac925x_core_init[] = {
/* set dac0mux for dac converter */
{ 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* unmute and set max the selector */
+ { 0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f },
{}
};
@@ -1334,7 +1346,16 @@ static unsigned int ref9200_pin_configs[8] = {
0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
};
-/*
+static unsigned int gateway9200_m4_pin_configs[8] = {
+ 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
+ 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
+};
+static unsigned int gateway9200_m4_2_pin_configs[8] = {
+ 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
+ 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
+};
+
+/*
STAC 9200 pin configs for
102801A8
102801DE
@@ -1464,6 +1485,8 @@ static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
[STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
[STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
[STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
+ [STAC_9200_M4] = gateway9200_m4_pin_configs,
+ [STAC_9200_M4_2] = gateway9200_m4_2_pin_configs,
[STAC_9200_PANASONIC] = ref9200_pin_configs,
};
@@ -1480,7 +1503,8 @@ static const char *stac9200_models[STAC_9200_MODELS] = {
[STAC_9200_DELL_M25] = "dell-m25",
[STAC_9200_DELL_M26] = "dell-m26",
[STAC_9200_DELL_M27] = "dell-m27",
- [STAC_9200_GATEWAY] = "gateway",
+ [STAC_9200_M4] = "gateway-m4",
+ [STAC_9200_M4_2] = "gateway-m4-2",
[STAC_9200_PANASONIC] = "panasonic",
};
@@ -1550,11 +1574,9 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = {
/* Panasonic */
SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
/* Gateway machines needs EAPD to be set on resume */
- SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
- SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
- STAC_9200_GATEWAY),
- SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
- STAC_9200_GATEWAY),
+ SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_M4),
+ SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", STAC_9200_M4_2),
+ SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", STAC_9200_M4_2),
/* OQO Mobile */
SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
{} /* terminator */
@@ -1565,44 +1587,85 @@ static unsigned int ref925x_pin_configs[8] = {
0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
};
-static unsigned int stac925x_MA6_pin_configs[8] = {
- 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
- 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
+static unsigned int stac925xM1_pin_configs[8] = {
+ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+ 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
};
-static unsigned int stac925x_PA6_pin_configs[8] = {
- 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
- 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
+static unsigned int stac925xM1_2_pin_configs[8] = {
+ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+ 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925xM2_pin_configs[8] = {
+ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+ 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
};
static unsigned int stac925xM2_2_pin_configs[8] = {
- 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
- 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
+ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+ 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925xM3_pin_configs[8] = {
+ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+ 0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3,
+};
+
+static unsigned int stac925xM5_pin_configs[8] = {
+ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+ 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925xM6_pin_configs[8] = {
+ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+ 0x40a000f0, 0x90100210, 0x400003f1, 0x90330320,
};
static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
[STAC_REF] = ref925x_pin_configs,
+ [STAC_M1] = stac925xM1_pin_configs,
+ [STAC_M1_2] = stac925xM1_2_pin_configs,
+ [STAC_M2] = stac925xM2_pin_configs,
[STAC_M2_2] = stac925xM2_2_pin_configs,
- [STAC_MA6] = stac925x_MA6_pin_configs,
- [STAC_PA6] = stac925x_PA6_pin_configs,
+ [STAC_M3] = stac925xM3_pin_configs,
+ [STAC_M5] = stac925xM5_pin_configs,
+ [STAC_M6] = stac925xM6_pin_configs,
};
static const char *stac925x_models[STAC_925x_MODELS] = {
[STAC_REF] = "ref",
+ [STAC_M1] = "m1",
+ [STAC_M1_2] = "m1-2",
+ [STAC_M2] = "m2",
[STAC_M2_2] = "m2-2",
- [STAC_MA6] = "m6",
- [STAC_PA6] = "pa6",
+ [STAC_M3] = "m3",
+ [STAC_M5] = "m5",
+ [STAC_M6] = "m6",
+};
+
+static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2),
+ SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5),
+ SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1),
+ SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_M2),
+ SND_PCI_QUIRK(0x107b, 0x0367, "Gateway MX6453", STAC_M1_2),
+ /* Not sure about the brand name for those */
+ SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M1),
+ SND_PCI_QUIRK(0x107b, 0x0507, "Gateway mobile", STAC_M3),
+ SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M6),
+ SND_PCI_QUIRK(0x107b, 0x0685, "Gateway mobile", STAC_M2_2),
+ {} /* terminator */
};
static struct snd_pci_quirk stac925x_cfg_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
- SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
- SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
- SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
- SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
- SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
+
+ /* Default table for unknown ID */
+ SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2),
+
{} /* terminator */
};
@@ -1682,7 +1745,7 @@ static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
- "DFI LanParty", STAC_92HD71BXX_REF),
+ "DFI LanParty", STAC_92HD83XXX_REF),
{} /* terminator */
};
@@ -1716,6 +1779,7 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
[STAC_DELL_M4_2] = dell_m4_2_pin_configs,
[STAC_DELL_M4_3] = dell_m4_3_pin_configs,
[STAC_HP_M4] = NULL,
+ [STAC_HP_DV5] = NULL,
};
static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
@@ -1724,6 +1788,7 @@ static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
[STAC_DELL_M4_2] = "dell-m4-2",
[STAC_DELL_M4_3] = "dell-m4-3",
[STAC_HP_M4] = "hp-m4",
+ [STAC_HP_DV5] = "hp-dv5",
};
static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
@@ -1736,6 +1801,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
"HP dv7", STAC_HP_M4),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc,
"HP dv7", STAC_HP_M4),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603,
+ "HP dv5", STAC_HP_DV5),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
"unknown HP", STAC_HP_M4),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
@@ -4163,8 +4230,19 @@ static void stac92xx_hp_detect(struct hda_codec *codec)
continue;
if (presence)
stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
+#if 0 /* FIXME */
+/* Resetting the pinctl like below may lead to (a sort of) regressions
+ * on some devices since they use the HP pin actually for line/speaker
+ * outs although the default pin config shows a different pin (that is
+ * wrong and useless).
+ *
+ * So, it's basically a problem of default pin configs, likely a BIOS issue.
+ * But, disabling the code below just works around it, and I'm too tired of
+ * bug reports with such devices...
+ */
else
stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
+#endif /* FIXME */
}
}
@@ -4390,7 +4468,8 @@ static int patch_stac9200(struct hda_codec *codec)
spec->num_adcs = 1;
spec->num_pwrs = 0;
- if (spec->board_config == STAC_9200_GATEWAY ||
+ if (spec->board_config == STAC_9200_M4 ||
+ spec->board_config == STAC_9200_M4_2 ||
spec->board_config == STAC_9200_OQO)
spec->init = stac9200_eapd_init;
else
@@ -4408,6 +4487,12 @@ static int patch_stac9200(struct hda_codec *codec)
return err;
}
+ /* CF-74 has no headphone detection, and the driver should *NOT*
+ * do detection and HP/speaker toggle because the hardware does it.
+ */
+ if (spec->board_config == STAC_9200_PANASONIC)
+ spec->hp_detect = 0;
+
codec->patch_ops = stac92xx_patch_ops;
return 0;
@@ -4425,12 +4510,22 @@ static int patch_stac925x(struct hda_codec *codec)
codec->spec = spec;
spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
spec->pin_nids = stac925x_pin_nids;
- spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
+
+ /* Check first for codec ID */
+ spec->board_config = snd_hda_check_board_codec_sid_config(codec,
+ STAC_925x_MODELS,
+ stac925x_models,
+ stac925x_codec_id_cfg_tbl);
+
+ /* Now checks for PCI ID, if codec ID is not found */
+ if (spec->board_config < 0)
+ spec->board_config = snd_hda_check_board_config(codec,
+ STAC_925x_MODELS,
stac925x_models,
stac925x_cfg_tbl);
again:
if (spec->board_config < 0) {
- snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
+ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
"using BIOS defaults\n");
err = stac92xx_save_bios_config_regs(codec);
} else
@@ -4672,6 +4767,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
spec->dmux_nids = stac92hd83xxx_dmux_nids;
spec->adc_nids = stac92hd83xxx_adc_nids;
spec->pwr_nids = stac92hd83xxx_pwr_nids;
+ spec->amp_nids = stac92hd83xxx_amp_nids;
spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
spec->multiout.dac_nids = spec->dac_nids;
@@ -4689,6 +4785,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
+ spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids);
spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
spec->dinput_mux = &stac92hd83xxx_dmux;
spec->pin_nids = stac92hd83xxx_pin_nids;
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 98c6a8c65d81..e9e829e83d7a 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -26,7 +26,7 @@
* SPI 0 -> 1st PCM1796 (front)
* SPI 1 -> 2nd PCM1796 (surround)
* SPI 2 -> 3rd PCM1796 (center/LFE)
- * SPI 4 -> 4th PCM1796 (back)
+ * SPI 4 -> 4th PCM1796 (back) and EEPROM self-destruct (do not use!)
*
* GPIO 2 -> M0 of CS5381
* GPIO 3 -> M1 of CS5381
@@ -207,6 +207,12 @@ static void xonar_gpio_changed(struct oxygen *chip);
static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
u8 reg, u8 value)
{
+ /*
+ * We don't want to do writes on SPI 4 because the EEPROM, which shares
+ * the same pin, might get confused and broken. We'd better take care
+ * that the driver works with the default register values ...
+ */
+#if 0
/* maps ALSA channel pair number to SPI output */
static const u8 codec_map[4] = {
0, 1, 2, 4
@@ -217,6 +223,7 @@ static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
(codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
(reg << 8) | value);
+#endif
}
static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
@@ -750,6 +757,9 @@ static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -12700, 100, 0);
static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
{
+ if (!strncmp(template->name, "Master Playback ", 16))
+ /* disable volume/mute because they would require SPI writes */
+ return 1;
if (!strncmp(template->name, "CD Capture ", 11))
/* CD in is actually connected to the video in pin */
template->private_value ^= AC97_CD ^ AC97_VIDEO;
@@ -840,9 +850,8 @@ static const struct oxygen_model model_xonar_d2 = {
.dac_volume_min = 0x0f,
.dac_volume_max = 0xff,
.misc_flags = OXYGEN_MISC_MIDI,
- .function_flags = OXYGEN_FUNCTION_SPI |
- OXYGEN_FUNCTION_ENABLE_SPI_4_5,
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .function_flags = OXYGEN_FUNCTION_SPI,
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};