public inbox for linux-acpi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/2] asus-laptop add kill switch support
@ 2008-01-16 15:57 Corentin CHARY
       [not found] ` <200801161657.50967.corentincj-EjuBZuxMvz2sTnJN9+BGXg@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Corentin CHARY @ 2008-01-16 15:57 UTC (permalink / raw)
  To: Len Brown, acpi4asus-user, linux-acpi; +Cc: Fabien Crespel

From: Corentin CHARY <corentincj@iksaif.net>

Note: All this work have been done by Fabien Crespel and the original
      patch was from him. Thks again ;).

The latest asus-laptop driver (version 0.42 from kernel version
2.6.22.13) is missing support for the "Kill Switch" of some laptops.
When you turn the Kill Switch ON, the LEDs are still on, while they should 
turn off and come back only when I turn the switch OFF again.

Basically:
- there is now a killswitch file in /sys/devices/platform/asus-laptop/
to report the KS status (read from HWRS)
- when the KS is turned ON, the LEDs are turned OFF, when it's turned
OFF, the previous status is restored
- when the KS is ON, the WLAN and BT status is read from and written to
the INTERNAL driver status (hotk->status) only, to avoid re-enabling the
LEDs. This is also useful to read the "previous status" of WLAN and BT,
and possibly to change it before disabling the Kill Switch. For example,
if WLAN is ON when I turn the KS ON, I can decide to turn it OFF and
enable BT only by writing into the corresponding sysfs files. Then I
turn the KS OFF, and only BT turns on :p
- during driver initialization, instead of always turning WLAN and BT
ON, the current status is read with read_wireless_status and written
immediately. This means that for the first initialization, the previous
status is restored (for example if I had WLAN ON / BT OFF in Windows, it
will be restored when Linux boots).

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 asus-laptop.c |  212 ++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 176 insertions(+), 36 deletions(-)

--- a/drivers/misc/asus-laptop.c	2008-01-15 23:22:19.000000000 +0100
+++ b/drivers/misc/asus-laptop.c	2008-01-15 23:23:00.000000000 +0100
@@ -31,6 +31,7 @@
  *  Josh Green     - Light Sens support
  *  Thomas Tuttle  - His first patch for led support was very helpfull
  *  Sam Lin        - GPS support
+ *  Fabien Crespel - Kill Switch support
  */
 
 #include <linux/autoconf.h>
@@ -59,16 +60,25 @@
 /*
  * Some events we use, same for all Asus
  */
-#define ATKD_BR_UP       0x10
-#define ATKD_BR_DOWN     0x20
-#define ATKD_LCD_ON      0x33
-#define ATKD_LCD_OFF     0x34
+#define ATKD_BR_UP       0x10	// Brightness Up base value
+#define ATKD_BR_DOWN     0x20	// Brightness Down base value
+#define ATKD_LCD_ON      0x33	// LCD Display ON
+#define ATKD_LCD_OFF     0x34	// LCD Display OFF
+#define ATKD_WL_TOGGLE   0x5D	// WLAN Toggle
+#define ATKD_WL_ON       0x5E	// WLAN ON notification
+#define ATKD_WL_OFF      0x5F	// WLAN OFF notification
+#define ATKD_BT_ON       0x7D	// Bluetooth ON notification
+#define ATKD_BT_OFF      0x7E	// Bluetooth OFF notification
+#define ATKD_KS_ON       0x81	// Kill Switch ON
+#define ATKD_KS_OFF      0x80	// Kill Switch OFF
 
 /*
  * Known bits returned by \_SB.ATKD.HWRS
  */
-#define WL_HWRS     0x80
-#define BT_HWRS     0x100
+#define RF_HWRS     0x01	// Radio Frequency enabled
+#define KS_HWRS     0x02	// Kill Switch present
+#define WL_HWRS     0x80	// Wifi adapter present
+#define BT_HWRS     0x100	// Bluetooth adapter present
 
 /*
  * Flags for hotk status
@@ -95,14 +105,23 @@
 MODULE_DESCRIPTION(ASUS_HOTK_NAME);
 MODULE_LICENSE("GPL");
 
-/* WAPF defines the behavior of the Fn+Fx wlan key
- * The significance of values is yet to be found, but
- * most of the time:
- * 0x0 will do nothing
+/* WAPF defines the behavior of the Fn+Fx wireless switch key.
+ * The significance of values is yet to be found, but most of the time:
+ *
+ * 0x0 will do nothing or give all control to hardware.
+ *
  * 0x1 will allow to control the device with Fn+Fx key.
+ *     When a Kill Switch is used, hardware will handle the Bluetooth device.
+ *     For both, software intervention might be needed to handle WLAN correctly.
+ *
  * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key
- * 0x5 like 0x1 or 0x4
+ *     and when the Kill Switch is toggled (0x80 and 0x81).
+ *     This is a software-only mode, this driver only handles the Kill Switch.
+ * 
+ * 0x5 like 0x1 or 0x4, but on most models 0x4 has the priority.
+ *
  * So, if something doesn't work as you want, just try other values =)
+ * Note that some models (like F3JC) are only meant to be used with 0x4.
  */
 static uint wapf = 1;
 module_param(wapf, uint, 0644);
@@ -129,6 +148,7 @@
 ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED");
 ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED");
 ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS");	/* All new models */
+ASUS_HANDLE(hwrs, ASUS_HOTK_PREFIX "HWRS"); /* Hardware information */
 
 /* Brightness */
 ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV");
@@ -176,7 +196,7 @@
 	char *name;		//laptop name
 	struct acpi_device *device;	//the device we are in
 	acpi_handle handle;	//the handle of the hotk device
-	char status;		//status of the hotk, for LEDs, ...
+	u16 status;		//status of the hotk, for LEDs, ...
 	u32 ledd_status;	//status of the LED display
 	u8 light_level;		//light sensor level
 	u8 light_switch;	//light sensor switch value
@@ -310,14 +330,47 @@
 	return (hotk->status & GPS_ON) ? 1 : 0;
 }
 
-/* Generic LED functions */
+/*
+ * The HWRS method returns information about the hardware.
+ * 0x80 bit is for WLAN, 0x100 for Bluetooth.
+ * 0x02 means there is a physical Kill Switch on the laptop.
+ * When it is present, 0x01 means Radio Frequency is ON (i.e. KS is OFF)
+ * The significance of others is yet to be found.
+ * If we don't find the method, we assume WLAN and BT are present.
+ * -- Note: 0x400 seems to always come with 0x02 ..?
+ */
+static int read_hwrs(void)
+{
+	ulong status;
+	acpi_status rv = AE_OK;
+	
+	if (!hwrs_handle)
+		return WL_HWRS | BT_HWRS;
+
+	rv = acpi_evaluate_integer(hwrs_handle, NULL, NULL, &status);
+	if (ACPI_FAILURE(rv)) {
+		printk(ASUS_WARNING "Error reading HWRS\n");
+		return WL_HWRS | BT_HWRS;
+	}
+	
+	return status;
+}
+
+static int read_killswitch_status(void)
+{
+	ulong status = read_hwrs();
+	return (status & KS_HWRS && !(status & RF_HWRS));
+}
+
+/* Generic status handling functions (for LEDs and other features) */
 static int read_status(int mask)
 {
-	/* There is a special method for both wireless devices */
-	if (mask == BT_ON || mask == WL_ON)
-		return read_wireless_status(mask);
-	else if (mask == GPS_ON)
-		return read_gps_status();
+	/* There is a special method for both wireless devices + GPS */
+	/* When a Kill Switch is ON, read internal value (= previous status) */
+	if ((mask == BT_ON || mask == WL_ON) && !read_killswitch_status())
+ 		return read_wireless_status(mask);
+ 	else if (mask == GPS_ON)
+ 		return read_gps_status();
 
 	return (hotk->status & mask) ? 1 : 0;
 }
@@ -327,6 +380,11 @@
 	hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
 
 	switch (mask) {
+	case WL_ON:
+	case BT_ON:
+		/* Don't change the LED if the Kill Switch is ON */
+		if (handle && read_killswitch_status()) return;
+		break;
 	case MLED_ON:
 		out = !out & 0x1;
 		break;
@@ -719,7 +777,19 @@
 {
 	return store_status(buf, count, NULL, GPS_ON);
 }
+ 
+/*
+ * Kill Switch
+ */
+static ssize_t show_killswitch(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", read_killswitch_status());
+}
 
+/*
+ * Notify Handler
+ */
 static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
 {
 	/* TODO Find a better way to handle events count. */
@@ -737,9 +807,78 @@
 		write_status(NULL, 0, LCD_ON);
 		lcd_blank(FB_BLANK_POWERDOWN);
 	}
+	
+	/*
+	 * Kill Switch ON/OFF events
+	 *
+	 * Enable/disable WLAN and BT depending on Kill Switch status.
+	 * Only works with models that send 0x80 and 0x81 when KS is changed.
+	 * Some models only send this event with WAPF = 0x04.
+	 */
+	if (event == ATKD_KS_ON) {
+
+		if (write_acpi_int(wl_switch_handle, NULL, 0, NULL))
+			printk(ASUS_WARNING "KS ON: failed to disable WLAN\n");
+
+		if (write_acpi_int(bt_switch_handle, NULL, 0, NULL))
+			printk(ASUS_WARNING "KS ON: failed to disable BT\n");
+
+	} else if (event == ATKD_KS_OFF) {
+		int status;
 
+		status = hotk->status & WL_ON ? 1 : 0;
+		if (write_acpi_int(wl_switch_handle, NULL, status, NULL))
+			printk(ASUS_WARNING "KS OFF: failed to restore WLAN\n");
+
+		status = hotk->status & BT_ON ? 1 : 0;
+		if (write_acpi_int(bt_switch_handle, NULL, status, NULL))
+			printk(ASUS_WARNING "KS OFF: failed to restore BT\n");
+	}
+	
+	/*
+	 * WLAN Toggle event
+	 *
+	 * Toggle the WLAN status & LED.
+	 * This may be sent by the Fn+Fx key, or by the Kill Switch.
+	 * It must ALWAYS set the LED, even if the KS is ON.
+	 * Should only happen with WAPF = 0x01
+	 */
+	if (event == ATKD_WL_TOGGLE && wl_switch_handle) {
+		int status;
+		int mask = 0;
+
+		status = read_wireless_status(WL_ON) ? 0 : 1;
+		if (!read_killswitch_status())
+			mask = WL_ON;
+		/* 
+		 * If KS is ON, only toggle the LED
+		 * else Toggle both the LED and internal status
+		 */
+		write_status(wl_switch_handle, status, mask);
+	}
+	
+	/*
+	 * WLAN and BT status events
+	 *
+	 * These events are only sent for notification and information purposes.
+	 * The hardware should have updated the LEDs on its own.
+	 * Here we use them to update the internal status, so that we always
+	 * have an accurate 'previous status' to report through sysfs files
+	 * when the Kill Switch is ON.
+	 * Should only happen with WAPF = 0x01 or 0x00
+	 */
+	if (!read_killswitch_status()) {
+		if (event == ATKD_WL_ON)
+			write_status(NULL, 1, WL_ON);
+		else if (event == ATKD_WL_OFF)
+			write_status(NULL, 0, WL_ON);
+		else if (event == ATKD_BT_ON)
+			write_status(NULL, 1, BT_ON);
+		else if (event == ATKD_BT_OFF)
+			write_status(NULL, 0, BT_ON);
+	}
 	acpi_bus_generate_proc_event(hotk->device, event,
-				hotk->event_count[event % 128]++);
+				     hotk->event_count[event % 128]++);
 
 	return;
 }
@@ -768,6 +907,7 @@
 static ASUS_CREATE_DEVICE_ATTR(ls_switch);
 static ASUS_CREATE_DEVICE_ATTR(ls_level);
 static ASUS_CREATE_DEVICE_ATTR(gps);
+static ASUS_CREATE_DEVICE_ATTR(killswitch);
 
 static struct attribute *asuspf_attributes[] = {
 	&dev_attr_infos.attr,
@@ -778,6 +918,7 @@
 	&dev_attr_ls_switch.attr,
 	&dev_attr_ls_level.attr,
 	&dev_attr_gps.attr,
+ 	&dev_attr_killswitch.attr,
 	NULL
 };
 
@@ -820,6 +961,9 @@
 
 	if (gps_status_handle && gps_on_handle && gps_off_handle)
 		ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps);
+
+	if (read_hwrs() & KS_HWRS)
+		ASUS_SET_DEVICE_ATTR(killswitch, 0444, show_killswitch, NULL);
 }
 
 static int asus_handle_init(char *name, acpi_handle * handle,
@@ -919,16 +1063,8 @@
 
 	ASUS_HANDLE_INIT(ledd_set);
 
-	/*
-	 * The HWRS method return informations about the hardware.
-	 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
-	 * The significance of others is yet to be found.
-	 * If we don't find the method, we assume the device are present.
-	 */
-	status =
-	    acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result);
-	if (ACPI_FAILURE(status))
-		hwrs_result = WL_HWRS | BT_HWRS;
+	ASUS_HANDLE_INIT(hwrs);
+	hwrs_result = read_hwrs();
 
 	if (hwrs_result & WL_HWRS)
 		ASUS_HANDLE_INIT(wl_switch);
@@ -1017,13 +1153,17 @@
 
 	asus_hotk_found = 1;
 
-	/* WLED and BLED are on by default */
-	write_status(bt_switch_handle, 1, BT_ON);
-	write_status(wl_switch_handle, 1, WL_ON);
-
-	/* If the h/w switch is off, we need to check the real status */
-	write_status(NULL, read_status(BT_ON), BT_ON);
-	write_status(NULL, read_status(WL_ON), WL_ON);
+	/* Initialize WLAN and Bluetooth with current hardware value */
+	write_status(bt_switch_handle, read_wireless_status(BT_ON), BT_ON);
+	write_status(wl_switch_handle, read_wireless_status(WL_ON), WL_ON);
+	
+	/* Make sure to turn off the LEDs if Kill Switch is ON */
+	if (read_killswitch_status()) {
+		if (write_acpi_int(wl_switch_handle, NULL, 0, NULL))
+			printk(ASUS_WARNING "KS ON: failed to disable WLAN\n");
+		if (write_acpi_int(bt_switch_handle, NULL, 0, NULL))
+			printk(ASUS_WARNING "KS ON: failed to disable BT\n");
+	}
 
 	/* LCD Backlight is on by default */
 	write_status(NULL, 1, LCD_ON);

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] asus-laptop add kill switch support
       [not found] ` <200801161657.50967.corentincj-EjuBZuxMvz2sTnJN9+BGXg@public.gmane.org>
@ 2008-01-17 10:52   ` Len Brown
  2008-01-17 11:15     ` Corentin CHARY
  2008-02-07  5:40   ` Len Brown
  1 sibling, 1 reply; 7+ messages in thread
From: Len Brown @ 2008-01-17 10:52 UTC (permalink / raw)
  To: corentincj-EjuBZuxMvz2sTnJN9+BGXg
  Cc: linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	acpi4asus-user-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Wednesday 16 January 2008 10:57, Corentin CHARY wrote:
> From: Corentin CHARY <corentincj-EjuBZuxMvz2sTnJN9+BGXg@public.gmane.org>
> 
> Note: All this work have been done by Fabien Crespel and the original
>       patch was from him. Thks again ;).

Then the "From:" line above should have Fabien's e-mail address --
as the original author, and Fabien should be the 1st Sign-off below.
You should be the 2nd Sign-off, as the patch passed through
you (with or without modification).

I can do this edit for you, of course, but need to hear
from you that you agree; since otherwise it would defeat
the entire concept of the signed-off-by certification.

thanks,
-Len

> 
> Signed-off-by: Corentin Chary <corentincj-EjuBZuxMvz2sTnJN9+BGXg@public.gmane.org>

-------------------------------------------------------------------------
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/

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] asus-laptop add kill switch support
  2008-01-17 10:52   ` Len Brown
@ 2008-01-17 11:15     ` Corentin CHARY
  0 siblings, 0 replies; 7+ messages in thread
From: Corentin CHARY @ 2008-01-17 11:15 UTC (permalink / raw)
  To: Len Brown; +Cc: acpi4asus-user, linux-acpi, Fabien Crespel

On Thursday 17 January 2008 11:52:23 Len Brown wrote:
> On Wednesday 16 January 2008 10:57, Corentin CHARY wrote:
> > From: Corentin CHARY <corentincj@iksaif.net>
> >
> > Note: All this work have been done by Fabien Crespel and the original
> >       patch was from him. Thks again ;).
>
> Then the "From:" line above should have Fabien's e-mail address --
> as the original author, and Fabien should be the 1st Sign-off below.
> You should be the 2nd Sign-off, as the patch passed through
> you (with or without modification).
>
> I can do this edit for you, of course, but need to hear
> from you that you agree; since otherwise it would defeat
> the entire concept of the signed-off-by certification.
>
> thanks,
> -Len
>
> > Signed-off-by: Corentin Chary <corentincj@iksaif.net>

Oups ... sorry.
Of course you can edit ;)

-- 
Corentin 'Iksaif' CHARY
http://xf.iksaif.net

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] asus-laptop add kill switch support
       [not found] ` <200801161657.50967.corentincj-EjuBZuxMvz2sTnJN9+BGXg@public.gmane.org>
  2008-01-17 10:52   ` Len Brown
@ 2008-02-07  5:40   ` Len Brown
  2008-02-07 18:06     ` Fabien Crespel
  1 sibling, 1 reply; 7+ messages in thread
From: Len Brown @ 2008-02-07  5:40 UTC (permalink / raw)
  To: corentincj-EjuBZuxMvz2sTnJN9+BGXg
  Cc: linux-acpi-u79uwXL29TY76Z2rM5mHXA, Fabien Crespel,
	acpi4asus-user-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

scripts/checkpatch.pl
ERROR: do not use C99 // comments
#101: FILE: drivers/misc/asus-laptop.c:63:
+#define ATKD_BR_UP       0x10  // Brightness Up base value

ERROR: do not use C99 // comments
#102: FILE: drivers/misc/asus-laptop.c:64:
+#define ATKD_BR_DOWN     0x20  // Brightness Down base value

ERROR: do not use C99 // comments
#103: FILE: drivers/misc/asus-laptop.c:65:
+#define ATKD_LCD_ON      0x33  // LCD Display ON

ERROR: do not use C99 // comments
#104: FILE: drivers/misc/asus-laptop.c:66:
+#define ATKD_LCD_OFF     0x34  // LCD Display OFF

ERROR: do not use C99 // comments
#105: FILE: drivers/misc/asus-laptop.c:67:
+#define ATKD_WL_TOGGLE   0x5D  // WLAN Toggle

ERROR: do not use C99 // comments
#106: FILE: drivers/misc/asus-laptop.c:68:
+#define ATKD_WL_ON       0x5E  // WLAN ON notification

ERROR: do not use C99 // comments
#107: FILE: drivers/misc/asus-laptop.c:69:
+#define ATKD_WL_OFF      0x5F  // WLAN OFF notification

ERROR: do not use C99 // comments
#108: FILE: drivers/misc/asus-laptop.c:70:
+#define ATKD_BT_ON       0x7D  // Bluetooth ON notification

ERROR: do not use C99 // comments
#109: FILE: drivers/misc/asus-laptop.c:71:
+#define ATKD_BT_OFF      0x7E  // Bluetooth OFF notification

ERROR: do not use C99 // comments
#110: FILE: drivers/misc/asus-laptop.c:72:
+#define ATKD_KS_ON       0x81  // Kill Switch ON

ERROR: do not use C99 // comments
#111: FILE: drivers/misc/asus-laptop.c:73:
+#define ATKD_KS_OFF      0x80  // Kill Switch OFF

ERROR: do not use C99 // comments
#118: FILE: drivers/misc/asus-laptop.c:78:
+#define RF_HWRS     0x01       // Radio Frequency enabled

ERROR: do not use C99 // comments
#119: FILE: drivers/misc/asus-laptop.c:79:
+#define KS_HWRS     0x02       // Kill Switch present

ERROR: do not use C99 // comments
#120: FILE: drivers/misc/asus-laptop.c:80:
+#define WL_HWRS     0x80       // Wifi adapter present

ERROR: do not use C99 // comments
#121: FILE: drivers/misc/asus-laptop.c:81:
+#define BT_HWRS     0x100      // Bluetooth adapter present

ERROR: trailing whitespace
#146: FILE: drivers/misc/asus-laptop.c:120:
+ * $

ERROR: do not use C99 // comments
#167: FILE: drivers/misc/asus-laptop.c:199:
+       u16 status;             //status of the hotk, for LEDs, ...

ERROR: trailing whitespace
#189: FILE: drivers/misc/asus-laptop.c:346:
+^I$

ERROR: trailing whitespace
#198: FILE: drivers/misc/asus-laptop.c:355:
+^I$

ERROR: use tabs not spaces
#219: FILE: drivers/misc/asus-laptop.c:371:
+ ^I^Ireturn read_wireless_status(mask);$

ERROR: use tabs not spaces
#220: FILE: drivers/misc/asus-laptop.c:372:
+ ^Ielse if (mask == GPS_ON)$

ERROR: use tabs not spaces
#221: FILE: drivers/misc/asus-laptop.c:373:
+ ^I^Ireturn read_gps_status();$

ERROR: trailing statements should be on next line
#232: FILE: drivers/misc/asus-laptop.c:386:
+               if (handle && read_killswitch_status()) return;

ERROR: trailing whitespace
#241: FILE: drivers/misc/asus-laptop.c:780:
+ $

ERROR: trailing whitespace
#261: FILE: drivers/misc/asus-laptop.c:810:
+^I$

ERROR: trailing whitespace
#288: FILE: drivers/misc/asus-laptop.c:837:
+^I$

ERROR: trailing whitespace
#304: FILE: drivers/misc/asus-laptop.c:853:
+^I^I/* $

ERROR: trailing whitespace
#310: FILE: drivers/misc/asus-laptop.c:859:
+^I$

ERROR: use tabs not spaces
#349: FILE: drivers/misc/asus-laptop.c:921:
+ ^I&dev_attr_killswitch.attr,$

ERROR: trailing whitespace
#396: FILE: drivers/misc/asus-laptop.c:1159:
+^I$

total: 30 errors, 0 warnings, 308 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
On Wednesday 16 January 2008 10:57, Corentin CHARY wrote:

-------------------------------------------------------------------------
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/

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] asus-laptop add kill switch support
  2008-02-07  5:40   ` Len Brown
@ 2008-02-07 18:06     ` Fabien Crespel
       [not found]       ` <1203349001.6019.85.camel@queen.suse.de>
  0 siblings, 1 reply; 7+ messages in thread
From: Fabien Crespel @ 2008-02-07 18:06 UTC (permalink / raw)
  To: Len Brown
  Cc: public-corentincj-EjuBZuxMvz2sTnJN9+BGXg,
	public-linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	public-acpi4asus-user-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f




Len Brown wrote :
 > Your patch has style problems, please review.  If any of these errors
 > are false positives report them to the maintainer, see
 > CHECKPATCH in MAINTAINERS.

Sorry about that, it was my first patch ;)
This should now be fixed, here is the updated patch. I also updated the 
description a bit.

Please also note the rest of asus-laptop.c also needs some cleaning up, there are 
still many C99-style comments, for instance.

- Fabien Crespel.

---

From: Fabien Crespel <fabien@crespel.net>

This patch adds support for the "Kill Switch" of some laptops. Previously, when 
you turned the Kill Switch ON, the LEDs were still on, while they should turn off 
and come back only when you turn the switch OFF again.

Basically:
- there is now a killswitch file in /sys/devices/platform/asus-laptop/ to report 
the KS status (read from HWRS)
- when the KS is turned ON, the LEDs are turned OFF, when it's turned OFF, the 
previous status is restored
- when the KS is ON, the WLAN and BT status is read from and written to the 
INTERNAL driver status (hotk->status) only, to avoid re-enabling the LEDs. This 
is also useful to read the "previous status" of WLAN and BT, and possibly to 
change it before disabling the Kill Switch. For example, if WLAN is ON when you 
turn the KS ON, you can decide to turn it OFF and enable BT only by writing into 
the corresponding sysfs files. Then, when you turn the KS OFF, only BT turns on
- during driver initialization, instead of always turning WLAN and BT ON, the 
current status is read with read_wireless_status and written immediately. This 
means that for the first initialization, the previous status is restored (for 
example if you had WLAN ON / BT OFF in Windows, it will be restored when Linux 
boots).

Signed-off-by: Fabien Crespel <fabien@crespel.net>
---
asus-laptop.c |  207 ++++++++++++++++++++++++++++++++++++++++++++++++----------
  1 file changed, 174 insertions(+), 33 deletions(-)

--- a/drivers/misc/asus-laptop.c	2008-02-07 17:19:41.000000000 +0100
+++ b/drivers/misc/asus-laptop.c	2008-02-07 17:40:47.000000000 +0100
@@ -31,6 +31,7 @@
   *  Josh Green     - Light Sens support
   *  Thomas Tuttle  - His first patch for led support was very helpfull
   *  Sam Lin        - GPS support
+ *  Fabien Crespel - Kill Switch support
   */

  #include <linux/kernel.h>
@@ -58,16 +59,25 @@
  /*
   * Some events we use, same for all Asus
   */
-#define ATKD_BR_UP       0x10
-#define ATKD_BR_DOWN     0x20
-#define ATKD_LCD_ON      0x33
-#define ATKD_LCD_OFF     0x34
+#define ATKD_BR_UP       0x10	/* Brightness Up base value */
+#define ATKD_BR_DOWN     0x20	/* Brightness Down base value */
+#define ATKD_LCD_ON      0x33	/* LCD Display ON */
+#define ATKD_LCD_OFF     0x34	/* LCD Display OFF */
+#define ATKD_WL_TOGGLE   0x5D	/* WLAN Toggle */
+#define ATKD_WL_ON       0x5E	/* WLAN ON notification */
+#define ATKD_WL_OFF      0x5F	/* WLAN OFF notification */
+#define ATKD_BT_ON       0x7D	/* Bluetooth ON notification */
+#define ATKD_BT_OFF      0x7E	/* Bluetooth OFF notification */
+#define ATKD_KS_ON       0x81	/* Kill Switch ON */
+#define ATKD_KS_OFF      0x80	/* Kill Switch OFF */

  /*
   * Known bits returned by \_SB.ATKD.HWRS
   */
-#define WL_HWRS     0x80
-#define BT_HWRS     0x100
+#define RF_HWRS     0x01	/* Radio Frequency enabled */
+#define KS_HWRS     0x02	/* Kill Switch present */
+#define WL_HWRS     0x80	/* Wifi adapter present */
+#define BT_HWRS     0x100	/* Bluetooth adapter present */

  /*
   * Flags for hotk status
@@ -94,14 +104,23 @@ MODULE_AUTHOR("Julien Lerouge, Karol Koz
  MODULE_DESCRIPTION(ASUS_HOTK_NAME);
  MODULE_LICENSE("GPL");

-/* WAPF defines the behavior of the Fn+Fx wlan key
- * The significance of values is yet to be found, but
- * most of the time:
- * 0x0 will do nothing
+/* WAPF defines the behavior of the Fn+Fx wireless switch key.
+ * The significance of values is yet to be found, but most of the time:
+ *
+ * 0x0 will do nothing or give all control to hardware.
+ *
   * 0x1 will allow to control the device with Fn+Fx key.
+ *     When a Kill Switch is used, hardware will handle the Bluetooth device.
+ *     For both, software intervention might be needed to handle WLAN correctly.
+ *
   * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key
- * 0x5 like 0x1 or 0x4
+ *     and when the Kill Switch is toggled (0x80 and 0x81).
+ *     This is a software-only mode, this driver only handles the Kill Switch.
+ *
+ * 0x5 like 0x1 or 0x4, but on most models 0x4 has the priority.
+ *
   * So, if something doesn't work as you want, just try other values =)
+ * Note that some models (like F3JC) are only meant to be used with 0x4.
   */
  static uint wapf = 1;
  module_param(wapf, uint, 0644);
@@ -128,6 +147,7 @@ ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "
  ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED");
  ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED");
  ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS");	/* All new models */
+ASUS_HANDLE(hwrs, ASUS_HOTK_PREFIX "HWRS"); /* Hardware information */

  /* Brightness */
  ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV");
@@ -175,7 +195,7 @@ struct asus_hotk {
  	char *name;		//laptop name
  	struct acpi_device *device;	//the device we are in
  	acpi_handle handle;	//the handle of the hotk device
-	char status;		//status of the hotk, for LEDs, ...
+	u16 status;		/* Status of the hotk, for LEDs, ... */
  	u32 ledd_status;	//status of the LED display
  	u8 light_level;		//light sensor level
  	u8 light_switch;	//light sensor switch value
@@ -309,11 +329,44 @@ static int read_gps_status(void)
  	return (hotk->status & GPS_ON) ? 1 : 0;
  }

-/* Generic LED functions */
+/*
+ * The HWRS method returns information about the hardware.
+ * 0x80 bit is for WLAN, 0x100 for Bluetooth.
+ * 0x02 means there is a physical Kill Switch on the laptop.
+ * When it is present, 0x01 means Radio Frequency is ON (i.e. KS is OFF)
+ * The significance of others is yet to be found.
+ * If we don't find the method, we assume WLAN and BT are present.
+ * -- Note: 0x400 seems to always come with 0x02 ..?
+ */
+static int read_hwrs(void)
+{
+	ulong status;
+	acpi_status rv = AE_OK;
+
+	if (!hwrs_handle)
+		return WL_HWRS | BT_HWRS;
+
+	rv = acpi_evaluate_integer(hwrs_handle, NULL, NULL, &status);
+	if (ACPI_FAILURE(rv)) {
+		printk(ASUS_WARNING "Error reading HWRS\n");
+		return WL_HWRS | BT_HWRS;
+	}
+
+	return status;
+}
+
+static int read_killswitch_status(void)
+{
+	ulong status = read_hwrs();
+	return (status & KS_HWRS && !(status & RF_HWRS));
+}
+
+/* Generic status handling functions (for LEDs and other features) */
  static int read_status(int mask)
  {
-	/* There is a special method for both wireless devices */
-	if (mask == BT_ON || mask == WL_ON)
+	/* There is a special method for both wireless devices + GPS */
+	/* When a Kill Switch is ON, read internal value (= previous status) */
+	if ((mask == BT_ON || mask == WL_ON) && !read_killswitch_status())
  		return read_wireless_status(mask);
  	else if (mask == GPS_ON)
  		return read_gps_status();
@@ -326,6 +379,12 @@ static void write_status(acpi_handle han
  	hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);

  	switch (mask) {
+	case WL_ON:
+	case BT_ON:
+		/* Don't change the LED if the Kill Switch is ON */
+		if (handle && read_killswitch_status())
+			return;
+		break;
  	case MLED_ON:
  		out = !(out & 0x1);
  		break;
@@ -719,6 +778,18 @@ static ssize_t store_gps(struct device *
  	return store_status(buf, count, NULL, GPS_ON);
  }

+/*
+ * Kill Switch
+ */
+static ssize_t show_killswitch(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", read_killswitch_status());
+}
+
+/*
+ * Notify Handler
+ */
  static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
  {
  	/* TODO Find a better way to handle events count. */
@@ -737,8 +808,77 @@ static void asus_hotk_notify(acpi_handle
  		lcd_blank(FB_BLANK_POWERDOWN);
  	}

+	/*
+	 * Kill Switch ON/OFF events
+	 *
+	 * Enable/disable WLAN and BT depending on Kill Switch status.
+	 * Only works with models that send 0x80 and 0x81 when KS is changed.
+	 * Some models only send this event with WAPF = 0x04.
+	 */
+	if (event == ATKD_KS_ON) {
+
+		if (write_acpi_int(wl_switch_handle, NULL, 0, NULL))
+			printk(ASUS_WARNING "KS ON: failed to disable WLAN\n");
+
+		if (write_acpi_int(bt_switch_handle, NULL, 0, NULL))
+			printk(ASUS_WARNING "KS ON: failed to disable BT\n");
+
+	} else if (event == ATKD_KS_OFF) {
+		int status;
+
+		status = hotk->status & WL_ON ? 1 : 0;
+		if (write_acpi_int(wl_switch_handle, NULL, status, NULL))
+			printk(ASUS_WARNING "KS OFF: failed to restore WLAN\n");
+
+		status = hotk->status & BT_ON ? 1 : 0;
+		if (write_acpi_int(bt_switch_handle, NULL, status, NULL))
+			printk(ASUS_WARNING "KS OFF: failed to restore BT\n");
+	}
+
+	/*
+	 * WLAN Toggle event
+	 *
+	 * Toggle the WLAN status & LED.
+	 * This may be sent by the Fn+Fx key, or by the Kill Switch.
+	 * It must ALWAYS set the LED, even if the KS is ON.
+	 * Should only happen with WAPF = 0x01
+	 */
+	if (event == ATKD_WL_TOGGLE && wl_switch_handle) {
+		int status;
+		int mask = 0;
+
+		status = read_wireless_status(WL_ON) ? 0 : 1;
+		if (!read_killswitch_status())
+			mask = WL_ON;
+		/*
+		 * If KS is ON, only toggle the LED
+		 * else Toggle both the LED and internal status
+		 */
+		write_status(wl_switch_handle, status, mask);
+	}
+
+	/*
+	 * WLAN and BT status events
+	 *
+	 * These events are only sent for notification and information purposes.
+	 * The hardware should have updated the LEDs on its own.
+	 * Here we use them to update the internal status, so that we always
+	 * have an accurate 'previous status' to report through sysfs files
+	 * when the Kill Switch is ON.
+	 * Should only happen with WAPF = 0x01 or 0x00
+	 */
+	if (!read_killswitch_status()) {
+		if (event == ATKD_WL_ON)
+			write_status(NULL, 1, WL_ON);
+		else if (event == ATKD_WL_OFF)
+			write_status(NULL, 0, WL_ON);
+		else if (event == ATKD_BT_ON)
+			write_status(NULL, 1, BT_ON);
+		else if (event == ATKD_BT_OFF)
+			write_status(NULL, 0, BT_ON);
+	}
  	acpi_bus_generate_proc_event(hotk->device, event,
-				hotk->event_count[event % 128]++);
+				     hotk->event_count[event % 128]++);

  	return;
  }
@@ -767,6 +907,7 @@ static ASUS_CREATE_DEVICE_ATTR(ledd);
  static ASUS_CREATE_DEVICE_ATTR(ls_switch);
  static ASUS_CREATE_DEVICE_ATTR(ls_level);
  static ASUS_CREATE_DEVICE_ATTR(gps);
+static ASUS_CREATE_DEVICE_ATTR(killswitch);

  static struct attribute *asuspf_attributes[] = {
  	&dev_attr_infos.attr,
@@ -777,6 +918,7 @@ static struct attribute *asuspf_attribut
  	&dev_attr_ls_switch.attr,
  	&dev_attr_ls_level.attr,
  	&dev_attr_gps.attr,
+	&dev_attr_killswitch.attr,
  	NULL
  };

@@ -819,6 +961,9 @@ static void asus_hotk_add_fs(void)

  	if (gps_status_handle && gps_on_handle && gps_off_handle)
  		ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps);
+
+	if (read_hwrs() & KS_HWRS)
+		ASUS_SET_DEVICE_ATTR(killswitch, 0444, show_killswitch, NULL);
  }

  static int asus_handle_init(char *name, acpi_handle * handle,
@@ -918,16 +1063,8 @@ static int asus_hotk_get_info(void)

  	ASUS_HANDLE_INIT(ledd_set);

-	/*
-	 * The HWRS method return informations about the hardware.
-	 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
-	 * The significance of others is yet to be found.
-	 * If we don't find the method, we assume the device are present.
-	 */
-	status =
-	    acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result);
-	if (ACPI_FAILURE(status))
-		hwrs_result = WL_HWRS | BT_HWRS;
+	ASUS_HANDLE_INIT(hwrs);
+	hwrs_result = read_hwrs();

  	if (hwrs_result & WL_HWRS)
  		ASUS_HANDLE_INIT(wl_switch);
@@ -1016,13 +1153,17 @@ static int asus_hotk_add(struct acpi_dev

  	asus_hotk_found = 1;

-	/* WLED and BLED are on by default */
-	write_status(bt_switch_handle, 1, BT_ON);
-	write_status(wl_switch_handle, 1, WL_ON);
-
-	/* If the h/w switch is off, we need to check the real status */
-	write_status(NULL, read_status(BT_ON), BT_ON);
-	write_status(NULL, read_status(WL_ON), WL_ON);
+	/* Initialize WLAN and Bluetooth with current hardware value */
+	write_status(bt_switch_handle, read_wireless_status(BT_ON), BT_ON);
+	write_status(wl_switch_handle, read_wireless_status(WL_ON), WL_ON);
+
+	/* Make sure to turn off the LEDs if Kill Switch is ON */
+	if (read_killswitch_status()) {
+		if (write_acpi_int(wl_switch_handle, NULL, 0, NULL))
+			printk(ASUS_WARNING "KS ON: failed to disable WLAN\n");
+		if (write_acpi_int(bt_switch_handle, NULL, 0, NULL))
+			printk(ASUS_WARNING "KS ON: failed to disable BT\n");
+	}

  	/* LCD Backlight is on by default */
  	write_status(NULL, 1, LCD_ON);




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] asus-laptop add kill switch support
       [not found]         ` <1203349001.6019.85.camel-X8wR35IVlAxolqkO4TVVkw@public.gmane.org>
@ 2008-02-19 23:38           ` Fabien Crespel
       [not found]             ` <47BB6863.7050208-czgx1wgAc3rR7s880joybQ@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Fabien Crespel @ 2008-02-19 23:38 UTC (permalink / raw)
  To: Thomas Renninger
  Cc: linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	acpi4asus-user-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Dmitry Torokhov,
	Len Brown

Thomas Renninger wrote :
> Hi,
>
> On Thu, 2008-02-07 at 19:06 +0100, Fabien Crespel wrote:
>> Basically:
>> - there is now a killswitch file in /sys/devices/platform/asus-laptop/ to report 
>> the KS status (read from HWRS)
>>     
> Not sure, but:
> Shouldn't this one register against a general kill-switch interface?
> E.g. include/linux/rfkill.h
> instead of starting an own interface...
>
>    Thomas
>   
Hello,

after looking at the rfkill interface, it doesn't seem to have the same 
purpose here : rfkill seems to be here to allow toggling radio frequency 
of devices in response to a key or another *software* generated event, 
while the "killswitch" sysfs file in my patch simply provides a way to 
read whether the *hardware* kill switch is ON (and not write or toggle 
anything, since it's completely out of software control).

My intention when adding this interface was to allow userspace tools 
like Lapsus to know when WLAN/Bluetooth are completely *disabled* (and 
not simply "off"). I don't think the rfkill interface provides a way to 
know that, or I missed it..? if it doesn't, wouldn't it be interesting 
to add it?

The rfkill interface seems interesting to support the Fn+F2 key though 
(WLAN/Bluetooth toggle), since currently it doesn't work on all models.

- Fabien.


-------------------------------------------------------------------------
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/

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] asus-laptop add kill switch support
       [not found]             ` <47BB6863.7050208-czgx1wgAc3rR7s880joybQ@public.gmane.org>
@ 2008-02-22 10:03               ` Thomas Renninger
  0 siblings, 0 replies; 7+ messages in thread
From: Thomas Renninger @ 2008-02-22 10:03 UTC (permalink / raw)
  To: Fabien Crespel
  Cc: Dmitry Torokhov, Greg KH,
	acpi4asus-user-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA, Len Brown

On Wed, 2008-02-20 at 00:38 +0100, Fabien Crespel wrote:
> Thomas Renninger wrote :
> > Hi,
> >
> > On Thu, 2008-02-07 at 19:06 +0100, Fabien Crespel wrote:
> >> Basically:
> >> - there is now a killswitch file in /sys/devices/platform/asus-laptop/ to report 
> >> the KS status (read from HWRS)
> >>     
> > Not sure, but:
> > Shouldn't this one register against a general kill-switch interface?
> > E.g. include/linux/rfkill.h
> > instead of starting an own interface...
> >
> >    Thomas
> >   
> Hello,
Hi,

first, I don't know much about this interface and wlan/bluetooth
toggling..., I hope someone who is deeper involved kicks into this
discussion.

> after looking at the rfkill interface, it doesn't seem to have the same 
> purpose here : rfkill seems to be here to allow toggling radio frequency 
> of devices in response to a key or another *software* generated event, 
> while the "killswitch" sysfs file in my patch simply provides a way to 
> read whether the *hardware* kill switch is ON (and not write or toggle 
> anything, since it's completely out of software control).
The problem I see is that you may introduce a very
specific /sys/.../asus_killswitch userspace interface for which a
generic one already or should exist.
You created this for a very specific Lapsus userspace app..., imagine
there are other userspace progs: HAL, WLAN/Bluetooth performance test
programs, whatever wants to know whether Wlan/Bluetooth is on or off.
They now have to collect all this data from different, possibly existing
sysfs files.
Instead (this is what has been done for backlight control), every
specific implementation should register at the backlight driver, you
even find this in the asus driver.
Like that, userspace can operate machine, even architecture independent.

> My intention when adding this interface was to allow userspace tools 
> like Lapsus to know when WLAN/Bluetooth are completely *disabled* (and 
> not simply "off"). I don't think the rfkill interface provides a way to 
> know that, or I missed it..? if it doesn't, wouldn't it be interesting 
> to add it?
> 
> The rfkill interface seems interesting to support the Fn+F2 key though 
> (WLAN/Bluetooth toggle), since currently it doesn't work on all models.

I don't know the policy to provide read or read+write access to the same
thing for different HW.
It can be done:
  1) through file access rights
  2) Simply return -ENODEV (or another error) when userspace tries
     to write to the file in your case, it must handle this gracefully
  3) Provide a set_wlan_state and a get_wlan_state sysfs file
  4) ?

   Thomas


-------------------------------------------------------------------------
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/

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2008-02-22 10:03 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-16 15:57 [PATCH 2/2] asus-laptop add kill switch support Corentin CHARY
     [not found] ` <200801161657.50967.corentincj-EjuBZuxMvz2sTnJN9+BGXg@public.gmane.org>
2008-01-17 10:52   ` Len Brown
2008-01-17 11:15     ` Corentin CHARY
2008-02-07  5:40   ` Len Brown
2008-02-07 18:06     ` Fabien Crespel
     [not found]       ` <1203349001.6019.85.camel@queen.suse.de>
     [not found]         ` <1203349001.6019.85.camel-X8wR35IVlAxolqkO4TVVkw@public.gmane.org>
2008-02-19 23:38           ` Fabien Crespel
     [not found]             ` <47BB6863.7050208-czgx1wgAc3rR7s880joybQ@public.gmane.org>
2008-02-22 10:03               ` Thomas Renninger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox