diff options
author | Len Brown <len.brown@intel.com> | 2007-11-20 01:20:42 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-11-20 01:20:42 -0500 |
commit | d12dbbfe948c89156ad1b0fe7c808ba4d6f00bc2 (patch) | |
tree | bc653ac4e505e5cba8ecf8186e2e8e32758d911c | |
parent | 614a6bbecceb97558819f18a676fd819ea61550b (diff) | |
parent | 59f91ff11e594913a5b3c03a4707fdf02338c8df (diff) |
Pull thinkpad-2.6.24 into release branch
-rw-r--r-- | Documentation/thinkpad-acpi.txt | 73 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 231 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.h | 4 |
3 files changed, 226 insertions, 82 deletions
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index ec499265deca..10c041ca13c7 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt | |||
@@ -1,7 +1,7 @@ | |||
1 | ThinkPad ACPI Extras Driver | 1 | ThinkPad ACPI Extras Driver |
2 | 2 | ||
3 | Version 0.16 | 3 | Version 0.17 |
4 | August 2nd, 2007 | 4 | October 04th, 2007 |
5 | 5 | ||
6 | Borislav Deianov <borislav@users.sf.net> | 6 | Borislav Deianov <borislav@users.sf.net> |
7 | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 7 | Henrique de Moraes Holschuh <hmh@hmh.eng.br> |
@@ -923,19 +923,34 @@ sysfs backlight device "thinkpad_screen" | |||
923 | This feature allows software control of the LCD brightness on ThinkPad | 923 | This feature allows software control of the LCD brightness on ThinkPad |
924 | models which don't have a hardware brightness slider. | 924 | models which don't have a hardware brightness slider. |
925 | 925 | ||
926 | It has some limitations: the LCD backlight cannot be actually turned on or off | 926 | It has some limitations: the LCD backlight cannot be actually turned on or |
927 | by this interface, and in many ThinkPad models, the "dim while on battery" | 927 | off by this interface, and in many ThinkPad models, the "dim while on |
928 | functionality will be enabled by the BIOS when this interface is used, and | 928 | battery" functionality will be enabled by the BIOS when this interface is |
929 | cannot be controlled. | 929 | used, and cannot be controlled. |
930 | 930 | ||
931 | The backlight control has eight levels, ranging from 0 to 7. Some of the | 931 | On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control |
932 | levels may not be distinct. | 932 | has eight brightness levels, ranging from 0 to 7. Some of the levels |
933 | 933 | may not be distinct. Later Lenovo models that implement the ACPI | |
934 | There are two interfaces to the firmware for brightness control, EC and CMOS. | 934 | display backlight brightness control methods have 16 levels, ranging |
935 | To select which one should be used, use the brightness_mode module parameter: | 935 | from 0 to 15. |
936 | brightness_mode=1 selects EC mode, brightness_mode=2 selects CMOS mode, | 936 | |
937 | brightness_mode=3 selects both EC and CMOS. The driver tries to autodetect | 937 | There are two interfaces to the firmware for direct brightness control, |
938 | which interface to use. | 938 | EC and CMOS. To select which one should be used, use the |
939 | brightness_mode module parameter: brightness_mode=1 selects EC mode, | ||
940 | brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC | ||
941 | and CMOS. The driver tries to autodetect which interface to use. | ||
942 | |||
943 | When display backlight brightness controls are available through the | ||
944 | standard ACPI interface, it is best to use it instead of this direct | ||
945 | ThinkPad-specific interface. The driver will disable its native | ||
946 | backlight brightness control interface if it detects that the standard | ||
947 | ACPI interface is available in the ThinkPad. | ||
948 | |||
949 | The brightness_enable module parameter can be used to control whether | ||
950 | the LCD brightness control feature will be enabled when available. | ||
951 | brightness_enable=0 forces it to be disabled. brightness_enable=1 | ||
952 | forces it to be enabled when available, even if the standard ACPI | ||
953 | interface is also available. | ||
939 | 954 | ||
940 | Procfs notes: | 955 | Procfs notes: |
941 | 956 | ||
@@ -947,11 +962,11 @@ Procfs notes: | |||
947 | 962 | ||
948 | Sysfs notes: | 963 | Sysfs notes: |
949 | 964 | ||
950 | The interface is implemented through the backlight sysfs class, which is poorly | 965 | The interface is implemented through the backlight sysfs class, which is |
951 | documented at this time. | 966 | poorly documented at this time. |
952 | 967 | ||
953 | Locate the thinkpad_screen device under /sys/class/backlight, and inside it | 968 | Locate the thinkpad_screen device under /sys/class/backlight, and inside |
954 | there will be the following attributes: | 969 | it there will be the following attributes: |
955 | 970 | ||
956 | max_brightness: | 971 | max_brightness: |
957 | Reads the maximum brightness the hardware can be set to. | 972 | Reads the maximum brightness the hardware can be set to. |
@@ -961,17 +976,19 @@ there will be the following attributes: | |||
961 | Reads what brightness the screen is set to at this instant. | 976 | Reads what brightness the screen is set to at this instant. |
962 | 977 | ||
963 | brightness: | 978 | brightness: |
964 | Writes request the driver to change brightness to the given | 979 | Writes request the driver to change brightness to the |
965 | value. Reads will tell you what brightness the driver is trying | 980 | given value. Reads will tell you what brightness the |
966 | to set the display to when "power" is set to zero and the display | 981 | driver is trying to set the display to when "power" is set |
967 | has not been dimmed by a kernel power management event. | 982 | to zero and the display has not been dimmed by a kernel |
983 | power management event. | ||
968 | 984 | ||
969 | power: | 985 | power: |
970 | power management mode, where 0 is "display on", and 1 to 3 will | 986 | power management mode, where 0 is "display on", and 1 to 3 |
971 | dim the display backlight to brightness level 0 because | 987 | will dim the display backlight to brightness level 0 |
972 | thinkpad-acpi cannot really turn the backlight off. Kernel | 988 | because thinkpad-acpi cannot really turn the backlight |
973 | power management events can temporarily increase the current | 989 | off. Kernel power management events can temporarily |
974 | power management level, i.e. they can dim the display. | 990 | increase the current power management level, i.e. they can |
991 | dim the display. | ||
975 | 992 | ||
976 | 993 | ||
977 | Volume control -- /proc/acpi/ibm/volume | 994 | Volume control -- /proc/acpi/ibm/volume |
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index e953276664a0..ab23a3221585 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -21,7 +21,7 @@ | |||
21 | * 02110-1301, USA. | 21 | * 02110-1301, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define IBM_VERSION "0.16" | 24 | #define IBM_VERSION "0.17" |
25 | #define TPACPI_SYSFS_VERSION 0x020000 | 25 | #define TPACPI_SYSFS_VERSION 0x020000 |
26 | 26 | ||
27 | /* | 27 | /* |
@@ -964,15 +964,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
964 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ | 964 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ |
965 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | 965 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ |
966 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | 966 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ |
967 | KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ | 967 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ |
968 | /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ | 968 | /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ |
969 | KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ | 969 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ |
970 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | 970 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ |
971 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | 971 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ |
972 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | 972 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ |
973 | KEY_VOLUMEUP, /* 0x14: VOLUME UP */ | 973 | KEY_RESERVED, /* 0x14: VOLUME UP */ |
974 | KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */ | 974 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ |
975 | KEY_MUTE, /* 0x16: MUTE */ | 975 | KEY_RESERVED, /* 0x16: MUTE */ |
976 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | 976 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ |
977 | /* (assignments unknown, please report if found) */ | 977 | /* (assignments unknown, please report if found) */ |
978 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | 978 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
@@ -993,9 +993,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
993 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | 993 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ |
994 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | 994 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ |
995 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | 995 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ |
996 | KEY_VOLUMEUP, /* 0x14: VOLUME UP */ | 996 | KEY_RESERVED, /* 0x14: VOLUME UP */ |
997 | KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */ | 997 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ |
998 | KEY_MUTE, /* 0x16: MUTE */ | 998 | KEY_RESERVED, /* 0x16: MUTE */ |
999 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | 999 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ |
1000 | /* (assignments unknown, please report if found) */ | 1000 | /* (assignments unknown, please report if found) */ |
1001 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | 1001 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
@@ -1342,9 +1342,8 @@ static int hotkey_read(char *p) | |||
1342 | return len; | 1342 | return len; |
1343 | } | 1343 | } |
1344 | 1344 | ||
1345 | res = mutex_lock_interruptible(&hotkey_mutex); | 1345 | if (mutex_lock_interruptible(&hotkey_mutex)) |
1346 | if (res < 0) | 1346 | return -ERESTARTSYS; |
1347 | return res; | ||
1348 | res = hotkey_get(&status, &mask); | 1347 | res = hotkey_get(&status, &mask); |
1349 | mutex_unlock(&hotkey_mutex); | 1348 | mutex_unlock(&hotkey_mutex); |
1350 | if (res) | 1349 | if (res) |
@@ -1373,9 +1372,8 @@ static int hotkey_write(char *buf) | |||
1373 | if (!tp_features.hotkey) | 1372 | if (!tp_features.hotkey) |
1374 | return -ENODEV; | 1373 | return -ENODEV; |
1375 | 1374 | ||
1376 | res = mutex_lock_interruptible(&hotkey_mutex); | 1375 | if (mutex_lock_interruptible(&hotkey_mutex)) |
1377 | if (res < 0) | 1376 | return -ERESTARTSYS; |
1378 | return res; | ||
1379 | 1377 | ||
1380 | res = hotkey_get(&status, &mask); | 1378 | res = hotkey_get(&status, &mask); |
1381 | if (res) | 1379 | if (res) |
@@ -3114,6 +3112,99 @@ static struct backlight_ops ibm_backlight_data = { | |||
3114 | 3112 | ||
3115 | static struct mutex brightness_mutex; | 3113 | static struct mutex brightness_mutex; |
3116 | 3114 | ||
3115 | static int __init tpacpi_query_bcll_levels(acpi_handle handle) | ||
3116 | { | ||
3117 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
3118 | union acpi_object *obj; | ||
3119 | int rc; | ||
3120 | |||
3121 | if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { | ||
3122 | obj = (union acpi_object *)buffer.pointer; | ||
3123 | if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { | ||
3124 | printk(IBM_ERR "Unknown BCLL data, " | ||
3125 | "please report this to %s\n", IBM_MAIL); | ||
3126 | rc = 0; | ||
3127 | } else { | ||
3128 | rc = obj->package.count; | ||
3129 | } | ||
3130 | } else { | ||
3131 | return 0; | ||
3132 | } | ||
3133 | |||
3134 | kfree(buffer.pointer); | ||
3135 | return rc; | ||
3136 | } | ||
3137 | |||
3138 | static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl, | ||
3139 | void *context, void **rv) | ||
3140 | { | ||
3141 | char name[ACPI_PATH_SEGMENT_LENGTH]; | ||
3142 | struct acpi_buffer buffer = { sizeof(name), &name }; | ||
3143 | |||
3144 | if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && | ||
3145 | !strncmp("BCLL", name, sizeof(name) - 1)) { | ||
3146 | if (tpacpi_query_bcll_levels(handle) == 16) { | ||
3147 | *rv = handle; | ||
3148 | return AE_CTRL_TERMINATE; | ||
3149 | } else { | ||
3150 | return AE_OK; | ||
3151 | } | ||
3152 | } else { | ||
3153 | return AE_OK; | ||
3154 | } | ||
3155 | } | ||
3156 | |||
3157 | static int __init brightness_check_levels(void) | ||
3158 | { | ||
3159 | int status; | ||
3160 | void *found_node = NULL; | ||
3161 | |||
3162 | if (!vid_handle) { | ||
3163 | IBM_ACPIHANDLE_INIT(vid); | ||
3164 | } | ||
3165 | if (!vid_handle) | ||
3166 | return 0; | ||
3167 | |||
3168 | /* Search for a BCLL package with 16 levels */ | ||
3169 | status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3, | ||
3170 | brightness_find_bcll, NULL, &found_node); | ||
3171 | |||
3172 | return (ACPI_SUCCESS(status) && found_node != NULL); | ||
3173 | } | ||
3174 | |||
3175 | static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl, | ||
3176 | void *context, void **rv) | ||
3177 | { | ||
3178 | char name[ACPI_PATH_SEGMENT_LENGTH]; | ||
3179 | struct acpi_buffer buffer = { sizeof(name), &name }; | ||
3180 | |||
3181 | if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && | ||
3182 | !strncmp("_BCL", name, sizeof(name) - 1)) { | ||
3183 | *rv = handle; | ||
3184 | return AE_CTRL_TERMINATE; | ||
3185 | } else { | ||
3186 | return AE_OK; | ||
3187 | } | ||
3188 | } | ||
3189 | |||
3190 | static int __init brightness_check_std_acpi_support(void) | ||
3191 | { | ||
3192 | int status; | ||
3193 | void *found_node = NULL; | ||
3194 | |||
3195 | if (!vid_handle) { | ||
3196 | IBM_ACPIHANDLE_INIT(vid); | ||
3197 | } | ||
3198 | if (!vid_handle) | ||
3199 | return 0; | ||
3200 | |||
3201 | /* Search for a _BCL method, but don't execute it */ | ||
3202 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, | ||
3203 | brightness_find_bcl, NULL, &found_node); | ||
3204 | |||
3205 | return (ACPI_SUCCESS(status) && found_node != NULL); | ||
3206 | } | ||
3207 | |||
3117 | static int __init brightness_init(struct ibm_init_struct *iibm) | 3208 | static int __init brightness_init(struct ibm_init_struct *iibm) |
3118 | { | 3209 | { |
3119 | int b; | 3210 | int b; |
@@ -3122,6 +3213,18 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
3122 | 3213 | ||
3123 | mutex_init(&brightness_mutex); | 3214 | mutex_init(&brightness_mutex); |
3124 | 3215 | ||
3216 | if (!brightness_enable) { | ||
3217 | dbg_printk(TPACPI_DBG_INIT, | ||
3218 | "brightness support disabled by module parameter\n"); | ||
3219 | return 1; | ||
3220 | } else if (brightness_enable > 1) { | ||
3221 | if (brightness_check_std_acpi_support()) { | ||
3222 | printk(IBM_NOTICE | ||
3223 | "standard ACPI backlight interface available, not loading native one...\n"); | ||
3224 | return 1; | ||
3225 | } | ||
3226 | } | ||
3227 | |||
3125 | if (!brightness_mode) { | 3228 | if (!brightness_mode) { |
3126 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) | 3229 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) |
3127 | brightness_mode = 2; | 3230 | brightness_mode = 2; |
@@ -3135,10 +3238,17 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
3135 | if (brightness_mode > 3) | 3238 | if (brightness_mode > 3) |
3136 | return -EINVAL; | 3239 | return -EINVAL; |
3137 | 3240 | ||
3241 | tp_features.bright_16levels = | ||
3242 | thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO && | ||
3243 | brightness_check_levels(); | ||
3244 | |||
3138 | b = brightness_get(NULL); | 3245 | b = brightness_get(NULL); |
3139 | if (b < 0) | 3246 | if (b < 0) |
3140 | return 1; | 3247 | return 1; |
3141 | 3248 | ||
3249 | if (tp_features.bright_16levels) | ||
3250 | printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n"); | ||
3251 | |||
3142 | ibm_backlight_device = backlight_device_register( | 3252 | ibm_backlight_device = backlight_device_register( |
3143 | TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, | 3253 | TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, |
3144 | &ibm_backlight_data); | 3254 | &ibm_backlight_data); |
@@ -3148,7 +3258,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
3148 | } | 3258 | } |
3149 | vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); | 3259 | vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); |
3150 | 3260 | ||
3151 | ibm_backlight_device->props.max_brightness = 7; | 3261 | ibm_backlight_device->props.max_brightness = |
3262 | (tp_features.bright_16levels)? 15 : 7; | ||
3152 | ibm_backlight_device->props.brightness = b; | 3263 | ibm_backlight_device->props.brightness = b; |
3153 | backlight_update_status(ibm_backlight_device); | 3264 | backlight_update_status(ibm_backlight_device); |
3154 | 3265 | ||
@@ -3167,6 +3278,8 @@ static void brightness_exit(void) | |||
3167 | 3278 | ||
3168 | static int brightness_update_status(struct backlight_device *bd) | 3279 | static int brightness_update_status(struct backlight_device *bd) |
3169 | { | 3280 | { |
3281 | /* it is the backlight class's job (caller) to handle | ||
3282 | * EINTR and other errors properly */ | ||
3170 | return brightness_set( | 3283 | return brightness_set( |
3171 | (bd->props.fb_blank == FB_BLANK_UNBLANK && | 3284 | (bd->props.fb_blank == FB_BLANK_UNBLANK && |
3172 | bd->props.power == FB_BLANK_UNBLANK) ? | 3285 | bd->props.power == FB_BLANK_UNBLANK) ? |
@@ -3184,13 +3297,14 @@ static int brightness_get(struct backlight_device *bd) | |||
3184 | if (brightness_mode & 1) { | 3297 | if (brightness_mode & 1) { |
3185 | if (!acpi_ec_read(brightness_offset, &lec)) | 3298 | if (!acpi_ec_read(brightness_offset, &lec)) |
3186 | return -EIO; | 3299 | return -EIO; |
3187 | lec &= 7; | 3300 | lec &= (tp_features.bright_16levels)? 0x0f : 0x07; |
3188 | level = lec; | 3301 | level = lec; |
3189 | }; | 3302 | }; |
3190 | if (brightness_mode & 2) { | 3303 | if (brightness_mode & 2) { |
3191 | lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) | 3304 | lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) |
3192 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | 3305 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) |
3193 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; | 3306 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; |
3307 | lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07; | ||
3194 | level = lcmos; | 3308 | level = lcmos; |
3195 | } | 3309 | } |
3196 | 3310 | ||
@@ -3206,12 +3320,13 @@ static int brightness_get(struct backlight_device *bd) | |||
3206 | return level; | 3320 | return level; |
3207 | } | 3321 | } |
3208 | 3322 | ||
3323 | /* May return EINTR which can always be mapped to ERESTARTSYS */ | ||
3209 | static int brightness_set(int value) | 3324 | static int brightness_set(int value) |
3210 | { | 3325 | { |
3211 | int cmos_cmd, inc, i, res; | 3326 | int cmos_cmd, inc, i, res; |
3212 | int current_value; | 3327 | int current_value; |
3213 | 3328 | ||
3214 | if (value > 7) | 3329 | if (value > ((tp_features.bright_16levels)? 15 : 7)) |
3215 | return -EINVAL; | 3330 | return -EINVAL; |
3216 | 3331 | ||
3217 | res = mutex_lock_interruptible(&brightness_mutex); | 3332 | res = mutex_lock_interruptible(&brightness_mutex); |
@@ -3227,7 +3342,7 @@ static int brightness_set(int value) | |||
3227 | cmos_cmd = value > current_value ? | 3342 | cmos_cmd = value > current_value ? |
3228 | TP_CMOS_BRIGHTNESS_UP : | 3343 | TP_CMOS_BRIGHTNESS_UP : |
3229 | TP_CMOS_BRIGHTNESS_DOWN; | 3344 | TP_CMOS_BRIGHTNESS_DOWN; |
3230 | inc = value > current_value ? 1 : -1; | 3345 | inc = (value > current_value)? 1 : -1; |
3231 | 3346 | ||
3232 | res = 0; | 3347 | res = 0; |
3233 | for (i = current_value; i != value; i += inc) { | 3348 | for (i = current_value; i != value; i += inc) { |
@@ -3256,10 +3371,11 @@ static int brightness_read(char *p) | |||
3256 | if ((level = brightness_get(NULL)) < 0) { | 3371 | if ((level = brightness_get(NULL)) < 0) { |
3257 | len += sprintf(p + len, "level:\t\tunreadable\n"); | 3372 | len += sprintf(p + len, "level:\t\tunreadable\n"); |
3258 | } else { | 3373 | } else { |
3259 | len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); | 3374 | len += sprintf(p + len, "level:\t\t%d\n", level); |
3260 | len += sprintf(p + len, "commands:\tup, down\n"); | 3375 | len += sprintf(p + len, "commands:\tup, down\n"); |
3261 | len += sprintf(p + len, "commands:\tlevel <level>" | 3376 | len += sprintf(p + len, "commands:\tlevel <level>" |
3262 | " (<level> is 0-7)\n"); | 3377 | " (<level> is 0-%d)\n", |
3378 | (tp_features.bright_16levels) ? 15 : 7); | ||
3263 | } | 3379 | } |
3264 | 3380 | ||
3265 | return len; | 3381 | return len; |
@@ -3268,28 +3384,34 @@ static int brightness_read(char *p) | |||
3268 | static int brightness_write(char *buf) | 3384 | static int brightness_write(char *buf) |
3269 | { | 3385 | { |
3270 | int level; | 3386 | int level; |
3271 | int new_level; | 3387 | int rc; |
3272 | char *cmd; | 3388 | char *cmd; |
3389 | int max_level = (tp_features.bright_16levels) ? 15 : 7; | ||
3273 | 3390 | ||
3274 | while ((cmd = next_cmd(&buf))) { | 3391 | level = brightness_get(NULL); |
3275 | if ((level = brightness_get(NULL)) < 0) | 3392 | if (level < 0) |
3276 | return level; | 3393 | return level; |
3277 | level &= 7; | ||
3278 | 3394 | ||
3395 | while ((cmd = next_cmd(&buf))) { | ||
3279 | if (strlencmp(cmd, "up") == 0) { | 3396 | if (strlencmp(cmd, "up") == 0) { |
3280 | new_level = level == 7 ? 7 : level + 1; | 3397 | if (level < max_level) |
3398 | level++; | ||
3281 | } else if (strlencmp(cmd, "down") == 0) { | 3399 | } else if (strlencmp(cmd, "down") == 0) { |
3282 | new_level = level == 0 ? 0 : level - 1; | 3400 | if (level > 0) |
3283 | } else if (sscanf(cmd, "level %d", &new_level) == 1 && | 3401 | level--; |
3284 | new_level >= 0 && new_level <= 7) { | 3402 | } else if (sscanf(cmd, "level %d", &level) == 1 && |
3285 | /* new_level set */ | 3403 | level >= 0 && level <= max_level) { |
3404 | /* new level set */ | ||
3286 | } else | 3405 | } else |
3287 | return -EINVAL; | 3406 | return -EINVAL; |
3288 | |||
3289 | brightness_set(new_level); | ||
3290 | } | 3407 | } |
3291 | 3408 | ||
3292 | 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; | ||
3293 | } | 3415 | } |
3294 | 3416 | ||
3295 | static struct ibm_struct brightness_driver_data = { | 3417 | static struct ibm_struct brightness_driver_data = { |
@@ -3652,9 +3774,8 @@ static ssize_t fan_pwm1_store(struct device *dev, | |||
3652 | /* scale down from 0-255 to 0-7 */ | 3774 | /* scale down from 0-255 to 0-7 */ |
3653 | newlevel = (s >> 5) & 0x07; | 3775 | newlevel = (s >> 5) & 0x07; |
3654 | 3776 | ||
3655 | rc = mutex_lock_interruptible(&fan_mutex); | 3777 | if (mutex_lock_interruptible(&fan_mutex)) |
3656 | if (rc < 0) | 3778 | return -ERESTARTSYS; |
3657 | return rc; | ||
3658 | 3779 | ||
3659 | rc = fan_get_status(&status); | 3780 | rc = fan_get_status(&status); |
3660 | if (!rc && (status & | 3781 | if (!rc && (status & |
@@ -3904,9 +4025,8 @@ static int fan_get_status_safe(u8 *status) | |||
3904 | int rc; | 4025 | int rc; |
3905 | u8 s; | 4026 | u8 s; |
3906 | 4027 | ||
3907 | rc = mutex_lock_interruptible(&fan_mutex); | 4028 | if (mutex_lock_interruptible(&fan_mutex)) |
3908 | if (rc < 0) | 4029 | return -ERESTARTSYS; |
3909 | return rc; | ||
3910 | rc = fan_get_status(&s); | 4030 | rc = fan_get_status(&s); |
3911 | if (!rc) | 4031 | if (!rc) |
3912 | fan_update_desired_level(s); | 4032 | fan_update_desired_level(s); |
@@ -4040,9 +4160,8 @@ static int fan_set_level_safe(int level) | |||
4040 | if (!fan_control_allowed) | 4160 | if (!fan_control_allowed) |
4041 | return -EPERM; | 4161 | return -EPERM; |
4042 | 4162 | ||
4043 | rc = mutex_lock_interruptible(&fan_mutex); | 4163 | if (mutex_lock_interruptible(&fan_mutex)) |
4044 | if (rc < 0) | 4164 | return -ERESTARTSYS; |
4045 | return rc; | ||
4046 | 4165 | ||
4047 | if (level == TPACPI_FAN_LAST_LEVEL) | 4166 | if (level == TPACPI_FAN_LAST_LEVEL) |
4048 | level = fan_control_desired_level; | 4167 | level = fan_control_desired_level; |
@@ -4063,9 +4182,8 @@ static int fan_set_enable(void) | |||
4063 | if (!fan_control_allowed) | 4182 | if (!fan_control_allowed) |
4064 | return -EPERM; | 4183 | return -EPERM; |
4065 | 4184 | ||
4066 | rc = mutex_lock_interruptible(&fan_mutex); | 4185 | if (mutex_lock_interruptible(&fan_mutex)) |
4067 | if (rc < 0) | 4186 | return -ERESTARTSYS; |
4068 | return rc; | ||
4069 | 4187 | ||
4070 | switch (fan_control_access_mode) { | 4188 | switch (fan_control_access_mode) { |
4071 | case TPACPI_FAN_WR_ACPI_FANS: | 4189 | case TPACPI_FAN_WR_ACPI_FANS: |
@@ -4119,9 +4237,8 @@ static int fan_set_disable(void) | |||
4119 | if (!fan_control_allowed) | 4237 | if (!fan_control_allowed) |
4120 | return -EPERM; | 4238 | return -EPERM; |
4121 | 4239 | ||
4122 | rc = mutex_lock_interruptible(&fan_mutex); | 4240 | if (mutex_lock_interruptible(&fan_mutex)) |
4123 | if (rc < 0) | 4241 | return -ERESTARTSYS; |
4124 | return rc; | ||
4125 | 4242 | ||
4126 | rc = 0; | 4243 | rc = 0; |
4127 | switch (fan_control_access_mode) { | 4244 | switch (fan_control_access_mode) { |
@@ -4158,9 +4275,8 @@ static int fan_set_speed(int speed) | |||
4158 | if (!fan_control_allowed) | 4275 | if (!fan_control_allowed) |
4159 | return -EPERM; | 4276 | return -EPERM; |
4160 | 4277 | ||
4161 | rc = mutex_lock_interruptible(&fan_mutex); | 4278 | if (mutex_lock_interruptible(&fan_mutex)) |
4162 | if (rc < 0) | 4279 | return -ERESTARTSYS; |
4163 | return rc; | ||
4164 | 4280 | ||
4165 | rc = 0; | 4281 | rc = 0; |
4166 | switch (fan_control_access_mode) { | 4282 | switch (fan_control_access_mode) { |
@@ -4701,9 +4817,15 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp) | |||
4701 | unsigned int i; | 4817 | unsigned int i; |
4702 | struct ibm_struct *ibm; | 4818 | struct ibm_struct *ibm; |
4703 | 4819 | ||
4820 | if (!kp || !kp->name || !val) | ||
4821 | return -EINVAL; | ||
4822 | |||
4704 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { | 4823 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { |
4705 | ibm = ibms_init[i].data; | 4824 | ibm = ibms_init[i].data; |
4706 | BUG_ON(ibm == NULL); | 4825 | WARN_ON(ibm == NULL); |
4826 | |||
4827 | if (!ibm || !ibm->name) | ||
4828 | continue; | ||
4707 | 4829 | ||
4708 | if (strcmp(ibm->name, kp->name) == 0 && ibm->write) { | 4830 | if (strcmp(ibm->name, kp->name) == 0 && ibm->write) { |
4709 | if (strlen(val) > sizeof(ibms_init[i].param) - 2) | 4831 | if (strlen(val) > sizeof(ibms_init[i].param) - 2) |
@@ -4732,6 +4854,9 @@ module_param_named(fan_control, fan_control_allowed, bool, 0); | |||
4732 | static int brightness_mode; | 4854 | static int brightness_mode; |
4733 | module_param_named(brightness_mode, brightness_mode, int, 0); | 4855 | module_param_named(brightness_mode, brightness_mode, int, 0); |
4734 | 4856 | ||
4857 | static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ | ||
4858 | module_param(brightness_enable, uint, 0); | ||
4859 | |||
4735 | static unsigned int hotkey_report_mode; | 4860 | static unsigned int hotkey_report_mode; |
4736 | module_param(hotkey_report_mode, uint, 0); | 4861 | module_param(hotkey_report_mode, uint, 0); |
4737 | 4862 | ||
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 3abcc8120634..8fba2bbe345e 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h | |||
@@ -84,7 +84,7 @@ | |||
84 | 84 | ||
85 | /* ThinkPad CMOS NVRAM constants */ | 85 | /* ThinkPad CMOS NVRAM constants */ |
86 | #define TP_NVRAM_ADDR_BRIGHTNESS 0x5e | 86 | #define TP_NVRAM_ADDR_BRIGHTNESS 0x5e |
87 | #define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07 | 87 | #define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x0f |
88 | #define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0 | 88 | #define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0 |
89 | 89 | ||
90 | #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") | 90 | #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") |
@@ -246,6 +246,7 @@ static struct { | |||
246 | u32 hotkey_wlsw:1; | 246 | u32 hotkey_wlsw:1; |
247 | u32 light:1; | 247 | u32 light:1; |
248 | u32 light_status:1; | 248 | u32 light_status:1; |
249 | u32 bright_16levels:1; | ||
249 | u32 wan:1; | 250 | u32 wan:1; |
250 | u32 fan_ctrl_status_undef:1; | 251 | u32 fan_ctrl_status_undef:1; |
251 | u32 input_device_registered:1; | 252 | u32 input_device_registered:1; |
@@ -338,6 +339,7 @@ static int bluetooth_write(char *buf); | |||
338 | static struct backlight_device *ibm_backlight_device; | 339 | static struct backlight_device *ibm_backlight_device; |
339 | static int brightness_offset = 0x31; | 340 | static int brightness_offset = 0x31; |
340 | static int brightness_mode; | 341 | static int brightness_mode; |
342 | static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */ | ||
341 | 343 | ||
342 | static int brightness_init(struct ibm_init_struct *iibm); | 344 | static int brightness_init(struct ibm_init_struct *iibm); |
343 | static void brightness_exit(void); | 345 | static void brightness_exit(void); |