Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc888de2 authored by Darren Hart's avatar Darren Hart
Browse files

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: default avatarDarren Hart <dvhart@linux.intel.com>
parents f587f07f a707c27c
Loading
Loading
Loading
Loading
+0 −54
Original line number Diff line number Diff line
@@ -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
+106 −10
Original line number Diff line number Diff line
@@ -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 @@ 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,
@@ -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)
{
@@ -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,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");
@@ -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");
@@ -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");