diff options
author | Corentin Chary <corentincj@iksaif.net> | 2010-11-29 02:14:07 -0500 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2011-01-07 17:03:42 -0500 |
commit | ba48fdb969d0404d54f6fa0266373afecbbd19d7 (patch) | |
tree | 8927f0c44c0619240e421b7d9f1a0971d5005517 | |
parent | 084fca63128849c0961b3cfdb0cd0345e8f51ad8 (diff) |
eeepc-wmi: add rfkill support for wlan, bluetooth and 3g
wimax support is missing because I don't have any DSDT
with WMI and wimax support.
Most of the code comes from eeepc-laptop.
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
-rw-r--r-- | drivers/platform/x86/Kconfig | 1 | ||||
-rw-r--r-- | drivers/platform/x86/eeepc-wmi.c | 138 |
2 files changed, 139 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index adcdbbd7d3fd..4c7f8b926103 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -425,6 +425,7 @@ config EEEPC_WMI | |||
425 | depends on INPUT | 425 | depends on INPUT |
426 | depends on EXPERIMENTAL | 426 | depends on EXPERIMENTAL |
427 | depends on BACKLIGHT_CLASS_DEVICE | 427 | depends on BACKLIGHT_CLASS_DEVICE |
428 | depends on RFKILL || RFKILL = n | ||
428 | select INPUT_SPARSEKMAP | 429 | select INPUT_SPARSEKMAP |
429 | select LEDS_CLASS | 430 | select LEDS_CLASS |
430 | select NEW_LEDS | 431 | select NEW_LEDS |
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index f12a25da4055..fb548f4b03e0 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/fb.h> | 35 | #include <linux/fb.h> |
36 | #include <linux/backlight.h> | 36 | #include <linux/backlight.h> |
37 | #include <linux/leds.h> | 37 | #include <linux/leds.h> |
38 | #include <linux/rfkill.h> | ||
38 | #include <linux/platform_device.h> | 39 | #include <linux/platform_device.h> |
39 | #include <acpi/acpi_bus.h> | 40 | #include <acpi/acpi_bus.h> |
40 | #include <acpi/acpi_drivers.h> | 41 | #include <acpi/acpi_drivers.h> |
@@ -62,6 +63,9 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); | |||
62 | 63 | ||
63 | #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 | 64 | #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 |
64 | #define EEEPC_WMI_DEVID_TPDLED 0x00100011 | 65 | #define EEEPC_WMI_DEVID_TPDLED 0x00100011 |
66 | #define EEEPC_WMI_DEVID_WLAN 0x00010011 | ||
67 | #define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 | ||
68 | #define EEEPC_WMI_DEVID_WWAN3G 0x00010019 | ||
65 | 69 | ||
66 | static const struct key_entry eeepc_wmi_keymap[] = { | 70 | static const struct key_entry eeepc_wmi_keymap[] = { |
67 | /* Sleep already handled via generic ACPI code */ | 71 | /* Sleep already handled via generic ACPI code */ |
@@ -94,6 +98,10 @@ struct eeepc_wmi { | |||
94 | int tpd_led_wk; | 98 | int tpd_led_wk; |
95 | struct workqueue_struct *led_workqueue; | 99 | struct workqueue_struct *led_workqueue; |
96 | struct work_struct tpd_led_work; | 100 | struct work_struct tpd_led_work; |
101 | |||
102 | struct rfkill *wlan_rfkill; | ||
103 | struct rfkill *bluetooth_rfkill; | ||
104 | struct rfkill *wwan3g_rfkill; | ||
97 | }; | 105 | }; |
98 | 106 | ||
99 | /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ | 107 | /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ |
@@ -280,6 +288,129 @@ static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) | |||
280 | } | 288 | } |
281 | 289 | ||
282 | /* | 290 | /* |
291 | * Rfkill devices | ||
292 | */ | ||
293 | static int eeepc_rfkill_set(void *data, bool blocked) | ||
294 | { | ||
295 | int dev_id = (unsigned long)data; | ||
296 | u32 ctrl_param = !blocked; | ||
297 | |||
298 | return eeepc_wmi_set_devstate(dev_id, ctrl_param); | ||
299 | } | ||
300 | |||
301 | static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) | ||
302 | { | ||
303 | int dev_id = (unsigned long)data; | ||
304 | u32 ctrl_param; | ||
305 | acpi_status status; | ||
306 | |||
307 | status = eeepc_wmi_get_devstate(dev_id, &ctrl_param); | ||
308 | |||
309 | if (ACPI_FAILURE(status)) | ||
310 | return ; | ||
311 | |||
312 | rfkill_set_sw_state(rfkill, !(ctrl_param & 0x1)); | ||
313 | } | ||
314 | |||
315 | static const struct rfkill_ops eeepc_rfkill_ops = { | ||
316 | .set_block = eeepc_rfkill_set, | ||
317 | .query = eeepc_rfkill_query, | ||
318 | }; | ||
319 | |||
320 | static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, | ||
321 | struct rfkill **rfkill, | ||
322 | const char *name, | ||
323 | enum rfkill_type type, int dev_id) | ||
324 | { | ||
325 | int result; | ||
326 | u32 ctrl_param; | ||
327 | acpi_status status; | ||
328 | |||
329 | status = eeepc_wmi_get_devstate(dev_id, &ctrl_param); | ||
330 | |||
331 | if (ACPI_FAILURE(status)) | ||
332 | return -1; | ||
333 | |||
334 | /* If the device is present, DSTS will always set some bits | ||
335 | * 0x00070000 - 1110000000000000000 - device supported | ||
336 | * 0x00060000 - 1100000000000000000 - not supported | ||
337 | * 0x00020000 - 0100000000000000000 - device supported | ||
338 | * 0x00010000 - 0010000000000000000 - not supported / special mode ? | ||
339 | */ | ||
340 | if (!ctrl_param || ctrl_param == 0x00060000) | ||
341 | return -ENODEV; | ||
342 | |||
343 | *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, | ||
344 | &eeepc_rfkill_ops, (void *)(long)dev_id); | ||
345 | |||
346 | if (!*rfkill) | ||
347 | return -EINVAL; | ||
348 | |||
349 | rfkill_init_sw_state(*rfkill, !(ctrl_param & 0x1)); | ||
350 | result = rfkill_register(*rfkill); | ||
351 | if (result) { | ||
352 | rfkill_destroy(*rfkill); | ||
353 | *rfkill = NULL; | ||
354 | return result; | ||
355 | } | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) | ||
360 | { | ||
361 | if (eeepc->wlan_rfkill) { | ||
362 | rfkill_unregister(eeepc->wlan_rfkill); | ||
363 | rfkill_destroy(eeepc->wlan_rfkill); | ||
364 | eeepc->wlan_rfkill = NULL; | ||
365 | } | ||
366 | if (eeepc->bluetooth_rfkill) { | ||
367 | rfkill_unregister(eeepc->bluetooth_rfkill); | ||
368 | rfkill_destroy(eeepc->bluetooth_rfkill); | ||
369 | eeepc->bluetooth_rfkill = NULL; | ||
370 | } | ||
371 | if (eeepc->wwan3g_rfkill) { | ||
372 | rfkill_unregister(eeepc->wwan3g_rfkill); | ||
373 | rfkill_destroy(eeepc->wwan3g_rfkill); | ||
374 | eeepc->wwan3g_rfkill = NULL; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) | ||
379 | { | ||
380 | int result = 0; | ||
381 | |||
382 | result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, | ||
383 | "eeepc-wlan", RFKILL_TYPE_WLAN, | ||
384 | EEEPC_WMI_DEVID_WLAN); | ||
385 | |||
386 | if (result && result != -ENODEV) | ||
387 | goto exit; | ||
388 | |||
389 | result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill, | ||
390 | "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH, | ||
391 | EEEPC_WMI_DEVID_BLUETOOTH); | ||
392 | |||
393 | if (result && result != -ENODEV) | ||
394 | goto exit; | ||
395 | |||
396 | result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, | ||
397 | "eeepc-wwan3g", RFKILL_TYPE_WWAN, | ||
398 | EEEPC_WMI_DEVID_WWAN3G); | ||
399 | |||
400 | if (result && result != -ENODEV) | ||
401 | goto exit; | ||
402 | |||
403 | exit: | ||
404 | if (result && result != -ENODEV) | ||
405 | eeepc_wmi_rfkill_exit(eeepc); | ||
406 | |||
407 | if (result == -ENODEV) | ||
408 | result = 0; | ||
409 | |||
410 | return result; | ||
411 | } | ||
412 | |||
413 | /* | ||
283 | * Backlight | 414 | * Backlight |
284 | */ | 415 | */ |
285 | static int read_brightness(struct backlight_device *bd) | 416 | static int read_brightness(struct backlight_device *bd) |
@@ -512,6 +643,10 @@ static struct platform_device * __init eeepc_wmi_add(void) | |||
512 | if (err) | 643 | if (err) |
513 | goto fail_leds; | 644 | goto fail_leds; |
514 | 645 | ||
646 | err = eeepc_wmi_rfkill_init(eeepc); | ||
647 | if (err) | ||
648 | goto fail_rfkill; | ||
649 | |||
515 | if (!acpi_video_backlight_support()) { | 650 | if (!acpi_video_backlight_support()) { |
516 | err = eeepc_wmi_backlight_init(eeepc); | 651 | err = eeepc_wmi_backlight_init(eeepc); |
517 | if (err) | 652 | if (err) |
@@ -533,6 +668,8 @@ static struct platform_device * __init eeepc_wmi_add(void) | |||
533 | fail_wmi_handler: | 668 | fail_wmi_handler: |
534 | eeepc_wmi_backlight_exit(eeepc); | 669 | eeepc_wmi_backlight_exit(eeepc); |
535 | fail_backlight: | 670 | fail_backlight: |
671 | eeepc_wmi_rfkill_exit(eeepc); | ||
672 | fail_rfkill: | ||
536 | eeepc_wmi_led_exit(eeepc); | 673 | eeepc_wmi_led_exit(eeepc); |
537 | fail_leds: | 674 | fail_leds: |
538 | eeepc_wmi_input_exit(eeepc); | 675 | eeepc_wmi_input_exit(eeepc); |
@@ -552,6 +689,7 @@ static int eeepc_wmi_remove(struct platform_device *device) | |||
552 | eeepc_wmi_backlight_exit(eeepc); | 689 | eeepc_wmi_backlight_exit(eeepc); |
553 | eeepc_wmi_input_exit(eeepc); | 690 | eeepc_wmi_input_exit(eeepc); |
554 | eeepc_wmi_led_exit(eeepc); | 691 | eeepc_wmi_led_exit(eeepc); |
692 | eeepc_wmi_rfkill_exit(eeepc); | ||
555 | eeepc_wmi_platform_exit(eeepc); | 693 | eeepc_wmi_platform_exit(eeepc); |
556 | 694 | ||
557 | kfree(eeepc); | 695 | kfree(eeepc); |