[PATCH] thinkpad_acpi: added BIOS mute interfaces for volume

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Alex Hung <alex.hung@xxxxxxxxxxxxx>
---
 drivers/platform/x86/thinkpad_acpi.c |  115 +++++++++++++++++++++++++++++++---
 1 files changed, 106 insertions(+), 9 deletions(-)

diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 7b82868..dc22a4c 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -6486,12 +6486,86 @@ enum tpacpi_volume_capabilities {
 	TPACPI_VOL_CAP_MAX
 };
 
+enum  {
+	TPACPI_AML_MUTE_GET_FUNC = 0x01,
+	TPACPI_AML_MUTE_SET_FUNC = 0x02,
+	TPACPI_AML_MUTE_SUPPORT_FUNC = 0x04,
+	TPACPI_AML_MUTE_READ_MASK = 0x01,
+	TPACPI_AML_MUTE_ERROR_STATE_MASK = 0x80000000,
+};
+
 static enum tpacpi_volume_access_mode volume_mode =
 	TPACPI_VOL_MODE_MAX;
 
 static enum tpacpi_volume_capabilities volume_capabilities;
 static int volume_control_allowed;
 
+
+static bool volume_bios_support(int func)
+{
+	acpi_handle temp;
+
+	if ((func | TPACPI_AML_MUTE_GET_FUNC) &&
+	    !ACPI_SUCCESS(acpi_get_handle(hkey_handle, "GSMS", &temp)))
+		return false;
+
+	if ((func | TPACPI_AML_MUTE_SET_FUNC) &&
+	    !ACPI_SUCCESS(acpi_get_handle(hkey_handle, "SSMS", &temp)))
+		return false;
+
+	if ((func | TPACPI_AML_MUTE_SUPPORT_FUNC) &&
+	    !ACPI_SUCCESS(acpi_get_handle(hkey_handle, "SHDA", &temp)))
+		return false;
+
+	return true;
+}
+
+static int hotkey_get_mute_state(int *state)
+{
+	if (!acpi_evalf(hkey_handle, state, "GSMS", "dd"))
+		return -EIO;
+
+	if (*state & TPACPI_AML_MUTE_ERROR_STATE_MASK)
+		pr_warning("getting mute state failed.\n");
+
+	*state &= TPACPI_AML_MUTE_READ_MASK;
+	pr_info("get mute state = %s.\n", *state ? "muted" : "unmuted");
+
+	return 0;
+}
+
+static int hotkey_set_mute_state(int state)
+{
+	int output;
+
+	if (!acpi_evalf(hkey_handle, &output, "SSMS", "dd", state))
+		return -EIO;
+
+	if (output & TPACPI_AML_MUTE_ERROR_STATE_MASK) {
+		pr_warning("setting mute state failed.\n");
+		return -EIO;
+	}
+	pr_info("set to mute led state to %s.\n", state ? "on" : "off");
+
+	return 0;
+}
+
+static int hotkey_set_mute_support(int support)
+{
+	int output;
+
+	if (!acpi_evalf(hkey_handle, &output, "SHDA", "dd", support))
+		return -EIO;
+
+	if (output & TPACPI_AML_MUTE_ERROR_STATE_MASK) {
+		pr_warning("setting mute support failed.\n");
+		return -EIO;
+	}
+	pr_info("%s mute led support.\n", support ? "disable" : "enable");
+
+	return 0;
+}
+
 /*
  * Used to syncronize writers to TP_EC_AUDIO and
  * TP_NVRAM_ADDR_MIXER, as we need to do read-modify-write
@@ -6982,6 +7056,7 @@ static int __init volume_init(struct ibm_init_struct *iibm)
 static int volume_read(struct seq_file *m)
 {
 	u8 status;
+	int mute;
 
 	if (volume_get_status(&status) < 0) {
 		seq_printf(m, "level:\t\tunreadable\n");
@@ -6991,8 +7066,12 @@ static int volume_read(struct seq_file *m)
 		else
 			seq_printf(m, "level:\t\t%d\n",
 					status & TP_EC_AUDIO_LVL_MSK);
-
-		seq_printf(m, "mute:\t\t%s\n",
+		if (volume_bios_support(TPACPI_AML_MUTE_GET_FUNC) &&
+		    !hotkey_get_mute_state(&mute))
+			seq_printf(m, "mute:\t\t%s\n",
+				mute ? "muted" : "unmuted");
+		else
+			seq_printf(m, "mute:\t\t%s\n",
 				onoff(status, TP_EC_AUDIO_MUTESW));
 
 		if (volume_control_allowed) {
@@ -7005,7 +7084,8 @@ static int volume_read(struct seq_file *m)
 					       " (<level> is 0-%d)\n",
 					       TP_EC_VOLUME_MAX);
 			}
-		}
+		} else if (volume_bios_support(TPACPI_AML_MUTE_SET_FUNC))
+			seq_printf(m, "commands:\tunmute, mute\n");
 	}
 
 	return 0;
@@ -7019,6 +7099,21 @@ static int volume_write(char *buf)
 	char *cmd;
 	int rc;
 
+	if (volume_bios_support(
+		TPACPI_AML_MUTE_SET_FUNC | TPACPI_AML_MUTE_SUPPORT_FUNC)) {
+		while ((cmd = next_cmd(&buf))) {
+			if (strlencmp(cmd, "mute") == 0)
+				hotkey_set_mute_state(1);
+			else if (strlencmp(cmd, "unmute") == 0)
+				hotkey_set_mute_state(0);
+			else if (strlencmp(cmd, "disable") == 0)
+				hotkey_set_mute_support(1);
+			else if (strlencmp(cmd, "enable") == 0)
+				hotkey_set_mute_support(0);
+		}
+		return -EINVAL;
+	}
+
 	/*
 	 * We do allow volume control at driver startup, so that the
 	 * user can set initial state through the volume=... parameter hack.
@@ -7061,12 +7156,14 @@ static int volume_write(char *buf)
 				continue;
 			}
 		}
-		if (strlencmp(cmd, "mute") == 0)
-			new_mute = TP_EC_AUDIO_MUTESW_MSK;
-		else if (strlencmp(cmd, "unmute") == 0)
-			new_mute = 0;
-		else
-			return -EINVAL;
+		if (!volume_bios_support(TPACPI_AML_MUTE_SET_FUNC)) {
+			if (strlencmp(cmd, "mute") == 0)
+				new_mute = TP_EC_AUDIO_MUTESW_MSK;
+			else if (strlencmp(cmd, "unmute") == 0)
+				new_mute = 0;
+			else
+				return -EINVAL;
+		}
 	}
 
 	if (tp_features.mixer_no_level_control) {
-- 
1.7.5.4


------------------------------------------------------------------------------
Better than sec? Nothing is better than sec when it comes to
monitoring Big Data applications. Try Boundary one-second 
resolution app monitoring today. Free.
http://p.sf.net/sfu/Boundary-dev2dev
_______________________________________________
ibm-acpi-devel mailing list
ibm-acpi-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/ibm-acpi-devel


[Index of Archives]     [Linux ACPI]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Photo]     [Yosemite Photos]     [Yosemite Advice]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]

  Powered by Linux