aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/acer-wmi.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-10-28 11:26:12 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-28 11:26:12 -0400
commit7a9787e1eba95a166265e6a260cf30af04ef0a99 (patch)
treee730a4565e0318140d2fbd2f0415d18a339d7336 /drivers/misc/acer-wmi.c
parent41b9eb264c8407655db57b60b4457fe1b2ec9977 (diff)
parent0173a3265b228da319ceb9c1ec6a5682fd1b2d92 (diff)
Merge commit 'v2.6.28-rc2' into x86/pci-ioapic-boot-irq-quirks
Diffstat (limited to 'drivers/misc/acer-wmi.c')
-rw-r--r--drivers/misc/acer-wmi.c252
1 files changed, 166 insertions, 86 deletions
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index e7a3fe508dff..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 */
@@ -192,6 +189,9 @@ static struct quirk_entry *quirks;
192 189
193static void set_quirks(void) 190static void set_quirks(void)
194{ 191{
192 if (!interface)
193 return;
194
195 if (quirks->mailled) 195 if (quirks->mailled)
196 interface->capability |= ACER_CAP_MAILLED; 196 interface->capability |= ACER_CAP_MAILLED;
197 197
@@ -473,7 +473,7 @@ struct wmi_interface *iface)
473 } 473 }
474 break; 474 break;
475 default: 475 default:
476 return AE_BAD_ADDRESS; 476 return AE_ERROR;
477 } 477 }
478 return AE_OK; 478 return AE_OK;
479} 479}
@@ -511,7 +511,7 @@ static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
511 break; 511 break;
512 } 512 }
513 default: 513 default:
514 return AE_BAD_ADDRESS; 514 return AE_ERROR;
515 } 515 }
516 516
517 /* Actually do the set */ 517 /* Actually do the set */
@@ -686,7 +686,7 @@ struct wmi_interface *iface)
686 return 0; 686 return 0;
687 } 687 }
688 default: 688 default:
689 return AE_BAD_ADDRESS; 689 return AE_ERROR;
690 } 690 }
691 status = WMI_execute_u32(method_id, 0, &result); 691 status = WMI_execute_u32(method_id, 0, &result);
692 692
@@ -732,7 +732,7 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
732 } 732 }
733 break; 733 break;
734 default: 734 default:
735 return AE_BAD_ADDRESS; 735 return AE_ERROR;
736 } 736 }
737 return WMI_execute_u32(method_id, (u32)value, NULL); 737 return WMI_execute_u32(method_id, (u32)value, NULL);
738} 738}
@@ -782,7 +782,7 @@ static struct wmi_interface wmid_interface = {
782 782
783static acpi_status get_u32(u32 *value, u32 cap) 783static acpi_status get_u32(u32 *value, u32 cap)
784{ 784{
785 acpi_status status = AE_BAD_ADDRESS; 785 acpi_status status = AE_ERROR;
786 786
787 switch (interface->type) { 787 switch (interface->type) {
788 case ACER_AMW0: 788 case ACER_AMW0:
@@ -803,11 +803,30 @@ static acpi_status get_u32(u32 *value, u32 cap)
803 803
804static acpi_status set_u32(u32 value, u32 cap) 804static acpi_status set_u32(u32 value, u32 cap)
805{ 805{
806 acpi_status status;
807
806 if (interface->capability & cap) { 808 if (interface->capability & cap) {
807 switch (interface->type) { 809 switch (interface->type) {
808 case ACER_AMW0: 810 case ACER_AMW0:
809 return AMW0_set_u32(value, cap, interface); 811 return AMW0_set_u32(value, cap, interface);
810 case ACER_AMW0_V2: 812 case ACER_AMW0_V2:
813 if (cap == ACER_CAP_MAILLED)
814 return AMW0_set_u32(value, cap, interface);
815
816 /*
817 * On some models, some WMID methods don't toggle
818 * properly. For those cases, we want to run the AMW0
819 * method afterwards to be certain we've really toggled
820 * the device state.
821 */
822 if (cap == ACER_CAP_WIRELESS ||
823 cap == ACER_CAP_BLUETOOTH) {
824 status = WMID_set_u32(value, cap, interface);
825 if (ACPI_FAILURE(status))
826 return status;
827
828 return AMW0_set_u32(value, cap, interface);
829 }
811 case ACER_WMID: 830 case ACER_WMID:
812 return WMID_set_u32(value, cap, interface); 831 return WMID_set_u32(value, cap, interface);
813 default: 832 default:
@@ -824,8 +843,6 @@ static void __init acer_commandline_init(void)
824 * capability isn't available on the given interface 843 * capability isn't available on the given interface
825 */ 844 */
826 set_u32(mailled, ACER_CAP_MAILLED); 845 set_u32(mailled, ACER_CAP_MAILLED);
827 set_u32(wireless, ACER_CAP_WIRELESS);
828 set_u32(bluetooth, ACER_CAP_BLUETOOTH);
829 set_u32(threeg, ACER_CAP_THREEG); 846 set_u32(threeg, ACER_CAP_THREEG);
830 set_u32(brightness, ACER_CAP_BRIGHTNESS); 847 set_u32(brightness, ACER_CAP_BRIGHTNESS);
831} 848}
@@ -911,40 +928,135 @@ static void acer_backlight_exit(void)
911} 928}
912 929
913/* 930/*
914 * Read/ write bool sysfs macro 931 * Rfkill devices
915 */ 932 */
916#define show_set_bool(value, cap) \ 933static void acer_rfkill_update(struct work_struct *ignored);
917static ssize_t \ 934static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
918show_bool_##value(struct device *dev, struct device_attribute *attr, \ 935static void acer_rfkill_update(struct work_struct *ignored)
919 char *buf) \ 936{
920{ \ 937 u32 state;
921 u32 result; \ 938 acpi_status status;
922 acpi_status status = get_u32(&result, cap); \ 939
923 if (ACPI_SUCCESS(status)) \ 940 status = get_u32(&state, ACER_CAP_WIRELESS);
924 return sprintf(buf, "%u\n", result); \ 941 if (ACPI_SUCCESS(status))
925 return sprintf(buf, "Read error\n"); \ 942 rfkill_force_state(wireless_rfkill, state ?
926} \ 943 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
927\ 944
928static ssize_t \ 945 if (has_cap(ACER_CAP_BLUETOOTH)) {
929set_bool_##value(struct device *dev, struct device_attribute *attr, \ 946 status = get_u32(&state, ACER_CAP_BLUETOOTH);
930 const char *buf, size_t count) \ 947 if (ACPI_SUCCESS(status))
931{ \ 948 rfkill_force_state(bluetooth_rfkill, state ?
932 u32 tmp = simple_strtoul(buf, NULL, 10); \ 949 RFKILL_STATE_UNBLOCKED :
933 acpi_status status = set_u32(tmp, cap); \ 950 RFKILL_STATE_SOFT_BLOCKED);
934 if (ACPI_FAILURE(status)) \ 951 }
935 return -EINVAL; \ 952
936 return count; \ 953 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
937} \ 954}
938static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \ 955
939 show_bool_##value, set_bool_##value); 956static int acer_rfkill_set(void *data, enum rfkill_state state)
940 957{
941show_set_bool(wireless, ACER_CAP_WIRELESS); 958 acpi_status status;
942show_set_bool(bluetooth, ACER_CAP_BLUETOOTH); 959 u32 *cap = data;
943show_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}
944 1034
945/* 1035/*
946 * Read interface sysfs macro 1036 * sysfs interface
947 */ 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
948static ssize_t show_interface(struct device *dev, struct device_attribute *attr, 1060static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
949 char *buf) 1061 char *buf)
950{ 1062{
@@ -1004,7 +1116,9 @@ static int __devinit acer_platform_probe(struct platform_device *device)
1004 goto error_brightness; 1116 goto error_brightness;
1005 } 1117 }
1006 1118
1007 return 0; 1119 err = acer_rfkill_init(&device->dev);
1120
1121 return err;
1008 1122
1009error_brightness: 1123error_brightness:
1010 acer_led_exit(); 1124 acer_led_exit();
@@ -1018,6 +1132,8 @@ static int acer_platform_remove(struct platform_device *device)
1018 acer_led_exit(); 1132 acer_led_exit();
1019 if (has_cap(ACER_CAP_BRIGHTNESS)) 1133 if (has_cap(ACER_CAP_BRIGHTNESS))
1020 acer_backlight_exit(); 1134 acer_backlight_exit();
1135
1136 acer_rfkill_exit();
1021 return 0; 1137 return 0;
1022} 1138}
1023 1139
@@ -1030,16 +1146,6 @@ pm_message_t state)
1030 if (!data) 1146 if (!data)
1031 return -ENOMEM; 1147 return -ENOMEM;
1032 1148
1033 if (has_cap(ACER_CAP_WIRELESS)) {
1034 get_u32(&value, ACER_CAP_WIRELESS);
1035 data->wireless = value;
1036 }
1037
1038 if (has_cap(ACER_CAP_BLUETOOTH)) {
1039 get_u32(&value, ACER_CAP_BLUETOOTH);
1040 data->bluetooth = value;
1041 }
1042
1043 if (has_cap(ACER_CAP_MAILLED)) { 1149 if (has_cap(ACER_CAP_MAILLED)) {
1044 get_u32(&value, ACER_CAP_MAILLED); 1150 get_u32(&value, ACER_CAP_MAILLED);
1045 data->mailled = value; 1151 data->mailled = value;
@@ -1060,15 +1166,6 @@ static int acer_platform_resume(struct platform_device *device)
1060 if (!data) 1166 if (!data)
1061 return -ENOMEM; 1167 return -ENOMEM;
1062 1168
1063 if (has_cap(ACER_CAP_WIRELESS))
1064 set_u32(data->wireless, ACER_CAP_WIRELESS);
1065
1066 if (has_cap(ACER_CAP_BLUETOOTH))
1067 set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
1068
1069 if (has_cap(ACER_CAP_THREEG))
1070 set_u32(data->threeg, ACER_CAP_THREEG);
1071
1072 if (has_cap(ACER_CAP_MAILLED)) 1169 if (has_cap(ACER_CAP_MAILLED))
1073 set_u32(data->mailled, ACER_CAP_MAILLED); 1170 set_u32(data->mailled, ACER_CAP_MAILLED);
1074 1171
@@ -1093,12 +1190,6 @@ static struct platform_device *acer_platform_device;
1093 1190
1094static int remove_sysfs(struct platform_device *device) 1191static int remove_sysfs(struct platform_device *device)
1095{ 1192{
1096 if (has_cap(ACER_CAP_WIRELESS))
1097 device_remove_file(&device->dev, &dev_attr_wireless);
1098
1099 if (has_cap(ACER_CAP_BLUETOOTH))
1100 device_remove_file(&device->dev, &dev_attr_bluetooth);
1101
1102 if (has_cap(ACER_CAP_THREEG)) 1193 if (has_cap(ACER_CAP_THREEG))
1103 device_remove_file(&device->dev, &dev_attr_threeg); 1194 device_remove_file(&device->dev, &dev_attr_threeg);
1104 1195
@@ -1111,20 +1202,6 @@ static int create_sysfs(void)
1111{ 1202{
1112 int retval = -ENOMEM; 1203 int retval = -ENOMEM;
1113 1204
1114 if (has_cap(ACER_CAP_WIRELESS)) {
1115 retval = device_create_file(&acer_platform_device->dev,
1116 &dev_attr_wireless);
1117 if (retval)
1118 goto error_sysfs;
1119 }
1120
1121 if (has_cap(ACER_CAP_BLUETOOTH)) {
1122 retval = device_create_file(&acer_platform_device->dev,
1123 &dev_attr_bluetooth);
1124 if (retval)
1125 goto error_sysfs;
1126 }
1127
1128 if (has_cap(ACER_CAP_THREEG)) { 1205 if (has_cap(ACER_CAP_THREEG)) {
1129 retval = device_create_file(&acer_platform_device->dev, 1206 retval = device_create_file(&acer_platform_device->dev,
1130 &dev_attr_threeg); 1207 &dev_attr_threeg);
@@ -1167,7 +1244,7 @@ static int create_debugfs(void)
1167 return 0; 1244 return 0;
1168 1245
1169error_debugfs: 1246error_debugfs:
1170 remove_debugfs(); 1247 remove_debugfs();
1171 return -ENOMEM; 1248 return -ENOMEM;
1172} 1249}
1173 1250
@@ -1218,6 +1295,8 @@ static int __init acer_wmi_init(void)
1218 return -ENODEV; 1295 return -ENODEV;
1219 } 1296 }
1220 1297
1298 set_quirks();
1299
1221 if (platform_driver_register(&acer_platform_driver)) { 1300 if (platform_driver_register(&acer_platform_driver)) {
1222 printk(ACER_ERR "Unable to register platform driver.\n"); 1301 printk(ACER_ERR "Unable to register platform driver.\n");
1223 goto error_platform_register; 1302 goto error_platform_register;
@@ -1248,6 +1327,7 @@ error_platform_register:
1248static void __exit acer_wmi_exit(void) 1327static void __exit acer_wmi_exit(void)
1249{ 1328{
1250 remove_sysfs(acer_platform_device); 1329 remove_sysfs(acer_platform_device);
1330 remove_debugfs();
1251 platform_device_del(acer_platform_device); 1331 platform_device_del(acer_platform_device);
1252 platform_driver_unregister(&acer_platform_driver); 1332 platform_driver_unregister(&acer_platform_driver);
1253 1333