diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/dell-wmi.c | 159 |
1 files changed, 128 insertions, 31 deletions
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 25721bf20092..e2b6a642b3c5 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c | |||
@@ -145,57 +145,154 @@ static const u16 bios_to_linux_keycode[256] __initconst = { | |||
145 | 145 | ||
146 | static struct input_dev *dell_wmi_input_dev; | 146 | static struct input_dev *dell_wmi_input_dev; |
147 | 147 | ||
148 | static void dell_wmi_process_key(int reported_key) | ||
149 | { | ||
150 | const struct key_entry *key; | ||
151 | |||
152 | key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, | ||
153 | reported_key); | ||
154 | if (!key) { | ||
155 | pr_info("Unknown key %x pressed\n", reported_key); | ||
156 | return; | ||
157 | } | ||
158 | |||
159 | pr_debug("Key %x pressed\n", reported_key); | ||
160 | |||
161 | /* Don't report brightness notifications that will also come via ACPI */ | ||
162 | if ((key->keycode == KEY_BRIGHTNESSUP || | ||
163 | key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) | ||
164 | return; | ||
165 | |||
166 | sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); | ||
167 | } | ||
168 | |||
148 | static void dell_wmi_notify(u32 value, void *context) | 169 | static void dell_wmi_notify(u32 value, void *context) |
149 | { | 170 | { |
150 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | 171 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; |
151 | union acpi_object *obj; | 172 | union acpi_object *obj; |
152 | acpi_status status; | 173 | acpi_status status; |
174 | acpi_size buffer_size; | ||
175 | u16 *buffer_entry, *buffer_end; | ||
176 | int len, i; | ||
153 | 177 | ||
154 | status = wmi_get_event_data(value, &response); | 178 | status = wmi_get_event_data(value, &response); |
155 | if (status != AE_OK) { | 179 | if (status != AE_OK) { |
156 | pr_info("bad event status 0x%x\n", status); | 180 | pr_warn("bad event status 0x%x\n", status); |
157 | return; | 181 | return; |
158 | } | 182 | } |
159 | 183 | ||
160 | obj = (union acpi_object *)response.pointer; | 184 | obj = (union acpi_object *)response.pointer; |
185 | if (!obj) { | ||
186 | pr_warn("no response\n"); | ||
187 | return; | ||
188 | } | ||
161 | 189 | ||
162 | if (obj && obj->type == ACPI_TYPE_BUFFER) { | 190 | if (obj->type != ACPI_TYPE_BUFFER) { |
163 | const struct key_entry *key; | 191 | pr_warn("bad response type %x\n", obj->type); |
164 | int reported_key; | 192 | kfree(obj); |
165 | u16 *buffer_entry = (u16 *)obj->buffer.pointer; | 193 | return; |
166 | int buffer_size = obj->buffer.length/2; | 194 | } |
167 | 195 | ||
168 | if (buffer_size >= 2 && dell_new_hk_type && buffer_entry[1] != 0x10) { | 196 | pr_debug("Received WMI event (%*ph)\n", |
169 | pr_info("Received unknown WMI event (0x%x)\n", | 197 | obj->buffer.length, obj->buffer.pointer); |
170 | buffer_entry[1]); | ||
171 | kfree(obj); | ||
172 | return; | ||
173 | } | ||
174 | 198 | ||
175 | if (buffer_size >= 3 && (dell_new_hk_type || buffer_entry[1] == 0x0)) | 199 | buffer_entry = (u16 *)obj->buffer.pointer; |
176 | reported_key = (int)buffer_entry[2]; | 200 | buffer_size = obj->buffer.length/2; |
201 | |||
202 | if (!dell_new_hk_type) { | ||
203 | if (buffer_size >= 3 && buffer_entry[1] == 0x0) | ||
204 | dell_wmi_process_key(buffer_entry[2]); | ||
177 | else if (buffer_size >= 2) | 205 | else if (buffer_size >= 2) |
178 | reported_key = (int)buffer_entry[1] & 0xffff; | 206 | dell_wmi_process_key(buffer_entry[1]); |
179 | else { | 207 | else |
180 | pr_info("Received unknown WMI event\n"); | 208 | pr_info("Received unknown WMI event\n"); |
181 | kfree(obj); | 209 | kfree(obj); |
182 | return; | 210 | return; |
211 | } | ||
212 | |||
213 | buffer_end = buffer_entry + buffer_size; | ||
214 | |||
215 | while (buffer_entry < buffer_end) { | ||
216 | |||
217 | len = buffer_entry[0]; | ||
218 | if (len == 0) | ||
219 | break; | ||
220 | |||
221 | len++; | ||
222 | |||
223 | if (buffer_entry + len > buffer_end) { | ||
224 | pr_warn("Invalid length of WMI event\n"); | ||
225 | break; | ||
183 | } | 226 | } |
184 | 227 | ||
185 | key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, | 228 | pr_debug("Process buffer (%*ph)\n", len*2, buffer_entry); |
186 | reported_key); | 229 | |
187 | if (!key) { | 230 | switch (buffer_entry[1]) { |
188 | pr_info("Unknown key %x pressed\n", reported_key); | 231 | case 0x00: |
189 | } else if ((key->keycode == KEY_BRIGHTNESSUP || | 232 | for (i = 2; i < len; ++i) { |
190 | key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) { | 233 | switch (buffer_entry[i]) { |
191 | /* Don't report brightness notifications that will also | 234 | case 0xe043: |
192 | * come via ACPI */ | 235 | /* NIC Link is Up */ |
193 | ; | 236 | pr_debug("NIC Link is Up\n"); |
194 | } else { | 237 | break; |
195 | sparse_keymap_report_entry(dell_wmi_input_dev, key, | 238 | case 0xe044: |
196 | 1, true); | 239 | /* NIC Link is Down */ |
240 | pr_debug("NIC Link is Down\n"); | ||
241 | break; | ||
242 | case 0xe045: | ||
243 | /* Unknown event but defined in DSDT */ | ||
244 | default: | ||
245 | /* Unknown event */ | ||
246 | pr_info("Unknown WMI event type 0x00: " | ||
247 | "0x%x\n", (int)buffer_entry[i]); | ||
248 | break; | ||
249 | } | ||
250 | } | ||
251 | break; | ||
252 | case 0x10: | ||
253 | /* Keys pressed */ | ||
254 | for (i = 2; i < len; ++i) | ||
255 | dell_wmi_process_key(buffer_entry[i]); | ||
256 | break; | ||
257 | case 0x11: | ||
258 | for (i = 2; i < len; ++i) { | ||
259 | switch (buffer_entry[i]) { | ||
260 | case 0xfff0: | ||
261 | /* Battery unplugged */ | ||
262 | pr_debug("Battery unplugged\n"); | ||
263 | break; | ||
264 | case 0xfff1: | ||
265 | /* Battery inserted */ | ||
266 | pr_debug("Battery inserted\n"); | ||
267 | break; | ||
268 | case 0x01e1: | ||
269 | case 0x02ea: | ||
270 | case 0x02eb: | ||
271 | case 0x02ec: | ||
272 | case 0x02f6: | ||
273 | /* Keyboard backlight level changed */ | ||
274 | pr_debug("Keyboard backlight level " | ||
275 | "changed\n"); | ||
276 | break; | ||
277 | default: | ||
278 | /* Unknown event */ | ||
279 | pr_info("Unknown WMI event type 0x11: " | ||
280 | "0x%x\n", (int)buffer_entry[i]); | ||
281 | break; | ||
282 | } | ||
283 | } | ||
284 | break; | ||
285 | default: | ||
286 | /* Unknown event */ | ||
287 | pr_info("Unknown WMI event type 0x%x\n", | ||
288 | (int)buffer_entry[1]); | ||
289 | break; | ||
197 | } | 290 | } |
291 | |||
292 | buffer_entry += len; | ||
293 | |||
198 | } | 294 | } |
295 | |||
199 | kfree(obj); | 296 | kfree(obj); |
200 | } | 297 | } |
201 | 298 | ||