1 From 32e3ffd1c4310efe205846ec125512a72357d499 Mon Sep 17 00:00:00 2001
2 From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
3 Date: Tue, 8 Jan 2008 02:56:15 -0200
4 Subject: ACPI: thinkpad-acpi: switch Lenovo BIOS to ACPI backlight mode
6 Lenovo ThinkPads with generic ACPI backlight level control can be easily
7 set to react to keyboard brightness key presses in a more predictable way
8 than what they do when in "DOS / bootloader" mode after Linux brings
11 The switch to the ACPI backlight mode in the firmware is designed to be
12 safe to use only as an one way trapdoor. One is not to force the firmware
13 to switch back to "DOS/bootloader" mode except by rebooting. The mode
14 switch itself is performed by calling any of the ACPI _BCL methods at least
17 When in ACPI mode, the backlight firmware just issues (standard) events for
18 the brightness up/down hot key presses, and doesn't touch the hardware.
19 thinkpad-acpi knows this, and will suppress issuing any backlight change
20 notifications in the default keymap to avoid double-reporting.
22 Thus, provided userspace is sane, all should work (and *keep* working),
23 which is more that can be said about the non-ACPI mode of the new Lenovo
24 ThinkPad BIOSes when coupled to current userspace and X.org drivers.
26 Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
28 drivers/misc/thinkpad_acpi.c | 123 +++++++++++++++++++++++-------------------
29 1 files changed, 67 insertions(+), 56 deletions(-)
31 REJECT REASON: we need an acpi notification handle on the video device
32 to get the ACPI events, at which point it is best to just tell the user
33 to use the new ACPI video driver anyway.
35 diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
36 index 7500c44..842aa07 100644
37 --- a/drivers/misc/thinkpad_acpi.c
38 +++ b/drivers/misc/thinkpad_acpi.c
39 @@ -225,6 +225,7 @@ static struct {
42 u32 bright_16levels:1;
43 + u32 bright_acpimode:1;
45 u32 fan_ctrl_status_undef:1;
46 u32 input_device_registered:1;
47 @@ -2065,6 +2066,21 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
48 TPACPI_HOTKEY_MAP_SIZE);
51 + /* Do not issue duplicate brightness change events to
53 + if (tp_features.bright_acpimode) {
54 + printk(TPACPI_NOTICE
55 + "Brightness hot keys firmware issues ACPI "
57 + printk(TPACPI_NOTICE
58 + "Disabling brightness hot keys on event "
60 + hotkey_keycode_map[TP_ACPI_HOTKEYSCAN_FNHOME] =
62 + hotkey_keycode_map[TP_ACPI_HOTKEYSCAN_FNEND] =
66 set_bit(EV_KEY, tpacpi_inputdev->evbit);
67 set_bit(EV_MSC, tpacpi_inputdev->evbit);
68 set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
69 @@ -4272,7 +4288,7 @@ static struct backlight_ops ibm_backlight_data = {
71 /* --------------------------------------------------------------------- */
73 -static int __init tpacpi_query_bcll_levels(acpi_handle handle)
74 +static int __init tpacpi_query_bcl_levels(acpi_handle handle)
76 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
77 union acpi_object *obj;
78 @@ -4281,7 +4297,7 @@ static int __init tpacpi_query_bcll_levels(acpi_handle handle)
79 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
80 obj = (union acpi_object *)buffer.pointer;
81 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
82 - printk(TPACPI_ERR "Unknown BCLL data, "
83 + printk(TPACPI_ERR "Unknown _BCL data, "
84 "please report this to %s\n", TPACPI_MAIL);
87 @@ -4295,44 +4311,6 @@ static int __init tpacpi_query_bcll_levels(acpi_handle handle)
91 -static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
92 - void *context, void **rv)
94 - char name[ACPI_PATH_SEGMENT_LENGTH];
95 - struct acpi_buffer buffer = { sizeof(name), &name };
97 - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
98 - !strncmp("BCLL", name, sizeof(name) - 1)) {
99 - if (tpacpi_query_bcll_levels(handle) == 16) {
101 - return AE_CTRL_TERMINATE;
110 -static int __init brightness_check_levels(void)
113 - void *found_node = NULL;
116 - TPACPI_ACPIHANDLE_INIT(vid);
121 - /* Search for a BCLL package with 16 levels */
122 - status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
123 - brightness_find_bcll, NULL,
126 - return (ACPI_SUCCESS(status) && found_node != NULL);
129 static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
130 void *context, void **rv)
132 @@ -4341,17 +4319,22 @@ static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
134 if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
135 !strncmp("_BCL", name, sizeof(name) - 1)) {
137 + BUG_ON(!rv || !*rv);
138 + **(int **)rv = tpacpi_query_bcl_levels(handle);
139 return AE_CTRL_TERMINATE;
146 + * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map
148 static int __init brightness_check_std_acpi_support(void)
151 - void *found_node = NULL;
152 + int bcl_levels = 0;
153 + void *bcl_ptr = &bcl_levels;
156 TPACPI_ACPIHANDLE_INIT(vid);
157 @@ -4359,11 +4342,21 @@ static int __init brightness_check_std_acpi_support(void)
161 - /* Search for a _BCL method, but don't execute it */
163 + * Search for a _BCL method, and execute it. This is safe on all
164 + * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista
165 + * BIOS in ACPI backlight control mode. We do NOT have to care
166 + * about calling the _BCL method in an enabled video device, any
167 + * will do for our purposes.
170 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
171 - brightness_find_bcl, NULL, &found_node);
172 + brightness_find_bcl, NULL, &bcl_ptr);
174 + if (ACPI_SUCCESS(status) && bcl_levels > 2)
175 + return (bcl_levels - 2);
177 - return (ACPI_SUCCESS(status) && found_node != NULL);
181 static int __init brightness_init(struct ibm_init_struct *iibm)
182 @@ -4374,13 +4367,19 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
184 mutex_init(&brightness_mutex);
186 - if (!brightness_enable) {
187 - dbg_printk(TPACPI_DBG_INIT,
188 - "brightness support disabled by "
189 - "module parameter\n");
191 - } else if (brightness_enable > 1) {
192 - if (brightness_check_std_acpi_support()) {
194 + * We always attempt to detect acpi support, so as to switch
195 + * Lenovo Vista BIOS to ACPI brightness mode even if we are not
196 + * going to publish a backlight interface
198 + b = brightness_check_std_acpi_support();
200 + if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
201 + printk(TPACPI_NOTICE
202 + "Lenovo BIOS switched to ACPI backlight "
205 + if (brightness_enable > 1) {
207 "standard ACPI backlight interface "
208 "available, not loading native one...\n");
209 @@ -4388,6 +4387,22 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
213 + if (!brightness_enable) {
214 + dbg_printk(TPACPI_DBG_INIT,
215 + "brightness support disabled by "
216 + "module parameter\n");
222 + "Unsupported brightness interface, "
223 + "please contact %s\n", TPACPI_MAIL);
227 + tp_features.bright_16levels = 1;
229 if (!brightness_mode) {
230 if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
232 @@ -4401,10 +4416,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
233 if (brightness_mode > 3)
236 - tp_features.bright_16levels =
237 - thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
238 - brightness_check_levels();
240 b = brightness_get(NULL);