aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2010-05-20 09:24:29 -0400
committerMatthew Garrett <mjg@redhat.com>2010-05-20 09:24:29 -0400
commit420f5f0c5aeb3ff47cf220e7b256f8fec327659c (patch)
tree9c9fcd733a04d8c147e9d01f44911c359e1543bf
parenta1e66dd0515c8cfa72b8e2a3834d59548cf84ba5 (diff)
parent7d9745cf239ca98cf1f694bff4765a276b05ee68 (diff)
Merge branch 'for-upstream/platform-x86_tpacpi' of git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6 into x86-platform
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt66
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c600
2 files changed, 425 insertions, 241 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index 39c0a09d0105..fc15538d8b46 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -292,13 +292,13 @@ sysfs notes:
292 292
293 Warning: when in NVRAM mode, the volume up/down/mute 293 Warning: when in NVRAM mode, the volume up/down/mute
294 keys are synthesized according to changes in the mixer, 294 keys are synthesized according to changes in the mixer,
295 so you have to use volume up or volume down to unmute, 295 which uses a single volume up or volume down hotkey
296 as per the ThinkPad volume mixer user interface. When 296 press to unmute, as per the ThinkPad volume mixer user
297 in ACPI event mode, volume up/down/mute are reported as 297 interface. When in ACPI event mode, volume up/down/mute
298 separate events, but this behaviour may be corrected in 298 events are reported by the firmware and can behave
299 future releases of this driver, in which case the 299 differently (and that behaviour changes with firmware
300 ThinkPad volume mixer user interface semantics will be 300 version -- not just with firmware models -- as well as
301 enforced. 301 OSI(Linux) state).
302 302
303 hotkey_poll_freq: 303 hotkey_poll_freq:
304 frequency in Hz for hot key polling. It must be between 304 frequency in Hz for hot key polling. It must be between
@@ -309,7 +309,7 @@ sysfs notes:
309 will cause hot key presses that require NVRAM polling 309 will cause hot key presses that require NVRAM polling
310 to never be reported. 310 to never be reported.
311 311
312 Setting hotkey_poll_freq too low will cause repeated 312 Setting hotkey_poll_freq too low may cause repeated
313 pressings of the same hot key to be misreported as a 313 pressings of the same hot key to be misreported as a
314 single key press, or to not even be detected at all. 314 single key press, or to not even be detected at all.
315 The recommended polling frequency is 10Hz. 315 The recommended polling frequency is 10Hz.
@@ -397,6 +397,7 @@ ACPI Scan
397event code Key Notes 397event code Key Notes
398 398
3990x1001 0x00 FN+F1 - 3990x1001 0x00 FN+F1 -
400
4000x1002 0x01 FN+F2 IBM: battery (rare) 4010x1002 0x01 FN+F2 IBM: battery (rare)
401 Lenovo: Screen lock 402 Lenovo: Screen lock
402 403
@@ -404,7 +405,8 @@ event code Key Notes
404 this hot key, even with hot keys 405 this hot key, even with hot keys
405 disabled or with Fn+F3 masked 406 disabled or with Fn+F3 masked
406 off 407 off
407 IBM: screen lock 408 IBM: screen lock, often turns
409 off the ThinkLight as side-effect
408 Lenovo: battery 410 Lenovo: battery
409 411
4100x1004 0x03 FN+F4 Sleep button (ACPI sleep button 4120x1004 0x03 FN+F4 Sleep button (ACPI sleep button
@@ -433,7 +435,8 @@ event code Key Notes
433 Do you feel lucky today? 435 Do you feel lucky today?
434 436
4350x1008 0x07 FN+F8 IBM: toggle screen expand 4370x1008 0x07 FN+F8 IBM: toggle screen expand
436 Lenovo: configure UltraNav 438 Lenovo: configure UltraNav,
439 or toggle screen expand
437 440
4380x1009 0x08 FN+F9 - 4410x1009 0x08 FN+F9 -
439 .. .. .. 442 .. .. ..
@@ -444,7 +447,7 @@ event code Key Notes
444 either through the ACPI event, 447 either through the ACPI event,
445 or through a hotkey event. 448 or through a hotkey event.
446 The firmware may refuse to 449 The firmware may refuse to
447 generate further FN+F4 key 450 generate further FN+F12 key
448 press events until a S3 or S4 451 press events until a S3 or S4
449 ACPI sleep cycle is performed, 452 ACPI sleep cycle is performed,
450 or some time passes. 453 or some time passes.
@@ -512,15 +515,19 @@ events for switches:
512SW_RFKILL_ALL T60 and later hardware rfkill rocker switch 515SW_RFKILL_ALL T60 and later hardware rfkill rocker switch
513SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A 516SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A
514 517
515Non hot-key ACPI HKEY event map: 518Non hotkey ACPI HKEY event map:
519-------------------------------
520
521Events that are not propagated by the driver, except for legacy
522compatibility purposes when hotkey_report_mode is set to 1:
523
5160x5001 Lid closed 5240x5001 Lid closed
5170x5002 Lid opened 5250x5002 Lid opened
5180x5009 Tablet swivel: switched to tablet mode 5260x5009 Tablet swivel: switched to tablet mode
5190x500A Tablet swivel: switched to normal mode 5270x500A Tablet swivel: switched to normal mode
5200x7000 Radio Switch may have changed state 5280x7000 Radio Switch may have changed state
521 529
522The above events are not propagated by the driver, except for legacy 530Events that are never propagated by the driver:
523compatibility purposes when hotkey_report_mode is set to 1.
524 531
5250x2304 System is waking up from suspend to undock 5320x2304 System is waking up from suspend to undock
5260x2305 System is waking up from suspend to eject bay 5330x2305 System is waking up from suspend to eject bay
@@ -528,14 +535,39 @@ compatibility purposes when hotkey_report_mode is set to 1.
5280x2405 System is waking up from hibernation to eject bay 5350x2405 System is waking up from hibernation to eject bay
5290x5010 Brightness level changed/control event 5360x5010 Brightness level changed/control event
530 537
531The above events are never propagated by the driver. 538Events that are propagated by the driver to userspace:
532 539
5400x2313 ALARM: System is waking up from suspend because
541 the battery is nearly empty
5420x2413 ALARM: System is waking up from hibernation because
543 the battery is nearly empty
5330x3003 Bay ejection (see 0x2x05) complete, can sleep again 5440x3003 Bay ejection (see 0x2x05) complete, can sleep again
5450x3006 Bay hotplug request (hint to power up SATA link when
546 the optical drive tray is ejected)
5340x4003 Undocked (see 0x2x04), can sleep again 5470x4003 Undocked (see 0x2x04), can sleep again
5350x500B Tablet pen inserted into its storage bay 5480x500B Tablet pen inserted into its storage bay
5360x500C Tablet pen removed from its storage bay 5490x500C Tablet pen removed from its storage bay
537 5500x6011 ALARM: battery is too hot
538The above events are propagated by the driver. 5510x6012 ALARM: battery is extremely hot
5520x6021 ALARM: a sensor is too hot
5530x6022 ALARM: a sensor is extremely hot
5540x6030 System thermal table changed
555
556Battery nearly empty alarms are a last resort attempt to get the
557operating system to hibernate or shutdown cleanly (0x2313), or shutdown
558cleanly (0x2413) before power is lost. They must be acted upon, as the
559wake up caused by the firmware will have negated most safety nets...
560
561When any of the "too hot" alarms happen, according to Lenovo the user
562should suspend or hibernate the laptop (and in the case of battery
563alarms, unplug the AC adapter) to let it cool down. These alarms do
564signal that something is wrong, they should never happen on normal
565operating conditions.
566
567The "extremely hot" alarms are emergencies. According to Lenovo, the
568operating system is to force either an immediate suspend or hibernate
569cycle, or a system shutdown. Obviously, something is very wrong if this
570happens.
539 571
540Compatibility notes: 572Compatibility notes:
541 573
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 */
126enum {
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 */
373static unsigned int bright_maxlvl; /* 0 = unknown */
374
366#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 375#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
367static int dbg_wlswemul; 376static int dbg_wlswemul;
368static int tpacpi_wlsw_emulstate; 377static 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
492static inline bool __pure __init tpacpi_is_lenovo(void)
493{
494 return thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO;
495}
496
497static 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
496static acpi_handle root_handle; 514static acpi_handle root_handle;
515static 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
504TPACPI_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
513TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */ 523TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */
514TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */ 524TPACPI_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
666static void drv_acpi_handle_init(char *name, 678static 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
703static 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
711static 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
692static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) 740static 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
1038static 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
1061static 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 */
1080static 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
1112static void printk_deprecated_attribute(const char * const what, 1086static 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
1878static 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
1903static int thinkpad_acpi_driver_read(struct seq_file *m) 1852static 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
5008static enum led_access_mode led_supported; 5009static enum led_access_mode led_supported;
5009 5010
5010TPACPI_HANDLE(led, ec, "SLED", /* 570 */ 5011static 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
5017static struct tpacpi_led_classdev *tpacpi_leds; 5014static 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
5271static 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
5274static int __init led_init(struct ibm_init_struct *iibm) 5297static 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
6152static 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
6175static 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 */
6194static 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 */
6260static 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
6172static int __init brightness_init(struct ibm_init_struct *iibm) 6297static 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,
6669static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, 6782static 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,
6692static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, 6807static 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
8812static 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
8691static struct ibm_init_struct ibms_init[] __initdata = { 8838static 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)