xref: /openbmc/linux/drivers/platform/x86/wmi.c (revision 7dd65feb)
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>
33 #include <linux/device.h>
34 #include <linux/list.h>
35 #include <linux/acpi.h>
36 #include <acpi/acpi_bus.h>
37 #include <acpi/acpi_drivers.h>
38 
39 ACPI_MODULE_NAME("wmi");
40 MODULE_AUTHOR("Carlos Corbacho");
41 MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
42 MODULE_LICENSE("GPL");
43 
44 #define ACPI_WMI_CLASS "wmi"
45 
46 #define PREFIX "ACPI: WMI: "
47 
48 static DEFINE_MUTEX(wmi_data_lock);
49 
50 struct 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 
63 struct 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;
69 	struct device *dev;
70 };
71 
72 static struct wmi_block wmi_blocks;
73 
74 /*
75  * If the GUID data block is marked as expensive, we must enable and
76  * explicitily disable data collection.
77  */
78 #define ACPI_WMI_EXPENSIVE   0x1
79 #define ACPI_WMI_METHOD      0x2	/* GUID is a method */
80 #define ACPI_WMI_STRING      0x4	/* GUID takes & returns a string */
81 #define ACPI_WMI_EVENT       0x8	/* GUID is an event */
82 
83 static int acpi_wmi_remove(struct acpi_device *device, int type);
84 static int acpi_wmi_add(struct acpi_device *device);
85 static void acpi_wmi_notify(struct acpi_device *device, u32 event);
86 
87 static const struct acpi_device_id wmi_device_ids[] = {
88 	{"PNP0C14", 0},
89 	{"pnp0c14", 0},
90 	{"", 0},
91 };
92 MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
93 
94 static struct acpi_driver acpi_wmi_driver = {
95 	.name = "wmi",
96 	.class = ACPI_WMI_CLASS,
97 	.ids = wmi_device_ids,
98 	.ops = {
99 		.add = acpi_wmi_add,
100 		.remove = acpi_wmi_remove,
101 		.notify = acpi_wmi_notify,
102 		},
103 };
104 
105 /*
106  * GUID parsing functions
107  */
108 
109 /**
110  * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
111  * @src:  Pointer to at least 2 characters to convert.
112  *
113  * Convert a two character ASCII hex string to a number.
114  *
115  * Return:  0-255  Success, the byte was parsed correctly
116  *          -1     Error, an invalid character was supplied
117  */
118 static int wmi_parse_hexbyte(const u8 *src)
119 {
120 	unsigned int x; /* For correct wrapping */
121 	int h;
122 
123 	/* high part */
124 	x = src[0];
125 	if (x - '0' <= '9' - '0') {
126 		h = x - '0';
127 	} else if (x - 'a' <= 'f' - 'a') {
128 		h = x - 'a' + 10;
129 	} else if (x - 'A' <= 'F' - 'A') {
130 		h = x - 'A' + 10;
131 	} else {
132 		return -1;
133 	}
134 	h <<= 4;
135 
136 	/* low part */
137 	x = src[1];
138 	if (x - '0' <= '9' - '0')
139 		return h | (x - '0');
140 	if (x - 'a' <= 'f' - 'a')
141 		return h | (x - 'a' + 10);
142 	if (x - 'A' <= 'F' - 'A')
143 		return h | (x - 'A' + 10);
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  */
154 static 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  */
180 static 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 
200 /*
201  * Convert a raw GUID to the ACII string representation
202  */
203 static 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 
224 	out = '\0';
225 	return 0;
226 }
227 
228 static 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 
238 	list_for_each(p, &wmi_blocks.list) {
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 
251 static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
252 {
253 	struct guid_block *block = NULL;
254 	char method[5];
255 	struct acpi_object_list input;
256 	union acpi_object params[1];
257 	acpi_status status;
258 	acpi_handle handle;
259 
260 	block = &wblock->gblock;
261 	handle = wblock->handle;
262 
263 	if (!block)
264 		return AE_NOT_EXIST;
265 
266 	input.count = 1;
267 	input.pointer = params;
268 	params[0].type = ACPI_TYPE_INTEGER;
269 	params[0].integer.value = enable;
270 
271 	snprintf(method, 5, "WE%02X", block->notify_id);
272 	status = acpi_evaluate_object(handle, method, &input, NULL);
273 
274 	if (status != AE_OK && status != AE_NOT_FOUND)
275 		return status;
276 	else
277 		return AE_OK;
278 }
279 
280 /*
281  * Exported WMI functions
282  */
283 /**
284  * wmi_evaluate_method - Evaluate a WMI method
285  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
286  * @instance: Instance index
287  * @method_id: Method ID to call
288  * &in: Buffer containing input for the method call
289  * &out: Empty buffer to return the method results
290  *
291  * Call an ACPI-WMI method
292  */
293 acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
294 u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
295 {
296 	struct guid_block *block = NULL;
297 	struct wmi_block *wblock = NULL;
298 	acpi_handle handle;
299 	acpi_status status;
300 	struct acpi_object_list input;
301 	union acpi_object params[3];
302 	char method[5] = "WM";
303 
304 	if (!find_guid(guid_string, &wblock))
305 		return AE_ERROR;
306 
307 	block = &wblock->gblock;
308 	handle = wblock->handle;
309 
310 	if (!(block->flags & ACPI_WMI_METHOD))
311 		return AE_BAD_DATA;
312 
313 	if (block->instance_count < instance)
314 		return AE_BAD_PARAMETER;
315 
316 	input.count = 2;
317 	input.pointer = params;
318 	params[0].type = ACPI_TYPE_INTEGER;
319 	params[0].integer.value = instance;
320 	params[1].type = ACPI_TYPE_INTEGER;
321 	params[1].integer.value = method_id;
322 
323 	if (in) {
324 		input.count = 3;
325 
326 		if (block->flags & ACPI_WMI_STRING) {
327 			params[2].type = ACPI_TYPE_STRING;
328 		} else {
329 			params[2].type = ACPI_TYPE_BUFFER;
330 		}
331 		params[2].buffer.length = in->length;
332 		params[2].buffer.pointer = in->pointer;
333 	}
334 
335 	strncat(method, block->object_id, 2);
336 
337 	status = acpi_evaluate_object(handle, method, &input, out);
338 
339 	return status;
340 }
341 EXPORT_SYMBOL_GPL(wmi_evaluate_method);
342 
343 /**
344  * wmi_query_block - Return contents of a WMI block
345  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
346  * @instance: Instance index
347  * &out: Empty buffer to return the contents of the data block to
348  *
349  * Return the contents of an ACPI-WMI data block to a buffer
350  */
351 acpi_status wmi_query_block(const char *guid_string, u8 instance,
352 struct acpi_buffer *out)
353 {
354 	struct guid_block *block = NULL;
355 	struct wmi_block *wblock = NULL;
356 	acpi_handle handle, wc_handle;
357 	acpi_status status, wc_status = AE_ERROR;
358 	struct acpi_object_list input, wc_input;
359 	union acpi_object wc_params[1], wq_params[1];
360 	char method[5];
361 	char wc_method[5] = "WC";
362 
363 	if (!guid_string || !out)
364 		return AE_BAD_PARAMETER;
365 
366 	if (!find_guid(guid_string, &wblock))
367 		return AE_ERROR;
368 
369 	block = &wblock->gblock;
370 	handle = wblock->handle;
371 
372 	if (block->instance_count < instance)
373 		return AE_BAD_PARAMETER;
374 
375 	/* Check GUID is a data block */
376 	if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
377 		return AE_ERROR;
378 
379 	input.count = 1;
380 	input.pointer = wq_params;
381 	wq_params[0].type = ACPI_TYPE_INTEGER;
382 	wq_params[0].integer.value = instance;
383 
384 	/*
385 	 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
386 	 * enable collection.
387 	 */
388 	if (block->flags & ACPI_WMI_EXPENSIVE) {
389 		wc_input.count = 1;
390 		wc_input.pointer = wc_params;
391 		wc_params[0].type = ACPI_TYPE_INTEGER;
392 		wc_params[0].integer.value = 1;
393 
394 		strncat(wc_method, block->object_id, 2);
395 
396 		/*
397 		 * Some GUIDs break the specification by declaring themselves
398 		 * expensive, but have no corresponding WCxx method. So we
399 		 * should not fail if this happens.
400 		 */
401 		wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
402 		if (ACPI_SUCCESS(wc_status))
403 			wc_status = acpi_evaluate_object(handle, wc_method,
404 				&wc_input, NULL);
405 	}
406 
407 	strcpy(method, "WQ");
408 	strncat(method, block->object_id, 2);
409 
410 	status = acpi_evaluate_object(handle, method, &input, out);
411 
412 	/*
413 	 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
414 	 * the WQxx method failed - we should disable collection anyway.
415 	 */
416 	if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
417 		wc_params[0].integer.value = 0;
418 		status = acpi_evaluate_object(handle,
419 		wc_method, &wc_input, NULL);
420 	}
421 
422 	return status;
423 }
424 EXPORT_SYMBOL_GPL(wmi_query_block);
425 
426 /**
427  * wmi_set_block - Write to a WMI block
428  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
429  * @instance: Instance index
430  * &in: Buffer containing new values for the data block
431  *
432  * Write the contents of the input buffer to an ACPI-WMI data block
433  */
434 acpi_status wmi_set_block(const char *guid_string, u8 instance,
435 const struct acpi_buffer *in)
436 {
437 	struct guid_block *block = NULL;
438 	struct wmi_block *wblock = NULL;
439 	acpi_handle handle;
440 	struct acpi_object_list input;
441 	union acpi_object params[2];
442 	char method[5] = "WS";
443 
444 	if (!guid_string || !in)
445 		return AE_BAD_DATA;
446 
447 	if (!find_guid(guid_string, &wblock))
448 		return AE_ERROR;
449 
450 	block = &wblock->gblock;
451 	handle = wblock->handle;
452 
453 	if (block->instance_count < instance)
454 		return AE_BAD_PARAMETER;
455 
456 	/* Check GUID is a data block */
457 	if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
458 		return AE_ERROR;
459 
460 	input.count = 2;
461 	input.pointer = params;
462 	params[0].type = ACPI_TYPE_INTEGER;
463 	params[0].integer.value = instance;
464 
465 	if (block->flags & ACPI_WMI_STRING) {
466 		params[1].type = ACPI_TYPE_STRING;
467 	} else {
468 		params[1].type = ACPI_TYPE_BUFFER;
469 	}
470 	params[1].buffer.length = in->length;
471 	params[1].buffer.pointer = in->pointer;
472 
473 	strncat(method, block->object_id, 2);
474 
475 	return acpi_evaluate_object(handle, method, &input, NULL);
476 }
477 EXPORT_SYMBOL_GPL(wmi_set_block);
478 
479 /**
480  * wmi_install_notify_handler - Register handler for WMI events
481  * @handler: Function to handle notifications
482  * @data: Data to be returned to handler when event is fired
483  *
484  * Register a handler for events sent to the ACPI-WMI mapper device.
485  */
486 acpi_status wmi_install_notify_handler(const char *guid,
487 wmi_notify_handler handler, void *data)
488 {
489 	struct wmi_block *block;
490 	acpi_status status;
491 
492 	if (!guid || !handler)
493 		return AE_BAD_PARAMETER;
494 
495 	if (!find_guid(guid, &block))
496 		return AE_NOT_EXIST;
497 
498 	if (block->handler)
499 		return AE_ALREADY_ACQUIRED;
500 
501 	block->handler = handler;
502 	block->handler_data = data;
503 
504 	status = wmi_method_enable(block, 1);
505 
506 	return status;
507 }
508 EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
509 
510 /**
511  * wmi_uninstall_notify_handler - Unregister handler for WMI events
512  *
513  * Unregister handler for events sent to the ACPI-WMI mapper device.
514  */
515 acpi_status wmi_remove_notify_handler(const char *guid)
516 {
517 	struct wmi_block *block;
518 	acpi_status status;
519 
520 	if (!guid)
521 		return AE_BAD_PARAMETER;
522 
523 	if (!find_guid(guid, &block))
524 		return AE_NOT_EXIST;
525 
526 	if (!block->handler)
527 		return AE_NULL_ENTRY;
528 
529 	status = wmi_method_enable(block, 0);
530 
531 	block->handler = NULL;
532 	block->handler_data = NULL;
533 
534 	return status;
535 }
536 EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
537 
538 /**
539  * wmi_get_event_data - Get WMI data associated with an event
540  *
541  * @event: Event to find
542  * @out: Buffer to hold event data. out->pointer should be freed with kfree()
543  *
544  * Returns extra data associated with an event in WMI.
545  */
546 acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
547 {
548 	struct acpi_object_list input;
549 	union acpi_object params[1];
550 	struct guid_block *gblock;
551 	struct wmi_block *wblock;
552 	struct list_head *p;
553 
554 	input.count = 1;
555 	input.pointer = params;
556 	params[0].type = ACPI_TYPE_INTEGER;
557 	params[0].integer.value = event;
558 
559 	list_for_each(p, &wmi_blocks.list) {
560 		wblock = list_entry(p, struct wmi_block, list);
561 		gblock = &wblock->gblock;
562 
563 		if ((gblock->flags & ACPI_WMI_EVENT) &&
564 			(gblock->notify_id == event))
565 			return acpi_evaluate_object(wblock->handle, "_WED",
566 				&input, out);
567 	}
568 
569 	return AE_NOT_FOUND;
570 }
571 EXPORT_SYMBOL_GPL(wmi_get_event_data);
572 
573 /**
574  * wmi_has_guid - Check if a GUID is available
575  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
576  *
577  * Check if a given GUID is defined by _WDG
578  */
579 bool wmi_has_guid(const char *guid_string)
580 {
581 	return find_guid(guid_string, NULL);
582 }
583 EXPORT_SYMBOL_GPL(wmi_has_guid);
584 
585 /*
586  * sysfs interface
587  */
588 static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
589 			     char *buf)
590 {
591 	char guid_string[37];
592 	struct wmi_block *wblock;
593 
594 	wblock = dev_get_drvdata(dev);
595 	if (!wblock)
596 		return -ENOMEM;
597 
598 	wmi_gtoa(wblock->gblock.guid, guid_string);
599 
600 	return sprintf(buf, "wmi:%s\n", guid_string);
601 }
602 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
603 
604 static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
605 {
606 	char guid_string[37];
607 
608 	struct wmi_block *wblock;
609 
610 	if (add_uevent_var(env, "MODALIAS="))
611 		return -ENOMEM;
612 
613 	wblock = dev_get_drvdata(dev);
614 	if (!wblock)
615 		return -ENOMEM;
616 
617 	wmi_gtoa(wblock->gblock.guid, guid_string);
618 
619 	strcpy(&env->buf[env->buflen - 1], "wmi:");
620 	memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
621 	env->buflen += 40;
622 
623 	return 0;
624 }
625 
626 static void wmi_dev_free(struct device *dev)
627 {
628 	kfree(dev);
629 }
630 
631 static struct class wmi_class = {
632 	.name = "wmi",
633 	.dev_release = wmi_dev_free,
634 	.dev_uevent = wmi_dev_uevent,
635 };
636 
637 static int wmi_create_devs(void)
638 {
639 	int result;
640 	char guid_string[37];
641 	struct guid_block *gblock;
642 	struct wmi_block *wblock;
643 	struct list_head *p;
644 	struct device *guid_dev;
645 
646 	/* Create devices for all the GUIDs */
647 	list_for_each(p, &wmi_blocks.list) {
648 		wblock = list_entry(p, struct wmi_block, list);
649 
650 		guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
651 		if (!guid_dev)
652 			return -ENOMEM;
653 
654 		wblock->dev = guid_dev;
655 
656 		guid_dev->class = &wmi_class;
657 		dev_set_drvdata(guid_dev, wblock);
658 
659 		gblock = &wblock->gblock;
660 
661 		wmi_gtoa(gblock->guid, guid_string);
662 		dev_set_name(guid_dev, guid_string);
663 
664 		result = device_register(guid_dev);
665 		if (result)
666 			return result;
667 
668 		result = device_create_file(guid_dev, &dev_attr_modalias);
669 		if (result)
670 			return result;
671 	}
672 
673 	return 0;
674 }
675 
676 static void wmi_remove_devs(void)
677 {
678 	struct guid_block *gblock;
679 	struct wmi_block *wblock;
680 	struct list_head *p;
681 	struct device *guid_dev;
682 
683 	/* Delete devices for all the GUIDs */
684 	list_for_each(p, &wmi_blocks.list) {
685 		wblock = list_entry(p, struct wmi_block, list);
686 
687 		guid_dev = wblock->dev;
688 		gblock = &wblock->gblock;
689 
690 		device_remove_file(guid_dev, &dev_attr_modalias);
691 
692 		device_unregister(guid_dev);
693 	}
694 }
695 
696 static void wmi_class_exit(void)
697 {
698 	wmi_remove_devs();
699 	class_unregister(&wmi_class);
700 }
701 
702 static int wmi_class_init(void)
703 {
704 	int ret;
705 
706 	ret = class_register(&wmi_class);
707 	if (ret)
708 		return ret;
709 
710 	ret = wmi_create_devs();
711 	if (ret)
712 		wmi_class_exit();
713 
714 	return ret;
715 }
716 
717 static bool guid_already_parsed(const char *guid_string)
718 {
719 	struct guid_block *gblock;
720 	struct wmi_block *wblock;
721 	struct list_head *p;
722 
723 	list_for_each(p, &wmi_blocks.list) {
724 		wblock = list_entry(p, struct wmi_block, list);
725 		gblock = &wblock->gblock;
726 
727 		if (strncmp(gblock->guid, guid_string, 16) == 0)
728 			return true;
729 	}
730 	return false;
731 }
732 
733 /*
734  * Parse the _WDG method for the GUID data blocks
735  */
736 static __init acpi_status parse_wdg(acpi_handle handle)
737 {
738 	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
739 	union acpi_object *obj;
740 	struct guid_block *gblock;
741 	struct wmi_block *wblock;
742 	char guid_string[37];
743 	acpi_status status;
744 	u32 i, total;
745 
746 	status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
747 
748 	if (ACPI_FAILURE(status))
749 		return status;
750 
751 	obj = (union acpi_object *) out.pointer;
752 
753 	if (obj->type != ACPI_TYPE_BUFFER)
754 		return AE_ERROR;
755 
756 	total = obj->buffer.length / sizeof(struct guid_block);
757 
758 	gblock = kzalloc(obj->buffer.length, GFP_KERNEL);
759 	if (!gblock)
760 		return AE_NO_MEMORY;
761 
762 	memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
763 
764 	for (i = 0; i < total; i++) {
765 		/*
766 		  Some WMI devices, like those for nVidia hooks, have a
767 		  duplicate GUID. It's not clear what we should do in this
768 		  case yet, so for now, we'll just ignore the duplicate.
769 		  Anyone who wants to add support for that device can come
770 		  up with a better workaround for the mess then.
771 		*/
772 		if (guid_already_parsed(gblock[i].guid) == true) {
773 			wmi_gtoa(gblock[i].guid, guid_string);
774 			printk(KERN_INFO PREFIX "Skipping duplicate GUID %s\n",
775 				guid_string);
776 			continue;
777 		}
778 		wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
779 		if (!wblock)
780 			return AE_NO_MEMORY;
781 
782 		wblock->gblock = gblock[i];
783 		wblock->handle = handle;
784 		list_add_tail(&wblock->list, &wmi_blocks.list);
785 	}
786 
787 	kfree(out.pointer);
788 	kfree(gblock);
789 
790 	return status;
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  */
797 static acpi_status
798 acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
799 		      u32 bits, acpi_integer * value,
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);
816 		(*value) |= ((acpi_integer)temp) << i;
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 
837 static void acpi_wmi_notify(struct acpi_device *device, u32 event)
838 {
839 	struct guid_block *block;
840 	struct wmi_block *wblock;
841 	struct list_head *p;
842 
843 	list_for_each(p, &wmi_blocks.list) {
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);
851 
852 			acpi_bus_generate_netlink_event(
853 				device->pnp.device_class, dev_name(&device->dev),
854 				event, 0);
855 			break;
856 		}
857 	}
858 }
859 
860 static int acpi_wmi_remove(struct acpi_device *device, int type)
861 {
862 	acpi_remove_address_space_handler(device->handle,
863 				ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
864 
865 	return 0;
866 }
867 
868 static int __init acpi_wmi_add(struct acpi_device *device)
869 {
870 	acpi_status status;
871 	int result = 0;
872 
873 	status = acpi_install_address_space_handler(device->handle,
874 						    ACPI_ADR_SPACE_EC,
875 						    &acpi_wmi_ec_space_handler,
876 						    NULL, NULL);
877 	if (ACPI_FAILURE(status))
878 		return -ENODEV;
879 
880 	status = parse_wdg(device->handle);
881 	if (ACPI_FAILURE(status)) {
882 		printk(KERN_ERR PREFIX "Error installing EC region handler\n");
883 		return -ENODEV;
884 	}
885 
886 	return result;
887 }
888 
889 static int __init acpi_wmi_init(void)
890 {
891 	int result;
892 
893 	INIT_LIST_HEAD(&wmi_blocks.list);
894 
895 	if (acpi_disabled)
896 		return -ENODEV;
897 
898 	result = acpi_bus_register_driver(&acpi_wmi_driver);
899 
900 	if (result < 0) {
901 		printk(KERN_INFO PREFIX "Error loading mapper\n");
902 		return -ENODEV;
903 	}
904 
905 	result = wmi_class_init();
906 	if (result) {
907 		acpi_bus_unregister_driver(&acpi_wmi_driver);
908 		return result;
909 	}
910 
911 	printk(KERN_INFO PREFIX "Mapper loaded\n");
912 
913 	return result;
914 }
915 
916 static void __exit acpi_wmi_exit(void)
917 {
918 	struct list_head *p, *tmp;
919 	struct wmi_block *wblock;
920 
921 	wmi_class_exit();
922 
923 	acpi_bus_unregister_driver(&acpi_wmi_driver);
924 
925 	list_for_each_safe(p, tmp, &wmi_blocks.list) {
926 		wblock = list_entry(p, struct wmi_block, list);
927 
928 		list_del(p);
929 		kfree(wblock);
930 	}
931 
932 	printk(KERN_INFO PREFIX "Mapper unloaded\n");
933 }
934 
935 subsys_initcall(acpi_wmi_init);
936 module_exit(acpi_wmi_exit);
937