Commit 420f9739 authored by David Henningsson's avatar David Henningsson Committed by Takashi Iwai

thinkpad-acpi: Add mute and mic-mute LED functionality

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: default avatarDavid Henningsson <david.henningsson@canonical.com>
Acked-by: default avatarHenrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 1d198f26
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>
......@@ -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:
......
......@@ -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
......@@ -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,
};
/****************************************************************************
****************************************************************************
*
......@@ -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)
......
#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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment