diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2009-05-30 12:25:08 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-06-17 22:48:22 -0400 |
commit | f21179a47ff8d1046a61c1cf5920244997a4a7bb (patch) | |
tree | f90635e4dc7f5602d960a199877a4bb20c6b7be6 /drivers/platform | |
parent | 60201732f03c1231742e5872abe55a3bf59849a5 (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/platform')
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 88 |
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 |
4819 | static struct tpacpi_led_classdev *tpacpi_leds; | 4819 | static struct tpacpi_led_classdev *tpacpi_leds; |
4820 | static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; | 4820 | static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; |
4821 | static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { | 4821 | 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 | "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 | ||
4834 | static inline bool tpacpi_is_led_restricted(const unsigned int led) | 4839 | static 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 | ||
5028 | static 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 | |||
5019 | static int __init led_init(struct ibm_init_struct *iibm) | 5076 | static 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")) { |