Loading drivers/acpi/blacklist.c +0 −54 Original line number Diff line number Diff line Loading @@ -304,60 +304,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { * 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 * this it exports a working "good old" eeepc_laptop interface, fixing Loading drivers/platform/x86/thinkpad_acpi.c +106 −10 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -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"); Loading Loading @@ -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; } Loading Loading @@ -6778,6 +6807,57 @@ static int __volume_set_volume_ec(const u8 vol) 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, Loading Loading @@ -6885,8 +6965,13 @@ static void volume_suspend(void) static void volume_resume(void) { 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) { Loading @@ -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) Loading Loading @@ -7085,6 +7173,9 @@ 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)); 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"); Loading @@ -7095,6 +7186,7 @@ static int __init volume_init(struct ibm_init_struct *iibm) (volume_control_allowed) ? "override (read/write)" : "monitor (read only)"); } vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, "registering volume hotkeys as change notification\n"); Loading Loading @@ -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"); Loading Loading
drivers/acpi/blacklist.c +0 −54 Original line number Diff line number Diff line Loading @@ -304,60 +304,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { * 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 * this it exports a working "good old" eeepc_laptop interface, fixing Loading
drivers/platform/x86/thinkpad_acpi.c +106 −10 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -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"); Loading Loading @@ -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; } Loading Loading @@ -6778,6 +6807,57 @@ static int __volume_set_volume_ec(const u8 vol) 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, Loading Loading @@ -6885,8 +6965,13 @@ static void volume_suspend(void) static void volume_resume(void) { 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) { Loading @@ -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) Loading Loading @@ -7085,6 +7173,9 @@ 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)); 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"); Loading @@ -7095,6 +7186,7 @@ static int __init volume_init(struct ibm_init_struct *iibm) (volume_control_allowed) ? "override (read/write)" : "monitor (read only)"); } vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, "registering volume hotkeys as change notification\n"); Loading Loading @@ -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"); Loading