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