Merge tag 'pci-v3.10-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[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];
255 struct acpi_object_list input;
256 union acpi_object params[1];
257 acpi_status status;
258 acpi_handle handle;
259
260 block = &wblock->gblock;
261 handle = wblock->handle;
262
263 if (!block)
264 return AE_NOT_EXIST;
265
266 input.count = 1;
267 input.pointer = params;
268 params[0].type = ACPI_TYPE_INTEGER;
269 params[0].integer.value = enable;
270
271 snprintf(method, 5, "WE%02X", block->notify_id);
272 status = acpi_evaluate_object(handle, method, &input, NULL);
273
274 if (status != AE_OK && status != AE_NOT_FOUND)
275 return status;
276 else
277 return AE_OK;
278}
279
bff431e4
CC
280/*
281 * Exported WMI functions
282 */
283/**
284 * wmi_evaluate_method - Evaluate a WMI method
285 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
286 * @instance: Instance index
287 * @method_id: Method ID to call
288 * &in: Buffer containing input for the method call
289 * &out: Empty buffer to return the method results
290 *
291 * Call an ACPI-WMI method
292 */
293acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
294u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
295{
296 struct guid_block *block = NULL;
297 struct wmi_block *wblock = NULL;
298 acpi_handle handle;
299 acpi_status status;
300 struct acpi_object_list input;
301 union acpi_object params[3];
f3d83e24 302 char method[5] = "WM";
bff431e4
CC
303
304 if (!find_guid(guid_string, &wblock))
08237974 305 return AE_ERROR;
bff431e4
CC
306
307 block = &wblock->gblock;
308 handle = wblock->handle;
309
e6bafba5 310 if (!(block->flags & ACPI_WMI_METHOD))
bff431e4
CC
311 return AE_BAD_DATA;
312
313 if (block->instance_count < instance)
314 return AE_BAD_PARAMETER;
315
316 input.count = 2;
317 input.pointer = params;
318 params[0].type = ACPI_TYPE_INTEGER;
319 params[0].integer.value = instance;
320 params[1].type = ACPI_TYPE_INTEGER;
321 params[1].integer.value = method_id;
322
323 if (in) {
324 input.count = 3;
325
326 if (block->flags & ACPI_WMI_STRING) {
327 params[2].type = ACPI_TYPE_STRING;
328 } else {
329 params[2].type = ACPI_TYPE_BUFFER;
330 }
331 params[2].buffer.length = in->length;
332 params[2].buffer.pointer = in->pointer;
333 }
334
335 strncat(method, block->object_id, 2);
336
337 status = acpi_evaluate_object(handle, method, &input, out);
338
339 return status;
340}
341EXPORT_SYMBOL_GPL(wmi_evaluate_method);
342
343/**
344 * wmi_query_block - Return contents of a WMI block
345 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
346 * @instance: Instance index
347 * &out: Empty buffer to return the contents of the data block to
348 *
349 * Return the contents of an ACPI-WMI data block to a buffer
350 */
351acpi_status wmi_query_block(const char *guid_string, u8 instance,
352struct acpi_buffer *out)
353{
354 struct guid_block *block = NULL;
355 struct wmi_block *wblock = NULL;
a527f2d7 356 acpi_handle handle, wc_handle;
bff431e4
CC
357 acpi_status status, wc_status = AE_ERROR;
358 struct acpi_object_list input, wc_input;
359 union acpi_object wc_params[1], wq_params[1];
f3d83e24
CL
360 char method[5];
361 char wc_method[5] = "WC";
bff431e4
CC
362
363 if (!guid_string || !out)
364 return AE_BAD_PARAMETER;
365
366 if (!find_guid(guid_string, &wblock))
08237974 367 return AE_ERROR;
bff431e4
CC
368
369 block = &wblock->gblock;
370 handle = wblock->handle;
371
372 if (block->instance_count < instance)
373 return AE_BAD_PARAMETER;
374
375 /* Check GUID is a data block */
376 if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
08237974 377 return AE_ERROR;
bff431e4
CC
378
379 input.count = 1;
380 input.pointer = wq_params;
381 wq_params[0].type = ACPI_TYPE_INTEGER;
382 wq_params[0].integer.value = instance;
383
384 /*
385 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
386 * enable collection.
387 */
388 if (block->flags & ACPI_WMI_EXPENSIVE) {
389 wc_input.count = 1;
390 wc_input.pointer = wc_params;
391 wc_params[0].type = ACPI_TYPE_INTEGER;
392 wc_params[0].integer.value = 1;
393
394 strncat(wc_method, block->object_id, 2);
395
396 /*
397 * Some GUIDs break the specification by declaring themselves
398 * expensive, but have no corresponding WCxx method. So we
399 * should not fail if this happens.
400 */
a527f2d7
CC
401 wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
402 if (ACPI_SUCCESS(wc_status))
403 wc_status = acpi_evaluate_object(handle, wc_method,
404 &wc_input, NULL);
bff431e4
CC
405 }
406
407 strcpy(method, "WQ");
408 strncat(method, block->object_id, 2);
409
dab36ad8 410 status = acpi_evaluate_object(handle, method, &input, out);
bff431e4
CC
411
412 /*
413 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
414 * the WQxx method failed - we should disable collection anyway.
415 */
a527f2d7 416 if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
bff431e4
CC
417 wc_params[0].integer.value = 0;
418 status = acpi_evaluate_object(handle,
419 wc_method, &wc_input, NULL);
420 }
421
422 return status;
423}
424EXPORT_SYMBOL_GPL(wmi_query_block);
425
426/**
427 * wmi_set_block - Write to a WMI block
428 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
429 * @instance: Instance index
430 * &in: Buffer containing new values for the data block
431 *
432 * Write the contents of the input buffer to an ACPI-WMI data block
433 */
434acpi_status wmi_set_block(const char *guid_string, u8 instance,
435const struct acpi_buffer *in)
436{
437 struct guid_block *block = NULL;
438 struct wmi_block *wblock = NULL;
439 acpi_handle handle;
440 struct acpi_object_list input;
441 union acpi_object params[2];
f3d83e24 442 char method[5] = "WS";
bff431e4
CC
443
444 if (!guid_string || !in)
445 return AE_BAD_DATA;
446
447 if (!find_guid(guid_string, &wblock))
08237974 448 return AE_ERROR;
bff431e4
CC
449
450 block = &wblock->gblock;
451 handle = wblock->handle;
452
453 if (block->instance_count < instance)
454 return AE_BAD_PARAMETER;
455
456 /* Check GUID is a data block */
457 if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
08237974 458 return AE_ERROR;
bff431e4
CC
459
460 input.count = 2;
461 input.pointer = params;
462 params[0].type = ACPI_TYPE_INTEGER;
463 params[0].integer.value = instance;
464
465 if (block->flags & ACPI_WMI_STRING) {
466 params[1].type = ACPI_TYPE_STRING;
467 } else {
468 params[1].type = ACPI_TYPE_BUFFER;
469 }
470 params[1].buffer.length = in->length;
471 params[1].buffer.pointer = in->pointer;
472
473 strncat(method, block->object_id, 2);
474
475 return acpi_evaluate_object(handle, method, &input, NULL);
476}
477EXPORT_SYMBOL_GPL(wmi_set_block);
478
37830662 479static void wmi_dump_wdg(const struct guid_block *g)
a929aae0
TR
480{
481 char guid_string[37];
482
483 wmi_gtoa(g->guid, guid_string);
8e07514d
DT
484
485 pr_info("%s:\n", guid_string);
486 pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
487 pr_info("\tnotify_id: %02X\n", g->notify_id);
488 pr_info("\treserved: %02X\n", g->reserved);
489 pr_info("\tinstance_count: %d\n", g->instance_count);
dd8e908e 490 pr_info("\tflags: %#x", g->flags);
a929aae0 491 if (g->flags) {
a929aae0 492 if (g->flags & ACPI_WMI_EXPENSIVE)
dd8e908e 493 pr_cont(" ACPI_WMI_EXPENSIVE");
a929aae0 494 if (g->flags & ACPI_WMI_METHOD)
dd8e908e 495 pr_cont(" ACPI_WMI_METHOD");
a929aae0 496 if (g->flags & ACPI_WMI_STRING)
dd8e908e 497 pr_cont(" ACPI_WMI_STRING");
a929aae0 498 if (g->flags & ACPI_WMI_EVENT)
dd8e908e 499 pr_cont(" ACPI_WMI_EVENT");
a929aae0 500 }
8e07514d 501 pr_cont("\n");
a929aae0
TR
502
503}
504
fc3155b2
TR
505static void wmi_notify_debug(u32 value, void *context)
506{
507 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
508 union acpi_object *obj;
1492616a 509 acpi_status status;
fc3155b2 510
1492616a
AL
511 status = wmi_get_event_data(value, &response);
512 if (status != AE_OK) {
8e07514d 513 pr_info("bad event status 0x%x\n", status);
1492616a
AL
514 return;
515 }
fc3155b2
TR
516
517 obj = (union acpi_object *)response.pointer;
518
519 if (!obj)
520 return;
521
8e07514d 522 pr_info("DEBUG Event ");
fc3155b2
TR
523 switch(obj->type) {
524 case ACPI_TYPE_BUFFER:
8e07514d 525 pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
fc3155b2
TR
526 break;
527 case ACPI_TYPE_STRING:
8e07514d 528 pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
fc3155b2
TR
529 break;
530 case ACPI_TYPE_INTEGER:
8e07514d 531 pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
fc3155b2
TR
532 break;
533 case ACPI_TYPE_PACKAGE:
8e07514d 534 pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
fc3155b2
TR
535 break;
536 default:
8e07514d 537 pr_cont("object type 0x%X\n", obj->type);
fc3155b2 538 }
1492616a 539 kfree(obj);
fc3155b2
TR
540}
541
bff431e4
CC
542/**
543 * wmi_install_notify_handler - Register handler for WMI events
544 * @handler: Function to handle notifications
545 * @data: Data to be returned to handler when event is fired
546 *
547 * Register a handler for events sent to the ACPI-WMI mapper device.
548 */
549acpi_status wmi_install_notify_handler(const char *guid,
550wmi_notify_handler handler, void *data)
551{
552 struct wmi_block *block;
58f6425e
CK
553 acpi_status status = AE_NOT_EXIST;
554 char tmp[16], guid_input[16];
555 struct list_head *p;
bff431e4
CC
556
557 if (!guid || !handler)
558 return AE_BAD_PARAMETER;
559
58f6425e
CK
560 wmi_parse_guid(guid, tmp);
561 wmi_swap_bytes(tmp, guid_input);
bff431e4 562
58f6425e
CK
563 list_for_each(p, &wmi_block_list) {
564 acpi_status wmi_status;
565 block = list_entry(p, struct wmi_block, list);
566
567 if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
568 if (block->handler &&
569 block->handler != wmi_notify_debug)
570 return AE_ALREADY_ACQUIRED;
bff431e4 571
58f6425e
CK
572 block->handler = handler;
573 block->handler_data = data;
bff431e4 574
58f6425e
CK
575 wmi_status = wmi_method_enable(block, 1);
576 if ((wmi_status != AE_OK) ||
577 ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
578 status = wmi_status;
579 }
580 }
a66bfa7a
MG
581
582 return status;
bff431e4
CC
583}
584EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
585
586/**
587 * wmi_uninstall_notify_handler - Unregister handler for WMI events
588 *
589 * Unregister handler for events sent to the ACPI-WMI mapper device.
590 */
591acpi_status wmi_remove_notify_handler(const char *guid)
592{
593 struct wmi_block *block;
58f6425e
CK
594 acpi_status status = AE_NOT_EXIST;
595 char tmp[16], guid_input[16];
596 struct list_head *p;
bff431e4
CC
597
598 if (!guid)
599 return AE_BAD_PARAMETER;
600
58f6425e
CK
601 wmi_parse_guid(guid, tmp);
602 wmi_swap_bytes(tmp, guid_input);
bff431e4 603
58f6425e
CK
604 list_for_each(p, &wmi_block_list) {
605 acpi_status wmi_status;
606 block = list_entry(p, struct wmi_block, list);
607
608 if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
609 if (!block->handler ||
610 block->handler == wmi_notify_debug)
611 return AE_NULL_ENTRY;
612
613 if (debug_event) {
614 block->handler = wmi_notify_debug;
615 status = AE_OK;
616 } else {
617 wmi_status = wmi_method_enable(block, 0);
618 block->handler = NULL;
619 block->handler_data = NULL;
620 if ((wmi_status != AE_OK) ||
621 ((wmi_status == AE_OK) &&
622 (status == AE_NOT_EXIST)))
623 status = wmi_status;
624 }
625 }
fc3155b2 626 }
58f6425e 627
a66bfa7a 628 return status;
bff431e4
CC
629}
630EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
631
632/**
633 * wmi_get_event_data - Get WMI data associated with an event
634 *
3e9b988e
AA
635 * @event: Event to find
636 * @out: Buffer to hold event data. out->pointer should be freed with kfree()
bff431e4
CC
637 *
638 * Returns extra data associated with an event in WMI.
639 */
640acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
641{
642 struct acpi_object_list input;
643 union acpi_object params[1];
644 struct guid_block *gblock;
645 struct wmi_block *wblock;
646 struct list_head *p;
647
648 input.count = 1;
649 input.pointer = params;
650 params[0].type = ACPI_TYPE_INTEGER;
651 params[0].integer.value = event;
652
762e1a2f 653 list_for_each(p, &wmi_block_list) {
bff431e4
CC
654 wblock = list_entry(p, struct wmi_block, list);
655 gblock = &wblock->gblock;
656
657 if ((gblock->flags & ACPI_WMI_EVENT) &&
658 (gblock->notify_id == event))
659 return acpi_evaluate_object(wblock->handle, "_WED",
660 &input, out);
661 }
662
663 return AE_NOT_FOUND;
664}
665EXPORT_SYMBOL_GPL(wmi_get_event_data);
666
667/**
668 * wmi_has_guid - Check if a GUID is available
669 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
670 *
671 * Check if a given GUID is defined by _WDG
672 */
673bool wmi_has_guid(const char *guid_string)
674{
675 return find_guid(guid_string, NULL);
676}
677EXPORT_SYMBOL_GPL(wmi_has_guid);
678
1caab3c1
MG
679/*
680 * sysfs interface
681 */
614ef432 682static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
1caab3c1
MG
683 char *buf)
684{
685 char guid_string[37];
686 struct wmi_block *wblock;
687
688 wblock = dev_get_drvdata(dev);
689 if (!wblock)
690 return -ENOMEM;
691
692 wmi_gtoa(wblock->gblock.guid, guid_string);
693
694 return sprintf(buf, "wmi:%s\n", guid_string);
695}
614ef432
DT
696
697static struct device_attribute wmi_dev_attrs[] = {
698 __ATTR_RO(modalias),
699 __ATTR_NULL
700};
1caab3c1
MG
701
702static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
703{
704 char guid_string[37];
705
706 struct wmi_block *wblock;
707
708 if (add_uevent_var(env, "MODALIAS="))
709 return -ENOMEM;
710
711 wblock = dev_get_drvdata(dev);
712 if (!wblock)
713 return -ENOMEM;
714
715 wmi_gtoa(wblock->gblock.guid, guid_string);
716
717 strcpy(&env->buf[env->buflen - 1], "wmi:");
718 memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
719 env->buflen += 40;
720
721 return 0;
722}
723
724static void wmi_dev_free(struct device *dev)
725{
c64eefd4
DT
726 struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
727
728 kfree(wmi_block);
1caab3c1
MG
729}
730
731static struct class wmi_class = {
732 .name = "wmi",
733 .dev_release = wmi_dev_free,
734 .dev_uevent = wmi_dev_uevent,
614ef432 735 .dev_attrs = wmi_dev_attrs,
1caab3c1
MG
736};
737
58f6425e
CK
738static int wmi_create_device(const struct guid_block *gblock,
739 struct wmi_block *wblock, acpi_handle handle)
1caab3c1 740{
c64eefd4 741 char guid_string[37];
1caab3c1 742
c64eefd4 743 wblock->dev.class = &wmi_class;
1caab3c1 744
c64eefd4
DT
745 wmi_gtoa(gblock->guid, guid_string);
746 dev_set_name(&wblock->dev, guid_string);
1caab3c1 747
c64eefd4 748 dev_set_drvdata(&wblock->dev, wblock);
1caab3c1 749
58f6425e 750 return device_register(&wblock->dev);
1caab3c1
MG
751}
752
c64eefd4 753static void wmi_free_devices(void)
1caab3c1 754{
c64eefd4 755 struct wmi_block *wblock, *next;
1caab3c1
MG
756
757 /* Delete devices for all the GUIDs */
023b9565
DT
758 list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
759 list_del(&wblock->list);
58f6425e
CK
760 if (wblock->dev.class)
761 device_unregister(&wblock->dev);
023b9565
DT
762 else
763 kfree(wblock);
764 }
1caab3c1
MG
765}
766
d1f9e497
CC
767static bool guid_already_parsed(const char *guid_string)
768{
d1f9e497 769 struct wmi_block *wblock;
d1f9e497 770
c64eefd4 771 list_for_each_entry(wblock, &wmi_block_list, list)
8b14d7b2 772 if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
d1f9e497 773 return true;
d1f9e497 774
c64eefd4 775 return false;
2d5ab555
DT
776}
777
bff431e4
CC
778/*
779 * Parse the _WDG method for the GUID data blocks
780 */
925b1089 781static acpi_status parse_wdg(acpi_handle handle)
bff431e4
CC
782{
783 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
784 union acpi_object *obj;
37830662 785 const struct guid_block *gblock;
bff431e4
CC
786 struct wmi_block *wblock;
787 acpi_status status;
c64eefd4 788 int retval;
bff431e4
CC
789 u32 i, total;
790
791 status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
bff431e4 792 if (ACPI_FAILURE(status))
c64eefd4 793 return -ENXIO;
bff431e4
CC
794
795 obj = (union acpi_object *) out.pointer;
3d2c63eb 796 if (!obj)
c64eefd4 797 return -ENXIO;
bff431e4 798
64ed0ab8 799 if (obj->type != ACPI_TYPE_BUFFER) {
c64eefd4 800 retval = -ENXIO;
64ed0ab8
DT
801 goto out_free_pointer;
802 }
bff431e4 803
37830662 804 gblock = (const struct guid_block *)obj->buffer.pointer;
bff431e4
CC
805 total = obj->buffer.length / sizeof(struct guid_block);
806
bff431e4 807 for (i = 0; i < total; i++) {
58f6425e
CK
808 if (debug_dump_wdg)
809 wmi_dump_wdg(&gblock[i]);
810
811 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
812 if (!wblock)
813 return AE_NO_MEMORY;
814
815 wblock->handle = handle;
816 wblock->gblock = gblock[i];
817
d1f9e497
CC
818 /*
819 Some WMI devices, like those for nVidia hooks, have a
820 duplicate GUID. It's not clear what we should do in this
58f6425e
CK
821 case yet, so for now, we'll just ignore the duplicate
822 for device creation.
d1f9e497 823 */
58f6425e
CK
824 if (!guid_already_parsed(gblock[i].guid)) {
825 retval = wmi_create_device(&gblock[i], wblock, handle);
826 if (retval) {
827 wmi_free_devices();
e1e0dacb 828 goto out_free_pointer;
58f6425e 829 }
d1f9e497 830 }
c64eefd4 831
58f6425e 832 list_add_tail(&wblock->list, &wmi_block_list);
bff431e4 833
fc3155b2
TR
834 if (debug_event) {
835 wblock->handler = wmi_notify_debug;
2d5ab555 836 wmi_method_enable(wblock, 1);
fc3155b2 837 }
bff431e4
CC
838 }
839
c64eefd4
DT
840 retval = 0;
841
a5167c5b
AL
842out_free_pointer:
843 kfree(out.pointer);
bff431e4 844
c64eefd4 845 return retval;
bff431e4
CC
846}
847
848/*
849 * WMI can have EmbeddedControl access regions. In which case, we just want to
850 * hand these off to the EC driver.
851 */
852static acpi_status
853acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
439913ff 854 u32 bits, u64 *value,
bff431e4
CC
855 void *handler_context, void *region_context)
856{
857 int result = 0, i = 0;
858 u8 temp = 0;
859
860 if ((address > 0xFF) || !value)
861 return AE_BAD_PARAMETER;
862
863 if (function != ACPI_READ && function != ACPI_WRITE)
864 return AE_BAD_PARAMETER;
865
866 if (bits != 8)
867 return AE_BAD_PARAMETER;
868
869 if (function == ACPI_READ) {
870 result = ec_read(address, &temp);
439913ff 871 (*value) |= ((u64)temp) << i;
bff431e4
CC
872 } else {
873 temp = 0xff & ((*value) >> i);
874 result = ec_write(address, temp);
875 }
876
877 switch (result) {
878 case -EINVAL:
879 return AE_BAD_PARAMETER;
880 break;
881 case -ENODEV:
882 return AE_NOT_FOUND;
883 break;
884 case -ETIME:
885 return AE_TIME;
886 break;
887 default:
888 return AE_OK;
889 }
890}
891
f61bb939 892static void acpi_wmi_notify(struct acpi_device *device, u32 event)
bff431e4
CC
893{
894 struct guid_block *block;
895 struct wmi_block *wblock;
896 struct list_head *p;
7715348c 897 char guid_string[37];
bff431e4 898
762e1a2f 899 list_for_each(p, &wmi_block_list) {
bff431e4
CC
900 wblock = list_entry(p, struct wmi_block, list);
901 block = &wblock->gblock;
902
903 if ((block->flags & ACPI_WMI_EVENT) &&
904 (block->notify_id == event)) {
905 if (wblock->handler)
906 wblock->handler(event, wblock->handler_data);
7715348c
TR
907 if (debug_event) {
908 wmi_gtoa(wblock->gblock.guid, guid_string);
8e07514d 909 pr_info("DEBUG Event GUID: %s\n", guid_string);
7715348c 910 }
bff431e4
CC
911
912 acpi_bus_generate_netlink_event(
0794469d 913 device->pnp.device_class, dev_name(&device->dev),
bff431e4
CC
914 event, 0);
915 break;
916 }
917 }
918}
919
51fac838 920static int acpi_wmi_remove(struct acpi_device *device)
bff431e4 921{
bff431e4
CC
922 acpi_remove_address_space_handler(device->handle,
923 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
c64eefd4 924 wmi_free_devices();
bff431e4
CC
925
926 return 0;
927}
928
925b1089 929static int acpi_wmi_add(struct acpi_device *device)
bff431e4
CC
930{
931 acpi_status status;
c64eefd4 932 int error;
bff431e4 933
bff431e4
CC
934 status = acpi_install_address_space_handler(device->handle,
935 ACPI_ADR_SPACE_EC,
936 &acpi_wmi_ec_space_handler,
937 NULL, NULL);
5212cd67 938 if (ACPI_FAILURE(status)) {
8e07514d 939 pr_err("Error installing EC region handler\n");
bff431e4 940 return -ENODEV;
5212cd67 941 }
bff431e4 942
c64eefd4
DT
943 error = parse_wdg(device->handle);
944 if (error) {
5212cd67
DT
945 acpi_remove_address_space_handler(device->handle,
946 ACPI_ADR_SPACE_EC,
947 &acpi_wmi_ec_space_handler);
8e07514d 948 pr_err("Failed to parse WDG method\n");
c64eefd4 949 return error;
bff431e4
CC
950 }
951
c64eefd4 952 return 0;
bff431e4
CC
953}
954
955static int __init acpi_wmi_init(void)
956{
c64eefd4 957 int error;
bff431e4
CC
958
959 if (acpi_disabled)
960 return -ENODEV;
961
c64eefd4
DT
962 error = class_register(&wmi_class);
963 if (error)
964 return error;
1caab3c1 965
c64eefd4
DT
966 error = acpi_bus_register_driver(&acpi_wmi_driver);
967 if (error) {
968 pr_err("Error loading mapper\n");
969 class_unregister(&wmi_class);
970 return error;
bff431e4
CC
971 }
972
8e07514d 973 pr_info("Mapper loaded\n");
8e07514d 974 return 0;
bff431e4
CC
975}
976
977static void __exit acpi_wmi_exit(void)
978{
bff431e4 979 acpi_bus_unregister_driver(&acpi_wmi_driver);
c64eefd4 980 class_unregister(&wmi_class);
bff431e4 981
8e07514d 982 pr_info("Mapper unloaded\n");
bff431e4
CC
983}
984
985subsys_initcall(acpi_wmi_init);
986module_exit(acpi_wmi_exit);