aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/thinkpad_acpi.c91
-rw-r--r--drivers/misc/thinkpad_acpi.h3
2 files changed, 83 insertions, 11 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 63b1e2610c60..322ba25b4798 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -3114,6 +3114,66 @@ static struct backlight_ops ibm_backlight_data = {
3114 3114
3115static struct mutex brightness_mutex; 3115static struct mutex brightness_mutex;
3116 3116
3117static int __init tpacpi_query_bcll_levels(acpi_handle handle)
3118{
3119 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
3120 union acpi_object *obj;
3121 int rc;
3122
3123 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
3124 obj = (union acpi_object *)buffer.pointer;
3125 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
3126 printk(IBM_ERR "Unknown BCLL data, "
3127 "please report this to %s\n", IBM_MAIL);
3128 rc = 0;
3129 } else {
3130 rc = obj->package.count;
3131 }
3132 } else {
3133 return 0;
3134 }
3135
3136 kfree(buffer.pointer);
3137 return rc;
3138}
3139
3140static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
3141 void *context, void **rv)
3142{
3143 char name[ACPI_PATH_SEGMENT_LENGTH];
3144 struct acpi_buffer buffer = { sizeof(name), &name };
3145
3146 if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
3147 !strncmp("BCLL", name, sizeof(name) - 1)) {
3148 if (tpacpi_query_bcll_levels(handle) == 16) {
3149 *rv = handle;
3150 return AE_CTRL_TERMINATE;
3151 } else {
3152 return AE_OK;
3153 }
3154 } else {
3155 return AE_OK;
3156 }
3157}
3158
3159static int __init brightness_check_levels(void)
3160{
3161 int status;
3162 void *found_node = NULL;
3163
3164 if (!vid_handle) {
3165 IBM_ACPIHANDLE_INIT(vid);
3166 }
3167 if (!vid_handle)
3168 return 0;
3169
3170 /* Search for a BCLL package with 16 levels */
3171 status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
3172 brightness_find_bcll, NULL, &found_node);
3173
3174 return (ACPI_SUCCESS(status) && found_node != NULL);
3175}
3176
3117static int __init brightness_init(struct ibm_init_struct *iibm) 3177static int __init brightness_init(struct ibm_init_struct *iibm)
3118{ 3178{
3119 int b; 3179 int b;
@@ -3135,10 +3195,17 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
3135 if (brightness_mode > 3) 3195 if (brightness_mode > 3)
3136 return -EINVAL; 3196 return -EINVAL;
3137 3197
3198 tp_features.bright_16levels =
3199 thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
3200 brightness_check_levels();
3201
3138 b = brightness_get(NULL); 3202 b = brightness_get(NULL);
3139 if (b < 0) 3203 if (b < 0)
3140 return 1; 3204 return 1;
3141 3205
3206 if (tp_features.bright_16levels)
3207 printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n");
3208
3142 ibm_backlight_device = backlight_device_register( 3209 ibm_backlight_device = backlight_device_register(
3143 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, 3210 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
3144 &ibm_backlight_data); 3211 &ibm_backlight_data);
@@ -3148,7 +3215,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
3148 } 3215 }
3149 vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); 3216 vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
3150 3217
3151 ibm_backlight_device->props.max_brightness = 7; 3218 ibm_backlight_device->props.max_brightness =
3219 (tp_features.bright_16levels)? 15 : 7;
3152 ibm_backlight_device->props.brightness = b; 3220 ibm_backlight_device->props.brightness = b;
3153 backlight_update_status(ibm_backlight_device); 3221 backlight_update_status(ibm_backlight_device);
3154 3222
@@ -3184,13 +3252,14 @@ static int brightness_get(struct backlight_device *bd)
3184 if (brightness_mode & 1) { 3252 if (brightness_mode & 1) {
3185 if (!acpi_ec_read(brightness_offset, &lec)) 3253 if (!acpi_ec_read(brightness_offset, &lec))
3186 return -EIO; 3254 return -EIO;
3187 lec &= 7; 3255 lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
3188 level = lec; 3256 level = lec;
3189 }; 3257 };
3190 if (brightness_mode & 2) { 3258 if (brightness_mode & 2) {
3191 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) 3259 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
3192 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) 3260 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
3193 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; 3261 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
3262 lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
3194 level = lcmos; 3263 level = lcmos;
3195 } 3264 }
3196 3265
@@ -3211,7 +3280,7 @@ static int brightness_set(int value)
3211 int cmos_cmd, inc, i, res; 3280 int cmos_cmd, inc, i, res;
3212 int current_value; 3281 int current_value;
3213 3282
3214 if (value > 7) 3283 if (value > ((tp_features.bright_16levels)? 15 : 7))
3215 return -EINVAL; 3284 return -EINVAL;
3216 3285
3217 res = mutex_lock_interruptible(&brightness_mutex); 3286 res = mutex_lock_interruptible(&brightness_mutex);
@@ -3227,7 +3296,7 @@ static int brightness_set(int value)
3227 cmos_cmd = value > current_value ? 3296 cmos_cmd = value > current_value ?
3228 TP_CMOS_BRIGHTNESS_UP : 3297 TP_CMOS_BRIGHTNESS_UP :
3229 TP_CMOS_BRIGHTNESS_DOWN; 3298 TP_CMOS_BRIGHTNESS_DOWN;
3230 inc = value > current_value ? 1 : -1; 3299 inc = (value > current_value)? 1 : -1;
3231 3300
3232 res = 0; 3301 res = 0;
3233 for (i = current_value; i != value; i += inc) { 3302 for (i = current_value; i != value; i += inc) {
@@ -3256,10 +3325,11 @@ static int brightness_read(char *p)
3256 if ((level = brightness_get(NULL)) < 0) { 3325 if ((level = brightness_get(NULL)) < 0) {
3257 len += sprintf(p + len, "level:\t\tunreadable\n"); 3326 len += sprintf(p + len, "level:\t\tunreadable\n");
3258 } else { 3327 } else {
3259 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); 3328 len += sprintf(p + len, "level:\t\t%d\n", level);
3260 len += sprintf(p + len, "commands:\tup, down\n"); 3329 len += sprintf(p + len, "commands:\tup, down\n");
3261 len += sprintf(p + len, "commands:\tlevel <level>" 3330 len += sprintf(p + len, "commands:\tlevel <level>"
3262 " (<level> is 0-7)\n"); 3331 " (<level> is 0-%d)\n",
3332 (tp_features.bright_16levels) ? 15 : 7);
3263 } 3333 }
3264 3334
3265 return len; 3335 return len;
@@ -3270,18 +3340,19 @@ static int brightness_write(char *buf)
3270 int level; 3340 int level;
3271 int new_level; 3341 int new_level;
3272 char *cmd; 3342 char *cmd;
3343 int max_level = (tp_features.bright_16levels) ? 15 : 7;
3273 3344
3274 while ((cmd = next_cmd(&buf))) { 3345 while ((cmd = next_cmd(&buf))) {
3275 if ((level = brightness_get(NULL)) < 0) 3346 if ((level = brightness_get(NULL)) < 0)
3276 return level; 3347 return level;
3277 level &= 7;
3278 3348
3279 if (strlencmp(cmd, "up") == 0) { 3349 if (strlencmp(cmd, "up") == 0) {
3280 new_level = level == 7 ? 7 : level + 1; 3350 new_level = level == (max_level)?
3351 max_level : level + 1;
3281 } else if (strlencmp(cmd, "down") == 0) { 3352 } else if (strlencmp(cmd, "down") == 0) {
3282 new_level = level == 0 ? 0 : level - 1; 3353 new_level = level == 0? 0 : level - 1;
3283 } else if (sscanf(cmd, "level %d", &new_level) == 1 && 3354 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
3284 new_level >= 0 && new_level <= 7) { 3355 new_level >= 0 && new_level <= max_level) {
3285 /* new_level set */ 3356 /* new_level set */
3286 } else 3357 } else
3287 return -EINVAL; 3358 return -EINVAL;
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index 3abcc8120634..8ca19c333727 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;