aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/thinkpad_acpi.c238
1 files changed, 133 insertions, 105 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 6cb781262f94..2c85a2e10a25 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -225,6 +225,7 @@ static struct {
225 u32 light:1; 225 u32 light:1;
226 u32 light_status:1; 226 u32 light_status:1;
227 u32 bright_16levels:1; 227 u32 bright_16levels:1;
228 u32 bright_acpimode:1;
228 u32 wan:1; 229 u32 wan:1;
229 u32 fan_ctrl_status_undef:1; 230 u32 fan_ctrl_status_undef:1;
230 u32 input_device_registered:1; 231 u32 input_device_registered:1;
@@ -807,6 +808,80 @@ static int parse_strtoul(const char *buf,
807 return 0; 808 return 0;
808} 809}
809 810
811static int __init tpacpi_query_bcl_levels(acpi_handle handle)
812{
813 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
814 union acpi_object *obj;
815 int rc;
816
817 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
818 obj = (union acpi_object *)buffer.pointer;
819 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
820 printk(TPACPI_ERR "Unknown _BCL data, "
821 "please report this to %s\n", TPACPI_MAIL);
822 rc = 0;
823 } else {
824 rc = obj->package.count;
825 }
826 } else {
827 return 0;
828 }
829
830 kfree(buffer.pointer);
831 return rc;
832}
833
834static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle,
835 u32 lvl, void *context, void **rv)
836{
837 char name[ACPI_PATH_SEGMENT_LENGTH];
838 struct acpi_buffer buffer = { sizeof(name), &name };
839
840 if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
841 !strncmp("_BCL", name, sizeof(name) - 1)) {
842 BUG_ON(!rv || !*rv);
843 **(int **)rv = tpacpi_query_bcl_levels(handle);
844 return AE_CTRL_TERMINATE;
845 } else {
846 return AE_OK;
847 }
848}
849
850/*
851 * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map
852 */
853static int __init tpacpi_check_std_acpi_brightness_support(void)
854{
855 int status;
856 int bcl_levels = 0;
857 void *bcl_ptr = &bcl_levels;
858
859 if (!vid_handle) {
860 TPACPI_ACPIHANDLE_INIT(vid);
861 }
862 if (!vid_handle)
863 return 0;
864
865 /*
866 * Search for a _BCL method, and execute it. This is safe on all
867 * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista
868 * BIOS in ACPI backlight control mode. We do NOT have to care
869 * about calling the _BCL method in an enabled video device, any
870 * will do for our purposes.
871 */
872
873 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
874 tpacpi_acpi_walk_find_bcl, NULL,
875 &bcl_ptr);
876
877 if (ACPI_SUCCESS(status) && bcl_levels > 2) {
878 tp_features.bright_acpimode = 1;
879 return (bcl_levels - 2);
880 }
881
882 return 0;
883}
884
810/************************************************************************* 885/*************************************************************************
811 * thinkpad-acpi driver attributes 886 * thinkpad-acpi driver attributes
812 */ 887 */
@@ -1887,6 +1962,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1887 KEY_UNKNOWN, /* 0x0D: FN+INSERT */ 1962 KEY_UNKNOWN, /* 0x0D: FN+INSERT */
1888 KEY_UNKNOWN, /* 0x0E: FN+DELETE */ 1963 KEY_UNKNOWN, /* 0x0E: FN+DELETE */
1889 1964
1965 /* These either have to go through ACPI video, or
1966 * act like in the IBM ThinkPads, so don't ever
1967 * enable them by default */
1890 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ 1968 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
1891 KEY_RESERVED, /* 0x10: FN+END (brightness down) */ 1969 KEY_RESERVED, /* 0x10: FN+END (brightness down) */
1892 1970
@@ -2091,6 +2169,32 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2091 set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); 2169 set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
2092 } 2170 }
2093 2171
2172 /* Do not issue duplicate brightness change events to
2173 * userspace */
2174 if (!tp_features.bright_acpimode)
2175 /* update bright_acpimode... */
2176 tpacpi_check_std_acpi_brightness_support();
2177
2178 if (tp_features.bright_acpimode) {
2179 printk(TPACPI_INFO
2180 "This ThinkPad has standard ACPI backlight "
2181 "brightness control, supported by the ACPI "
2182 "video driver\n");
2183 printk(TPACPI_NOTICE
2184 "Disabling thinkpad-acpi brightness events "
2185 "by default...\n");
2186
2187 /* The hotkey_reserved_mask change below is not
2188 * necessary while the keys are at KEY_RESERVED in the
2189 * default map, but better safe than sorry, leave it
2190 * here as a marker of what we have to do, especially
2191 * when we finally become able to set this at runtime
2192 * on response to X.org requests */
2193 hotkey_reserved_mask |=
2194 (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
2195 | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
2196 }
2197
2094 dbg_printk(TPACPI_DBG_INIT, 2198 dbg_printk(TPACPI_DBG_INIT,
2095 "enabling hot key handling\n"); 2199 "enabling hot key handling\n");
2096 res = hotkey_status_set(1); 2200 res = hotkey_status_set(1);
@@ -4273,100 +4377,6 @@ static struct backlight_ops ibm_backlight_data = {
4273 4377
4274/* --------------------------------------------------------------------- */ 4378/* --------------------------------------------------------------------- */
4275 4379
4276static int __init tpacpi_query_bcll_levels(acpi_handle handle)
4277{
4278 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
4279 union acpi_object *obj;
4280 int rc;
4281
4282 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
4283 obj = (union acpi_object *)buffer.pointer;
4284 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
4285 printk(TPACPI_ERR "Unknown BCLL data, "
4286 "please report this to %s\n", TPACPI_MAIL);
4287 rc = 0;
4288 } else {
4289 rc = obj->package.count;
4290 }
4291 } else {
4292 return 0;
4293 }
4294
4295 kfree(buffer.pointer);
4296 return rc;
4297}
4298
4299static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
4300 void *context, void **rv)
4301{
4302 char name[ACPI_PATH_SEGMENT_LENGTH];
4303 struct acpi_buffer buffer = { sizeof(name), &name };
4304
4305 if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
4306 !strncmp("BCLL", name, sizeof(name) - 1)) {
4307 if (tpacpi_query_bcll_levels(handle) == 16) {
4308 *rv = handle;
4309 return AE_CTRL_TERMINATE;
4310 } else {
4311 return AE_OK;
4312 }
4313 } else {
4314 return AE_OK;
4315 }
4316}
4317
4318static int __init brightness_check_levels(void)
4319{
4320 int status;
4321 void *found_node = NULL;
4322
4323 if (!vid_handle) {
4324 TPACPI_ACPIHANDLE_INIT(vid);
4325 }
4326 if (!vid_handle)
4327 return 0;
4328
4329 /* Search for a BCLL package with 16 levels */
4330 status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
4331 brightness_find_bcll, NULL,
4332 &found_node);
4333
4334 return (ACPI_SUCCESS(status) && found_node != NULL);
4335}
4336
4337static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
4338 void *context, void **rv)
4339{
4340 char name[ACPI_PATH_SEGMENT_LENGTH];
4341 struct acpi_buffer buffer = { sizeof(name), &name };
4342
4343 if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
4344 !strncmp("_BCL", name, sizeof(name) - 1)) {
4345 *rv = handle;
4346 return AE_CTRL_TERMINATE;
4347 } else {
4348 return AE_OK;
4349 }
4350}
4351
4352static int __init brightness_check_std_acpi_support(void)
4353{
4354 int status;
4355 void *found_node = NULL;
4356
4357 if (!vid_handle) {
4358 TPACPI_ACPIHANDLE_INIT(vid);
4359 }
4360 if (!vid_handle)
4361 return 0;
4362
4363 /* Search for a _BCL method, but don't execute it */
4364 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
4365 brightness_find_bcl, NULL, &found_node);
4366
4367 return (ACPI_SUCCESS(status) && found_node != NULL);
4368}
4369
4370static int __init brightness_init(struct ibm_init_struct *iibm) 4380static int __init brightness_init(struct ibm_init_struct *iibm)
4371{ 4381{
4372 int b; 4382 int b;
@@ -4375,13 +4385,19 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
4375 4385
4376 mutex_init(&brightness_mutex); 4386 mutex_init(&brightness_mutex);
4377 4387
4378 if (!brightness_enable) { 4388 /*
4379 dbg_printk(TPACPI_DBG_INIT, 4389 * We always attempt to detect acpi support, so as to switch
4380 "brightness support disabled by " 4390 * Lenovo Vista BIOS to ACPI brightness mode even if we are not
4381 "module parameter\n"); 4391 * going to publish a backlight interface
4382 return 1; 4392 */
4383 } else if (brightness_enable > 1) { 4393 b = tpacpi_check_std_acpi_brightness_support();
4384 if (brightness_check_std_acpi_support()) { 4394 if (b > 0) {
4395 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
4396 printk(TPACPI_NOTICE
4397 "Lenovo BIOS switched to ACPI backlight "
4398 "control mode\n");
4399 }
4400 if (brightness_enable > 1) {
4385 printk(TPACPI_NOTICE 4401 printk(TPACPI_NOTICE
4386 "standard ACPI backlight interface " 4402 "standard ACPI backlight interface "
4387 "available, not loading native one...\n"); 4403 "available, not loading native one...\n");
@@ -4389,6 +4405,22 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
4389 } 4405 }
4390 } 4406 }
4391 4407
4408 if (!brightness_enable) {
4409 dbg_printk(TPACPI_DBG_INIT,
4410 "brightness support disabled by "
4411 "module parameter\n");
4412 return 1;
4413 }
4414
4415 if (b > 16) {
4416 printk(TPACPI_ERR
4417 "Unsupported brightness interface, "
4418 "please contact %s\n", TPACPI_MAIL);
4419 return 1;
4420 }
4421 if (b == 16)
4422 tp_features.bright_16levels = 1;
4423
4392 if (!brightness_mode) { 4424 if (!brightness_mode) {
4393 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) 4425 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
4394 brightness_mode = 2; 4426 brightness_mode = 2;
@@ -4402,10 +4434,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
4402 if (brightness_mode > 3) 4434 if (brightness_mode > 3)
4403 return -EINVAL; 4435 return -EINVAL;
4404 4436
4405 tp_features.bright_16levels =
4406 thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
4407 brightness_check_levels();
4408
4409 b = brightness_get(NULL); 4437 b = brightness_get(NULL);
4410 if (b < 0) 4438 if (b < 0)
4411 return 1; 4439 return 1;