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