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