提交 f21179a4 编写于 作者: H Henrique de Moraes Holschuh 提交者: Len Brown

thinkpad-acpi: enhance led support

Add support for extra LEDs on recent ThinkPads, and avoid registering
with the led class the LEDs which are not available for a given
ThinkPad model.

All non-restricted LEDs are always available through the procfs
interface, as the firmware doesn't care if an attempt is made to
access an invalid LED.
Signed-off-by: NHenrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: NLen Brown <len.brown@intel.com>
上级 60201732
...@@ -920,7 +920,7 @@ The available commands are: ...@@ -920,7 +920,7 @@ The available commands are:
echo '<LED number> off' >/proc/acpi/ibm/led echo '<LED number> off' >/proc/acpi/ibm/led
echo '<LED number> blink' >/proc/acpi/ibm/led echo '<LED number> blink' >/proc/acpi/ibm/led
The <LED number> range is 0 to 7. The set of LEDs that can be The <LED number> range is 0 to 15. The set of LEDs that can be
controlled varies from model to model. Here is the common ThinkPad controlled varies from model to model. Here is the common ThinkPad
mapping: mapping:
...@@ -932,6 +932,11 @@ mapping: ...@@ -932,6 +932,11 @@ mapping:
5 - UltraBase battery slot 5 - UltraBase battery slot
6 - (unknown) 6 - (unknown)
7 - standby 7 - standby
8 - dock status 1
9 - dock status 2
10, 11 - (unknown)
12 - thinkvantage
13, 14, 15 - (unknown)
All of the above can be turned on and off and can be made to blink. All of the above can be turned on and off and can be made to blink.
...@@ -940,10 +945,12 @@ sysfs notes: ...@@ -940,10 +945,12 @@ sysfs notes:
The ThinkPad LED sysfs interface is described in detail by the LED class The ThinkPad LED sysfs interface is described in detail by the LED class
documentation, in Documentation/leds-class.txt. documentation, in Documentation/leds-class.txt.
The leds are named (in LED ID order, from 0 to 7): The LEDs are named (in LED ID order, from 0 to 12):
"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt", "tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt", "tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt",
"tpacpi::unknown_led", "tpacpi::standby". "tpacpi::unknown_led", "tpacpi::standby", "tpacpi::dock_status1",
"tpacpi::dock_status2", "tpacpi::unknown_led2", "tpacpi::unknown_led3",
"tpacpi::thinkvantage".
Due to limitations in the sysfs LED class, if the status of the LED Due to limitations in the sysfs LED class, if the status of the LED
indicators cannot be read due to an error, thinkpad-acpi will report it as indicators cannot be read due to an error, thinkpad-acpi will report it as
...@@ -958,6 +965,12 @@ ThinkPad indicator LED should blink in hardware accelerated mode, use the ...@@ -958,6 +965,12 @@ ThinkPad indicator LED should blink in hardware accelerated mode, use the
"timer" trigger, and leave the delay_on and delay_off parameters set to "timer" trigger, and leave the delay_on and delay_off parameters set to
zero (to request hardware acceleration autodetection). zero (to request hardware acceleration autodetection).
LEDs that are known not to exist in a given ThinkPad model are not
made available through the sysfs interface. If you have a dock and you
notice there are LEDs listed for your ThinkPad that do not exist (and
are not in the dock), or if you notice that there are missing LEDs,
a report to ibm-acpi-devel@lists.sourceforge.net is appreciated.
ACPI sounds -- /proc/acpi/ibm/beep ACPI sounds -- /proc/acpi/ibm/beep
---------------------------------- ----------------------------------
...@@ -1555,3 +1568,7 @@ Sysfs interface changelog: ...@@ -1555,3 +1568,7 @@ Sysfs interface changelog:
0x020300: hotkey enable/disable support removed, attributes 0x020300: hotkey enable/disable support removed, attributes
hotkey_bios_enabled and hotkey_enable deprecated and hotkey_bios_enabled and hotkey_enable deprecated and
marked for removal. marked for removal.
0x020400: Marker for 16 LEDs support. Also, LEDs that are known
to not exist in a given model are not registered with
the LED sysfs class anymore.
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
*/ */
#define TPACPI_VERSION "0.23" #define TPACPI_VERSION "0.23"
#define TPACPI_SYSFS_VERSION 0x020300 #define TPACPI_SYSFS_VERSION 0x020400
/* /*
* Changelog: * Changelog:
...@@ -4815,7 +4815,7 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */ ...@@ -4815,7 +4815,7 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
"LED", /* all others */ "LED", /* all others */
); /* R30, R31 */ ); /* R30, R31 */
#define TPACPI_LED_NUMLEDS 8 #define TPACPI_LED_NUMLEDS 16
static struct tpacpi_led_classdev *tpacpi_leds; static struct tpacpi_led_classdev *tpacpi_leds;
static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
...@@ -4828,15 +4828,20 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { ...@@ -4828,15 +4828,20 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
"tpacpi::dock_batt", "tpacpi::dock_batt",
"tpacpi::unknown_led", "tpacpi::unknown_led",
"tpacpi::standby", "tpacpi::standby",
"tpacpi::dock_status1",
"tpacpi::dock_status2",
"tpacpi::unknown_led2",
"tpacpi::unknown_led3",
"tpacpi::thinkvantage",
}; };
#define TPACPI_SAFE_LEDS 0x0081U #define TPACPI_SAFE_LEDS 0x1081U
static inline bool tpacpi_is_led_restricted(const unsigned int led) static inline bool tpacpi_is_led_restricted(const unsigned int led)
{ {
#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS #ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
return false; return false;
#else #else
return (TPACPI_SAFE_LEDS & (1 << led)) == 0; return (1U & (TPACPI_SAFE_LEDS >> led)) == 0;
#endif #endif
} }
...@@ -4998,6 +5003,10 @@ static int __init tpacpi_init_led(unsigned int led) ...@@ -4998,6 +5003,10 @@ static int __init tpacpi_init_led(unsigned int led)
tpacpi_leds[led].led = led; tpacpi_leds[led].led = led;
/* LEDs with no name don't get registered */
if (!tpacpi_led_names[led])
return 0;
tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set; tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set;
tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set; tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set;
if (led_supported == TPACPI_LED_570) if (led_supported == TPACPI_LED_570)
...@@ -5016,10 +5025,59 @@ static int __init tpacpi_init_led(unsigned int led) ...@@ -5016,10 +5025,59 @@ static int __init tpacpi_init_led(unsigned int led)
return rc; return rc;
} }
static const struct tpacpi_quirk led_useful_qtable[] __initconst = {
TPACPI_Q_IBM('1', 'E', 0x009f), /* A30 */
TPACPI_Q_IBM('1', 'N', 0x009f), /* A31 */
TPACPI_Q_IBM('1', 'G', 0x009f), /* A31 */
TPACPI_Q_IBM('1', 'I', 0x0097), /* T30 */
TPACPI_Q_IBM('1', 'R', 0x0097), /* T40, T41, T42, R50, R51 */
TPACPI_Q_IBM('7', '0', 0x0097), /* T43, R52 */
TPACPI_Q_IBM('1', 'Y', 0x0097), /* T43 */
TPACPI_Q_IBM('1', 'W', 0x0097), /* R50e */
TPACPI_Q_IBM('1', 'V', 0x0097), /* R51 */
TPACPI_Q_IBM('7', '8', 0x0097), /* R51e */
TPACPI_Q_IBM('7', '6', 0x0097), /* R52 */
TPACPI_Q_IBM('1', 'K', 0x00bf), /* X30 */
TPACPI_Q_IBM('1', 'Q', 0x00bf), /* X31, X32 */
TPACPI_Q_IBM('1', 'U', 0x00bf), /* X40 */
TPACPI_Q_IBM('7', '4', 0x00bf), /* X41 */
TPACPI_Q_IBM('7', '5', 0x00bf), /* X41t */
TPACPI_Q_IBM('7', '9', 0x1f97), /* T60 (1) */
TPACPI_Q_IBM('7', '7', 0x1f97), /* Z60* (1) */
TPACPI_Q_IBM('7', 'F', 0x1f97), /* Z61* (1) */
TPACPI_Q_IBM('7', 'B', 0x1fb7), /* X60 (1) */
/* (1) - may have excess leds enabled on MSB */
/* Defaults (order matters, keep last, don't reorder!) */
{ /* Lenovo */
.vendor = PCI_VENDOR_ID_LENOVO,
.bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
.quirks = 0x1fffU,
},
{ /* IBM ThinkPads with no EC version string */
.vendor = PCI_VENDOR_ID_IBM,
.bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_UNKNOWN,
.quirks = 0x00ffU,
},
{ /* IBM ThinkPads with EC version string */
.vendor = PCI_VENDOR_ID_IBM,
.bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
.quirks = 0x00bfU,
},
};
#undef TPACPI_LEDQ_IBM
#undef TPACPI_LEDQ_LNV
static int __init led_init(struct ibm_init_struct *iibm) static int __init led_init(struct ibm_init_struct *iibm)
{ {
unsigned int i; unsigned int i;
int rc; int rc;
unsigned long useful_leds;
vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
...@@ -5041,6 +5099,9 @@ static int __init led_init(struct ibm_init_struct *iibm) ...@@ -5041,6 +5099,9 @@ static int __init led_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
str_supported(led_supported), led_supported); str_supported(led_supported), led_supported);
if (led_supported == TPACPI_LED_NONE)
return 1;
tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS, tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
GFP_KERNEL); GFP_KERNEL);
if (!tpacpi_leds) { if (!tpacpi_leds) {
...@@ -5048,8 +5109,12 @@ static int __init led_init(struct ibm_init_struct *iibm) ...@@ -5048,8 +5109,12 @@ static int __init led_init(struct ibm_init_struct *iibm)
return -ENOMEM; return -ENOMEM;
} }
useful_leds = tpacpi_check_quirks(led_useful_qtable,
ARRAY_SIZE(led_useful_qtable));
for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
if (!tpacpi_is_led_restricted(i)) { if (!tpacpi_is_led_restricted(i) &&
test_bit(i, &useful_leds)) {
rc = tpacpi_init_led(i); rc = tpacpi_init_led(i);
if (rc < 0) { if (rc < 0) {
led_exit(); led_exit();
...@@ -5059,12 +5124,11 @@ static int __init led_init(struct ibm_init_struct *iibm) ...@@ -5059,12 +5124,11 @@ static int __init led_init(struct ibm_init_struct *iibm)
} }
#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS #ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
if (led_supported != TPACPI_LED_NONE)
printk(TPACPI_NOTICE printk(TPACPI_NOTICE
"warning: userspace override of important " "warning: userspace override of important "
"firmware LEDs is enabled\n"); "firmware LEDs is enabled\n");
#endif #endif
return (led_supported != TPACPI_LED_NONE)? 0 : 1; return 0;
} }
#define str_led_status(s) \ #define str_led_status(s) \
...@@ -5094,7 +5158,7 @@ static int led_read(char *p) ...@@ -5094,7 +5158,7 @@ static int led_read(char *p)
} }
len += sprintf(p + len, "commands:\t" len += sprintf(p + len, "commands:\t"
"<led> on, <led> off, <led> blink (<led> is 0-7)\n"); "<led> on, <led> off, <led> blink (<led> is 0-15)\n");
return len; return len;
} }
...@@ -5109,7 +5173,7 @@ static int led_write(char *buf) ...@@ -5109,7 +5173,7 @@ static int led_write(char *buf)
return -ENODEV; return -ENODEV;
while ((cmd = next_cmd(&buf))) { while ((cmd = next_cmd(&buf))) {
if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7) if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 15)
return -EINVAL; return -EINVAL;
if (strstr(cmd, "off")) { if (strstr(cmd, "off")) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册