This patch series contains what is ready so far of my rfkill rework effort. Much has been talked about it already, please refer to the thread started by Message-Id: <1207946244-14525-1-git-send-email-hmh@hmh.eng.br> (http://thread.gmane.org/gmane.linux.kernel/664500) if you don't understand what brought this on. In particular, anyone that still thinks drivers can use the input layer to send rfkill state change messages around, or that rfkill class and input-polldev work as a way to have read/write rfkill switches, go read that thread... Fixing this is about half the reason why this patchset exists (the other being that thinkpad-acpi needs it, and therefore I need it as an user and also as a kernel developer). This series is available as a git branch at: git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git rfkill The first two patches are just to sync the pending-merge queue of thinkpad-acpi to avoid wasting my time with various versions of other patches because of two patches that will hit mainline very soon. Do not pay too much attention to them. The input layer patch is already approved by Dmitry, but he asked me to merge it along with the rest of the stuff that needs it. The full rfkill work is NOT complete. The userspace interface is lacking a way to read and write to the global rfkill switch states, in order to let userspace do all that rfkill-input.c can do (i.e. something like the private rfkill_switch_all and rfkill_epo). I do have some patches that do it, but I am not happy with them. I will send them later, please comment on this "supposedly to be ready for merging" patch set first. As it stands, I'd like to know if the patches in this series are acceptable to go upstream. They do NOT break anything further in the kernel, but they don't fix any drivers by themselves either (the drivers, like b43, need to be fixed to use the rfkill class properly). If you need a 2.6.23 (might also work on 2.6.24 and 2.6.25) backport of this series, OR if you ...
The less tested codepaths for LED handling, used on ThinkPads 570, 600e/x,
770e, 770x, A21e, A2xm/p, T20-22, X20 and maybe a few others, would write
data to kernel memory it had no business touching, for leds number 3 and
above. If one is lucky, that illegal write would cause an OOPS, but
chances are it would silently corrupt a byte.
The problem was introduced in commit af116101, "ACPI: thinkpad-acpi: add
sysfs led class support to thinkpad leds (v3.2)".
Fix the bug by refactoring the entire code to be far more obvious on what
it wants to do. Also do some defensive "constification".
Issue reported by Karol Lewandowski <lmctlx@gmail.com> (he's an lucky guy
and got an OOPS instead of silent corruption :-) ).
Root cause of the OOPS identified by Adrian Bunk <bunk@kernel.org>.
Thanks, Adrian!
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Tested-by: Karol Lewandowski <lmctlx@gmail.com>
Cc: Adrian Bunk <bunk@kernel.org>
---
drivers/misc/thinkpad_acpi.c | 55 +++++++++++++++++++++--------------------
1 files changed, 28 insertions(+), 27 deletions(-)
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 3c53668..5a560d9 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -3853,7 +3853,7 @@ static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
"tpacpi::standby",
};
-static int led_get_status(unsigned int led)
+static int led_get_status(const unsigned int led)
{
int status;
enum led_status_t led_s;
@@ -3877,41 +3877,42 @@ static int led_get_status(unsigned int led)
/* not reached */
}
-static int led_set_status(unsigned int led, enum led_status_t ledstatus)
+static int led_set_status(const unsigned int led,
+ const enum led_status_t ledstatus)
{
/* off, on, blink. Index is led_status_t */
- static const int const led_sled_arg1[] = { 0, 1, 3 };
- static const int const led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
- static const int const led_exp_hlcl[] = { 0, 1, ...The SW_RADIO code for EV_SW events has a name that is not descriptive enough of its intended function, and could induce someone to think KEY_RADIO is its EV_KEY counterpart, which is false. Rename it to SW_RFKILL_ALL, and document what this event is for. Keep the old name around, to avoid userspace ABI breaks. The SW_RFKILL_ALL event is meant to be used by rfkill master switches. It is not bound to a particular radio switch type, and usually applies to all types. It is semantically tied to master rfkill switches that enable or disable every radio in a system. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Acked-by: Dmitry Torokhov <dtor@mail.ru> Cc: Ivo van Doorn <IvDoorn@gmail.com> --- Documentation/laptops/thinkpad-acpi.txt | 2 +- drivers/misc/thinkpad_acpi.c | 4 ++-- include/linux/input.h | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 01c6c3d..64b3f14 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -503,7 +503,7 @@ generate input device EV_KEY events. In addition to the EV_KEY events, thinkpad-acpi may also issue EV_SW events for switches: -SW_RADIO T60 and later hardare rfkill rocker switch +SW_RFKILL_ALL T60 and later hardare rfkill rocker switch SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A Non hot-key ACPI HKEY event map: diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 5a560d9..084a8f9 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1293,7 +1293,7 @@ static void tpacpi_input_send_radiosw(void) mutex_lock(&tpacpi_inputdev_send_mutex); input_report_switch(tpacpi_inputdev, - SW_RADIO, !!wlsw); + SW_RFKILL_ALL, !!wlsw); input_sync(tpacpi_inputdev); mutex_unlock(&tpacpi_inputdev_send_mutex); @@ -2231,7 +2231,7 @@ static ...
rfkill really should have been named rfswitch. As it is, one can get
confused whether RFKILL_STATE_ON means the KILL switch is on (and
therefore, the radio is being *blocked* from operating), or whether it
means the RADIO rf output is on.
Clearly state that RFKILL_STATE_ON means the radio is *unblocked* from
operating (i.e. there is no rf killing going on).
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: Ivo van Doorn <IvDoorn@gmail.com>
Cc: John W. Linville <linville@tuxdriver.com>
Cc: Dmitry Torokhov <dtor@mail.ru>
---
Documentation/rfkill.txt | 7 +++++++
include/linux/rfkill.h | 6 +++---
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt
index a83ff23..ec75d6d 100644
--- a/Documentation/rfkill.txt
+++ b/Documentation/rfkill.txt
@@ -8,6 +8,13 @@ rfkill - RF switch subsystem support
===============================================================================
1: Implementation details
+The rfkill switch subsystem exists to add a generic interface to circuitry that
+can enable or disable the RF output of a radio *transmitter* of any type.
+
+When a rfkill switch is in the RFKILL_STATE_ON, the radio transmitter is
+*enabled*. When the rfkill switch is in the RFKILL_STATE_OFF, the radio
+transmitter is *disabled*.
+
The rfkill switch subsystem offers support for keys often found on laptops
to enable wireless devices like WiFi and Bluetooth.
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index e3ab21d..ca89ae1 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -44,8 +44,8 @@ enum rfkill_type {
};
enum rfkill_state {
- RFKILL_STATE_OFF = 0,
- RFKILL_STATE_ON = 1,
+ RFKILL_STATE_OFF = 0, /* Radio output blocked */
+ RFKILL_STATE_ON = 1, /* Radio output active */
};
/**
@@ -53,7 +53,7 @@ enum rfkill_state {
* @name: Name of the switch.
* @type: Radio type which the button controls, the value stored
* here should ...Fix a minor typo in an exported function documentation Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Cc: Ivo van Doorn <IvDoorn@gmail.com> Cc: John W. Linville <linville@tuxdriver.com> Cc: Dmitry Torokhov <dtor@mail.ru> --- net/rfkill/rfkill.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 4e10a95..f95081a 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -412,7 +412,7 @@ int rfkill_register(struct rfkill *rfkill) EXPORT_SYMBOL(rfkill_register); /** - * rfkill_unregister - Uegister a rfkill structure. + * rfkill_unregister - Unregister a rfkill structure. * @rfkill: rfkill structure to be unregistered * * This function should be called by the network driver during device -- 1.5.5.1 --
Rework some subdriver init and exit handlers, in order to fix some
initialization error paths that were missing, or broken.
Hitting those bugs should be extremely rare in the real world, but should
that happen, thinkpad-acpi would fail to dealocate some resources and a
reboot might well be needed to be able to load the driver again.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
---
drivers/misc/thinkpad_acpi.c | 435 ++++++++++++++++++++++--------------------
1 files changed, 229 insertions(+), 206 deletions(-)
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 3f28f6e..3c53668 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -1921,6 +1921,29 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
&dev_attr_hotkey_wakeup_hotunplug_complete.attr,
};
+static void hotkey_exit(void)
+{
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ hotkey_poll_stop_sync();
+#endif
+
+ if (hotkey_dev_attributes)
+ delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
+
+ kfree(hotkey_keycode_map);
+
+ if (tp_features.hotkey) {
+ dbg_printk(TPACPI_DBG_EXIT,
+ "restoring original hot key mask\n");
+ /* no short-circuit boolean operator below! */
+ if ((hotkey_mask_set(hotkey_orig_mask) |
+ hotkey_status_set(hotkey_orig_status)) != 0)
+ printk(TPACPI_ERR
+ "failed to restore hot key mask "
+ "to BIOS defaults\n");
+ }
+}
+
static int __init hotkey_init(struct ibm_init_struct *iibm)
{
/* Requirements for changing the default keymaps:
@@ -2060,226 +2083,220 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
str_supported(tp_features.hotkey));
- if (tp_features.hotkey) {
- hotkey_dev_attributes = create_attr_set(13, NULL);
- if (!hotkey_dev_attributes)
- return -ENOMEM;
- res = ...Teach rfkill-input how to handle SW_RFKILL_ALL events (new name for the
SW_RADIO event).
SW_RFKILL_ALL is an absolute enable-or-disable command that is tied to all
radios in a system.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: Ivo van Doorn <IvDoorn@gmail.com>
Cc: Dmitry Torokhov <dtor@mail.ru>
---
net/rfkill/rfkill-input.c | 45 +++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index e4b051d..9d6c925 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -55,6 +55,22 @@ static void rfkill_task_handler(struct work_struct *work)
mutex_unlock(&task->mutex);
}
+static void rfkill_schedule_set(struct rfkill_task *task,
+ enum rfkill_state desired_state)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&task->lock, flags);
+
+ if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
+ task->desired_state = desired_state;
+ task->last = jiffies;
+ schedule_work(&task->work);
+ }
+
+ spin_unlock_irqrestore(&task->lock, flags);
+}
+
static void rfkill_schedule_toggle(struct rfkill_task *task)
{
unsigned long flags;
@@ -87,9 +103,9 @@ static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
static void rfkill_event(struct input_handle *handle, unsigned int type,
- unsigned int code, int down)
+ unsigned int code, int data)
{
- if (type == EV_KEY && down == 1) {
+ if (type == EV_KEY && data == 1) {
switch (code) {
case KEY_WLAN:
rfkill_schedule_toggle(&rfkill_wlan);
@@ -106,6 +122,26 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
default:
break;
}
+ } else if (type == EV_SW) {
+ switch (code) {
+ case SW_RFKILL_ALL:
+ /* EVERY radio type. data != 0 means radios ON */
+ rfkill_schedule_set(&rfkill_wimax,
+ (data)? RFKILL_STATE_ON:
+ ...Currently, radios are always enabled when their rfkill interface is
registered. This is not optimal, the safest state for a radio is to be
offline unless the user turns it on.
Add a module parameter that causes all radios to be disabled when their
rfkill interface is registered. The module default is not changed so
unless the parameter is used, radios will still be forced to their enabled
state when they are registered.
The new rfkill module parameter is called "default_state".
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
---
net/rfkill/rfkill.c | 11 ++++++++++-
1 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index f95081a..3edc585 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -39,6 +39,11 @@ MODULE_LICENSE("GPL");
static LIST_HEAD(rfkill_list); /* list of registered rf switches */
static DEFINE_MUTEX(rfkill_mutex);
+static unsigned int rfkill_default_state = RFKILL_STATE_ON;
+module_param_named(default_state, rfkill_default_state, uint, 0444);
+MODULE_PARM_DESC(default_state,
+ "Default initial state for all radio types, 0 = radio off");
+
static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX];
@@ -436,8 +441,12 @@ static int __init rfkill_init(void)
int error;
int i;
+ if (rfkill_default_state != RFKILL_STATE_OFF &&
+ rfkill_default_state != RFKILL_STATE_ON)
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(rfkill_states); i++)
- rfkill_states[i] = RFKILL_STATE_ON;
+ rfkill_states[i] = rfkill_default_state;
error = class_register(&rfkill_class);
if (error) {
--
1.5.5.1
--
We will need access to the rfkill switch type in string format for more
than just sysfs. Therefore, move it to a generic helper.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: Ivo van Doorn <IvDoorn@gmail.com>
---
net/rfkill/rfkill.c | 33 +++++++++++++++------------------
1 files changed, 15 insertions(+), 18 deletions(-)
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 251defe..4ed8d19 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -220,34 +220,31 @@ static ssize_t rfkill_name_show(struct device *dev,
return sprintf(buf, "%s\n", rfkill->name);
}
-static ssize_t rfkill_type_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static const char const *rfkill_get_type_str(enum rfkill_type type)
{
- struct rfkill *rfkill = to_rfkill(dev);
- const char *type;
-
- switch (rfkill->type) {
+ switch (type) {
case RFKILL_TYPE_WLAN:
- type = "wlan";
- break;
+ return "wlan";
case RFKILL_TYPE_BLUETOOTH:
- type = "bluetooth";
- break;
+ return "bluetooth";
case RFKILL_TYPE_UWB:
- type = "ultrawideband";
- break;
+ return "ultrawideband";
case RFKILL_TYPE_WIMAX:
- type = "wimax";
- break;
+ return "wimax";
case RFKILL_TYPE_WWAN:
- type = "wwan";
- break;
+ return "wwan";
default:
BUG();
}
+}
+
+static ssize_t rfkill_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
- return sprintf(buf, "%s\n", type);
+ return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type));
}
static ssize_t rfkill_state_show(struct device *dev,
--
1.5.5.1
--
Use the notification chains to also send uevents, so that userspace can be
notified of state changes of every rfkill switch.
Userspace should use these events for OSD/status report applications and
rfkill GUI frontends. HAL might want to broadcast them over DBUS, for
example. It might be also useful for userspace implementations of
rfkill-input, or to use HAL as the platform driver which promotes rfkill
switch change events into input events (to synchronize all other switches)
when necessary for platforms that lack a convenient platform-specific
kernel module to do it.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: Ivo van Doorn <IvDoorn@gmail.com>
Cc: Dmitry Torokhov <dtor@mail.ru>
---
net/rfkill/rfkill.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 42 insertions(+), 0 deletions(-)
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 4ed8d19..ba25bde 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -382,12 +382,51 @@ static int rfkill_resume(struct device *dev)
#define rfkill_resume NULL
#endif
+static int rfkill_blocking_uevent_notifier(struct notifier_block *nb,
+ unsigned long eventid,
+ void *data)
+{
+ struct rfkill *rfkill = (struct rfkill *)data;
+
+ switch (eventid) {
+ case RFKILL_STATE_CHANGED:
+ kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block rfkill_blocking_uevent_nb = {
+ .notifier_call = rfkill_blocking_uevent_notifier,
+ .priority = 0,
+};
+
+static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
+ int error;
+
+ error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name);
+ if (error)
+ return error;
+ error = add_uevent_var(env, "RFKILL_TYPE=%s",
+ rfkill_get_type_str(rfkill->type));
+ if (error)
+ return error;
+ error = add_uevent_var(env, "RFKILL_STATE=%u", rfkill->state);
+ return ...Unfortunately, instead of adding a generic Wireless WAN type, a technology-
specific type (WiMAX) was added. That's useless for other WWAN devices,
such as EDGE, UMTS, X-RTT and other such radios.
Add a WWAN rfkill type for generic wireless WAN devices. No keys are added
as most devices really want to use KEY_WLAN for WWAN control (in a cycle of
none, WLAN, WWAN, WLAN+WWAN) and need no specific keycode added.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Cc: Iñaky Pérez-González <inaky.perez-gonzalez@intel.com>
Cc: Ivo van Doorn <IvDoorn@gmail.com>
Cc: John W. Linville <linville@tuxdriver.com>
Cc: David S. Miller <davem@davemloft.net>
---
include/linux/rfkill.h | 2 ++
net/rfkill/rfkill-input.c | 4 ++++
net/rfkill/rfkill.c | 3 +++
3 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index 844e961..c0cab7d 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -34,12 +34,14 @@
* RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
* RFKILL_TYPE_UWB: switch is on a ultra wideband device.
* RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
+ * RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
*/
enum rfkill_type {
RFKILL_TYPE_WLAN ,
RFKILL_TYPE_BLUETOOTH,
RFKILL_TYPE_UWB,
RFKILL_TYPE_WIMAX,
+ RFKILL_TYPE_WWAN,
RFKILL_TYPE_MAX,
};
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index 9d6c925..29c13d3 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -101,6 +101,7 @@ static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
+static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
static void rfkill_event(struct input_handle *handle, unsigned int type,
unsigned int code, int data)
@@ -126,6 +127,9 @@ ...If WiMAX is a subset of the WWAN technology, shouldn't we replace WiMAX completely in rfkill? Otherwise people might get ideas and add the other technologies seperately as well. ;) Other then that, the addition of WWAN is fine with me. :) --
Actually, I have no reason to believe there *isn't* a device with KEY_WIMAX... but we need the WWAN type before we bother with a WiMax type :-) IMO, we should fix the issue by adding a "supertype", i.e., a class. Use that for generic grouping, and let type be more specific when there is a reason for it. Repeat the class as the type to get a "generic" type, when there is no reason to bother with more specific types. Stuff like "WiMax", "802.1a", "EDGE", "GRPS", "802.1bg" would be the type, and class would be "WLAN", "WWAN", etc. We would only deal with classes on rfkill-input. Anything else more specific should be done in userspace instead, disabling rfkill-input. -- "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 --
BTW, I just realized this was mistakenly put in your initial patch; How would this apply to the case where I want to use the HW key to switch one off and turn the other one off (say I have both a WiMAX and EDGE cards in my machine); how could we do it to distinguish which key is which? I might be missing something. -- Inaky --
I don't understand. Switch one off and turn the other one off? Isn't that the same thing? -- "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 --
-EOPERATORISDUMB, sorry; I meant turn one off and the other on. -- Inaky --
Then here's what you'd have with (class, type): EITHER 1. rfkill-input would manipulate based on class for a given input event. Therefore we would remove KEY_WIMAX from rfkill-input. OR... 2. rfkill-input would be teached to manipulate for classes (all switches in a class), and for (class,type) (hunt down all rfkill switches of that given type and class)... and it does mean KEY_WIMAX would only affect WiMAX switches, while WWAN would affect EDGE, GPRS, *WIMAX*, etc. And if you need anything different, you'd have to do it in userspace as you want, and disable rfkill-input entirely, or for the switches you want to override (using user_claim). -- "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 --
The resume handler should reset the wireless transmitter rfkill
state to exactly what it was when the system was suspended. Do it,
and do it using the normal routines for state change while at it.
The suspend handler should force-switch the transmitter to blocked
state, ignoring caches. Do it.
Also take an opportunity shot to rfkill_remove_switch() and also
force the transmitter to blocked state there, bypassing caches.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: Ivo van Doorn <IvDoorn@gmail.com>
---
net/rfkill/rfkill.c | 35 ++++++++++++++++++-----------------
1 files changed, 18 insertions(+), 17 deletions(-)
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index c5a79ab..f11220b 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -75,24 +75,25 @@ static void update_rfkill_state(struct rfkill *rfkill)
}
static int rfkill_toggle_radio(struct rfkill *rfkill,
- enum rfkill_state state)
+ enum rfkill_state state,
+ int force)
{
int retval = 0;
enum rfkill_state oldstate, newstate;
oldstate = rfkill->state;
- if (rfkill->get_state &&
+ if (rfkill->get_state && !force &&
!rfkill->get_state(rfkill->data, &newstate))
rfkill->state = newstate;
- if (state != rfkill->state) {
+ if (force || state != rfkill->state) {
retval = rfkill->toggle_radio(rfkill->data, state);
if (!retval)
rfkill->state = state;
}
- if (rfkill->state != oldstate)
+ if (force || rfkill->state != oldstate)
rfkill_led_trigger(rfkill, rfkill->state);
return retval;
@@ -107,7 +108,6 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
* a specific switch is claimed by userspace in which case it is
* left alone.
*/
-
void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
{
struct rfkill *rfkill;
@@ -118,7 +118,7 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
list_for_each_entry(rfkill, &rfkill_list, node) {
if ...Add a notifier chain for use by the rfkill class. This notifier chain signals the following events (more to be added when needed): 1. rfkill: rfkill device state has changed A pointer to the rfkill struct will be passed as a parameter. The notifier message types have been added to include/linux/rfkill.h instead of to include/linux/notifier.h in order to avoid the madness of modifying a header used globally (and that triggers an almost full tree rebuild every time it is touched) with information that is of interest only to code that includes the rfkill.h header. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Cc: Ivo van Doorn <IvDoorn@gmail.com> --- include/linux/rfkill.h | 7 +++++ net/rfkill/rfkill.c | 70 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index c0cab7d..98667be 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -117,4 +117,11 @@ static inline char *rfkill_get_led_name(struct rfkill *rfkill) #endif } +/* rfkill notification chain */ +#define RFKILL_STATE_CHANGED 0x0001 /* state of a normal rfkill + switch has changed */ + +int register_rfkill_notifier(struct notifier_block *nb); +int unregister_rfkill_notifier(struct notifier_block *nb); + #endif /* RFKILL_H */ diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index f11220b..251defe 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -46,6 +46,49 @@ MODULE_PARM_DESC(default_state, static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX]; +static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); + + +/** + * register_rfkill_notifier - Add notifier to rfkill notifier chain + * @nb: pointer to the new entry to add to the chain + * + * See blocking_notifier_chain_register() for return value and further + * observations. + * + * Adds a notifier to the rfkill notifier chain. The chain will be + * called with a ...
One must, one must..., asynchronous ... Thomas --
Will fix. -- "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 --
Besides the spelling comments from Thomas, patch is fine with me. --
SW_RFKILL_ALL is the "emergency power-off all radios" input event. It must
be handled, and must always do the same thing as far as the rfkill system
is concerned: all transmitters are to go *immediately* offline.
For safety, do NOT allow userspace to override EV_SW SW_RFKILL_ALL OFF. As
long as rfkill-input is loaded, that event will *always* be processed, and
it will *always* force all rfkill switches to disable all wireless
transmitters, regardless of user_claim attribute or anything else.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: Ivo van Doorn <IvDoorn@gmail.com>
Cc: Dmitry Torokhov <dtor@mail.ru>
---
net/rfkill/rfkill-input.c | 29 ++++++++++++++---------------
net/rfkill/rfkill-input.h | 1 +
net/rfkill/rfkill.c | 18 ++++++++++++++++++
3 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index 29c13d3..0fadeed 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -127,21 +127,20 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
switch (code) {
case SW_RFKILL_ALL:
/* EVERY radio type. data != 0 means radios ON */
- rfkill_schedule_set(&rfkill_wwan,
- (data)? RFKILL_STATE_ON:
- RFKILL_STATE_OFF);
- rfkill_schedule_set(&rfkill_wimax,
- (data)? RFKILL_STATE_ON:
- RFKILL_STATE_OFF);
- rfkill_schedule_set(&rfkill_uwb,
- (data)? RFKILL_STATE_ON:
- RFKILL_STATE_OFF);
- rfkill_schedule_set(&rfkill_bt,
- (data)? RFKILL_STATE_ON:
- RFKILL_STATE_OFF);
- rfkill_schedule_set(&rfkill_wlan,
- (data)? RFKILL_STATE_ON:
- RFKILL_STATE_OFF);
+ /* handle EPO (emergency power off) through shortcut */
+ if (data) {
+ rfkill_schedule_set(&rfkill_wwan,
+ RFKILL_STATE_ON);
+ rfkill_schedule_set(&rfkill_wimax,
+ RFKILL_STATE_ON);
+ rfkill_schedule_set(&rfkill_uwb,
+ ...I don't quite agree here. The SW_RFKILL_ALL key is the one send by thinkpad-acpi, what makes that key so special that is has to be handled differently then a key that only controls a single radio type? All keys should have the same rules when it is pressed, so either all keys should --
Well, first there is no KEY involved, it is a SWITCH :-) But that's not the reason it is special. What makes SW_RFKILL_ALL special, is that it is the kernel view of *The* RFKill Switch. SW_RFKILL_ALL is the event you get when the user manipulates the very *thing* that created the "rfkill switch" term. You get that event when someone moves that slider switch in the side/top of a laptop which has to kill all RF output in hardware as far as safety regulations go. Therefore, it refers to the only rfkill switch that has guidelines that say that it must always work, and that it must not be possible to override it in software. Too bad that doesn't apply to "removable" radio transmitters, like PCMCIA and ExpressCard WLAN cards, USB RF transmitters, and so on... probably, the user is expected to yank them off when he moves the switch to the "no radios working here!" position. Well, we can do better. We can make it apply to these other radio transmitters, too. So yes, it *is* special when it is doing its "power DOWN the transmitters" function. It is not special at all when it is in the "allow radios to function if they want to" position, which is why I special-cased only the "OFF" state. IMHO, that makes it special enough to implement it in a different way that is not subject to, e.g., brain damage in userspace. As for thinkpad-acpi being the only in-tree code issuing that event so far, well... I have seen laptops from many vendors with that switch, and it is likely that the firmware of at least some of these laptops let you know the state of the switch (like the thinkpad firmware does), so I'd expect more users of SW_RFKILL_ALL to show up soon. I am just paving the way. That, and as an user, I'd really like to be able to implement a KEY_RFKILL_ALL keycode to use when I don't have a proper SW_RFKILL_ALL IMO, "kill ALL radios" events are is the only kind of rfkill input event that have to *always work*, even if something in userspace tried to configure it not ...
So do keys that are pressed that only send the KEY_WLAN, KEY_BLUETOOTH or KEY_UWB signals. They all indicate the key has been pressed and the radios That is a valid point, and rfkill is supposed to do that, but making a difference between RFKILL_ALL and the individual types is wrong because that won't result in a clearly defined expected behavior for all Well the definition of "ALL radios" is the part that is the question, when the KEY_WLAN is pressed it would be "ALL WLAN radios" and should still have the same rules for allowing or disallowing userspace to overwrite the status. Ivo --
Indicate versus enforce. There is a BIG difference there, and you can see it even on how it was implemented by the laptop vendor. The enforcing switch has hardware behind it to make sure it works. For the indication keys, you IMO, the big difference between regular KEY_* and RFKILL_ALL is that RFKILL_ALL has EPO (emergency power-off) semanthics, while the others don't. KEY_WLAN is usually easily overriden in firmware and software, vendors often don't even bother to implement it in firmware, it is just software. RFKILL_ALL switches cannot be overriden at all in any hardware worth its weight, and they work even if the entire system has gone out for lunch and is deadlocked. That's quite a big difference. The only reason I don't usually call the hardware rfkill switches "radio EPO switches" is because they are not big, red, and shaped like a mushroom. But they are in fact required to act like one in airline regulations, AFAIK. And that certainly matches the good implementations of the hardware rfkill switch I know of (they wire-kill the radios, not even firmware gets in the way). So yes, I do feel RFKILL_ALL is different, and it warrants EPO semanthics in the kernel, while all other rfkill events, such as KEY_WLAN, don't. I don't feel strongly about not giving EPO semanthics to other rfkill events, More like through the new read-write/write-only rfkill class, since you have Not really. If you are concerned with a type, it is not an emergency situation, nor is it a "you are entering a no-RF-emission area" situation. There *IS* a difference when a human decides to shut down EVERYTHING regardless of type, or when he just wants the WLAN to stop wasting power but still wants Bluetooth up so that he can listen to music on his wireless headphones. And that notion carried over as the UI for circuit switches. There IS a UI notion behind "master switches", and it is very different from the notion behind "sector switches". And KEY_WLAN would just be a sector switch, with ...
You just made my 2 laptops very happy because apparently they don't behave like most keys do. ;) Laptop 1) - Key to control WLAN (Broadcom) - Key to control Bluetooth (Broadcom??) Laptop 2) - Key to control WLAN (Intel) And each key really controls the hardware, without any software required. Especially for Laptop one it will not be nice to attack RFKILL_ALL to both keys, True, but the trick is that you don't know exactly when the radio is the emergency key or not. Perhaps you do know with some hardware like thinkpad, but with my second laptop for example, it only has 1 kind of radio and that is WLAN it also has 1 key. When it is pressed, you simply don't know if it is switched off because of the no-RF area or to powersave. With my first laptop, the broadcom WLAN driver will register the key, but it doesn't know if it is alone or if Bluetooth hardware is also present. So it cannot know if it is a master Such a thing would indeed be nice, as long as you can positively identify a master switch, but as long as that is not possible/implemented it will only be confusing for driver developers, userspace developers and the users. Ivo --
You don't have a SW_RFKILL_ALL switch :-) It is the same as my ThinkPad T43, it does *NOT* have a SW_RFKILL_ALL switch, and it has a wireless config hotkey, which is handled in firmware. The firmware can wire-kill the Intel WLAN card, and it can also unplug(!) the internal Bluetooth device from the internal USB bus. You'd typically assign KEY_WLAN or something else to those keys, but NOT a (fictitious) KEY_RFKILL_ALL. Works just like a ThinkPad before you set its hotkey mask to request the firmware Those keys definately are *NOT* to have *_RFKILL_ALL attached to them by default, Then you assume it is just a normal key. If the user wants to promote that key to the Wireless EPO key, he changes the default assignment of KEY_WLAN to Correct. This is *explicitly* documented by the patches. The broadcomm driver has to assume it is a slave rfkill device, and NEVER report any input events. It has no knowledge of which platform the broadcomm chip was installed into, after all. OTOH, it *will* report the status change through the rfkill notify chain and also through the rfkill uevents, and either a platform module for your laptop, or HAL (in userspace) can trap those, and issue the relevant input events. *IF* you get the events only through the broadcomm device, that is. If you get them We document it *throughoutly*, and add a big fat warning about the misuse of RFKILL_ALL. It should be enough. Will you consider ACKing a new version of the patchset which documents better the *_RFKILL_ALL events? -- "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 --
Ok, with some additional documentation it should be sufficient for now. We can later see if minor adjustments need to be made based on userspace implementation (which with he current rfkill implementation is still very limited). Ivo --
Rework the documentation so as to make sure driver writers understand exactly where the boundaries are for input drivers related to rfkill switches, buttons and keys, and rfkill class drivers. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Cc: Ivo van Doorn <IvDoorn@gmail.com> Cc: Dmitry Torokhov <dtor@mail.ru> --- Documentation/rfkill.txt | 329 ++++++++++++++++++++++++++++++++++++++------- 1 files changed, 277 insertions(+), 52 deletions(-) diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index ec75d6d..bf8709c 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -2,82 +2,299 @@ rfkill - RF switch subsystem support ==================================== 1 Implementation details -2 Driver support -3 Userspace support +2 Kernel driver guidelines +3 Kernel API +4 Userspace support -=============================================================================== -1: Implementation details + +INTRODUCTION: The rfkill switch subsystem exists to add a generic interface to circuitry that -can enable or disable the RF output of a radio *transmitter* of any type. +can enable or disable the signal output of a wireless *transmitter* of any +type. By far, the most common use is to disable radio-frequency transmitters. -When a rfkill switch is in the RFKILL_STATE_ON, the radio transmitter is -*enabled*. When the rfkill switch is in the RFKILL_STATE_OFF, the radio -transmitter is *disabled*. +The rfkill switch subsystem offers support for keys and switches often found on +laptops to enable wireless devices like WiFi and Bluetooth to actually perform +an action. -The rfkill switch subsystem offers support for keys often found on laptops -to enable wireless devices like WiFi and Bluetooth. +The buttons to enable and disable the wireless transmitters are important in +situations where the user is for example using his laptop on a location where +radio-frequency transmitters _must_ be disabled (e.g. airplanes). ...
interaction [snip] OF AN RKFILL ? i.e., does one say "R F KILL" or does one say "rifkill" or "rufkill" or [snip] --- ~Randy --
Will do, for completeness if anything. Yeah, I somehow lost part of that sentence while editing the file or I have no idea :( I'd read it as if I were spelling "R" "F", so I think it should be an "AN". Thanks for the corrections. -- "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 --
Wouldn't that be "changes" as welll? Regards, Elias --
Yes. Thanks. ~Randy --
Wasn't it the plan to send the current hardware state as rfkill registration argument, so we can force drivers to send a valid state to rfkill? Ivo --
Yes, but IMHO we should do that in a future patch. That patch will touch every rfkill driver, so I'd rather we do that later. IMHO it is best to get the most important stuff merged, first... Then, in that future patch, we change the API, fix all in-tree drivers using that API, and update the documentation to match the new API. For now, we update the documentation to match the current API. What do you think? -- "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 --
Sounds good to me. :) Ivo --
I'll take that as an ACK :-) -- "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 --
Rework the documentation so as to make sure driver writers understand exactly where the boundaries are for input drivers related to rfkill switches, buttons and keys, and rfkill class drivers. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Acked-by: Ivo van Doorn <IvDoorn@gmail.com> Cc: Dmitry Torokhov <dtor@mail.ru> --- Ivo, This version better documents *_RFKILL_ALL. Is it good enough for an ACK for patch 14 of 15? --- Documentation/rfkill.txt | 358 +++++++++++++++++++++++++++++++++++++++------- 1 files changed, 305 insertions(+), 53 deletions(-) diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index ec75d6d..4660208 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -1,83 +1,327 @@ rfkill - RF switch subsystem support ==================================== -1 Implementation details -2 Driver support -3 Userspace support +1 Introduction +2 Implementation details +3 Kernel driver guidelines +4 Kernel API +5 Userspace support -=============================================================================== -1: Implementation details + +1. Introduction: The rfkill switch subsystem exists to add a generic interface to circuitry that -can enable or disable the RF output of a radio *transmitter* of any type. +can enable or disable the signal output of a wireless *transmitter* of any +type. By far, the most common use is to disable radio-frequency transmitters. -When a rfkill switch is in the RFKILL_STATE_ON, the radio transmitter is -*enabled*. When the rfkill switch is in the RFKILL_STATE_OFF, the radio -transmitter is *disabled*. +The rfkill switch subsystem offers support for keys and switches often found on +laptops to enable wireless devices like WiFi and Bluetooth to actually perform +an action. -The rfkill switch subsystem offers support for keys often found on laptops -to enable wireless devices like WiFi and Bluetooth. +The buttons to enable and disable the wireless transmitters ...
Yes, you can put my ack on patch 14. Thanks for the documentation update. :) --
Then, this entire batch is ready for merging. Now, if only Len would come back from wherever he disappeared to, in order to merge the two thinkpad-acpi patches, I could send it to netdev for merge. I will at least publish the entire stack as a thinkpad-acpi pre-release version, to get some testing on the real world with some power users. I am thinking about how to best handle the global states. Doing it through the rfkill class is ready, but the result was *UGLY*. More on this later. -- "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 --
Actually, I believe the correct merge order would through wireless-dev, Ivo --
Noted. At merge time (which will be as soon as the thinkpad-acpi changes hit mainline), I will send them to you, John, and linux-wireless. Unless you want me to send them all right now to linux-wireless to see if there are any comments? -- "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 --
Well why wait with merging it into wireless-dev until thinkpad-acpi is merged? I don't think there are real dependencies other then the SW_RFKILL_ALL define. Perhaps you could send the rfkill patches with SW_RADIO instead of SW_RFKILL_ALL and make the rename after the thinkpad and rfkill series have both been merged. That would probably be the fastest route for this patch series. Ivo --
Yeah, but it would be bad for the documentation, and SW_RADIO was renamed because it was an error-inducer, so I *really* don't want to attract any more eyes to rfkill WITHOUT getting that error-inducing define renamed first. OTOH, I don't want the clashes thinkpad-acpi init changes to cause a mess for whomever is going to merge rfkill, as even if I submit them now, the rfkill changes are next- material, while the thinkpad-acpi changes are merge-them-ASAP material. I will talk to Andrew Morton and see if he accepts to push the two thinkpad-acpi changes to Linus ASAP. Or maybe we will luck out and Len will show up in 72h, I think he is bound to come back really soon now. -- "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 --
I wonder why thinkpad_acpi has to go through Len, it seems to live in drivers/misc... Does it depend on some other ACPI changes that are not in mainline/-mm yet? If it not I'd probably bombard Andrew with it. Alternatively SW_RFKILL_ALL can be brought in through wireless three or I can add it to my "for_linus" branch that I want Linus to pull soon. -- Dmitry --
No, the patches in question don't depend on anything at all other than thinkpad-acpi itself. If there were no thinkpad-acpi patches "in flight" in need to get to mainline soon, there would be no problem at all... but at least one of them clashes with the SW_RFKILL_ALL patch. thinkpad-acpi merges through Len Brown because that's probably the best subsystem for it to be tied to right now. It uses various other subsystems, like the input layer, hwmon, LEDs and rfkill, but it makes extremely heavy use of the ACPI subsystem to actually *do* something. But patches to thinkpad-acpi do not HAVE to always go through Len, as I would be thankful if you could merge the input layer SW_RFKILL_ALL patch ASAP through your for_linus branch, as that's probably the fastest way to get the whole rfkill stack in its way to the linux-next tree. The SW_RFKILL_ALL patch is the only real dependency of the rfkill patches on anything. If that gets merged now, I can immediately send the rfkill stack to wireless-dev AND respin the two thinkpad-acpi patches that are pending on Len's hands to apply without issues on top of a tree that already had SW_RADIO renamed. I will send the SW_RFKILL_ALL patch in a version that applies on top of Linus git tree to you in a few moments. -- "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 --
The SW_RADIO code for EV_SW events has a name that is not descriptive enough of its intended function, and could induce someone to think KEY_RADIO is its EV_KEY counterpart, which is false. Rename it to SW_RFKILL_ALL, and document what this event is for. Keep the old name around, to avoid userspace ABI breaks. The SW_RFKILL_ALL event is meant to be used by rfkill master switches. It is not bound to a particular radio switch type, and usually applies to all types. It is semantically tied to master rfkill switches that enable or disable every radio in a system. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Acked-by: Dmitry Torokhov <dtor@mail.ru> Cc: Ivo van Doorn <IvDoorn@gmail.com> --- Documentation/laptops/thinkpad-acpi.txt | 2 +- drivers/misc/thinkpad_acpi.c | 4 ++-- include/linux/input.h | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 01c6c3d..64b3f14 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -503,7 +503,7 @@ generate input device EV_KEY events. In addition to the EV_KEY events, thinkpad-acpi may also issue EV_SW events for switches: -SW_RADIO T60 and later hardare rfkill rocker switch +SW_RFKILL_ALL T60 and later hardare rfkill rocker switch SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A Non hot-key ACPI HKEY event map: diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 3f28f6e..a111148 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1293,7 +1293,7 @@ static void tpacpi_input_send_radiosw(void) mutex_lock(&tpacpi_inputdev_send_mutex); input_report_switch(tpacpi_inputdev, - SW_RADIO, !!wlsw); + SW_RFKILL_ALL, !!wlsw); input_sync(tpacpi_inputdev); mutex_unlock(&tpacpi_inputdev_send_mutex); @@ -2199,7 +2199,7 @@ static ...
I have just done this. The patchset (with a minor fix to address an issue sparse found) has been sent to linux-wireless and John Linville for merging. -- "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 --
Currently, rfkill support for read/write rfkill switches is hacked through
a round-trip over the input layer and rfkill-input to let a driver sync
rfkill->state to hardware changes.
This is buggy and sub-optimal. It causes real problems. It is best to
think of the rfkill class as supporting only write-only switches at the
moment.
In order to implement the read/write functionality properly:
Add a get_state() hook that is called by the class every time it needs to
fetch the current state of the switch. Add a call to this hook every time
the *current* state of the radio plays a role in a decision.
Also add a force_state() method that can be used to forcefully syncronize
the class' idea of the current state of the switch. This allows for a
faster implementation of the read/write functionality, as a driver which
get events on switch changes can avoid the need for a get_state() hook.
If the get_state() hook is left as NULL, current behaviour is maintained,
so this change is fully backwards compatible with the current rfkill
drivers.
For hardware that issues events when the rfkill state changes, leave
get_state() NULL in the rfkill struct, set the initial state properly
before registering with the rfkill class, and use the force_state() method
in the driver to keep the rfkill interface up-to-date.
get_state() can be called by the class from atomic context. It must not
sleep.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: Ivo van Doorn <IvDoorn@gmail.com>
Cc: Dmitry Torokhov <dtor@mail.ru>
---
include/linux/rfkill.h | 5 ++++
net/rfkill/rfkill.c | 49 +++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index ca89ae1..844e961 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -61,6 +61,8 @@ enum rfkill_state {
* @data: Pointer to the RF button drivers private data which will be
* passed along when toggling ...