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:
parent
f860ee26db
commit
6e28fbef0f
@ -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_wimax, RFKILL_TYPE_WIMAX);
|
||||||
static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
|
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,
|
static void rfkill_event(struct input_handle *handle, unsigned int type,
|
||||||
unsigned int code, int data)
|
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) {
|
} else if (type == EV_SW) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case SW_RFKILL_ALL:
|
case SW_RFKILL_ALL:
|
||||||
/* EVERY radio type. data != 0 means radios ON */
|
rfkill_schedule_evsw_rfkillall(data);
|
||||||
/* 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();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -168,6 +173,7 @@ static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
|
|||||||
handle->handler = handler;
|
handle->handler = handler;
|
||||||
handle->name = "rfkill";
|
handle->name = "rfkill";
|
||||||
|
|
||||||
|
/* causes rfkill_start() to be called */
|
||||||
error = input_register_handle(handle);
|
error = input_register_handle(handle);
|
||||||
if (error)
|
if (error)
|
||||||
goto err_free_handle;
|
goto err_free_handle;
|
||||||
@ -185,6 +191,23 @@ static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
|
|||||||
return error;
|
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)
|
static void rfkill_disconnect(struct input_handle *handle)
|
||||||
{
|
{
|
||||||
input_close_device(handle);
|
input_close_device(handle);
|
||||||
@ -225,6 +248,7 @@ static struct input_handler rfkill_handler = {
|
|||||||
.event = rfkill_event,
|
.event = rfkill_event,
|
||||||
.connect = rfkill_connect,
|
.connect = rfkill_connect,
|
||||||
.disconnect = rfkill_disconnect,
|
.disconnect = rfkill_disconnect,
|
||||||
|
.start = rfkill_start,
|
||||||
.name = "rfkill",
|
.name = "rfkill",
|
||||||
.id_table = rfkill_ids,
|
.id_table = rfkill_ids,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user