[PATCH 2/8] ACPI: thinkpad-acpi: switch Lenovo BIOS to ACPI backlight mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Lenovo ThinkPads with generic ACPI backlight level control can be easily
set to react to keyboard brightness key presses in a more predictable way
than what they do when in "DOS / bootloader" mode after Linux brings
up the ACPI interface.

The switch to the ACPI backlight mode in the firmware is designed to be
safe to use only as an one way trapdoor.  One is not to force the firmware
to switch back to "DOS/bootloader" mode except by rebooting.  The mode
switch itself is performed by calling any of the ACPI _BCL methods at least
once.

When in ACPI mode, the backlight firmware just issues (standard) events for
the brightness up/down hot key presses, and doesn't touch the hardware.
thinkpad-acpi knows this, and will suppress issuing any backlight change
notifications in the default keymap to avoid double-reporting.

Thus, provided userspace is sane, all should work (and *keep* working),
which is more that can be said about the non-ACPI mode of the new Lenovo
ThinkPad BIOSes when coupled to current userspace and X.org drivers.

Signed-off-by: Henrique de Moraes Holschuh <hmh@xxxxxxxxxx>
---
 drivers/misc/thinkpad_acpi.c |  123 +++++++++++++++++++++++-------------------
 1 files changed, 67 insertions(+), 56 deletions(-)

diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 0d84b63..7c40802 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -224,6 +224,7 @@ static struct {
 	u32 light:1;
 	u32 light_status:1;
 	u32 bright_16levels:1;
+	u32 bright_acpimode:1;
 	u32 wan:1;
 	u32 fan_ctrl_status_undef:1;
 	u32 input_device_registered:1;
@@ -1993,6 +1994,21 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 				TPACPI_HOTKEY_MAP_SIZE);
 		}
 
+		/* Do not issue duplicate brightness change events to
+		 * userspace */
+		if (tp_features.bright_acpimode) {
+			printk(TPACPI_NOTICE
+			       "Brightness hot keys firmware issues ACPI "
+			       "video events\n");
+			printk(TPACPI_NOTICE
+			       "Disabling brightness hot keys on event "
+			       "device keymap\n");
+			hotkey_keycode_map[TP_ACPI_HOTKEYSCAN_FNHOME] =
+								KEY_RESERVED;
+			hotkey_keycode_map[TP_ACPI_HOTKEYSCAN_FNEND] =
+								KEY_RESERVED;
+		}
+
 		set_bit(EV_KEY, tpacpi_inputdev->evbit);
 		set_bit(EV_MSC, tpacpi_inputdev->evbit);
 		set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
@@ -4193,7 +4209,7 @@ static struct backlight_ops ibm_backlight_data = {
 
 /* --------------------------------------------------------------------- */
 
-static int __init tpacpi_query_bcll_levels(acpi_handle handle)
+static int __init tpacpi_query_bcl_levels(acpi_handle handle)
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *obj;
@@ -4202,7 +4218,7 @@ static int __init tpacpi_query_bcll_levels(acpi_handle handle)
 	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 BCLL data, "
+			printk(TPACPI_ERR "Unknown _BCL data, "
 			       "please report this to %s\n", TPACPI_MAIL);
 			rc = 0;
 		} else {
@@ -4216,44 +4232,6 @@ static int __init tpacpi_query_bcll_levels(acpi_handle handle)
 	return rc;
 }
 
-static acpi_status __init brightness_find_bcll(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("BCLL", name, sizeof(name) - 1)) {
-		if (tpacpi_query_bcll_levels(handle) == 16) {
-			*rv = handle;
-			return AE_CTRL_TERMINATE;
-		} else {
-			return AE_OK;
-		}
-	} else {
-		return AE_OK;
-	}
-}
-
-static int __init brightness_check_levels(void)
-{
-	int status;
-	void *found_node = NULL;
-
-	if (!vid_handle) {
-		TPACPI_ACPIHANDLE_INIT(vid);
-	}
-	if (!vid_handle)
-		return 0;
-
-	/* Search for a BCLL package with 16 levels */
-	status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
-					brightness_find_bcll, NULL,
-					&found_node);
-
-	return (ACPI_SUCCESS(status) && found_node != NULL);
-}
-
 static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
 					void *context, void **rv)
 {
@@ -4262,17 +4240,22 @@ static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
 
 	if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
 	    !strncmp("_BCL", name, sizeof(name) - 1)) {
-		*rv = handle;
+		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 brightness_check_std_acpi_support(void)
 {
 	int status;
-	void *found_node = NULL;
+	int bcl_levels = 0;
+	void *bcl_ptr = &bcl_levels;
 
 	if (!vid_handle) {
 		TPACPI_ACPIHANDLE_INIT(vid);
@@ -4280,11 +4263,21 @@ static int __init brightness_check_std_acpi_support(void)
 	if (!vid_handle)
 		return 0;
 
-	/* Search for a _BCL method, but don't execute it */
+	/*
+	 * 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,
-				     brightness_find_bcl, NULL, &found_node);
+				     brightness_find_bcl, NULL, &bcl_ptr);
+
+	if (ACPI_SUCCESS(status) && bcl_levels > 2)
+		return (bcl_levels - 2);
 
-	return (ACPI_SUCCESS(status) && found_node != NULL);
+	return 0;
 }
 
 static int __init brightness_init(struct ibm_init_struct *iibm)
@@ -4295,13 +4288,19 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 
 	mutex_init(&brightness_mutex);
 
-	if (!brightness_enable) {
-		dbg_printk(TPACPI_DBG_INIT,
-			   "brightness support disabled by "
-			   "module parameter\n");
-		return 1;
-	} else if (brightness_enable > 1) {
-		if (brightness_check_std_acpi_support()) {
+	/*
+	 * 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 = brightness_check_std_acpi_support();
+	if (b > 0) {
+		if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+			printk(TPACPI_NOTICE
+			       "Lenovo BIOS switched to ACPI backlight "
+			       "control mode\n");
+		}
+		if (brightness_enable > 1) {
 			printk(TPACPI_NOTICE
 			       "standard ACPI backlight interface "
 			       "available, not loading native one...\n");
@@ -4309,6 +4308,22 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 		}
 	}
 
+	if (!brightness_enable) {
+		dbg_printk(TPACPI_DBG_INIT,
+			   "brightness support disabled by "
+			   "module parameter\n");
+		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;
+
 	if (!brightness_mode) {
 		if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
 			brightness_mode = 2;
@@ -4322,10 +4337,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 	if (brightness_mode > 3)
 		return -EINVAL;
 
-	tp_features.bright_16levels =
-			thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
-			brightness_check_levels();
-
 	b = brightness_get(NULL);
 	if (b < 0)
 		return 1;
-- 
1.5.3.8


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
ibm-acpi-devel mailing list
ibm-acpi-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/ibm-acpi-devel

[Index of Archives]     [Linux ACPI]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Photo]     [Yosemite Photos]     [Yosemite Advice]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]

  Powered by Linux