From patchwork Thu Nov 10 18:21:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Jordan X-Patchwork-Id: 81751 Delivered-To: patch@linaro.org Received: by 10.182.1.168 with SMTP id 8csp1060249obn; Thu, 10 Nov 2016 11:03:01 -0800 (PST) X-Received: by 10.194.176.162 with SMTP id cj2mr5650755wjc.25.1478804581326; Thu, 10 Nov 2016 11:03:01 -0800 (PST) Return-Path: Received: from alsa0.perex.cz (alsa0.perex.cz. [77.48.224.243]) by mx.google.com with ESMTP id u15si14279787wmu.53.2016.11.10.11.03.00; Thu, 10 Nov 2016 11:03:01 -0800 (PST) Received-SPF: pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) client-ip=77.48.224.243; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@messagingengine.com; spf=pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 1EDA426739E; Thu, 10 Nov 2016 20:03:00 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail1.perex.cz X-Spam-Level: X-Spam-Status: No, score=0.1 required=5.0 tests=DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, T_DKIM_INVALID autolearn=disabled version=3.4.0 Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 7239526692B; Thu, 10 Nov 2016 20:00:36 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 606AF266998; Thu, 10 Nov 2016 19:21:34 +0100 (CET) Received: from out4-smtp.messagingengine.com (out4-smtp.messagingengine.com [66.111.4.28]) by alsa0.perex.cz (Postfix) with ESMTP id 545ED26647B for ; Thu, 10 Nov 2016 19:21:31 +0100 (CET) Received: from compute6.internal (compute6.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 48BBB22017; Thu, 10 Nov 2016 13:21:31 -0500 (EST) Received: from web2 ([10.202.2.212]) by compute6.internal (MEProxy); Thu, 10 Nov 2016 13:21:31 -0500 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-sender:x-me-sender:x-sasl-enc; s=smtpout; bh=CN MqvG6s08TyLnRFtTVpzGYaCdU=; b=qESpRiOm55sZAwBHauqgF8yKnt9sGCy95d 2kMxKUjjHHVzs6LfxWubAQsNqutLrf4XTQ4NssaWXik5MAz9XobfoeW4f4yI041D lzjeNE2AmbMkZx5/g7uAcjvSxik9tuOlBFA/vgfxFz3c/GCKQ+qiVyC/zkxbLZgx y0yA+ptlw= X-ME-Sender: Received: by mailuser.nyi.internal (Postfix, from userid 99) id 1F6C1626B6; Thu, 10 Nov 2016 13:21:31 -0500 (EST) Message-Id: <1478802091.454740.783828673.10EC9220@webmail.messagingengine.com> From: David Jordan To: Takashi Iwai MIME-Version: 1.0 X-Mailer: MessagingEngine.com Webmail Interface - ajax-d68eb56e In-Reply-To: References: <1478537979.2123627.780087305.7503B79D@webmail.messagingengine.com> <63dfc720-71c9-9556-61cc-9fec629ddef5@ladisch.de> <1478554581.3026158.780400457.4CB1BFD6@webmail.messagingengine.com> Date: Thu, 10 Nov 2016 10:21:31 -0800 Cc: alsa-devel@alsa-project.org, Clemens Ladisch Subject: Re: [alsa-devel] Fixup set PCM/headphones volume from Master X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org I've attached the patch I've been working with. -- David Jordan david2@system76.com 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@system76.com > > > > 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@alsa-project.org > > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel > > _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org 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 #include #include +#include #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"}, {} };