Re: [PATCH v2 2/2] eeepc-laptop: Use standard interfaces

Previous thread: BUG: scheduling while atomic: ip/23212/0x00000102 by Arkadiusz Miskiewicz on Monday, August 4, 2008 - 9:45 am. (10 messages)

Next thread: [PATCH 0/6] Subset of watchdog fixes by Alan Cox on Monday, August 4, 2008 - 9:52 am. (7 messages)
From: Matthew Garrett
Date: Monday, August 4, 2008 - 10:08 am

eeepc-laptop uses the hwmon struct after unregistering the device, 
causing an oops on module unload. Flip the ordering to fix.

Signed-off-by: Matthew Garrett <mjg@redhat.com>

---

diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index 9e8d79e..facdb98 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -553,9 +553,9 @@ static void eeepc_hwmon_exit(void)
 	hwmon = eeepc_hwmon_device;
 	if (!hwmon)
 		return ;
-	hwmon_device_unregister(hwmon);
 	sysfs_remove_group(&hwmon->kobj,
 			   &hwmon_attribute_group);
+	hwmon_device_unregister(hwmon);
 	eeepc_hwmon_device = NULL;
 }

-- 
Matthew Garrett | mjg59@srcf.ucam.org
--

From: Matthew Garrett
Date: Monday, August 4, 2008 - 10:15 am

eeepc-laptop currently only sends key events via ACPI and has 
non-standard rfkill control. Add an input device and use the rfkill 
infrastructure.

Signed-off-by: Matthew Garrett <mjg@redhat.com>

---

This attempts to ensure that bluetoth and wlan rfkill devices are only 
created if the device is prseent, but I don't have a Bluetooth-enabled 
Eee to hand so I'm not certain it's correct. Testing with rfkill-input 
shows that the wifi interface works, though.

commit 0656cf909274db0e59bb570c2bddd242cf075e7f
Author: Matthew Garrett <mjg59@srcf.ucam.org>
Date:   Mon Aug 4 18:00:57 2008 +0100

    Rationalise interfacse

diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index facdb98..ad55e60 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -28,6 +28,8 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 #include <linux/uaccess.h>
+#include <linux/input.h>
+#include <linux/rfkill.h>
 
 #define EEEPC_LAPTOP_VERSION	"0.1"
 
@@ -125,6 +127,10 @@ struct eeepc_hotk {
 					   by this BIOS */
 	uint init_flag;			/* Init flags */
 	u16 event_count[128];		/* count for each event */
+	struct input_dev *inputdev;
+	u16 *keycode_map;
+	struct rfkill *eeepc_wlan_rfkill;
+	struct rfkill *eeepc_bluetooth_rfkill;
 };
 
 /* The actual device the driver binds to */
@@ -140,6 +146,27 @@ static struct platform_driver platform_driver = {
 
 static struct platform_device *platform_device;
 
+struct key_entry {
+	char type;
+	u8 code;
+	u16 keycode;
+};
+
+enum { KE_KEY, KE_END };
+
+static struct key_entry eeepc_keymap[] = {
+	/* Sleep already handled via generic ACPI code */
+	{KE_KEY, 0x10, KEY_WLAN },
+	{KE_KEY, 0x12, KEY_PROG1 },
+	{KE_KEY, 0x13, KEY_MUTE },
+	{KE_KEY, 0x14, KEY_VOLUMEDOWN },
+	{KE_KEY, 0x15, KEY_VOLUMEUP },
+	{KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
+	{KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
+	{KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
+	{KE_END, 0},
+};
+
 /*
  * The hotkey driver ...
From: Ivo van Doorn
Date: Monday, August 4, 2008 - 10:53 am

Please use the rfkill_force_state() to report state changes,
that will ensure that the events are immediately send to the
rfkill layer.

Otherwise events will not be reported untill the next get_state() event.



--

From: Matthew Garrett
Date: Monday, August 4, 2008 - 10:36 am

Why does writing to the sysfs file not generate an update implicitly? 
This is purely a software rfkill device, the input hotkey just generates 
KEY_WLAN and needs rfkill-input to handle it.
-- 
Matthew Garrett <mjg59@srcf.ucam.org>
--

From: Henrique de Moraes Holschuh
Date: Monday, August 4, 2008 - 2:21 pm

It does.  rfkill_force_state() is used to propagate state changes done by
outside sources back into rfkill.  All internal changes caused by rfkill or
known to rfkill are dealt with by rfkill itself.

If there are no such outside sources, you don't need rfkill_force_state() or
get_state() at all, as long as you set rfkill->state properly before you
call rfkill_register.

BTW: if it has a hardware rfkill switch that overrides the rfkill
controller, that DOES count as an outside source of changes.

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh
--

From: Henrique de Moraes Holschuh
Date: Monday, August 4, 2008 - 2:29 pm

This might just be style, but I'd rather you didn't do this unless get_acpi
and set_acpi do take enum rfkill_state...  Doing state conversion would be a
lot more future-proof, as well:

Something like:
	set_acpi(CM_ASL_WLAN, (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1);

And:

	*state = get_acpi(CM_ASL_WLAN) ? RFKILL_STATE_SOFT_BLOCKED :
						RFKILL_STATE_UNBLOCKED;


This is not needed, and if we get rid of user_claim_unsupported later, your
code wouldn't need changes if you get rid of that line.

I have not paid much attention to it yet, but so far I have failed to
understand what user_claim_unsupported is good for in the new style rfkill
interface.

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh
--

From: Matthew Garrett
Date: Wednesday, August 6, 2008 - 2:23 am

eeepc-laptop uses the hwmon struct after unregistering the device, 
causing an oops on module unload. Flip the ordering to fix.
                                                                                                                                                                                                        
Signed-off-by: Matthew Garrett <mjg@redhat.com>

---

commit 95f4bc41ef256b8e3dfa94cabe1faf0776ac988c
Author: Matthew Garrett <mjg59@srcf.ucam.org>
Date:   Mon Aug 4 17:57:40 2008 +0100

    Fix use after free

diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index 9e8d79e..facdb98 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -553,9 +553,9 @@ static void eeepc_hwmon_exit(void)
 	hwmon = eeepc_hwmon_device;
 	if (!hwmon)
 		return ;
-	hwmon_device_unregister(hwmon);
 	sysfs_remove_group(&hwmon->kobj,
 			   &hwmon_attribute_group);
+	hwmon_device_unregister(hwmon);
 	eeepc_hwmon_device = NULL;
 }
 

-- 
Matthew Garrett | mjg59@srcf.ucam.org
--

From: Matthew Garrett
Date: Wednesday, August 6, 2008 - 2:25 am

eeepc-laptop currently only sends key events via ACPI and has 
non-standard rfkill control. Add an input device and use the rfkill 
infrastructure.
                                                                                                                                                                                                        
Signed-off-by: Matthew Garrett <mjg@redhat.com>

---

Updated to explicitly set state at registration time and use the enums 
rather than relying on their ordering (as suggested by Henrique)

diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index facdb98..f7f1eae 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -28,6 +28,8 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 #include <linux/uaccess.h>
+#include <linux/input.h>
+#include <linux/rfkill.h>
 
 #define EEEPC_LAPTOP_VERSION	"0.1"
 
@@ -125,6 +127,10 @@ struct eeepc_hotk {
 					   by this BIOS */
 	uint init_flag;			/* Init flags */
 	u16 event_count[128];		/* count for each event */
+	struct input_dev *inputdev;
+	u16 *keycode_map;
+	struct rfkill *eeepc_wlan_rfkill;
+	struct rfkill *eeepc_bluetooth_rfkill;
 };
 
 /* The actual device the driver binds to */
@@ -140,6 +146,27 @@ static struct platform_driver platform_driver = {
 
 static struct platform_device *platform_device;
 
+struct key_entry {
+	char type;
+	u8 code;
+	u16 keycode;
+};
+
+enum { KE_KEY, KE_END };
+
+static struct key_entry eeepc_keymap[] = {
+	/* Sleep already handled via generic ACPI code */
+	{KE_KEY, 0x10, KEY_WLAN },
+	{KE_KEY, 0x12, KEY_PROG1 },
+	{KE_KEY, 0x13, KEY_MUTE },
+	{KE_KEY, 0x14, KEY_VOLUMEDOWN },
+	{KE_KEY, 0x15, KEY_VOLUMEUP },
+	{KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
+	{KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
+	{KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
+	{KE_END, 0},
+};
+
 /*
  * The hotkey driver declaration
  */
@@ -261,6 +288,44 @@ static int update_bl_status(struct backlight_device *bd)
 }
 
 ...
From: Andrew Morton
Date: Tuesday, August 19, 2008 - 2:58 am

drivers/misc/eeepc-laptop.c: In function 'eeepc_hotk_add':
drivers/misc/eeepc-laptop.c:577: error: 'CM_ASL_WIFI' undeclared (first use in this function)
drivers/misc/eeepc-laptop.c:577: error: (Each undeclared identifier is reported only once
drivers/misc/eeepc-laptop.c:577: error: for each function it appears in.)
drivers/misc/eeepc-laptop.c:595: error: 'eeepc_bluetooth_rfkill_set' undeclared (first use in this function)
drivers/misc/eeepc-laptop.c:597: error: 'eeepc_bluetooth_rfkill_state' undeclared (first use in this function)

maybe this had some dependencies which I didn't know about.

--

From: Matthew Garrett
Date: Tuesday, August 19, 2008 - 4:13 am

eeepc-laptop currently only sends key events via ACPI and has 
non-standard rfkill control. Add an input device and use the rfkill 
infrastructure.

Signed-off-by: Matthew Garrett <mjg@redhat.com>

---

Sorry, managed to send the wrong version before. This one actually 
builds.

diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index facdb98..017fa89 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -28,6 +28,8 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 #include <linux/uaccess.h>
+#include <linux/input.h>
+#include <linux/rfkill.h>
 
 #define EEEPC_LAPTOP_VERSION	"0.1"
 
@@ -125,6 +127,10 @@ struct eeepc_hotk {
 					   by this BIOS */
 	uint init_flag;			/* Init flags */
 	u16 event_count[128];		/* count for each event */
+	struct input_dev *inputdev;
+	u16 *keycode_map;
+	struct rfkill *eeepc_wlan_rfkill;
+	struct rfkill *eeepc_bluetooth_rfkill;
 };
 
 /* The actual device the driver binds to */
@@ -140,6 +146,27 @@ static struct platform_driver platform_driver = {
 
 static struct platform_device *platform_device;
 
+struct key_entry {
+	char type;
+	u8 code;
+	u16 keycode;
+};
+
+enum { KE_KEY, KE_END };
+
+static struct key_entry eeepc_keymap[] = {
+	/* Sleep already handled via generic ACPI code */
+	{KE_KEY, 0x10, KEY_WLAN },
+	{KE_KEY, 0x12, KEY_PROG1 },
+	{KE_KEY, 0x13, KEY_MUTE },
+	{KE_KEY, 0x14, KEY_VOLUMEDOWN },
+	{KE_KEY, 0x15, KEY_VOLUMEUP },
+	{KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
+	{KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
+	{KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
+	{KE_END, 0},
+};
+
 /*
  * The hotkey driver declaration
  */
@@ -261,6 +288,44 @@ static int update_bl_status(struct backlight_device *bd)
 }
 
 /*
+ * Rfkill helpers
+ */
+
+static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
+{
+	if (state == RFKILL_STATE_SOFT_BLOCKED)
+		return set_acpi(CM_ASL_WLAN, 0);
+	else
+		return set_acpi(CM_ASL_WLAN, 1);
+}
+
+static int ...
From: Henrique de Moraes Holschuh
Date: Tuesday, August 19, 2008 - 4:09 pm

Looks fine to me at first glance.  I do wonder if there are no events at all
you could hook to rfkill_force_state() instead of (or in addition to) using
the get_state()?

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh
--

From: Matthew Garrett
Date: Tuesday, August 19, 2008 - 4:24 pm

The only change event is generated by hitting the wifi key, which ties 
into rfkill-input. Won't that already force a state update on the event?

-- 
Matthew Garrett | mjg59@srcf.ucam.org
--

From: Henrique de Moraes Holschuh
Date: Tuesday, August 19, 2008 - 6:18 pm

Yes, but one must keep this in mind:

1. If the event has no bearing on compulsory hardware state changes (i.e.
the hardware won't change state by itself when the event happens, it is
really just reporting a simple key press that will do nothing by itself),
you just report the key as an event.

2. If the hardware/firmware *ALSO* compulsory changes the rfkill state (i.e.
the event also means the real rfkill controller state probably changed), you
take the opportunity to do a forced immediate state poll and
rfkill_force_state() the new state.

So, it basically depends whether the EEEPC hardware/firmware does (1) or
(2).  If it is (1), the patch is correct.  If it is (2), it should do a bit
more stuff that ends up with a call to rfkill_force_state().

The reason is that there is absolutely *NO* reason why rfkill-input (or
anything else for that matter) has to obey the input event.  They can just
discard it if they want: it is a local system policy matter.  Therefore, if
there is anything in *hardware* or *firmware* that is already acting on that
event, you *MUST* arrange for a call to rfkill_force_state().

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh
--

From: Matthew Garrett
Date: Tuesday, August 19, 2008 - 6:28 pm

The firmware does not perform any compulsory change.

-- 
Matthew Garrett | mjg59@srcf.ucam.org
--

From: Henrique de Moraes Holschuh
Date: Tuesday, August 19, 2008 - 6:32 pm

Hi Matthew!


Then, I have no futher comments.  Looks good to me.

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh
--

From: Matthew Garrett
Date: Tuesday, August 19, 2008 - 6:42 pm

Excellent, glad I've got that right.

One completely unrelated question. In the following situation (relevant 
to Dells, not the Eee)

* The system has a key (not a switch) that in firmware disables the 
hardware (HARD_BLOCKED)
* That key generates an event through the keyboard controller, but not 
through any other obviously detectable means
* The radio control is also controllable through software (SOFT_BLOCKED)

Should pressing the key generate a KEY_WLAN event?

I note that rfkill-input will, if the device is in HARD_BLOCKED state, 
attempt to set it to UNBLOCKED. This sounds like generating the keycode 
is the wrong thing to do, since it'll cause rfkill-input to try to undo 
the change that's just been made. However, if the key isn't mapped 
there's no obvious way for any of the stack to determine that a change 
has been made and propagate that to userspace. What should we be doing 
here?

-- 
Matthew Garrett | mjg59@srcf.ucam.org
--

From: Henrique de Moraes Holschuh
Date: Tuesday, August 19, 2008 - 7:30 pm

Ick.  I sure hope you can query the firmware, so that you can look at it as
if it were a switch instead of a key (and look at the key press event as a
"switch changed state" event -- never mind it is difficult to hook to that
event right now)?

I mean, trying to deal with firmware/hardware that changes states on its own
in any other basis than "it is a switch", is error prone.  You miss one


Frankly?  I think so.  It would be nice if you could hook the key as a "hint
that the rfkill controller may have changed state" on the driver, and ALSO
as a normal input device (so that it can command more than just that one
WLAN radio).

But I think it would be EVEN BETTER if you could somehow suppress that KEY_*
event, and synthesize an EV_SW SW_WLAN in its place (you will have to ask
Dmitry to add it, since it is a first use) instead.  If you cannot, KEY_WLAN

I have some patches in flight that will make rfkill-input smarter about it.
But that's just an enhancement.  The current way it operates is annoying,
but last time I checked, it doesn't blow up.

Just return -EPERM on your device driver's toggle_radio() callback if you
are at HARD_BLOCKED and someone asks you to go to UNBLOCKED.  That is what

Never worry about propagating rfkill state to userspace in a driver.  rfkill
will do it by itself using uevents, that code has already been accepted.
The rfkill class will do it for all rfkill controllers, and rfkill input may
be taught to do it later if userspace people ask for it (nobody did it yet
because it is not very useful, since what you want is reports of what really
IS happening to the radios, and those come from the rfkill class.  All
rfkill-input could tell userspace is what it is *trying* to change radio
states, but not whether they did really happen).

The reason why you'd want to send a KEY_WLAN event (or, if you can, an EV_SW
SW_WLAN event) is to change that key from something that controls an
specific WLAN radio, to something that can *potentially* control every ...
From: Len Brown
Date: Wednesday, October 8, 2008 - 1:50 pm

applied to acpi-test.
Corentin Chary, you're the driver maintainer, do you Ack?

thanks,
-Len

--

Previous thread: BUG: scheduling while atomic: ip/23212/0x00000102 by Arkadiusz Miskiewicz on Monday, August 4, 2008 - 9:45 am. (10 messages)

Next thread: [PATCH 0/6] Subset of watchdog fixes by Alan Cox on Monday, August 4, 2008 - 9:52 am. (7 messages)