Merge branch 'thinkpad-acpi' into for-next
thinkpad-acpi: acpi: Remove _OSI(Linux) for ThinkPads thinkpad-acpi: Try to use full software mute control Signed-off-by: Darren Hart <dvhart@linux.intel.com>
This commit is contained in:
Коммит
cc888de2c3
|
@ -304,60 +304,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
|
||||||
* Linux ignores it, except for the machines enumerated below.
|
* Linux ignores it, except for the machines enumerated below.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Lenovo has a mix of systems OSI(Linux) situations
|
|
||||||
* and thus we can not wildcard the vendor.
|
|
||||||
*
|
|
||||||
* _OSI(Linux) helps sound
|
|
||||||
* DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
|
|
||||||
* DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
|
|
||||||
* T400, T500
|
|
||||||
* _OSI(Linux) has Linux specific hooks
|
|
||||||
* DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"),
|
|
||||||
* _OSI(Linux) is a NOP:
|
|
||||||
* DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
|
|
||||||
* DMI_MATCH(DMI_PRODUCT_VERSION, "LENOVO3000 V100"),
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
.callback = dmi_enable_osi_linux,
|
|
||||||
.ident = "Lenovo ThinkPad R61",
|
|
||||||
.matches = {
|
|
||||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
|
||||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.callback = dmi_enable_osi_linux,
|
|
||||||
.ident = "Lenovo ThinkPad T61",
|
|
||||||
.matches = {
|
|
||||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
|
||||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.callback = dmi_enable_osi_linux,
|
|
||||||
.ident = "Lenovo ThinkPad X61",
|
|
||||||
.matches = {
|
|
||||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
|
||||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.callback = dmi_enable_osi_linux,
|
|
||||||
.ident = "Lenovo ThinkPad T400",
|
|
||||||
.matches = {
|
|
||||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
|
||||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T400"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.callback = dmi_enable_osi_linux,
|
|
||||||
.ident = "Lenovo ThinkPad T500",
|
|
||||||
.matches = {
|
|
||||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
|
||||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T500"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
/*
|
/*
|
||||||
* Without this this EEEpc exports a non working WMI interface, with
|
* Without this this EEEpc exports a non working WMI interface, with
|
||||||
* this it exports a working "good old" eeepc_laptop interface, fixing
|
* this it exports a working "good old" eeepc_laptop interface, fixing
|
||||||
|
|
|
@ -6559,6 +6559,17 @@ static struct ibm_struct brightness_driver_data = {
|
||||||
* bits 3-0 (volume). Other bits in NVRAM may have other functions,
|
* 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,
|
* such as bit 7 which is used to detect repeated presses of MUTE,
|
||||||
* and we leave them unchanged.
|
* 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
|
#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
|
||||||
|
@ -6613,11 +6624,21 @@ enum tpacpi_volume_capabilities {
|
||||||
TPACPI_VOL_CAP_MAX
|
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 =
|
static enum tpacpi_volume_access_mode volume_mode =
|
||||||
TPACPI_VOL_MODE_MAX;
|
TPACPI_VOL_MODE_MAX;
|
||||||
|
|
||||||
static enum tpacpi_volume_capabilities volume_capabilities;
|
static enum tpacpi_volume_capabilities volume_capabilities;
|
||||||
static bool volume_control_allowed;
|
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
|
* Used to syncronize writers to TP_EC_AUDIO and
|
||||||
|
@ -6635,6 +6656,8 @@ static void tpacpi_volume_checkpoint_nvram(void)
|
||||||
return;
|
return;
|
||||||
if (!volume_control_allowed)
|
if (!volume_control_allowed)
|
||||||
return;
|
return;
|
||||||
|
if (software_mute_active)
|
||||||
|
return;
|
||||||
|
|
||||||
vdbg_printk(TPACPI_DBG_MIXER,
|
vdbg_printk(TPACPI_DBG_MIXER,
|
||||||
"trying to checkpoint mixer state to NVRAM...\n");
|
"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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6778,6 +6807,57 @@ unlock:
|
||||||
return rc;
|
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)
|
static int volume_alsa_set_volume(const u8 vol)
|
||||||
{
|
{
|
||||||
dbg_printk(TPACPI_DBG_MIXER,
|
dbg_printk(TPACPI_DBG_MIXER,
|
||||||
|
@ -6885,7 +6965,12 @@ static void volume_suspend(void)
|
||||||
|
|
||||||
static void volume_resume(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)
|
static void volume_shutdown(void)
|
||||||
|
@ -6901,6 +6986,9 @@ static void volume_exit(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
tpacpi_volume_checkpoint_nvram();
|
tpacpi_volume_checkpoint_nvram();
|
||||||
|
|
||||||
|
if (software_mute_active)
|
||||||
|
volume_exit_software_mute();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init volume_create_alsa_mixer(void)
|
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",
|
"mute is supported, volume control is %s\n",
|
||||||
str_supported(!tp_features.mixer_no_level_control));
|
str_supported(!tp_features.mixer_no_level_control));
|
||||||
|
|
||||||
rc = volume_create_alsa_mixer();
|
if (software_mute_requested && volume_set_software_mute(true) == 0) {
|
||||||
if (rc) {
|
software_mute_active = true;
|
||||||
pr_err("Could not create the ALSA mixer interface\n");
|
} else {
|
||||||
return rc;
|
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",
|
pr_info("Console audio control enabled, mode: %s\n",
|
||||||
(volume_control_allowed) ?
|
(volume_control_allowed) ?
|
||||||
"override (read/write)" :
|
"override (read/write)" :
|
||||||
"monitor (read only)");
|
"monitor (read only)");
|
||||||
|
}
|
||||||
|
|
||||||
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
|
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER,
|
||||||
"registering volume hotkeys as change notification\n");
|
"registering volume hotkeys as change notification\n");
|
||||||
|
@ -9091,6 +9183,10 @@ MODULE_PARM_DESC(volume_control,
|
||||||
"Enables software override for the console audio "
|
"Enables software override for the console audio "
|
||||||
"control when true");
|
"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 */
|
/* ALSA module API parameters */
|
||||||
module_param_named(index, alsa_index, int, 0444);
|
module_param_named(index, alsa_index, int, 0444);
|
||||||
MODULE_PARM_DESC(index, "ALSA index for the ACPI EC Mixer");
|
MODULE_PARM_DESC(index, "ALSA index for the ACPI EC Mixer");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче