Subject: [GIT PATCH] rfkill rework for 2.6.27 (v3)


Here is the revised patchset, including (tested) fixes for the problems
reported by Fabien and Dmitry for the last two patches. It includes
Fabien's patch (also tested) to rfkill-input. Fabien sent the
signed-off-by to me privately along with a non-gmane-mangled copy of his
patch.

Dmitry, if you could look the patches dealing with rfkill-input and
either ACK them, or reply with any further issues you find, I'd
appreciate it a lot. I have CC'ed the whole thing to you this time, so
that you can see the big picture.

Ivo, patch 11 is new. It might benefit from either an ACK or NACK from
you. Patch 12 has been ACKed by you previously, but you might want to
check if you still agree with it since I had to do some non-trivial
changes to it.

If there are no further comments or problems with this patchset, I'd
really like to see it sent to the -next tree...

Note that this patchset *requires* commit
5adad0133907790c50283bf03271d920d6897043 from mainline to compile, and
that commit is not available in wireless-testing's master branch. Other
than that, the patches apply on top of wireless-testing master without
fuzz.

They're available at
http://repo.or.cz/w/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
for-upstream/rfkill

(note that the above branch was rebased on top of latest -rc, due to
the lack of commit 5adad0133907790c50283bf03271d920d6897043 in
wireless-testing).

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


2008-06-24 20:29:28

by Fabien Crespel

[permalink] [raw]
Subject: Re: [PATCH 04/13] rfkill: add parameter to disable radios by default

Dan Williams wrote :
> On Tue, 2008-06-24 at 19:06 +0200, Fabien Crespel wrote:
>
>> Indeed, I think it would be better to let the driver choose the default state
>> (initialization) instead of forcing it when registering. This would allow drivers
>> to restore the device state after a reboot or shutdown (provided the firmware
>> stores it, which is the case at least on my ASUS F3JC laptop).
>>
>
> Do you mean your laptop BIOS stores the value in nvram somewhere? What
> specific driver reads that value back out?
>
> Dan
>
Yes, the laptop BIOS stores the value. Reading it back is done the same
way as reading the WLAN/BT status later (through an ACPI method), so the
driver only has to read and write the status at initialization to
restore the device status & LEDs (because the reported status doesn't
reflect the hardware status at boot time).

- Fabien.


Subject: [PATCH 11/13] rfkill: drop current_state from tasks in rfkill-input

From: Fabien Crespel <[email protected]>

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.

Signed-off-by: Fabien Crespel <[email protected]>
Acked-by: Henrique de Moraes Holschuh <[email protected]>
Cc: Ivo van Doorn <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
---
net/rfkill/rfkill-input.c | 15 +--------------
1 files changed, 1 insertions(+), 14 deletions(-)

diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index 29c13d3..d285f9a 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -30,27 +30,15 @@ struct rfkill_task {
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 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
.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);
--
1.5.5.4


Subject: [PATCH 02/13] rfkill: fix minor typo in kernel doc

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


Subject: [PATCH 05/13] rfkill: add read-write rfkill switch support

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


2008-06-25 07:19:31

by Fabien Crespel

[permalink] [raw]
Subject: Re: [PATCH 04/13] rfkill: add parameter to disable radios by default

Dan Williams wrote:
>
> Yeah, but what driver -is- that? asus-laptop or something?
>

It's asus-laptop, but only my own version of it. The current official
version simply turns the devices on when loading. I sent a patch for
this and other features (kill switch awareness, suspend/resume
handlers...) a few months ago but it wasn't included, and anyway
asus-laptop needs a major rework to use the input layer and rfkill. I've
started working on it, and I'll post about it soon.

- Fabien.


Subject: [PATCH 12/13] rfkill: do not allow userspace to override ALL RADIOS OFF

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 | 47 ++++++++++++++++++++++++++++++--------------
net/rfkill/rfkill-input.h | 1 +
net/rfkill/rfkill.c | 18 +++++++++++++++++
3 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index d285f9a..5d4c8b2 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -43,11 +43,26 @@ static void rfkill_task_handler(struct work_struct *work)
mutex_unlock(&task->mutex);
}

+static void rfkill_task_epo_handler(struct work_struct *work)
+{
+ rfkill_epo();
+}
+
+static DECLARE_WORK(epo_work, rfkill_task_epo_handler);
+
+static void rfkill_schedule_epo(void)
+{
+ schedule_work(&epo_work);
+}
+
static void rfkill_schedule_set(struct rfkill_task *task,
enum rfkill_state desired_state)
{
unsigned long flags;

+ if (unlikely(work_pending(&epo_work)))
+ return;
+
spin_lock_irqsave(&task->lock, flags);

if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
@@ -63,6 +78,9 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
{
unsigned long flags;

+ if (unlikely(work_pending(&epo_work)))
+ return;
+
spin_lock_irqsave(&task->lock, flags);

if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
@@ -114,21 +132,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_schedule_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


2008-06-24 17:57:51

by Dan Williams

[permalink] [raw]
Subject: Re: [PATCH 04/13] rfkill: add parameter to disable radios by default

On Tue, 2008-06-24 at 19:06 +0200, Fabien Crespel wrote:
> Dmitry Baryshkov wrote:
> >
> > Why not add the possibility for each rfkill-enabled radio to supply it's
> > default state?
> >
>
> Indeed, I think it would be better to let the driver choose the default state
> (initialization) instead of forcing it when registering. This would allow drivers
> to restore the device state after a reboot or shutdown (provided the firmware
> stores it, which is the case at least on my ASUS F3JC laptop).

Do you mean your laptop BIOS stores the value in nvram somewhere? What
specific driver reads that value back out?

Dan


2008-06-24 21:50:20

by Dan Williams

[permalink] [raw]
Subject: Re: [PATCH 04/13] rfkill: add parameter to disable radios by default

On Tue, 2008-06-24 at 22:29 +0200, Fabien Crespel wrote:
> Dan Williams wrote :
> > On Tue, 2008-06-24 at 19:06 +0200, Fabien Crespel wrote:
> >
> >> Indeed, I think it would be better to let the driver choose the default state
> >> (initialization) instead of forcing it when registering. This would allow drivers
> >> to restore the device state after a reboot or shutdown (provided the firmware
> >> stores it, which is the case at least on my ASUS F3JC laptop).
> >>
> >
> > Do you mean your laptop BIOS stores the value in nvram somewhere? What
> > specific driver reads that value back out?
> >
> > Dan
> >
> Yes, the laptop BIOS stores the value. Reading it back is done the same
> way as reading the WLAN/BT status later (through an ACPI method), so the
> driver only has to read and write the status at initialization to
> restore the device status & LEDs (because the reported status doesn't
> reflect the hardware status at boot time).

Yeah, but what driver -is- that? asus-laptop or something?

Dan


2008-06-23 20:49:49

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [PATCH 11/13] rfkill: drop current_state from tasks in rfkill-input

On Monday 23 June 2008, Henrique de Moraes Holschuh wrote:
> From: Fabien Crespel <[email protected]>
>
> 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.
>
> Signed-off-by: Fabien Crespel <[email protected]>
> Acked-by: Henrique de Moraes Holschuh <[email protected]>
> Cc: Ivo van Doorn <[email protected]>
> Cc: Dmitry Torokhov <[email protected]>

Acked-by: Ivo van Doorn <[email protected]>

> ---
> net/rfkill/rfkill-input.c | 15 +--------------
> 1 files changed, 1 insertions(+), 14 deletions(-)
>
> diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
> index 29c13d3..d285f9a 100644
> --- a/net/rfkill/rfkill-input.c
> +++ b/net/rfkill/rfkill-input.c
> @@ -30,27 +30,15 @@ struct rfkill_task {
> 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 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
> .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);



Subject: Re: [PATCH 04/13] rfkill: add parameter to disable radios by default

On Tue, 24 Jun 2008, Fabien Crespel wrote:
> Dmitry Baryshkov wrote:
>> Why not add the possibility for each rfkill-enabled radio to supply
>> it's default state?
>
> Indeed, I think it would be better to let the driver choose the default
> state (initialization) instead of forcing it when registering. This would

For drivers dealing with input devices, it makes some sense. Mind you,
there IS no API you can use for it right now that will work fine, and anyone
dreaming of doing it through rfkill-input will get an earful :-)

We need to add an API to export the global states in rfkill and rfkill
input, first. platform drivers that are completely sure they know what
they're doing could then use that API to basically call rfkill_toggle_all.

HOWEVER:

1. It requires rfkill's default to be BLOCK. Otherwise, you can have
periods while the devices are blocked at system startup (firmware),
then unblocked during boot (rfkill just loaded), then blocked again
(platform driver loaded after rfkill).

I don't see this as much of an issue, since we'd add this functionality
along with the global state APIs (that need to also address userspace),
so anyone who likes his radios to start UNBLOCKED would just need to do
it in his userspace init scripts.

2. It has severe ordering problems if there is more than one driver wanting
to do it. It is not that it wouldn't work, but not only the radio might
be on undesired states until the last driver loads, the end result would
also depend on WHICH driver loaded last. Yuck.

So the functions would be made to lock down after one use. You'd get one
"set the initial state" per radio type, plus one for RFKILL_ALL.

3. It is only acceptable for drivers of input devices that issue rfkill
events.

> allow drivers to restore the device state after a reboot or shutdown
> (provided the firmware stores it, which is the case at least on my ASUS
> F3JC laptop).

Sounds interesting. But is this functionality worth the hassle of
implementing 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

Subject: [PATCH 01/13] rfkill: clarify meaning of rfkill states

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


Subject: [PATCH 10/13] rfkill: add uevent notifications

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


Subject: [PATCH 04/13] rfkill: add parameter to disable radios by default

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


Subject: [PATCH 07/13] rfkill: rework suspend and resume handlers

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


Subject: [PATCH 06/13] rfkill: add the WWAN radio type

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

Subject: [PATCH 03/13] rfkill: handle SW_RFKILL_ALL events

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


Subject: Re: [PATCH 04/13] rfkill: add parameter to disable radios by default

On Tue, 24 Jun 2008, Dmitry Baryshkov wrote:
> Henrique de Moraes Holschuh wrote:
> > 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".
>
> Why not add the possibility for each rfkill-enabled radio to supply it's
> default state?

The radios already can, and should, inform rfkill of their power-up state
(set rfkill->state before calling rfkill_register), but if it is different
from the global state, rfkill will try to adjust it to match the rest of the
system.

When you implement rfkill support on your wireless driver, you transfer all
policy decisions about rfkill state to the rfkill system.

That's how it is supposed to work. If you have all radios blocked,
hotplugging a new one will cause it to be blocked by rfkill soon after it
registers itsef. If you have bluetooth unblocked, when you hotplug a new
bluetooth radio, rfkill will unblock it when it registers itself.

If you mean you'd like to be able to use kernel parameters to set the
default state for each radio type separately, the first version of the patch
did just that, but it was vetoed and I was asked to use a single parameter.

This doesn't mean the system doesn't control the radios on a per-type basis,
it does. It is just that you can only tell it to start with every radio
BLOCKED by default, or to start with every radio UNBLOCKED by default,
regardless of type.

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

Subject: [PATCH 09/13] rfkill: add type string helper

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


Subject: [PATCH 08/13] rfkill: add notifier chains support

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


2008-06-24 17:10:04

by Fabien Crespel

[permalink] [raw]
Subject: Re: [PATCH 04/13] rfkill: add parameter to disable radios by default

Dmitry Baryshkov wrote:
>
> Why not add the possibility for each rfkill-enabled radio to supply it's
> default state?
>

Indeed, I think it would be better to let the driver choose the default state
(initialization) instead of forcing it when registering. This would allow drivers
to restore the device state after a reboot or shutdown (provided the firmware
stores it, which is the case at least on my ASUS F3JC laptop).

- Fabien.


Subject: [PATCH 13/13] rfkill: document rw rfkill switches and clarify input subsystem interactions

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 | 363 +++++++++++++++++++++++++++++++++++++++-------
1 files changed, 308 insertions(+), 55 deletions(-)

diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt
index ec75d6d..cf230c1 100644
--- a/Documentation/rfkill.txt
+++ b/Documentation/rfkill.txt
@@ -1,83 +1,328 @@
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. It is an in-kernel implementation of default
+policy of reacting to rfkill-related input events and neither mandatory nor
+required for wireless drivers to operate.
+
+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 +332,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


2008-06-25 08:08:22

by Fabien Crespel

[permalink] [raw]
Subject: Re: [PATCH 04/13] rfkill: add parameter to disable radios by default

Henrique de Moraes Holschuh wrote:
> Sounds interesting. But is this functionality worth the hassle of
> implementing it?

For the end user, I think it's better to have the device state restored
at boot time if it's possible. Even though it can be tricky to
implement, as you outlined.

- Fabien.


Subject: Re: [PATCH 04/13] rfkill: add parameter to disable radios by default

Hi Fabien!

On Wed, 25 Jun 2008, Fabien Crespel wrote:

> Henrique de Moraes Holschuh wrote:
>> Sounds interesting. But is this functionality worth the hassle of
>> implementing it?
>
> For the end user, I think it's better to have the device state restored
> at boot time if it's possible. Even though it can be tricky to
> implement, as you outlined.

It is tricky alright. Talking to an user that likes "everything on" at boot
(something I wouldn't be caught dead doing, but hey, to each his own and all
that...), I found another one...

* In order to not lose the possibility of giving rfkill a default of
UNBLOCK, we could accept the kernel parameter as an override of sorts. if
it is there, we block the "first state" API calls and use the value of the
parameter. It wouldn't be that much of an extra mile to go, IMHO, if one
is already doing the rest of the work.

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

2008-06-26 13:28:25

by Dmitry Baryshkov

[permalink] [raw]
Subject: Re: [GIT PATCH] rfkill rework for 2.6.27 (v3)



Hi,

Here is a patch for rfkill sitting in my queue. It depends on the
leds-make-sure-led-trigger-is-valid-before-calling-trigger-activate.patch
lately merged into -mm, which hopefully will be merged into mainline soon
after 2.6.27 window opens.

>From b69b08959d1b1bb989b156492346441dd4a04423 Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <[email protected]>
Date: Fri, 20 Jun 2008 01:48:17 +0400
Subject: [PATCH] RFKILL: small improvements for leds handling

allow one to override the name of the led trigger
provide default activate function to set the state of the led.

Signed-off-by: Dmitry Baryshkov <[email protected]>
---
net/rfkill/rfkill.c | 15 ++++++++++++++-
1 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 4e10a95..e9010ff 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -57,6 +57,16 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
#endif /* CONFIG_RFKILL_LEDS */
}

+#ifdef CONFIG_RFKILL_LEDS
+static void rfkill_led_trigger_activate(struct led_classdev *led)
+{
+ struct rfkill *rfkill = container_of(led->trigger,
+ struct rfkill, led_trigger);
+
+ rfkill_led_trigger(rfkill, rfkill->state);
+}
+#endif /* CONFIG_RFKILL_LEDS */
+
static int rfkill_toggle_radio(struct rfkill *rfkill,
enum rfkill_state state)
{
@@ -355,7 +365,10 @@ static void rfkill_led_trigger_register(struct rfkill *rfkill)
#ifdef CONFIG_RFKILL_LEDS
int error;

- rfkill->led_trigger.name = rfkill->dev.bus_id;
+ if (!rfkill->led_trigger.name)
+ rfkill->led_trigger.name = rfkill->dev.bus_id;
+ if (!rfkill->led_trigger.activate)
+ rfkill->led_trigger.activate = rfkill_led_trigger_activate;
error = led_trigger_register(&rfkill->led_trigger);
if (error)
rfkill->led_trigger.name = NULL;
--
1.5.5.4


--
With best wishes
Dmitry



2008-06-24 14:15:06

by Dmitry Baryshkov

[permalink] [raw]
Subject: Re: [PATCH 04/13] rfkill: add parameter to disable radios by default

Henrique de Moraes Holschuh wrote:

> 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".
>

Why not add the possibility for each rfkill-enabled radio to supply it's
default state?



--
With best wishes
Dmitry