]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/platform/x86/wmi.c
toshiba_bluetooth: Fix enabling/disabling loop on recent devices
[mirror_ubuntu-bionic-kernel.git] / drivers / platform / x86 / wmi.c
CommitLineData
bff431e4
CC
1/*
2 * ACPI-WMI mapping driver
3 *
4 * Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
5 *
6 * GUID parsing code from ldm.c is:
7 * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
8 * Copyright (c) 2001-2007 Anton Altaparmakov
9 * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
10 *
11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or (at
16 * your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 *
27 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28 */
29
8e07514d
DT
30#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31
bff431e4
CC
32#include <linux/kernel.h>
33#include <linux/init.h>
34#include <linux/types.h>
1caab3c1 35#include <linux/device.h>
bff431e4
CC
36#include <linux/list.h>
37#include <linux/acpi.h>
5a0e3ad6 38#include <linux/slab.h>
7c52d551 39#include <linux/module.h>
bff431e4
CC
40
41ACPI_MODULE_NAME("wmi");
42MODULE_AUTHOR("Carlos Corbacho");
43MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
44MODULE_LICENSE("GPL");
45
46#define ACPI_WMI_CLASS "wmi"
47
762e1a2f 48static LIST_HEAD(wmi_block_list);
bff431e4
CC
49
50struct guid_block {
51 char guid[16];
52 union {
53 char object_id[2];
54 struct {
55 unsigned char notify_id;
56 unsigned char reserved;
57 };
58 };
59 u8 instance_count;
60 u8 flags;
61};
62
63struct wmi_block {
64 struct list_head list;
65 struct guid_block gblock;
66 acpi_handle handle;
67 wmi_notify_handler handler;
68 void *handler_data;
c64eefd4 69 struct device dev;
bff431e4
CC
70};
71
bff431e4
CC
72
73/*
74 * If the GUID data block is marked as expensive, we must enable and
75 * explicitily disable data collection.
76 */
77#define ACPI_WMI_EXPENSIVE 0x1
78#define ACPI_WMI_METHOD 0x2 /* GUID is a method */
79#define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */
80#define ACPI_WMI_EVENT 0x8 /* GUID is an event */
81
90ab5ee9 82static bool debug_event;
fc3155b2
TR
83module_param(debug_event, bool, 0444);
84MODULE_PARM_DESC(debug_event,
85 "Log WMI Events [0/1]");
86
90ab5ee9 87static bool debug_dump_wdg;
a929aae0
TR
88module_param(debug_dump_wdg, bool, 0444);
89MODULE_PARM_DESC(debug_dump_wdg,
90 "Dump available WMI interfaces [0/1]");
91
51fac838 92static int acpi_wmi_remove(struct acpi_device *device);
bff431e4 93static int acpi_wmi_add(struct acpi_device *device);
f61bb939 94static void acpi_wmi_notify(struct acpi_device *device, u32 event);
bff431e4
CC
95
96static const struct acpi_device_id wmi_device_ids[] = {
97 {"PNP0C14", 0},
98 {"pnp0c14", 0},
99 {"", 0},
100};
101MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
102
103static struct acpi_driver acpi_wmi_driver = {
104 .name = "wmi",
105 .class = ACPI_WMI_CLASS,
106 .ids = wmi_device_ids,
107 .ops = {
108 .add = acpi_wmi_add,
109 .remove = acpi_wmi_remove,
f61bb939 110 .notify = acpi_wmi_notify,
c64eefd4 111 },
bff431e4
CC
112};
113
114/*
115 * GUID parsing functions
116 */
117
118/**
119 * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
120 * @src: Pointer to at least 2 characters to convert.
121 *
122 * Convert a two character ASCII hex string to a number.
123 *
124 * Return: 0-255 Success, the byte was parsed correctly
125 * -1 Error, an invalid character was supplied
126 */
127static int wmi_parse_hexbyte(const u8 *src)
128{
bff431e4 129 int h;
392bd8b5 130 int value;
bff431e4
CC
131
132 /* high part */
392bd8b5
AS
133 h = value = hex_to_bin(src[0]);
134 if (value < 0)
bff431e4 135 return -1;
bff431e4
CC
136
137 /* low part */
392bd8b5
AS
138 value = hex_to_bin(src[1]);
139 if (value >= 0)
140 return (h << 4) | value;
bff431e4
CC
141 return -1;
142}
143
144/**
145 * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
146 * @src: Memory block holding binary GUID (16 bytes)
147 * @dest: Memory block to hold byte swapped binary GUID (16 bytes)
148 *
149 * Byte swap a binary GUID to match it's real GUID value
150 */
151static void wmi_swap_bytes(u8 *src, u8 *dest)
152{
153 int i;
154
155 for (i = 0; i <= 3; i++)
156 memcpy(dest + i, src + (3 - i), 1);
157
158 for (i = 0; i <= 1; i++)
159 memcpy(dest + 4 + i, src + (5 - i), 1);
160
161 for (i = 0; i <= 1; i++)
162 memcpy(dest + 6 + i, src + (7 - i), 1);
163
164 memcpy(dest + 8, src + 8, 8);
165}
166
167/**
168 * wmi_parse_guid - Convert GUID from ASCII to binary
169 * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
170 * @dest: Memory block to hold binary GUID (16 bytes)
171 *
172 * N.B. The GUID need not be NULL terminated.
173 *
174 * Return: 'true' @dest contains binary GUID
175 * 'false' @dest contents are undefined
176 */
177static bool wmi_parse_guid(const u8 *src, u8 *dest)
178{
179 static const int size[] = { 4, 2, 2, 2, 6 };
180 int i, j, v;
181
182 if (src[8] != '-' || src[13] != '-' ||
183 src[18] != '-' || src[23] != '-')
184 return false;
185
186 for (j = 0; j < 5; j++, src++) {
187 for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
188 v = wmi_parse_hexbyte(src);
189 if (v < 0)
190 return false;
191 }
192 }
193
194 return true;
195}
196
1caab3c1
MG
197/*
198 * Convert a raw GUID to the ACII string representation
199 */
200static int wmi_gtoa(const char *in, char *out)
201{
202 int i;
203
204 for (i = 3; i >= 0; i--)
205 out += sprintf(out, "%02X", in[i] & 0xFF);
206
207 out += sprintf(out, "-");
208 out += sprintf(out, "%02X", in[5] & 0xFF);
209 out += sprintf(out, "%02X", in[4] & 0xFF);
210 out += sprintf(out, "-");
211 out += sprintf(out, "%02X", in[7] & 0xFF);
212 out += sprintf(out, "%02X", in[6] & 0xFF);
213 out += sprintf(out, "-");
214 out += sprintf(out, "%02X", in[8] & 0xFF);
215 out += sprintf(out, "%02X", in[9] & 0xFF);
216 out += sprintf(out, "-");
217
218 for (i = 10; i <= 15; i++)
219 out += sprintf(out, "%02X", in[i] & 0xFF);
220
4e4304d7 221 *out = '\0';
1caab3c1
MG
222 return 0;
223}
224
bff431e4
CC
225static bool find_guid(const char *guid_string, struct wmi_block **out)
226{
227 char tmp[16], guid_input[16];
228 struct wmi_block *wblock;
229 struct guid_block *block;
230 struct list_head *p;
231
232 wmi_parse_guid(guid_string, tmp);
233 wmi_swap_bytes(tmp, guid_input);
234
762e1a2f 235 list_for_each(p, &wmi_block_list) {
bff431e4
CC
236 wblock = list_entry(p, struct wmi_block, list);
237 block = &wblock->gblock;
238
239 if (memcmp(block->guid, guid_input, 16) == 0) {
240 if (out)
241 *out = wblock;
242 return 1;
243 }
244 }
245 return 0;
246}
247
a66bfa7a
MG
248static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
249{
250 struct guid_block *block = NULL;
251 char method[5];
a66bfa7a
MG
252 acpi_status status;
253 acpi_handle handle;
254
255 block = &wblock->gblock;
256 handle = wblock->handle;
257
a66bfa7a 258 snprintf(method, 5, "WE%02X", block->notify_id);
8122ab66 259 status = acpi_execute_simple_method(handle, method, enable);
a66bfa7a
MG
260
261 if (status != AE_OK && status != AE_NOT_FOUND)
262 return status;
263 else
264 return AE_OK;
265}
266
bff431e4
CC
267/*
268 * Exported WMI functions
269 */
270/**
271 * wmi_evaluate_method - Evaluate a WMI method
272 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
273 * @instance: Instance index
274 * @method_id: Method ID to call
275 * &in: Buffer containing input for the method call
276 * &out: Empty buffer to return the method results
277 *
278 * Call an ACPI-WMI method
279 */
280acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
281u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
282{
283 struct guid_block *block = NULL;
284 struct wmi_block *wblock = NULL;
285 acpi_handle handle;
286 acpi_status status;
287 struct acpi_object_list input;
288 union acpi_object params[3];
f3d83e24 289 char method[5] = "WM";
bff431e4
CC
290
291 if (!find_guid(guid_string, &wblock))
08237974 292 return AE_ERROR;
bff431e4
CC
293
294 block = &wblock->gblock;
295 handle = wblock->handle;
296
e6bafba5 297 if (!(block->flags & ACPI_WMI_METHOD))
bff431e4
CC
298 return AE_BAD_DATA;
299
300 if (block->instance_count < instance)
301 return AE_BAD_PARAMETER;
302
303 input.count = 2;
304 input.pointer = params;
305 params[0].type = ACPI_TYPE_INTEGER;
306 params[0].integer.value = instance;
307 params[1].type = ACPI_TYPE_INTEGER;
308 params[1].integer.value = method_id;
309
310 if (in) {
311 input.count = 3;
312
313 if (block->flags & ACPI_WMI_STRING) {
314 params[2].type = ACPI_TYPE_STRING;
315 } else {
316 params[2].type = ACPI_TYPE_BUFFER;
317 }
318 params[2].buffer.length = in->length;
319 params[2].buffer.pointer = in->pointer;
320 }
321
322 strncat(method, block->object_id, 2);
323
324 status = acpi_evaluate_object(handle, method, &input, out);
325
326 return status;
327}
328EXPORT_SYMBOL_GPL(wmi_evaluate_method);
329
330/**
331 * wmi_query_block - Return contents of a WMI block
332 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
333 * @instance: Instance index
334 * &out: Empty buffer to return the contents of the data block to
335 *
336 * Return the contents of an ACPI-WMI data block to a buffer
337 */
338acpi_status wmi_query_block(const char *guid_string, u8 instance,
339struct acpi_buffer *out)
340{
341 struct guid_block *block = NULL;
342 struct wmi_block *wblock = NULL;
54f14c27 343 acpi_handle handle;
bff431e4 344 acpi_status status, wc_status = AE_ERROR;
8122ab66
ZR
345 struct acpi_object_list input;
346 union acpi_object wq_params[1];
f3d83e24
CL
347 char method[5];
348 char wc_method[5] = "WC";
bff431e4
CC
349
350 if (!guid_string || !out)
351 return AE_BAD_PARAMETER;
352
353 if (!find_guid(guid_string, &wblock))
08237974 354 return AE_ERROR;
bff431e4
CC
355
356 block = &wblock->gblock;
357 handle = wblock->handle;
358
359 if (block->instance_count < instance)
360 return AE_BAD_PARAMETER;
361
362 /* Check GUID is a data block */
363 if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
08237974 364 return AE_ERROR;
bff431e4
CC
365
366 input.count = 1;
367 input.pointer = wq_params;
368 wq_params[0].type = ACPI_TYPE_INTEGER;
369 wq_params[0].integer.value = instance;
370
371 /*
372 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
373 * enable collection.
374 */
375 if (block->flags & ACPI_WMI_EXPENSIVE) {
bff431e4
CC
376 strncat(wc_method, block->object_id, 2);
377
378 /*
379 * Some GUIDs break the specification by declaring themselves
380 * expensive, but have no corresponding WCxx method. So we
381 * should not fail if this happens.
382 */
54f14c27 383 if (acpi_has_method(handle, wc_method))
8122ab66
ZR
384 wc_status = acpi_execute_simple_method(handle,
385 wc_method, 1);
bff431e4
CC
386 }
387
388 strcpy(method, "WQ");
389 strncat(method, block->object_id, 2);
390
dab36ad8 391 status = acpi_evaluate_object(handle, method, &input, out);
bff431e4
CC
392
393 /*
394 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
395 * the WQxx method failed - we should disable collection anyway.
396 */
a527f2d7 397 if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
8122ab66 398 status = acpi_execute_simple_method(handle, wc_method, 0);
bff431e4
CC
399 }
400
401 return status;
402}
403EXPORT_SYMBOL_GPL(wmi_query_block);
404
405/**
406 * wmi_set_block - Write to a WMI block
407 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
408 * @instance: Instance index
409 * &in: Buffer containing new values for the data block
410 *
411 * Write the contents of the input buffer to an ACPI-WMI data block
412 */
413acpi_status wmi_set_block(const char *guid_string, u8 instance,
414const struct acpi_buffer *in)
415{
416 struct guid_block *block = NULL;
417 struct wmi_block *wblock = NULL;
418 acpi_handle handle;
419 struct acpi_object_list input;
420 union acpi_object params[2];
f3d83e24 421 char method[5] = "WS";
bff431e4
CC
422
423 if (!guid_string || !in)
424 return AE_BAD_DATA;
425
426 if (!find_guid(guid_string, &wblock))
08237974 427 return AE_ERROR;
bff431e4
CC
428
429 block = &wblock->gblock;
430 handle = wblock->handle;
431
432 if (block->instance_count < instance)
433 return AE_BAD_PARAMETER;
434
435 /* Check GUID is a data block */
436 if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
08237974 437 return AE_ERROR;
bff431e4
CC
438
439 input.count = 2;
440 input.pointer = params;
441 params[0].type = ACPI_TYPE_INTEGER;
442 params[0].integer.value = instance;
443
444 if (block->flags & ACPI_WMI_STRING) {
445 params[1].type = ACPI_TYPE_STRING;
446 } else {
447 params[1].type = ACPI_TYPE_BUFFER;
448 }
449 params[1].buffer.length = in->length;
450 params[1].buffer.pointer = in->pointer;
451
452 strncat(method, block->object_id, 2);
453
454 return acpi_evaluate_object(handle, method, &input, NULL);
455}
456EXPORT_SYMBOL_GPL(wmi_set_block);
457
37830662 458static void wmi_dump_wdg(const struct guid_block *g)
a929aae0
TR
459{
460 char guid_string[37];
461
462 wmi_gtoa(g->guid, guid_string);
8e07514d
DT
463
464 pr_info("%s:\n", guid_string);
465 pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
466 pr_info("\tnotify_id: %02X\n", g->notify_id);
467 pr_info("\treserved: %02X\n", g->reserved);
468 pr_info("\tinstance_count: %d\n", g->instance_count);
dd8e908e 469 pr_info("\tflags: %#x", g->flags);
a929aae0 470 if (g->flags) {
a929aae0 471 if (g->flags & ACPI_WMI_EXPENSIVE)
dd8e908e 472 pr_cont(" ACPI_WMI_EXPENSIVE");
a929aae0 473 if (g->flags & ACPI_WMI_METHOD)
dd8e908e 474 pr_cont(" ACPI_WMI_METHOD");
a929aae0 475 if (g->flags & ACPI_WMI_STRING)
dd8e908e 476 pr_cont(" ACPI_WMI_STRING");
a929aae0 477 if (g->flags & ACPI_WMI_EVENT)
dd8e908e 478 pr_cont(" ACPI_WMI_EVENT");
a929aae0 479 }
8e07514d 480 pr_cont("\n");
a929aae0
TR
481
482}
483
fc3155b2
TR
484static void wmi_notify_debug(u32 value, void *context)
485{
486 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
487 union acpi_object *obj;
1492616a 488 acpi_status status;
fc3155b2 489
1492616a
AL
490 status = wmi_get_event_data(value, &response);
491 if (status != AE_OK) {
8e07514d 492 pr_info("bad event status 0x%x\n", status);
1492616a
AL
493 return;
494 }
fc3155b2
TR
495
496 obj = (union acpi_object *)response.pointer;
497
498 if (!obj)
499 return;
500
8e07514d 501 pr_info("DEBUG Event ");
fc3155b2
TR
502 switch(obj->type) {
503 case ACPI_TYPE_BUFFER:
8e07514d 504 pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
fc3155b2
TR
505 break;
506 case ACPI_TYPE_STRING:
8e07514d 507 pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
fc3155b2
TR
508 break;
509 case ACPI_TYPE_INTEGER:
8e07514d 510 pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
fc3155b2
TR
511 break;
512 case ACPI_TYPE_PACKAGE:
8e07514d 513 pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
fc3155b2
TR
514 break;
515 default:
8e07514d 516 pr_cont("object type 0x%X\n", obj->type);
fc3155b2 517 }
1492616a 518 kfree(obj);
fc3155b2
TR
519}
520
bff431e4
CC
521/**
522 * wmi_install_notify_handler - Register handler for WMI events
523 * @handler: Function to handle notifications
524 * @data: Data to be returned to handler when event is fired
525 *
526 * Register a handler for events sent to the ACPI-WMI mapper device.
527 */
528acpi_status wmi_install_notify_handler(const char *guid,
529wmi_notify_handler handler, void *data)
530{
531 struct wmi_block *block;
58f6425e
CK
532 acpi_status status = AE_NOT_EXIST;
533 char tmp[16], guid_input[16];
534 struct list_head *p;
bff431e4
CC
535
536 if (!guid || !handler)
537 return AE_BAD_PARAMETER;
538
58f6425e
CK
539 wmi_parse_guid(guid, tmp);
540 wmi_swap_bytes(tmp, guid_input);
bff431e4 541
58f6425e
CK
542 list_for_each(p, &wmi_block_list) {
543 acpi_status wmi_status;
544 block = list_entry(p, struct wmi_block, list);
545
546 if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
547 if (block->handler &&
548 block->handler != wmi_notify_debug)
549 return AE_ALREADY_ACQUIRED;
bff431e4 550
58f6425e
CK
551 block->handler = handler;
552 block->handler_data = data;
bff431e4 553
58f6425e
CK
554 wmi_status = wmi_method_enable(block, 1);
555 if ((wmi_status != AE_OK) ||
556 ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
557 status = wmi_status;
558 }
559 }
a66bfa7a
MG
560
561 return status;
bff431e4
CC
562}
563EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
564
565/**
566 * wmi_uninstall_notify_handler - Unregister handler for WMI events
567 *
568 * Unregister handler for events sent to the ACPI-WMI mapper device.
569 */
570acpi_status wmi_remove_notify_handler(const char *guid)
571{
572 struct wmi_block *block;
58f6425e
CK
573 acpi_status status = AE_NOT_EXIST;
574 char tmp[16], guid_input[16];
575 struct list_head *p;
bff431e4
CC
576
577 if (!guid)
578 return AE_BAD_PARAMETER;
579
58f6425e
CK
580 wmi_parse_guid(guid, tmp);
581 wmi_swap_bytes(tmp, guid_input);
bff431e4 582
58f6425e
CK
583 list_for_each(p, &wmi_block_list) {
584 acpi_status wmi_status;
585 block = list_entry(p, struct wmi_block, list);
586
587 if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
588 if (!block->handler ||
589 block->handler == wmi_notify_debug)
590 return AE_NULL_ENTRY;
591
592 if (debug_event) {
593 block->handler = wmi_notify_debug;
594 status = AE_OK;
595 } else {
596 wmi_status = wmi_method_enable(block, 0);
597 block->handler = NULL;
598 block->handler_data = NULL;
599 if ((wmi_status != AE_OK) ||
600 ((wmi_status == AE_OK) &&
601 (status == AE_NOT_EXIST)))
602 status = wmi_status;
603 }
604 }
fc3155b2 605 }
58f6425e 606
a66bfa7a 607 return status;
bff431e4
CC
608}
609EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
610
611/**
612 * wmi_get_event_data - Get WMI data associated with an event
613 *
3e9b988e
AA
614 * @event: Event to find
615 * @out: Buffer to hold event data. out->pointer should be freed with kfree()
bff431e4
CC
616 *
617 * Returns extra data associated with an event in WMI.
618 */
619acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
620{
621 struct acpi_object_list input;
622 union acpi_object params[1];
623 struct guid_block *gblock;
624 struct wmi_block *wblock;
625 struct list_head *p;
626
627 input.count = 1;
628 input.pointer = params;
629 params[0].type = ACPI_TYPE_INTEGER;
630 params[0].integer.value = event;
631
762e1a2f 632 list_for_each(p, &wmi_block_list) {
bff431e4
CC
633 wblock = list_entry(p, struct wmi_block, list);
634 gblock = &wblock->gblock;
635
636 if ((gblock->flags & ACPI_WMI_EVENT) &&
637 (gblock->notify_id == event))
638 return acpi_evaluate_object(wblock->handle, "_WED",
639 &input, out);
640 }
641
642 return AE_NOT_FOUND;
643}
644EXPORT_SYMBOL_GPL(wmi_get_event_data);
645
646/**
647 * wmi_has_guid - Check if a GUID is available
648 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
649 *
650 * Check if a given GUID is defined by _WDG
651 */
652bool wmi_has_guid(const char *guid_string)
653{
654 return find_guid(guid_string, NULL);
655}
656EXPORT_SYMBOL_GPL(wmi_has_guid);
657
1caab3c1
MG
658/*
659 * sysfs interface
660 */
614ef432 661static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
1caab3c1
MG
662 char *buf)
663{
664 char guid_string[37];
665 struct wmi_block *wblock;
666
667 wblock = dev_get_drvdata(dev);
a80e1053
PB
668 if (!wblock) {
669 strcat(buf, "\n");
670 return strlen(buf);
671 }
1caab3c1
MG
672
673 wmi_gtoa(wblock->gblock.guid, guid_string);
674
675 return sprintf(buf, "wmi:%s\n", guid_string);
676}
e80b89a5 677static DEVICE_ATTR_RO(modalias);
614ef432 678
e80b89a5
GKH
679static struct attribute *wmi_attrs[] = {
680 &dev_attr_modalias.attr,
681 NULL,
614ef432 682};
e80b89a5 683ATTRIBUTE_GROUPS(wmi);
1caab3c1
MG
684
685static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
686{
687 char guid_string[37];
688
689 struct wmi_block *wblock;
690
691 if (add_uevent_var(env, "MODALIAS="))
692 return -ENOMEM;
693
694 wblock = dev_get_drvdata(dev);
695 if (!wblock)
696 return -ENOMEM;
697
698 wmi_gtoa(wblock->gblock.guid, guid_string);
699
700 strcpy(&env->buf[env->buflen - 1], "wmi:");
701 memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
702 env->buflen += 40;
703
704 return 0;
705}
706
707static void wmi_dev_free(struct device *dev)
708{
c64eefd4
DT
709 struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
710
711 kfree(wmi_block);
1caab3c1
MG
712}
713
714static struct class wmi_class = {
715 .name = "wmi",
716 .dev_release = wmi_dev_free,
717 .dev_uevent = wmi_dev_uevent,
e80b89a5 718 .dev_groups = wmi_groups,
1caab3c1
MG
719};
720
58f6425e
CK
721static int wmi_create_device(const struct guid_block *gblock,
722 struct wmi_block *wblock, acpi_handle handle)
1caab3c1 723{
c64eefd4 724 char guid_string[37];
1caab3c1 725
c64eefd4 726 wblock->dev.class = &wmi_class;
1caab3c1 727
c64eefd4 728 wmi_gtoa(gblock->guid, guid_string);
02aa2a37 729 dev_set_name(&wblock->dev, "%s", guid_string);
1caab3c1 730
c64eefd4 731 dev_set_drvdata(&wblock->dev, wblock);
1caab3c1 732
58f6425e 733 return device_register(&wblock->dev);
1caab3c1
MG
734}
735
c64eefd4 736static void wmi_free_devices(void)
1caab3c1 737{
c64eefd4 738 struct wmi_block *wblock, *next;
1caab3c1
MG
739
740 /* Delete devices for all the GUIDs */
023b9565
DT
741 list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
742 list_del(&wblock->list);
58f6425e
CK
743 if (wblock->dev.class)
744 device_unregister(&wblock->dev);
023b9565
DT
745 else
746 kfree(wblock);
747 }
1caab3c1
MG
748}
749
d1f9e497
CC
750static bool guid_already_parsed(const char *guid_string)
751{
d1f9e497 752 struct wmi_block *wblock;
d1f9e497 753
c64eefd4 754 list_for_each_entry(wblock, &wmi_block_list, list)
8b14d7b2 755 if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
d1f9e497 756 return true;
d1f9e497 757
c64eefd4 758 return false;
2d5ab555
DT
759}
760
bff431e4
CC
761/*
762 * Parse the _WDG method for the GUID data blocks
763 */
0a018a68 764static int parse_wdg(acpi_handle handle)
bff431e4
CC
765{
766 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
767 union acpi_object *obj;
37830662 768 const struct guid_block *gblock;
bff431e4
CC
769 struct wmi_block *wblock;
770 acpi_status status;
c64eefd4 771 int retval;
bff431e4
CC
772 u32 i, total;
773
774 status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
bff431e4 775 if (ACPI_FAILURE(status))
c64eefd4 776 return -ENXIO;
bff431e4
CC
777
778 obj = (union acpi_object *) out.pointer;
3d2c63eb 779 if (!obj)
c64eefd4 780 return -ENXIO;
bff431e4 781
64ed0ab8 782 if (obj->type != ACPI_TYPE_BUFFER) {
c64eefd4 783 retval = -ENXIO;
64ed0ab8
DT
784 goto out_free_pointer;
785 }
bff431e4 786
37830662 787 gblock = (const struct guid_block *)obj->buffer.pointer;
bff431e4
CC
788 total = obj->buffer.length / sizeof(struct guid_block);
789
bff431e4 790 for (i = 0; i < total; i++) {
58f6425e
CK
791 if (debug_dump_wdg)
792 wmi_dump_wdg(&gblock[i]);
793
794 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
795 if (!wblock)
0a018a68 796 return -ENOMEM;
58f6425e
CK
797
798 wblock->handle = handle;
799 wblock->gblock = gblock[i];
800
d1f9e497
CC
801 /*
802 Some WMI devices, like those for nVidia hooks, have a
803 duplicate GUID. It's not clear what we should do in this
58f6425e
CK
804 case yet, so for now, we'll just ignore the duplicate
805 for device creation.
d1f9e497 806 */
58f6425e
CK
807 if (!guid_already_parsed(gblock[i].guid)) {
808 retval = wmi_create_device(&gblock[i], wblock, handle);
809 if (retval) {
810 wmi_free_devices();
e1e0dacb 811 goto out_free_pointer;
58f6425e 812 }
d1f9e497 813 }
c64eefd4 814
58f6425e 815 list_add_tail(&wblock->list, &wmi_block_list);
bff431e4 816
fc3155b2
TR
817 if (debug_event) {
818 wblock->handler = wmi_notify_debug;
2d5ab555 819 wmi_method_enable(wblock, 1);
fc3155b2 820 }
bff431e4
CC
821 }
822
c64eefd4
DT
823 retval = 0;
824
a5167c5b
AL
825out_free_pointer:
826 kfree(out.pointer);
bff431e4 827
c64eefd4 828 return retval;
bff431e4
CC
829}
830
831/*
832 * WMI can have EmbeddedControl access regions. In which case, we just want to
833 * hand these off to the EC driver.
834 */
835static acpi_status
836acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
439913ff 837 u32 bits, u64 *value,
bff431e4
CC
838 void *handler_context, void *region_context)
839{
840 int result = 0, i = 0;
841 u8 temp = 0;
842
843 if ((address > 0xFF) || !value)
844 return AE_BAD_PARAMETER;
845
846 if (function != ACPI_READ && function != ACPI_WRITE)
847 return AE_BAD_PARAMETER;
848
849 if (bits != 8)
850 return AE_BAD_PARAMETER;
851
852 if (function == ACPI_READ) {
853 result = ec_read(address, &temp);
439913ff 854 (*value) |= ((u64)temp) << i;
bff431e4
CC
855 } else {
856 temp = 0xff & ((*value) >> i);
857 result = ec_write(address, temp);
858 }
859
860 switch (result) {
861 case -EINVAL:
862 return AE_BAD_PARAMETER;
863 break;
864 case -ENODEV:
865 return AE_NOT_FOUND;
866 break;
867 case -ETIME:
868 return AE_TIME;
869 break;
870 default:
871 return AE_OK;
872 }
873}
874
f61bb939 875static void acpi_wmi_notify(struct acpi_device *device, u32 event)
bff431e4
CC
876{
877 struct guid_block *block;
878 struct wmi_block *wblock;
879 struct list_head *p;
7715348c 880 char guid_string[37];
bff431e4 881
762e1a2f 882 list_for_each(p, &wmi_block_list) {
bff431e4
CC
883 wblock = list_entry(p, struct wmi_block, list);
884 block = &wblock->gblock;
885
886 if ((block->flags & ACPI_WMI_EVENT) &&
887 (block->notify_id == event)) {
888 if (wblock->handler)
889 wblock->handler(event, wblock->handler_data);
7715348c
TR
890 if (debug_event) {
891 wmi_gtoa(wblock->gblock.guid, guid_string);
8e07514d 892 pr_info("DEBUG Event GUID: %s\n", guid_string);
7715348c 893 }
bff431e4
CC
894
895 acpi_bus_generate_netlink_event(
0794469d 896 device->pnp.device_class, dev_name(&device->dev),
bff431e4
CC
897 event, 0);
898 break;
899 }
900 }
901}
902
51fac838 903static int acpi_wmi_remove(struct acpi_device *device)
bff431e4 904{
bff431e4
CC
905 acpi_remove_address_space_handler(device->handle,
906 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
c64eefd4 907 wmi_free_devices();
bff431e4
CC
908
909 return 0;
910}
911
925b1089 912static int acpi_wmi_add(struct acpi_device *device)
bff431e4
CC
913{
914 acpi_status status;
c64eefd4 915 int error;
bff431e4 916
bff431e4
CC
917 status = acpi_install_address_space_handler(device->handle,
918 ACPI_ADR_SPACE_EC,
919 &acpi_wmi_ec_space_handler,
920 NULL, NULL);
5212cd67 921 if (ACPI_FAILURE(status)) {
8e07514d 922 pr_err("Error installing EC region handler\n");
bff431e4 923 return -ENODEV;
5212cd67 924 }
bff431e4 925
c64eefd4
DT
926 error = parse_wdg(device->handle);
927 if (error) {
5212cd67
DT
928 acpi_remove_address_space_handler(device->handle,
929 ACPI_ADR_SPACE_EC,
930 &acpi_wmi_ec_space_handler);
8e07514d 931 pr_err("Failed to parse WDG method\n");
c64eefd4 932 return error;
bff431e4
CC
933 }
934
c64eefd4 935 return 0;
bff431e4
CC
936}
937
938static int __init acpi_wmi_init(void)
939{
c64eefd4 940 int error;
bff431e4
CC
941
942 if (acpi_disabled)
943 return -ENODEV;
944
c64eefd4
DT
945 error = class_register(&wmi_class);
946 if (error)
947 return error;
1caab3c1 948
c64eefd4
DT
949 error = acpi_bus_register_driver(&acpi_wmi_driver);
950 if (error) {
951 pr_err("Error loading mapper\n");
952 class_unregister(&wmi_class);
953 return error;
bff431e4
CC
954 }
955
8e07514d 956 pr_info("Mapper loaded\n");
8e07514d 957 return 0;
bff431e4
CC
958}
959
960static void __exit acpi_wmi_exit(void)
961{
bff431e4 962 acpi_bus_unregister_driver(&acpi_wmi_driver);
c64eefd4 963 class_unregister(&wmi_class);
bff431e4 964
8e07514d 965 pr_info("Mapper unloaded\n");
bff431e4
CC
966}
967
968subsys_initcall(acpi_wmi_init);
969module_exit(acpi_wmi_exit);