From 19d337dff95cbf76edd3ad95c0cee2732c3e1ec5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jun 2009 13:01:37 +0200 Subject: 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 Signed-off-by: Henrique de Moraes Holschuh [thinkpad] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/platform/x86/acer-wmi.c | 50 ++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 28 deletions(-) (limited to 'drivers/platform/x86/acer-wmi.c') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 62d02b3c998e..b618fa51db2d 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -958,58 +958,50 @@ static void acer_rfkill_update(struct work_struct *ignored) status = get_u32(&state, ACER_CAP_WIRELESS); if (ACPI_SUCCESS(status)) - rfkill_force_state(wireless_rfkill, state ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED); + rfkill_set_sw_state(wireless_rfkill, !!state); if (has_cap(ACER_CAP_BLUETOOTH)) { status = get_u32(&state, ACER_CAP_BLUETOOTH); if (ACPI_SUCCESS(status)) - rfkill_force_state(bluetooth_rfkill, state ? - RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED); + rfkill_set_sw_state(bluetooth_rfkill, !!state); } schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); } -static int acer_rfkill_set(void *data, enum rfkill_state state) +static int acer_rfkill_set(void *data, bool blocked) { acpi_status status; - u32 *cap = data; - status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap); + u32 cap = (unsigned long)data; + status = set_u32(!!blocked, cap); if (ACPI_FAILURE(status)) return -ENODEV; return 0; } -static struct rfkill * acer_rfkill_register(struct device *dev, -enum rfkill_type type, char *name, u32 cap) +static const struct rfkill_ops acer_rfkill_ops = { + .set_block = acer_rfkill_set, +}; + +static struct rfkill *acer_rfkill_register(struct device *dev, + enum rfkill_type type, + char *name, u32 cap) { int err; u32 state; - u32 *data; struct rfkill *rfkill_dev; - rfkill_dev = rfkill_allocate(dev, type); + rfkill_dev = rfkill_alloc(name, dev, type, + &acer_rfkill_ops, + (void *)(unsigned long)cap); if (!rfkill_dev) return ERR_PTR(-ENOMEM); - rfkill_dev->name = name; get_u32(&state, cap); - rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED; - data = kzalloc(sizeof(u32), GFP_KERNEL); - if (!data) { - rfkill_free(rfkill_dev); - return ERR_PTR(-ENOMEM); - } - *data = cap; - rfkill_dev->data = data; - rfkill_dev->toggle_radio = acer_rfkill_set; + rfkill_set_sw_state(rfkill_dev, !state); err = rfkill_register(rfkill_dev); if (err) { - kfree(rfkill_dev->data); - rfkill_free(rfkill_dev); + rfkill_destroy(rfkill_dev); return ERR_PTR(err); } return rfkill_dev; @@ -1027,8 +1019,8 @@ static int acer_rfkill_init(struct device *dev) RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", ACER_CAP_BLUETOOTH); if (IS_ERR(bluetooth_rfkill)) { - kfree(wireless_rfkill->data); rfkill_unregister(wireless_rfkill); + rfkill_destroy(wireless_rfkill); return PTR_ERR(bluetooth_rfkill); } } @@ -1041,11 +1033,13 @@ static int acer_rfkill_init(struct device *dev) static void acer_rfkill_exit(void) { cancel_delayed_work_sync(&acer_rfkill_work); - kfree(wireless_rfkill->data); + rfkill_unregister(wireless_rfkill); + rfkill_destroy(wireless_rfkill); + if (has_cap(ACER_CAP_BLUETOOTH)) { - kfree(bluetooth_rfkill->data); rfkill_unregister(bluetooth_rfkill); + rfkill_destroy(bluetooth_rfkill); } return; } -- cgit v1.2.3