aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/acer-wmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/acer-wmi.c')
-rw-r--r--drivers/misc/acer-wmi.c215
1 files changed, 135 insertions, 80 deletions
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index a67aef5e284c..0532a2de2ce4 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>
@@ -123,21 +125,15 @@ enum interface_flags {
123 125
124static int max_brightness = 0xF; 126static int max_brightness = 0xF;
125 127
126static int wireless = -1;
127static int bluetooth = -1;
128static int mailled = -1; 128static int mailled = -1;
129static int brightness = -1; 129static int brightness = -1;
130static int threeg = -1; 130static int threeg = -1;
131static int force_series; 131static int force_series;
132 132
133module_param(mailled, int, 0444); 133module_param(mailled, int, 0444);
134module_param(wireless, int, 0444);
135module_param(bluetooth, int, 0444);
136module_param(brightness, int, 0444); 134module_param(brightness, int, 0444);
137module_param(threeg, int, 0444); 135module_param(threeg, int, 0444);
138module_param(force_series, int, 0444); 136module_param(force_series, int, 0444);
139MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
140MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
141MODULE_PARM_DESC(mailled, "Set initial state of Mail LED"); 137MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
142MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); 138MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
143MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); 139MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
@@ -145,8 +141,6 @@ MODULE_PARM_DESC(force_series, "Force a different laptop series");
145 141
146struct acer_data { 142struct acer_data {
147 int mailled; 143 int mailled;
148 int wireless;
149 int bluetooth;
150 int threeg; 144 int threeg;
151 int brightness; 145 int brightness;
152}; 146};
@@ -157,6 +151,9 @@ struct acer_debug {
157 u32 wmid_devices; 151 u32 wmid_devices;
158}; 152};
159 153
154static struct rfkill *wireless_rfkill;
155static struct rfkill *bluetooth_rfkill;
156
160/* Each low-level interface must define at least some of the following */ 157/* Each low-level interface must define at least some of the following */
161struct wmi_interface { 158struct wmi_interface {
162 /* The WMI device type */ 159 /* The WMI device type */
@@ -846,8 +843,6 @@ static void __init acer_commandline_init(void)
846 * capability isn't available on the given interface 843 * capability isn't available on the given interface
847 */ 844 */
848 set_u32(mailled, ACER_CAP_MAILLED); 845 set_u32(mailled, ACER_CAP_MAILLED);
849 set_u32(wireless, ACER_CAP_WIRELESS);
850 set_u32(bluetooth, ACER_CAP_BLUETOOTH);
851 set_u32(threeg, ACER_CAP_THREEG); 846 set_u32(threeg, ACER_CAP_THREEG);
852 set_u32(brightness, ACER_CAP_BRIGHTNESS); 847 set_u32(brightness, ACER_CAP_BRIGHTNESS);
853} 848}
@@ -933,40 +928,135 @@ static void acer_backlight_exit(void)
933} 928}
934 929
935/* 930/*
936 * Read/ write bool sysfs macro 931 * Rfkill devices
937 */ 932 */
938#define show_set_bool(value, cap) \ 933static void acer_rfkill_update(struct work_struct *ignored);
939static ssize_t \ 934static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
940show_bool_##value(struct device *dev, struct device_attribute *attr, \ 935static void acer_rfkill_update(struct work_struct *ignored)
941 char *buf) \ 936{
942{ \ 937 u32 state;
943 u32 result; \ 938 acpi_status status;
944 acpi_status status = get_u32(&result, cap); \ 939
945 if (ACPI_SUCCESS(status)) \ 940 status = get_u32(&state, ACER_CAP_WIRELESS);
946 return sprintf(buf, "%u\n", result); \ 941 if (ACPI_SUCCESS(status))
947 return sprintf(buf, "Read error\n"); \ 942 rfkill_force_state(wireless_rfkill, state ?
948} \ 943 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
949\ 944
950static ssize_t \ 945 if (has_cap(ACER_CAP_BLUETOOTH)) {
951set_bool_##value(struct device *dev, struct device_attribute *attr, \ 946 status = get_u32(&state, ACER_CAP_BLUETOOTH);
952 const char *buf, size_t count) \ 947 if (ACPI_SUCCESS(status))
953{ \ 948 rfkill_force_state(bluetooth_rfkill, state ?
954 u32 tmp = simple_strtoul(buf, NULL, 10); \ 949 RFKILL_STATE_UNBLOCKED :
955 acpi_status status = set_u32(tmp, cap); \ 950 RFKILL_STATE_SOFT_BLOCKED);
956 if (ACPI_FAILURE(status)) \ 951 }
957 return -EINVAL; \ 952
958 return count; \ 953 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
959} \ 954}
960static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \ 955
961 show_bool_##value, set_bool_##value); 956static int acer_rfkill_set(void *data, enum rfkill_state state)
962 957{
963show_set_bool(wireless, ACER_CAP_WIRELESS); 958 acpi_status status;
964show_set_bool(bluetooth, ACER_CAP_BLUETOOTH); 959 u32 *cap = data;
965show_set_bool(threeg, ACER_CAP_THREEG); 960 status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
961 if (ACPI_FAILURE(status))
962 return -ENODEV;
963 return 0;
964}
965
966static struct rfkill * acer_rfkill_register(struct device *dev,
967enum rfkill_type type, char *name, u32 cap)
968{
969 int err;
970 u32 state;
971 u32 *data;
972 struct rfkill *rfkill_dev;
973
974 rfkill_dev = rfkill_allocate(dev, type);
975 if (!rfkill_dev)
976 return ERR_PTR(-ENOMEM);
977 rfkill_dev->name = name;
978 get_u32(&state, cap);
979 rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
980 RFKILL_STATE_SOFT_BLOCKED;
981 data = kzalloc(sizeof(u32), GFP_KERNEL);
982 if (!data) {
983 rfkill_free(rfkill_dev);
984 return ERR_PTR(-ENOMEM);
985 }
986 *data = cap;
987 rfkill_dev->data = data;
988 rfkill_dev->toggle_radio = acer_rfkill_set;
989 rfkill_dev->user_claim_unsupported = 1;
990
991 err = rfkill_register(rfkill_dev);
992 if (err) {
993 kfree(rfkill_dev->data);
994 rfkill_free(rfkill_dev);
995 return ERR_PTR(err);
996 }
997 return rfkill_dev;
998}
999
1000static int acer_rfkill_init(struct device *dev)
1001{
1002 wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
1003 "acer-wireless", ACER_CAP_WIRELESS);
1004 if (IS_ERR(wireless_rfkill))
1005 return PTR_ERR(wireless_rfkill);
1006
1007 if (has_cap(ACER_CAP_BLUETOOTH)) {
1008 bluetooth_rfkill = acer_rfkill_register(dev,
1009 RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
1010 ACER_CAP_BLUETOOTH);
1011 if (IS_ERR(bluetooth_rfkill)) {
1012 kfree(wireless_rfkill->data);
1013 rfkill_unregister(wireless_rfkill);
1014 return PTR_ERR(bluetooth_rfkill);
1015 }
1016 }
1017
1018 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
1019
1020 return 0;
1021}
1022
1023static void acer_rfkill_exit(void)
1024{
1025 cancel_delayed_work_sync(&acer_rfkill_work);
1026 kfree(wireless_rfkill->data);
1027 rfkill_unregister(wireless_rfkill);
1028 if (has_cap(ACER_CAP_BLUETOOTH)) {
1029 kfree(wireless_rfkill->data);
1030 rfkill_unregister(bluetooth_rfkill);
1031 }
1032 return;
1033}
966 1034
967/* 1035/*
968 * Read interface sysfs macro 1036 * sysfs interface
969 */ 1037 */
1038static ssize_t show_bool_threeg(struct device *dev,
1039 struct device_attribute *attr, char *buf)
1040{
1041 u32 result; \
1042 acpi_status status = get_u32(&result, ACER_CAP_THREEG);
1043 if (ACPI_SUCCESS(status))
1044 return sprintf(buf, "%u\n", result);
1045 return sprintf(buf, "Read error\n");
1046}
1047
1048static ssize_t set_bool_threeg(struct device *dev,
1049 struct device_attribute *attr, const char *buf, size_t count)
1050{
1051 u32 tmp = simple_strtoul(buf, NULL, 10);
1052 acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
1053 if (ACPI_FAILURE(status))
1054 return -EINVAL;
1055 return count;
1056}
1057static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg,
1058 set_bool_threeg);
1059
970static ssize_t show_interface(struct device *dev, struct device_attribute *attr, 1060static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
971 char *buf) 1061 char *buf)
972{ 1062{
@@ -1026,7 +1116,9 @@ static int __devinit acer_platform_probe(struct platform_device *device)
1026 goto error_brightness; 1116 goto error_brightness;
1027 } 1117 }
1028 1118
1029 return 0; 1119 err = acer_rfkill_init(&device->dev);
1120
1121 return err;
1030 1122
1031error_brightness: 1123error_brightness:
1032 acer_led_exit(); 1124 acer_led_exit();
@@ -1040,6 +1132,8 @@ static int acer_platform_remove(struct platform_device *device)
1040 acer_led_exit(); 1132 acer_led_exit();
1041 if (has_cap(ACER_CAP_BRIGHTNESS)) 1133 if (has_cap(ACER_CAP_BRIGHTNESS))
1042 acer_backlight_exit(); 1134 acer_backlight_exit();
1135
1136 acer_rfkill_exit();
1043 return 0; 1137 return 0;
1044} 1138}
1045 1139
@@ -1052,16 +1146,6 @@ pm_message_t state)
1052 if (!data) 1146 if (!data)
1053 return -ENOMEM; 1147 return -ENOMEM;
1054 1148
1055 if (has_cap(ACER_CAP_WIRELESS)) {
1056 get_u32(&value, ACER_CAP_WIRELESS);
1057 data->wireless = value;
1058 }
1059
1060 if (has_cap(ACER_CAP_BLUETOOTH)) {
1061 get_u32(&value, ACER_CAP_BLUETOOTH);
1062 data->bluetooth = value;
1063 }
1064
1065 if (has_cap(ACER_CAP_MAILLED)) { 1149 if (has_cap(ACER_CAP_MAILLED)) {
1066 get_u32(&value, ACER_CAP_MAILLED); 1150 get_u32(&value, ACER_CAP_MAILLED);
1067 data->mailled = value; 1151 data->mailled = value;
@@ -1082,15 +1166,6 @@ static int acer_platform_resume(struct platform_device *device)
1082 if (!data) 1166 if (!data)
1083 return -ENOMEM; 1167 return -ENOMEM;
1084 1168
1085 if (has_cap(ACER_CAP_WIRELESS))
1086 set_u32(data->wireless, ACER_CAP_WIRELESS);
1087
1088 if (has_cap(ACER_CAP_BLUETOOTH))
1089 set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
1090
1091 if (has_cap(ACER_CAP_THREEG))
1092 set_u32(data->threeg, ACER_CAP_THREEG);
1093
1094 if (has_cap(ACER_CAP_MAILLED)) 1169 if (has_cap(ACER_CAP_MAILLED))
1095 set_u32(data->mailled, ACER_CAP_MAILLED); 1170 set_u32(data->mailled, ACER_CAP_MAILLED);
1096 1171
@@ -1115,12 +1190,6 @@ static struct platform_device *acer_platform_device;
1115 1190
1116static int remove_sysfs(struct platform_device *device) 1191static int remove_sysfs(struct platform_device *device)
1117{ 1192{
1118 if (has_cap(ACER_CAP_WIRELESS))
1119 device_remove_file(&device->dev, &dev_attr_wireless);
1120
1121 if (has_cap(ACER_CAP_BLUETOOTH))
1122 device_remove_file(&device->dev, &dev_attr_bluetooth);
1123
1124 if (has_cap(ACER_CAP_THREEG)) 1193 if (has_cap(ACER_CAP_THREEG))
1125 device_remove_file(&device->dev, &dev_attr_threeg); 1194 device_remove_file(&device->dev, &dev_attr_threeg);
1126 1195
@@ -1133,20 +1202,6 @@ static int create_sysfs(void)
1133{ 1202{
1134 int retval = -ENOMEM; 1203 int retval = -ENOMEM;
1135 1204
1136 if (has_cap(ACER_CAP_WIRELESS)) {
1137 retval = device_create_file(&acer_platform_device->dev,
1138 &dev_attr_wireless);
1139 if (retval)
1140 goto error_sysfs;
1141 }
1142
1143 if (has_cap(ACER_CAP_BLUETOOTH)) {
1144 retval = device_create_file(&acer_platform_device->dev,
1145 &dev_attr_bluetooth);
1146 if (retval)
1147 goto error_sysfs;
1148 }
1149
1150 if (has_cap(ACER_CAP_THREEG)) { 1205 if (has_cap(ACER_CAP_THREEG)) {
1151 retval = device_create_file(&acer_platform_device->dev, 1206 retval = device_create_file(&acer_platform_device->dev,
1152 &dev_attr_threeg); 1207 &dev_attr_threeg);