]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'acer-wmi' into test
authorLen Brown <len.brown@intel.com>
Thu, 23 Oct 2008 03:19:47 +0000 (23:19 -0400)
committerLen Brown <len.brown@intel.com>
Thu, 23 Oct 2008 03:19:47 +0000 (23:19 -0400)
Documentation/laptops/acer-wmi.txt
drivers/acpi/wmi.c
drivers/misc/Kconfig
drivers/misc/acer-wmi.c

index 69b5dd4e5a59bd74550397266122c465a8a12b5f..2b3a6b5260bfd64d37a86ca957cf69a6f25dda08 100644 (file)
@@ -1,7 +1,7 @@
 Acer Laptop WMI Extras Driver
 http://code.google.com/p/aceracpi
-Version 0.1
-9th February 2008
+Version 0.2
+18th August 2008
 
 Copyright 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
 
@@ -87,17 +87,7 @@ acer-wmi come with built-in wireless. However, should you feel so inclined to
 ever wish to remove the card, or swap it out at some point, please get in touch
 with me, as we may well be able to gain some data on wireless card detection.
 
-To read the status of the wireless radio (0=off, 1=on):
-cat /sys/devices/platform/acer-wmi/wireless
-
-To enable the wireless radio:
-echo 1 > /sys/devices/platform/acer-wmi/wireless
-
-To disable the wireless radio:
-echo 0 > /sys/devices/platform/acer-wmi/wireless
-
-To set the state of the wireless radio when loading acer-wmi, pass:
-wireless=X (where X is 0 or 1)
+The wireless radio is exposed through rfkill.
 
 Bluetooth
 *********
@@ -117,17 +107,7 @@ For the adventurously minded - if you want to buy an internal bluetooth
 module off the internet that is compatible with your laptop and fit it, then
 it will work just fine with acer-wmi.
 
-To read the status of the bluetooth module (0=off, 1=on):
-cat /sys/devices/platform/acer-wmi/wireless
-
-To enable the bluetooth module:
-echo 1 > /sys/devices/platform/acer-wmi/bluetooth
-
-To disable the bluetooth module:
-echo 0 > /sys/devices/platform/acer-wmi/bluetooth
-
-To set the state of the bluetooth module when loading acer-wmi, pass:
-bluetooth=X (where X is 0 or 1)
+Bluetooth is exposed through rfkill.
 
 3G
 **
index cfe2c833474d07e0a7dc6ddc35b6656c9bc4523a..5464cfcf82973bc72ee9b6d05604a292623fd9af 100644 (file)
@@ -217,6 +217,35 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
        return 0;
 }
 
+static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
+{
+       struct guid_block *block = NULL;
+       char method[5];
+       struct acpi_object_list input;
+       union acpi_object params[1];
+       acpi_status status;
+       acpi_handle handle;
+
+       block = &wblock->gblock;
+       handle = wblock->handle;
+
+       if (!block)
+               return AE_NOT_EXIST;
+
+       input.count = 1;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_INTEGER;
+       params[0].integer.value = enable;
+
+       snprintf(method, 5, "WE%02X", block->notify_id);
+       status = acpi_evaluate_object(handle, method, &input, NULL);
+
+       if (status != AE_OK && status != AE_NOT_FOUND)
+               return status;
+       else
+               return AE_OK;
+}
+
 /*
  * Exported WMI functions
  */
@@ -427,6 +456,7 @@ acpi_status wmi_install_notify_handler(const char *guid,
 wmi_notify_handler handler, void *data)
 {
        struct wmi_block *block;
+       acpi_status status;
 
        if (!guid || !handler)
                return AE_BAD_PARAMETER;
@@ -441,7 +471,9 @@ wmi_notify_handler handler, void *data)
        block->handler = handler;
        block->handler_data = data;
 
-       return AE_OK;
+       status = wmi_method_enable(block, 1);
+
+       return status;
 }
 EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
 
@@ -453,6 +485,7 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
 acpi_status wmi_remove_notify_handler(const char *guid)
 {
        struct wmi_block *block;
+       acpi_status status;
 
        if (!guid)
                return AE_BAD_PARAMETER;
@@ -464,10 +497,12 @@ acpi_status wmi_remove_notify_handler(const char *guid)
        if (!block->handler)
                return AE_NULL_ENTRY;
 
+       status = wmi_method_enable(block, 0);
+
        block->handler = NULL;
        block->handler_data = NULL;
 
-       return AE_OK;
+       return status;
 }
 EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
 
index a726f3b01a6b36debf060b647c4384a4aab8f1b3..6abb95919c3898a00c684a48739a83f6ab51de73 100644 (file)
@@ -145,6 +145,7 @@ config ACER_WMI
        depends on NEW_LEDS
        depends on BACKLIGHT_CLASS_DEVICE
        depends on SERIO_I8042
+       depends on RFKILL
        select ACPI_WMI
        ---help---
          This is a driver for newer Acer (and Wistron) laptops. It adds
index d8b0d326e4522232fbcc1455dce67fb3e207c059..cf4c39fbc66fd4faf91a7be1a88d8d0d4581eecb 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/i8042.h>
+#include <linux/rfkill.h>
+#include <linux/workqueue.h>
 #include <linux/debugfs.h>
 
 #include <acpi/acpi_drivers.h>
@@ -123,21 +125,15 @@ enum interface_flags {
 
 static int max_brightness = 0xF;
 
-static int wireless = -1;
-static int bluetooth = -1;
 static int mailled = -1;
 static int brightness = -1;
 static int threeg = -1;
 static int force_series;
 
 module_param(mailled, int, 0444);
-module_param(wireless, int, 0444);
-module_param(bluetooth, int, 0444);
 module_param(brightness, int, 0444);
 module_param(threeg, int, 0444);
 module_param(force_series, int, 0444);
-MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
-MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
@@ -145,8 +141,6 @@ MODULE_PARM_DESC(force_series, "Force a different laptop series");
 
 struct acer_data {
        int mailled;
-       int wireless;
-       int bluetooth;
        int threeg;
        int brightness;
 };
@@ -157,6 +151,9 @@ struct acer_debug {
        u32 wmid_devices;
 };
 
+static struct rfkill *wireless_rfkill;
+static struct rfkill *bluetooth_rfkill;
+
 /* Each low-level interface must define at least some of the following */
 struct wmi_interface {
        /* The WMI device type */
@@ -846,8 +843,6 @@ static void __init acer_commandline_init(void)
         * capability isn't available on the given interface
         */
        set_u32(mailled, ACER_CAP_MAILLED);
-       set_u32(wireless, ACER_CAP_WIRELESS);
-       set_u32(bluetooth, ACER_CAP_BLUETOOTH);
        set_u32(threeg, ACER_CAP_THREEG);
        set_u32(brightness, ACER_CAP_BRIGHTNESS);
 }
@@ -933,40 +928,135 @@ static void acer_backlight_exit(void)
 }
 
 /*
- * Read/ write bool sysfs macro
+ * Rfkill devices
  */
-#define show_set_bool(value, cap) \
-static ssize_t \
-show_bool_##value(struct device *dev, struct device_attribute *attr, \
-       char *buf) \
-{ \
-       u32 result; \
-       acpi_status status = get_u32(&result, cap); \
-       if (ACPI_SUCCESS(status)) \
-               return sprintf(buf, "%u\n", result); \
-       return sprintf(buf, "Read error\n"); \
-} \
-\
-static ssize_t \
-set_bool_##value(struct device *dev, struct device_attribute *attr, \
-       const char *buf, size_t count) \
-{ \
-       u32 tmp = simple_strtoul(buf, NULL, 10); \
-       acpi_status status = set_u32(tmp, cap); \
-               if (ACPI_FAILURE(status)) \
-                       return -EINVAL; \
-       return count; \
-} \
-static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
-       show_bool_##value, set_bool_##value);
-
-show_set_bool(wireless, ACER_CAP_WIRELESS);
-show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
-show_set_bool(threeg, ACER_CAP_THREEG);
+static void acer_rfkill_update(struct work_struct *ignored);
+static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
+static void acer_rfkill_update(struct work_struct *ignored)
+{
+       u32 state;
+       acpi_status status;
+
+       status = get_u32(&state, ACER_CAP_WIRELESS);
+       if (ACPI_SUCCESS(status))
+               rfkill_force_state(wireless_rfkill, state ?
+                       RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
+
+       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);
+       }
+
+       schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
+}
+
+static int acer_rfkill_set(void *data, enum rfkill_state state)
+{
+       acpi_status status;
+       u32 *cap = data;
+       status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *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)
+{
+       int err;
+       u32 state;
+       u32 *data;
+       struct rfkill *rfkill_dev;
+
+       rfkill_dev = rfkill_allocate(dev, type);
+       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_dev->user_claim_unsupported = 1;
+
+       err = rfkill_register(rfkill_dev);
+       if (err) {
+               kfree(rfkill_dev->data);
+               rfkill_free(rfkill_dev);
+               return ERR_PTR(err);
+       }
+       return rfkill_dev;
+}
+
+static int acer_rfkill_init(struct device *dev)
+{
+       wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
+               "acer-wireless", ACER_CAP_WIRELESS);
+       if (IS_ERR(wireless_rfkill))
+               return PTR_ERR(wireless_rfkill);
+
+       if (has_cap(ACER_CAP_BLUETOOTH)) {
+               bluetooth_rfkill = acer_rfkill_register(dev,
+                       RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
+                       ACER_CAP_BLUETOOTH);
+               if (IS_ERR(bluetooth_rfkill)) {
+                       kfree(wireless_rfkill->data);
+                       rfkill_unregister(wireless_rfkill);
+                       return PTR_ERR(bluetooth_rfkill);
+               }
+       }
+
+       schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
+
+       return 0;
+}
+
+static void acer_rfkill_exit(void)
+{
+       cancel_delayed_work_sync(&acer_rfkill_work);
+       kfree(wireless_rfkill->data);
+       rfkill_unregister(wireless_rfkill);
+       if (has_cap(ACER_CAP_BLUETOOTH)) {
+               kfree(wireless_rfkill->data);
+               rfkill_unregister(bluetooth_rfkill);
+       }
+       return;
+}
 
 /*
- * Read interface sysfs macro
+ * sysfs interface
  */
+static ssize_t show_bool_threeg(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       u32 result; \
+       acpi_status status = get_u32(&result, ACER_CAP_THREEG);
+       if (ACPI_SUCCESS(status))
+               return sprintf(buf, "%u\n", result);
+       return sprintf(buf, "Read error\n");
+}
+
+static ssize_t set_bool_threeg(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       u32 tmp = simple_strtoul(buf, NULL, 10);
+       acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
+               if (ACPI_FAILURE(status))
+                       return -EINVAL;
+       return count;
+}
+static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg,
+       set_bool_threeg);
+
 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
        char *buf)
 {
@@ -1026,7 +1116,9 @@ static int __devinit acer_platform_probe(struct platform_device *device)
                        goto error_brightness;
        }
 
-       return 0;
+       err = acer_rfkill_init(&device->dev);
+
+       return err;
 
 error_brightness:
        acer_led_exit();
@@ -1040,6 +1132,8 @@ static int acer_platform_remove(struct platform_device *device)
                acer_led_exit();
        if (has_cap(ACER_CAP_BRIGHTNESS))
                acer_backlight_exit();
+
+       acer_rfkill_exit();
        return 0;
 }
 
@@ -1052,16 +1146,6 @@ pm_message_t state)
        if (!data)
                return -ENOMEM;
 
-       if (has_cap(ACER_CAP_WIRELESS)) {
-               get_u32(&value, ACER_CAP_WIRELESS);
-               data->wireless = value;
-       }
-
-       if (has_cap(ACER_CAP_BLUETOOTH)) {
-               get_u32(&value, ACER_CAP_BLUETOOTH);
-               data->bluetooth = value;
-       }
-
        if (has_cap(ACER_CAP_MAILLED)) {
                get_u32(&value, ACER_CAP_MAILLED);
                data->mailled = value;
@@ -1082,15 +1166,6 @@ static int acer_platform_resume(struct platform_device *device)
        if (!data)
                return -ENOMEM;
 
-       if (has_cap(ACER_CAP_WIRELESS))
-               set_u32(data->wireless, ACER_CAP_WIRELESS);
-
-       if (has_cap(ACER_CAP_BLUETOOTH))
-               set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
-
-       if (has_cap(ACER_CAP_THREEG))
-               set_u32(data->threeg, ACER_CAP_THREEG);
-
        if (has_cap(ACER_CAP_MAILLED))
                set_u32(data->mailled, ACER_CAP_MAILLED);
 
@@ -1115,12 +1190,6 @@ static struct platform_device *acer_platform_device;
 
 static int remove_sysfs(struct platform_device *device)
 {
-       if (has_cap(ACER_CAP_WIRELESS))
-               device_remove_file(&device->dev, &dev_attr_wireless);
-
-       if (has_cap(ACER_CAP_BLUETOOTH))
-               device_remove_file(&device->dev, &dev_attr_bluetooth);
-
        if (has_cap(ACER_CAP_THREEG))
                device_remove_file(&device->dev, &dev_attr_threeg);
 
@@ -1133,20 +1202,6 @@ static int create_sysfs(void)
 {
        int retval = -ENOMEM;
 
-       if (has_cap(ACER_CAP_WIRELESS)) {
-               retval = device_create_file(&acer_platform_device->dev,
-                       &dev_attr_wireless);
-               if (retval)
-                       goto error_sysfs;
-       }
-
-       if (has_cap(ACER_CAP_BLUETOOTH)) {
-               retval = device_create_file(&acer_platform_device->dev,
-                       &dev_attr_bluetooth);
-               if (retval)
-                       goto error_sysfs;
-       }
-
        if (has_cap(ACER_CAP_THREEG)) {
                retval = device_create_file(&acer_platform_device->dev,
                        &dev_attr_threeg);