aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c251
1 files changed, 140 insertions, 111 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index a768a69d58d2..b03bf5153b0f 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -304,8 +304,8 @@ static struct {
304 u32 hotkey_tablet:1; 304 u32 hotkey_tablet:1;
305 u32 light:1; 305 u32 light:1;
306 u32 light_status:1; 306 u32 light_status:1;
307 u32 bright_16levels:1;
308 u32 bright_acpimode:1; 307 u32 bright_acpimode:1;
308 u32 bright_unkfw:1;
309 u32 wan:1; 309 u32 wan:1;
310 u32 uwb:1; 310 u32 uwb:1;
311 u32 fan_ctrl_status_undef:1; 311 u32 fan_ctrl_status_undef:1;
@@ -368,6 +368,9 @@ struct tpacpi_led_classdev {
368 unsigned int led; 368 unsigned int led;
369}; 369};
370 370
371/* brightness level capabilities */
372static unsigned int bright_maxlvl; /* 0 = unknown */
373
371#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 374#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
372static int dbg_wlswemul; 375static int dbg_wlswemul;
373static int tpacpi_wlsw_emulstate; 376static int tpacpi_wlsw_emulstate;
@@ -1051,80 +1054,6 @@ static void tpacpi_disable_brightness_delay(void)
1051 "ACPI backlight control delay disabled\n"); 1054 "ACPI backlight control delay disabled\n");
1052} 1055}
1053 1056
1054static int __init tpacpi_query_bcl_levels(acpi_handle handle)
1055{
1056 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1057 union acpi_object *obj;
1058 int rc;
1059
1060 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
1061 obj = (union acpi_object *)buffer.pointer;
1062 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
1063 printk(TPACPI_ERR "Unknown _BCL data, "
1064 "please report this to %s\n", TPACPI_MAIL);
1065 rc = 0;
1066 } else {
1067 rc = obj->package.count;
1068 }
1069 } else {
1070 return 0;
1071 }
1072
1073 kfree(buffer.pointer);
1074 return rc;
1075}
1076
1077static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle,
1078 u32 lvl, void *context, void **rv)
1079{
1080 char name[ACPI_PATH_SEGMENT_LENGTH];
1081 struct acpi_buffer buffer = { sizeof(name), &name };
1082
1083 if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
1084 !strncmp("_BCL", name, sizeof(name) - 1)) {
1085 BUG_ON(!rv || !*rv);
1086 **(int **)rv = tpacpi_query_bcl_levels(handle);
1087 return AE_CTRL_TERMINATE;
1088 } else {
1089 return AE_OK;
1090 }
1091}
1092
1093/*
1094 * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map
1095 */
1096static int __init tpacpi_check_std_acpi_brightness_support(void)
1097{
1098 int status;
1099 int bcl_levels = 0;
1100 void *bcl_ptr = &bcl_levels;
1101
1102 if (!vid_handle) {
1103 TPACPI_ACPIHANDLE_INIT(vid);
1104 }
1105 if (!vid_handle)
1106 return 0;
1107
1108 /*
1109 * Search for a _BCL method, and execute it. This is safe on all
1110 * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista
1111 * BIOS in ACPI backlight control mode. We do NOT have to care
1112 * about calling the _BCL method in an enabled video device, any
1113 * will do for our purposes.
1114 */
1115
1116 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
1117 tpacpi_acpi_walk_find_bcl, NULL, NULL,
1118 &bcl_ptr);
1119
1120 if (ACPI_SUCCESS(status) && bcl_levels > 2) {
1121 tp_features.bright_acpimode = 1;
1122 return (bcl_levels - 2);
1123 }
1124
1125 return 0;
1126}
1127
1128static void printk_deprecated_attribute(const char * const what, 1057static void printk_deprecated_attribute(const char * const what,
1129 const char * const details) 1058 const char * const details)
1130{ 1059{
@@ -3420,11 +3349,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
3420 } 3349 }
3421 3350
3422 /* Do not issue duplicate brightness change events to 3351 /* Do not issue duplicate brightness change events to
3423 * userspace */ 3352 * userspace. tpacpi_detect_brightness_capabilities() must have
3424 if (!tp_features.bright_acpimode) 3353 * been called before this point */
3425 /* update bright_acpimode... */
3426 tpacpi_check_std_acpi_brightness_support();
3427
3428 if (tp_features.bright_acpimode && acpi_video_backlight_support()) { 3354 if (tp_features.bright_acpimode && acpi_video_backlight_support()) {
3429 printk(TPACPI_INFO 3355 printk(TPACPI_INFO
3430 "This ThinkPad has standard ACPI backlight " 3356 "This ThinkPad has standard ACPI backlight "
@@ -5989,7 +5915,7 @@ static unsigned int tpacpi_brightness_nvram_get(void)
5989 lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) 5915 lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
5990 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) 5916 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
5991 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; 5917 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
5992 lnvram &= (tp_features.bright_16levels) ? 0x0f : 0x07; 5918 lnvram &= bright_maxlvl;
5993 5919
5994 return lnvram; 5920 return lnvram;
5995} 5921}
@@ -6098,8 +6024,7 @@ static int brightness_set(unsigned int value)
6098{ 6024{
6099 int res; 6025 int res;
6100 6026
6101 if (value > ((tp_features.bright_16levels)? 15 : 7) || 6027 if (value > bright_maxlvl || value < 0)
6102 value < 0)
6103 return -EINVAL; 6028 return -EINVAL;
6104 6029
6105 vdbg_printk(TPACPI_DBG_BRGHT, 6030 vdbg_printk(TPACPI_DBG_BRGHT,
@@ -6174,6 +6099,80 @@ static struct backlight_ops ibm_backlight_data = {
6174 6099
6175/* --------------------------------------------------------------------- */ 6100/* --------------------------------------------------------------------- */
6176 6101
6102static int __init tpacpi_query_bcl_levels(acpi_handle handle)
6103{
6104 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
6105 union acpi_object *obj;
6106 int rc;
6107
6108 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
6109 obj = (union acpi_object *)buffer.pointer;
6110 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
6111 printk(TPACPI_ERR "Unknown _BCL data, "
6112 "please report this to %s\n", TPACPI_MAIL);
6113 rc = 0;
6114 } else {
6115 rc = obj->package.count;
6116 }
6117 } else {
6118 return 0;
6119 }
6120
6121 kfree(buffer.pointer);
6122 return rc;
6123}
6124
6125static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle,
6126 u32 lvl, void *context, void **rv)
6127{
6128 char name[ACPI_PATH_SEGMENT_LENGTH];
6129 struct acpi_buffer buffer = { sizeof(name), &name };
6130
6131 if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
6132 !strncmp("_BCL", name, sizeof(name) - 1)) {
6133 BUG_ON(!rv || !*rv);
6134 **(int **)rv = tpacpi_query_bcl_levels(handle);
6135 return AE_CTRL_TERMINATE;
6136 } else {
6137 return AE_OK;
6138 }
6139}
6140
6141/*
6142 * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map
6143 */
6144static unsigned int __init tpacpi_check_std_acpi_brightness_support(void)
6145{
6146 int status;
6147 int bcl_levels = 0;
6148 void *bcl_ptr = &bcl_levels;
6149
6150 if (!vid_handle)
6151 TPACPI_ACPIHANDLE_INIT(vid);
6152
6153 if (!vid_handle)
6154 return 0;
6155
6156 /*
6157 * Search for a _BCL method, and execute it. This is safe on all
6158 * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista
6159 * BIOS in ACPI backlight control mode. We do NOT have to care
6160 * about calling the _BCL method in an enabled video device, any
6161 * will do for our purposes.
6162 */
6163
6164 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
6165 tpacpi_acpi_walk_find_bcl, NULL, NULL,
6166 &bcl_ptr);
6167
6168 if (ACPI_SUCCESS(status) && bcl_levels > 2) {
6169 tp_features.bright_acpimode = 1;
6170 return bcl_levels - 2;
6171 }
6172
6173 return 0;
6174}
6175
6177/* 6176/*
6178 * These are only useful for models that have only one possibility 6177 * These are only useful for models that have only one possibility
6179 * of GPU. If the BIOS model handles both ATI and Intel, don't use 6178 * of GPU. If the BIOS model handles both ATI and Intel, don't use
@@ -6204,6 +6203,47 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
6204 TPACPI_Q_IBM('7', '5', TPACPI_BRGHT_Q_NOEC), /* X41 Tablet */ 6203 TPACPI_Q_IBM('7', '5', TPACPI_BRGHT_Q_NOEC), /* X41 Tablet */
6205}; 6204};
6206 6205
6206/*
6207 * Returns < 0 for error, otherwise sets tp_features.bright_*
6208 * and bright_maxlvl.
6209 */
6210static void __init tpacpi_detect_brightness_capabilities(void)
6211{
6212 unsigned int b;
6213
6214 vdbg_printk(TPACPI_DBG_INIT,
6215 "detecting firmware brightness interface capabilities\n");
6216
6217 /* we could run a quirks check here (same table used by
6218 * brightness_init) if needed */
6219
6220 /*
6221 * We always attempt to detect acpi support, so as to switch
6222 * Lenovo Vista BIOS to ACPI brightness mode even if we are not
6223 * going to publish a backlight interface
6224 */
6225 b = tpacpi_check_std_acpi_brightness_support();
6226 switch (b) {
6227 case 16:
6228 bright_maxlvl = 15;
6229 printk(TPACPI_INFO
6230 "detected a 16-level brightness capable ThinkPad\n");
6231 break;
6232 case 8:
6233 case 0:
6234 bright_maxlvl = 7;
6235 printk(TPACPI_INFO
6236 "detected a 8-level brightness capable ThinkPad\n");
6237 break;
6238 default:
6239 printk(TPACPI_ERR
6240 "Unsupported brightness interface, "
6241 "please contact %s\n", TPACPI_MAIL);
6242 tp_features.bright_unkfw = 1;
6243 bright_maxlvl = b - 1;
6244 }
6245}
6246
6207static int __init brightness_init(struct ibm_init_struct *iibm) 6247static int __init brightness_init(struct ibm_init_struct *iibm)
6208{ 6248{
6209 struct backlight_properties props; 6249 struct backlight_properties props;
@@ -6217,14 +6257,13 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
6217 quirks = tpacpi_check_quirks(brightness_quirk_table, 6257 quirks = tpacpi_check_quirks(brightness_quirk_table,
6218 ARRAY_SIZE(brightness_quirk_table)); 6258 ARRAY_SIZE(brightness_quirk_table));
6219 6259
6220 /* 6260 /* tpacpi_detect_brightness_capabilities() must have run already */
6221 * We always attempt to detect acpi support, so as to switch 6261
6222 * Lenovo Vista BIOS to ACPI brightness mode even if we are not 6262 /* if it is unknown, we don't handle it: it wouldn't be safe */
6223 * going to publish a backlight interface 6263 if (tp_features.bright_unkfw)
6224 */ 6264 return 1;
6225 b = tpacpi_check_std_acpi_brightness_support();
6226 if (b > 0) {
6227 6265
6266 if (tp_features.bright_acpimode) {
6228 if (acpi_video_backlight_support()) { 6267 if (acpi_video_backlight_support()) {
6229 if (brightness_enable > 1) { 6268 if (brightness_enable > 1) {
6230 printk(TPACPI_NOTICE 6269 printk(TPACPI_NOTICE
@@ -6253,15 +6292,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
6253 return 1; 6292 return 1;
6254 } 6293 }
6255 6294
6256 if (b > 16) {
6257 printk(TPACPI_ERR
6258 "Unsupported brightness interface, "
6259 "please contact %s\n", TPACPI_MAIL);
6260 return 1;
6261 }
6262 if (b == 16)
6263 tp_features.bright_16levels = 1;
6264
6265 /* 6295 /*
6266 * Check for module parameter bogosity, note that we 6296 * Check for module parameter bogosity, note that we
6267 * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be 6297 * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be
@@ -6292,12 +6322,9 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
6292 if (tpacpi_brightness_get_raw(&b) < 0) 6322 if (tpacpi_brightness_get_raw(&b) < 0)
6293 return 1; 6323 return 1;
6294 6324
6295 if (tp_features.bright_16levels)
6296 printk(TPACPI_INFO
6297 "detected a 16-level brightness capable ThinkPad\n");
6298
6299 memset(&props, 0, sizeof(struct backlight_properties)); 6325 memset(&props, 0, sizeof(struct backlight_properties));
6300 props.max_brightness = (tp_features.bright_16levels) ? 15 : 7; 6326 props.max_brightness = bright_maxlvl;
6327 props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
6301 ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME, 6328 ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME,
6302 NULL, NULL, 6329 NULL, NULL,
6303 &ibm_backlight_data, 6330 &ibm_backlight_data,
@@ -6320,7 +6347,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
6320 "or not on your ThinkPad\n", TPACPI_MAIL); 6347 "or not on your ThinkPad\n", TPACPI_MAIL);
6321 } 6348 }
6322 6349
6323 ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
6324 backlight_update_status(ibm_backlight_device); 6350 backlight_update_status(ibm_backlight_device);
6325 6351
6326 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, 6352 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
@@ -6363,9 +6389,8 @@ static int brightness_read(struct seq_file *m)
6363 } else { 6389 } else {
6364 seq_printf(m, "level:\t\t%d\n", level); 6390 seq_printf(m, "level:\t\t%d\n", level);
6365 seq_printf(m, "commands:\tup, down\n"); 6391 seq_printf(m, "commands:\tup, down\n");
6366 seq_printf(m, "commands:\tlevel <level>" 6392 seq_printf(m, "commands:\tlevel <level> (<level> is 0-%d)\n",
6367 " (<level> is 0-%d)\n", 6393 bright_maxlvl);
6368 (tp_features.bright_16levels) ? 15 : 7);
6369 } 6394 }
6370 6395
6371 return 0; 6396 return 0;
@@ -6376,7 +6401,6 @@ static int brightness_write(char *buf)
6376 int level; 6401 int level;
6377 int rc; 6402 int rc;
6378 char *cmd; 6403 char *cmd;
6379 int max_level = (tp_features.bright_16levels) ? 15 : 7;
6380 6404
6381 level = brightness_get(NULL); 6405 level = brightness_get(NULL);
6382 if (level < 0) 6406 if (level < 0)
@@ -6384,13 +6408,13 @@ static int brightness_write(char *buf)
6384 6408
6385 while ((cmd = next_cmd(&buf))) { 6409 while ((cmd = next_cmd(&buf))) {
6386 if (strlencmp(cmd, "up") == 0) { 6410 if (strlencmp(cmd, "up") == 0) {
6387 if (level < max_level) 6411 if (level < bright_maxlvl)
6388 level++; 6412 level++;
6389 } else if (strlencmp(cmd, "down") == 0) { 6413 } else if (strlencmp(cmd, "down") == 0) {
6390 if (level > 0) 6414 if (level > 0)
6391 level--; 6415 level--;
6392 } else if (sscanf(cmd, "level %d", &level) == 1 && 6416 } else if (sscanf(cmd, "level %d", &level) == 1 &&
6393 level >= 0 && level <= max_level) { 6417 level >= 0 && level <= bright_maxlvl) {
6394 /* new level set */ 6418 /* new level set */
6395 } else 6419 } else
6396 return -EINVAL; 6420 return -EINVAL;
@@ -9130,6 +9154,11 @@ static int __init thinkpad_acpi_module_init(void)
9130 tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; 9154 tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
9131 tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev; 9155 tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev;
9132 } 9156 }
9157
9158 /* Init subdriver dependencies */
9159 tpacpi_detect_brightness_capabilities();
9160
9161 /* Init subdrivers */
9133 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { 9162 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
9134 ret = ibm_init(&ibms_init[i]); 9163 ret = ibm_init(&ibms_init[i]);
9135 if (ret >= 0 && *ibms_init[i].param) 9164 if (ret >= 0 && *ibms_init[i].param)