diff mbox

[Saucy,1/8] thinkpad-acpi: Add mute and mic-mute LED functionality

Message ID 1387182343-17346-1-git-send-email-hui.wang@canonical.com
State New
Headers show

Commit Message

Hui Wang Dec. 16, 2013, 8:25 a.m. UTC
From: David Henningsson <david.henningsson@canonical.com>

BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1261296

The LEDs are currently not visible to userspace, for security
reasons. They are exported through thinkpad_acpi.h for use by the
snd-hda-intel driver.

Thanks to Alex Hung <alex.hung@canonical.com> and Takashi Iwai
<tiwai@suse.de> for writing parts of this patch.

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Acked-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
(cherry-picked from the commit 420f9739a62cdb027f5580d25c813501ff93aa6f)
---
 Documentation/laptops/thinkpad-acpi.txt |  7 ++-
 drivers/platform/x86/thinkpad_acpi.c    | 92 ++++++++++++++++++++++++++++++++-
 include/linux/thinkpad_acpi.h           | 15 ++++++
 3 files changed, 111 insertions(+), 3 deletions(-)
 create mode 100644 include/linux/thinkpad_acpi.h

Comments

Tim Gardner Dec. 16, 2013, 2:06 p.m. UTC | #1
Appears to be mostly model specific.
Brad Figg Dec. 18, 2013, 5:36 p.m. UTC | #2
On 12/16/2013 12:25 AM, Hui Wang wrote:
> From: David Henningsson <david.henningsson@canonical.com>
> 
> BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1261296
> 
> The LEDs are currently not visible to userspace, for security
> reasons. They are exported through thinkpad_acpi.h for use by the
> snd-hda-intel driver.
> 
> Thanks to Alex Hung <alex.hung@canonical.com> and Takashi Iwai
> <tiwai@suse.de> for writing parts of this patch.
> 
> Signed-off-by: David Henningsson <david.henningsson@canonical.com>
> Acked-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> (cherry-picked from the commit 420f9739a62cdb027f5580d25c813501ff93aa6f)
> ---
>  Documentation/laptops/thinkpad-acpi.txt |  7 ++-
>  drivers/platform/x86/thinkpad_acpi.c    | 92 ++++++++++++++++++++++++++++++++-
>  include/linux/thinkpad_acpi.h           | 15 ++++++
>  3 files changed, 111 insertions(+), 3 deletions(-)
>  create mode 100644 include/linux/thinkpad_acpi.h
> 
> diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
> index cf7bc6c..e411408 100644
> --- a/Documentation/laptops/thinkpad-acpi.txt
> +++ b/Documentation/laptops/thinkpad-acpi.txt
> @@ -1,7 +1,7 @@
>  		     ThinkPad ACPI Extras Driver
>  
> -                            Version 0.24
> -                        December 11th,  2009
> +                            Version 0.25
> +                        October 16th,  2013
>  
>                 Borislav Deianov <borislav@users.sf.net>
>               Henrique de Moraes Holschuh <hmh@hmh.eng.br>
> @@ -802,6 +802,9 @@ compiled with the CONFIG_THINKPAD_ACPI_UNSAFE_LEDS option enabled.
>  Distributions must never enable this option.  Individual users that
>  are aware of the consequences are welcome to enabling it.
>  
> +Audio mute and microphone mute LEDs are supported, but currently not
> +visible to userspace. They are used by the snd-hda-intel audio driver.
> +
>  procfs notes:
>  
>  The available commands are:
> diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
> index 99eeaf4..481b96b 100644
> --- a/drivers/platform/x86/thinkpad_acpi.c
> +++ b/drivers/platform/x86/thinkpad_acpi.c
> @@ -23,7 +23,7 @@
>  
>  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>  
> -#define TPACPI_VERSION "0.24"
> +#define TPACPI_VERSION "0.25"
>  #define TPACPI_SYSFS_VERSION 0x020700
>  
>  /*
> @@ -88,6 +88,7 @@
>  
>  #include <linux/pci_ids.h>
>  
> +#include <linux/thinkpad_acpi.h>
>  
>  /* ThinkPad CMOS commands */
>  #define TP_CMOS_VOLUME_DOWN	0
> @@ -8373,6 +8374,91 @@ static struct ibm_struct fan_driver_data = {
>  	.resume = fan_resume,
>  };
>  
> +/*************************************************************************
> + * Mute LED subdriver
> + */
> +
> +
> +struct tp_led_table {
> +	acpi_string name;
> +	int on_value;
> +	int off_value;
> +	int state;
> +};
> +
> +static struct tp_led_table led_tables[] = {
> +	[TPACPI_LED_MUTE] = {
> +		.name = "SSMS",
> +		.on_value = 1,
> +		.off_value = 0,
> +	},
> +	[TPACPI_LED_MICMUTE] = {
> +		.name = "MMTS",
> +		.on_value = 2,
> +		.off_value = 0,
> +	},
> +};
> +
> +static int mute_led_on_off(struct tp_led_table *t, bool state)
> +{
> +	acpi_handle temp;
> +	int output;
> +
> +	if (!ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp))) {
> +		pr_warn("Thinkpad ACPI has no %s interface.\n", t->name);
> +		return -EIO;
> +	}
> +
> +	if (!acpi_evalf(hkey_handle, &output, t->name, "dd",
> +			state ? t->on_value : t->off_value))
> +		return -EIO;
> +
> +	t->state = state;
> +	return state;
> +}
> +
> +int tpacpi_led_set(int whichled, bool on)
> +{
> +	struct tp_led_table *t;
> +
> +	if (whichled < 0 || whichled >= TPACPI_LED_MAX)
> +		return -EINVAL;
> +
> +	t = &led_tables[whichled];
> +	if (t->state < 0 || t->state == on)
> +		return t->state;
> +	return mute_led_on_off(t, on);
> +}
> +EXPORT_SYMBOL_GPL(tpacpi_led_set);
> +
> +static int mute_led_init(struct ibm_init_struct *iibm)
> +{
> +	acpi_handle temp;
> +	int i;
> +
> +	for (i = 0; i < TPACPI_LED_MAX; i++) {
> +		struct tp_led_table *t = &led_tables[i];
> +		if (ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp)))
> +			mute_led_on_off(t, false);
> +		else
> +			t->state = -ENODEV;
> +	}
> +	return 0;
> +}
> +
> +static void mute_led_exit(void)
> +{
> +	int i;
> +
> +	for (i = 0; i < TPACPI_LED_MAX; i++)
> +		tpacpi_led_set(i, false);
> +}
> +
> +static struct ibm_struct mute_led_driver_data = {
> +	.name = "mute_led",
> +	.exit = mute_led_exit,
> +};
> +
>  /****************************************************************************
>   ****************************************************************************
>   *
> @@ -8791,6 +8877,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
>  		.init = fan_init,
>  		.data = &fan_driver_data,
>  	},
> +	{
> +		.init = mute_led_init,
> +		.data = &mute_led_driver_data,
> +	},
>  };
>  
>  static int __init set_ibm_param(const char *val, struct kernel_param *kp)
> diff --git a/include/linux/thinkpad_acpi.h b/include/linux/thinkpad_acpi.h
> new file mode 100644
> index 0000000..361de59
> --- /dev/null
> +++ b/include/linux/thinkpad_acpi.h
> @@ -0,0 +1,15 @@
> +#ifndef __THINKPAD_ACPI_H__
> +#define __THINKPAD_ACPI_H__
> +
> +/* These two functions return 0 if success, or negative error code
> +   (e g -ENODEV if no led present) */
> +
> +enum {
> +	TPACPI_LED_MUTE,
> +	TPACPI_LED_MICMUTE,
> +	TPACPI_LED_MAX,
> +};
> +
> +int tpacpi_led_set(int whichled, bool on);
> +
> +#endif
>
Tim Gardner Dec. 18, 2013, 11 p.m. UTC | #3

diff mbox

Patch

diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index cf7bc6c..e411408 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -1,7 +1,7 @@ 
 		     ThinkPad ACPI Extras Driver
 
-                            Version 0.24
-                        December 11th,  2009
+                            Version 0.25
+                        October 16th,  2013
 
                Borislav Deianov <borislav@users.sf.net>
              Henrique de Moraes Holschuh <hmh@hmh.eng.br>
@@ -802,6 +802,9 @@  compiled with the CONFIG_THINKPAD_ACPI_UNSAFE_LEDS option enabled.
 Distributions must never enable this option.  Individual users that
 are aware of the consequences are welcome to enabling it.
 
+Audio mute and microphone mute LEDs are supported, but currently not
+visible to userspace. They are used by the snd-hda-intel audio driver.
+
 procfs notes:
 
 The available commands are:
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 99eeaf4..481b96b 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -23,7 +23,7 @@ 
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#define TPACPI_VERSION "0.24"
+#define TPACPI_VERSION "0.25"
 #define TPACPI_SYSFS_VERSION 0x020700
 
 /*
@@ -88,6 +88,7 @@ 
 
 #include <linux/pci_ids.h>
 
+#include <linux/thinkpad_acpi.h>
 
 /* ThinkPad CMOS commands */
 #define TP_CMOS_VOLUME_DOWN	0
@@ -8373,6 +8374,91 @@  static struct ibm_struct fan_driver_data = {
 	.resume = fan_resume,
 };
 
+/*************************************************************************
+ * Mute LED subdriver
+ */
+
+
+struct tp_led_table {
+	acpi_string name;
+	int on_value;
+	int off_value;
+	int state;
+};
+
+static struct tp_led_table led_tables[] = {
+	[TPACPI_LED_MUTE] = {
+		.name = "SSMS",
+		.on_value = 1,
+		.off_value = 0,
+	},
+	[TPACPI_LED_MICMUTE] = {
+		.name = "MMTS",
+		.on_value = 2,
+		.off_value = 0,
+	},
+};
+
+static int mute_led_on_off(struct tp_led_table *t, bool state)
+{
+	acpi_handle temp;
+	int output;
+
+	if (!ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp))) {
+		pr_warn("Thinkpad ACPI has no %s interface.\n", t->name);
+		return -EIO;
+	}
+
+	if (!acpi_evalf(hkey_handle, &output, t->name, "dd",
+			state ? t->on_value : t->off_value))
+		return -EIO;
+
+	t->state = state;
+	return state;
+}
+
+int tpacpi_led_set(int whichled, bool on)
+{
+	struct tp_led_table *t;
+
+	if (whichled < 0 || whichled >= TPACPI_LED_MAX)
+		return -EINVAL;
+
+	t = &led_tables[whichled];
+	if (t->state < 0 || t->state == on)
+		return t->state;
+	return mute_led_on_off(t, on);
+}
+EXPORT_SYMBOL_GPL(tpacpi_led_set);
+
+static int mute_led_init(struct ibm_init_struct *iibm)
+{
+	acpi_handle temp;
+	int i;
+
+	for (i = 0; i < TPACPI_LED_MAX; i++) {
+		struct tp_led_table *t = &led_tables[i];
+		if (ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp)))
+			mute_led_on_off(t, false);
+		else
+			t->state = -ENODEV;
+	}
+	return 0;
+}
+
+static void mute_led_exit(void)
+{
+	int i;
+
+	for (i = 0; i < TPACPI_LED_MAX; i++)
+		tpacpi_led_set(i, false);
+}
+
+static struct ibm_struct mute_led_driver_data = {
+	.name = "mute_led",
+	.exit = mute_led_exit,
+};
+
 /****************************************************************************
  ****************************************************************************
  *
@@ -8791,6 +8877,10 @@  static struct ibm_init_struct ibms_init[] __initdata = {
 		.init = fan_init,
 		.data = &fan_driver_data,
 	},
+	{
+		.init = mute_led_init,
+		.data = &mute_led_driver_data,
+	},
 };
 
 static int __init set_ibm_param(const char *val, struct kernel_param *kp)
diff --git a/include/linux/thinkpad_acpi.h b/include/linux/thinkpad_acpi.h
new file mode 100644
index 0000000..361de59
--- /dev/null
+++ b/include/linux/thinkpad_acpi.h
@@ -0,0 +1,15 @@ 
+#ifndef __THINKPAD_ACPI_H__
+#define __THINKPAD_ACPI_H__
+
+/* These two functions return 0 if success, or negative error code
+   (e g -ENODEV if no led present) */
+
+enum {
+	TPACPI_LED_MUTE,
+	TPACPI_LED_MICMUTE,
+	TPACPI_LED_MAX,
+};
+
+int tpacpi_led_set(int whichled, bool on);
+
+#endif