diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-03-10 09:30:40 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-03-10 10:13:17 -0400 |
commit | dd5746a85cb21ea5b3afca0b569586a05aa56846 (patch) | |
tree | 56efed83d982a2176b2c4826e9a3c42e5693ea0d /sound/pci | |
parent | 6dfc0d2c4b9a5455c60e0b9ee95bbf22fc516cef (diff) |
ALSA: hda - Create vmaster for conexant codecs
Instead of binding volumes, create a virtual master volume for Conexant
codecs. This allows separate HP and speaker volume controls.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 47 |
1 files changed, 36 insertions, 11 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 1938e92e1f03..e1476d6d8b39 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -58,6 +58,7 @@ struct conexant_spec { | |||
58 | 58 | ||
59 | struct snd_kcontrol_new *mixers[5]; | 59 | struct snd_kcontrol_new *mixers[5]; |
60 | int num_mixers; | 60 | int num_mixers; |
61 | hda_nid_t vmaster_nid; | ||
61 | 62 | ||
62 | const struct hda_verb *init_verbs[5]; /* initialization verbs | 63 | const struct hda_verb *init_verbs[5]; /* initialization verbs |
63 | * don't forget NULL | 64 | * don't forget NULL |
@@ -462,6 +463,18 @@ static void conexant_free(struct hda_codec *codec) | |||
462 | kfree(codec->spec); | 463 | kfree(codec->spec); |
463 | } | 464 | } |
464 | 465 | ||
466 | static const char *slave_vols[] = { | ||
467 | "Headphone Playback Volume", | ||
468 | "Speaker Playback Volume", | ||
469 | NULL | ||
470 | }; | ||
471 | |||
472 | static const char *slave_sws[] = { | ||
473 | "Headphone Playback Switch", | ||
474 | "Speaker Playback Switch", | ||
475 | NULL | ||
476 | }; | ||
477 | |||
465 | static int conexant_build_controls(struct hda_codec *codec) | 478 | static int conexant_build_controls(struct hda_codec *codec) |
466 | { | 479 | { |
467 | struct conexant_spec *spec = codec->spec; | 480 | struct conexant_spec *spec = codec->spec; |
@@ -489,6 +502,26 @@ static int conexant_build_controls(struct hda_codec *codec) | |||
489 | if (err < 0) | 502 | if (err < 0) |
490 | return err; | 503 | return err; |
491 | } | 504 | } |
505 | |||
506 | /* if we have no master control, let's create it */ | ||
507 | if (spec->vmaster_nid && | ||
508 | !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
509 | unsigned int vmaster_tlv[4]; | ||
510 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||
511 | HDA_OUTPUT, vmaster_tlv); | ||
512 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
513 | vmaster_tlv, slave_vols); | ||
514 | if (err < 0) | ||
515 | return err; | ||
516 | } | ||
517 | if (spec->vmaster_nid && | ||
518 | !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
519 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
520 | NULL, slave_sws); | ||
521 | if (err < 0) | ||
522 | return err; | ||
523 | } | ||
524 | |||
492 | return 0; | 525 | return 0; |
493 | } | 526 | } |
494 | 527 | ||
@@ -1182,16 +1215,6 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
1182 | return 1; | 1215 | return 1; |
1183 | } | 1216 | } |
1184 | 1217 | ||
1185 | /* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */ | ||
1186 | static struct hda_bind_ctls cxt5047_bind_master_vol = { | ||
1187 | .ops = &snd_hda_bind_vol, | ||
1188 | .values = { | ||
1189 | HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), | ||
1190 | HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), | ||
1191 | 0 | ||
1192 | }, | ||
1193 | }; | ||
1194 | |||
1195 | /* mute internal speaker if HP is plugged */ | 1218 | /* mute internal speaker if HP is plugged */ |
1196 | static void cxt5047_hp_automute(struct hda_codec *codec) | 1219 | static void cxt5047_hp_automute(struct hda_codec *codec) |
1197 | { | 1220 | { |
@@ -1311,7 +1334,8 @@ static struct snd_kcontrol_new cxt5047_toshiba_mixers[] = { | |||
1311 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), | 1334 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), |
1312 | HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), | 1335 | HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), |
1313 | HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), | 1336 | HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), |
1314 | HDA_BIND_VOL("Master Playback Volume", &cxt5047_bind_master_vol), | 1337 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), |
1338 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x00, HDA_OUTPUT), | ||
1315 | { | 1339 | { |
1316 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1340 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1317 | .name = "Master Playback Switch", | 1341 | .name = "Master Playback Switch", |
@@ -1631,6 +1655,7 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1631 | codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; | 1655 | codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; |
1632 | #endif | 1656 | #endif |
1633 | } | 1657 | } |
1658 | spec->vmaster_nid = 0x13; | ||
1634 | return 0; | 1659 | return 0; |
1635 | } | 1660 | } |
1636 | 1661 | ||