Skip to content

Commit

Permalink
eeepc-wmi: add rfkill support for wlan, bluetooth and 3g
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Corentin Chary authored and Matthew Garrett committed Jan 7, 2011
1 parent 084fca6 commit ba48fdb
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/platform/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ config EEEPC_WMI
depends on INPUT
depends on EXPERIMENTAL
depends on BACKLIGHT_CLASS_DEVICE
depends on RFKILL || RFKILL = n
select INPUT_SPARSEKMAP
select LEDS_CLASS
select NEW_LEDS
Expand Down
138 changes: 138 additions & 0 deletions drivers/platform/x86/eeepc-wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/leds.h>
#include <linux/rfkill.h>
#include <linux/platform_device.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
Expand Down Expand Up @@ -62,6 +63,9 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);

#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012
#define EEEPC_WMI_DEVID_TPDLED 0x00100011
#define EEEPC_WMI_DEVID_WLAN 0x00010011
#define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013
#define EEEPC_WMI_DEVID_WWAN3G 0x00010019

static const struct key_entry eeepc_wmi_keymap[] = {
/* Sleep already handled via generic ACPI code */
Expand Down Expand Up @@ -94,6 +98,10 @@ struct eeepc_wmi {
int tpd_led_wk;
struct workqueue_struct *led_workqueue;
struct work_struct tpd_led_work;

struct rfkill *wlan_rfkill;
struct rfkill *bluetooth_rfkill;
struct rfkill *wwan3g_rfkill;
};

/* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */
Expand Down Expand Up @@ -279,6 +287,129 @@ static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc)
destroy_workqueue(eeepc->led_workqueue);
}

/*
* Rfkill devices
*/
static int eeepc_rfkill_set(void *data, bool blocked)
{
int dev_id = (unsigned long)data;
u32 ctrl_param = !blocked;

return eeepc_wmi_set_devstate(dev_id, ctrl_param);
}

static void eeepc_rfkill_query(struct rfkill *rfkill, void *data)
{
int dev_id = (unsigned long)data;
u32 ctrl_param;
acpi_status status;

status = eeepc_wmi_get_devstate(dev_id, &ctrl_param);

if (ACPI_FAILURE(status))
return ;

rfkill_set_sw_state(rfkill, !(ctrl_param & 0x1));
}

static const struct rfkill_ops eeepc_rfkill_ops = {
.set_block = eeepc_rfkill_set,
.query = eeepc_rfkill_query,
};

static int eeepc_new_rfkill(struct eeepc_wmi *eeepc,
struct rfkill **rfkill,
const char *name,
enum rfkill_type type, int dev_id)
{
int result;
u32 ctrl_param;
acpi_status status;

status = eeepc_wmi_get_devstate(dev_id, &ctrl_param);

if (ACPI_FAILURE(status))
return -1;

/* If the device is present, DSTS will always set some bits
* 0x00070000 - 1110000000000000000 - device supported
* 0x00060000 - 1100000000000000000 - not supported
* 0x00020000 - 0100000000000000000 - device supported
* 0x00010000 - 0010000000000000000 - not supported / special mode ?
*/
if (!ctrl_param || ctrl_param == 0x00060000)
return -ENODEV;

*rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
&eeepc_rfkill_ops, (void *)(long)dev_id);

if (!*rfkill)
return -EINVAL;

rfkill_init_sw_state(*rfkill, !(ctrl_param & 0x1));
result = rfkill_register(*rfkill);
if (result) {
rfkill_destroy(*rfkill);
*rfkill = NULL;
return result;
}
return 0;
}

static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc)
{
if (eeepc->wlan_rfkill) {
rfkill_unregister(eeepc->wlan_rfkill);
rfkill_destroy(eeepc->wlan_rfkill);
eeepc->wlan_rfkill = NULL;
}
if (eeepc->bluetooth_rfkill) {
rfkill_unregister(eeepc->bluetooth_rfkill);
rfkill_destroy(eeepc->bluetooth_rfkill);
eeepc->bluetooth_rfkill = NULL;
}
if (eeepc->wwan3g_rfkill) {
rfkill_unregister(eeepc->wwan3g_rfkill);
rfkill_destroy(eeepc->wwan3g_rfkill);
eeepc->wwan3g_rfkill = NULL;
}
}

static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc)
{
int result = 0;

result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
"eeepc-wlan", RFKILL_TYPE_WLAN,
EEEPC_WMI_DEVID_WLAN);

if (result && result != -ENODEV)
goto exit;

result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
"eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
EEEPC_WMI_DEVID_BLUETOOTH);

if (result && result != -ENODEV)
goto exit;

result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
"eeepc-wwan3g", RFKILL_TYPE_WWAN,
EEEPC_WMI_DEVID_WWAN3G);

if (result && result != -ENODEV)
goto exit;

exit:
if (result && result != -ENODEV)
eeepc_wmi_rfkill_exit(eeepc);

if (result == -ENODEV)
result = 0;

return result;
}

/*
* Backlight
*/
Expand Down Expand Up @@ -512,6 +643,10 @@ static struct platform_device * __init eeepc_wmi_add(void)
if (err)
goto fail_leds;

err = eeepc_wmi_rfkill_init(eeepc);
if (err)
goto fail_rfkill;

if (!acpi_video_backlight_support()) {
err = eeepc_wmi_backlight_init(eeepc);
if (err)
Expand All @@ -533,6 +668,8 @@ static struct platform_device * __init eeepc_wmi_add(void)
fail_wmi_handler:
eeepc_wmi_backlight_exit(eeepc);
fail_backlight:
eeepc_wmi_rfkill_exit(eeepc);
fail_rfkill:
eeepc_wmi_led_exit(eeepc);
fail_leds:
eeepc_wmi_input_exit(eeepc);
Expand All @@ -552,6 +689,7 @@ static int eeepc_wmi_remove(struct platform_device *device)
eeepc_wmi_backlight_exit(eeepc);
eeepc_wmi_input_exit(eeepc);
eeepc_wmi_led_exit(eeepc);
eeepc_wmi_rfkill_exit(eeepc);
eeepc_wmi_platform_exit(eeepc);

kfree(eeepc);
Expand Down

0 comments on commit ba48fdb

Please sign in to comment.