I've attached the patch I've been working with. -- David Jordan david2@xxxxxxxxxxxx On Tue, Nov 8, 2016, at 06:42 AM, Takashi Iwai wrote: > On Mon, 07 Nov 2016 22:36:21 +0100, > David Jordan wrote: > > > > It's HDA, Realtek ALC898. The headphones jack (analog 3.5mm output) > > (0x1b) is connected to a separate ESS DAC, which takes sound input from > > the PCM SPDIF output. > > Note that the "Master" volume is a vmaster control, and usually it > covers all DAC volume controls. > > It'd be better if you provide a patch you're fighting with, together > with alsa-info.sh output. Then other people can track the issue > either with the real h/w or hda-emu. > > > Takashi > > > > > > -- > > David Jordan > > david2@xxxxxxxxxxxx > > > > On Mon, Nov 7, 2016, at 01:19 PM, Clemens Ladisch wrote: > > > David Jordan wrote: > > > > I'm working on a kernel-level fixup for a set of hardware > > > > > > What hardware? If HDA, which codec, and how is it connected? > > > > > > > > > Regards, > > > Clemens > > _______________________________________________ > > Alsa-devel mailing list > > Alsa-devel@xxxxxxxxxxxxxxxx > > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel > >
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4b6d861..4419a7e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -32,6 +32,7 @@ #include <linux/input.h> #include <sound/core.h> #include <sound/jack.h> +#include <sound/tlv.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" @@ -128,6 +129,14 @@ struct alc_spec { unsigned int coef0; struct input_dev *kb_dev; u8 alc_mute_keycode_map[1]; + + /* for clevo headphones fix */ + unsigned int hp_volume; + unsigned int num_inits; + struct snd_kcontrol *master_kctl; + struct snd_kcontrol *pcm_kctl; + struct snd_kcontrol embedded_pcm_kctl; +/* struct snd_kcontrol *master_kctl;*/ }; /* @@ -1797,6 +1806,7 @@ enum { ALC882_FIXUP_NO_PRIMARY_HP, ALC887_FIXUP_ASUS_BASS, ALC887_FIXUP_BASS_CHMAP, + ALC898_FIXUP_CLEVO_SPDIF, }; static void alc889_fixup_coef(struct hda_codec *codec, @@ -1956,6 +1966,205 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec, } } + + + + +/* Set PCM volume from Master. HP volume is based on PCM volume exclusively. + * TODO: Trigger this function on Master Volume Change. + * TODO: Ensure appropriate scaling of PCM levels relative to Master. + */ + +#define CLEVO_PCM_MAX_VOLUME 31 + +static int snd_clevo_pcm_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + + printk("SYS76: snd_clevo_pcm_volume_info\n"); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = CLEVO_PCM_MAX_VOLUME; + return 0; +} + +static int snd_clevo_pcm_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + printk("SYS76: snd_clevo_pcm_volume_get\n"); + struct hda_codec *chip = snd_kcontrol_chip(kcontrol); + unsigned int idx = kcontrol->id.subdevice; + + + struct alc_spec *spec = chip->spec; + + printk("SYS76: pcm_volume get...addrs\n"); + printk("addr spec %lu \n", spec); + printk("addr codec %lu \n", chip); + printk("spec->hp_volume %u\n", spec->hp_volume); + + if (spec != 0) { + printk("meep!\n"); + ucontrol->value.integer.value[0] = CLEVO_PCM_MAX_VOLUME - spec->hp_volume;//chip->playback_volume[idx][0]; + ucontrol->value.integer.value[1] = CLEVO_PCM_MAX_VOLUME - spec->hp_volume;//chip->playback_volume[idx][1]; + } + else { + printk("leep!\n"); + ucontrol->value.integer.value[0] = CLEVO_PCM_MAX_VOLUME - 1;//chip->playback_volume[idx][0]; + ucontrol->value.integer.value[1] = CLEVO_PCM_MAX_VOLUME - 1;//chip->playback_volume[idx][1]; + } + return 0; +} + +//Okay, so this is creating the pcm_volume_ctl, but how is hard? +static int snd_clevo_pcm_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *chip = snd_kcontrol_chip(kcontrol); + unsigned int idx; + unsigned char val; + int i, change = 0; + + printk("SYS76: snd_clevo_pcm_volume_put\n"); + + struct alc_spec *spec = chip->spec; + struct snd_card *card = chip->card; + + printk(kcontrol->id.name); + + + /* */ +/* struct snd_ctl_elem_id pcm_id;*/ +/* struct snd_kcontrol *pcm_control;*/ +/* memset(&pcm_id, 0, sizeof(pcm_id));*/ +/* pcm_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;*/ +/* pcm_id.device = 0;*/ +/* pcm_id.index = 0;*/ +/* strcpy(pcm_id.name, "PCM Playback Volume");*/ +/* Crashes Here:*/ +/* pcm_control = snd_ctl_find_id(chip->card, &pcm_id);*/ +/* */ + + printk("SYS76: PUT snd before find mixer ctl\n"); + +/* Get the PCM Control to set it. For some reason this fails.*/ + struct snd_kcontrol * pcm_kctl = snd_hda_find_mixer_ctl(chip, "PCM Playback Volume"); + struct snd_ctl_elem_value *pcm_uctl; + + printk("SYS76: PUT snd_hda_find_mixer_ctl\n"); + + if (!pcm_kctl) + printk("SYS76: PUT no kctl\n"); + return; + pcm_uctl = kzalloc(sizeof(*pcm_uctl), GFP_KERNEL); + if (!pcm_uctl) + return; + +/* Set the PCM ucontrol from Master ucontrol*/ + val = ucontrol->value.integer.value[0]; + val &= HDA_AMP_VOLMASK; + + pcm_uctl->value.integer.value[0] = val; + pcm_uctl->value.integer.value[1] = val; + pcm_kctl->put(pcm_kctl, pcm_uctl); + + kfree(pcm_uctl); + + return change; +} + + +static void alc898_clevo_automute_hook(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + int val; + snd_hda_codec_write(codec, codec->core.afg, 0, + AC_VERB_SET_GPIO_MASK, 2); + snd_hda_codec_write(codec, codec->core.afg, 0, + AC_VERB_SET_GPIO_DIRECTION, 0); + + struct alc_spec *spec = codec->spec; + + if (snd_hda_jack_detect(codec, 0x1b) && (snd_hda_codec_read(codec, codec->core.afg, 0, + AC_VERB_GET_GPIO_DATA, 0) >= 0)) { + val = snd_hda_codec_get_pin_target(codec, 0x1b); + val |= AC_PINCTL_VREF_80; + snd_hda_set_pin_ctl(codec, 0x1b, val); + snd_hda_gen_hp_automute(codec, jack); + } else { + printk("S76: automute case B\n"); + val = snd_hda_codec_get_pin_target(codec, 0x1b); + val = val & 0xfff8; + snd_hda_set_pin_ctl(codec, 0x1b, val); + snd_hda_gen_hp_automute(codec, jack); + + /* Don't mute the digital output, needed for ESS DAC operation */ + /* TODO: This might belong in alc898_fixup_clevo instead. */ + /* struct snd_kcontrol *kctl; + kctl = snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch"); + if (!kctl) + return; + kctl->put = NULL; */ + + } +} +static void alc898_fixup_clevo(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + printk("SYS76: version 0020\n"); + printk("SYS76: num_mixers = %u\n", spec->num_mixers); + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.detect_hp = 1; + spec->gen.automute_speaker = 1; + spec->gen.autocfg.hp_pins[0] = 0x1b; /* copy it for automute */ + snd_hda_jack_detect_enable_callback(codec, 0x1b, + alc898_clevo_automute_hook); + spec->gen.hp_automute_hook = alc898_clevo_automute_hook; + } + + + struct snd_ctl_elem_id mid; + memset(&mid, 0, sizeof(mid)); + strcpy(mid.name, "PCM Playback Volume"); + mid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + struct snd_kcontrol * pcm_kcontrol; + pcm_kcontrol = snd_ctl_find_id(codec->card, &mid); + if (!pcm_kcontrol) { + printk("SYS76: No PCM_kcontrol\n"); + printk("SYS76: oh well\n"); + return; //returning so we don't do the master stuff until pcm exists...maybe fix kernel panic this way + } + else { + spec->pcm_kctl = pcm_kcontrol; + spec->embedded_pcm_kctl = *pcm_kcontrol; + printk("MY PCM NUMID IS: %x", pcm_kcontrol->id.numid); + } + + struct snd_ctl_elem_id sid; + memset(&sid, 0, sizeof(sid)); + strcpy(sid.name, "Master Playback Volume"); + sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + struct snd_kcontrol * newsid; + //huh, find_id and find_numid are different...look into this + newsid = snd_ctl_find_id(codec->card, &sid); + if (!newsid) { + printk("SYS76: No PCM Playback Volume ctl\n"); + //Now try *replacing* the headphone control instead of adding another + //the snd_ctl_activate function is interesting maybe? + //snd_ctl_replace(codec->card, snd_ctl_new1(&snd_clevo_pcm_volume_control, codec), 0); + } + else { + printk("SYS76: PCM Playback Volume ctl id is %d\n", newsid->id.numid); + newsid->put = snd_clevo_pcm_volume_put; + printk("SYS76: My ID hahaha!\n"); + } +} + + static void alc_fixup_bass_chmap(struct hda_codec *codec, const struct hda_fixup *fix, int action); @@ -2195,6 +2404,10 @@ static const struct hda_fixup alc882_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_bass_chmap, }, + [ALC898_FIXUP_CLEVO_SPDIF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc898_fixup_clevo, + }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -2264,6 +2477,41 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), + SND_PCI_QUIRK(0x1558, 0x0872, "Clevo P870DM2/P870DM3", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x0873, "Clevo P870DM2-G/P870DM3-G", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x0874, "Clevo P870DM2-G/P870DM3-G", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x0875, "Clevo P870KM/P870KM1", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x0876, "Clevo P870KM-G/P870KM1_G", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x65a1, "Clevo P65xHS_HP-D0", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x65a2, "Clevo P65xHS_HP-D", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x65a3, "Clevo P65xHS_HP-G0", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x65a4, "Clevo P65xHS_HP-G", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x67a1, "Clevo P67xHS_HP-D0", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x67a2, "Clevo P67xHS_HP-D", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x67a3, "Clevo P67xHS_HP-G0", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x67a4, "Clevo P67xHS_HP-G", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6a01, "Clevo P65xRS_RP-D0", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6a02, "Clevo P65xRS_RP-D", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6a03, "Clevo P65xRS_RP-G0", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6a04, "Clevo P65xRS_RP-G", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6a05, "Clevo P65xRS_RP-V", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6a06, "Clevo P65xRS_RP-Direct", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6b01, "Clevo P67xRS_RP-D0", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6b02, "Clevo P67xRS_RP-D", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6b03, "Clevo P67xRS_RP-G0", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6b04, "Clevo P67xRS_RP-G", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6b05, "Clevo P67xRS_RP-V", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6b06, "Clevo P67xRS_RP-Direct", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x7504, "Clevo P750DM2", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x7505, "Clevo P750DM2G", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x7506, "Clevo P750KM", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x7507, "Clevo P750KMG", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x7705, "Clevo P775DM2", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x7706, "Clevo P775DM2G", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x7707, "Clevo P775KM", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x7708, "Clevo P775KMG", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x7705, "System76 serw10", ALC898_FIXUP_CLEVO_SPDIF), + SND_PCI_QUIRK(0x1558, 0x6b01, "System76 oryp2-ess", ALC898_FIXUP_CLEVO_SPDIF), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530), @@ -2277,6 +2525,7 @@ static const struct hda_model_fixup alc882_fixup_models[] = { {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"}, {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"}, + {.id = ALC898_FIXUP_CLEVO_SPDIF, .name = "system76"}, {} };
_______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel