[alsa-devel] [PATCH v3 1/2] thinkpad-acpi: Try to use full software mute control
Andy Lutomirski
luto at amacapital.net
Mon Dec 8 22:44:21 CET 2014
On Fri, Oct 31, 2014 at 4:07 PM, Henrique de Moraes Holschuh
<hmh at hmh.eng.br> wrote:
> On Fri, 17 Oct 2014, Andy Lutomirski wrote:
>> 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, on some models,
>> 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 doesn't seem to be a consistent way to get
>> any notification when the HW mute state is changed.
>>
>> Signed-off-by: Andy Lutomirski <luto at mit.edu>
>
> Acked-by: Henrique de Moraes Holschuh <hmh at hmh.eng.br>
What tree do these go through? I haven't spotted them in linux-next.
Thanks,
Andy
>
>> ---
>> drivers/platform/x86/thinkpad_acpi.c | 116 ++++++++++++++++++++++++++++++++---
>> 1 file changed, 106 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
>> index 3bbc6eb60de5..cfc317f2de23 100644
>> --- a/drivers/platform/x86/thinkpad_acpi.c
>> +++ b/drivers/platform/x86/thinkpad_acpi.c
>> @@ -6559,6 +6559,17 @@ 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.
>> + *
>> + * On newer Lenovo ThinkPads, the EC can 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, on some
>> + * models, 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 +6624,21 @@ 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;
>> +static int software_mute_orig_mode;
>>
>> /*
>> * Used to syncronize writers to TP_EC_AUDIO and
>> @@ -6635,6 +6656,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 +6719,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 +6807,57 @@ unlock:
>> return rc;
>> }
>>
>> +static int volume_set_software_mute(bool startup)
>> +{
>> + int result;
>> +
>> + if (!tpacpi_is_lenovo())
>> + return -ENODEV;
>> +
>> + if (startup) {
>> + if (!acpi_evalf(ec_handle, &software_mute_orig_mode,
>> + "HAUM", "qd"))
>> + return -EIO;
>> +
>> + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
>> + "Initial HAUM setting was %d\n",
>> + software_mute_orig_mode);
>> + }
>> +
>> + if (!acpi_evalf(ec_handle, &result, "SAUM", "qdd",
>> + (int)TP_EC_MUTE_BTN_NONE))
>> + return -EIO;
>> +
>> + if (result != TP_EC_MUTE_BTN_NONE)
>> + pr_warn("Unexpected SAUM result %d\n",
>> + result);
>> +
>> + /*
>> + * 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 (tp_features.mixer_no_level_control)
>> + result = volume_set_mute(false);
>> + else
>> + result = volume_set_status(TP_EC_VOLUME_MAX);
>> +
>> + if (result != 0)
>> + pr_warn("Failed to unmute the HW mute switch\n");
>> +
>> + return 0;
>> +}
>> +
>> +static void volume_exit_software_mute(void)
>> +{
>> + int r;
>> +
>> + if (!acpi_evalf(ec_handle, &r, "SAUM", "qdd", software_mute_orig_mode)
>> + || r != software_mute_orig_mode)
>> + pr_warn("Failed to restore mute mode\n");
>> +}
>> +
>> static int volume_alsa_set_volume(const u8 vol)
>> {
>> dbg_printk(TPACPI_DBG_MIXER,
>> @@ -6885,7 +6965,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("Failed to restore software mute\n");
>> + } else {
>> + volume_alsa_notify_change();
>> + }
>> }
>>
>> static void volume_shutdown(void)
>> @@ -6901,6 +6986,9 @@ static void volume_exit(void)
>> }
>>
>> tpacpi_volume_checkpoint_nvram();
>> +
>> + if (software_mute_active)
>> + volume_exit_software_mute();
>> }
>>
>> static int __init volume_create_alsa_mixer(void)
>> @@ -7085,16 +7173,20 @@ 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) {
>> + software_mute_active = true;
>> + } 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 +9183,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");
>
> --
> "One disk to rule them all, One disk to find them. One disk to bring
> them all and in the darkness grind them. In the Land of Redmond
> where the shadows lie." -- The Silicon Valley Tarot
> Henrique Holschuh
--
Andy Lutomirski
AMA Capital Management, LLC
More information about the Alsa-devel
mailing list