mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
rfkill: rewrite
This patch completely rewrites the rfkill core to address the following deficiencies: * all rfkill drivers need to implement polling where necessary rather than having one central implementation * updating the rfkill state cannot be done from arbitrary contexts, forcing drivers to use schedule_work and requiring lots of code * rfkill drivers need to keep track of soft/hard blocked internally -- the core should do this * the rfkill API has many unexpected quirks, for example being asymmetric wrt. alloc/free and register/unregister * rfkill can call back into a driver from within a function the driver called -- this is prone to deadlocks and generally should be avoided * rfkill-input pointlessly is a separate module * drivers need to #ifdef rfkill functions (unless they want to depend on or select RFKILL) -- rfkill should provide inlines that do nothing if it isn't compiled in * the rfkill structure is not opaque -- drivers need to initialise it correctly (lots of sanity checking code required) -- instead force drivers to pass the right variables to rfkill_alloc() * the documentation is hard to read because it always assumes the reader is completely clueless and contains way TOO MANY CAPS * the rfkill code needlessly uses a lot of locks and atomic operations in locked sections * fix LED trigger to actually change the LED when the radio state changes -- this wasn't done before Tested-by: Alan Jenkins <[email protected]> Signed-off-by: Henrique de Moraes Holschuh <[email protected]> [thinkpad] Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: John W. Linville <[email protected]>
This commit is contained in:
parent
0f6399c4c5
commit
19d337dff9
46 changed files with 2536 additions and 3273 deletions
|
|
@ -1,23 +1,9 @@
|
|||
#
|
||||
# WiMAX LAN device configuration
|
||||
#
|
||||
# Note the ugly 'depends on' on WIMAX: that disallows RFKILL to be a
|
||||
# module if WIMAX is to be linked in. The WiMAX code is done in such a
|
||||
# way that it doesn't require and explicit dependency on RFKILL in
|
||||
# case an embedded system wants to rip it out.
|
||||
#
|
||||
# As well, enablement of the RFKILL code means we need the INPUT layer
|
||||
# support to inject events coming from hw rfkill switches. That
|
||||
# dependency could be killed if input.h provided appropriate means to
|
||||
# work when input is disabled.
|
||||
|
||||
comment "WiMAX Wireless Broadband support requires CONFIG_INPUT enabled"
|
||||
depends on INPUT = n && RFKILL != n
|
||||
|
||||
menuconfig WIMAX
|
||||
tristate "WiMAX Wireless Broadband support"
|
||||
depends on (y && RFKILL != m) || m
|
||||
depends on (INPUT && RFKILL != n) || RFKILL = n
|
||||
help
|
||||
|
||||
Select to configure support for devices that provide
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@
|
|||
* A non-polled generic rfkill device is embedded into the WiMAX
|
||||
* subsystem's representation of a device.
|
||||
*
|
||||
* FIXME: Need polled support? use a timer or add the implementation
|
||||
* to the stack.
|
||||
* FIXME: Need polled support? Let drivers provide a poll routine
|
||||
* and hand it to rfkill ops then?
|
||||
*
|
||||
* All device drivers have to do is after wimax_dev_init(), call
|
||||
* wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
* wimax_rfkill() Kernel calling wimax_rfkill()
|
||||
* __wimax_rf_toggle_radio()
|
||||
*
|
||||
* wimax_rfkill_toggle_radio() RF-Kill subsytem calling
|
||||
* wimax_rfkill_set_radio_block() RF-Kill subsytem calling
|
||||
* __wimax_rf_toggle_radio()
|
||||
*
|
||||
* __wimax_rf_toggle_radio()
|
||||
|
|
@ -65,15 +65,11 @@
|
|||
#include <linux/wimax.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/input.h>
|
||||
#include "wimax-internal.h"
|
||||
|
||||
#define D_SUBMODULE op_rfkill
|
||||
#include "debug-levels.h"
|
||||
|
||||
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
|
||||
|
||||
|
||||
/**
|
||||
* wimax_report_rfkill_hw - Reports changes in the hardware RF switch
|
||||
*
|
||||
|
|
@ -99,7 +95,6 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
|
|||
int result;
|
||||
struct device *dev = wimax_dev_to_dev(wimax_dev);
|
||||
enum wimax_st wimax_state;
|
||||
enum rfkill_state rfkill_state;
|
||||
|
||||
d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
|
||||
BUG_ON(state == WIMAX_RF_QUERY);
|
||||
|
|
@ -112,16 +107,15 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
|
|||
|
||||
if (state != wimax_dev->rf_hw) {
|
||||
wimax_dev->rf_hw = state;
|
||||
rfkill_state = state == WIMAX_RF_ON ?
|
||||
RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
|
||||
if (wimax_dev->rf_hw == WIMAX_RF_ON
|
||||
&& wimax_dev->rf_sw == WIMAX_RF_ON)
|
||||
wimax_state = WIMAX_ST_READY;
|
||||
else
|
||||
wimax_state = WIMAX_ST_RADIO_OFF;
|
||||
|
||||
rfkill_set_hw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
|
||||
|
||||
__wimax_state_change(wimax_dev, wimax_state);
|
||||
input_report_key(wimax_dev->rfkill_input, KEY_WIMAX,
|
||||
rfkill_state);
|
||||
}
|
||||
error_not_ready:
|
||||
mutex_unlock(&wimax_dev->mutex);
|
||||
|
|
@ -174,6 +168,7 @@ void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
|
|||
else
|
||||
wimax_state = WIMAX_ST_RADIO_OFF;
|
||||
__wimax_state_change(wimax_dev, wimax_state);
|
||||
rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
|
||||
}
|
||||
error_not_ready:
|
||||
mutex_unlock(&wimax_dev->mutex);
|
||||
|
|
@ -249,36 +244,31 @@ out_no_change:
|
|||
*
|
||||
* NOTE: This call will block until the operation is completed.
|
||||
*/
|
||||
static
|
||||
int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state)
|
||||
static int wimax_rfkill_set_radio_block(void *data, bool blocked)
|
||||
{
|
||||
int result;
|
||||
struct wimax_dev *wimax_dev = data;
|
||||
struct device *dev = wimax_dev_to_dev(wimax_dev);
|
||||
enum wimax_rf_state rf_state;
|
||||
|
||||
d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
|
||||
switch (state) {
|
||||
case RFKILL_STATE_SOFT_BLOCKED:
|
||||
d_fnstart(3, dev, "(wimax_dev %p blocked %u)\n", wimax_dev, blocked);
|
||||
rf_state = WIMAX_RF_ON;
|
||||
if (blocked)
|
||||
rf_state = WIMAX_RF_OFF;
|
||||
break;
|
||||
case RFKILL_STATE_UNBLOCKED:
|
||||
rf_state = WIMAX_RF_ON;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
mutex_lock(&wimax_dev->mutex);
|
||||
if (wimax_dev->state <= __WIMAX_ST_QUIESCING)
|
||||
result = 0; /* just pretend it didn't happen */
|
||||
result = 0;
|
||||
else
|
||||
result = __wimax_rf_toggle_radio(wimax_dev, rf_state);
|
||||
mutex_unlock(&wimax_dev->mutex);
|
||||
d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n",
|
||||
wimax_dev, state, result);
|
||||
d_fnend(3, dev, "(wimax_dev %p blocked %u) = %d\n",
|
||||
wimax_dev, blocked, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const struct rfkill_ops wimax_rfkill_ops = {
|
||||
.set_block = wimax_rfkill_set_radio_block,
|
||||
};
|
||||
|
||||
/**
|
||||
* wimax_rfkill - Set the software RF switch state for a WiMAX device
|
||||
|
|
@ -322,6 +312,7 @@ int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state)
|
|||
result = __wimax_rf_toggle_radio(wimax_dev, state);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
|
||||
break;
|
||||
case WIMAX_RF_QUERY:
|
||||
break;
|
||||
|
|
@ -349,40 +340,20 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
|
|||
{
|
||||
int result;
|
||||
struct rfkill *rfkill;
|
||||
struct input_dev *input_dev;
|
||||
struct device *dev = wimax_dev_to_dev(wimax_dev);
|
||||
|
||||
d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
|
||||
/* Initialize RF Kill */
|
||||
result = -ENOMEM;
|
||||
rfkill = rfkill_allocate(dev, RFKILL_TYPE_WIMAX);
|
||||
rfkill = rfkill_alloc(wimax_dev->name, dev, RFKILL_TYPE_WIMAX,
|
||||
&wimax_rfkill_ops, wimax_dev);
|
||||
if (rfkill == NULL)
|
||||
goto error_rfkill_allocate;
|
||||
|
||||
d_printf(1, dev, "rfkill %p\n", rfkill);
|
||||
|
||||
wimax_dev->rfkill = rfkill;
|
||||
|
||||
rfkill->name = wimax_dev->name;
|
||||
rfkill->state = RFKILL_STATE_UNBLOCKED;
|
||||
rfkill->data = wimax_dev;
|
||||
rfkill->toggle_radio = wimax_rfkill_toggle_radio;
|
||||
|
||||
/* Initialize the input device for the hw key */
|
||||
input_dev = input_allocate_device();
|
||||
if (input_dev == NULL)
|
||||
goto error_input_allocate;
|
||||
wimax_dev->rfkill_input = input_dev;
|
||||
d_printf(1, dev, "rfkill %p input %p\n", rfkill, input_dev);
|
||||
|
||||
input_dev->name = wimax_dev->name;
|
||||
/* FIXME: get a real device bus ID and stuff? do we care? */
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->id.vendor = 0xffff;
|
||||
input_dev->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_WIMAX, input_dev->keybit);
|
||||
|
||||
/* Register both */
|
||||
result = input_register_device(wimax_dev->rfkill_input);
|
||||
if (result < 0)
|
||||
goto error_input_register;
|
||||
result = rfkill_register(wimax_dev->rfkill);
|
||||
if (result < 0)
|
||||
goto error_rfkill_register;
|
||||
|
|
@ -394,17 +365,8 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
|
|||
d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev);
|
||||
return 0;
|
||||
|
||||
/* if rfkill_register() suceeds, can't use rfkill_free() any
|
||||
* more, only rfkill_unregister() [it owns the refcount]; with
|
||||
* the input device we have the same issue--hence the if. */
|
||||
error_rfkill_register:
|
||||
input_unregister_device(wimax_dev->rfkill_input);
|
||||
wimax_dev->rfkill_input = NULL;
|
||||
error_input_register:
|
||||
if (wimax_dev->rfkill_input)
|
||||
input_free_device(wimax_dev->rfkill_input);
|
||||
error_input_allocate:
|
||||
rfkill_free(wimax_dev->rfkill);
|
||||
rfkill_destroy(wimax_dev->rfkill);
|
||||
error_rfkill_allocate:
|
||||
d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result);
|
||||
return result;
|
||||
|
|
@ -423,45 +385,12 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
|
|||
{
|
||||
struct device *dev = wimax_dev_to_dev(wimax_dev);
|
||||
d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
|
||||
rfkill_unregister(wimax_dev->rfkill); /* frees */
|
||||
input_unregister_device(wimax_dev->rfkill_input);
|
||||
rfkill_unregister(wimax_dev->rfkill);
|
||||
rfkill_destroy(wimax_dev->rfkill);
|
||||
d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev);
|
||||
}
|
||||
|
||||
|
||||
#else /* #ifdef CONFIG_RFKILL */
|
||||
|
||||
void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
|
||||
enum wimax_rf_state state)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw);
|
||||
|
||||
void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
|
||||
enum wimax_rf_state state)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw);
|
||||
|
||||
int wimax_rfkill(struct wimax_dev *wimax_dev,
|
||||
enum wimax_rf_state state)
|
||||
{
|
||||
return WIMAX_RF_ON << 1 | WIMAX_RF_ON;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wimax_rfkill);
|
||||
|
||||
int wimax_rfkill_add(struct wimax_dev *wimax_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* #ifdef CONFIG_RFKILL */
|
||||
|
||||
|
||||
/*
|
||||
* Exporting to user space over generic netlink
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in a new issue