aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/thinkpad_acpi.c
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2008-06-03 22:36:11 -0400
committerLen Brown <len.brown@intel.com>2008-06-11 19:13:45 -0400
commit24e45bbe695719dca8c20e03d386eb6ea86526b5 (patch)
treedb4b154bbeffe64d275bdfc05a0cc32259e1e54f /drivers/misc/thinkpad_acpi.c
parent9c0a76e16ee6648f4bd19563e9fe12a4f4fabba1 (diff)
thinkpad-acpi: fix LED handling on older ThinkPads
The less tested codepaths for LED handling, used on ThinkPads 570, 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 and maybe a few others, would write data to kernel memory it had no business touching, for leds number 3 and above. If one is lucky, that illegal write would cause an OOPS, but chances are it would silently corrupt a byte. The problem was introduced in commit af116101, "ACPI: thinkpad-acpi: add sysfs led class support to thinkpad leds (v3.2)". Fix the bug by refactoring the entire code to be far more obvious on what it wants to do. Also do some defensive "constification". Issue reported by Karol Lewandowski <lmctlx@gmail.com> (he's an lucky guy and got an OOPS instead of silent corruption :-) ). Root cause of the OOPS identified by Adrian Bunk <bunk@kernel.org>. Thanks, Adrian! Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Tested-by: Karol Lewandowski <lmctlx@gmail.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r--drivers/misc/thinkpad_acpi.c55
1 files changed, 28 insertions, 27 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 58973da1e6d1..b5969298f3d3 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -3853,7 +3853,7 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
3853 "tpacpi::standby", 3853 "tpacpi::standby",
3854}; 3854};
3855 3855
3856static int led_get_status(unsigned int led) 3856static int led_get_status(const unsigned int led)
3857{ 3857{
3858 int status; 3858 int status;
3859 enum led_status_t led_s; 3859 enum led_status_t led_s;
@@ -3877,41 +3877,42 @@ static int led_get_status(unsigned int led)
3877 /* not reached */ 3877 /* not reached */
3878} 3878}
3879 3879
3880static int led_set_status(unsigned int led, enum led_status_t ledstatus) 3880static int led_set_status(const unsigned int led,
3881 const enum led_status_t ledstatus)
3881{ 3882{
3882 /* off, on, blink. Index is led_status_t */ 3883 /* off, on, blink. Index is led_status_t */
3883 static const int led_sled_arg1[] = { 0, 1, 3 }; 3884 static const unsigned int led_sled_arg1[] = { 0, 1, 3 };
3884 static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ 3885 static const unsigned int led_led_arg1[] = { 0, 0x80, 0xc0 };
3885 static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
3886 static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
3887 3886
3888 int rc = 0; 3887 int rc = 0;
3889 3888
3890 switch (led_supported) { 3889 switch (led_supported) {
3891 case TPACPI_LED_570: 3890 case TPACPI_LED_570:
3892 /* 570 */ 3891 /* 570 */
3893 led = 1 << led; 3892 if (led > 7)
3894 if (!acpi_evalf(led_handle, NULL, NULL, "vdd", 3893 return -EINVAL;
3895 led, led_sled_arg1[ledstatus])) 3894 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
3896 rc = -EIO; 3895 (1 << led), led_sled_arg1[ledstatus]))
3897 break; 3896 rc = -EIO;
3897 break;
3898 case TPACPI_LED_OLD: 3898 case TPACPI_LED_OLD:
3899 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ 3899 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
3900 led = 1 << led; 3900 if (led > 7)
3901 rc = ec_write(TPACPI_LED_EC_HLMS, led); 3901 return -EINVAL;
3902 if (rc >= 0) 3902 rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led));
3903 rc = ec_write(TPACPI_LED_EC_HLBL, 3903 if (rc >= 0)
3904 led * led_exp_hlbl[ledstatus]); 3904 rc = ec_write(TPACPI_LED_EC_HLBL,
3905 if (rc >= 0) 3905 (ledstatus == TPACPI_LED_BLINK) << led);
3906 rc = ec_write(TPACPI_LED_EC_HLCL, 3906 if (rc >= 0)
3907 led * led_exp_hlcl[ledstatus]); 3907 rc = ec_write(TPACPI_LED_EC_HLCL,
3908 break; 3908 (ledstatus != TPACPI_LED_OFF) << led);
3909 break;
3909 case TPACPI_LED_NEW: 3910 case TPACPI_LED_NEW:
3910 /* all others */ 3911 /* all others */
3911 if (!acpi_evalf(led_handle, NULL, NULL, "vdd", 3912 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
3912 led, led_led_arg1[ledstatus])) 3913 led, led_led_arg1[ledstatus]))
3913 rc = -EIO; 3914 rc = -EIO;
3914 break; 3915 break;
3915 default: 3916 default:
3916 rc = -ENXIO; 3917 rc = -ENXIO;
3917 } 3918 }