diff options
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 251 |
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 */ | ||
372 | static unsigned int bright_maxlvl; /* 0 = unknown */ | ||
373 | |||
371 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 374 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
372 | static int dbg_wlswemul; | 375 | static int dbg_wlswemul; |
373 | static int tpacpi_wlsw_emulstate; | 376 | static 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 | ||
1054 | static 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 | |||
1077 | static 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 | */ | ||
1096 | static 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 | |||
1128 | static void printk_deprecated_attribute(const char * const what, | 1057 | static 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 | ||
6102 | static 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 | |||
6125 | static 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 | */ | ||
6144 | static 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 | */ | ||
6210 | static 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 | |||
6207 | static int __init brightness_init(struct ibm_init_struct *iibm) | 6247 | static 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) |