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); |
