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