diff options
author | Lee, Chun-Yi <joeyli.kernel@gmail.com> | 2010-12-06 21:29:22 -0500 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2011-01-07 17:03:48 -0500 |
commit | b3c9092b2fed427d45117d23ceb577ad8dc46a9a (patch) | |
tree | 726ab8a4ee2d95672c4dac824d98443b382889aa /drivers/platform/x86/acer-wmi.c | |
parent | 3fdca87d10f1d45b1c034da343e68beb082f9b84 (diff) |
acer-wmi: Add 3G rfkill sysfs file
Add 3G rfkill sysfs file for provide userland to control 3G device
on/off by using WMI method.
Signed-off-by: Lee, Chun-Yi <jlee@novell.com>
Acked-by: Thomas Renninger <trenn@suse.de>
Acked-by: Jiri Benc <jbenc@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Carlos Corbaho <carlos@strangeworlds.co.uk>
Cc: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform/x86/acer-wmi.c')
-rw-r--r-- | drivers/platform/x86/acer-wmi.c | 100 |
1 files changed, 99 insertions, 1 deletions
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index a1c6141f463b..85d263349aac 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -85,6 +85,7 @@ MODULE_LICENSE("GPL"); | |||
85 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" | 85 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" |
86 | #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" | 86 | #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" |
87 | #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" | 87 | #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" |
88 | #define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" | ||
88 | 89 | ||
89 | /* | 90 | /* |
90 | * Acer ACPI event GUIDs | 91 | * Acer ACPI event GUIDs |
@@ -121,6 +122,24 @@ struct event_return_value { | |||
121 | } __attribute__((packed)); | 122 | } __attribute__((packed)); |
122 | 123 | ||
123 | /* | 124 | /* |
125 | * GUID3 Get Device Status device flags | ||
126 | */ | ||
127 | #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ | ||
128 | |||
129 | struct wmid3_gds_input_param { /* Get Device Status input parameter */ | ||
130 | u8 function_num; /* Function Number */ | ||
131 | u8 hotkey_number; /* Hotkey Number */ | ||
132 | u16 devices; /* Get Device */ | ||
133 | } __attribute__((packed)); | ||
134 | |||
135 | struct wmid3_gds_return_value { /* Get Device Status return value*/ | ||
136 | u8 error_code; /* Error Code */ | ||
137 | u8 ec_return_value; /* EC Return Value */ | ||
138 | u16 devices; /* Current Device Status */ | ||
139 | u32 reserved; | ||
140 | } __attribute__((packed)); | ||
141 | |||
142 | /* | ||
124 | * Interface capability flags | 143 | * Interface capability flags |
125 | */ | 144 | */ |
126 | #define ACER_CAP_MAILLED (1<<0) | 145 | #define ACER_CAP_MAILLED (1<<0) |
@@ -174,6 +193,7 @@ struct acer_debug { | |||
174 | 193 | ||
175 | static struct rfkill *wireless_rfkill; | 194 | static struct rfkill *wireless_rfkill; |
176 | static struct rfkill *bluetooth_rfkill; | 195 | static struct rfkill *bluetooth_rfkill; |
196 | static struct rfkill *threeg_rfkill; | ||
177 | 197 | ||
178 | /* Each low-level interface must define at least some of the following */ | 198 | /* Each low-level interface must define at least some of the following */ |
179 | struct wmi_interface { | 199 | struct wmi_interface { |
@@ -982,6 +1002,54 @@ static void acer_backlight_exit(void) | |||
982 | backlight_device_unregister(acer_backlight_device); | 1002 | backlight_device_unregister(acer_backlight_device); |
983 | } | 1003 | } |
984 | 1004 | ||
1005 | static acpi_status wmid3_get_device_status(u32 *value, u16 device) | ||
1006 | { | ||
1007 | struct wmid3_gds_return_value return_value; | ||
1008 | acpi_status status; | ||
1009 | union acpi_object *obj; | ||
1010 | struct wmid3_gds_input_param params = { | ||
1011 | .function_num = 0x1, | ||
1012 | .hotkey_number = 0x01, | ||
1013 | .devices = device, | ||
1014 | }; | ||
1015 | struct acpi_buffer input = { | ||
1016 | sizeof(struct wmid3_gds_input_param), | ||
1017 | ¶ms | ||
1018 | }; | ||
1019 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1020 | |||
1021 | status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); | ||
1022 | if (ACPI_FAILURE(status)) | ||
1023 | return status; | ||
1024 | |||
1025 | obj = output.pointer; | ||
1026 | |||
1027 | if (!obj) | ||
1028 | return AE_ERROR; | ||
1029 | else if (obj->type != ACPI_TYPE_BUFFER) { | ||
1030 | kfree(obj); | ||
1031 | return AE_ERROR; | ||
1032 | } | ||
1033 | if (obj->buffer.length != 8) { | ||
1034 | printk(ACER_WARNING "Unknown buffer length %d\n", | ||
1035 | obj->buffer.length); | ||
1036 | kfree(obj); | ||
1037 | return AE_ERROR; | ||
1038 | } | ||
1039 | |||
1040 | return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); | ||
1041 | kfree(obj); | ||
1042 | |||
1043 | if (return_value.error_code || return_value.ec_return_value) | ||
1044 | printk(ACER_WARNING "Get Device Status failed: " | ||
1045 | "0x%x - 0x%x\n", return_value.error_code, | ||
1046 | return_value.ec_return_value); | ||
1047 | else | ||
1048 | *value = !!(return_value.devices & device); | ||
1049 | |||
1050 | return status; | ||
1051 | } | ||
1052 | |||
985 | /* | 1053 | /* |
986 | * Rfkill devices | 1054 | * Rfkill devices |
987 | */ | 1055 | */ |
@@ -1002,6 +1070,13 @@ static void acer_rfkill_update(struct work_struct *ignored) | |||
1002 | rfkill_set_sw_state(bluetooth_rfkill, !state); | 1070 | rfkill_set_sw_state(bluetooth_rfkill, !state); |
1003 | } | 1071 | } |
1004 | 1072 | ||
1073 | if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) { | ||
1074 | status = wmid3_get_device_status(&state, | ||
1075 | ACER_WMID3_GDS_THREEG); | ||
1076 | if (ACPI_SUCCESS(status)) | ||
1077 | rfkill_set_sw_state(threeg_rfkill, !state); | ||
1078 | } | ||
1079 | |||
1005 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | 1080 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); |
1006 | } | 1081 | } |
1007 | 1082 | ||
@@ -1058,6 +1133,19 @@ static int acer_rfkill_init(struct device *dev) | |||
1058 | } | 1133 | } |
1059 | } | 1134 | } |
1060 | 1135 | ||
1136 | if (has_cap(ACER_CAP_THREEG)) { | ||
1137 | threeg_rfkill = acer_rfkill_register(dev, | ||
1138 | RFKILL_TYPE_WWAN, "acer-threeg", | ||
1139 | ACER_CAP_THREEG); | ||
1140 | if (IS_ERR(threeg_rfkill)) { | ||
1141 | rfkill_unregister(wireless_rfkill); | ||
1142 | rfkill_destroy(wireless_rfkill); | ||
1143 | rfkill_unregister(bluetooth_rfkill); | ||
1144 | rfkill_destroy(bluetooth_rfkill); | ||
1145 | return PTR_ERR(threeg_rfkill); | ||
1146 | } | ||
1147 | } | ||
1148 | |||
1061 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | 1149 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); |
1062 | 1150 | ||
1063 | return 0; | 1151 | return 0; |
@@ -1074,6 +1162,11 @@ static void acer_rfkill_exit(void) | |||
1074 | rfkill_unregister(bluetooth_rfkill); | 1162 | rfkill_unregister(bluetooth_rfkill); |
1075 | rfkill_destroy(bluetooth_rfkill); | 1163 | rfkill_destroy(bluetooth_rfkill); |
1076 | } | 1164 | } |
1165 | |||
1166 | if (has_cap(ACER_CAP_THREEG)) { | ||
1167 | rfkill_unregister(threeg_rfkill); | ||
1168 | rfkill_destroy(threeg_rfkill); | ||
1169 | } | ||
1077 | return; | 1170 | return; |
1078 | } | 1171 | } |
1079 | 1172 | ||
@@ -1084,7 +1177,12 @@ static ssize_t show_bool_threeg(struct device *dev, | |||
1084 | struct device_attribute *attr, char *buf) | 1177 | struct device_attribute *attr, char *buf) |
1085 | { | 1178 | { |
1086 | u32 result; \ | 1179 | u32 result; \ |
1087 | acpi_status status = get_u32(&result, ACER_CAP_THREEG); | 1180 | acpi_status status; |
1181 | if (wmi_has_guid(WMID_GUID3)) | ||
1182 | status = wmid3_get_device_status(&result, | ||
1183 | ACER_WMID3_GDS_THREEG); | ||
1184 | else | ||
1185 | status = get_u32(&result, ACER_CAP_THREEG); | ||
1088 | if (ACPI_SUCCESS(status)) | 1186 | if (ACPI_SUCCESS(status)) |
1089 | return sprintf(buf, "%u\n", result); | 1187 | return sprintf(buf, "%u\n", result); |
1090 | return sprintf(buf, "Read error\n"); | 1188 | return sprintf(buf, "Read error\n"); |