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