diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-06-02 07:01:37 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-06-03 14:06:13 -0400 |
commit | 19d337dff95cbf76edd3ad95c0cee2732c3e1ec5 (patch) | |
tree | 33326eeb09cb9664cc8427a5dc7cd2b08b5a57c3 /net/wimax | |
parent | 0f6399c4c525b518644a9b09f8d6fb125a418c4d (diff) |
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 <alan-jenkins@tuffmail.co.uk>
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> [thinkpad]
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wimax')
-rw-r--r-- | net/wimax/Kconfig | 14 | ||||
-rw-r--r-- | net/wimax/op-rfkill.c | 123 |
2 files changed, 26 insertions, 111 deletions
diff --git a/net/wimax/Kconfig b/net/wimax/Kconfig index 1b46747a5f5a..0bdbb6928205 100644 --- a/net/wimax/Kconfig +++ b/net/wimax/Kconfig | |||
@@ -1,23 +1,9 @@ | |||
1 | # | 1 | # |
2 | # WiMAX LAN device configuration | 2 | # WiMAX LAN device configuration |
3 | # | 3 | # |
4 | # Note the ugly 'depends on' on WIMAX: that disallows RFKILL to be a | ||
5 | # module if WIMAX is to be linked in. The WiMAX code is done in such a | ||
6 | # way that it doesn't require and explicit dependency on RFKILL in | ||
7 | # case an embedded system wants to rip it out. | ||
8 | # | ||
9 | # As well, enablement of the RFKILL code means we need the INPUT layer | ||
10 | # support to inject events coming from hw rfkill switches. That | ||
11 | # dependency could be killed if input.h provided appropriate means to | ||
12 | # work when input is disabled. | ||
13 | |||
14 | comment "WiMAX Wireless Broadband support requires CONFIG_INPUT enabled" | ||
15 | depends on INPUT = n && RFKILL != n | ||
16 | 4 | ||
17 | menuconfig WIMAX | 5 | menuconfig WIMAX |
18 | tristate "WiMAX Wireless Broadband support" | 6 | tristate "WiMAX Wireless Broadband support" |
19 | depends on (y && RFKILL != m) || m | ||
20 | depends on (INPUT && RFKILL != n) || RFKILL = n | ||
21 | help | 7 | help |
22 | 8 | ||
23 | Select to configure support for devices that provide | 9 | Select to configure support for devices that provide |
diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index a3616e2ccb8a..bb102e4aa3e9 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c | |||
@@ -29,8 +29,8 @@ | |||
29 | * A non-polled generic rfkill device is embedded into the WiMAX | 29 | * A non-polled generic rfkill device is embedded into the WiMAX |
30 | * subsystem's representation of a device. | 30 | * subsystem's representation of a device. |
31 | * | 31 | * |
32 | * FIXME: Need polled support? use a timer or add the implementation | 32 | * FIXME: Need polled support? Let drivers provide a poll routine |
33 | * to the stack. | 33 | * and hand it to rfkill ops then? |
34 | * | 34 | * |
35 | * All device drivers have to do is after wimax_dev_init(), call | 35 | * All device drivers have to do is after wimax_dev_init(), call |
36 | * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update | 36 | * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update |
@@ -43,7 +43,7 @@ | |||
43 | * wimax_rfkill() Kernel calling wimax_rfkill() | 43 | * wimax_rfkill() Kernel calling wimax_rfkill() |
44 | * __wimax_rf_toggle_radio() | 44 | * __wimax_rf_toggle_radio() |
45 | * | 45 | * |
46 | * wimax_rfkill_toggle_radio() RF-Kill subsytem calling | 46 | * wimax_rfkill_set_radio_block() RF-Kill subsytem calling |
47 | * __wimax_rf_toggle_radio() | 47 | * __wimax_rf_toggle_radio() |
48 | * | 48 | * |
49 | * __wimax_rf_toggle_radio() | 49 | * __wimax_rf_toggle_radio() |
@@ -65,15 +65,11 @@ | |||
65 | #include <linux/wimax.h> | 65 | #include <linux/wimax.h> |
66 | #include <linux/security.h> | 66 | #include <linux/security.h> |
67 | #include <linux/rfkill.h> | 67 | #include <linux/rfkill.h> |
68 | #include <linux/input.h> | ||
69 | #include "wimax-internal.h" | 68 | #include "wimax-internal.h" |
70 | 69 | ||
71 | #define D_SUBMODULE op_rfkill | 70 | #define D_SUBMODULE op_rfkill |
72 | #include "debug-levels.h" | 71 | #include "debug-levels.h" |
73 | 72 | ||
74 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
75 | |||
76 | |||
77 | /** | 73 | /** |
78 | * wimax_report_rfkill_hw - Reports changes in the hardware RF switch | 74 | * wimax_report_rfkill_hw - Reports changes in the hardware RF switch |
79 | * | 75 | * |
@@ -99,7 +95,6 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, | |||
99 | int result; | 95 | int result; |
100 | struct device *dev = wimax_dev_to_dev(wimax_dev); | 96 | struct device *dev = wimax_dev_to_dev(wimax_dev); |
101 | enum wimax_st wimax_state; | 97 | enum wimax_st wimax_state; |
102 | enum rfkill_state rfkill_state; | ||
103 | 98 | ||
104 | d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); | 99 | d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); |
105 | BUG_ON(state == WIMAX_RF_QUERY); | 100 | BUG_ON(state == WIMAX_RF_QUERY); |
@@ -112,16 +107,15 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, | |||
112 | 107 | ||
113 | if (state != wimax_dev->rf_hw) { | 108 | if (state != wimax_dev->rf_hw) { |
114 | wimax_dev->rf_hw = state; | 109 | wimax_dev->rf_hw = state; |
115 | rfkill_state = state == WIMAX_RF_ON ? | ||
116 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | ||
117 | if (wimax_dev->rf_hw == WIMAX_RF_ON | 110 | if (wimax_dev->rf_hw == WIMAX_RF_ON |
118 | && wimax_dev->rf_sw == WIMAX_RF_ON) | 111 | && wimax_dev->rf_sw == WIMAX_RF_ON) |
119 | wimax_state = WIMAX_ST_READY; | 112 | wimax_state = WIMAX_ST_READY; |
120 | else | 113 | else |
121 | wimax_state = WIMAX_ST_RADIO_OFF; | 114 | wimax_state = WIMAX_ST_RADIO_OFF; |
115 | |||
116 | rfkill_set_hw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); | ||
117 | |||
122 | __wimax_state_change(wimax_dev, wimax_state); | 118 | __wimax_state_change(wimax_dev, wimax_state); |
123 | input_report_key(wimax_dev->rfkill_input, KEY_WIMAX, | ||
124 | rfkill_state); | ||
125 | } | 119 | } |
126 | error_not_ready: | 120 | error_not_ready: |
127 | mutex_unlock(&wimax_dev->mutex); | 121 | mutex_unlock(&wimax_dev->mutex); |
@@ -174,6 +168,7 @@ void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, | |||
174 | else | 168 | else |
175 | wimax_state = WIMAX_ST_RADIO_OFF; | 169 | wimax_state = WIMAX_ST_RADIO_OFF; |
176 | __wimax_state_change(wimax_dev, wimax_state); | 170 | __wimax_state_change(wimax_dev, wimax_state); |
171 | rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); | ||
177 | } | 172 | } |
178 | error_not_ready: | 173 | error_not_ready: |
179 | mutex_unlock(&wimax_dev->mutex); | 174 | mutex_unlock(&wimax_dev->mutex); |
@@ -249,36 +244,31 @@ out_no_change: | |||
249 | * | 244 | * |
250 | * NOTE: This call will block until the operation is completed. | 245 | * NOTE: This call will block until the operation is completed. |
251 | */ | 246 | */ |
252 | static | 247 | static int wimax_rfkill_set_radio_block(void *data, bool blocked) |
253 | int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state) | ||
254 | { | 248 | { |
255 | int result; | 249 | int result; |
256 | struct wimax_dev *wimax_dev = data; | 250 | struct wimax_dev *wimax_dev = data; |
257 | struct device *dev = wimax_dev_to_dev(wimax_dev); | 251 | struct device *dev = wimax_dev_to_dev(wimax_dev); |
258 | enum wimax_rf_state rf_state; | 252 | enum wimax_rf_state rf_state; |
259 | 253 | ||
260 | d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); | 254 | d_fnstart(3, dev, "(wimax_dev %p blocked %u)\n", wimax_dev, blocked); |
261 | switch (state) { | 255 | rf_state = WIMAX_RF_ON; |
262 | case RFKILL_STATE_SOFT_BLOCKED: | 256 | if (blocked) |
263 | rf_state = WIMAX_RF_OFF; | 257 | rf_state = WIMAX_RF_OFF; |
264 | break; | ||
265 | case RFKILL_STATE_UNBLOCKED: | ||
266 | rf_state = WIMAX_RF_ON; | ||
267 | break; | ||
268 | default: | ||
269 | BUG(); | ||
270 | } | ||
271 | mutex_lock(&wimax_dev->mutex); | 258 | mutex_lock(&wimax_dev->mutex); |
272 | if (wimax_dev->state <= __WIMAX_ST_QUIESCING) | 259 | if (wimax_dev->state <= __WIMAX_ST_QUIESCING) |
273 | result = 0; /* just pretend it didn't happen */ | 260 | result = 0; |
274 | else | 261 | else |
275 | result = __wimax_rf_toggle_radio(wimax_dev, rf_state); | 262 | result = __wimax_rf_toggle_radio(wimax_dev, rf_state); |
276 | mutex_unlock(&wimax_dev->mutex); | 263 | mutex_unlock(&wimax_dev->mutex); |
277 | d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n", | 264 | d_fnend(3, dev, "(wimax_dev %p blocked %u) = %d\n", |
278 | wimax_dev, state, result); | 265 | wimax_dev, blocked, result); |
279 | return result; | 266 | return result; |
280 | } | 267 | } |
281 | 268 | ||
269 | static const struct rfkill_ops wimax_rfkill_ops = { | ||
270 | .set_block = wimax_rfkill_set_radio_block, | ||
271 | }; | ||
282 | 272 | ||
283 | /** | 273 | /** |
284 | * wimax_rfkill - Set the software RF switch state for a WiMAX device | 274 | * 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) | |||
322 | result = __wimax_rf_toggle_radio(wimax_dev, state); | 312 | result = __wimax_rf_toggle_radio(wimax_dev, state); |
323 | if (result < 0) | 313 | if (result < 0) |
324 | goto error; | 314 | goto error; |
315 | rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); | ||
325 | break; | 316 | break; |
326 | case WIMAX_RF_QUERY: | 317 | case WIMAX_RF_QUERY: |
327 | break; | 318 | break; |
@@ -349,40 +340,20 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) | |||
349 | { | 340 | { |
350 | int result; | 341 | int result; |
351 | struct rfkill *rfkill; | 342 | struct rfkill *rfkill; |
352 | struct input_dev *input_dev; | ||
353 | struct device *dev = wimax_dev_to_dev(wimax_dev); | 343 | struct device *dev = wimax_dev_to_dev(wimax_dev); |
354 | 344 | ||
355 | d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); | 345 | d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); |
356 | /* Initialize RF Kill */ | 346 | /* Initialize RF Kill */ |
357 | result = -ENOMEM; | 347 | result = -ENOMEM; |
358 | rfkill = rfkill_allocate(dev, RFKILL_TYPE_WIMAX); | 348 | rfkill = rfkill_alloc(wimax_dev->name, dev, RFKILL_TYPE_WIMAX, |
349 | &wimax_rfkill_ops, wimax_dev); | ||
359 | if (rfkill == NULL) | 350 | if (rfkill == NULL) |
360 | goto error_rfkill_allocate; | 351 | goto error_rfkill_allocate; |
352 | |||
353 | d_printf(1, dev, "rfkill %p\n", rfkill); | ||
354 | |||
361 | wimax_dev->rfkill = rfkill; | 355 | wimax_dev->rfkill = rfkill; |
362 | 356 | ||
363 | rfkill->name = wimax_dev->name; | ||
364 | rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
365 | rfkill->data = wimax_dev; | ||
366 | rfkill->toggle_radio = wimax_rfkill_toggle_radio; | ||
367 | |||
368 | /* Initialize the input device for the hw key */ | ||
369 | input_dev = input_allocate_device(); | ||
370 | if (input_dev == NULL) | ||
371 | goto error_input_allocate; | ||
372 | wimax_dev->rfkill_input = input_dev; | ||
373 | d_printf(1, dev, "rfkill %p input %p\n", rfkill, input_dev); | ||
374 | |||
375 | input_dev->name = wimax_dev->name; | ||
376 | /* FIXME: get a real device bus ID and stuff? do we care? */ | ||
377 | input_dev->id.bustype = BUS_HOST; | ||
378 | input_dev->id.vendor = 0xffff; | ||
379 | input_dev->evbit[0] = BIT(EV_KEY); | ||
380 | set_bit(KEY_WIMAX, input_dev->keybit); | ||
381 | |||
382 | /* Register both */ | ||
383 | result = input_register_device(wimax_dev->rfkill_input); | ||
384 | if (result < 0) | ||
385 | goto error_input_register; | ||
386 | result = rfkill_register(wimax_dev->rfkill); | 357 | result = rfkill_register(wimax_dev->rfkill); |
387 | if (result < 0) | 358 | if (result < 0) |
388 | goto error_rfkill_register; | 359 | goto error_rfkill_register; |
@@ -394,17 +365,8 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) | |||
394 | d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev); | 365 | d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev); |
395 | return 0; | 366 | return 0; |
396 | 367 | ||
397 | /* if rfkill_register() suceeds, can't use rfkill_free() any | ||
398 | * more, only rfkill_unregister() [it owns the refcount]; with | ||
399 | * the input device we have the same issue--hence the if. */ | ||
400 | error_rfkill_register: | 368 | error_rfkill_register: |
401 | input_unregister_device(wimax_dev->rfkill_input); | 369 | rfkill_destroy(wimax_dev->rfkill); |
402 | wimax_dev->rfkill_input = NULL; | ||
403 | error_input_register: | ||
404 | if (wimax_dev->rfkill_input) | ||
405 | input_free_device(wimax_dev->rfkill_input); | ||
406 | error_input_allocate: | ||
407 | rfkill_free(wimax_dev->rfkill); | ||
408 | error_rfkill_allocate: | 370 | error_rfkill_allocate: |
409 | d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); | 371 | d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); |
410 | return result; | 372 | return result; |
@@ -423,45 +385,12 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev) | |||
423 | { | 385 | { |
424 | struct device *dev = wimax_dev_to_dev(wimax_dev); | 386 | struct device *dev = wimax_dev_to_dev(wimax_dev); |
425 | d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); | 387 | d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); |
426 | rfkill_unregister(wimax_dev->rfkill); /* frees */ | 388 | rfkill_unregister(wimax_dev->rfkill); |
427 | input_unregister_device(wimax_dev->rfkill_input); | 389 | rfkill_destroy(wimax_dev->rfkill); |
428 | d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev); | 390 | d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev); |
429 | } | 391 | } |
430 | 392 | ||
431 | 393 | ||
432 | #else /* #ifdef CONFIG_RFKILL */ | ||
433 | |||
434 | void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, | ||
435 | enum wimax_rf_state state) | ||
436 | { | ||
437 | } | ||
438 | EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw); | ||
439 | |||
440 | void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, | ||
441 | enum wimax_rf_state state) | ||
442 | { | ||
443 | } | ||
444 | EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw); | ||
445 | |||
446 | int wimax_rfkill(struct wimax_dev *wimax_dev, | ||
447 | enum wimax_rf_state state) | ||
448 | { | ||
449 | return WIMAX_RF_ON << 1 | WIMAX_RF_ON; | ||
450 | } | ||
451 | EXPORT_SYMBOL_GPL(wimax_rfkill); | ||
452 | |||
453 | int wimax_rfkill_add(struct wimax_dev *wimax_dev) | ||
454 | { | ||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | void wimax_rfkill_rm(struct wimax_dev *wimax_dev) | ||
459 | { | ||
460 | } | ||
461 | |||
462 | #endif /* #ifdef CONFIG_RFKILL */ | ||
463 | |||
464 | |||
465 | /* | 394 | /* |
466 | * Exporting to user space over generic netlink | 395 | * Exporting to user space over generic netlink |
467 | * | 396 | * |