aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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 /drivers
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c88
1 files changed, 76 insertions, 12 deletions
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")) {