diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 600 |
1 files changed, 376 insertions, 224 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 63290b33c879..4bdb13796e24 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -122,8 +122,14 @@ enum { | |||
122 | TP_NVRAM_POS_LEVEL_VOLUME = 0, | 122 | TP_NVRAM_POS_LEVEL_VOLUME = 0, |
123 | }; | 123 | }; |
124 | 124 | ||
125 | /* Misc NVRAM-related */ | ||
126 | enum { | ||
127 | TP_NVRAM_LEVEL_VOLUME_MAX = 14, | ||
128 | }; | ||
129 | |||
125 | /* ACPI HIDs */ | 130 | /* ACPI HIDs */ |
126 | #define TPACPI_ACPI_HKEY_HID "IBM0068" | 131 | #define TPACPI_ACPI_HKEY_HID "IBM0068" |
132 | #define TPACPI_ACPI_EC_HID "PNP0C09" | ||
127 | 133 | ||
128 | /* Input IDs */ | 134 | /* Input IDs */ |
129 | #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ | 135 | #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ |
@@ -299,8 +305,8 @@ static struct { | |||
299 | u32 hotkey_tablet:1; | 305 | u32 hotkey_tablet:1; |
300 | u32 light:1; | 306 | u32 light:1; |
301 | u32 light_status:1; | 307 | u32 light_status:1; |
302 | u32 bright_16levels:1; | ||
303 | u32 bright_acpimode:1; | 308 | u32 bright_acpimode:1; |
309 | u32 bright_unkfw:1; | ||
304 | u32 wan:1; | 310 | u32 wan:1; |
305 | u32 uwb:1; | 311 | u32 uwb:1; |
306 | u32 fan_ctrl_status_undef:1; | 312 | u32 fan_ctrl_status_undef:1; |
@@ -363,6 +369,9 @@ struct tpacpi_led_classdev { | |||
363 | unsigned int led; | 369 | unsigned int led; |
364 | }; | 370 | }; |
365 | 371 | ||
372 | /* brightness level capabilities */ | ||
373 | static unsigned int bright_maxlvl; /* 0 = unknown */ | ||
374 | |||
366 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 375 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
367 | static int dbg_wlswemul; | 376 | static int dbg_wlswemul; |
368 | static int tpacpi_wlsw_emulstate; | 377 | static int tpacpi_wlsw_emulstate; |
@@ -480,6 +489,15 @@ static unsigned long __init tpacpi_check_quirks( | |||
480 | return 0; | 489 | return 0; |
481 | } | 490 | } |
482 | 491 | ||
492 | static inline bool __pure __init tpacpi_is_lenovo(void) | ||
493 | { | ||
494 | return thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO; | ||
495 | } | ||
496 | |||
497 | static inline bool __pure __init tpacpi_is_ibm(void) | ||
498 | { | ||
499 | return thinkpad_id.vendor == PCI_VENDOR_ID_IBM; | ||
500 | } | ||
483 | 501 | ||
484 | /**************************************************************************** | 502 | /**************************************************************************** |
485 | **************************************************************************** | 503 | **************************************************************************** |
@@ -494,21 +512,13 @@ static unsigned long __init tpacpi_check_quirks( | |||
494 | */ | 512 | */ |
495 | 513 | ||
496 | static acpi_handle root_handle; | 514 | static acpi_handle root_handle; |
515 | static acpi_handle ec_handle; | ||
497 | 516 | ||
498 | #define TPACPI_HANDLE(object, parent, paths...) \ | 517 | #define TPACPI_HANDLE(object, parent, paths...) \ |
499 | static acpi_handle object##_handle; \ | 518 | static acpi_handle object##_handle; \ |
500 | static acpi_handle *object##_parent = &parent##_handle; \ | 519 | static const acpi_handle *object##_parent __initdata = \ |
501 | static char *object##_path; \ | 520 | &parent##_handle; \ |
502 | static char *object##_paths[] = { paths } | 521 | static char *object##_paths[] __initdata = { paths } |
503 | |||
504 | TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ | ||
505 | "\\_SB.PCI.ISA.EC", /* 570 */ | ||
506 | "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ | ||
507 | "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ | ||
508 | "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */ | ||
509 | "\\_SB.PCI0.ICH3.EC0", /* R31 */ | ||
510 | "\\_SB.PCI0.LPC.EC", /* all others */ | ||
511 | ); | ||
512 | 522 | ||
513 | TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */ | 523 | TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */ |
514 | TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */ | 524 | TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */ |
@@ -528,6 +538,7 @@ TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ | |||
528 | "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ | 538 | "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ |
529 | "\\_SB.PCI0.VID0", /* 770e */ | 539 | "\\_SB.PCI0.VID0", /* 770e */ |
530 | "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ | 540 | "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ |
541 | "\\_SB.PCI0.AGP.VGA", /* X100e and a few others */ | ||
531 | "\\_SB.PCI0.AGP.VID", /* all others */ | 542 | "\\_SB.PCI0.AGP.VID", /* all others */ |
532 | ); /* R30, R31 */ | 543 | ); /* R30, R31 */ |
533 | 544 | ||
@@ -594,9 +605,10 @@ static int acpi_evalf(acpi_handle handle, | |||
594 | 605 | ||
595 | switch (res_type) { | 606 | switch (res_type) { |
596 | case 'd': /* int */ | 607 | case 'd': /* int */ |
597 | if (res) | 608 | success = (status == AE_OK && |
609 | out_obj.type == ACPI_TYPE_INTEGER); | ||
610 | if (success && res) | ||
598 | *(int *)res = out_obj.integer.value; | 611 | *(int *)res = out_obj.integer.value; |
599 | success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER; | ||
600 | break; | 612 | break; |
601 | case 'v': /* void */ | 613 | case 'v': /* void */ |
602 | success = status == AE_OK; | 614 | success = status == AE_OK; |
@@ -609,8 +621,8 @@ static int acpi_evalf(acpi_handle handle, | |||
609 | } | 621 | } |
610 | 622 | ||
611 | if (!success && !quiet) | 623 | if (!success && !quiet) |
612 | printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", | 624 | printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %s\n", |
613 | method, fmt0, status); | 625 | method, fmt0, acpi_format_exception(status)); |
614 | 626 | ||
615 | return success; | 627 | return success; |
616 | } | 628 | } |
@@ -661,11 +673,11 @@ static int issue_thinkpad_cmos_command(int cmos_cmd) | |||
661 | 673 | ||
662 | #define TPACPI_ACPIHANDLE_INIT(object) \ | 674 | #define TPACPI_ACPIHANDLE_INIT(object) \ |
663 | drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ | 675 | drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ |
664 | object##_paths, ARRAY_SIZE(object##_paths), &object##_path) | 676 | object##_paths, ARRAY_SIZE(object##_paths)) |
665 | 677 | ||
666 | static void drv_acpi_handle_init(char *name, | 678 | static void __init drv_acpi_handle_init(const char *name, |
667 | acpi_handle *handle, acpi_handle parent, | 679 | acpi_handle *handle, const acpi_handle parent, |
668 | char **paths, int num_paths, char **path) | 680 | char **paths, const int num_paths) |
669 | { | 681 | { |
670 | int i; | 682 | int i; |
671 | acpi_status status; | 683 | acpi_status status; |
@@ -676,10 +688,9 @@ static void drv_acpi_handle_init(char *name, | |||
676 | for (i = 0; i < num_paths; i++) { | 688 | for (i = 0; i < num_paths; i++) { |
677 | status = acpi_get_handle(parent, paths[i], handle); | 689 | status = acpi_get_handle(parent, paths[i], handle); |
678 | if (ACPI_SUCCESS(status)) { | 690 | if (ACPI_SUCCESS(status)) { |
679 | *path = paths[i]; | ||
680 | dbg_printk(TPACPI_DBG_INIT, | 691 | dbg_printk(TPACPI_DBG_INIT, |
681 | "Found ACPI handle %s for %s\n", | 692 | "Found ACPI handle %s for %s\n", |
682 | *path, name); | 693 | paths[i], name); |
683 | return; | 694 | return; |
684 | } | 695 | } |
685 | } | 696 | } |
@@ -689,6 +700,43 @@ static void drv_acpi_handle_init(char *name, | |||
689 | *handle = NULL; | 700 | *handle = NULL; |
690 | } | 701 | } |
691 | 702 | ||
703 | static acpi_status __init tpacpi_acpi_handle_locate_callback(acpi_handle handle, | ||
704 | u32 level, void *context, void **return_value) | ||
705 | { | ||
706 | *(acpi_handle *)return_value = handle; | ||
707 | |||
708 | return AE_CTRL_TERMINATE; | ||
709 | } | ||
710 | |||
711 | static void __init tpacpi_acpi_handle_locate(const char *name, | ||
712 | const char *hid, | ||
713 | acpi_handle *handle) | ||
714 | { | ||
715 | acpi_status status; | ||
716 | acpi_handle device_found; | ||
717 | |||
718 | BUG_ON(!name || !hid || !handle); | ||
719 | vdbg_printk(TPACPI_DBG_INIT, | ||
720 | "trying to locate ACPI handle for %s, using HID %s\n", | ||
721 | name, hid); | ||
722 | |||
723 | memset(&device_found, 0, sizeof(device_found)); | ||
724 | status = acpi_get_devices(hid, tpacpi_acpi_handle_locate_callback, | ||
725 | (void *)name, &device_found); | ||
726 | |||
727 | *handle = NULL; | ||
728 | |||
729 | if (ACPI_SUCCESS(status)) { | ||
730 | *handle = device_found; | ||
731 | dbg_printk(TPACPI_DBG_INIT, | ||
732 | "Found ACPI handle for %s\n", name); | ||
733 | } else { | ||
734 | vdbg_printk(TPACPI_DBG_INIT, | ||
735 | "Could not locate an ACPI handle for %s: %s\n", | ||
736 | name, acpi_format_exception(status)); | ||
737 | } | ||
738 | } | ||
739 | |||
692 | static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) | 740 | static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) |
693 | { | 741 | { |
694 | struct ibm_struct *ibm = data; | 742 | struct ibm_struct *ibm = data; |
@@ -736,8 +784,8 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm) | |||
736 | "handling %s events\n", ibm->name); | 784 | "handling %s events\n", ibm->name); |
737 | } else { | 785 | } else { |
738 | printk(TPACPI_ERR | 786 | printk(TPACPI_ERR |
739 | "acpi_install_notify_handler(%s) failed: %d\n", | 787 | "acpi_install_notify_handler(%s) failed: %s\n", |
740 | ibm->name, status); | 788 | ibm->name, acpi_format_exception(status)); |
741 | } | 789 | } |
742 | return -ENODEV; | 790 | return -ENODEV; |
743 | } | 791 | } |
@@ -1035,80 +1083,6 @@ static void tpacpi_disable_brightness_delay(void) | |||
1035 | "ACPI backlight control delay disabled\n"); | 1083 | "ACPI backlight control delay disabled\n"); |
1036 | } | 1084 | } |
1037 | 1085 | ||
1038 | static int __init tpacpi_query_bcl_levels(acpi_handle handle) | ||
1039 | { | ||
1040 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1041 | union acpi_object *obj; | ||
1042 | int rc; | ||
1043 | |||
1044 | if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { | ||
1045 | obj = (union acpi_object *)buffer.pointer; | ||
1046 | if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { | ||
1047 | printk(TPACPI_ERR "Unknown _BCL data, " | ||
1048 | "please report this to %s\n", TPACPI_MAIL); | ||
1049 | rc = 0; | ||
1050 | } else { | ||
1051 | rc = obj->package.count; | ||
1052 | } | ||
1053 | } else { | ||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | kfree(buffer.pointer); | ||
1058 | return rc; | ||
1059 | } | ||
1060 | |||
1061 | static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, | ||
1062 | u32 lvl, void *context, void **rv) | ||
1063 | { | ||
1064 | char name[ACPI_PATH_SEGMENT_LENGTH]; | ||
1065 | struct acpi_buffer buffer = { sizeof(name), &name }; | ||
1066 | |||
1067 | if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && | ||
1068 | !strncmp("_BCL", name, sizeof(name) - 1)) { | ||
1069 | BUG_ON(!rv || !*rv); | ||
1070 | **(int **)rv = tpacpi_query_bcl_levels(handle); | ||
1071 | return AE_CTRL_TERMINATE; | ||
1072 | } else { | ||
1073 | return AE_OK; | ||
1074 | } | ||
1075 | } | ||
1076 | |||
1077 | /* | ||
1078 | * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map | ||
1079 | */ | ||
1080 | static int __init tpacpi_check_std_acpi_brightness_support(void) | ||
1081 | { | ||
1082 | int status; | ||
1083 | int bcl_levels = 0; | ||
1084 | void *bcl_ptr = &bcl_levels; | ||
1085 | |||
1086 | if (!vid_handle) { | ||
1087 | TPACPI_ACPIHANDLE_INIT(vid); | ||
1088 | } | ||
1089 | if (!vid_handle) | ||
1090 | return 0; | ||
1091 | |||
1092 | /* | ||
1093 | * Search for a _BCL method, and execute it. This is safe on all | ||
1094 | * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista | ||
1095 | * BIOS in ACPI backlight control mode. We do NOT have to care | ||
1096 | * about calling the _BCL method in an enabled video device, any | ||
1097 | * will do for our purposes. | ||
1098 | */ | ||
1099 | |||
1100 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, | ||
1101 | tpacpi_acpi_walk_find_bcl, NULL, NULL, | ||
1102 | &bcl_ptr); | ||
1103 | |||
1104 | if (ACPI_SUCCESS(status) && bcl_levels > 2) { | ||
1105 | tp_features.bright_acpimode = 1; | ||
1106 | return (bcl_levels - 2); | ||
1107 | } | ||
1108 | |||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1112 | static void printk_deprecated_attribute(const char * const what, | 1086 | static void printk_deprecated_attribute(const char * const what, |
1113 | const char * const details) | 1087 | const char * const details) |
1114 | { | 1088 | { |
@@ -1872,34 +1846,9 @@ static bool __init tpacpi_is_fw_known(void) | |||
1872 | ****************************************************************************/ | 1846 | ****************************************************************************/ |
1873 | 1847 | ||
1874 | /************************************************************************* | 1848 | /************************************************************************* |
1875 | * thinkpad-acpi init subdriver | 1849 | * thinkpad-acpi metadata subdriver |
1876 | */ | 1850 | */ |
1877 | 1851 | ||
1878 | static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) | ||
1879 | { | ||
1880 | printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION); | ||
1881 | printk(TPACPI_INFO "%s\n", TPACPI_URL); | ||
1882 | |||
1883 | printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n", | ||
1884 | (thinkpad_id.bios_version_str) ? | ||
1885 | thinkpad_id.bios_version_str : "unknown", | ||
1886 | (thinkpad_id.ec_version_str) ? | ||
1887 | thinkpad_id.ec_version_str : "unknown"); | ||
1888 | |||
1889 | if (thinkpad_id.vendor && thinkpad_id.model_str) | ||
1890 | printk(TPACPI_INFO "%s %s, model %s\n", | ||
1891 | (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? | ||
1892 | "IBM" : ((thinkpad_id.vendor == | ||
1893 | PCI_VENDOR_ID_LENOVO) ? | ||
1894 | "Lenovo" : "Unknown vendor"), | ||
1895 | thinkpad_id.model_str, | ||
1896 | (thinkpad_id.nummodel_str) ? | ||
1897 | thinkpad_id.nummodel_str : "unknown"); | ||
1898 | |||
1899 | tpacpi_check_outdated_fw(); | ||
1900 | return 0; | ||
1901 | } | ||
1902 | |||
1903 | static int thinkpad_acpi_driver_read(struct seq_file *m) | 1852 | static int thinkpad_acpi_driver_read(struct seq_file *m) |
1904 | { | 1853 | { |
1905 | seq_printf(m, "driver:\t\t%s\n", TPACPI_DESC); | 1854 | seq_printf(m, "driver:\t\t%s\n", TPACPI_DESC); |
@@ -2405,6 +2354,36 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | |||
2405 | tpacpi_hotkey_send_key(__scancode); \ | 2354 | tpacpi_hotkey_send_key(__scancode); \ |
2406 | } while (0) | 2355 | } while (0) |
2407 | 2356 | ||
2357 | void issue_volchange(const unsigned int oldvol, | ||
2358 | const unsigned int newvol) | ||
2359 | { | ||
2360 | unsigned int i = oldvol; | ||
2361 | |||
2362 | while (i > newvol) { | ||
2363 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); | ||
2364 | i--; | ||
2365 | } | ||
2366 | while (i < newvol) { | ||
2367 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | ||
2368 | i++; | ||
2369 | } | ||
2370 | } | ||
2371 | |||
2372 | void issue_brightnesschange(const unsigned int oldbrt, | ||
2373 | const unsigned int newbrt) | ||
2374 | { | ||
2375 | unsigned int i = oldbrt; | ||
2376 | |||
2377 | while (i > newbrt) { | ||
2378 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); | ||
2379 | i--; | ||
2380 | } | ||
2381 | while (i < newbrt) { | ||
2382 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); | ||
2383 | i++; | ||
2384 | } | ||
2385 | } | ||
2386 | |||
2408 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); | 2387 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); |
2409 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); | 2388 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); |
2410 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); | 2389 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); |
@@ -2414,41 +2393,61 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | |||
2414 | 2393 | ||
2415 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle); | 2394 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle); |
2416 | 2395 | ||
2417 | /* handle volume */ | 2396 | /* |
2418 | if (oldn->volume_toggle != newn->volume_toggle) { | 2397 | * Handle volume |
2419 | if (oldn->mute != newn->mute) { | 2398 | * |
2399 | * This code is supposed to duplicate the IBM firmware behaviour: | ||
2400 | * - Pressing MUTE issues mute hotkey message, even when already mute | ||
2401 | * - Pressing Volume up/down issues volume up/down hotkey messages, | ||
2402 | * even when already at maximum or minumum volume | ||
2403 | * - The act of unmuting issues volume up/down notification, | ||
2404 | * depending which key was used to unmute | ||
2405 | * | ||
2406 | * We are constrained to what the NVRAM can tell us, which is not much | ||
2407 | * and certainly not enough if more than one volume hotkey was pressed | ||
2408 | * since the last poll cycle. | ||
2409 | * | ||
2410 | * Just to make our life interesting, some newer Lenovo ThinkPads have | ||
2411 | * bugs in the BIOS and may fail to update volume_toggle properly. | ||
2412 | */ | ||
2413 | if (newn->mute) { | ||
2414 | /* muted */ | ||
2415 | if (!oldn->mute || | ||
2416 | oldn->volume_toggle != newn->volume_toggle || | ||
2417 | oldn->volume_level != newn->volume_level) { | ||
2418 | /* recently muted, or repeated mute keypress, or | ||
2419 | * multiple presses ending in mute */ | ||
2420 | issue_volchange(oldn->volume_level, newn->volume_level); | ||
2420 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); | 2421 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); |
2421 | } | 2422 | } |
2422 | if (oldn->volume_level > newn->volume_level) { | 2423 | } else { |
2423 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); | 2424 | /* unmute */ |
2424 | } else if (oldn->volume_level < newn->volume_level) { | 2425 | if (oldn->mute) { |
2426 | /* recently unmuted, issue 'unmute' keypress */ | ||
2425 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | 2427 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); |
2426 | } else if (oldn->mute == newn->mute) { | 2428 | } |
2427 | /* repeated key presses that didn't change state */ | 2429 | if (oldn->volume_level != newn->volume_level) { |
2428 | if (newn->mute) { | 2430 | issue_volchange(oldn->volume_level, newn->volume_level); |
2429 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); | 2431 | } else if (oldn->volume_toggle != newn->volume_toggle) { |
2430 | } else if (newn->volume_level != 0) { | 2432 | /* repeated vol up/down keypress at end of scale ? */ |
2431 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | 2433 | if (newn->volume_level == 0) |
2432 | } else { | ||
2433 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); | 2434 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); |
2434 | } | 2435 | else if (newn->volume_level >= TP_NVRAM_LEVEL_VOLUME_MAX) |
2436 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | ||
2435 | } | 2437 | } |
2436 | } | 2438 | } |
2437 | 2439 | ||
2438 | /* handle brightness */ | 2440 | /* handle brightness */ |
2439 | if (oldn->brightness_toggle != newn->brightness_toggle) { | 2441 | if (oldn->brightness_level != newn->brightness_level) { |
2440 | if (oldn->brightness_level < newn->brightness_level) { | 2442 | issue_brightnesschange(oldn->brightness_level, |
2441 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); | 2443 | newn->brightness_level); |
2442 | } else if (oldn->brightness_level > newn->brightness_level) { | 2444 | } else if (oldn->brightness_toggle != newn->brightness_toggle) { |
2445 | /* repeated key presses that didn't change state */ | ||
2446 | if (newn->brightness_level == 0) | ||
2443 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); | 2447 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); |
2444 | } else { | 2448 | else if (newn->brightness_level >= bright_maxlvl |
2445 | /* repeated key presses that didn't change state */ | 2449 | && !tp_features.bright_unkfw) |
2446 | if (newn->brightness_level != 0) { | 2450 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); |
2447 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); | ||
2448 | } else { | ||
2449 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); | ||
2450 | } | ||
2451 | } | ||
2452 | } | 2451 | } |
2453 | 2452 | ||
2454 | #undef TPACPI_COMPARE_KEY | 2453 | #undef TPACPI_COMPARE_KEY |
@@ -3353,7 +3352,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3353 | goto err_exit; | 3352 | goto err_exit; |
3354 | } | 3353 | } |
3355 | 3354 | ||
3356 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { | 3355 | if (tpacpi_is_lenovo()) { |
3357 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | 3356 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
3358 | "using Lenovo default hot key map\n"); | 3357 | "using Lenovo default hot key map\n"); |
3359 | memcpy(hotkey_keycode_map, &lenovo_keycode_map, | 3358 | memcpy(hotkey_keycode_map, &lenovo_keycode_map, |
@@ -3391,11 +3390,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
3391 | } | 3390 | } |
3392 | 3391 | ||
3393 | /* Do not issue duplicate brightness change events to | 3392 | /* Do not issue duplicate brightness change events to |
3394 | * userspace */ | 3393 | * userspace. tpacpi_detect_brightness_capabilities() must have |
3395 | if (!tp_features.bright_acpimode) | 3394 | * been called before this point */ |
3396 | /* update bright_acpimode... */ | ||
3397 | tpacpi_check_std_acpi_brightness_support(); | ||
3398 | |||
3399 | if (tp_features.bright_acpimode && acpi_video_backlight_support()) { | 3395 | if (tp_features.bright_acpimode && acpi_video_backlight_support()) { |
3400 | printk(TPACPI_INFO | 3396 | printk(TPACPI_INFO |
3401 | "This ThinkPad has standard ACPI backlight " | 3397 | "This ThinkPad has standard ACPI backlight " |
@@ -4422,7 +4418,8 @@ static int __init video_init(struct ibm_init_struct *iibm) | |||
4422 | vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); | 4418 | vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); |
4423 | 4419 | ||
4424 | TPACPI_ACPIHANDLE_INIT(vid); | 4420 | TPACPI_ACPIHANDLE_INIT(vid); |
4425 | TPACPI_ACPIHANDLE_INIT(vid2); | 4421 | if (tpacpi_is_ibm()) |
4422 | TPACPI_ACPIHANDLE_INIT(vid2); | ||
4426 | 4423 | ||
4427 | if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) | 4424 | if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) |
4428 | /* G41, assume IVGA doesn't change */ | 4425 | /* G41, assume IVGA doesn't change */ |
@@ -4431,10 +4428,12 @@ static int __init video_init(struct ibm_init_struct *iibm) | |||
4431 | if (!vid_handle) | 4428 | if (!vid_handle) |
4432 | /* video switching not supported on R30, R31 */ | 4429 | /* video switching not supported on R30, R31 */ |
4433 | video_supported = TPACPI_VIDEO_NONE; | 4430 | video_supported = TPACPI_VIDEO_NONE; |
4434 | else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) | 4431 | else if (tpacpi_is_ibm() && |
4432 | acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) | ||
4435 | /* 570 */ | 4433 | /* 570 */ |
4436 | video_supported = TPACPI_VIDEO_570; | 4434 | video_supported = TPACPI_VIDEO_570; |
4437 | else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) | 4435 | else if (tpacpi_is_ibm() && |
4436 | acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) | ||
4438 | /* 600e/x, 770e, 770x */ | 4437 | /* 600e/x, 770e, 770x */ |
4439 | video_supported = TPACPI_VIDEO_770; | 4438 | video_supported = TPACPI_VIDEO_770; |
4440 | else | 4439 | else |
@@ -4811,8 +4810,10 @@ static int __init light_init(struct ibm_init_struct *iibm) | |||
4811 | 4810 | ||
4812 | vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); | 4811 | vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); |
4813 | 4812 | ||
4814 | TPACPI_ACPIHANDLE_INIT(ledb); | 4813 | if (tpacpi_is_ibm()) { |
4815 | TPACPI_ACPIHANDLE_INIT(lght); | 4814 | TPACPI_ACPIHANDLE_INIT(ledb); |
4815 | TPACPI_ACPIHANDLE_INIT(lght); | ||
4816 | } | ||
4816 | TPACPI_ACPIHANDLE_INIT(cmos); | 4817 | TPACPI_ACPIHANDLE_INIT(cmos); |
4817 | INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker); | 4818 | INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker); |
4818 | 4819 | ||
@@ -5007,11 +5008,7 @@ enum { /* For TPACPI_LED_OLD */ | |||
5007 | 5008 | ||
5008 | static enum led_access_mode led_supported; | 5009 | static enum led_access_mode led_supported; |
5009 | 5010 | ||
5010 | TPACPI_HANDLE(led, ec, "SLED", /* 570 */ | 5011 | static acpi_handle led_handle; |
5011 | "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, */ | ||
5012 | /* T20-22, X20-21 */ | ||
5013 | "LED", /* all others */ | ||
5014 | ); /* R30, R31 */ | ||
5015 | 5012 | ||
5016 | #define TPACPI_LED_NUMLEDS 16 | 5013 | #define TPACPI_LED_NUMLEDS 16 |
5017 | static struct tpacpi_led_classdev *tpacpi_leds; | 5014 | static struct tpacpi_led_classdev *tpacpi_leds; |
@@ -5271,6 +5268,32 @@ static const struct tpacpi_quirk led_useful_qtable[] __initconst = { | |||
5271 | #undef TPACPI_LEDQ_IBM | 5268 | #undef TPACPI_LEDQ_IBM |
5272 | #undef TPACPI_LEDQ_LNV | 5269 | #undef TPACPI_LEDQ_LNV |
5273 | 5270 | ||
5271 | static enum led_access_mode __init led_init_detect_mode(void) | ||
5272 | { | ||
5273 | acpi_status status; | ||
5274 | |||
5275 | if (tpacpi_is_ibm()) { | ||
5276 | /* 570 */ | ||
5277 | status = acpi_get_handle(ec_handle, "SLED", &led_handle); | ||
5278 | if (ACPI_SUCCESS(status)) | ||
5279 | return TPACPI_LED_570; | ||
5280 | |||
5281 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ | ||
5282 | status = acpi_get_handle(ec_handle, "SYSL", &led_handle); | ||
5283 | if (ACPI_SUCCESS(status)) | ||
5284 | return TPACPI_LED_OLD; | ||
5285 | } | ||
5286 | |||
5287 | /* most others */ | ||
5288 | status = acpi_get_handle(ec_handle, "LED", &led_handle); | ||
5289 | if (ACPI_SUCCESS(status)) | ||
5290 | return TPACPI_LED_NEW; | ||
5291 | |||
5292 | /* R30, R31, and unknown firmwares */ | ||
5293 | led_handle = NULL; | ||
5294 | return TPACPI_LED_NONE; | ||
5295 | } | ||
5296 | |||
5274 | static int __init led_init(struct ibm_init_struct *iibm) | 5297 | static int __init led_init(struct ibm_init_struct *iibm) |
5275 | { | 5298 | { |
5276 | unsigned int i; | 5299 | unsigned int i; |
@@ -5279,20 +5302,7 @@ static int __init led_init(struct ibm_init_struct *iibm) | |||
5279 | 5302 | ||
5280 | vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); | 5303 | vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); |
5281 | 5304 | ||
5282 | TPACPI_ACPIHANDLE_INIT(led); | 5305 | led_supported = led_init_detect_mode(); |
5283 | |||
5284 | if (!led_handle) | ||
5285 | /* led not supported on R30, R31 */ | ||
5286 | led_supported = TPACPI_LED_NONE; | ||
5287 | else if (strlencmp(led_path, "SLED") == 0) | ||
5288 | /* 570 */ | ||
5289 | led_supported = TPACPI_LED_570; | ||
5290 | else if (strlencmp(led_path, "SYSL") == 0) | ||
5291 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ | ||
5292 | led_supported = TPACPI_LED_OLD; | ||
5293 | else | ||
5294 | /* all others */ | ||
5295 | led_supported = TPACPI_LED_NEW; | ||
5296 | 5306 | ||
5297 | vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", | 5307 | vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", |
5298 | str_supported(led_supported), led_supported); | 5308 | str_supported(led_supported), led_supported); |
@@ -5741,11 +5751,12 @@ static int __init thermal_init(struct ibm_init_struct *iibm) | |||
5741 | TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8; | 5751 | TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8; |
5742 | } | 5752 | } |
5743 | } else if (acpi_tmp7) { | 5753 | } else if (acpi_tmp7) { |
5744 | if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { | 5754 | if (tpacpi_is_ibm() && |
5755 | acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { | ||
5745 | /* 600e/x, 770e, 770x */ | 5756 | /* 600e/x, 770e, 770x */ |
5746 | thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT; | 5757 | thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT; |
5747 | } else { | 5758 | } else { |
5748 | /* Standard ACPI TMPx access, max 8 sensors */ | 5759 | /* IBM/LENOVO DSDT EC.TMPx access, max 8 sensors */ |
5749 | thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; | 5760 | thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; |
5750 | } | 5761 | } |
5751 | } else { | 5762 | } else { |
@@ -5954,7 +5965,7 @@ static unsigned int tpacpi_brightness_nvram_get(void) | |||
5954 | lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) | 5965 | lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) |
5955 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | 5966 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) |
5956 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; | 5967 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; |
5957 | lnvram &= (tp_features.bright_16levels) ? 0x0f : 0x07; | 5968 | lnvram &= bright_maxlvl; |
5958 | 5969 | ||
5959 | return lnvram; | 5970 | return lnvram; |
5960 | } | 5971 | } |
@@ -6063,8 +6074,7 @@ static int brightness_set(unsigned int value) | |||
6063 | { | 6074 | { |
6064 | int res; | 6075 | int res; |
6065 | 6076 | ||
6066 | if (value > ((tp_features.bright_16levels)? 15 : 7) || | 6077 | if (value > bright_maxlvl || value < 0) |
6067 | value < 0) | ||
6068 | return -EINVAL; | 6078 | return -EINVAL; |
6069 | 6079 | ||
6070 | vdbg_printk(TPACPI_DBG_BRGHT, | 6080 | vdbg_printk(TPACPI_DBG_BRGHT, |
@@ -6139,6 +6149,80 @@ static struct backlight_ops ibm_backlight_data = { | |||
6139 | 6149 | ||
6140 | /* --------------------------------------------------------------------- */ | 6150 | /* --------------------------------------------------------------------- */ |
6141 | 6151 | ||
6152 | static int __init tpacpi_query_bcl_levels(acpi_handle handle) | ||
6153 | { | ||
6154 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
6155 | union acpi_object *obj; | ||
6156 | int rc; | ||
6157 | |||
6158 | if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { | ||
6159 | obj = (union acpi_object *)buffer.pointer; | ||
6160 | if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { | ||
6161 | printk(TPACPI_ERR "Unknown _BCL data, " | ||
6162 | "please report this to %s\n", TPACPI_MAIL); | ||
6163 | rc = 0; | ||
6164 | } else { | ||
6165 | rc = obj->package.count; | ||
6166 | } | ||
6167 | } else { | ||
6168 | return 0; | ||
6169 | } | ||
6170 | |||
6171 | kfree(buffer.pointer); | ||
6172 | return rc; | ||
6173 | } | ||
6174 | |||
6175 | static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, | ||
6176 | u32 lvl, void *context, void **rv) | ||
6177 | { | ||
6178 | char name[ACPI_PATH_SEGMENT_LENGTH]; | ||
6179 | struct acpi_buffer buffer = { sizeof(name), &name }; | ||
6180 | |||
6181 | if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && | ||
6182 | !strncmp("_BCL", name, sizeof(name) - 1)) { | ||
6183 | BUG_ON(!rv || !*rv); | ||
6184 | **(int **)rv = tpacpi_query_bcl_levels(handle); | ||
6185 | return AE_CTRL_TERMINATE; | ||
6186 | } else { | ||
6187 | return AE_OK; | ||
6188 | } | ||
6189 | } | ||
6190 | |||
6191 | /* | ||
6192 | * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map | ||
6193 | */ | ||
6194 | static unsigned int __init tpacpi_check_std_acpi_brightness_support(void) | ||
6195 | { | ||
6196 | int status; | ||
6197 | int bcl_levels = 0; | ||
6198 | void *bcl_ptr = &bcl_levels; | ||
6199 | |||
6200 | if (!vid_handle) | ||
6201 | TPACPI_ACPIHANDLE_INIT(vid); | ||
6202 | |||
6203 | if (!vid_handle) | ||
6204 | return 0; | ||
6205 | |||
6206 | /* | ||
6207 | * Search for a _BCL method, and execute it. This is safe on all | ||
6208 | * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista | ||
6209 | * BIOS in ACPI backlight control mode. We do NOT have to care | ||
6210 | * about calling the _BCL method in an enabled video device, any | ||
6211 | * will do for our purposes. | ||
6212 | */ | ||
6213 | |||
6214 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, | ||
6215 | tpacpi_acpi_walk_find_bcl, NULL, NULL, | ||
6216 | &bcl_ptr); | ||
6217 | |||
6218 | if (ACPI_SUCCESS(status) && bcl_levels > 2) { | ||
6219 | tp_features.bright_acpimode = 1; | ||
6220 | return bcl_levels - 2; | ||
6221 | } | ||
6222 | |||
6223 | return 0; | ||
6224 | } | ||
6225 | |||
6142 | /* | 6226 | /* |
6143 | * These are only useful for models that have only one possibility | 6227 | * These are only useful for models that have only one possibility |
6144 | * of GPU. If the BIOS model handles both ATI and Intel, don't use | 6228 | * of GPU. If the BIOS model handles both ATI and Intel, don't use |
@@ -6169,6 +6253,47 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = { | |||
6169 | TPACPI_Q_IBM('7', '5', TPACPI_BRGHT_Q_NOEC), /* X41 Tablet */ | 6253 | TPACPI_Q_IBM('7', '5', TPACPI_BRGHT_Q_NOEC), /* X41 Tablet */ |
6170 | }; | 6254 | }; |
6171 | 6255 | ||
6256 | /* | ||
6257 | * Returns < 0 for error, otherwise sets tp_features.bright_* | ||
6258 | * and bright_maxlvl. | ||
6259 | */ | ||
6260 | static void __init tpacpi_detect_brightness_capabilities(void) | ||
6261 | { | ||
6262 | unsigned int b; | ||
6263 | |||
6264 | vdbg_printk(TPACPI_DBG_INIT, | ||
6265 | "detecting firmware brightness interface capabilities\n"); | ||
6266 | |||
6267 | /* we could run a quirks check here (same table used by | ||
6268 | * brightness_init) if needed */ | ||
6269 | |||
6270 | /* | ||
6271 | * We always attempt to detect acpi support, so as to switch | ||
6272 | * Lenovo Vista BIOS to ACPI brightness mode even if we are not | ||
6273 | * going to publish a backlight interface | ||
6274 | */ | ||
6275 | b = tpacpi_check_std_acpi_brightness_support(); | ||
6276 | switch (b) { | ||
6277 | case 16: | ||
6278 | bright_maxlvl = 15; | ||
6279 | printk(TPACPI_INFO | ||
6280 | "detected a 16-level brightness capable ThinkPad\n"); | ||
6281 | break; | ||
6282 | case 8: | ||
6283 | case 0: | ||
6284 | bright_maxlvl = 7; | ||
6285 | printk(TPACPI_INFO | ||
6286 | "detected a 8-level brightness capable ThinkPad\n"); | ||
6287 | break; | ||
6288 | default: | ||
6289 | printk(TPACPI_ERR | ||
6290 | "Unsupported brightness interface, " | ||
6291 | "please contact %s\n", TPACPI_MAIL); | ||
6292 | tp_features.bright_unkfw = 1; | ||
6293 | bright_maxlvl = b - 1; | ||
6294 | } | ||
6295 | } | ||
6296 | |||
6172 | static int __init brightness_init(struct ibm_init_struct *iibm) | 6297 | static int __init brightness_init(struct ibm_init_struct *iibm) |
6173 | { | 6298 | { |
6174 | struct backlight_properties props; | 6299 | struct backlight_properties props; |
@@ -6182,14 +6307,13 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
6182 | quirks = tpacpi_check_quirks(brightness_quirk_table, | 6307 | quirks = tpacpi_check_quirks(brightness_quirk_table, |
6183 | ARRAY_SIZE(brightness_quirk_table)); | 6308 | ARRAY_SIZE(brightness_quirk_table)); |
6184 | 6309 | ||
6185 | /* | 6310 | /* tpacpi_detect_brightness_capabilities() must have run already */ |
6186 | * We always attempt to detect acpi support, so as to switch | 6311 | |
6187 | * Lenovo Vista BIOS to ACPI brightness mode even if we are not | 6312 | /* if it is unknown, we don't handle it: it wouldn't be safe */ |
6188 | * going to publish a backlight interface | 6313 | if (tp_features.bright_unkfw) |
6189 | */ | 6314 | return 1; |
6190 | b = tpacpi_check_std_acpi_brightness_support(); | ||
6191 | if (b > 0) { | ||
6192 | 6315 | ||
6316 | if (tp_features.bright_acpimode) { | ||
6193 | if (acpi_video_backlight_support()) { | 6317 | if (acpi_video_backlight_support()) { |
6194 | if (brightness_enable > 1) { | 6318 | if (brightness_enable > 1) { |
6195 | printk(TPACPI_NOTICE | 6319 | printk(TPACPI_NOTICE |
@@ -6218,15 +6342,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
6218 | return 1; | 6342 | return 1; |
6219 | } | 6343 | } |
6220 | 6344 | ||
6221 | if (b > 16) { | ||
6222 | printk(TPACPI_ERR | ||
6223 | "Unsupported brightness interface, " | ||
6224 | "please contact %s\n", TPACPI_MAIL); | ||
6225 | return 1; | ||
6226 | } | ||
6227 | if (b == 16) | ||
6228 | tp_features.bright_16levels = 1; | ||
6229 | |||
6230 | /* | 6345 | /* |
6231 | * Check for module parameter bogosity, note that we | 6346 | * Check for module parameter bogosity, note that we |
6232 | * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be | 6347 | * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be |
@@ -6249,7 +6364,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
6249 | } | 6364 | } |
6250 | 6365 | ||
6251 | /* Safety */ | 6366 | /* Safety */ |
6252 | if (thinkpad_id.vendor != PCI_VENDOR_ID_IBM && | 6367 | if (!tpacpi_is_ibm() && |
6253 | (brightness_mode == TPACPI_BRGHT_MODE_ECNVRAM || | 6368 | (brightness_mode == TPACPI_BRGHT_MODE_ECNVRAM || |
6254 | brightness_mode == TPACPI_BRGHT_MODE_EC)) | 6369 | brightness_mode == TPACPI_BRGHT_MODE_EC)) |
6255 | return -EINVAL; | 6370 | return -EINVAL; |
@@ -6257,12 +6372,9 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
6257 | if (tpacpi_brightness_get_raw(&b) < 0) | 6372 | if (tpacpi_brightness_get_raw(&b) < 0) |
6258 | return 1; | 6373 | return 1; |
6259 | 6374 | ||
6260 | if (tp_features.bright_16levels) | ||
6261 | printk(TPACPI_INFO | ||
6262 | "detected a 16-level brightness capable ThinkPad\n"); | ||
6263 | |||
6264 | memset(&props, 0, sizeof(struct backlight_properties)); | 6375 | memset(&props, 0, sizeof(struct backlight_properties)); |
6265 | props.max_brightness = (tp_features.bright_16levels) ? 15 : 7; | 6376 | props.max_brightness = bright_maxlvl; |
6377 | props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; | ||
6266 | ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME, | 6378 | ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME, |
6267 | NULL, NULL, | 6379 | NULL, NULL, |
6268 | &ibm_backlight_data, | 6380 | &ibm_backlight_data, |
@@ -6285,7 +6397,10 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
6285 | "or not on your ThinkPad\n", TPACPI_MAIL); | 6397 | "or not on your ThinkPad\n", TPACPI_MAIL); |
6286 | } | 6398 | } |
6287 | 6399 | ||
6288 | ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; | 6400 | /* Added by mistake in early 2007. Probably useless, but it could |
6401 | * be working around some unknown firmware problem where the value | ||
6402 | * read at startup doesn't match the real hardware state... so leave | ||
6403 | * it in place just in case */ | ||
6289 | backlight_update_status(ibm_backlight_device); | 6404 | backlight_update_status(ibm_backlight_device); |
6290 | 6405 | ||
6291 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, | 6406 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, |
@@ -6328,9 +6443,8 @@ static int brightness_read(struct seq_file *m) | |||
6328 | } else { | 6443 | } else { |
6329 | seq_printf(m, "level:\t\t%d\n", level); | 6444 | seq_printf(m, "level:\t\t%d\n", level); |
6330 | seq_printf(m, "commands:\tup, down\n"); | 6445 | seq_printf(m, "commands:\tup, down\n"); |
6331 | seq_printf(m, "commands:\tlevel <level>" | 6446 | seq_printf(m, "commands:\tlevel <level> (<level> is 0-%d)\n", |
6332 | " (<level> is 0-%d)\n", | 6447 | bright_maxlvl); |
6333 | (tp_features.bright_16levels) ? 15 : 7); | ||
6334 | } | 6448 | } |
6335 | 6449 | ||
6336 | return 0; | 6450 | return 0; |
@@ -6341,7 +6455,6 @@ static int brightness_write(char *buf) | |||
6341 | int level; | 6455 | int level; |
6342 | int rc; | 6456 | int rc; |
6343 | char *cmd; | 6457 | char *cmd; |
6344 | int max_level = (tp_features.bright_16levels) ? 15 : 7; | ||
6345 | 6458 | ||
6346 | level = brightness_get(NULL); | 6459 | level = brightness_get(NULL); |
6347 | if (level < 0) | 6460 | if (level < 0) |
@@ -6349,13 +6462,13 @@ static int brightness_write(char *buf) | |||
6349 | 6462 | ||
6350 | while ((cmd = next_cmd(&buf))) { | 6463 | while ((cmd = next_cmd(&buf))) { |
6351 | if (strlencmp(cmd, "up") == 0) { | 6464 | if (strlencmp(cmd, "up") == 0) { |
6352 | if (level < max_level) | 6465 | if (level < bright_maxlvl) |
6353 | level++; | 6466 | level++; |
6354 | } else if (strlencmp(cmd, "down") == 0) { | 6467 | } else if (strlencmp(cmd, "down") == 0) { |
6355 | if (level > 0) | 6468 | if (level > 0) |
6356 | level--; | 6469 | level--; |
6357 | } else if (sscanf(cmd, "level %d", &level) == 1 && | 6470 | } else if (sscanf(cmd, "level %d", &level) == 1 && |
6358 | level >= 0 && level <= max_level) { | 6471 | level >= 0 && level <= bright_maxlvl) { |
6359 | /* new level set */ | 6472 | /* new level set */ |
6360 | } else | 6473 | } else |
6361 | return -EINVAL; | 6474 | return -EINVAL; |
@@ -6669,6 +6782,8 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol, | |||
6669 | static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, | 6782 | static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, |
6670 | struct snd_ctl_elem_value *ucontrol) | 6783 | struct snd_ctl_elem_value *ucontrol) |
6671 | { | 6784 | { |
6785 | tpacpi_disclose_usertask("ALSA", "set volume to %ld\n", | ||
6786 | ucontrol->value.integer.value[0]); | ||
6672 | return volume_alsa_set_volume(ucontrol->value.integer.value[0]); | 6787 | return volume_alsa_set_volume(ucontrol->value.integer.value[0]); |
6673 | } | 6788 | } |
6674 | 6789 | ||
@@ -6692,6 +6807,9 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol, | |||
6692 | static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, | 6807 | static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, |
6693 | struct snd_ctl_elem_value *ucontrol) | 6808 | struct snd_ctl_elem_value *ucontrol) |
6694 | { | 6809 | { |
6810 | tpacpi_disclose_usertask("ALSA", "%smute\n", | ||
6811 | ucontrol->value.integer.value[0] ? | ||
6812 | "un" : ""); | ||
6695 | return volume_alsa_set_mute(!ucontrol->value.integer.value[0]); | 6813 | return volume_alsa_set_mute(!ucontrol->value.integer.value[0]); |
6696 | } | 6814 | } |
6697 | 6815 | ||
@@ -7968,9 +8086,11 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
7968 | tp_features.second_fan = 0; | 8086 | tp_features.second_fan = 0; |
7969 | fan_control_desired_level = 7; | 8087 | fan_control_desired_level = 7; |
7970 | 8088 | ||
7971 | TPACPI_ACPIHANDLE_INIT(fans); | 8089 | if (tpacpi_is_ibm()) { |
7972 | TPACPI_ACPIHANDLE_INIT(gfan); | 8090 | TPACPI_ACPIHANDLE_INIT(fans); |
7973 | TPACPI_ACPIHANDLE_INIT(sfan); | 8091 | TPACPI_ACPIHANDLE_INIT(gfan); |
8092 | TPACPI_ACPIHANDLE_INIT(sfan); | ||
8093 | } | ||
7974 | 8094 | ||
7975 | quirks = tpacpi_check_quirks(fan_quirk_table, | 8095 | quirks = tpacpi_check_quirks(fan_quirk_table, |
7976 | ARRAY_SIZE(fan_quirk_table)); | 8096 | ARRAY_SIZE(fan_quirk_table)); |
@@ -8662,6 +8782,10 @@ static int __init probe_for_thinkpad(void) | |||
8662 | if (acpi_disabled) | 8782 | if (acpi_disabled) |
8663 | return -ENODEV; | 8783 | return -ENODEV; |
8664 | 8784 | ||
8785 | /* It would be dangerous to run the driver in this case */ | ||
8786 | if (!tpacpi_is_ibm() && !tpacpi_is_lenovo()) | ||
8787 | return -ENODEV; | ||
8788 | |||
8665 | /* | 8789 | /* |
8666 | * Non-ancient models have better DMI tagging, but very old models | 8790 | * Non-ancient models have better DMI tagging, but very old models |
8667 | * don't. tpacpi_is_fw_known() is a cheat to help in that case. | 8791 | * don't. tpacpi_is_fw_known() is a cheat to help in that case. |
@@ -8670,8 +8794,8 @@ static int __init probe_for_thinkpad(void) | |||
8670 | (thinkpad_id.ec_model != 0) || | 8794 | (thinkpad_id.ec_model != 0) || |
8671 | tpacpi_is_fw_known(); | 8795 | tpacpi_is_fw_known(); |
8672 | 8796 | ||
8673 | /* ec is required because many other handles are relative to it */ | 8797 | /* The EC handler is required */ |
8674 | TPACPI_ACPIHANDLE_INIT(ec); | 8798 | tpacpi_acpi_handle_locate("ec", TPACPI_ACPI_EC_HID, &ec_handle); |
8675 | if (!ec_handle) { | 8799 | if (!ec_handle) { |
8676 | if (is_thinkpad) | 8800 | if (is_thinkpad) |
8677 | printk(TPACPI_ERR | 8801 | printk(TPACPI_ERR |
@@ -8685,12 +8809,34 @@ static int __init probe_for_thinkpad(void) | |||
8685 | return 0; | 8809 | return 0; |
8686 | } | 8810 | } |
8687 | 8811 | ||
8812 | static void __init thinkpad_acpi_init_banner(void) | ||
8813 | { | ||
8814 | printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION); | ||
8815 | printk(TPACPI_INFO "%s\n", TPACPI_URL); | ||
8816 | |||
8817 | printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n", | ||
8818 | (thinkpad_id.bios_version_str) ? | ||
8819 | thinkpad_id.bios_version_str : "unknown", | ||
8820 | (thinkpad_id.ec_version_str) ? | ||
8821 | thinkpad_id.ec_version_str : "unknown"); | ||
8822 | |||
8823 | BUG_ON(!thinkpad_id.vendor); | ||
8824 | |||
8825 | if (thinkpad_id.model_str) | ||
8826 | printk(TPACPI_INFO "%s %s, model %s\n", | ||
8827 | (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? | ||
8828 | "IBM" : ((thinkpad_id.vendor == | ||
8829 | PCI_VENDOR_ID_LENOVO) ? | ||
8830 | "Lenovo" : "Unknown vendor"), | ||
8831 | thinkpad_id.model_str, | ||
8832 | (thinkpad_id.nummodel_str) ? | ||
8833 | thinkpad_id.nummodel_str : "unknown"); | ||
8834 | } | ||
8688 | 8835 | ||
8689 | /* Module init, exit, parameters */ | 8836 | /* Module init, exit, parameters */ |
8690 | 8837 | ||
8691 | static struct ibm_init_struct ibms_init[] __initdata = { | 8838 | static struct ibm_init_struct ibms_init[] __initdata = { |
8692 | { | 8839 | { |
8693 | .init = thinkpad_acpi_driver_init, | ||
8694 | .data = &thinkpad_acpi_driver_data, | 8840 | .data = &thinkpad_acpi_driver_data, |
8695 | }, | 8841 | }, |
8696 | { | 8842 | { |
@@ -8960,6 +9106,9 @@ static int __init thinkpad_acpi_module_init(void) | |||
8960 | 9106 | ||
8961 | /* Driver initialization */ | 9107 | /* Driver initialization */ |
8962 | 9108 | ||
9109 | thinkpad_acpi_init_banner(); | ||
9110 | tpacpi_check_outdated_fw(); | ||
9111 | |||
8963 | TPACPI_ACPIHANDLE_INIT(ecrd); | 9112 | TPACPI_ACPIHANDLE_INIT(ecrd); |
8964 | TPACPI_ACPIHANDLE_INIT(ecwr); | 9113 | TPACPI_ACPIHANDLE_INIT(ecwr); |
8965 | 9114 | ||
@@ -9059,13 +9208,16 @@ static int __init thinkpad_acpi_module_init(void) | |||
9059 | tpacpi_inputdev->name = "ThinkPad Extra Buttons"; | 9208 | tpacpi_inputdev->name = "ThinkPad Extra Buttons"; |
9060 | tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0"; | 9209 | tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0"; |
9061 | tpacpi_inputdev->id.bustype = BUS_HOST; | 9210 | tpacpi_inputdev->id.bustype = BUS_HOST; |
9062 | tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ? | 9211 | tpacpi_inputdev->id.vendor = thinkpad_id.vendor; |
9063 | thinkpad_id.vendor : | ||
9064 | PCI_VENDOR_ID_IBM; | ||
9065 | tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; | 9212 | tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; |
9066 | tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; | 9213 | tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; |
9067 | tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev; | 9214 | tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev; |
9068 | } | 9215 | } |
9216 | |||
9217 | /* Init subdriver dependencies */ | ||
9218 | tpacpi_detect_brightness_capabilities(); | ||
9219 | |||
9220 | /* Init subdrivers */ | ||
9069 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { | 9221 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { |
9070 | ret = ibm_init(&ibms_init[i]); | 9222 | ret = ibm_init(&ibms_init[i]); |
9071 | if (ret >= 0 && *ibms_init[i].param) | 9223 | if (ret >= 0 && *ibms_init[i].param) |