Hello John,
Here is the revised patchset to bring rfkill up to shape enough that it
becomes useable for platform drivers like thinkpad-acpi.
There are some very minor changes:
* Added a check for illegal states on rfkill_force_state() since
it is an exported function and someone might call it with wrong
parameters;
* Fix use of %u instead of %d on uevent generation for RFKILL_STATE
to match the type for enum rfkill_state;
* Minor documentation wording changes;
All the patches in this patchset have been ACKed by Ivo, the rfkill
maintainer. They're based on wireless-testing master branch, but they
apply cleanly on top of 2.6.26-rc7 as well.
No real problem was found on any of the patches in the thread they
generated last time I posted, AFAIK all doubts regarding these patches
have been explained to the satisfaction of everyone involved, and they
dealt far more with the rfkill subsystem itself than with anything any
of the patches was doing.
True, there are still shortcomings in the rfkill subsystem even after
this patchset, but that's not a problem with the patches but rather
missing features and changes that should be done on further patches.
Some of these patches are ready (e.g. extra documentation) and others (a
new hardlocked rfkill state for rfkill-state) are being tested, and will
be send to linux-wireless soon.
Please merge this patchset on wireless-testing to get it on its way to
linux-next, so that it can go to 2.6.27 when the merge window opens.
This patchset is extremely important for my thinkpad-acpi work, and for
other drivers like hp-wmi.
Note that these patches are backwards-compatible in API and ABI. No
in-tree drivers are broken by it, but it doesn't magically fixes their
rfkill support either. It just makes it possible to write drivers using
rfkill that actually work properly.
These patches went through a lot of discursion already, available at
http://thread.gmane.org/gmane.linux.kernel/664500 and a more recent
thread at http://thread.gmane.org/gmane.linux.kernel/682233 and
http://thread.gmane.org/gmane.linux.kernel.wireless.general/15677.
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 for-upstream/rfkill
Shortlog:
Henrique de Moraes Holschuh (12):
rfkill: clarify meaning of rfkill states
rfkill: fix minor typo in kernel doc
rfkill: handle SW_RFKILL_ALL events
rfkill: add parameter to disable radios by default
rfkill: add read-write rfkill switch support
rfkill: add the WWAN radio type
rfkill: rework suspend and resume handlers
rfkill: add notifier chains support
rfkill: add type string helper
rfkill: add uevent notifications
rfkill: do not allow userspace to override ALL RADIOS OFF
rfkill: document rw rfkill switches and clarify input subsystem interactions
Thank you.
--
"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
On Sun, 22 Jun 2008, Fabien Crespel wrote:
> Anyway, the whole current_state thing seems completely useless and a
> source of problems in rfkill-input, since state comparison is already
> done in rfkill, and rfkill-input is more than likely to become out of
> sync with the real state.
>
> Therefore I propose this additional patch to remove current_state
> completely from rfkill-input.
It would work fine from what I see. And it will even be beneficial in the
long run, as it will cause rfkill-input to reapply a global state, fixing
any switches that diverged from it (and are lot BLOCKED, or "claimed", etc).
Right now, this is not very useful, but when we add a sysfs interface to
interact with the global states directly, it will be.
Please send me your signed-off line, I will respin the patch to fit exactly
before the EPO patch into the patchset (so that we don't have breakage in
any intermediate step of the patchset), and send it as a block.
--
"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
Fix a minor typo in an exported function documentation
Signed-off-by: Henrique de Moraes Holschuh <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
Cc: John W. Linville <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
---
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.4
On Wed, 11 Jun 2008 20:10:53 +0300, "Tomas Winkler" <[email protected]> said:
> Not that I cannot read the code, but what this rkill class actually
> should do according your vision?
It is not a vision. I am working with what we currently have, and fixing it.
It looks like a bit more than a simple code fix, because of the extremely
sorry state the documentation for rfkill was (i.e. it was on par with what
we have for most of the stuff in the kernel), and the fact that almost nobody
really knew how to use rfkill properly given its current limitations
(especially the ones existing before my patchset), so you couldn't even find
good examples to follow.
And there is a lesson here: NOTHING that involves the input layer should
ever be merged without a damn complete usage guide to go with it :-)
There is no re-designing going on. That could be done later, I suppose,
but it is not what I am doing. At most, I am adding a feature here or there.
The documentation effort is bringing to light a lot of misconceptions about
rfkill and how to use it (and also a lot of its current limitations), and
I will address some of these limitations since I am already knee-deep into
rfkill right now anyway.
> Does it implement radio-state state machine....notification hub for
> rfkill switches ...
rfkill class: Interface between softswitch and wireless device drivers with
the rfkill subsystem. This INCLUDES sysfs and uevents, so it also includes
part of the rfkill subsystem interface to userspace.
But the rfkill class it is NOT the whole rfkill subsystem, at all. It is only
ONE of the interfaces to the rfkill subsystem. There are at least two others:
whatever is provided by rfkill-input (which includes processing of input layer
events), and whatever is provided by rfkill.h that you can call directly.
So, let me repeat it: the rfkill class is just a SUBSET of the rfkill subsystem.
> > An example:
> >
> > ipw4965 probably has two rfkill controls in itself (an input pin for a
> > hardkill line, and an R/W IO register to help its driver (ilw4965) implement
> > a rfkill softswitch). Those TWO rfkill inputs are to be combined into just
> > ONE rfkill class which will be attached to the Linux device provided by
> > ilw4965. This is the end of the story from the PoC of the ilw4965 module.
>
> iwl4965 has actually one more rf kill switch. It switches itself off
> if it goes over critical temperature.
> For NIC it looks like temporal rfkill.
We would just consider that something that looks like another hardkill input line,
and be done with it. When you synthesize the rfkill state for ipw4965, you'd use
its thermal shutdown status, its hw-rfkill-line input pin status, and its
softswitch status (the only one you can control). Everything outside of iwl4965
would still just see a single rfkill status, it doesn't matter how many internal
components contributed to that status.
--
"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
On Fri, 2008-06-06 at 11:14 -0300, Henrique de Moraes Holschuh wrote:
> On Fri, 06 Jun 2008, Dan Williams wrote:
> > Let me explain this a bit more.
> >
> > - My original request was based on my flawed understanding of the
> > current scope of the rfkill system
>
> Ok. I am keeping that in mind.
>
> > - If the rfkill system is _only_ supposed to handle switches that turn
> > the radio off automatically, then a "third state" for the rfkill class
> > really serves _no_ purpose at all, because the radio's already blocked
> > when the switch is thrown
>
> Given these rules (not documented fully yet, I shall fix it when this
> thread quiesces):
>
> 1. Every transmitter shall have ONE, and just ONE (not zero, not two,
> not more) rfkill class attached. For those transmitters lacking support
> in hardware to make it block, the drivers shall quiesce them and avoid
> doing anything to cause transmissions, or even use bus tricks to power
> the device down (i.e. the driver will emulate a switch capable of doing
> the blocking).
>
> Thus, rfkill class will give you the DEVICE (radio) rfkill block/unblock
> state on wireless devices (ignore switches for now, I will explain them
> in another email).
>
> The information of whether a transmitter is currently blocked in a way
> you can request it to be unblocked (soft-kill) or currently blocked in a
> way you cannot request it to be unblocked (hard-kill) DOES belong in
> rfkill class. Do you want/need that information, yes or no?
Yes, I want/need that information.
> > - There are drivers that implement rfkill (laptop-specific BIOS drivers)
> > that have _no_ associated transmitter device; thus the current 'struct
> > rfkill' can only be a representation of the _switch_; thus a "third
> > state" would be useless here as well (as is the toggle_radio() callback)
>
> I haven't finished replying to your other email yet, because it is not a
> fast reply (and I am in a hurry in the next two days) and I need to look
> at hp-wmi itself to understand what the issue that is causing confusion
> is. THAT reply will explain to you how it works with "pure read/write
> switches that are not in a wireless device". THEN we shall be able to
> unravel the confusion, and I will finally understand what you are trying
> to tell me (or you will understand what I am trying to tell you).
Well, it's not just hp-wmi.
On a laptop with _no_ rfkill keys and only pure input keys that get
handled by userspace or whatever, there should still be "transmitter
sw-blocked/hw-blocked/unblocked" functionality available, even though
there is no hardware rfkill key present on the system. That's another
thing I'm confused about. It seems that the rfkill class is not
appropriate for that if it's trying to also handle actual rfkill keys
too.
They are two separate things, because there are examples of hardware
that are both ways. And separating the switch bits from the transmitter
bits is the best way to accommodate both types of hardware.
Dan
> > - It just seems a lot clearer to me to have a separation between the
> > rfkill switch and the radio bits since there's no need to tie them
> > together
>
> And this is part of the confusion. So, for now, please just look at the
> question four paragraphs above, and tell me whether you want that
> information or not. I'd think you would, since you want to gray out the
> "enable radio" button when the radio is blocked by some hardware signal
> you cannot override, but I could be confused about it...
>
On Sun, 22 Jun 2008, Dmitry Torokhov wrote:
> On Sun, Jun 22, 2008 at 12:38:47PM -0300, Henrique de Moraes Holschuh wrote:
> > 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 <[email protected]>
> > Acked-by: Ivo van Doorn <[email protected]>
> > Cc: Dmitry Torokhov <[email protected]>
>
> rfkill_event() is called with handle->dev.event_lock spinlock held and
> therefore can not sleep. rfkill_epo() takes rfkill mutex and may sleep
> so it can't be used in the interrupt context. That is the reason why
> we had tasks for switching rf switches in the first place.
Will fix to schedule an immediate call to _epo in task context, that
should fix the locking issue. Thanks for noticing that one!
--
"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
On Fri, Jun 06, 2008 at 11:14:19AM -0300, Henrique de Moraes Holschuh wrote:
> 1. Every transmitter shall have ONE, and just ONE (not zero, not two,
> not more) rfkill class attached. For those transmitters lacking support
> in hardware to make it block, the drivers shall quiesce them and avoid
> doing anything to cause transmissions, or even use bus tricks to power
> the device down (i.e. the driver will emulate a switch capable of doing
> the blocking).
How do we enforce this? iwl4965 provides an rfkill device, but hp-wmi
will also provide one for the wifi. If I swap out the wireless card for
something else, I may lose the card-specific rfkill device.
--
Matthew Garrett | [email protected]
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 <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
---
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.4
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 <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
---
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 fb56690..a561e35 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 pointer to the relevant rfkill structure as a parameter,
+ * refer to include/linux/rfkill.h for the possible events.
+ *
+ * Notifiers added to this chain are to always return NOTIFY_DONE. This
+ * chain is a blocking notifier chain: notifiers can sleep.
+ *
+ * Calls to this chain may have been done through a workqueue. One must
+ * assume unordered asynchronous behaviour, there is no way to know if
+ * actions related to the event that generated the notification have been
+ * carried out already.
+ */
+int register_rfkill_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&rfkill_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_rfkill_notifier);
+
+/**
+ * unregister_rfkill_notifier - remove notifier from rfkill notifier chain
+ * @nb: pointer to the entry to remove from the chain
+ *
+ * See blocking_notifier_chain_unregister() for return value and further
+ * observations.
+ *
+ * Removes a notifier from the rfkill notifier chain.
+ */
+int unregister_rfkill_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_rfkill_notifier);
+
static void rfkill_led_trigger(struct rfkill *rfkill,
enum rfkill_state state)
@@ -62,14 +105,25 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
#endif /* CONFIG_RFKILL_LEDS */
}
+static void notify_rfkill_state_change(struct rfkill *rfkill)
+{
+ blocking_notifier_call_chain(&rfkill_notifier_list,
+ RFKILL_STATE_CHANGED,
+ rfkill);
+}
+
static void update_rfkill_state(struct rfkill *rfkill)
{
- enum rfkill_state newstate;
+ enum rfkill_state newstate, oldstate;
if (rfkill->get_state) {
mutex_lock(&rfkill->mutex);
- if (!rfkill->get_state(rfkill->data, &newstate))
+ if (!rfkill->get_state(rfkill->data, &newstate)) {
+ oldstate = rfkill->state;
rfkill->state = newstate;
+ if (oldstate != newstate)
+ notify_rfkill_state_change(rfkill);
+ }
mutex_unlock(&rfkill->mutex);
}
}
@@ -93,8 +147,10 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
rfkill->state = state;
}
- if (force || rfkill->state != oldstate)
+ if (force || rfkill->state != oldstate) {
rfkill_led_trigger(rfkill, rfkill->state);
+ notify_rfkill_state_change(rfkill);
+ }
return retval;
}
@@ -139,12 +195,20 @@ EXPORT_SYMBOL(rfkill_switch_all);
*/
int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
{
+ enum rfkill_state oldstate;
+
if (state != RFKILL_STATE_OFF &&
state != RFKILL_STATE_ON)
return -EINVAL;
mutex_lock(&rfkill->mutex);
+
+ oldstate = rfkill->state;
rfkill->state = state;
+
+ if (state != oldstate)
+ notify_rfkill_state_change(rfkill);
+
mutex_unlock(&rfkill->mutex);
return 0;
--
1.5.5.4
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 <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
---
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,
+ RFKILL_STATE_ON);
+ rfkill_schedule_set(&rfkill_bt,
+ RFKILL_STATE_ON);
+ rfkill_schedule_set(&rfkill_wlan,
+ RFKILL_STATE_ON);
+ } else
+ rfkill_epo();
break;
default:
break;
diff --git a/net/rfkill/rfkill-input.h b/net/rfkill/rfkill-input.h
index 4dae500..f63d050 100644
--- a/net/rfkill/rfkill-input.h
+++ b/net/rfkill/rfkill-input.h
@@ -12,5 +12,6 @@
#define __RFKILL_INPUT_H
void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
+void rfkill_epo(void);
#endif /* __RFKILL_INPUT_H */
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index dd1c3f1..7d07175 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -182,6 +182,24 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
EXPORT_SYMBOL(rfkill_switch_all);
/**
+ * rfkill_epo - emergency power off all transmitters
+ *
+ * This kicks all rfkill devices to RFKILL_STATE_OFF, ignoring
+ * everything in its path but rfkill_mutex.
+ */
+void rfkill_epo(void)
+{
+ struct rfkill *rfkill;
+
+ mutex_lock(&rfkill_mutex);
+ list_for_each_entry(rfkill, &rfkill_list, node) {
+ rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF, 1);
+ }
+ mutex_unlock(&rfkill_mutex);
+}
+EXPORT_SYMBOL_GPL(rfkill_epo);
+
+/**
* rfkill_force_state - Force the internal rfkill radio state
* @rfkill: pointer to the rfkill class to modify.
* @state: the current radio state the class should be forced to.
--
1.5.5.4
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 <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
---
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 3c77734..dd1c3f1 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -386,12 +386,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=%d", rfkill->state);
+ return error;
+}
+
static struct class rfkill_class = {
.name = "rfkill",
.dev_release = rfkill_release,
.dev_attrs = rfkill_dev_attrs,
.suspend = rfkill_suspend,
.resume = rfkill_resume,
+ .dev_uevent = rfkill_dev_uevent,
};
static int rfkill_add_switch(struct rfkill *rfkill)
@@ -566,11 +605,14 @@ static int __init rfkill_init(void)
return error;
}
+ register_rfkill_notifier(&rfkill_blocking_uevent_nb);
+
return 0;
}
static void __exit rfkill_exit(void)
{
+ unregister_rfkill_notifier(&rfkill_blocking_uevent_nb);
class_unregister(&rfkill_class);
}
--
1.5.5.4
On Sun, 22 Jun 2008, Fabien Crespel wrote:
> I've been testing this series of patch today for a new version of
> asus-laptop, and this patch ("rfkill: do not allow userspace to override
> ALL RADIOS OFF") introduces a bug in rfkill-input.
More than one, apparently. Dmitry pointed out that _epo needs to be called
in task context, which rfkill-input was failing to do.
> rfkill_epo() doesn't change the current_state of the tasks, and the
> various calls to rfkill_schedule_set(..., RFKILL_STATE_ON) don't work if
> the last current_state stored was already RFKILL_STATE_ON.
>
> Anyway, the whole current_state thing seems completely useless and a
> source of problems in rfkill-input, since state comparison is already
> done in rfkill, and rfkill-input is more than likely to become out of
> sync with the real state.
>
> Therefore I propose this additional patch to remove current_state
> completely from rfkill-input.
I would like to get rid of it, but I need some sleep before I can think
clearly about this issue.
--
"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
Unfortunately, instead of adding a generic Wireless WAN type, a technol=
ogy-
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 a=
dded
as most devices really want to use KEY_WLAN for WWAN control (in a cycl=
e of
none, WLAN, WWAN, WLAN+WWAN) and need no specific keycode added.
Signed-off-by: Henrique de Moraes Holschuh <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
Cc: I=C3=B1aky P=C3=A9rez-Gonz=C3=A1lez <[email protected]=
>
Cc: John W. Linville <[email protected]>
Cc: David S. Miller <[email protected]>
---
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,
};
=20
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);
=20
static void rfkill_event(struct input_handle *handle, unsigned int typ=
e,
unsigned int code, int data)
@@ -126,6 +127,9 @@ static void rfkill_event(struct input_handle *handl=
e, unsigned int type,
switch (code) {
case SW_RFKILL_ALL:
/* EVERY radio type. data !=3D 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);
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 4ae4486..79f3bbb 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -180,6 +180,9 @@ static ssize_t rfkill_type_show(struct device *dev,
case RFKILL_TYPE_WIMAX:
type =3D "wimax";
break;
+ case RFKILL_TYPE_WWAN:
+ type =3D "wwan";
+ break;
default:
BUG();
}
--=20
1.5.5.4
On Mon, 23 Jun 2008, Dmitry Torokhov wrote:
> On Mon, Jun 23, 2008 at 02:22:07AM -0300, Henrique de Moraes Holschuh wrote:
> > On Sun, 22 Jun 2008, Fabien Crespel wrote:
> > > rfkill_epo() doesn't change the current_state of the tasks, and the
> > > various calls to rfkill_schedule_set(..., RFKILL_STATE_ON) don't work if
> > > the last current_state stored was already RFKILL_STATE_ON.
> > >
> > > Anyway, the whole current_state thing seems completely useless and a
> > > source of problems in rfkill-input, since state comparison is already
> > > done in rfkill, and rfkill-input is more than likely to become out of
> > > sync with the real state.
>
> Real state of what? The state of rfkill-input represents desired
> (target) state of a group of RF switches of certain type (all WIFI or
> all Bluetooth, etc) and may indeed be different from the state of
> individual transmitter.
Indeed. rfkill-input takes care of what I call "global state (per rfkill
type)". We don't export that to userspace yet, the only way to interact
with them is through input events right now. This will change, eventually.
That said, there is no need to try to avoid extra calls to
rfkill_switch_all, which AFAIK is all current_state is good for.
I tested Fabien's patch here, and it does seem to work well. I added some
guards to EPO so that it just ignores any attempts to queue
rfkill_switch_all calls while a rfkill_epo call is queued, as well.
> > > Therefore I propose this additional patch to remove current_state
> > > completely from rfkill-input.
> >
> > I would like to get rid of it, but I need some sleep before I can think
> > clearly about this issue.
>
> I think the best solution for now would be to add 'force' argument to
> rfkill_switch_all that would override rfkill->user_claim.
No, rfkill-input is not to override rfkill->user_claim except for EPO. Even
if we added a force parameter to rfkill_switch_all, rfkill-input wouldn't be
able to use it (except in the EPO path, that has a better helper to use
anyway: rfkill_epo()).
I fixed the whole EPO issue already, btw. I tried with Fabien's patch, and
on top of it I applied a modified version of the EPO patch that calls
rfkill_epo through the generic work queue and ignores other attempts to
queue rfkill_switch_all while rfkill_epo hasn't run yet (on the grounds that
rfkill_epo would override them anyway, and that when in doubt of what should
be happening because we got a bunch of confusing events all piled up, we
want EPO to win).
I am just waiting for Fabien's signed-off-by line, so that I can push v3 of
the patchset with the bug fixes.
I am also looking at a way to make rfkill-input restore the previous global
states when it receives an SW_RFKILL_ALL ON sometime after an EPO. That's
how I'd prefer it to act (so I will make it selectable, and you guys tell me
what the default should be).
--
"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
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 <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
---
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 a561e35..3c77734 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -224,34 +224,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 *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.4
Hello there,
I've been testing this series of patch today for a new version of asus-laptop,
and this patch ("rfkill: do not allow userspace to override ALL RADIOS OFF")
introduces a bug in rfkill-input.
rfkill_epo() doesn't change the current_state of the tasks, and the various calls
to rfkill_schedule_set(..., RFKILL_STATE_ON) don't work if the last current_state
stored was already RFKILL_STATE_ON.
Anyway, the whole current_state thing seems completely useless and a source of
problems in rfkill-input, since state comparison is already done in rfkill, and
rfkill-input is more than likely to become out of sync with the real state.
Therefore I propose this additional patch to remove current_state completely from
rfkill-input.
- Fabien.
---
--- a/net/rfkill/rfkill-input.c 2008-06-22 21:16:15.000000000 +0200
+++ b/net/rfkill/rfkill-input.c 2008-06-22 21:20:01.000000000 +0200
@@ -30,27 +30,15 @@
spinlock_t lock; /* for accessing last and desired state */
unsigned long last; /* last schedule */
enum rfkill_state desired_state; /* on/off */
- enum rfkill_state current_state; /* on/off */
};
static void rfkill_task_handler(struct work_struct *work)
{
struct rfkill_task *task = container_of(work, struct rfkill_task, work);
- enum rfkill_state state;
mutex_lock(&task->mutex);
- /*
- * Use temp variable to fetch desired state to keep it
- * consistent even if rfkill_schedule_toggle() runs in
- * another thread or interrupts us.
- */
- state = task->desired_state;
-
- if (state != task->current_state) {
- rfkill_switch_all(task->type, state);
- task->current_state = state;
- }
+ rfkill_switch_all(task->type, task->desired_state);
mutex_unlock(&task->mutex);
}
@@ -94,7 +82,6 @@
.mutex = __MUTEX_INITIALIZER(n.mutex), \
.lock = __SPIN_LOCK_UNLOCKED(n.lock), \
.desired_state = RFKILL_STATE_ON, \
- .current_state = RFKILL_STATE_ON, \
}
static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
On Sun, 08 Jun 2008, Matthew Garrett wrote:
> On Fri, Jun 06, 2008 at 11:14:19AM -0300, Henrique de Moraes Holschuh wrote:
> > 1. Every transmitter shall have ONE, and just ONE (not zero, not two,
> > not more) rfkill class attached. For those transmitters lacking support
> > in hardware to make it block, the drivers shall quiesce them and avoid
> > doing anything to cause transmissions, or even use bus tricks to power
> > the device down (i.e. the driver will emulate a switch capable of doing
> > the blocking).
>
> How do we enforce this? iwl4965 provides an rfkill device, but hp-wmi
> will also provide one for the wifi. If I swap out the wireless card for
> something else, I may lose the card-specific rfkill device.
Let's define some very STRICT terminology to avoid confusion.
rfkill class: the sysfs rfkill class, related to struct rfkill.
rfkill class attached [to a Linux struct device]: a device whose
struct device was given to rfkill_allocate() as the parent.
transmitter: part of a wireless device. So far, every wireless device
I have seen has only one transmitter from the kernel PoV. A device
with two transmitters would be able to transmit two different information
streams at the same time, with different parameters (such as frequency,
power).
transmitter != switch, so hp-wmi, thinkpad-acpi, and anything else that is
not an actual wireless hardware device IS NOT INCLUDED in that "one and just
one" constraint. In fact, thinkpad-acpi has two rfkill classes attached to
its main platform device, one for the bluetooth softswitch, and another for
the wwan softswitch.
So, "Every transmitter shall have ONE and just ONE rfkill class attached."
just means that you call rfkill_allocate with that device as the parent just
ONCE per transmitter (and everything I have seen so far has just one
transmitter).
Which also means that, for wireless drivers (which have transmitters), you
need to synthesize the "device rfkill state" to give to that rfkill class.
THE TRANSMITTER MIGHT BE UNDER THE EFFECT OF MORE THAN ONE RFKILL LINE.
And if the device [transmitter] has NO rfkill capabilities by itself, we
emulate the minimum of one in software [per transmitter]. If the device
has one input pin for rfkill, that one is also taken into account when
generating the state for the ONLY ONE rfkill class attached to that device
[per transmitter], etc.
Now, firmware switches are different, and something for another email that
I haven't typed in yet (busy in real life right now).
An example:
ipw4965 probably has two rfkill controls in itself (an input pin for a
hardkill line, and an R/W IO register to help its driver (ilw4965) implement
a rfkill softswitch). Those TWO rfkill inputs are to be combined into just
ONE rfkill class which will be attached to the Linux device provided by
ilw4965. This is the end of the story from the PoC of the ilw4965 module.
hp-wmi probably has one softswitch it controls, that ends up connected to
that input pin in the ipw4965 card so you end up being able to use a hp-wmi
softswitch to hardkill the ipw4965 card. This IS expected, and it will not
matter or break anything. In the current rfkill incarnation, rfkill doesn't
understand or know or want to know about rfkill switch topology as it
stands.
Did I manage to get the idea across, this time? Remember, I am not
describing the rfkill class interactions for switches in that email, JUST
for wireless drivers, which hp-wmi, thinkpad-acpi, etc are not...
What happens on the hp-wmi side when the ipw4965 card is removed, is to be
explained in the other email about switches, but it is not much. Basically,
hp-wmi has to be written in such a way that it won't matter for the user,
and THERE is the real reason why one must never confuse the softswitch
control with input devices. Remember that as long as rfkill-input is
loaded, if anything sends a "change all WLAN rfkill switches" input event,
all WLAN rfkill switches WILL be changed, regardless of whether they are
wired among themselves, or completely independent.
--
"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
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 <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
Cc: John W. Linville <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
---
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 be a value from enum rfkill_type.
- * @state: State of the switch (on/off).
+ * @state: State of the switch, "ON" means radio can operate.
* @user_claim_unsupported: Whether the hardware supports exclusive
* RF-kill control by userspace. Set this before registering.
* @user_claim: Set when the switch is controlled exlusively by userspace.
--
1.5.5.4
On Thu, 05 Jun 2008 10:46:47 -0400, "Dan Williams" <[email protected]> said:
> On Thu, 2008-06-05 at 10:03 -0300, Henrique de Moraes Holschuh wrote:
> > On Thu, 05 Jun 2008, Dan Williams wrote:
> > > a) hard switches that kill the radio and notify the driver
> >
> > rfkill class material, yes.
> >
> > > b) hard switches that notify the driver but do not directly kill the
> > > radio
> >
> > These are input devices, and not directly related to the rfkill class
> > (but related to the rfkill subsystem).
>
> So in your mind, these drivers would re-emit state changes of their
> rfkill switches back into the kernel input layer, correct?
Yes. And the funny thing is, they are supposed not to ACT by themselves
at all, they are to wait for someone to tell them to through the rfkill class.
(NOTE: this applies only to scenario (b) above. It is NOT valid for other
scenarios like (a) or (c) or any other).
To be more clear:
MODULE FOO (driver for the foo wireless device).
* Ties to the input layer, and reports pressure of the "hard switch that notify
the driver (MODULE FOO) but do not directly kill the radio (device foo)" using
the proper input event.
It does NOTHING further with the information that the button/switch was pressed.
Really. It just generates the input event and sends it.
* Uses the rfkill class connected to the device foo in the device tree to receive
commands to toggle the real device rfkill state.
If some input event is indeed supposed to cause the device state to change, the
driver gets called back through the rfkill class toggle_radio() hook.
So, the button press would go through the input layer to SOMETHING ELSE (likely
to rfkill-input), which would take the **policy** decision of what to do with
that event, and then cause the appropriate rfkill class instances to change their
state.
So, MODULE FOO would get a hook call (toggle_radio) through the rfkill class, in
order to do something about the input event MODULE FOO itself generated.
Or it might not get that hook call, if the local admin wanted something different
to happen.
> > > c) hard switches that disconnect the device from its bus entirely (most
> > > BT rfkill)
> >
> > These are also rfkill class material.
> >
> > > d) hard switches that notify BIOS only (not the driver) and rely on
> > > special laptop drivers (hp-wmi, toshiba-laptop, etc) to notify the
> > > system
> >
> > If they just notify the BIOS, they are input devices. If they cause the
> > BIOS to mess with the transmitters, they are rfkill class material.
>
> Obviously here, the laptop specific driver would re-emit the state
> change into the the kernel input layer since it is handled by a
> completely separate driver than the radio itself is handled by?
Correct. The platform driver might actually also register notifier callbacks
on the rfkill subsystem, and, for example, automatically promote all b43
rfkill status changes into input events if this is the correct thing to
do for THAT specific platform (it is NOT the correct thing to do by
default, so b43 can't do it itself).
> > > e) keyboard "soft" switches that are simply input layer buttons (like Fn
> > > +F5 on thinkpads) and don't toggle
> >
> > These are input devices in almost all cases. But since you brought up
> > thinkpads, I better warn you that the Fn+F5 in a ThinkPad, depending on
> > thinkpad BIOS revision and ACPI HKEY mask state, *is* active and will
> > mess with the transmitters directly (and thus it is not an input
> > device). thinkpad-acpi forces it to "just an input device" state by
> > default to keep things sane.
> >
> > > Besides that, we can rfkill radios in software through commands like
> > > "iwconfig wlan0 txpower off".
> >
> > Yeah. This could be also rfkill material, if you want to have rfkill as
> > another *way* to interact with the same functionality. It could cause
> > some minor issues (like which power do I set the transmitter to, if it
> > is turned off by txpower off, but someone undos that through rfkill?)
> > but it would work.
>
> I want _one_ interface to get the radio block state (either blocked or
> unblocked) for any device that has a radio, be it WiFi, WiMAX, BT, WWAN,
> UWB, etc.
rfkill is supposed to be it, yes.
> I also want _one_ interface to determine how many rfkill switches the
> system has, and what their state is (either blocking radios or not
> blocking radios). This is what the current rfkill system seems to
> provide.
It provides that information PARTIALLY. Currently, you can enumerate
all rfkill interfaces through sysfs, and you can interact with each
one separately. However, you cannot interact with the internal type-
specific global switches (which are NOT rfkill class) inside
rfkill-input.
I haven't solved that problem to my satisfaction yet, so the only patch
I have for it has not seen the light of the net. It is too ugly to live
IMHO.
So, I'd say the individual rfkill class sysfs interface is nearly complete
(we need to add the third state or do something else to tell you when
a radio is blocked and cannot be unblocked).
But the rfkill subsystem interface (deals with rfkill-input) to userspace
is NOT feature-complete yet. This really, really shouldn't bother NM,
it is HAL-layer level stuff.
> I don't want to have to use SIOCGIWTXPOW for wifi, something else for
> BT, something else for WWAN, something else for WiMAX, just to figure
> out whether a radio is blocked or unblocked. That's just wrong but
> something that we can eventually fix.
Well, the problem is that SIOCGIWTXPOW is NOT a direct equivalent to rfkill,
rfkill has no concept of attenuation (or amplification, for that matter).
It is up for the wireless people to decide if their SIOCGIWTXPOW controls
are the same exposed by rfkill or not, and what to do when reenabling from
a txpower off (probably you will have to recall the last non-off txpower
and use that). The rfkill subsystem really doesn't care, as long as you
don't do it by adding more than one rfkill class to the same device.
> So, it seems I was confused about the scope of the current rfkill
> system. While it probably should be "rfkill_switch" I'm not sure we can
> change that now. While it would be nice to have a single interface to
> query radio power state, that can be a future improvement.
I think it is a better idea to fix what we have, first. Let it settle
down, and then take the full view and check if you need to enhance it,
replace it, or design something else that goes along with it. I'd bet on
the third option, but it is a bit early to tell.
> > > Only (a), (b), (c), and sometimes (d) actually kill the radio and block
> > > changes by the user. Otherwise, it's up to userspace to kill the radios
> > > when events come in.
> >
> > If it doesn't kill the radio, it is not rfkill class material. At most,
> > it could be an input device that issues events related to rfkill.
>
> Right, I misunderstood the original scope of the kernel rfkill stuff. I
> thought it covered everything except case E (pure input-layer only
> buttons).
It sort of does, in the sense that rfkill (not the rfkill class!) defines
how the input layer should be used for these events.
> I'd like the rfkill system to eventually cover cases A - D, and also
> handle radio block state notifications and queries. I'm willing to help
> code that. Actual power levels of the radio is probably best left up to
> the device-specific subsystem, but at least the state (and events!) of
> "radio now blocked" or "radio now unblocked" are useful to have.
Unless I missed something, I have provided you with that for cases
A to D already. What I didn't provide you with was "radio now blocked and
you cannot unblock it", *yet*. You have convinced me it is something
needed, and if left to my own devices, I will implement it as a third
state.
HOWEVER, rfkill can't provide you with "radio is enabled, configured,
operational and transmitting" status. It really can't say much of what
is happening in the unblocked state.
> > Currently we can't differentiate "block changes by the user" from "the
> > kernel can change the state if you ask it to". I agree this is a
> > desireable feature, and I'd rather add a third rfkill_state to propagate
> > that information.
>
> Well... I still think this is best as a _radio_ property, not as a
> killswitch property. Physical switches are physical, you can't change
> the state and thus the third state here isn't useful. If we separate
> switch state from radio power state that makes it clear (at least to
> me).
But then you have more than one "switch" per radio, which needs changes
to rfkill (currently, you are NOT to do it).
Currently, one is to think of a rfkill class as the representation of
the "radio property". Which means you *lose the information* of which
underlying hardware/firmware reason the device has to be blocked.
I think we are actually better off by losing that information, it is
not useful for UIs (you need to know the device is force-blocked, not
WHY it is blocked or force-blocked -- that is highly platform-specific).
> Since the current rfkillX device is the _switch_, and since I'm not
> aware of any machines where the BIOS synthesizes a toggle state from a
> non-toggle button, maybe we should punt this until such a device
> actually turns up?
The current rfkillX device represents the radio state, which means it might
need to synthesize it from various hardware bits.
E.g. Let's look at a possible conversion of IPW2200 to the rfkill class.
The IPW2200 driver has TWO rfkill "registers":
R1 - Read/Write, controlled by the driver
R2 - Read-Only, reflects an input pin in the hardware and cannot be
overriden.
The IPW2000 driver would register just *one* instance of the rfkill class,
and it would return the status as this.
Assume R1 active high, and R2 active high. Active means BLOCK RADIO.
rfkill_status = (R1 | R2) ? RFKILL_STATUS_OFF : RFKILL_STATUS_ON.
I.e. if either one (or both) of the registers are blocking the radio, it
reports the status as RFKILL_STATUS_OFF. Otherwise, it reports the status
as RFKILL_STATUS_ON (unblocked).
Now, for the toggle_radio function in pseudo-code:
switch (new_state) {
case RFKILL_STATUS_ON:
if (R2) {
R1 = 1; /* fail safe, least surprise */
return -EPERM; /* cannot override! */
}
R1 = 0;
break;
case RFKILL_STATUS_OFF:
R1 = 1;
break;
}
There are possible variations, the most pressing one that comes to mind
is whether we should force the R1 switch to 1 or 0 when R2 is 1 on the
RFKILL_STATUS_ON branch. I used the "won't EVER cause the radio to be
unblocked by surprise" alternative.
However, now userspace really gets to know if the ipw2200 radio is blocked or not,
it doesn't have to hunt down two different rfkill class instances for it. And it
just needs to listen to uevents (which HAL should be taught to export to DBUS) for
ipw2200 to know when the status changes, no pooling or even reading of sysfs
attributes would be required.
If you wanted to also handle txpower off through rfkill, you'd take the state of
txpower into consideration on the code above, and still have only ONE rfkillX
instance for the ipw2200 device.
> > > The only thing I personally care about is separating radio state from
> > > switch state so that I can distinguish a softkill (via ex. iwconfig
> > > wlan0 txpower off) from a hardkill via a real killswitch.
> >
> > Ok, so what you care about is to know if you COULD CHANGE THE STATE,
> > correct?
>
> Could change the radio _block_ state, yes. rfkill switch state no,
I mean the radio _block_ state. See above. One rfkill class per device,
synthesizing the state of n, n>=1 real switches. So, you get the radio
block state from it.
> because I don't know of any examples of those and frankly I think it's
> easier to just make the user flip the switch again. Keeping it simpler
> is better.
I'd agree with this view, least surprise is good, and the way the whole
rfkill idea was engineered to leave the transmitter BLOCKED in cause of
doubt.
> > The third state would tell you that.
> >
> > > Why should a "device rfkill state" be in a separate module? Radio state
> > > _is_ rfkill state. rfkill switches turn the radio on or off but
> >
> > device-wide rfkill state is rfkill state. radio state could be
> > anything.
>
> I started using "radio block state" in this mail instead.
Ok, radio block state is also good. As long as we both know exactly
what we mean by it.
> > But yes, I understand what you want. The two states you talk about are
> > the same if you have only ONE rfkill class attached to a device, and
> > they are different (but related) things when you have MORE than one
> > rfkill class attached to a device.
>
> What situations would have more than one rfkill class attached to the
> device?
If you try to model IPW2200 or other hardware with many rfkill input signals
as one signal per rfkill class. That's something that is probably NOT a good
idea at all.
> > IMO, we should attach just one rfkill class per transmitter device, and
> > handle the "you cannot change the state" possibility by adding a third
> > state to rfkill_state.
>
> Right about the one rfkill class per device than drives a killswitch.
> But that's not necessarily the transmitter device. It might be a child
> of the laptop module if it's a BIOS switch that also kills the radio
> automatically. In the case of hp-wmi, it provides 3 different rfkill
> class devices.
Which is why I want to do it in a way we don't have to know what is a
child of what, slaved to what, master of what...
> > > devices should have _one_ method of turning themselves off through
> > > either hardware or software, and the system that provides that method
> > > should be the rfkill system.
> >
> > We don't agree there. If you use "devices should have _one_ method of
> > *forcing themselves off* outside of the normal control path of interface
> > up/down", THEN we agree.
>
> Right, all devices with transmitters should have _one_ method of
> blocking and unblocking their transmitters.
OK.
> > The reason is extremely simple: rfkill CANNOT TURN SOMETHING ON. If it
> > *was* ON, and you used rfkill to turn it OFF, than yes, when you "stop
> > turning it OFF through rfkill", it will go back to ON.
> >
> > But if it was not ON in the first place, it won't go to ON when you stop
> > turning it OFF through rfkill. It will just remain OFF, unless
> > something else that is NOT rfkill hooks into the event and takes the
> > oportunity to do whatever is needed (such as configure the interface and
> > bring it up) to bring the device to ON state.
>
> Good point.
It is a very central point to rfkill, if you lose track of it, things get
very confusing, very very quickly.
> > > > Anyway, if we are to use various *related* rfkill switches per device,
> > > > rfkill needs further changes, including an extra callback into the
> > > > driver, so as to be able to export the device rfkill state also in all
> > > > switch rfkill state events (otherwise these events become quite useless
> > > > for many uses).
> > >
> > > But yes, there would need to be a "device rfkill state" changed event
> > > and another call to get the device rfkill state.
> >
> > Indeed. It is a possiblity. I still feel a third addition to
> > rfkill_state and the use of only ONE rfkill class per transmitter device
> > is a better way to do it.
>
> As I said above, I think I disagree about the third state. I think the
> best thing to do is keep the general rfkill switch operation as it is
> now (only 2 states, blocked and unblocked), and eventually add a
> standard "radio block state" sysfs entry on the _transmitter_ device
> with 3 values: hw-blocked, sw-blocked, and unblocked.
If we mandate the one-rfkill-class-per-transmitter rule, you now have two
attributes that say the very same thing, except that the old one (the one
we currently have) lacks the force-blocked state. So basically, you just
avoided a minor ABI change by not adding the third state to rfkill_state.
If we mandate the one-rfkill-class-per-kill-line rule, you will add
complexity, now a driver like IPW2200 would need at least two rfkill
class instances. In THIS case, the new attribute conveys interesting
information, but OTOH, NM and any user application will have to deal
with more than one rfkill sysfs instance per device, and we will have
weird issues to deal with, like how to deal with user_claim...
The reason I insist on the third state so much is that rfkill *really*
was not designed to cope with two or more per transmitter. You now
have to mess with various rfkill switches to get something to happen
(and most of the time, all but one will EPERM you, because they are
read-only, and my subconsious mind is severely screaming up this is
a BAD IDEA, we currently forbid read-only switches and I recall there
were some subtle issues with the input layer events for read-only
stuff).
> Does that sound OK? I feel like I have a better understanding of what
It WOULD work, I think. But for the reasons above, I am more inclined
to add a third state. It is much simpler on the code, and it has no
drawbacks I can see, while the multiple rfkill per device approach does
have some (and it gives me a bad feeling every time I consider it).
What whould be the technical advantages of a separate attribute
from your UI (NM) point of view? That is not yet clear to me, at
all. Assume you will only get ONE rfkillX interface per device,
which means it DOES reflect the block/unblock state of the device.
--
"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
This is how I view the requirements/state of rfkill system. Not trying
to come with any design yet or mapping it to what we currently have in
rfkill. Just clearing the table for myself and maybe others.
1. radio state is inclusive disjunction or conjunction of all rfkill
switches (depends on what 0,1 means)
* user space and kernel components (e.g. mac80211) must be notified
about change in radio state
2. rfkill switches types
a. sw - can be switched by software means
b. hw - must be manually toggled..
c. devices switch - switch has direct connection to device (hw switches only)
device provides the input to the radio state
c. input switch - device is requested to change radio state (hw and
sw switches)
3. state of each rfkill switch has to be visible to user space, also
sw and hw attributes of switch must be known to user space.
4. switch state must be preserved across reboot and suspend/resume,
hw switch of course might be changed even when computer is powered off
5. There must be at least one sw input switch.
Tomas
On Tue, Jun 10, 2008 at 7:11 AM, Henrique de Moraes Holschuh
<[email protected]> wrote:
> On Sun, 08 Jun 2008, Matthew Garrett wrote:
>> On Fri, Jun 06, 2008 at 11:14:19AM -0300, Henrique de Moraes Holschuh wrote:
>> > 1. Every transmitter shall have ONE, and just ONE (not zero, not two,
>> > not more) rfkill class attached. For those transmitters lacking support
>> > in hardware to make it block, the drivers shall quiesce them and avoid
>> > doing anything to cause transmissions, or even use bus tricks to power
>> > the device down (i.e. the driver will emulate a switch capable of doing
>> > the blocking).
>>
>> How do we enforce this? iwl4965 provides an rfkill device, but hp-wmi
>> will also provide one for the wifi. If I swap out the wireless card for
>> something else, I may lose the card-specific rfkill device.
>
> Let's define some very STRICT terminology to avoid confusion.
>
> rfkill class: the sysfs rfkill class, related to struct rfkill.
>
> rfkill class attached [to a Linux struct device]: a device whose
> struct device was given to rfkill_allocate() as the parent.
>
> transmitter: part of a wireless device. So far, every wireless device
> I have seen has only one transmitter from the kernel PoV. A device
> with two transmitters would be able to transmit two different information
> streams at the same time, with different parameters (such as frequency,
> power).
>
> transmitter != switch, so hp-wmi, thinkpad-acpi, and anything else that is
> not an actual wireless hardware device IS NOT INCLUDED in that "one and just
> one" constraint. In fact, thinkpad-acpi has two rfkill classes attached to
> its main platform device, one for the bluetooth softswitch, and another for
> the wwan softswitch.
>
> So, "Every transmitter shall have ONE and just ONE rfkill class attached."
> just means that you call rfkill_allocate with that device as the parent just
> ONCE per transmitter (and everything I have seen so far has just one
> transmitter).
Not that I cannot read the code, but what this rkill class actually
should do according your vision?
Does it implement radio-state state machine....notification hub for
rfkill switches ...
>
> Which also means that, for wireless drivers (which have transmitters), you
> need to synthesize the "device rfkill state" to give to that rfkill class.
> THE TRANSMITTER MIGHT BE UNDER THE EFFECT OF MORE THAN ONE RFKILL LINE.
>
> And if the device [transmitter] has NO rfkill capabilities by itself, we
> emulate the minimum of one in software [per transmitter]. If the device
> has one input pin for rfkill, that one is also taken into account when
> generating the state for the ONLY ONE rfkill class attached to that device
> [per transmitter], etc.
>
> Now, firmware switches are different, and something for another email that
> I haven't typed in yet (busy in real life right now).
>
> An example:
>
> ipw4965 probably has two rfkill controls in itself (an input pin for a
> hardkill line, and an R/W IO register to help its driver (ilw4965) implement
> a rfkill softswitch). Those TWO rfkill inputs are to be combined into just
> ONE rfkill class which will be attached to the Linux device provided by
> ilw4965. This is the end of the story from the PoC of the ilw4965 module.
>
iwl4965 has actually one more rf kill switch. It switches itself off
if it goes over critical temperature.
For NIC it looks like temporal rfkill.
Tomas
> hp-wmi probably has one softswitch it controls, that ends up connected to
> that input pin in the ipw4965 card so you end up being able to use a hp-wmi
> softswitch to hardkill the ipw4965 card. This IS expected, and it will not
> matter or break anything. In the current rfkill incarnation, rfkill doesn't
> understand or know or want to know about rfkill switch topology as it
> stands.
>
> Did I manage to get the idea across, this time? Remember, I am not
> describing the rfkill class interactions for switches in that email, JUST
> for wireless drivers, which hp-wmi, thinkpad-acpi, etc are not...
>
> What happens on the hp-wmi side when the ipw4965 card is removed, is to be
> explained in the other email about switches, but it is not much. Basically,
> hp-wmi has to be written in such a way that it won't matter for the user,
> and THERE is the real reason why one must never confuse the softswitch
> control with input devices. Remember that as long as rfkill-input is
> loaded, if anything sends a "change all WLAN rfkill switches" input event,
> all WLAN rfkill switches WILL be changed, regardless of whether they are
> wired among themselves, or completely independent.
>
> --
> "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 <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
---
include/linux/rfkill.h | 5 ++++
net/rfkill/rfkill.c | 53 +++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 55 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 radio state.
* @toggle_radio(): Mandatory handler to control state of the radio.
+ * @get_state(): handler to read current radio state from hardware,
+ * may be called from atomic context, should return 0 on success.
* @led_trigger: A LED trigger for this button's LED.
* @dev: Device structure integrating the switch into device tree.
* @node: Used to place switch into list of all switches known to the
@@ -80,6 +82,7 @@ struct rfkill {
void *data;
int (*toggle_radio)(void *data, enum rfkill_state state);
+ int (*get_state)(void *data, enum rfkill_state *state);
#ifdef CONFIG_RFKILL_LEDS
struct led_trigger led_trigger;
@@ -95,6 +98,8 @@ void rfkill_free(struct rfkill *rfkill);
int rfkill_register(struct rfkill *rfkill);
void rfkill_unregister(struct rfkill *rfkill);
+int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state);
+
/**
* rfkill_get_led_name - Get the LED trigger name for the button's LED.
* This function might return a NULL pointer if registering of the
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 3edc585..4ae4486 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -62,19 +62,39 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
#endif /* CONFIG_RFKILL_LEDS */
}
+static void update_rfkill_state(struct rfkill *rfkill)
+{
+ enum rfkill_state newstate;
+
+ if (rfkill->get_state) {
+ mutex_lock(&rfkill->mutex);
+ if (!rfkill->get_state(rfkill->data, &newstate))
+ rfkill->state = newstate;
+ mutex_unlock(&rfkill->mutex);
+ }
+}
+
static int rfkill_toggle_radio(struct rfkill *rfkill,
enum rfkill_state state)
{
int retval = 0;
+ enum rfkill_state oldstate, newstate;
+
+ oldstate = rfkill->state;
+
+ if (rfkill->get_state &&
+ !rfkill->get_state(rfkill->data, &newstate))
+ rfkill->state = newstate;
if (state != rfkill->state) {
retval = rfkill->toggle_radio(rfkill->data, state);
- if (!retval) {
+ if (!retval)
rfkill->state = state;
- rfkill_led_trigger(rfkill, state);
- }
}
+ if (rfkill->state != oldstate)
+ rfkill_led_trigger(rfkill, rfkill->state);
+
return retval;
}
@@ -105,6 +125,32 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
}
EXPORT_SYMBOL(rfkill_switch_all);
+/**
+ * rfkill_force_state - Force the internal rfkill radio state
+ * @rfkill: pointer to the rfkill class to modify.
+ * @state: the current radio state the class should be forced to.
+ *
+ * This function updates the internal state of the radio cached
+ * by the rfkill class. It should be used when the driver gets
+ * a notification by the firmware/hardware of the current *real*
+ * state of the radio rfkill switch.
+ *
+ * It may not be called from an atomic context.
+ */
+int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
+{
+ if (state != RFKILL_STATE_OFF &&
+ state != RFKILL_STATE_ON)
+ return -EINVAL;
+
+ mutex_lock(&rfkill->mutex);
+ rfkill->state = state;
+ mutex_unlock(&rfkill->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(rfkill_force_state);
+
static ssize_t rfkill_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -147,6 +193,7 @@ static ssize_t rfkill_state_show(struct device *dev,
{
struct rfkill *rfkill = to_rfkill(dev);
+ update_rfkill_state(rfkill);
return sprintf(buf, "%d\n", rfkill->state);
}
--
1.5.5.4
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 <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
---
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:
+ 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);
+ break;
+ default:
+ break;
+ }
}
}
@@ -168,6 +204,11 @@ static const struct input_device_id rfkill_ids[] = {
.evbit = { BIT_MASK(EV_KEY) },
.keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
},
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT,
+ .evbit = { BIT(EV_SW) },
+ .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) },
+ },
{ }
};
--
1.5.5.4
Hi Henrique,
On Sun, Jun 22, 2008 at 12:38:47PM -0300, Henrique de Moraes Holschuh wrote:
> 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 <[email protected]>
> Acked-by: Ivo van Doorn <[email protected]>
> Cc: Dmitry Torokhov <[email protected]>
rfkill_event() is called with handle->dev.event_lock spinlock held and
therefore can not sleep. rfkill_epo() takes rfkill mutex and may sleep
so it can't be used in the interrupt context. That is the reason why
we had tasks for switching rf switches in the first place.
--
Dmitry
On Thu, 05 Jun 2008, Tomas Winkler wrote:
> >> Third I think this patch use opposite logic as used currently in
> >> practice. RFKILL_ON means that radio is off .
This is how the code works: RFKILL_STATE_ON does not block the radio.
RFKILL_STATE_OFF blocks the radio. I documented the *reality* of that
code so that people would know for sure from now on. And no, I don't
exactly *like* it either.
So, yes, "rfkill.h" and net/rfkill* uses negative logic if you pay
attention to the "kill" in the name and also to the ON/OFF in the state
names, and that is confusing.
What we can do is change the names of those states, since those are just
kernel API and documentation (we cannot change their numerical values,
that is ABI exposed to userspace over sysfs).
But for obvious code maintenance reasons, which I am sure you know
about, we cannot just switch the names around. The new names have to be
different from the old ones (for the compiler to catch old usage), and
different *enough* from the old ones to not cause confusion on humans
(or the new usage will be misused).
> > The correct reading of rfkill class states are:
> >
> > RFKILL_STATE_ON: transmitter is UNBLOCKED and *may* operate
> > RFKILL_STATE_OFF: transmitter is BLOCKED and will *NOT* operate.
> > Nothing else is correct.
[snip]
> This is opposite logic as used in industry and you are creating mess
> here. RFKILL_ON means that you killed the radio and it moves
> radio to disable state.
No, I am not *creating* any mess. I am documenting whatever we already
have, and while I don't like it, I don't think it is bad enough (after
documentation) to qualify as a mess.
> If you want to use your logic the remove the world KILL form it.
> RF_ON, RF_OFF would match your intention.
RFKILL_STATE is in there as a namespace prefix. The new state names I
proposed are "BLOCKED" and "UNBLOCKED", which I hope are of quite clear
meaning. If you feel their meaning is not clear, which names would you
propose?
As for the RFKILL_STATE_ part of the name, I consider bad practice not
to have the namespace prefix, but I don't feel too strongly about it
either (still, I won't be the one proposing a change removing a
namespace prefix). If you want something different, send a patch
(please base it on a tree with this patch set applied, and update the
documentation). If Ivo ACKS it, it is in. Certainly, lots of kernel
defines and enums that are specific to some subsystem or to some set of
functions lack any such prefixes in mainline.
Or you could ask Ivo about renaming rfkill, and submit patches to that
effect.
--
"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
On Thu, 12 Jun 2008 11:43:04 -0400, "Dan Williams" <[email protected]> said:
> As you've explained it, I believe this will work IFF we take your
> suggestion and add a 3rd state RADIO_SW_BLOCKED to go along with
> RADIO_HW_BLOCKED and RADIO_UNBLOCKED.
Now you get it why I wanted the third state instead of a separate attribute,
I hope. It integrates much better on how *current* rfkill is supposed to
be used.
Good, I now just have to get to that email explaining switches, which I sort
of managed to already do partially, if you understood the above :-)
> In this system, if NM wants to softblock a wifi device for example, it
> would likely just turn off the transmitter with 'SIOCSIWTXPOW', thus the
Or you could also use sysfs to set the state to 0 (BLOCK). It is supposed
to perform the same operation as 'SIOCSIWTXPOW' to a power of 0, as far as
rfkill is concerned. Or you could, if you wanted to turn off *ALL*
transmitters of the same type, issue an input layer event for rfkill-input
to process. Whichever suits your application best.
> wifi device itself would report it's rfkill state as RADIO_SW_BLOCKED.
> NM would then be aware that it could be re-enabled at any time through
> software.
Yes.
> If the user then hits the hardkill switch, the wifi device would report
> RADIO_HW_BLOCKED, and NM would be aware that the user must unkill the
> transmitter with a physical switch.
Yes.
> It gets a bit interesting when unrelated killswitches like hp-wmi and
> thinkpad-acpi are used, because if those just softkill the radio, you
> could end up in the situation where the radio itself is RADIO_UNBLOCKED
> but the struct rfkill created by hp-wmi is RADIO_SW_BLOCKED if BIOS
> doesn't track the actual state of the radio too. How do we fix that?
It is already fixed :-) The radio itself will be RADIO_HW_BLOCKED (to
use your terms). Think about it: the thinkpad-acpi and hp-wmi
softswitches are not magic, they somehow rfkill the real radio devices.
That "somehow" is done through an input pin in the radio device that
will change state when the thinkpad-acpi/hp-wmi softswitch changes state,
so the radio device driver (which has NOTHING to do with thinkpad-acpi
OR hp-wmi, and doesn't even know they exist!) will report that the radio
is now in state RADIO_HW_BLOCKED.
So, a softswitch in one platform driver like thinkpad-acpi or hp-wmi CAN
cause a separate device under control by another module (the radio itself)
to see a hardswitch rfkill happening. This is fine, it is as things are
supposed to work.
That's why I call the current rfkill design one that hides the switch
topology from its users. Which is a Good Thing, as it means it gets
that much easier to write platform drivers and network drivers that
use rfkill.
The uglyness of the way some devices implement rfkill happens when the
hardware/firmware itself kludges things by unplugging devices from the
BUS when you rfkill that device. This has nothing to do with the rfkill
code in the kernel, it is just how some of these things work and we cannot
change that. Bluetooth and WWAN usually get this kind of treatment.
There is no sane workaround that could be done for that, we will have to
deal with hotplug and hotunplugging being a common operation for such
devices.
--
"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 <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
---
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 79f3bbb..fb56690 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 ((!rfkill->user_claim) && (rfkill->type == type))
- rfkill_toggle_radio(rfkill, state);
+ rfkill_toggle_radio(rfkill, state, 0);
}
mutex_unlock(&rfkill_mutex);
@@ -214,7 +214,8 @@ static ssize_t rfkill_state_store(struct device *dev,
if (mutex_lock_interruptible(&rfkill->mutex))
return -ERESTARTSYS;
error = rfkill_toggle_radio(rfkill,
- state ? RFKILL_STATE_ON : RFKILL_STATE_OFF);
+ state ? RFKILL_STATE_ON : RFKILL_STATE_OFF,
+ 0);
mutex_unlock(&rfkill->mutex);
return error ? error : count;
@@ -255,7 +256,8 @@ static ssize_t rfkill_claim_store(struct device *dev,
if (rfkill->user_claim != claim) {
if (!claim)
rfkill_toggle_radio(rfkill,
- rfkill_states[rfkill->type]);
+ rfkill_states[rfkill->type],
+ 0);
rfkill->user_claim = claim;
}
@@ -288,12 +290,11 @@ static int rfkill_suspend(struct device *dev, pm_message_t state)
if (dev->power.power_state.event != state.event) {
if (state.event & PM_EVENT_SLEEP) {
- mutex_lock(&rfkill->mutex);
-
- if (rfkill->state == RFKILL_STATE_ON)
- rfkill->toggle_radio(rfkill->data,
- RFKILL_STATE_OFF);
+ /* Stop transmitter, keep state, no notifies */
+ update_rfkill_state(rfkill);
+ mutex_lock(&rfkill->mutex);
+ rfkill->toggle_radio(rfkill->data, RFKILL_STATE_OFF);
mutex_unlock(&rfkill->mutex);
}
@@ -310,8 +311,8 @@ static int rfkill_resume(struct device *dev)
if (dev->power.power_state.event != PM_EVENT_ON) {
mutex_lock(&rfkill->mutex);
- if (rfkill->state == RFKILL_STATE_ON)
- rfkill->toggle_radio(rfkill->data, RFKILL_STATE_ON);
+ /* restore radio state AND notify everybody */
+ rfkill_toggle_radio(rfkill, rfkill->state, 1);
mutex_unlock(&rfkill->mutex);
}
@@ -338,7 +339,7 @@ static int rfkill_add_switch(struct rfkill *rfkill)
mutex_lock(&rfkill_mutex);
- error = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type]);
+ error = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type], 0);
if (!error)
list_add_tail(&rfkill->node, &rfkill_list);
@@ -351,7 +352,7 @@ static void rfkill_remove_switch(struct rfkill *rfkill)
{
mutex_lock(&rfkill_mutex);
list_del_init(&rfkill->node);
- rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF);
+ rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF, 1);
mutex_unlock(&rfkill_mutex);
}
--
1.5.5.4
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.
Also fix a small error in the documentation: setting the state of a normal
instance of the rfkill class does not affect the state of any other devices
(unless they are tied by firmware/hardware somehow).
Signed-off-by: Henrique de Moraes Holschuh <[email protected]>
Acked-by: Ivo van Doorn <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
---
Documentation/rfkill.txt | 362 +++++++++++++++++++++++++++++++++++++++-------
1 files changed, 307 insertions(+), 55 deletions(-)
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt
index ec75d6d..e08a79e 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 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).
-This is done by providing the user 3 possibilities:
- 1 - The rfkill system handles all events; userspace is not aware of events.
- 2 - The rfkill system handles all events; userspace is informed about the events.
- 3 - The rfkill system does not handle events; userspace handles all events.
+Because of this requirement, userspace support for the keys should not be made
+mandatory. Because userspace might want to perform some additional smarter
+tasks when the key is pressed, rfkill provides userspace the possibility to
+take over the task to handle the key events.
-The buttons to enable and disable the wireless radios are important in
-situations where the user is for example using his laptop on a location where
-wireless radios _must_ be disabled (e.g. airplanes).
-Because of this requirement, userspace support for the keys should not be
-made mandatory. Because userspace might want to perform some additional smarter
-tasks when the key is pressed, rfkill still provides userspace the possibility
-to take over the task to handle the key events.
+===============================================================================
+2: Implementation details
+
+The rfkill class provides kernel drivers with an interface that allows them to
+know when they should enable or disable a wireless network device transmitter.
+
+The rfkill-input module provides the kernel with the ability to implement
+a basic response when the user presses a key or button (or toggles a switch)
+related to rfkill functionality. This is optional, and can also be done in
+userspace.
+
+The rfkill-input module also provides EPO (emergency power-off) functionality
+for all wireless transmitters. This function cannot be overriden, and it is
+always active. rfkill EPO is related to *_RFKILL_ALL input events.
+
+All state changes on rfkill devices are propagated by the rfkill class to a
+notification chain and also to userspace through uevents.
The system inside the kernel has been split into 2 separate sections:
1 - RFKILL
2 - RFKILL_INPUT
-The first option enables rfkill support and will make sure userspace will
-be notified of any events through the input device. It also creates several
-sysfs entries which can be used by userspace. See section "Userspace support".
+The first option enables rfkill support and will make sure userspace will be
+notified of any events through uevents. It provides a notification chain for
+interested parties in the kernel to also get notified of rfkill state changes
+in other drivers. It creates several sysfs entries which can be used by
+userspace. See section "Userspace support".
+
+The second option provides an rfkill input handler. This handler will listen to
+all rfkill key events and will toggle the radio accordingly. With this option
+enabled userspace could either do nothing or simply perform monitoring tasks.
+
+When a rfkill switch is in the RFKILL_STATE_ON, the wireless transmitter (radio
+TX circuit for example) is *enabled*. When the rfkill switch is in the
+RFKILL_STATE_OFF, the wireless transmitter is to be *blocked* from operating.
+
+Full rfkill functionality requires two different subsystems to cooperate: the
+input layer and the rfkill class. The input layer issues *commands* to the
+entire system requesting that devices registered to the rfkill class change
+state. The way this interaction happens is not complex, but it is not obvious
+either:
+
+Kernel Input layer:
+
+ * Generates KEY_WWAN, KEY_WLAN, KEY_BLUETOOTH, SW_RFKILL_ALL, and
+ other such events when the user presses certain keys, buttons, or
+ toggles certain physical switches.
+
+ THE INPUT LAYER IS NEVER USED TO PROPAGATE STATUS, NOTIFICATIONS OR THE
+ KIND OF STUFF AN ON-SCREEN-DISPLAY APPLICATION WOULD REPORT. It is
+ used to issue *commands* for the system to change behaviour, and these
+ commands may or may not be carried out by some kernel driver or
+ userspace application. It follows that doing user feedback based only
+ on input events is broken, there is no guarantee that an input event
+ will be acted upon.
+
+ Most wireless communication device drivers implementing rfkill
+ functionality MUST NOT generate these events, and have no reason to
+ register themselves with the input layer. This is a common
+ misconception. There is an API to propagate rfkill status change
+ information, and it is NOT the input layer.
+
+rfkill class:
+
+ * Calls a hook in a driver to effectively change the wireless
+ transmitter state;
+ * Keeps track of the wireless transmitter state (with help from
+ the driver);
+ * Generates userspace notifications (uevents) and a call to a
+ notification chain (kernel) when there is a wireless transmitter
+ state change;
+ * Connects a wireless communications driver with the common rfkill
+ control system, which, for example, allows actions such as
+ "switch all bluetooth devices offline" to be carried out by
+ userspace or by rfkill-input.
+
+ THE RFKILL CLASS NEVER ISSUES INPUT EVENTS. THE RFKILL CLASS DOES
+ NOT LISTEN TO INPUT EVENTS. NO DRIVER USING THE RFKILL CLASS SHALL
+ EVER LISTEN TO, OR ACT ON RFKILL INPUT EVENTS.
+
+ Most wireless data communication drivers in the kernel have just to
+ implement the rfkill class API to work properly. Interfacing to the
+ input layer is not often required (and is very often a *bug*).
+
+Userspace input handlers (uevents) or kernel input handlers (rfkill-input):
+
+ * Implements the policy of what should happen when one of the input
+ layer events related to rfkill operation is received.
+ * Uses the sysfs interface (userspace) or private rfkill API calls
+ to tell the devices registered with the rfkill class to change
+ their state (i.e. translates the input layer event into real
+ action).
+ * rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0
+ (power off all transmitters) in a special way: it ignores any
+ overrides and local state cache and forces all transmitters to
+ the OFF state (including those which are already supposed to be
+ OFF). Note that the opposite event (power on all transmitters)
+ is handled normally.
+
+Userspace uevent handler or kernel platform-specific drivers hooked to the
+rfkill notifier chain:
+
+ * Taps into the rfkill notifier chain or to KOBJ_CHANGE uevents,
+ in order to know when a device that is registered with the rfkill
+ class changes state;
+ * Issues feedback notifications to the user;
+ * In the rare platforms where this is required, synthesizes an input
+ event to command all *OTHER* rfkill devices to also change their
+ statues when a specific rfkill device changes state.
+
+
+===============================================================================
+3: Kernel driver guidelines
+
+The first thing one needs to know is whether his driver should be talking to
+the rfkill class or to the input layer.
+
+Do not mistake input devices for rfkill devices. The only type of "rfkill
+switch" device that is to be registered with the rfkill class are those
+directly controlling the circuits that cause a wireless transmitter to stop
+working (or the software equivalent of them). Every other kind of "rfkill
+switch" is just an input device and MUST NOT be registered with the rfkill
+class.
+
+A driver should register a device with the rfkill class when ALL of the
+following conditions are met:
+
+1. The device is/controls a data communications wireless transmitter;
+
+2. The kernel can interact with the hardware/firmware to CHANGE the wireless
+ transmitter state (block/unblock TX operation);
+
+A driver should register a device with the input subsystem to issue
+rfkill-related events (KEY_WLAN, KEY_BLUETOOTH, KEY_WWAN, KEY_WIMAX,
+SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met:
+
+1. It is directly related to some physical device the user interacts with, to
+ command the O.S./firmware/hardware to enable/disable a data communications
+ wireless transmitter.
+
+ Examples of the physical device are: buttons, keys and switches the user
+ will press/touch/slide/switch to enable or disable the wireless
+ communication device.
+
+2. It is NOT slaved to another device, i.e. there is no other device that
+ issues rfkill-related input events in preference to this one.
+
+ Typically, the ACPI "radio kill" switch of a laptop is the master input
+ device to issue rfkill events, and, e.g., the WLAN card is just a slave
+ device that gets disabled by its hardware radio-kill input pin.
-The second option provides an rfkill input handler. This handler will
-listen to all rfkill key events and will toggle the radio accordingly.
-With this option enabled userspace could either do nothing or simply
-perform monitoring tasks.
+When in doubt, do not issue input events. For drivers that should generate
+input events in some platforms, but not in others (e.g. b43), the best solution
+is to NEVER generate input events in the first place. That work should be
+deferred to a platform-specific kernel module (which will know when to generate
+events through the rfkill notifier chain) or to userspace. This avoids the
+usual maintenance problems with DMI whitelisting.
+
+Corner cases and examples:
====================================
-2: Driver support
-To build a driver with rfkill subsystem support, the driver should
-depend on the Kconfig symbol RFKILL; it should _not_ depend on
-RKFILL_INPUT.
+1. If the device is an input device that, because of hardware or firmware,
+causes wireless transmitters to be blocked regardless of the kernel's will, it
+is still just an input device, and NOT to be registered with the rfkill class.
-Unless key events trigger an interrupt to which the driver listens, polling
-will be required to determine the key state changes. For this the input
-layer providers the input-polldev handler.
+2. If the wireless transmitter switch control is read-only, it is an input
+device and not to be registered with the rfkill class (and maybe not to be made
+an input layer event source either, see below).
-A driver should implement a few steps to correctly make use of the
-rfkill subsystem. First for non-polling drivers:
+3. If there is some other device driver *closer* to the actual hardware the
+user interacted with (the button/switch/key) to issue an input event, THAT is
+the device driver that should be issuing input events.
- - rfkill_allocate()
- - input_allocate_device()
- - rfkill_register()
- - input_register_device()
+E.g:
+ [RFKILL slider switch] -- [GPIO hardware] -- [WLAN card rf-kill input]
+ (platform driver) (wireless card driver)
+
+The user is closer to the RFKILL slide switch plaform driver, so the driver
+which must issue input events is the platform driver looking at the GPIO
+hardware, and NEVER the wireless card driver (which is just a slave). It is
+very likely that there are other leaves than just the WLAN card rf-kill input
+(e.g. a bluetooth card, etc)...
+
+On the other hand, some embedded devices do this:
+
+ [RFKILL slider switch] -- [WLAN card rf-kill input]
+ (wireless card driver)
+
+In this situation, the wireless card driver *could* register itself as an input
+device and issue rf-kill related input events... but in order to AVOID the need
+for DMI whitelisting, the wireless card driver does NOT do it. Userspace (HAL)
+or a platform driver (that exists only on these embedded devices) will do the
+dirty job of issuing the input events.
+
+
+COMMON MISTAKES in kernel drivers, related to rfkill:
+====================================
+
+1. NEVER confuse input device keys and buttons with input device switches.
+
+ 1a. Switches are always set or reset. They report the current state
+ (on position or off position).
+
+ 1b. Keys and buttons are either in the pressed or not-pressed state, and
+ that's it. A "button" that latches down when you press it, and
+ unlatches when you press it again is in fact a switch as far as input
+ devices go.
+
+Add the SW_* events you need for switches, do NOT try to emulate a button using
+KEY_* events just because there is no such SW_* event yet. Do NOT try to use,
+for example, KEY_BLUETOOTH when you should be using SW_BLUETOOTH instead.
+
+2. Input device switches (sources of EV_SW events) DO store their current
+state, and that state CAN be queried from userspace through IOCTLs. There is
+no sysfs interface for this, but that doesn't mean you should break things
+trying to hook it to the rfkill class to get a sysfs interface :-)
+
+3. Do not issue *_RFKILL_ALL events, unless you are sure it is the correct
+event for your switch/button. These events are emergency power-off events when
+they are trying to turn the transmitters off. An example of an input device
+which SHOULD generate *_RFKILL_ALL events is the wireless-kill switch in a
+laptop which is NOT a hotkey, but a real switch that kills radios in hardware,
+even if the O.S. has gone to lunch. An example of an input device which SHOULD
+NOT generate *_RFKILL_ALL events is any sort of hot key that does nothing by
+itself, as well as any hot key that is type-specific (e.g. the one for WLAN).
+
+
+===============================================================================
+4: Kernel API
+
+To build a driver with rfkill subsystem support, the driver should depend on
+the Kconfig symbol RFKILL; it should _not_ depend on RKFILL_INPUT.
+
+The hardware the driver talks to may be write-only (where the current state
+of the hardware is unknown), or read-write (where the hardware can be queried
+about its current state).
+
+The rfkill class will call the get_state hook of a device every time it needs
+to know the *real* current state of the hardware. This can happen often.
+
+Some hardware provides events when its status changes. In these cases, it is
+best for the driver to not provide a get_state hook, and instead register the
+rfkill class *already* with the correct status, and keep it updated using
+rfkill_force_state() when it gets an event from the hardware.
-For polling drivers:
+There is no provision for a statically-allocated rfkill struct. You must
+use rfkill_allocate() to allocate one.
+You should:
- rfkill_allocate()
- - input_allocate_polled_device()
+ - modify rfkill fields (flags, name)
+ - modify state to the current hardware state (THIS IS THE ONLY TIME
+ YOU CAN ACCESS state DIRECTLY)
- rfkill_register()
- - input_register_polled_device()
-When a key event has been detected, the correct event should be
-sent over the input device which has been registered by the driver.
+Please refer to the source for more documentation.
-====================================
-3: Userspace support
+===============================================================================
+5: Userspace support
+
+rfkill devices issue uevents (with an action of "change"), with the following
+environment variables set:
+
+RFKILL_NAME
+RFKILL_STATE
+RFKILL_TYPE
-For each key an input device will be created which will send out the correct
-key event when the rfkill key has been pressed.
+The ABI for these variables is defined by the sysfs attributes. It is best
+to take a quick look at the source to make sure of the possible values.
+
+It is expected that HAL will trap those, and bridge them to DBUS, etc. These
+events CAN and SHOULD be used to give feedback to the user about the rfkill
+status of the system.
+
+Input devices may issue events that are related to rfkill. These are the
+various KEY_* events and SW_* events supported by rfkill-input.c.
+
+******IMPORTANT******
+When rfkill-input is ACTIVE, userspace is NOT TO CHANGE THE STATE OF AN RFKILL
+SWITCH IN RESPONSE TO AN INPUT EVENT also handled by rfkill-input, unless it
+has set to true the user_claim attribute for that particular switch. This rule
+is *absolute*; do NOT violate it.
+******IMPORTANT******
+
+Userspace must not assume it is the only source of control for rfkill switches.
+Their state CAN and WILL change on its own, due to firmware actions, direct
+user actions, and the rfkill-input EPO override for *_RFKILL_ALL.
+
+When rfkill-input is not active, userspace must initiate an rfkill status
+change by writing to the "state" attribute in order for anything to happen.
+
+Take particular care to implement EV_SW SW_RFKILL_ALL properly. When that
+switch is set to OFF, *every* rfkill device *MUST* be immediately put into the
+OFF state, no questions asked.
The following sysfs entries will be created:
@@ -87,10 +331,18 @@ The following sysfs entries will be created:
claim: 1: Userspace handles events, 0: Kernel handles events
Both the "state" and "claim" entries are also writable. For the "state" entry
-this means that when 1 or 0 is written all radios, not yet in the requested
-state, will be will be toggled accordingly.
+this means that when 1 or 0 is written, the device rfkill state (if not yet in
+the requested state), will be will be toggled accordingly.
+
For the "claim" entry writing 1 to it means that the kernel no longer handles
key events even though RFKILL_INPUT input was enabled. When "claim" has been
set to 0, userspace should make sure that it listens for the input events or
-check the sysfs "state" entry regularly to correctly perform the required
-tasks when the rkfill key is pressed.
+check the sysfs "state" entry regularly to correctly perform the required tasks
+when the rkfill key is pressed.
+
+A note about input devices and EV_SW events:
+
+In order to know the current state of an input device switch (like
+SW_RFKILL_ALL), you will need to use an IOCTL. That information is not
+available through sysfs in a generic way at this time, and it is not available
+through the rfkill class AT ALL.
--
1.5.5.4
On Tue, 2008-06-10 at 01:11 -0300, Henrique de Moraes Holschuh wrote:
> On Sun, 08 Jun 2008, Matthew Garrett wrote:
> > On Fri, Jun 06, 2008 at 11:14:19AM -0300, Henrique de Moraes Holschuh wrote:
> > > 1. Every transmitter shall have ONE, and just ONE (not zero, not two,
> > > not more) rfkill class attached. For those transmitters lacking support
> > > in hardware to make it block, the drivers shall quiesce them and avoid
> > > doing anything to cause transmissions, or even use bus tricks to power
> > > the device down (i.e. the driver will emulate a switch capable of doing
> > > the blocking).
> >
> > How do we enforce this? iwl4965 provides an rfkill device, but hp-wmi
> > will also provide one for the wifi. If I swap out the wireless card for
> > something else, I may lose the card-specific rfkill device.
>
> Let's define some very STRICT terminology to avoid confusion.
>
> rfkill class: the sysfs rfkill class, related to struct rfkill.
>
> rfkill class attached [to a Linux struct device]: a device whose
> struct device was given to rfkill_allocate() as the parent.
>
> transmitter: part of a wireless device. So far, every wireless device
> I have seen has only one transmitter from the kernel PoV. A device
> with two transmitters would be able to transmit two different information
> streams at the same time, with different parameters (such as frequency,
> power).
>
> transmitter != switch, so hp-wmi, thinkpad-acpi, and anything else that is
> not an actual wireless hardware device IS NOT INCLUDED in that "one and just
> one" constraint. In fact, thinkpad-acpi has two rfkill classes attached to
> its main platform device, one for the bluetooth softswitch, and another for
> the wwan softswitch.
>
> So, "Every transmitter shall have ONE and just ONE rfkill class attached."
> just means that you call rfkill_allocate with that device as the parent just
> ONCE per transmitter (and everything I have seen so far has just one
> transmitter).
>
> Which also means that, for wireless drivers (which have transmitters), you
> need to synthesize the "device rfkill state" to give to that rfkill class.
> THE TRANSMITTER MIGHT BE UNDER THE EFFECT OF MORE THAN ONE RFKILL LINE.
>
> And if the device [transmitter] has NO rfkill capabilities by itself, we
> emulate the minimum of one in software [per transmitter]. If the device
> has one input pin for rfkill, that one is also taken into account when
> generating the state for the ONLY ONE rfkill class attached to that device
> [per transmitter], etc.
>
> Now, firmware switches are different, and something for another email that
> I haven't typed in yet (busy in real life right now).
>
> An example:
>
> ipw4965 probably has two rfkill controls in itself (an input pin for a
> hardkill line, and an R/W IO register to help its driver (ilw4965) implement
> a rfkill softswitch). Those TWO rfkill inputs are to be combined into just
> ONE rfkill class which will be attached to the Linux device provided by
> ilw4965. This is the end of the story from the PoC of the ilw4965 module.
>
> hp-wmi probably has one softswitch it controls, that ends up connected to
> that input pin in the ipw4965 card so you end up being able to use a hp-wmi
> softswitch to hardkill the ipw4965 card. This IS expected, and it will not
> matter or break anything. In the current rfkill incarnation, rfkill doesn't
> understand or know or want to know about rfkill switch topology as it
> stands.
>
> Did I manage to get the idea across, this time? Remember, I am not
> describing the rfkill class interactions for switches in that email, JUST
> for wireless drivers, which hp-wmi, thinkpad-acpi, etc are not...
>
> What happens on the hp-wmi side when the ipw4965 card is removed, is to be
> explained in the other email about switches, but it is not much. Basically,
> hp-wmi has to be written in such a way that it won't matter for the user,
> and THERE is the real reason why one must never confuse the softswitch
> control with input devices. Remember that as long as rfkill-input is
> loaded, if anything sends a "change all WLAN rfkill switches" input event,
> all WLAN rfkill switches WILL be changed, regardless of whether they are
> wired among themselves, or completely independent.
As you've explained it, I believe this will work IFF we take your
suggestion and add a 3rd state RADIO_SW_BLOCKED to go along with
RADIO_HW_BLOCKED and RADIO_UNBLOCKED.
In this system, if NM wants to softblock a wifi device for example, it
would likely just turn off the transmitter with 'SIOCSIWTXPOW', thus the
wifi device itself would report it's rfkill state as RADIO_SW_BLOCKED.
NM would then be aware that it could be re-enabled at any time through
software.
If the user then hits the hardkill switch, the wifi device would report
RADIO_HW_BLOCKED, and NM would be aware that the user must unkill the
transmitter with a physical switch.
It gets a bit interesting when unrelated killswitches like hp-wmi and
thinkpad-acpi are used, because if those just softkill the radio, you
could end up in the situation where the radio itself is RADIO_UNBLOCKED
but the struct rfkill created by hp-wmi is RADIO_SW_BLOCKED if BIOS
doesn't track the actual state of the radio too. How do we fix that?
Dan
On Thu, 2008-06-05 at 17:13 -0300, Henrique de Moraes Holschuh wrote:
> On Thu, 05 Jun 2008 10:46:47 -0400, "Dan Williams" <[email protected]> said:
> > On Thu, 2008-06-05 at 10:03 -0300, Henrique de Moraes Holschuh wrote:
> > > On Thu, 05 Jun 2008, Dan Williams wrote:
> > > > a) hard switches that kill the radio and notify the driver
> > >
> > > rfkill class material, yes.
> > >
> > > > b) hard switches that notify the driver but do not directly kill the
> > > > radio
> > >
> > > These are input devices, and not directly related to the rfkill class
> > > (but related to the rfkill subsystem).
> >
> > So in your mind, these drivers would re-emit state changes of their
> > rfkill switches back into the kernel input layer, correct?
>
> Yes. And the funny thing is, they are supposed not to ACT by themselves
> at all, they are to wait for someone to tell them to through the rfkill class.
>
> (NOTE: this applies only to scenario (b) above. It is NOT valid for other
> scenarios like (a) or (c) or any other).
>
>
> To be more clear:
>
> MODULE FOO (driver for the foo wireless device).
> * Ties to the input layer, and reports pressure of the "hard switch that notify
> the driver (MODULE FOO) but do not directly kill the radio (device foo)" using
> the proper input event.
>
> It does NOTHING further with the information that the button/switch was pressed.
> Really. It just generates the input event and sends it.
>
> * Uses the rfkill class connected to the device foo in the device tree to receive
> commands to toggle the real device rfkill state.
>
> If some input event is indeed supposed to cause the device state to change, the
> driver gets called back through the rfkill class toggle_radio() hook.
>
> So, the button press would go through the input layer to SOMETHING ELSE (likely
> to rfkill-input), which would take the **policy** decision of what to do with
> that event, and then cause the appropriate rfkill class instances to change their
> state.
>
> So, MODULE FOO would get a hook call (toggle_radio) through the rfkill class, in
> order to do something about the input event MODULE FOO itself generated.
>
> Or it might not get that hook call, if the local admin wanted something different
> to happen.
>
> > > > c) hard switches that disconnect the device from its bus entirely (most
> > > > BT rfkill)
> > >
> > > These are also rfkill class material.
> > >
> > > > d) hard switches that notify BIOS only (not the driver) and rely on
> > > > special laptop drivers (hp-wmi, toshiba-laptop, etc) to notify the
> > > > system
> > >
> > > If they just notify the BIOS, they are input devices. If they cause the
> > > BIOS to mess with the transmitters, they are rfkill class material.
> >
> > Obviously here, the laptop specific driver would re-emit the state
> > change into the the kernel input layer since it is handled by a
> > completely separate driver than the radio itself is handled by?
>
> Correct. The platform driver might actually also register notifier callbacks
> on the rfkill subsystem, and, for example, automatically promote all b43
> rfkill status changes into input events if this is the correct thing to
> do for THAT specific platform (it is NOT the correct thing to do by
> default, so b43 can't do it itself).
>
> > > > e) keyboard "soft" switches that are simply input layer buttons (like Fn
> > > > +F5 on thinkpads) and don't toggle
> > >
> > > These are input devices in almost all cases. But since you brought up
> > > thinkpads, I better warn you that the Fn+F5 in a ThinkPad, depending on
> > > thinkpad BIOS revision and ACPI HKEY mask state, *is* active and will
> > > mess with the transmitters directly (and thus it is not an input
> > > device). thinkpad-acpi forces it to "just an input device" state by
> > > default to keep things sane.
> > >
> > > > Besides that, we can rfkill radios in software through commands like
> > > > "iwconfig wlan0 txpower off".
> > >
> > > Yeah. This could be also rfkill material, if you want to have rfkill as
> > > another *way* to interact with the same functionality. It could cause
> > > some minor issues (like which power do I set the transmitter to, if it
> > > is turned off by txpower off, but someone undos that through rfkill?)
> > > but it would work.
> >
> > I want _one_ interface to get the radio block state (either blocked or
> > unblocked) for any device that has a radio, be it WiFi, WiMAX, BT, WWAN,
> > UWB, etc.
>
> rfkill is supposed to be it, yes.
>
> > I also want _one_ interface to determine how many rfkill switches the
> > system has, and what their state is (either blocking radios or not
> > blocking radios). This is what the current rfkill system seems to
> > provide.
>
> It provides that information PARTIALLY. Currently, you can enumerate
> all rfkill interfaces through sysfs, and you can interact with each
> one separately. However, you cannot interact with the internal type-
> specific global switches (which are NOT rfkill class) inside
> rfkill-input.
>
> I haven't solved that problem to my satisfaction yet, so the only patch
> I have for it has not seen the light of the net. It is too ugly to live
> IMHO.
>
> So, I'd say the individual rfkill class sysfs interface is nearly complete
> (we need to add the third state or do something else to tell you when
> a radio is blocked and cannot be unblocked).
>
> But the rfkill subsystem interface (deals with rfkill-input) to userspace
> is NOT feature-complete yet. This really, really shouldn't bother NM,
> it is HAL-layer level stuff.
It bothers NM because NM uses HAL for rfkill information, and HAL
doesn't yet handle the difference between hardkill and softkill. That's
exactly what I'm trying to fix here.
> > I don't want to have to use SIOCGIWTXPOW for wifi, something else for
> > BT, something else for WWAN, something else for WiMAX, just to figure
> > out whether a radio is blocked or unblocked. That's just wrong but
> > something that we can eventually fix.
>
> Well, the problem is that SIOCGIWTXPOW is NOT a direct equivalent to rfkill,
> rfkill has no concept of attenuation (or amplification, for that matter).
Yeah, but that's not really relevant here. All we need is "radio
blocked" or "radio unblocked" as a property on the transmitter device.
We don't are about the signal power, we just care about whether the
radio is blocked or unblocked.
> It is up for the wireless people to decide if their SIOCGIWTXPOW controls
> are the same exposed by rfkill or not, and what to do when reenabling from
> a txpower off (probably you will have to recall the last non-off txpower
> and use that). The rfkill subsystem really doesn't care, as long as you
> don't do it by adding more than one rfkill class to the same device.
>
> > So, it seems I was confused about the scope of the current rfkill
> > system. While it probably should be "rfkill_switch" I'm not sure we can
> > change that now. While it would be nice to have a single interface to
> > query radio power state, that can be a future improvement.
>
> I think it is a better idea to fix what we have, first. Let it settle
> down, and then take the full view and check if you need to enhance it,
> replace it, or design something else that goes along with it. I'd bet on
> the third option, but it is a bit early to tell.
>
> > > > Only (a), (b), (c), and sometimes (d) actually kill the radio and block
> > > > changes by the user. Otherwise, it's up to userspace to kill the radios
> > > > when events come in.
> > >
> > > If it doesn't kill the radio, it is not rfkill class material. At most,
> > > it could be an input device that issues events related to rfkill.
> >
> > Right, I misunderstood the original scope of the kernel rfkill stuff. I
> > thought it covered everything except case E (pure input-layer only
> > buttons).
>
> It sort of does, in the sense that rfkill (not the rfkill class!) defines
> how the input layer should be used for these events.
>
> > I'd like the rfkill system to eventually cover cases A - D, and also
> > handle radio block state notifications and queries. I'm willing to help
> > code that. Actual power levels of the radio is probably best left up to
> > the device-specific subsystem, but at least the state (and events!) of
> > "radio now blocked" or "radio now unblocked" are useful to have.
>
> Unless I missed something, I have provided you with that for cases
> A to D already. What I didn't provide you with was "radio now blocked and
> you cannot unblock it", *yet*. You have convinced me it is something
> needed, and if left to my own devices, I will implement it as a third
> state.
But again, we don't need a third state! We need to separate the radio
block state from the rfkill switch state.
Not all radios have rfkill switches attached to them, and thus having a
3rd rfkill state just doesn't work. In the case of hp-wmi, there is no
killswitch associated with the wireless device, it's handled by BIOS and
does not necessarily have interaction with the transmitter.
Having a 3rd state on a killswitch which can't physically _have_ 3
states isn't right. The switch is often completely independent of the
radio, and that's something we need to represent.
Because of that, the toggle_radio() member of struct rfkill just isn't
in the right place. That changes _radio_ block state, but since struct
rfkill is the _switch_, toggle_radio() is wrong here. In the case of
hp-wmi, there's no radio to toggle, since it's a hardswitch, and since
hp-wmi isn't a wireless driver!
Again, we need to separate radio block state from switch state, because
they are two different things. We don't need to break anything here; we
just need to add some bits for radio block state.
Dan
> HOWEVER, rfkill can't provide you with "radio is enabled, configured,
> operational and transmitting" status. It really can't say much of what
> is happening in the unblocked state.
>
> > > Currently we can't differentiate "block changes by the user" from "the
> > > kernel can change the state if you ask it to". I agree this is a
> > > desireable feature, and I'd rather add a third rfkill_state to propagate
> > > that information.
> >
> > Well... I still think this is best as a _radio_ property, not as a
> > killswitch property. Physical switches are physical, you can't change
> > the state and thus the third state here isn't useful. If we separate
> > switch state from radio power state that makes it clear (at least to
> > me).
>
> But then you have more than one "switch" per radio, which needs changes
> to rfkill (currently, you are NOT to do it).
>
> Currently, one is to think of a rfkill class as the representation of
> the "radio property". Which means you *lose the information* of which
> underlying hardware/firmware reason the device has to be blocked.
>
> I think we are actually better off by losing that information, it is
> not useful for UIs (you need to know the device is force-blocked, not
> WHY it is blocked or force-blocked -- that is highly platform-specific).
>
> > Since the current rfkillX device is the _switch_, and since I'm not
> > aware of any machines where the BIOS synthesizes a toggle state from a
> > non-toggle button, maybe we should punt this until such a device
> > actually turns up?
>
> The current rfkillX device represents the radio state, which means it might
> need to synthesize it from various hardware bits.
>
> E.g. Let's look at a possible conversion of IPW2200 to the rfkill class.
>
> The IPW2200 driver has TWO rfkill "registers":
> R1 - Read/Write, controlled by the driver
> R2 - Read-Only, reflects an input pin in the hardware and cannot be
> overriden.
>
> The IPW2000 driver would register just *one* instance of the rfkill class,
> and it would return the status as this.
>
> Assume R1 active high, and R2 active high. Active means BLOCK RADIO.
>
> rfkill_status = (R1 | R2) ? RFKILL_STATUS_OFF : RFKILL_STATUS_ON.
>
> I.e. if either one (or both) of the registers are blocking the radio, it
> reports the status as RFKILL_STATUS_OFF. Otherwise, it reports the status
> as RFKILL_STATUS_ON (unblocked).
>
> Now, for the toggle_radio function in pseudo-code:
>
> switch (new_state) {
> case RFKILL_STATUS_ON:
> if (R2) {
> R1 = 1; /* fail safe, least surprise */
> return -EPERM; /* cannot override! */
> }
> R1 = 0;
> break;
> case RFKILL_STATUS_OFF:
> R1 = 1;
> break;
> }
>
> There are possible variations, the most pressing one that comes to mind
> is whether we should force the R1 switch to 1 or 0 when R2 is 1 on the
> RFKILL_STATUS_ON branch. I used the "won't EVER cause the radio to be
> unblocked by surprise" alternative.
>
> However, now userspace really gets to know if the ipw2200 radio is blocked or not,
> it doesn't have to hunt down two different rfkill class instances for it. And it
> just needs to listen to uevents (which HAL should be taught to export to DBUS) for
> ipw2200 to know when the status changes, no pooling or even reading of sysfs
> attributes would be required.
>
> If you wanted to also handle txpower off through rfkill, you'd take the state of
> txpower into consideration on the code above, and still have only ONE rfkillX
> instance for the ipw2200 device.
>
> > > > The only thing I personally care about is separating radio state from
> > > > switch state so that I can distinguish a softkill (via ex. iwconfig
> > > > wlan0 txpower off) from a hardkill via a real killswitch.
> > >
> > > Ok, so what you care about is to know if you COULD CHANGE THE STATE,
> > > correct?
> >
> > Could change the radio _block_ state, yes. rfkill switch state no,
>
> I mean the radio _block_ state. See above. One rfkill class per device,
> synthesizing the state of n, n>=1 real switches. So, you get the radio
> block state from it.
>
> > because I don't know of any examples of those and frankly I think it's
> > easier to just make the user flip the switch again. Keeping it simpler
> > is better.
>
> I'd agree with this view, least surprise is good, and the way the whole
> rfkill idea was engineered to leave the transmitter BLOCKED in cause of
> doubt.
>
> > > The third state would tell you that.
> > >
> > > > Why should a "device rfkill state" be in a separate module? Radio state
> > > > _is_ rfkill state. rfkill switches turn the radio on or off but
> > >
> > > device-wide rfkill state is rfkill state. radio state could be
> > > anything.
> >
> > I started using "radio block state" in this mail instead.
>
> Ok, radio block state is also good. As long as we both know exactly
> what we mean by it.
>
> > > But yes, I understand what you want. The two states you talk about are
> > > the same if you have only ONE rfkill class attached to a device, and
> > > they are different (but related) things when you have MORE than one
> > > rfkill class attached to a device.
> >
> > What situations would have more than one rfkill class attached to the
> > device?
>
> If you try to model IPW2200 or other hardware with many rfkill input signals
> as one signal per rfkill class. That's something that is probably NOT a good
> idea at all.
>
> > > IMO, we should attach just one rfkill class per transmitter device, and
> > > handle the "you cannot change the state" possibility by adding a third
> > > state to rfkill_state.
> >
> > Right about the one rfkill class per device than drives a killswitch.
> > But that's not necessarily the transmitter device. It might be a child
> > of the laptop module if it's a BIOS switch that also kills the radio
> > automatically. In the case of hp-wmi, it provides 3 different rfkill
> > class devices.
>
> Which is why I want to do it in a way we don't have to know what is a
> child of what, slaved to what, master of what...
>
> > > > devices should have _one_ method of turning themselves off through
> > > > either hardware or software, and the system that provides that method
> > > > should be the rfkill system.
> > >
> > > We don't agree there. If you use "devices should have _one_ method of
> > > *forcing themselves off* outside of the normal control path of interface
> > > up/down", THEN we agree.
> >
> > Right, all devices with transmitters should have _one_ method of
> > blocking and unblocking their transmitters.
>
> OK.
>
> > > The reason is extremely simple: rfkill CANNOT TURN SOMETHING ON. If it
> > > *was* ON, and you used rfkill to turn it OFF, than yes, when you "stop
> > > turning it OFF through rfkill", it will go back to ON.
> > >
> > > But if it was not ON in the first place, it won't go to ON when you stop
> > > turning it OFF through rfkill. It will just remain OFF, unless
> > > something else that is NOT rfkill hooks into the event and takes the
> > > oportunity to do whatever is needed (such as configure the interface and
> > > bring it up) to bring the device to ON state.
> >
> > Good point.
>
> It is a very central point to rfkill, if you lose track of it, things get
> very confusing, very very quickly.
>
> > > > > Anyway, if we are to use various *related* rfkill switches per device,
> > > > > rfkill needs further changes, including an extra callback into the
> > > > > driver, so as to be able to export the device rfkill state also in all
> > > > > switch rfkill state events (otherwise these events become quite useless
> > > > > for many uses).
> > > >
> > > > But yes, there would need to be a "device rfkill state" changed event
> > > > and another call to get the device rfkill state.
> > >
> > > Indeed. It is a possiblity. I still feel a third addition to
> > > rfkill_state and the use of only ONE rfkill class per transmitter device
> > > is a better way to do it.
> >
> > As I said above, I think I disagree about the third state. I think the
> > best thing to do is keep the general rfkill switch operation as it is
> > now (only 2 states, blocked and unblocked), and eventually add a
> > standard "radio block state" sysfs entry on the _transmitter_ device
> > with 3 values: hw-blocked, sw-blocked, and unblocked.
>
> If we mandate the one-rfkill-class-per-transmitter rule, you now have two
> attributes that say the very same thing, except that the old one (the one
> we currently have) lacks the force-blocked state. So basically, you just
> avoided a minor ABI change by not adding the third state to rfkill_state.
>
> If we mandate the one-rfkill-class-per-kill-line rule, you will add
> complexity, now a driver like IPW2200 would need at least two rfkill
> class instances. In THIS case, the new attribute conveys interesting
> information, but OTOH, NM and any user application will have to deal
> with more than one rfkill sysfs instance per device, and we will have
> weird issues to deal with, like how to deal with user_claim...
>
> The reason I insist on the third state so much is that rfkill *really*
> was not designed to cope with two or more per transmitter. You now
> have to mess with various rfkill switches to get something to happen
> (and most of the time, all but one will EPERM you, because they are
> read-only, and my subconsious mind is severely screaming up this is
> a BAD IDEA, we currently forbid read-only switches and I recall there
> were some subtle issues with the input layer events for read-only
> stuff).
>
> > Does that sound OK? I feel like I have a better understanding of what
>
> It WOULD work, I think. But for the reasons above, I am more inclined
> to add a third state. It is much simpler on the code, and it has no
> drawbacks I can see, while the multiple rfkill per device approach does
> have some (and it gives me a bad feeling every time I consider it).
>
> What whould be the technical advantages of a separate attribute
> from your UI (NM) point of view? That is not yet clear to me, at
> all. Assume you will only get ONE rfkillX interface per device,
> which means it DOES reflect the block/unblock state of the device.
>
On Thu, 2008-06-05 at 23:26 -0400, Dan Williams wrote:
> On Thu, 2008-06-05 at 17:13 -0300, Henrique de Moraes Holschuh wrote:
> > On Thu, 05 Jun 2008 10:46:47 -0400, "Dan Williams" <[email protected]> said:
> > > On Thu, 2008-06-05 at 10:03 -0300, Henrique de Moraes Holschuh wrote:
> > > > On Thu, 05 Jun 2008, Dan Williams wrote:
> > > > > a) hard switches that kill the radio and notify the driver
> > > >
> > > > rfkill class material, yes.
> > > >
> > > > > b) hard switches that notify the driver but do not directly kill the
> > > > > radio
> > > >
> > > > These are input devices, and not directly related to the rfkill class
> > > > (but related to the rfkill subsystem).
> > >
> > > So in your mind, these drivers would re-emit state changes of their
> > > rfkill switches back into the kernel input layer, correct?
> >
> > Yes. And the funny thing is, they are supposed not to ACT by themselves
> > at all, they are to wait for someone to tell them to through the rfkill class.
> >
> > (NOTE: this applies only to scenario (b) above. It is NOT valid for other
> > scenarios like (a) or (c) or any other).
> >
> >
> > To be more clear:
> >
> > MODULE FOO (driver for the foo wireless device).
> > * Ties to the input layer, and reports pressure of the "hard switch that notify
> > the driver (MODULE FOO) but do not directly kill the radio (device foo)" using
> > the proper input event.
> >
> > It does NOTHING further with the information that the button/switch was pressed.
> > Really. It just generates the input event and sends it.
> >
> > * Uses the rfkill class connected to the device foo in the device tree to receive
> > commands to toggle the real device rfkill state.
> >
> > If some input event is indeed supposed to cause the device state to change, the
> > driver gets called back through the rfkill class toggle_radio() hook.
> >
> > So, the button press would go through the input layer to SOMETHING ELSE (likely
> > to rfkill-input), which would take the **policy** decision of what to do with
> > that event, and then cause the appropriate rfkill class instances to change their
> > state.
> >
> > So, MODULE FOO would get a hook call (toggle_radio) through the rfkill class, in
> > order to do something about the input event MODULE FOO itself generated.
> >
> > Or it might not get that hook call, if the local admin wanted something different
> > to happen.
> >
> > > > > c) hard switches that disconnect the device from its bus entirely (most
> > > > > BT rfkill)
> > > >
> > > > These are also rfkill class material.
> > > >
> > > > > d) hard switches that notify BIOS only (not the driver) and rely on
> > > > > special laptop drivers (hp-wmi, toshiba-laptop, etc) to notify the
> > > > > system
> > > >
> > > > If they just notify the BIOS, they are input devices. If they cause the
> > > > BIOS to mess with the transmitters, they are rfkill class material.
> > >
> > > Obviously here, the laptop specific driver would re-emit the state
> > > change into the the kernel input layer since it is handled by a
> > > completely separate driver than the radio itself is handled by?
> >
> > Correct. The platform driver might actually also register notifier callbacks
> > on the rfkill subsystem, and, for example, automatically promote all b43
> > rfkill status changes into input events if this is the correct thing to
> > do for THAT specific platform (it is NOT the correct thing to do by
> > default, so b43 can't do it itself).
> >
> > > > > e) keyboard "soft" switches that are simply input layer buttons (like Fn
> > > > > +F5 on thinkpads) and don't toggle
> > > >
> > > > These are input devices in almost all cases. But since you brought up
> > > > thinkpads, I better warn you that the Fn+F5 in a ThinkPad, depending on
> > > > thinkpad BIOS revision and ACPI HKEY mask state, *is* active and will
> > > > mess with the transmitters directly (and thus it is not an input
> > > > device). thinkpad-acpi forces it to "just an input device" state by
> > > > default to keep things sane.
> > > >
> > > > > Besides that, we can rfkill radios in software through commands like
> > > > > "iwconfig wlan0 txpower off".
> > > >
> > > > Yeah. This could be also rfkill material, if you want to have rfkill as
> > > > another *way* to interact with the same functionality. It could cause
> > > > some minor issues (like which power do I set the transmitter to, if it
> > > > is turned off by txpower off, but someone undos that through rfkill?)
> > > > but it would work.
> > >
> > > I want _one_ interface to get the radio block state (either blocked or
> > > unblocked) for any device that has a radio, be it WiFi, WiMAX, BT, WWAN,
> > > UWB, etc.
> >
> > rfkill is supposed to be it, yes.
> >
> > > I also want _one_ interface to determine how many rfkill switches the
> > > system has, and what their state is (either blocking radios or not
> > > blocking radios). This is what the current rfkill system seems to
> > > provide.
> >
> > It provides that information PARTIALLY. Currently, you can enumerate
> > all rfkill interfaces through sysfs, and you can interact with each
> > one separately. However, you cannot interact with the internal type-
> > specific global switches (which are NOT rfkill class) inside
> > rfkill-input.
> >
> > I haven't solved that problem to my satisfaction yet, so the only patch
> > I have for it has not seen the light of the net. It is too ugly to live
> > IMHO.
> >
> > So, I'd say the individual rfkill class sysfs interface is nearly complete
> > (we need to add the third state or do something else to tell you when
> > a radio is blocked and cannot be unblocked).
> >
> > But the rfkill subsystem interface (deals with rfkill-input) to userspace
> > is NOT feature-complete yet. This really, really shouldn't bother NM,
> > it is HAL-layer level stuff.
>
> It bothers NM because NM uses HAL for rfkill information, and HAL
> doesn't yet handle the difference between hardkill and softkill. That's
> exactly what I'm trying to fix here.
>
> > > I don't want to have to use SIOCGIWTXPOW for wifi, something else for
> > > BT, something else for WWAN, something else for WiMAX, just to figure
> > > out whether a radio is blocked or unblocked. That's just wrong but
> > > something that we can eventually fix.
> >
> > Well, the problem is that SIOCGIWTXPOW is NOT a direct equivalent to rfkill,
> > rfkill has no concept of attenuation (or amplification, for that matter).
>
> Yeah, but that's not really relevant here. All we need is "radio
> blocked" or "radio unblocked" as a property on the transmitter device.
> We don't are about the signal power, we just care about whether the
> radio is blocked or unblocked.
>
> > It is up for the wireless people to decide if their SIOCGIWTXPOW controls
> > are the same exposed by rfkill or not, and what to do when reenabling from
> > a txpower off (probably you will have to recall the last non-off txpower
> > and use that). The rfkill subsystem really doesn't care, as long as you
> > don't do it by adding more than one rfkill class to the same device.
> >
> > > So, it seems I was confused about the scope of the current rfkill
> > > system. While it probably should be "rfkill_switch" I'm not sure we can
> > > change that now. While it would be nice to have a single interface to
> > > query radio power state, that can be a future improvement.
> >
> > I think it is a better idea to fix what we have, first. Let it settle
> > down, and then take the full view and check if you need to enhance it,
> > replace it, or design something else that goes along with it. I'd bet on
> > the third option, but it is a bit early to tell.
> >
> > > > > Only (a), (b), (c), and sometimes (d) actually kill the radio and block
> > > > > changes by the user. Otherwise, it's up to userspace to kill the radios
> > > > > when events come in.
> > > >
> > > > If it doesn't kill the radio, it is not rfkill class material. At most,
> > > > it could be an input device that issues events related to rfkill.
> > >
> > > Right, I misunderstood the original scope of the kernel rfkill stuff. I
> > > thought it covered everything except case E (pure input-layer only
> > > buttons).
> >
> > It sort of does, in the sense that rfkill (not the rfkill class!) defines
> > how the input layer should be used for these events.
> >
> > > I'd like the rfkill system to eventually cover cases A - D, and also
> > > handle radio block state notifications and queries. I'm willing to help
> > > code that. Actual power levels of the radio is probably best left up to
> > > the device-specific subsystem, but at least the state (and events!) of
> > > "radio now blocked" or "radio now unblocked" are useful to have.
> >
> > Unless I missed something, I have provided you with that for cases
> > A to D already. What I didn't provide you with was "radio now blocked and
> > you cannot unblock it", *yet*. You have convinced me it is something
> > needed, and if left to my own devices, I will implement it as a third
> > state.
>
> But again, we don't need a third state! We need to separate the radio
> block state from the rfkill switch state.
Let me explain this a bit more.
- My original request was based on my flawed understanding of the
current scope of the rfkill system
- If the rfkill system is _only_ supposed to handle switches that turn
the radio off automatically, then a "third state" for the rfkill class
really serves _no_ purpose at all, because the radio's already blocked
when the switch is thrown
- There are drivers that implement rfkill (laptop-specific BIOS drivers)
that have _no_ associated transmitter device; thus the current 'struct
rfkill' can only be a representation of the _switch_; thus a "third
state" would be useless here as well (as is the toggle_radio() callback)
- It just seems a lot clearer to me to have a separation between the
rfkill switch and the radio bits since there's no need to tie them
together
Dan
> Not all radios have rfkill switches attached to them, and thus having a
> 3rd rfkill state just doesn't work. In the case of hp-wmi, there is no
> killswitch associated with the wireless device, it's handled by BIOS and
> does not necessarily have interaction with the transmitter.
>
> Having a 3rd state on a killswitch which can't physically _have_ 3
> states isn't right. The switch is often completely independent of the
> radio, and that's something we need to represent.
>
> Because of that, the toggle_radio() member of struct rfkill just isn't
> in the right place. That changes _radio_ block state, but since struct
> rfkill is the _switch_, toggle_radio() is wrong here. In the case of
> hp-wmi, there's no radio to toggle, since it's a hardswitch, and since
> hp-wmi isn't a wireless driver!
>
> Again, we need to separate radio block state from switch state, because
> they are two different things. We don't need to break anything here; we
> just need to add some bits for radio block state.
>
> Dan
>
> > HOWEVER, rfkill can't provide you with "radio is enabled, configured,
> > operational and transmitting" status. It really can't say much of what
> > is happening in the unblocked state.
> >
> > > > Currently we can't differentiate "block changes by the user" from "the
> > > > kernel can change the state if you ask it to". I agree this is a
> > > > desireable feature, and I'd rather add a third rfkill_state to propagate
> > > > that information.
> > >
> > > Well... I still think this is best as a _radio_ property, not as a
> > > killswitch property. Physical switches are physical, you can't change
> > > the state and thus the third state here isn't useful. If we separate
> > > switch state from radio power state that makes it clear (at least to
> > > me).
> >
> > But then you have more than one "switch" per radio, which needs changes
> > to rfkill (currently, you are NOT to do it).
> >
> > Currently, one is to think of a rfkill class as the representation of
> > the "radio property". Which means you *lose the information* of which
> > underlying hardware/firmware reason the device has to be blocked.
> >
> > I think we are actually better off by losing that information, it is
> > not useful for UIs (you need to know the device is force-blocked, not
> > WHY it is blocked or force-blocked -- that is highly platform-specific).
> >
> > > Since the current rfkillX device is the _switch_, and since I'm not
> > > aware of any machines where the BIOS synthesizes a toggle state from a
> > > non-toggle button, maybe we should punt this until such a device
> > > actually turns up?
> >
> > The current rfkillX device represents the radio state, which means it might
> > need to synthesize it from various hardware bits.
> >
> > E.g. Let's look at a possible conversion of IPW2200 to the rfkill class.
> >
> > The IPW2200 driver has TWO rfkill "registers":
> > R1 - Read/Write, controlled by the driver
> > R2 - Read-Only, reflects an input pin in the hardware and cannot be
> > overriden.
> >
> > The IPW2000 driver would register just *one* instance of the rfkill class,
> > and it would return the status as this.
> >
> > Assume R1 active high, and R2 active high. Active means BLOCK RADIO.
> >
> > rfkill_status = (R1 | R2) ? RFKILL_STATUS_OFF : RFKILL_STATUS_ON.
> >
> > I.e. if either one (or both) of the registers are blocking the radio, it
> > reports the status as RFKILL_STATUS_OFF. Otherwise, it reports the status
> > as RFKILL_STATUS_ON (unblocked).
> >
> > Now, for the toggle_radio function in pseudo-code:
> >
> > switch (new_state) {
> > case RFKILL_STATUS_ON:
> > if (R2) {
> > R1 = 1; /* fail safe, least surprise */
> > return -EPERM; /* cannot override! */
> > }
> > R1 = 0;
> > break;
> > case RFKILL_STATUS_OFF:
> > R1 = 1;
> > break;
> > }
> >
> > There are possible variations, the most pressing one that comes to mind
> > is whether we should force the R1 switch to 1 or 0 when R2 is 1 on the
> > RFKILL_STATUS_ON branch. I used the "won't EVER cause the radio to be
> > unblocked by surprise" alternative.
> >
> > However, now userspace really gets to know if the ipw2200 radio is blocked or not,
> > it doesn't have to hunt down two different rfkill class instances for it. And it
> > just needs to listen to uevents (which HAL should be taught to export to DBUS) for
> > ipw2200 to know when the status changes, no pooling or even reading of sysfs
> > attributes would be required.
> >
> > If you wanted to also handle txpower off through rfkill, you'd take the state of
> > txpower into consideration on the code above, and still have only ONE rfkillX
> > instance for the ipw2200 device.
> >
> > > > > The only thing I personally care about is separating radio state from
> > > > > switch state so that I can distinguish a softkill (via ex. iwconfig
> > > > > wlan0 txpower off) from a hardkill via a real killswitch.
> > > >
> > > > Ok, so what you care about is to know if you COULD CHANGE THE STATE,
> > > > correct?
> > >
> > > Could change the radio _block_ state, yes. rfkill switch state no,
> >
> > I mean the radio _block_ state. See above. One rfkill class per device,
> > synthesizing the state of n, n>=1 real switches. So, you get the radio
> > block state from it.
> >
> > > because I don't know of any examples of those and frankly I think it's
> > > easier to just make the user flip the switch again. Keeping it simpler
> > > is better.
> >
> > I'd agree with this view, least surprise is good, and the way the whole
> > rfkill idea was engineered to leave the transmitter BLOCKED in cause of
> > doubt.
> >
> > > > The third state would tell you that.
> > > >
> > > > > Why should a "device rfkill state" be in a separate module? Radio state
> > > > > _is_ rfkill state. rfkill switches turn the radio on or off but
> > > >
> > > > device-wide rfkill state is rfkill state. radio state could be
> > > > anything.
> > >
> > > I started using "radio block state" in this mail instead.
> >
> > Ok, radio block state is also good. As long as we both know exactly
> > what we mean by it.
> >
> > > > But yes, I understand what you want. The two states you talk about are
> > > > the same if you have only ONE rfkill class attached to a device, and
> > > > they are different (but related) things when you have MORE than one
> > > > rfkill class attached to a device.
> > >
> > > What situations would have more than one rfkill class attached to the
> > > device?
> >
> > If you try to model IPW2200 or other hardware with many rfkill input signals
> > as one signal per rfkill class. That's something that is probably NOT a good
> > idea at all.
> >
> > > > IMO, we should attach just one rfkill class per transmitter device, and
> > > > handle the "you cannot change the state" possibility by adding a third
> > > > state to rfkill_state.
> > >
> > > Right about the one rfkill class per device than drives a killswitch.
> > > But that's not necessarily the transmitter device. It might be a child
> > > of the laptop module if it's a BIOS switch that also kills the radio
> > > automatically. In the case of hp-wmi, it provides 3 different rfkill
> > > class devices.
> >
> > Which is why I want to do it in a way we don't have to know what is a
> > child of what, slaved to what, master of what...
> >
> > > > > devices should have _one_ method of turning themselves off through
> > > > > either hardware or software, and the system that provides that method
> > > > > should be the rfkill system.
> > > >
> > > > We don't agree there. If you use "devices should have _one_ method of
> > > > *forcing themselves off* outside of the normal control path of interface
> > > > up/down", THEN we agree.
> > >
> > > Right, all devices with transmitters should have _one_ method of
> > > blocking and unblocking their transmitters.
> >
> > OK.
> >
> > > > The reason is extremely simple: rfkill CANNOT TURN SOMETHING ON. If it
> > > > *was* ON, and you used rfkill to turn it OFF, than yes, when you "stop
> > > > turning it OFF through rfkill", it will go back to ON.
> > > >
> > > > But if it was not ON in the first place, it won't go to ON when you stop
> > > > turning it OFF through rfkill. It will just remain OFF, unless
> > > > something else that is NOT rfkill hooks into the event and takes the
> > > > oportunity to do whatever is needed (such as configure the interface and
> > > > bring it up) to bring the device to ON state.
> > >
> > > Good point.
> >
> > It is a very central point to rfkill, if you lose track of it, things get
> > very confusing, very very quickly.
> >
> > > > > > Anyway, if we are to use various *related* rfkill switches per device,
> > > > > > rfkill needs further changes, including an extra callback into the
> > > > > > driver, so as to be able to export the device rfkill state also in all
> > > > > > switch rfkill state events (otherwise these events become quite useless
> > > > > > for many uses).
> > > > >
> > > > > But yes, there would need to be a "device rfkill state" changed event
> > > > > and another call to get the device rfkill state.
> > > >
> > > > Indeed. It is a possiblity. I still feel a third addition to
> > > > rfkill_state and the use of only ONE rfkill class per transmitter device
> > > > is a better way to do it.
> > >
> > > As I said above, I think I disagree about the third state. I think the
> > > best thing to do is keep the general rfkill switch operation as it is
> > > now (only 2 states, blocked and unblocked), and eventually add a
> > > standard "radio block state" sysfs entry on the _transmitter_ device
> > > with 3 values: hw-blocked, sw-blocked, and unblocked.
> >
> > If we mandate the one-rfkill-class-per-transmitter rule, you now have two
> > attributes that say the very same thing, except that the old one (the one
> > we currently have) lacks the force-blocked state. So basically, you just
> > avoided a minor ABI change by not adding the third state to rfkill_state.
> >
> > If we mandate the one-rfkill-class-per-kill-line rule, you will add
> > complexity, now a driver like IPW2200 would need at least two rfkill
> > class instances. In THIS case, the new attribute conveys interesting
> > information, but OTOH, NM and any user application will have to deal
> > with more than one rfkill sysfs instance per device, and we will have
> > weird issues to deal with, like how to deal with user_claim...
> >
> > The reason I insist on the third state so much is that rfkill *really*
> > was not designed to cope with two or more per transmitter. You now
> > have to mess with various rfkill switches to get something to happen
> > (and most of the time, all but one will EPERM you, because they are
> > read-only, and my subconsious mind is severely screaming up this is
> > a BAD IDEA, we currently forbid read-only switches and I recall there
> > were some subtle issues with the input layer events for read-only
> > stuff).
> >
> > > Does that sound OK? I feel like I have a better understanding of what
> >
> > It WOULD work, I think. But for the reasons above, I am more inclined
> > to add a third state. It is much simpler on the code, and it has no
> > drawbacks I can see, while the multiple rfkill per device approach does
> > have some (and it gives me a bad feeling every time I consider it).
> >
> > What whould be the technical advantages of a separate attribute
> > from your UI (NM) point of view? That is not yet clear to me, at
> > all. Assume you will only get ONE rfkillX interface per device,
> > which means it DOES reflect the block/unblock state of the device.
> >
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Henrique,
On Sun, Jun 22, 2008 at 12:38:48PM -0300, Henrique de Moraes Holschuh wrote:
> +2: Implementation details
> +
> +The rfkill class provides kernel drivers with an interface that allows them to
> +know when they should enable or disable a wireless network device transmitter.
> +
> +The rfkill-input module provides the kernel with the ability to implement
> +a basic response when the user presses a key or button (or toggles a switch)
> +related to rfkill functionality. This is optional, and can also be done in
> +userspace.
> +
> +The rfkill-input module also provides EPO (emergency power-off) functionality
> +for all wireless transmitters. This function cannot be overriden, and it is
> +always active. rfkill EPO is related to *_RFKILL_ALL input events.
> +
I think I would like to see the statement that rfkill-input is an
in-kernel implementation of default policy of reacting to Wifi-related
(in wide sense) button presses and neither mandatory nor required for
wireless drivers to operate.
--
Dmitry
On Fri, 06 Jun 2008, Dan Williams wrote:
> Let me explain this a bit more.
>
> - My original request was based on my flawed understanding of the
> current scope of the rfkill system
Ok. I am keeping that in mind.
> - If the rfkill system is _only_ supposed to handle switches that turn
> the radio off automatically, then a "third state" for the rfkill class
> really serves _no_ purpose at all, because the radio's already blocked
> when the switch is thrown
Given these rules (not documented fully yet, I shall fix it when this
thread quiesces):
1. Every transmitter shall have ONE, and just ONE (not zero, not two,
not more) rfkill class attached. For those transmitters lacking support
in hardware to make it block, the drivers shall quiesce them and avoid
doing anything to cause transmissions, or even use bus tricks to power
the device down (i.e. the driver will emulate a switch capable of doing
the blocking).
Thus, rfkill class will give you the DEVICE (radio) rfkill block/unblock
state on wireless devices (ignore switches for now, I will explain them
in another email).
The information of whether a transmitter is currently blocked in a way
you can request it to be unblocked (soft-kill) or currently blocked in a
way you cannot request it to be unblocked (hard-kill) DOES belong in
rfkill class. Do you want/need that information, yes or no?
> - There are drivers that implement rfkill (laptop-specific BIOS drivers)
> that have _no_ associated transmitter device; thus the current 'struct
> rfkill' can only be a representation of the _switch_; thus a "third
> state" would be useless here as well (as is the toggle_radio() callback)
I haven't finished replying to your other email yet, because it is not a
fast reply (and I am in a hurry in the next two days) and I need to look
at hp-wmi itself to understand what the issue that is causing confusion
is. THAT reply will explain to you how it works with "pure read/write
switches that are not in a wireless device". THEN we shall be able to
unravel the confusion, and I will finally understand what you are trying
to tell me (or you will understand what I am trying to tell you).
> - It just seems a lot clearer to me to have a separation between the
> rfkill switch and the radio bits since there's no need to tie them
> together
And this is part of the confusion. So, for now, please just look at the
question four paragraphs above, and tell me whether you want that
information or not. I'd think you would, since you want to gray out the
"enable radio" button when the radio is blocked by some hardware signal
you cannot override, but I could be confused about it...
--
"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