aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/acer-wmi.c130
2 files changed, 130 insertions, 1 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a726f3b01a6b..6abb95919c38 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -145,6 +145,7 @@ config ACER_WMI
145 depends on NEW_LEDS 145 depends on NEW_LEDS
146 depends on BACKLIGHT_CLASS_DEVICE 146 depends on BACKLIGHT_CLASS_DEVICE
147 depends on SERIO_I8042 147 depends on SERIO_I8042
148 depends on RFKILL
148 select ACPI_WMI 149 select ACPI_WMI
149 ---help--- 150 ---help---
150 This is a driver for newer Acer (and Wistron) laptops. It adds 151 This is a driver for newer Acer (and Wistron) laptops. It adds
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index d8b0d326e452..e3e11e88747e 100644
--- a/drivers/misc/acer-wmi.c
+++ b/drivers/misc/acer-wmi.c
@@ -33,6 +33,8 @@
33#include <linux/platform_device.h> 33#include <linux/platform_device.h>
34#include <linux/acpi.h> 34#include <linux/acpi.h>
35#include <linux/i8042.h> 35#include <linux/i8042.h>
36#include <linux/rfkill.h>
37#include <linux/workqueue.h>
36#include <linux/debugfs.h> 38#include <linux/debugfs.h>
37 39
38#include <acpi/acpi_drivers.h> 40#include <acpi/acpi_drivers.h>
@@ -157,6 +159,9 @@ struct acer_debug {
157 u32 wmid_devices; 159 u32 wmid_devices;
158}; 160};
159 161
162static struct rfkill *wireless_rfkill;
163static struct rfkill *bluetooth_rfkill;
164
160/* Each low-level interface must define at least some of the following */ 165/* Each low-level interface must define at least some of the following */
161struct wmi_interface { 166struct wmi_interface {
162 /* The WMI device type */ 167 /* The WMI device type */
@@ -933,6 +938,125 @@ static void acer_backlight_exit(void)
933} 938}
934 939
935/* 940/*
941 * Rfkill devices
942 */
943static struct workqueue_struct *rfkill_workqueue;
944
945static void acer_rfkill_update(struct work_struct *ignored);
946static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
947static void acer_rfkill_update(struct work_struct *ignored)
948{
949 u32 state;
950 acpi_status status;
951
952 status = get_u32(&state, ACER_CAP_WIRELESS);
953 if (ACPI_SUCCESS(status))
954 rfkill_force_state(wireless_rfkill, state ?
955 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
956
957 if (has_cap(ACER_CAP_BLUETOOTH)) {
958 status = get_u32(&state, ACER_CAP_BLUETOOTH);
959 if (ACPI_SUCCESS(status))
960 rfkill_force_state(bluetooth_rfkill, state ?
961 RFKILL_STATE_UNBLOCKED :
962 RFKILL_STATE_SOFT_BLOCKED);
963 }
964
965 queue_delayed_work(rfkill_workqueue, &acer_rfkill_work,
966 round_jiffies_relative(HZ));
967}
968
969static int acer_rfkill_set(void *data, enum rfkill_state state)
970{
971 acpi_status status;
972 u32 *cap = data;
973 status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
974 if (ACPI_FAILURE(status))
975 return -ENODEV;
976 return 0;
977}
978
979static struct rfkill * acer_rfkill_register(struct device *dev,
980enum rfkill_type type, char *name, u32 cap)
981{
982 int err;
983 u32 state;
984 u32 *data;
985 struct rfkill *rfkill_dev;
986
987 rfkill_dev = rfkill_allocate(dev, type);
988 if (!rfkill_dev)
989 return ERR_PTR(-ENOMEM);
990 rfkill_dev->name = name;
991 get_u32(&state, cap);
992 rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
993 RFKILL_STATE_SOFT_BLOCKED;
994 data = kzalloc(sizeof(u32), GFP_KERNEL);
995 if (!data) {
996 rfkill_free(rfkill_dev);
997 return ERR_PTR(-ENOMEM);
998 }
999 *data = cap;
1000 rfkill_dev->data = data;
1001 rfkill_dev->toggle_radio = acer_rfkill_set;
1002 rfkill_dev->user_claim_unsupported = 1;
1003
1004 err = rfkill_register(rfkill_dev);
1005 if (err) {
1006 kfree(rfkill_dev->data);
1007 rfkill_free(rfkill_dev);
1008 return ERR_PTR(err);
1009 }
1010 return rfkill_dev;
1011}
1012
1013static int acer_rfkill_init(struct device *dev)
1014{
1015 wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
1016 "acer-wireless", ACER_CAP_WIRELESS);
1017 if (IS_ERR(wireless_rfkill))
1018 return PTR_ERR(wireless_rfkill);
1019
1020 if (has_cap(ACER_CAP_BLUETOOTH)) {
1021 bluetooth_rfkill = acer_rfkill_register(dev,
1022 RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
1023 ACER_CAP_BLUETOOTH);
1024 if (IS_ERR(bluetooth_rfkill)) {
1025 kfree(wireless_rfkill->data);
1026 rfkill_unregister(wireless_rfkill);
1027 return PTR_ERR(bluetooth_rfkill);
1028 }
1029 }
1030
1031 rfkill_workqueue = create_singlethread_workqueue("rfkill_workqueue");
1032 if (!rfkill_workqueue) {
1033 if (has_cap(ACER_CAP_BLUETOOTH)) {
1034 kfree(bluetooth_rfkill->data);
1035 rfkill_unregister(bluetooth_rfkill);
1036 }
1037 kfree(wireless_rfkill->data);
1038 rfkill_unregister(wireless_rfkill);
1039 return -ENOMEM;
1040 }
1041 queue_delayed_work(rfkill_workqueue, &acer_rfkill_work, HZ);
1042
1043 return 0;
1044}
1045
1046static void acer_rfkill_exit(void)
1047{
1048 cancel_delayed_work_sync(&acer_rfkill_work);
1049 destroy_workqueue(rfkill_workqueue);
1050 kfree(wireless_rfkill->data);
1051 rfkill_unregister(wireless_rfkill);
1052 if (has_cap(ACER_CAP_BLUETOOTH)) {
1053 kfree(wireless_rfkill->data);
1054 rfkill_unregister(bluetooth_rfkill);
1055 }
1056 return;
1057}
1058
1059/*
936 * Read/ write bool sysfs macro 1060 * Read/ write bool sysfs macro
937 */ 1061 */
938#define show_set_bool(value, cap) \ 1062#define show_set_bool(value, cap) \
@@ -1026,7 +1150,9 @@ static int __devinit acer_platform_probe(struct platform_device *device)
1026 goto error_brightness; 1150 goto error_brightness;
1027 } 1151 }
1028 1152
1029 return 0; 1153 err = acer_rfkill_init(&device->dev);
1154
1155 return err;
1030 1156
1031error_brightness: 1157error_brightness:
1032 acer_led_exit(); 1158 acer_led_exit();
@@ -1040,6 +1166,8 @@ static int acer_platform_remove(struct platform_device *device)
1040 acer_led_exit(); 1166 acer_led_exit();
1041 if (has_cap(ACER_CAP_BRIGHTNESS)) 1167 if (has_cap(ACER_CAP_BRIGHTNESS))
1042 acer_backlight_exit(); 1168 acer_backlight_exit();
1169
1170 acer_rfkill_exit();
1043 return 0; 1171 return 0;
1044} 1172}
1045 1173