From e28393c0c4416dffb46ca481e670f10c6a35baca Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:23 -0300 Subject: thinkpad-acpi: constrain IBM-era support to IBM boxes Lenovo is playing around with its ACPI BIOS, and will end up reusing method names. Their memory is not nearly as long as thinkpad-acpi's... Secure most of the old IBM codepaths against running in a non-IBM box. This would happen on the Lenovo X100e in video_init(), for example. We would misdetect it as an ancient model 570 firmware. Also, refuse to load the driver if we cannot identify the vendor. No ACPI ThinkPad in existence lacks this information, AFAIK. Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 57 ++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 18 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 63290b33c87..21759dacff6 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -480,6 +480,15 @@ static unsigned long __init tpacpi_check_quirks( return 0; } +static inline bool __pure __init tpacpi_is_lenovo(void) +{ + return thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO; +} + +static inline bool __pure __init tpacpi_is_ibm(void) +{ + return thinkpad_id.vendor == PCI_VENDOR_ID_IBM; +} /**************************************************************************** **************************************************************************** @@ -1886,7 +1895,9 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) (thinkpad_id.ec_version_str) ? thinkpad_id.ec_version_str : "unknown"); - if (thinkpad_id.vendor && thinkpad_id.model_str) + BUG_ON(!thinkpad_id.vendor); + + if (thinkpad_id.model_str) printk(TPACPI_INFO "%s %s, model %s\n", (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? "IBM" : ((thinkpad_id.vendor == @@ -3353,7 +3364,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) goto err_exit; } - if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { + if (tpacpi_is_lenovo()) { dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "using Lenovo default hot key map\n"); memcpy(hotkey_keycode_map, &lenovo_keycode_map, @@ -4422,7 +4433,8 @@ static int __init video_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); TPACPI_ACPIHANDLE_INIT(vid); - TPACPI_ACPIHANDLE_INIT(vid2); + if (tpacpi_is_ibm()) + TPACPI_ACPIHANDLE_INIT(vid2); if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) /* G41, assume IVGA doesn't change */ @@ -4431,10 +4443,12 @@ static int __init video_init(struct ibm_init_struct *iibm) if (!vid_handle) /* video switching not supported on R30, R31 */ video_supported = TPACPI_VIDEO_NONE; - else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) + else if (tpacpi_is_ibm() && + acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) /* 570 */ video_supported = TPACPI_VIDEO_570; - else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) + else if (tpacpi_is_ibm() && + acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) /* 600e/x, 770e, 770x */ video_supported = TPACPI_VIDEO_770; else @@ -4811,8 +4825,10 @@ static int __init light_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); - TPACPI_ACPIHANDLE_INIT(ledb); - TPACPI_ACPIHANDLE_INIT(lght); + if (tpacpi_is_ibm()) { + TPACPI_ACPIHANDLE_INIT(ledb); + TPACPI_ACPIHANDLE_INIT(lght); + } TPACPI_ACPIHANDLE_INIT(cmos); INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker); @@ -5284,10 +5300,10 @@ static int __init led_init(struct ibm_init_struct *iibm) if (!led_handle) /* led not supported on R30, R31 */ led_supported = TPACPI_LED_NONE; - else if (strlencmp(led_path, "SLED") == 0) + else if (tpacpi_is_ibm() && strlencmp(led_path, "SLED") == 0) /* 570 */ led_supported = TPACPI_LED_570; - else if (strlencmp(led_path, "SYSL") == 0) + else if (tpacpi_is_ibm() && strlencmp(led_path, "SYSL") == 0) /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ led_supported = TPACPI_LED_OLD; else @@ -5741,11 +5757,12 @@ static int __init thermal_init(struct ibm_init_struct *iibm) TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8; } } else if (acpi_tmp7) { - if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { + if (tpacpi_is_ibm() && + acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { /* 600e/x, 770e, 770x */ thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT; } else { - /* Standard ACPI TMPx access, max 8 sensors */ + /* IBM/LENOVO DSDT EC.TMPx access, max 8 sensors */ thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; } } else { @@ -6249,7 +6266,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) } /* Safety */ - if (thinkpad_id.vendor != PCI_VENDOR_ID_IBM && + if (!tpacpi_is_ibm() && (brightness_mode == TPACPI_BRGHT_MODE_ECNVRAM || brightness_mode == TPACPI_BRGHT_MODE_EC)) return -EINVAL; @@ -7968,9 +7985,11 @@ static int __init fan_init(struct ibm_init_struct *iibm) tp_features.second_fan = 0; fan_control_desired_level = 7; - TPACPI_ACPIHANDLE_INIT(fans); - TPACPI_ACPIHANDLE_INIT(gfan); - TPACPI_ACPIHANDLE_INIT(sfan); + if (tpacpi_is_ibm()) { + TPACPI_ACPIHANDLE_INIT(fans); + TPACPI_ACPIHANDLE_INIT(gfan); + TPACPI_ACPIHANDLE_INIT(sfan); + } quirks = tpacpi_check_quirks(fan_quirk_table, ARRAY_SIZE(fan_quirk_table)); @@ -8662,6 +8681,10 @@ static int __init probe_for_thinkpad(void) if (acpi_disabled) return -ENODEV; + /* It would be dangerous to run the driver in this case */ + if (!tpacpi_is_ibm() && !tpacpi_is_lenovo()) + return -ENODEV; + /* * Non-ancient models have better DMI tagging, but very old models * don't. tpacpi_is_fw_known() is a cheat to help in that case. @@ -9059,9 +9082,7 @@ static int __init thinkpad_acpi_module_init(void) tpacpi_inputdev->name = "ThinkPad Extra Buttons"; tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0"; tpacpi_inputdev->id.bustype = BUS_HOST; - tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ? - thinkpad_id.vendor : - PCI_VENDOR_ID_IBM; + tpacpi_inputdev->id.vendor = thinkpad_id.vendor; tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev; -- cgit v1.2.3-70-g09d2 From a318930d06a7a93bd50000c7112f995b459adda7 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:26 -0300 Subject: thinkpad-acpi: X100e quick fixes The X100e needs some quick fixes to work semi-right with this driver. There are much better ways to do this, but we can start with a quick update and do it properly later. Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 21759dacff6..7817cef6aae 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -516,6 +516,7 @@ TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */ "\\_SB.PCI0.ICH3.EC0", /* R31 */ + "\\_SB.PCI0.LPC0.EC", /* X100e and a few others */ "\\_SB.PCI0.LPC.EC", /* all others */ ); @@ -537,6 +538,7 @@ TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ "\\_SB.PCI0.VID0", /* 770e */ "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ + "\\_SB.PCI0.AGP.VGA", /* X100e and a few others */ "\\_SB.PCI0.AGP.VID", /* all others */ ); /* R30, R31 */ -- cgit v1.2.3-70-g09d2 From 5d756db99a7382d5cd173e912d527e9ee73d0596 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:28 -0300 Subject: thinkpad-acpi: fix volume/mute hotkey poll handling The hotkey polling code is supposed to generate hotkey messages as close to the way the IBM event-based volume hotkey firmware does as possible, i.e: * Pressing MUTE issues a mute hotkey event, even if already mute; * Pressing Volume up/down issues a volume up/down hotkey event, even if already at maximum or minumum volume; * The act of unmuting issues a volume up/down event, depending on which hotkey was used to unmute. Fix the code to do just that (mute handling was incorrect), and handle multiple hotkey presses between two polling cycles. The new code uses the volume_toggle bit in NVRAM only to detect repeated presses of the mute key and multiple presses of the volume keys trying to go past the end of the volume scale. This will work around a bug in recent Lenovo firmware (e.g. T400), which causes the firmware to not update the volume_toggle bit in certain situations. Reported-by: Yang Zhe Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 71 +++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 14 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 7817cef6aae..1f27b350ae0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -122,6 +122,11 @@ enum { TP_NVRAM_POS_LEVEL_VOLUME = 0, }; +/* Misc NVRAM-related */ +enum { + TP_NVRAM_LEVEL_VOLUME_MAX = 14, +}; + /* ACPI HIDs */ #define TPACPI_ACPI_HKEY_HID "IBM0068" @@ -2418,6 +2423,21 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, tpacpi_hotkey_send_key(__scancode); \ } while (0) + void issue_volchange(const unsigned int oldvol, + const unsigned int newvol) + { + unsigned int i = oldvol; + + while (i > newvol) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); + i--; + } + while (i < newvol) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); + i++; + } + } + TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); @@ -2427,24 +2447,47 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle); - /* handle volume */ - if (oldn->volume_toggle != newn->volume_toggle) { - if (oldn->mute != newn->mute) { + /* + * Handle volume + * + * This code is supposed to duplicate the IBM firmware behaviour: + * - Pressing MUTE issues mute hotkey message, even when already mute + * - Pressing Volume up/down issues volume up/down hotkey messages, + * even when already at maximum or minumum volume + * - The act of unmuting issues volume up/down notification, + * depending which key was used to unmute + * + * We are constrained to what the NVRAM can tell us, which is not much + * and certainly not enough if more than one volume hotkey was pressed + * since the last poll cycle. + * + * Just to make our life interesting, some newer Lenovo ThinkPads have + * bugs in the BIOS and may fail to update volume_toggle properly. + */ + if (newn->mute) { + /* muted */ + if (!oldn->mute || + oldn->volume_toggle != newn->volume_toggle || + oldn->volume_level != newn->volume_level) { + /* recently muted, or repeated mute keypress, or + * multiple presses ending in mute */ + issue_volchange(oldn->volume_level, newn->volume_level); TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); } - if (oldn->volume_level > newn->volume_level) { - TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); - } else if (oldn->volume_level < newn->volume_level) { + } else { + /* unmute */ + if (oldn->mute) { + /* recently unmuted, issue 'unmute' keypress */ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); - } else if (oldn->mute == newn->mute) { - /* repeated key presses that didn't change state */ - if (newn->mute) { - TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); - } else if (newn->volume_level != 0) { - TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); - } else { + } + if (oldn->volume_level != newn->volume_level) { + issue_volchange(oldn->volume_level, newn->volume_level); + } else if (oldn->volume_toggle != newn->volume_toggle) { + /* repeated vol up/down keypress at end of scale ? */ + if (newn->volume_level == 0) TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); - } + else if (newn->volume_level >= TP_NVRAM_LEVEL_VOLUME_MAX) + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); } } -- cgit v1.2.3-70-g09d2 From 7a43f788988ac47b21ce258197c5014b5249c9f5 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:31 -0300 Subject: thinkpad-acpi: move greeting messages out of the first subdriver (v2) Move the driver initial greetings out of the first subdriver, as we do a lot of other initialization before that point, and the initial greetings should go as soon as the driver decides that it should load. These greetings are not cosmetic, they make my life easier when users report bugs. Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 56 +++++++++++++++++------------------- 1 file changed, 27 insertions(+), 29 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 1f27b350ae0..a768a69d58d 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1888,36 +1888,9 @@ static bool __init tpacpi_is_fw_known(void) ****************************************************************************/ /************************************************************************* - * thinkpad-acpi init subdriver + * thinkpad-acpi metadata subdriver */ -static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) -{ - printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION); - printk(TPACPI_INFO "%s\n", TPACPI_URL); - - printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n", - (thinkpad_id.bios_version_str) ? - thinkpad_id.bios_version_str : "unknown", - (thinkpad_id.ec_version_str) ? - thinkpad_id.ec_version_str : "unknown"); - - BUG_ON(!thinkpad_id.vendor); - - if (thinkpad_id.model_str) - printk(TPACPI_INFO "%s %s, model %s\n", - (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? - "IBM" : ((thinkpad_id.vendor == - PCI_VENDOR_ID_LENOVO) ? - "Lenovo" : "Unknown vendor"), - thinkpad_id.model_str, - (thinkpad_id.nummodel_str) ? - thinkpad_id.nummodel_str : "unknown"); - - tpacpi_check_outdated_fw(); - return 0; -} - static int thinkpad_acpi_driver_read(struct seq_file *m) { seq_printf(m, "driver:\t\t%s\n", TPACPI_DESC); @@ -8753,12 +8726,34 @@ static int __init probe_for_thinkpad(void) return 0; } +static void __init thinkpad_acpi_init_banner(void) +{ + printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION); + printk(TPACPI_INFO "%s\n", TPACPI_URL); + + printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n", + (thinkpad_id.bios_version_str) ? + thinkpad_id.bios_version_str : "unknown", + (thinkpad_id.ec_version_str) ? + thinkpad_id.ec_version_str : "unknown"); + + BUG_ON(!thinkpad_id.vendor); + + if (thinkpad_id.model_str) + printk(TPACPI_INFO "%s %s, model %s\n", + (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? + "IBM" : ((thinkpad_id.vendor == + PCI_VENDOR_ID_LENOVO) ? + "Lenovo" : "Unknown vendor"), + thinkpad_id.model_str, + (thinkpad_id.nummodel_str) ? + thinkpad_id.nummodel_str : "unknown"); +} /* Module init, exit, parameters */ static struct ibm_init_struct ibms_init[] __initdata = { { - .init = thinkpad_acpi_driver_init, .data = &thinkpad_acpi_driver_data, }, { @@ -9028,6 +9023,9 @@ static int __init thinkpad_acpi_module_init(void) /* Driver initialization */ + thinkpad_acpi_init_banner(); + tpacpi_check_outdated_fw(); + TPACPI_ACPIHANDLE_INIT(ecrd); TPACPI_ACPIHANDLE_INIT(ecwr); -- cgit v1.2.3-70-g09d2 From 77775838bb76173d7a1ed28f75dfe388962aceca Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:33 -0300 Subject: thinkpad-acpi: let other subdrivers know backlight level range Extract the backlight level range size detection from the brightness subdriver, and allow the other subdrivers access to that information. This also allows us to relocate some code to a more convenient place. The moved code was largerly unmodified, except for the return type of tpacpi_check_std_acpi_brightness_support(), which now is correctly marked as returning "unsigned int", and and two cosmetic fixes to make checkpatch.pl happy. Fixes for the NVRAM polling mode for the brightness hotkeys will need this. Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 251 +++++++++++++++++++---------------- 1 file changed, 140 insertions(+), 111 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a768a69d58d..b03bf5153b0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -304,8 +304,8 @@ static struct { u32 hotkey_tablet:1; u32 light:1; u32 light_status:1; - u32 bright_16levels:1; u32 bright_acpimode:1; + u32 bright_unkfw:1; u32 wan:1; u32 uwb:1; u32 fan_ctrl_status_undef:1; @@ -368,6 +368,9 @@ struct tpacpi_led_classdev { unsigned int led; }; +/* brightness level capabilities */ +static unsigned int bright_maxlvl; /* 0 = unknown */ + #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES static int dbg_wlswemul; static int tpacpi_wlsw_emulstate; @@ -1051,80 +1054,6 @@ static void tpacpi_disable_brightness_delay(void) "ACPI backlight control delay disabled\n"); } -static int __init tpacpi_query_bcl_levels(acpi_handle handle) -{ - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - int rc; - - if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { - obj = (union acpi_object *)buffer.pointer; - if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { - printk(TPACPI_ERR "Unknown _BCL data, " - "please report this to %s\n", TPACPI_MAIL); - rc = 0; - } else { - rc = obj->package.count; - } - } else { - return 0; - } - - kfree(buffer.pointer); - return rc; -} - -static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, - u32 lvl, void *context, void **rv) -{ - char name[ACPI_PATH_SEGMENT_LENGTH]; - struct acpi_buffer buffer = { sizeof(name), &name }; - - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && - !strncmp("_BCL", name, sizeof(name) - 1)) { - BUG_ON(!rv || !*rv); - **(int **)rv = tpacpi_query_bcl_levels(handle); - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} - -/* - * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map - */ -static int __init tpacpi_check_std_acpi_brightness_support(void) -{ - int status; - int bcl_levels = 0; - void *bcl_ptr = &bcl_levels; - - if (!vid_handle) { - TPACPI_ACPIHANDLE_INIT(vid); - } - if (!vid_handle) - return 0; - - /* - * Search for a _BCL method, and execute it. This is safe on all - * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista - * BIOS in ACPI backlight control mode. We do NOT have to care - * about calling the _BCL method in an enabled video device, any - * will do for our purposes. - */ - - status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, - tpacpi_acpi_walk_find_bcl, NULL, NULL, - &bcl_ptr); - - if (ACPI_SUCCESS(status) && bcl_levels > 2) { - tp_features.bright_acpimode = 1; - return (bcl_levels - 2); - } - - return 0; -} - static void printk_deprecated_attribute(const char * const what, const char * const details) { @@ -3420,11 +3349,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } /* Do not issue duplicate brightness change events to - * userspace */ - if (!tp_features.bright_acpimode) - /* update bright_acpimode... */ - tpacpi_check_std_acpi_brightness_support(); - + * userspace. tpacpi_detect_brightness_capabilities() must have + * been called before this point */ if (tp_features.bright_acpimode && acpi_video_backlight_support()) { printk(TPACPI_INFO "This ThinkPad has standard ACPI backlight " @@ -5989,7 +5915,7 @@ static unsigned int tpacpi_brightness_nvram_get(void) lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; - lnvram &= (tp_features.bright_16levels) ? 0x0f : 0x07; + lnvram &= bright_maxlvl; return lnvram; } @@ -6098,8 +6024,7 @@ static int brightness_set(unsigned int value) { int res; - if (value > ((tp_features.bright_16levels)? 15 : 7) || - value < 0) + if (value > bright_maxlvl || value < 0) return -EINVAL; vdbg_printk(TPACPI_DBG_BRGHT, @@ -6174,6 +6099,80 @@ static struct backlight_ops ibm_backlight_data = { /* --------------------------------------------------------------------- */ +static int __init tpacpi_query_bcl_levels(acpi_handle handle) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + int rc; + + if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { + obj = (union acpi_object *)buffer.pointer; + if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { + printk(TPACPI_ERR "Unknown _BCL data, " + "please report this to %s\n", TPACPI_MAIL); + rc = 0; + } else { + rc = obj->package.count; + } + } else { + return 0; + } + + kfree(buffer.pointer); + return rc; +} + +static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, + u32 lvl, void *context, void **rv) +{ + char name[ACPI_PATH_SEGMENT_LENGTH]; + struct acpi_buffer buffer = { sizeof(name), &name }; + + if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && + !strncmp("_BCL", name, sizeof(name) - 1)) { + BUG_ON(!rv || !*rv); + **(int **)rv = tpacpi_query_bcl_levels(handle); + return AE_CTRL_TERMINATE; + } else { + return AE_OK; + } +} + +/* + * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map + */ +static unsigned int __init tpacpi_check_std_acpi_brightness_support(void) +{ + int status; + int bcl_levels = 0; + void *bcl_ptr = &bcl_levels; + + if (!vid_handle) + TPACPI_ACPIHANDLE_INIT(vid); + + if (!vid_handle) + return 0; + + /* + * Search for a _BCL method, and execute it. This is safe on all + * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista + * BIOS in ACPI backlight control mode. We do NOT have to care + * about calling the _BCL method in an enabled video device, any + * will do for our purposes. + */ + + status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, + tpacpi_acpi_walk_find_bcl, NULL, NULL, + &bcl_ptr); + + if (ACPI_SUCCESS(status) && bcl_levels > 2) { + tp_features.bright_acpimode = 1; + return bcl_levels - 2; + } + + return 0; +} + /* * These are only useful for models that have only one possibility * of GPU. If the BIOS model handles both ATI and Intel, don't use @@ -6204,6 +6203,47 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = { TPACPI_Q_IBM('7', '5', TPACPI_BRGHT_Q_NOEC), /* X41 Tablet */ }; +/* + * Returns < 0 for error, otherwise sets tp_features.bright_* + * and bright_maxlvl. + */ +static void __init tpacpi_detect_brightness_capabilities(void) +{ + unsigned int b; + + vdbg_printk(TPACPI_DBG_INIT, + "detecting firmware brightness interface capabilities\n"); + + /* we could run a quirks check here (same table used by + * brightness_init) if needed */ + + /* + * We always attempt to detect acpi support, so as to switch + * Lenovo Vista BIOS to ACPI brightness mode even if we are not + * going to publish a backlight interface + */ + b = tpacpi_check_std_acpi_brightness_support(); + switch (b) { + case 16: + bright_maxlvl = 15; + printk(TPACPI_INFO + "detected a 16-level brightness capable ThinkPad\n"); + break; + case 8: + case 0: + bright_maxlvl = 7; + printk(TPACPI_INFO + "detected a 8-level brightness capable ThinkPad\n"); + break; + default: + printk(TPACPI_ERR + "Unsupported brightness interface, " + "please contact %s\n", TPACPI_MAIL); + tp_features.bright_unkfw = 1; + bright_maxlvl = b - 1; + } +} + static int __init brightness_init(struct ibm_init_struct *iibm) { struct backlight_properties props; @@ -6217,14 +6257,13 @@ static int __init brightness_init(struct ibm_init_struct *iibm) quirks = tpacpi_check_quirks(brightness_quirk_table, ARRAY_SIZE(brightness_quirk_table)); - /* - * We always attempt to detect acpi support, so as to switch - * Lenovo Vista BIOS to ACPI brightness mode even if we are not - * going to publish a backlight interface - */ - b = tpacpi_check_std_acpi_brightness_support(); - if (b > 0) { + /* tpacpi_detect_brightness_capabilities() must have run already */ + + /* if it is unknown, we don't handle it: it wouldn't be safe */ + if (tp_features.bright_unkfw) + return 1; + if (tp_features.bright_acpimode) { if (acpi_video_backlight_support()) { if (brightness_enable > 1) { printk(TPACPI_NOTICE @@ -6253,15 +6292,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm) return 1; } - if (b > 16) { - printk(TPACPI_ERR - "Unsupported brightness interface, " - "please contact %s\n", TPACPI_MAIL); - return 1; - } - if (b == 16) - tp_features.bright_16levels = 1; - /* * Check for module parameter bogosity, note that we * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be @@ -6292,12 +6322,9 @@ static int __init brightness_init(struct ibm_init_struct *iibm) if (tpacpi_brightness_get_raw(&b) < 0) return 1; - if (tp_features.bright_16levels) - printk(TPACPI_INFO - "detected a 16-level brightness capable ThinkPad\n"); - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = (tp_features.bright_16levels) ? 15 : 7; + props.max_brightness = bright_maxlvl; + props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, &ibm_backlight_data, @@ -6320,7 +6347,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm) "or not on your ThinkPad\n", TPACPI_MAIL); } - ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; backlight_update_status(ibm_backlight_device); vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, @@ -6363,9 +6389,8 @@ static int brightness_read(struct seq_file *m) } else { seq_printf(m, "level:\t\t%d\n", level); seq_printf(m, "commands:\tup, down\n"); - seq_printf(m, "commands:\tlevel " - " ( is 0-%d)\n", - (tp_features.bright_16levels) ? 15 : 7); + seq_printf(m, "commands:\tlevel ( is 0-%d)\n", + bright_maxlvl); } return 0; @@ -6376,7 +6401,6 @@ static int brightness_write(char *buf) int level; int rc; char *cmd; - int max_level = (tp_features.bright_16levels) ? 15 : 7; level = brightness_get(NULL); if (level < 0) @@ -6384,13 +6408,13 @@ static int brightness_write(char *buf) while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "up") == 0) { - if (level < max_level) + if (level < bright_maxlvl) level++; } else if (strlencmp(cmd, "down") == 0) { if (level > 0) level--; } else if (sscanf(cmd, "level %d", &level) == 1 && - level >= 0 && level <= max_level) { + level >= 0 && level <= bright_maxlvl) { /* new level set */ } else return -EINVAL; @@ -9130,6 +9154,11 @@ static int __init thinkpad_acpi_module_init(void) tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev; } + + /* Init subdriver dependencies */ + tpacpi_detect_brightness_capabilities(); + + /* Init subdrivers */ for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { ret = ibm_init(&ibms_init[i]); if (ret >= 0 && *ibms_init[i].param) -- cgit v1.2.3-70-g09d2 From 289990228155cbc58a35c1b266af00f387caa595 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:36 -0300 Subject: thinkpad-acpi: fix brightness hotkey poll handling Handle multiple brightness hotkey presses between two polling cycles. Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b03bf5153b0..fa412a43f5e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2340,6 +2340,21 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, } } + void issue_brightnesschange(const unsigned int oldbrt, + const unsigned int newbrt) + { + unsigned int i = oldbrt; + + while (i > newbrt) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); + i--; + } + while (i < newbrt) { + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); + i++; + } + } + TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); @@ -2394,19 +2409,16 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, } /* handle brightness */ - if (oldn->brightness_toggle != newn->brightness_toggle) { - if (oldn->brightness_level < newn->brightness_level) { - TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); - } else if (oldn->brightness_level > newn->brightness_level) { + if (oldn->brightness_level != newn->brightness_level) { + issue_brightnesschange(oldn->brightness_level, + newn->brightness_level); + } else if (oldn->brightness_toggle != newn->brightness_toggle) { + /* repeated key presses that didn't change state */ + if (newn->brightness_level == 0) TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); - } else { - /* repeated key presses that didn't change state */ - if (newn->brightness_level != 0) { - TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); - } else { - TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); - } - } + else if (newn->brightness_level >= bright_maxlvl + && !tp_features.bright_unkfw) + TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); } #undef TPACPI_COMPARE_KEY -- cgit v1.2.3-70-g09d2 From 38e11cdec90f1dd7355db4aed8a1857258e99485 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:40 -0300 Subject: thinkpad-acpi: disclose usertask for ALSA callbacks Disclose the user task doing ALSA access when requested by the debug bitmask. Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index fa412a43f5e..b03cb3e0458 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6740,6 +6740,8 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol, static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + tpacpi_disclose_usertask("ALSA", "set volume to %ld\n", + ucontrol->value.integer.value[0]); return volume_alsa_set_volume(ucontrol->value.integer.value[0]); } @@ -6763,6 +6765,9 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol, static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + tpacpi_disclose_usertask("ALSA", "%smute\n", + ucontrol->value.integer.value[0] ? + "un" : ""); return volume_alsa_set_mute(!ucontrol->value.integer.value[0]); } -- cgit v1.2.3-70-g09d2 From 437e470c4ca818c97426afa3a67fbd7e34cffe00 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:43 -0300 Subject: thinkpad-acpi: detect EC node using its HID (v2) Use the EC HID (PNP0C09) to locate its main node, instead of a static list. Suggested-by: Matthew Garrett Signed-off-by: Henrique de Moraes Holschuh Cc: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 53 ++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 12 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b03cb3e0458..877a7802e83 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -129,6 +129,7 @@ enum { /* ACPI HIDs */ #define TPACPI_ACPI_HKEY_HID "IBM0068" +#define TPACPI_ACPI_EC_HID "PNP0C09" /* Input IDs */ #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ @@ -511,6 +512,7 @@ static inline bool __pure __init tpacpi_is_ibm(void) */ static acpi_handle root_handle; +static acpi_handle ec_handle; #define TPACPI_HANDLE(object, parent, paths...) \ static acpi_handle object##_handle; \ @@ -518,16 +520,6 @@ static acpi_handle root_handle; static char *object##_path; \ static char *object##_paths[] = { paths } -TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ - "\\_SB.PCI.ISA.EC", /* 570 */ - "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ - "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ - "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */ - "\\_SB.PCI0.ICH3.EC0", /* R31 */ - "\\_SB.PCI0.LPC0.EC", /* X100e and a few others */ - "\\_SB.PCI0.LPC.EC", /* all others */ - ); - TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */ TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */ @@ -708,6 +700,43 @@ static void drv_acpi_handle_init(char *name, *handle = NULL; } +static acpi_status __init tpacpi_acpi_handle_locate_callback(acpi_handle handle, + u32 level, void *context, void **return_value) +{ + *(acpi_handle *)return_value = handle; + + return AE_CTRL_TERMINATE; +} + +static void __init tpacpi_acpi_handle_locate(const char *name, + const char *hid, + acpi_handle *handle) +{ + acpi_status status; + acpi_handle device_found; + + BUG_ON(!name || !hid || !handle); + vdbg_printk(TPACPI_DBG_INIT, + "trying to locate ACPI handle for %s, using HID %s\n", + name, hid); + + memset(&device_found, 0, sizeof(device_found)); + status = acpi_get_devices(hid, tpacpi_acpi_handle_locate_callback, + (void *)name, &device_found); + + *handle = NULL; + + if (ACPI_SUCCESS(status)) { + *handle = device_found; + dbg_printk(TPACPI_DBG_INIT, + "Found ACPI handle for %s\n", name); + } else { + vdbg_printk(TPACPI_DBG_INIT, + "Could not locate an ACPI handle for %s: %s\n", + name, acpi_format_exception(status)); + } +} + static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) { struct ibm_struct *ibm = data; @@ -8752,8 +8781,8 @@ static int __init probe_for_thinkpad(void) (thinkpad_id.ec_model != 0) || tpacpi_is_fw_known(); - /* ec is required because many other handles are relative to it */ - TPACPI_ACPIHANDLE_INIT(ec); + /* The EC handler is required */ + tpacpi_acpi_handle_locate("ec", TPACPI_ACPI_EC_HID, &ec_handle); if (!ec_handle) { if (is_thinkpad) printk(TPACPI_ERR -- cgit v1.2.3-70-g09d2 From 263f4a30e4f1dc5385650738c1dcf3728036ecc4 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:45 -0300 Subject: thinkpad-acpi: acpi_evalf fixes Use acpi_format_exception() in acpi_evalf() instead of logging numeric errors. Also, when ACPICA returns an error, we should not be touching the return object, as it is invalid. In debug mode, acpi_evalf() callers would printk the returned crap (but fortunately, not use it). Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 877a7802e83..da3a70b280f 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -605,9 +605,10 @@ static int acpi_evalf(acpi_handle handle, switch (res_type) { case 'd': /* int */ - if (res) + success = (status == AE_OK && + out_obj.type == ACPI_TYPE_INTEGER); + if (success && res) *(int *)res = out_obj.integer.value; - success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER; break; case 'v': /* void */ success = status == AE_OK; @@ -620,8 +621,8 @@ static int acpi_evalf(acpi_handle handle, } if (!success && !quiet) - printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", - method, fmt0, status); + printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %s\n", + method, fmt0, acpi_format_exception(status)); return success; } -- cgit v1.2.3-70-g09d2 From 72f19921217c2267adc65cbe69c63da970578a14 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:48 -0300 Subject: thinkpad-acpi: explain errors from acpi_install_notify_handler Log more human-friendly errors instead of numeric values when setup_acpi_notify() fails to install a notification handler. Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index da3a70b280f..a39f159d4f2 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -785,8 +785,8 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm) "handling %s events\n", ibm->name); } else { printk(TPACPI_ERR - "acpi_install_notify_handler(%s) failed: %d\n", - ibm->name, status); + "acpi_install_notify_handler(%s) failed: %s\n", + ibm->name, acpi_format_exception(status)); } return -ENODEV; } -- cgit v1.2.3-70-g09d2 From 2cbb5c8f5533facb606adc5986ce40da2e987d6d Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:50 -0300 Subject: thinkpad-acpi: don't depend on led_path for led firmware type (v2) Don't depend on the contents of led_path to know which LED interface the firmware wants. This removes the only user of *_path for the thinkpad-acpi ACPI handlers, which will simplify future code. Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 47 +++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 19 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a39f159d4f2..29ad2734644 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -5009,11 +5009,7 @@ enum { /* For TPACPI_LED_OLD */ static enum led_access_mode led_supported; -TPACPI_HANDLE(led, ec, "SLED", /* 570 */ - "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, */ - /* T20-22, X20-21 */ - "LED", /* all others */ - ); /* R30, R31 */ +static acpi_handle led_handle; #define TPACPI_LED_NUMLEDS 16 static struct tpacpi_led_classdev *tpacpi_leds; @@ -5273,6 +5269,32 @@ static const struct tpacpi_quirk led_useful_qtable[] __initconst = { #undef TPACPI_LEDQ_IBM #undef TPACPI_LEDQ_LNV +static enum led_access_mode __init led_init_detect_mode(void) +{ + acpi_status status; + + if (tpacpi_is_ibm()) { + /* 570 */ + status = acpi_get_handle(ec_handle, "SLED", &led_handle); + if (ACPI_SUCCESS(status)) + return TPACPI_LED_570; + + /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ + status = acpi_get_handle(ec_handle, "SYSL", &led_handle); + if (ACPI_SUCCESS(status)) + return TPACPI_LED_OLD; + } + + /* most others */ + status = acpi_get_handle(ec_handle, "LED", &led_handle); + if (ACPI_SUCCESS(status)) + return TPACPI_LED_NEW; + + /* R30, R31, and unknown firmwares */ + led_handle = NULL; + return TPACPI_LED_NONE; +} + static int __init led_init(struct ibm_init_struct *iibm) { unsigned int i; @@ -5281,20 +5303,7 @@ static int __init led_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); - TPACPI_ACPIHANDLE_INIT(led); - - if (!led_handle) - /* led not supported on R30, R31 */ - led_supported = TPACPI_LED_NONE; - else if (tpacpi_is_ibm() && strlencmp(led_path, "SLED") == 0) - /* 570 */ - led_supported = TPACPI_LED_570; - else if (tpacpi_is_ibm() && strlencmp(led_path, "SYSL") == 0) - /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ - led_supported = TPACPI_LED_OLD; - else - /* all others */ - led_supported = TPACPI_LED_NEW; + led_supported = led_init_detect_mode(); vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", str_supported(led_supported), led_supported); -- cgit v1.2.3-70-g09d2 From ef07a5abadfcb2470fc9cbfbee0cb41076b4ba9b Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:54 -0300 Subject: thinkpad-acpi: clean up ACPI handles handling 1. Remove _path, as its only user was already removed in a previous commit 2. Move all handle initialization, as well as _parent and _paths to __init.* sections. This reduces the driver's runtime footprint nicely. Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 29ad2734644..b3bfce95383 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -516,9 +516,9 @@ static acpi_handle ec_handle; #define TPACPI_HANDLE(object, parent, paths...) \ static acpi_handle object##_handle; \ - static acpi_handle *object##_parent = &parent##_handle; \ - static char *object##_path; \ - static char *object##_paths[] = { paths } + static const acpi_handle *object##_parent __initdata = \ + &parent##_handle; \ + static char *object##_paths[] __initdata = { paths } TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */ TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */ @@ -673,11 +673,11 @@ static int issue_thinkpad_cmos_command(int cmos_cmd) #define TPACPI_ACPIHANDLE_INIT(object) \ drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ - object##_paths, ARRAY_SIZE(object##_paths), &object##_path) + object##_paths, ARRAY_SIZE(object##_paths)) -static void drv_acpi_handle_init(char *name, - acpi_handle *handle, acpi_handle parent, - char **paths, int num_paths, char **path) +static void __init drv_acpi_handle_init(const char *name, + acpi_handle *handle, const acpi_handle parent, + char **paths, const int num_paths) { int i; acpi_status status; @@ -688,10 +688,9 @@ static void drv_acpi_handle_init(char *name, for (i = 0; i < num_paths; i++) { status = acpi_get_handle(parent, paths[i], handle); if (ACPI_SUCCESS(status)) { - *path = paths[i]; dbg_printk(TPACPI_DBG_INIT, "Found ACPI handle %s for %s\n", - *path, name); + paths[i], name); return; } } -- cgit v1.2.3-70-g09d2 From 7d9745cf239ca98cf1f694bff4765a276b05ee68 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sun, 16 May 2010 19:45:57 -0300 Subject: thinkpad-acpi: document backlight level writeback at driver init Document this, it is no fun to try to second guess why this sort of stuff is in place years after it was added... Signed-off-by: Henrique de Moraes Holschuh --- drivers/platform/x86/thinkpad_acpi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b3bfce95383..4bdb13796e2 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6397,6 +6397,10 @@ static int __init brightness_init(struct ibm_init_struct *iibm) "or not on your ThinkPad\n", TPACPI_MAIL); } + /* Added by mistake in early 2007. Probably useless, but it could + * be working around some unknown firmware problem where the value + * read at startup doesn't match the real hardware state... so leave + * it in place just in case */ backlight_update_status(ibm_backlight_device); vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, -- cgit v1.2.3-70-g09d2