rfkill: query EV_SW states when rfkill-input (re)?connects to a input device

Every time a new input device that is capable of one of the
rfkill EV_SW events (currently only SW_RFKILL_ALL) is connected to
rfkill-input, we must check the states of the input EV_SW switches
and take action.  Otherwise, we will ignore the initial switch state.

We also need to re-check the states of the EV_SW switches after
a device that was under an exclusive grab is released back to us,
since we got no input events from that device while it was grabbed.

Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
Cc: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Henrique de Moraes Holschuh 2008-07-31 10:53:57 -03:00 committed by John W. Linville
parent f860ee26db
commit 6e28fbef0f
1 changed files with 39 additions and 15 deletions

View File

@ -109,6 +109,25 @@ static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
static void rfkill_schedule_evsw_rfkillall(int state)
{
/* EVERY radio type. state != 0 means radios ON */
/* handle EPO (emergency power off) through shortcut */
if (state) {
rfkill_schedule_set(&rfkill_wwan,
RFKILL_STATE_UNBLOCKED);
rfkill_schedule_set(&rfkill_wimax,
RFKILL_STATE_UNBLOCKED);
rfkill_schedule_set(&rfkill_uwb,
RFKILL_STATE_UNBLOCKED);
rfkill_schedule_set(&rfkill_bt,
RFKILL_STATE_UNBLOCKED);
rfkill_schedule_set(&rfkill_wlan,
RFKILL_STATE_UNBLOCKED);
} else
rfkill_schedule_epo();
}
static void rfkill_event(struct input_handle *handle, unsigned int type,
unsigned int code, int data)
{
@ -132,21 +151,7 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
} else if (type == EV_SW) {
switch (code) {
case SW_RFKILL_ALL:
/* EVERY radio type. data != 0 means radios ON */
/* handle EPO (emergency power off) through shortcut */
if (data) {
rfkill_schedule_set(&rfkill_wwan,
RFKILL_STATE_UNBLOCKED);
rfkill_schedule_set(&rfkill_wimax,
RFKILL_STATE_UNBLOCKED);
rfkill_schedule_set(&rfkill_uwb,
RFKILL_STATE_UNBLOCKED);
rfkill_schedule_set(&rfkill_bt,
RFKILL_STATE_UNBLOCKED);
rfkill_schedule_set(&rfkill_wlan,
RFKILL_STATE_UNBLOCKED);
} else
rfkill_schedule_epo();
rfkill_schedule_evsw_rfkillall(data);
break;
default:
break;
@ -168,6 +173,7 @@ static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
handle->handler = handler;
handle->name = "rfkill";
/* causes rfkill_start() to be called */
error = input_register_handle(handle);
if (error)
goto err_free_handle;
@ -185,6 +191,23 @@ static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
return error;
}
static void rfkill_start(struct input_handle *handle)
{
/* Take event_lock to guard against configuration changes, we
* should be able to deal with concurrency with rfkill_event()
* just fine (which event_lock will also avoid). */
spin_lock_irq(&handle->dev->event_lock);
if (test_bit(EV_SW, handle->dev->evbit)) {
if (test_bit(SW_RFKILL_ALL, handle->dev->swbit))
rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL,
handle->dev->sw));
/* add resync for further EV_SW events here */
}
spin_unlock_irq(&handle->dev->event_lock);
}
static void rfkill_disconnect(struct input_handle *handle)
{
input_close_device(handle);
@ -225,6 +248,7 @@ static struct input_handler rfkill_handler = {
.event = rfkill_event,
.connect = rfkill_connect,
.disconnect = rfkill_disconnect,
.start = rfkill_start,
.name = "rfkill",
.id_table = rfkill_ids,
};