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