Skip to content

Commit

Permalink
thinkpad-acpi: Add mute and mic-mute LED functionality
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Henningsson authored and tiwai committed Oct 17, 2013
1 parent 1d198f2 commit 420f973
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 3 deletions.
7 changes: 5 additions & 2 deletions Documentation/laptops/thinkpad-acpi.txt
Original file line number Diff line number Diff line change
@@ -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>
Expand Down Expand Up @@ -741,6 +741,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:
Expand Down
92 changes: 91 additions & 1 deletion drivers/platform/x86/thinkpad_acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

/*
Expand Down Expand Up @@ -88,6 +88,7 @@

#include <linux/pci_ids.h>

#include <linux/thinkpad_acpi.h>

/* ThinkPad CMOS commands */
#define TP_CMOS_VOLUME_DOWN 0
Expand Down Expand Up @@ -8350,6 +8351,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,
};

/****************************************************************************
****************************************************************************
*
Expand Down Expand Up @@ -8768,6 +8854,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)
Expand Down
15 changes: 15 additions & 0 deletions include/linux/thinkpad_acpi.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 420f973

Please sign in to comment.