My codec has a beep-generating node:
$ cat /proc/asound/card1/codec#0 Codec: VIA VT1802 ... Vendor Id: 0x11068446 Subsystem Id: 0x15587410 Revision Id: 0x100000 ... Node 0x22 [Beep Generator Widget] wcaps 0x70040c: Mono Amp-Out Amp-Out caps: ofs=0x0a, nsteps=0x12, stepsize=0x05, mute=1 Amp-Out vals: [0x0a] Power states: D0 D1 D2 D3 Power: setting=D0, actual=D0 ...
But I was missing the:
Control: name=...
entries that I need to manage this widget from alsamixer. With this patch (based on the similar Mono Amp-Out handling in patch_conexant.c), I get a new:
input: HDA Digital PCBeep as /devices/pci0000:00/0000:00:1b.0/sound/card1/hdaudioC1D0/input15
entry in dmesg and controls to manage that beep:
$ cat /proc/asound/card1/codec#0 | grep -A5 Beep Node 0x22 [Beep Generator Widget] wcaps 0x70040c: Mono Amp-Out Control: name="Beep Playback Volume", index=0, device=0 ControlAmp: chs=1, dir=Out, idx=0, ofs=0 Control: name="Beep Playback Switch", index=0, device=0 ControlAmp: chs=1, dir=Out, idx=0, ofs=0 Amp-Out caps: ofs=0x0a, nsteps=0x12, stepsize=0x05, mute=1 Amp-Out vals: [0x12] Power states: D0 D1 D2 D3 Power: setting=D0, actual=D0
Signed-off-by: W. Trevor King wking@tremily.us --- On Sun, Mar 22, 2015 at 09:27:24PM +0800, Raymond Yau wrote:
Why beep generator cannot automically found by auto parser ? … 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); if (wid_type == AC_WID_BEEP) spec->gen.beep_nid = nid; }
This is pretty much what patch_conexant.c's cx_auto_parse_beep() does, so I've just shifted that code over here to handle beeps in VIA codecs. It works on my VT1802, but I don't have any other VIA codecs around to check that it works on all of the VIA codecs (Takashi pointed out that they can be buggy [1]). Do I need to shift the auto_parse_beep() check into the VT1802-specific portion of patch_vt2002P(), or can I leave it here in the generic via_parse_auto_config()? Alternatively, we could wedge it into via_new_spec(), which would give the per-codec patches time to clear spec->gen.beep_nid for broken codecs before via_parse_auto_config() calls snd_hda_gen_parse_auto_config() which consumes beep_nid.
Cheers, Trevor
[1]: id:s5hpp813vva.wl-tiwai@suse.de http://thread.gmane.org/gmane.linux.alsa.devel/135819/focus=135823
sound/pci/hda/patch_via.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 3de6d3d..e4919f8 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -109,6 +109,8 @@ struct via_spec { int hp_work_active; int vt1708_jack_detect;
+ unsigned int beep_amp; + void (*set_widgets_power_state)(struct hda_codec *codec); unsigned int dac_stream_tag[4]; }; @@ -355,6 +357,59 @@ static const struct snd_kcontrol_new via_pin_power_ctl_enum[] = { {} /* terminator */ };
+#ifdef CONFIG_SND_HDA_INPUT_BEEP +static inline void set_beep_amp(struct via_spec *spec, hda_nid_t nid, + int idx, int dir) +{ + spec->gen.beep_nid = nid; + spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); +} +/* additional beep mixers; the actual parameters are overwritten at build */ +static const struct snd_kcontrol_new cxt_beep_mixer[] = { + HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), + { } /* end */ +}; + +/* create beep controls if needed */ +static int add_beep_ctls(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + if (spec->beep_amp) { + const struct snd_kcontrol_new *knew; + for (knew = cxt_beep_mixer; knew->name; knew++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); + if (err < 0) + return err; + } + } + return 0; +} + +static void auto_parse_beep(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + hda_nid_t nid, end_nid; + + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) + if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) { + set_beep_amp(spec, nid, 0, HDA_OUTPUT); + break; + } +} +#else +#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#define add_beep_ctls(codec) 0 +#define auto_parse_beep(codec) +#endif
/* check AA path's mute status */ static bool is_aa_path_mute(struct hda_codec *codec) @@ -441,6 +496,10 @@ static int via_build_controls(struct hda_codec *codec) if (err < 0) return err;
+ err = add_beep_ctls(codec); + if (err < 0) + return err; + if (spec->set_widgets_power_state) spec->mixers[spec->num_mixers++] = via_pin_power_ctl_enum;
@@ -631,6 +690,8 @@ static int via_parse_auto_config(struct hda_codec *codec) if (err < 0) return err;
+ auto_parse_beep(codec); + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) return err;