aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorentin Chary <corentincj@iksaif.net>2010-11-29 02:14:07 -0500
committerMatthew Garrett <mjg@redhat.com>2011-01-07 17:03:42 -0500
commitba48fdb969d0404d54f6fa0266373afecbbd19d7 (patch)
tree8927f0c44c0619240e421b7d9f1a0971d5005517
parent084fca63128849c0961b3cfdb0cd0345e8f51ad8 (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/Kconfig1
-rw-r--r--drivers/platform/x86/eeepc-wmi.c138
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
66static const struct key_entry eeepc_wmi_keymap[] = { 70static 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 */
293static 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
301static 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
315static const struct rfkill_ops eeepc_rfkill_ops = {
316 .set_block = eeepc_rfkill_set,
317 .query = eeepc_rfkill_query,
318};
319
320static 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
359static 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
378static 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
403exit:
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 */
285static int read_brightness(struct backlight_device *bd) 416static 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)
533fail_wmi_handler: 668fail_wmi_handler:
534 eeepc_wmi_backlight_exit(eeepc); 669 eeepc_wmi_backlight_exit(eeepc);
535fail_backlight: 670fail_backlight:
671 eeepc_wmi_rfkill_exit(eeepc);
672fail_rfkill:
536 eeepc_wmi_led_exit(eeepc); 673 eeepc_wmi_led_exit(eeepc);
537fail_leds: 674fail_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);