diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2007-10-30 15:46:25 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-11-05 13:07:11 -0500 |
commit | 4273af8d08c823d5898a2b1c2d0f25b4a8b9eaee (patch) | |
tree | 822101a563cd5fc7b87ea98498ca9e10ae7f8a02 | |
parent | fc589a3ce5f38db6239c147da4f9172a25575ecc (diff) |
ACPI: thinkpad-acpi: fix brightness_set error paths
The code calling brightness_set() can't handle EINTR/ERESTARTSYS well, nor
is it checking brightness_set() return status properly.
Fix it.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 306daa524c03..8c9430775285 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -3278,6 +3278,8 @@ static void brightness_exit(void) | |||
3278 | 3278 | ||
3279 | static int brightness_update_status(struct backlight_device *bd) | 3279 | static int brightness_update_status(struct backlight_device *bd) |
3280 | { | 3280 | { |
3281 | /* it is the backlight class's job (caller) to handle | ||
3282 | * EINTR and other errors properly */ | ||
3281 | return brightness_set( | 3283 | return brightness_set( |
3282 | (bd->props.fb_blank == FB_BLANK_UNBLANK && | 3284 | (bd->props.fb_blank == FB_BLANK_UNBLANK && |
3283 | bd->props.power == FB_BLANK_UNBLANK) ? | 3285 | bd->props.power == FB_BLANK_UNBLANK) ? |
@@ -3318,6 +3320,7 @@ static int brightness_get(struct backlight_device *bd) | |||
3318 | return level; | 3320 | return level; |
3319 | } | 3321 | } |
3320 | 3322 | ||
3323 | /* May return EINTR which can always be mapped to ERESTARTSYS */ | ||
3321 | static int brightness_set(int value) | 3324 | static int brightness_set(int value) |
3322 | { | 3325 | { |
3323 | int cmos_cmd, inc, i, res; | 3326 | int cmos_cmd, inc, i, res; |
@@ -3381,29 +3384,34 @@ static int brightness_read(char *p) | |||
3381 | static int brightness_write(char *buf) | 3384 | static int brightness_write(char *buf) |
3382 | { | 3385 | { |
3383 | int level; | 3386 | int level; |
3384 | int new_level; | 3387 | int rc; |
3385 | char *cmd; | 3388 | char *cmd; |
3386 | int max_level = (tp_features.bright_16levels) ? 15 : 7; | 3389 | int max_level = (tp_features.bright_16levels) ? 15 : 7; |
3387 | 3390 | ||
3388 | while ((cmd = next_cmd(&buf))) { | 3391 | level = brightness_get(NULL); |
3389 | if ((level = brightness_get(NULL)) < 0) | 3392 | if (level < 0) |
3390 | return level; | 3393 | return level; |
3391 | 3394 | ||
3395 | while ((cmd = next_cmd(&buf))) { | ||
3392 | if (strlencmp(cmd, "up") == 0) { | 3396 | if (strlencmp(cmd, "up") == 0) { |
3393 | new_level = level == (max_level)? | 3397 | if (level < max_level) |
3394 | max_level : level + 1; | 3398 | level++; |
3395 | } else if (strlencmp(cmd, "down") == 0) { | 3399 | } else if (strlencmp(cmd, "down") == 0) { |
3396 | new_level = level == 0? 0 : level - 1; | 3400 | if (level > 0) |
3397 | } else if (sscanf(cmd, "level %d", &new_level) == 1 && | 3401 | level--; |
3398 | new_level >= 0 && new_level <= max_level) { | 3402 | } else if (sscanf(cmd, "level %d", &level) == 1 && |
3399 | /* new_level set */ | 3403 | level >= 0 && level <= max_level) { |
3404 | /* new level set */ | ||
3400 | } else | 3405 | } else |
3401 | return -EINVAL; | 3406 | return -EINVAL; |
3402 | |||
3403 | brightness_set(new_level); | ||
3404 | } | 3407 | } |
3405 | 3408 | ||
3406 | return 0; | 3409 | /* |
3410 | * Now we know what the final level should be, so we try to set it. | ||
3411 | * Doing it this way makes the syscall restartable in case of EINTR | ||
3412 | */ | ||
3413 | rc = brightness_set(level); | ||
3414 | return (rc == -EINTR)? ERESTARTSYS : rc; | ||
3407 | } | 3415 | } |
3408 | 3416 | ||
3409 | static struct ibm_struct brightness_driver_data = { | 3417 | static struct ibm_struct brightness_driver_data = { |