From patchwork Thu Oct 16 18:02:17 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Lutomirski X-Patchwork-Id: 5093121 X-Patchwork-Delegate: tiwai@suse.de Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id A96949F3ED for ; Thu, 16 Oct 2014 18:03:11 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A25F7201F5 for ; Thu, 16 Oct 2014 18:03:10 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 3F47A201FA for ; Thu, 16 Oct 2014 18:03:08 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 226DF2605EF; Thu, 16 Oct 2014 20:03:07 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 8712D2605FA; Thu, 16 Oct 2014 20:02:41 +0200 (CEST) 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 A93C026063D; Thu, 16 Oct 2014 20:02:39 +0200 (CEST) Received: from mail-pd0-f176.google.com (mail-pd0-f176.google.com [209.85.192.176]) by alsa0.perex.cz (Postfix) with ESMTP id 4CBCF2605F6 for ; Thu, 16 Oct 2014 20:02:31 +0200 (CEST) Received: by mail-pd0-f176.google.com with SMTP id fp1so3640746pdb.7 for ; Thu, 16 Oct 2014 11:02:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=dI+ceaopBnvpbwhcTYsBrnRvv4bflCyNhnRJNPSa+ag=; b=Se7lJ07a0tMmBL7YCDv0qjfIgCdLpz85wlauwTc1xYCnMQBkUqMh31I8iiPXnrEiTt Zs+fgJseJSxiL2zIKgSh4fDca/Rthxm6CDrblMUV2fV+vpKubycvWpLkeQvX7sdtrKLV ibQqxqtRld5BvZjdNs7E0l/8ZfY7u34fmvbN7ST7b1H/6sTdm1cP6tOYjgfRJ0RcmtcL nWCz1p5ZF4swrCGwvKzBYOInw+Dl+5aDCxP6iZC36OdvrdSCv7XXHIWdM2kjrCkGh2sy aovp1BT6IguuJR1BCtMr64qFwLlHJflPFRcEzJvHtQE5rtvaO5D7Hz2XTnZn3k75ICne fGSg== X-Gm-Message-State: ALoCoQlLySEy5wgIvOeKaMrSEFzgxXgUnKkZ4yVlg2VjNTQCgUb5jeZPQpRLnzsgBCXTHZY7dsWe X-Received: by 10.66.180.166 with SMTP id dp6mr2868520pac.101.1413482550313; Thu, 16 Oct 2014 11:02:30 -0700 (PDT) Received: from localhost ([2001:5a8:4:83c0:2876:faf2:b8dc:60f7]) by mx.google.com with ESMTPSA id qx4sm20338879pbc.14.2014.10.16.11.02.27 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 16 Oct 2014 11:02:29 -0700 (PDT) From: Andy Lutomirski To: Henrique de Moraes Holschuh , Matthew Garrett , ibm-acpi-devel@lists.sourceforge.net Date: Thu, 16 Oct 2014 11:02:17 -0700 Message-Id: <72f375b46a34702fc9f8be419fa83c219fbc28c5.1413481880.git.luto@amacapital.net> X-Mailer: git-send-email 1.9.3 In-Reply-To: References: In-Reply-To: References: Cc: Len Brown , ALSA development , Takashi Iwai , Grant Diffey , platform-driver-x86@vger.kernel.org, Andy Lutomirski , Jerone Young , David Henningsson Subject: [alsa-devel] [PATCH 1/2] thinkpad-acpi: Try to use full software mute control 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: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP From: Andy Lutomirski ThinkPads have hardware volume controls and three buttons to control them. (These are separate from the standard mixer.) By default, the buttons are: - Mute: Mutes the hardware volume control and generates KEY_MUTE. - Up: Unmutes, generates KEY_VOLUMEUP, and increases volume if applicable. (Newer thinkpads only have hardware mute/unmute.) - Down: Unmutes, generates KEY_VOLUMEDOWN, and decreases volume if applicable. This behavior is unfortunate, since modern userspace will also handle the hotkeys and change the other mixer. If the software mixer is muted and the hardware mixer is unmuted and you push mute, hilarity ensues as they both switch state. Rather than adding a lot of complex ALSA integration to fix this, just disable the special ThinkPad volume controls when possible. This turns the mute and volume buttons into regular buttons, and standard software controls will work as expected. ALSA already knows about the mute light on models with a mute light, so everything should just work. This should also allow us to remove _OSI(Linux) for all ThinkPads. For future reference: It turns out that we can ask ACPI for one of three behaviors directly on very new models. They are "latch" (the default), "none" (no automatic control), and "toggle" (mute unmutes when muted). All of the modes besides "none" seem to be a bit buggy, though, and there is no known way to get any notification that the hardware state has changed other than listening for a mute button press on the i8042 port. Signed-off-by: Andy Lutomirski --- drivers/platform/x86/thinkpad_acpi.c | 107 +++++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 3bbc6eb60de5..9c8e17ec4b14 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6559,6 +6559,16 @@ static struct ibm_struct brightness_driver_data = { * bits 3-0 (volume). Other bits in NVRAM may have other functions, * such as bit 7 which is used to detect repeated presses of MUTE, * and we leave them unchanged. + * + * The EC or perhaps SMM firmware can optionally automatically change + * the volume in response to user input. Unfortunately, this rarely + * works well. The laptop changes the state of its internal MUTE gate + * *and* sends KEY_MUTE, causing any user code that responds to the mute + * button to get confused. The hardware MUTE gate is also unnecessary, + * since user code can handle the mute button without kernel or EC help. + * + * To avoid confusing userspace, we simply disable all EC-based mute + * and volume controls when possible. */ #ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT @@ -6613,11 +6623,20 @@ enum tpacpi_volume_capabilities { TPACPI_VOL_CAP_MAX }; +enum tpacpi_mute_btn_mode { + TP_EC_MUTE_BTN_LATCH = 0, /* Mute mutes; up/down unmutes */ + /* We don't know what mode 1 is. */ + TP_EC_MUTE_BTN_NONE = 2, /* Mute and up/down are just keys */ + TP_EC_MUTE_BTN_TOGGLE = 3, /* Mute toggles; up/down unmutes */ +}; + static enum tpacpi_volume_access_mode volume_mode = TPACPI_VOL_MODE_MAX; static enum tpacpi_volume_capabilities volume_capabilities; static bool volume_control_allowed; +static bool software_mute_requested = true; +static bool software_mute_active; /* * Used to syncronize writers to TP_EC_AUDIO and @@ -6635,6 +6654,8 @@ static void tpacpi_volume_checkpoint_nvram(void) return; if (!volume_control_allowed) return; + if (software_mute_active) + return; vdbg_printk(TPACPI_DBG_MIXER, "trying to checkpoint mixer state to NVRAM...\n"); @@ -6696,6 +6717,12 @@ static int volume_set_status_ec(const u8 status) dbg_printk(TPACPI_DBG_MIXER, "set EC mixer to 0x%02x\n", status); + /* + * On X200s, and possibly on others, it can take a while for + * reads to become correct. + */ + msleep(1); + return 0; } @@ -6778,6 +6805,38 @@ unlock: return rc; } +static int volume_set_software_mute(bool verbose) +{ + int rc = 0; + int result; + + if (mutex_lock_killable(&volume_mutex) < 0) + return -EINTR; + + if (verbose) { + if (!acpi_evalf(ec_handle, &result, "HAUM", "qd")) + return -EIO; + + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, + "Initial HAUM setting was %d\n", + result); + } + + if (!acpi_evalf(ec_handle, &result, "SAUM", "qdd", + (int)TP_EC_MUTE_BTN_NONE)) { + rc = -EIO; + goto out; + } + + if (result != TP_EC_MUTE_BTN_NONE) + pr_warn("thinkpad_acpi: Unexpected SAUM result %d\n", + result); + +out: + mutex_unlock(&volume_mutex); + return rc; +} + static int volume_alsa_set_volume(const u8 vol) { dbg_printk(TPACPI_DBG_MIXER, @@ -6885,7 +6944,12 @@ static void volume_suspend(void) static void volume_resume(void) { - volume_alsa_notify_change(); + if (software_mute_active) { + if (volume_set_software_mute(false) < 0) + pr_warn("thinkpad_acpi: failed to restore software mute\n"); + } else { + volume_alsa_notify_change(); + } } static void volume_shutdown(void) @@ -7004,6 +7068,8 @@ static const struct tpacpi_quirk volume_quirk_table[] __initconst = { .quirks = TPACPI_VOL_Q_MUTEONLY } }; +static int volume_write(char *buf); + static int __init volume_init(struct ibm_init_struct *iibm) { unsigned long quirks; @@ -7085,16 +7151,33 @@ static int __init volume_init(struct ibm_init_struct *iibm) "mute is supported, volume control is %s\n", str_supported(!tp_features.mixer_no_level_control)); - rc = volume_create_alsa_mixer(); - if (rc) { - pr_err("Could not create the ALSA mixer interface\n"); - return rc; - } + if (software_mute_requested && volume_set_software_mute(true) == 0) { + char unmute_cmd[] = "unmute,level 14"; /* must be non-const */ + BUILD_BUG_ON(TP_EC_VOLUME_MAX != 14); + + software_mute_active = true; + + /* + * In software mute mode, the standard codec controls + * take precendence, so we unmute the ThinkPad HW switch + * at startup. Just on case there are SAUM-capable + * ThinkPads with level controls, set max HW volume as + * well. + */ + if (volume_write(unmute_cmd) != 0) + pr_warn("Failed to unmute ThinkPad HW\n"); + } else { + rc = volume_create_alsa_mixer(); + if (rc) { + pr_err("Could not create the ALSA mixer interface\n"); + return rc; + } - pr_info("Console audio control enabled, mode: %s\n", - (volume_control_allowed) ? - "override (read/write)" : - "monitor (read only)"); + pr_info("Console audio control enabled, mode: %s\n", + (volume_control_allowed) ? + "override (read/write)" : + "monitor (read only)"); + } vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, "registering volume hotkeys as change notification\n"); @@ -9091,6 +9174,10 @@ MODULE_PARM_DESC(volume_control, "Enables software override for the console audio " "control when true"); +module_param_named(software_mute, software_mute_requested, bool, 0444); +MODULE_PARM_DESC(software_mute, + "Request full software mute control"); + /* ALSA module API parameters */ module_param_named(index, alsa_index, int, 0444); MODULE_PARM_DESC(index, "ALSA index for the ACPI EC Mixer");