aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2009-05-30 12:25:08 -0400
committerLen Brown <len.brown@intel.com>2009-06-17 22:48:22 -0400
commitf21179a47ff8d1046a61c1cf5920244997a4a7bb (patch)
treef90635e4dc7f5602d960a199877a4bb20c6b7be6
parent60201732f03c1231742e5872abe55a3bf59849a5 (diff)
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: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt23
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c88
2 files changed, 96 insertions, 15 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index e7e9a69069e1..88fc0661de56 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -920,7 +920,7 @@ The available commands are:
920 echo '<LED number> off' >/proc/acpi/ibm/led 920 echo '<LED number> off' >/proc/acpi/ibm/led
921 echo '<LED number> blink' >/proc/acpi/ibm/led 921 echo '<LED number> blink' >/proc/acpi/ibm/led
922 922
923The <LED number> range is 0 to 7. The set of LEDs that can be 923The <LED number> range is 0 to 15. The set of LEDs that can be
924controlled varies from model to model. Here is the common ThinkPad 924controlled varies from model to model. Here is the common ThinkPad
925mapping: 925mapping:
926 926
@@ -932,6 +932,11 @@ mapping:
932 5 - UltraBase battery slot 932 5 - UltraBase battery slot
933 6 - (unknown) 933 6 - (unknown)
934 7 - standby 934 7 - standby
935 8 - dock status 1
936 9 - dock status 2
937 10, 11 - (unknown)
938 12 - thinkvantage
939 13, 14, 15 - (unknown)
935 940
936All of the above can be turned on and off and can be made to blink. 941All of the above can be turned on and off and can be made to blink.
937 942
@@ -940,10 +945,12 @@ sysfs notes:
940The ThinkPad LED sysfs interface is described in detail by the LED class 945The ThinkPad LED sysfs interface is described in detail by the LED class
941documentation, in Documentation/leds-class.txt. 946documentation, in Documentation/leds-class.txt.
942 947
943The leds are named (in LED ID order, from 0 to 7): 948The LEDs are named (in LED ID order, from 0 to 12):
944"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt", 949"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
945"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt", 950"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt",
946"tpacpi::unknown_led", "tpacpi::standby". 951"tpacpi::unknown_led", "tpacpi::standby", "tpacpi::dock_status1",
952"tpacpi::dock_status2", "tpacpi::unknown_led2", "tpacpi::unknown_led3",
953"tpacpi::thinkvantage".
947 954
948Due to limitations in the sysfs LED class, if the status of the LED 955Due to limitations in the sysfs LED class, if the status of the LED
949indicators cannot be read due to an error, thinkpad-acpi will report it as 956indicators 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"timer" trigger, and leave the delay_on and delay_off parameters set to 965"timer" trigger, and leave the delay_on and delay_off parameters set to
959zero (to request hardware acceleration autodetection). 966zero (to request hardware acceleration autodetection).
960 967
968LEDs that are known not to exist in a given ThinkPad model are not
969made available through the sysfs interface. If you have a dock and you
970notice there are LEDs listed for your ThinkPad that do not exist (and
971are not in the dock), or if you notice that there are missing LEDs,
972a report to ibm-acpi-devel@lists.sourceforge.net is appreciated.
973
961 974
962ACPI sounds -- /proc/acpi/ibm/beep 975ACPI sounds -- /proc/acpi/ibm/beep
963---------------------------------- 976----------------------------------
@@ -1555,3 +1568,7 @@ Sysfs interface changelog:
15550x020300: hotkey enable/disable support removed, attributes 15680x020300: hotkey enable/disable support removed, attributes
1556 hotkey_bios_enabled and hotkey_enable deprecated and 1569 hotkey_bios_enabled and hotkey_enable deprecated and
1557 marked for removal. 1570 marked for removal.
1571
15720x020400: Marker for 16 LEDs support. Also, LEDs that are known
1573 to not exist in a given model are not registered with
1574 the LED sysfs class anymore.
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index da739d5c9210..06c7c03c8f2f 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -22,7 +22,7 @@
22 */ 22 */
23 23
24#define TPACPI_VERSION "0.23" 24#define TPACPI_VERSION "0.23"
25#define TPACPI_SYSFS_VERSION 0x020300 25#define TPACPI_SYSFS_VERSION 0x020400
26 26
27/* 27/*
28 * Changelog: 28 * Changelog:
@@ -4815,7 +4815,7 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
4815 "LED", /* all others */ 4815 "LED", /* all others */
4816 ); /* R30, R31 */ 4816 ); /* R30, R31 */
4817 4817
4818#define TPACPI_LED_NUMLEDS 8 4818#define TPACPI_LED_NUMLEDS 16
4819static struct tpacpi_led_classdev *tpacpi_leds; 4819static struct tpacpi_led_classdev *tpacpi_leds;
4820static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; 4820static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
4821static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { 4821static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
@@ -4828,15 +4828,20 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
4828 "tpacpi::dock_batt", 4828 "tpacpi::dock_batt",
4829 "tpacpi::unknown_led", 4829 "tpacpi::unknown_led",
4830 "tpacpi::standby", 4830 "tpacpi::standby",
4831 "tpacpi::dock_status1",
4832 "tpacpi::dock_status2",
4833 "tpacpi::unknown_led2",
4834 "tpacpi::unknown_led3",
4835 "tpacpi::thinkvantage",
4831}; 4836};
4832#define TPACPI_SAFE_LEDS 0x0081U 4837#define TPACPI_SAFE_LEDS 0x1081U
4833 4838
4834static inline bool tpacpi_is_led_restricted(const unsigned int led) 4839static inline bool tpacpi_is_led_restricted(const unsigned int led)
4835{ 4840{
4836#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS 4841#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
4837 return false; 4842 return false;
4838#else 4843#else
4839 return (TPACPI_SAFE_LEDS & (1 << led)) == 0; 4844 return (1U & (TPACPI_SAFE_LEDS >> led)) == 0;
4840#endif 4845#endif
4841} 4846}
4842 4847
@@ -4998,6 +5003,10 @@ static int __init tpacpi_init_led(unsigned int led)
4998 5003
4999 tpacpi_leds[led].led = led; 5004 tpacpi_leds[led].led = led;
5000 5005
5006 /* LEDs with no name don't get registered */
5007 if (!tpacpi_led_names[led])
5008 return 0;
5009
5001 tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set; 5010 tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set;
5002 tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set; 5011 tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set;
5003 if (led_supported == TPACPI_LED_570) 5012 if (led_supported == TPACPI_LED_570)
@@ -5016,10 +5025,59 @@ static int __init tpacpi_init_led(unsigned int led)
5016 return rc; 5025 return rc;
5017} 5026}
5018 5027
5028static const struct tpacpi_quirk led_useful_qtable[] __initconst = {
5029 TPACPI_Q_IBM('1', 'E', 0x009f), /* A30 */
5030 TPACPI_Q_IBM('1', 'N', 0x009f), /* A31 */
5031 TPACPI_Q_IBM('1', 'G', 0x009f), /* A31 */
5032
5033 TPACPI_Q_IBM('1', 'I', 0x0097), /* T30 */
5034 TPACPI_Q_IBM('1', 'R', 0x0097), /* T40, T41, T42, R50, R51 */
5035 TPACPI_Q_IBM('7', '0', 0x0097), /* T43, R52 */
5036 TPACPI_Q_IBM('1', 'Y', 0x0097), /* T43 */
5037 TPACPI_Q_IBM('1', 'W', 0x0097), /* R50e */
5038 TPACPI_Q_IBM('1', 'V', 0x0097), /* R51 */
5039 TPACPI_Q_IBM('7', '8', 0x0097), /* R51e */
5040 TPACPI_Q_IBM('7', '6', 0x0097), /* R52 */
5041
5042 TPACPI_Q_IBM('1', 'K', 0x00bf), /* X30 */
5043 TPACPI_Q_IBM('1', 'Q', 0x00bf), /* X31, X32 */
5044 TPACPI_Q_IBM('1', 'U', 0x00bf), /* X40 */
5045 TPACPI_Q_IBM('7', '4', 0x00bf), /* X41 */
5046 TPACPI_Q_IBM('7', '5', 0x00bf), /* X41t */
5047
5048 TPACPI_Q_IBM('7', '9', 0x1f97), /* T60 (1) */
5049 TPACPI_Q_IBM('7', '7', 0x1f97), /* Z60* (1) */
5050 TPACPI_Q_IBM('7', 'F', 0x1f97), /* Z61* (1) */
5051 TPACPI_Q_IBM('7', 'B', 0x1fb7), /* X60 (1) */
5052
5053 /* (1) - may have excess leds enabled on MSB */
5054
5055 /* Defaults (order matters, keep last, don't reorder!) */
5056 { /* Lenovo */
5057 .vendor = PCI_VENDOR_ID_LENOVO,
5058 .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
5059 .quirks = 0x1fffU,
5060 },
5061 { /* IBM ThinkPads with no EC version string */
5062 .vendor = PCI_VENDOR_ID_IBM,
5063 .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_UNKNOWN,
5064 .quirks = 0x00ffU,
5065 },
5066 { /* IBM ThinkPads with EC version string */
5067 .vendor = PCI_VENDOR_ID_IBM,
5068 .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY,
5069 .quirks = 0x00bfU,
5070 },
5071};
5072
5073#undef TPACPI_LEDQ_IBM
5074#undef TPACPI_LEDQ_LNV
5075
5019static int __init led_init(struct ibm_init_struct *iibm) 5076static int __init led_init(struct ibm_init_struct *iibm)
5020{ 5077{
5021 unsigned int i; 5078 unsigned int i;
5022 int rc; 5079 int rc;
5080 unsigned long useful_leds;
5023 5081
5024 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); 5082 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
5025 5083
@@ -5041,6 +5099,9 @@ static int __init led_init(struct ibm_init_struct *iibm)
5041 vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", 5099 vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
5042 str_supported(led_supported), led_supported); 5100 str_supported(led_supported), led_supported);
5043 5101
5102 if (led_supported == TPACPI_LED_NONE)
5103 return 1;
5104
5044 tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS, 5105 tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
5045 GFP_KERNEL); 5106 GFP_KERNEL);
5046 if (!tpacpi_leds) { 5107 if (!tpacpi_leds) {
@@ -5048,8 +5109,12 @@ static int __init led_init(struct ibm_init_struct *iibm)
5048 return -ENOMEM; 5109 return -ENOMEM;
5049 } 5110 }
5050 5111
5112 useful_leds = tpacpi_check_quirks(led_useful_qtable,
5113 ARRAY_SIZE(led_useful_qtable));
5114
5051 for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { 5115 for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
5052 if (!tpacpi_is_led_restricted(i)) { 5116 if (!tpacpi_is_led_restricted(i) &&
5117 test_bit(i, &useful_leds)) {
5053 rc = tpacpi_init_led(i); 5118 rc = tpacpi_init_led(i);
5054 if (rc < 0) { 5119 if (rc < 0) {
5055 led_exit(); 5120 led_exit();
@@ -5059,12 +5124,11 @@ static int __init led_init(struct ibm_init_struct *iibm)
5059 } 5124 }
5060 5125
5061#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS 5126#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
5062 if (led_supported != TPACPI_LED_NONE) 5127 printk(TPACPI_NOTICE
5063 printk(TPACPI_NOTICE 5128 "warning: userspace override of important "
5064 "warning: userspace override of important " 5129 "firmware LEDs is enabled\n");
5065 "firmware LEDs is enabled\n");
5066#endif 5130#endif
5067 return (led_supported != TPACPI_LED_NONE)? 0 : 1; 5131 return 0;
5068} 5132}
5069 5133
5070#define str_led_status(s) \ 5134#define str_led_status(s) \
@@ -5094,7 +5158,7 @@ static int led_read(char *p)
5094 } 5158 }
5095 5159
5096 len += sprintf(p + len, "commands:\t" 5160 len += sprintf(p + len, "commands:\t"
5097 "<led> on, <led> off, <led> blink (<led> is 0-7)\n"); 5161 "<led> on, <led> off, <led> blink (<led> is 0-15)\n");
5098 5162
5099 return len; 5163 return len;
5100} 5164}
@@ -5109,7 +5173,7 @@ static int led_write(char *buf)
5109 return -ENODEV; 5173 return -ENODEV;
5110 5174
5111 while ((cmd = next_cmd(&buf))) { 5175 while ((cmd = next_cmd(&buf))) {
5112 if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7) 5176 if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 15)
5113 return -EINVAL; 5177 return -EINVAL;
5114 5178
5115 if (strstr(cmd, "off")) { 5179 if (strstr(cmd, "off")) {