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#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
31
32#include <linux/kernel.h>
33#include <linux/init.h>
34#include <linux/types.h>
35#include <linux/device.h>
36#include <linux/list.h>
37#include <linux/acpi.h>
38#include <linux/slab.h>
39#include <linux/module.h>
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
48static LIST_HEAD(wmi_block_list);
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;
69	struct device dev;
70};
71
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
82static bool debug_event;
83module_param(debug_event, bool, 0444);
84MODULE_PARM_DESC(debug_event,
85		 "Log WMI Events [0/1]");
86
87static bool debug_dump_wdg;
88module_param(debug_dump_wdg, bool, 0444);
89MODULE_PARM_DESC(debug_dump_wdg,
90		 "Dump available WMI interfaces [0/1]");
91
92static int acpi_wmi_remove(struct acpi_device *device);
93static int acpi_wmi_add(struct acpi_device *device);
94static void acpi_wmi_notify(struct acpi_device *device, u32 event);
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,
110		.notify = acpi_wmi_notify,
111	},
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{
129	int h;
130	int value;
131
132	/* high part */
133	h = value = hex_to_bin(src[0]);
134	if (value < 0)
135		return -1;
136
137	/* low part */
138	value = hex_to_bin(src[1]);
139	if (value >= 0)
140		return (h << 4) | value;
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
197/*
198 * Convert a raw GUID to the ACII string representation
199 */
200static int wmi_gtoa(const char *in, char *out)
201{
202	int i;
203
204	for (i = 3; i >= 0; i--)
205		out += sprintf(out, "%02X", in[i] & 0xFF);
206
207	out += sprintf(out, "-");
208	out += sprintf(out, "%02X", in[5] & 0xFF);
209	out += sprintf(out, "%02X", in[4] & 0xFF);
210	out += sprintf(out, "-");
211	out += sprintf(out, "%02X", in[7] & 0xFF);
212	out += sprintf(out, "%02X", in[6] & 0xFF);
213	out += sprintf(out, "-");
214	out += sprintf(out, "%02X", in[8] & 0xFF);
215	out += sprintf(out, "%02X", in[9] & 0xFF);
216	out += sprintf(out, "-");
217
218	for (i = 10; i <= 15; i++)
219		out += sprintf(out, "%02X", in[i] & 0xFF);
220
221	*out = '\0';
222	return 0;
223}
224
225static bool find_guid(const char *guid_string, struct wmi_block **out)
226{
227	char tmp[16], guid_input[16];
228	struct wmi_block *wblock;
229	struct guid_block *block;
230	struct list_head *p;
231
232	wmi_parse_guid(guid_string, tmp);
233	wmi_swap_bytes(tmp, guid_input);
234
235	list_for_each(p, &wmi_block_list) {
236		wblock = list_entry(p, struct wmi_block, list);
237		block = &wblock->gblock;
238
239		if (memcmp(block->guid, guid_input, 16) == 0) {
240			if (out)
241				*out = wblock;
242			return true;
243		}
244	}
245	return false;
246}
247
248static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
249{
250	struct guid_block *block = NULL;
251	char method[5];
252	acpi_status status;
253	acpi_handle handle;
254
255	block = &wblock->gblock;
256	handle = wblock->handle;
257
258	snprintf(method, 5, "WE%02X", block->notify_id);
259	status = acpi_execute_simple_method(handle, method, enable);
260
261	if (status != AE_OK && status != AE_NOT_FOUND)
262		return status;
263	else
264		return AE_OK;
265}
266
267/*
268 * Exported WMI functions
269 */
270/**
271 * wmi_evaluate_method - Evaluate a WMI method
272 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
273 * @instance: Instance index
274 * @method_id: Method ID to call
275 * &in: Buffer containing input for the method call
276 * &out: Empty buffer to return the method results
277 *
278 * Call an ACPI-WMI method
279 */
280acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
281u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
282{
283	struct guid_block *block = NULL;
284	struct wmi_block *wblock = NULL;
285	acpi_handle handle;
286	acpi_status status;
287	struct acpi_object_list input;
288	union acpi_object params[3];
289	char method[5] = "WM";
290
291	if (!find_guid(guid_string, &wblock))
292		return AE_ERROR;
293
294	block = &wblock->gblock;
295	handle = wblock->handle;
296
297	if (!(block->flags & ACPI_WMI_METHOD))
298		return AE_BAD_DATA;
299
300	if (block->instance_count < instance)
301		return AE_BAD_PARAMETER;
302
303	input.count = 2;
304	input.pointer = params;
305	params[0].type = ACPI_TYPE_INTEGER;
306	params[0].integer.value = instance;
307	params[1].type = ACPI_TYPE_INTEGER;
308	params[1].integer.value = method_id;
309
310	if (in) {
311		input.count = 3;
312
313		if (block->flags & ACPI_WMI_STRING) {
314			params[2].type = ACPI_TYPE_STRING;
315		} else {
316			params[2].type = ACPI_TYPE_BUFFER;
317		}
318		params[2].buffer.length = in->length;
319		params[2].buffer.pointer = in->pointer;
320	}
321
322	strncat(method, block->object_id, 2);
323
324	status = acpi_evaluate_object(handle, method, &input, out);
325
326	return status;
327}
328EXPORT_SYMBOL_GPL(wmi_evaluate_method);
329
330/**
331 * wmi_query_block - Return contents of a WMI block
332 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
333 * @instance: Instance index
334 * &out: Empty buffer to return the contents of the data block to
335 *
336 * Return the contents of an ACPI-WMI data block to a buffer
337 */
338acpi_status wmi_query_block(const char *guid_string, u8 instance,
339struct acpi_buffer *out)
340{
341	struct guid_block *block = NULL;
342	struct wmi_block *wblock = NULL;
343	acpi_handle handle;
344	acpi_status status, wc_status = AE_ERROR;
345	struct acpi_object_list input;
346	union acpi_object wq_params[1];
347	char method[5];
348	char wc_method[5] = "WC";
349
350	if (!guid_string || !out)
351		return AE_BAD_PARAMETER;
352
353	if (!find_guid(guid_string, &wblock))
354		return AE_ERROR;
355
356	block = &wblock->gblock;
357	handle = wblock->handle;
358
359	if (block->instance_count < instance)
360		return AE_BAD_PARAMETER;
361
362	/* Check GUID is a data block */
363	if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
364		return AE_ERROR;
365
366	input.count = 1;
367	input.pointer = wq_params;
368	wq_params[0].type = ACPI_TYPE_INTEGER;
369	wq_params[0].integer.value = instance;
370
371	/*
372	 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
373	 * enable collection.
374	 */
375	if (block->flags & ACPI_WMI_EXPENSIVE) {
376		strncat(wc_method, block->object_id, 2);
377
378		/*
379		 * Some GUIDs break the specification by declaring themselves
380		 * expensive, but have no corresponding WCxx method. So we
381		 * should not fail if this happens.
382		 */
383		if (acpi_has_method(handle, wc_method))
384			wc_status = acpi_execute_simple_method(handle,
385								wc_method, 1);
386	}
387
388	strcpy(method, "WQ");
389	strncat(method, block->object_id, 2);
390
391	status = acpi_evaluate_object(handle, method, &input, out);
392
393	/*
394	 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
395	 * the WQxx method failed - we should disable collection anyway.
396	 */
397	if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
398		status = acpi_execute_simple_method(handle, wc_method, 0);
399	}
400
401	return status;
402}
403EXPORT_SYMBOL_GPL(wmi_query_block);
404
405/**
406 * wmi_set_block - Write to a WMI block
407 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
408 * @instance: Instance index
409 * &in: Buffer containing new values for the data block
410 *
411 * Write the contents of the input buffer to an ACPI-WMI data block
412 */
413acpi_status wmi_set_block(const char *guid_string, u8 instance,
414const struct acpi_buffer *in)
415{
416	struct guid_block *block = NULL;
417	struct wmi_block *wblock = NULL;
418	acpi_handle handle;
419	struct acpi_object_list input;
420	union acpi_object params[2];
421	char method[5] = "WS";
422
423	if (!guid_string || !in)
424		return AE_BAD_DATA;
425
426	if (!find_guid(guid_string, &wblock))
427		return AE_ERROR;
428
429	block = &wblock->gblock;
430	handle = wblock->handle;
431
432	if (block->instance_count < instance)
433		return AE_BAD_PARAMETER;
434
435	/* Check GUID is a data block */
436	if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
437		return AE_ERROR;
438
439	input.count = 2;
440	input.pointer = params;
441	params[0].type = ACPI_TYPE_INTEGER;
442	params[0].integer.value = instance;
443
444	if (block->flags & ACPI_WMI_STRING) {
445		params[1].type = ACPI_TYPE_STRING;
446	} else {
447		params[1].type = ACPI_TYPE_BUFFER;
448	}
449	params[1].buffer.length = in->length;
450	params[1].buffer.pointer = in->pointer;
451
452	strncat(method, block->object_id, 2);
453
454	return acpi_evaluate_object(handle, method, &input, NULL);
455}
456EXPORT_SYMBOL_GPL(wmi_set_block);
457
458static void wmi_dump_wdg(const struct guid_block *g)
459{
460	char guid_string[37];
461
462	wmi_gtoa(g->guid, guid_string);
463
464	pr_info("%s:\n", guid_string);
465	pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
466	pr_info("\tnotify_id: %02X\n", g->notify_id);
467	pr_info("\treserved: %02X\n", g->reserved);
468	pr_info("\tinstance_count: %d\n", g->instance_count);
469	pr_info("\tflags: %#x", g->flags);
470	if (g->flags) {
471		if (g->flags & ACPI_WMI_EXPENSIVE)
472			pr_cont(" ACPI_WMI_EXPENSIVE");
473		if (g->flags & ACPI_WMI_METHOD)
474			pr_cont(" ACPI_WMI_METHOD");
475		if (g->flags & ACPI_WMI_STRING)
476			pr_cont(" ACPI_WMI_STRING");
477		if (g->flags & ACPI_WMI_EVENT)
478			pr_cont(" ACPI_WMI_EVENT");
479	}
480	pr_cont("\n");
481
482}
483
484static void wmi_notify_debug(u32 value, void *context)
485{
486	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
487	union acpi_object *obj;
488	acpi_status status;
489
490	status = wmi_get_event_data(value, &response);
491	if (status != AE_OK) {
492		pr_info("bad event status 0x%x\n", status);
493		return;
494	}
495
496	obj = (union acpi_object *)response.pointer;
497
498	if (!obj)
499		return;
500
501	pr_info("DEBUG Event ");
502	switch(obj->type) {
503	case ACPI_TYPE_BUFFER:
504		pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
505		break;
506	case ACPI_TYPE_STRING:
507		pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
508		break;
509	case ACPI_TYPE_INTEGER:
510		pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
511		break;
512	case ACPI_TYPE_PACKAGE:
513		pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
514		break;
515	default:
516		pr_cont("object type 0x%X\n", obj->type);
517	}
518	kfree(obj);
519}
520
521/**
522 * wmi_install_notify_handler - Register handler for WMI events
523 * @handler: Function to handle notifications
524 * @data: Data to be returned to handler when event is fired
525 *
526 * Register a handler for events sent to the ACPI-WMI mapper device.
527 */
528acpi_status wmi_install_notify_handler(const char *guid,
529wmi_notify_handler handler, void *data)
530{
531	struct wmi_block *block;
532	acpi_status status = AE_NOT_EXIST;
533	char tmp[16], guid_input[16];
534	struct list_head *p;
535
536	if (!guid || !handler)
537		return AE_BAD_PARAMETER;
538
539	wmi_parse_guid(guid, tmp);
540	wmi_swap_bytes(tmp, guid_input);
541
542	list_for_each(p, &wmi_block_list) {
543		acpi_status wmi_status;
544		block = list_entry(p, struct wmi_block, list);
545
546		if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
547			if (block->handler &&
548			    block->handler != wmi_notify_debug)
549				return AE_ALREADY_ACQUIRED;
550
551			block->handler = handler;
552			block->handler_data = data;
553
554			wmi_status = wmi_method_enable(block, 1);
555			if ((wmi_status != AE_OK) ||
556			    ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
557				status = wmi_status;
558		}
559	}
560
561	return status;
562}
563EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
564
565/**
566 * wmi_uninstall_notify_handler - Unregister handler for WMI events
567 *
568 * Unregister handler for events sent to the ACPI-WMI mapper device.
569 */
570acpi_status wmi_remove_notify_handler(const char *guid)
571{
572	struct wmi_block *block;
573	acpi_status status = AE_NOT_EXIST;
574	char tmp[16], guid_input[16];
575	struct list_head *p;
576
577	if (!guid)
578		return AE_BAD_PARAMETER;
579
580	wmi_parse_guid(guid, tmp);
581	wmi_swap_bytes(tmp, guid_input);
582
583	list_for_each(p, &wmi_block_list) {
584		acpi_status wmi_status;
585		block = list_entry(p, struct wmi_block, list);
586
587		if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
588			if (!block->handler ||
589			    block->handler == wmi_notify_debug)
590				return AE_NULL_ENTRY;
591
592			if (debug_event) {
593				block->handler = wmi_notify_debug;
594				status = AE_OK;
595			} else {
596				wmi_status = wmi_method_enable(block, 0);
597				block->handler = NULL;
598				block->handler_data = NULL;
599				if ((wmi_status != AE_OK) ||
600				    ((wmi_status == AE_OK) &&
601				     (status == AE_NOT_EXIST)))
602					status = wmi_status;
603			}
604		}
605	}
606
607	return status;
608}
609EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
610
611/**
612 * wmi_get_event_data - Get WMI data associated with an event
613 *
614 * @event: Event to find
615 * @out: Buffer to hold event data. out->pointer should be freed with kfree()
616 *
617 * Returns extra data associated with an event in WMI.
618 */
619acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
620{
621	struct acpi_object_list input;
622	union acpi_object params[1];
623	struct guid_block *gblock;
624	struct wmi_block *wblock;
625	struct list_head *p;
626
627	input.count = 1;
628	input.pointer = params;
629	params[0].type = ACPI_TYPE_INTEGER;
630	params[0].integer.value = event;
631
632	list_for_each(p, &wmi_block_list) {
633		wblock = list_entry(p, struct wmi_block, list);
634		gblock = &wblock->gblock;
635
636		if ((gblock->flags & ACPI_WMI_EVENT) &&
637			(gblock->notify_id == event))
638			return acpi_evaluate_object(wblock->handle, "_WED",
639				&input, out);
640	}
641
642	return AE_NOT_FOUND;
643}
644EXPORT_SYMBOL_GPL(wmi_get_event_data);
645
646/**
647 * wmi_has_guid - Check if a GUID is available
648 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
649 *
650 * Check if a given GUID is defined by _WDG
651 */
652bool wmi_has_guid(const char *guid_string)
653{
654	return find_guid(guid_string, NULL);
655}
656EXPORT_SYMBOL_GPL(wmi_has_guid);
657
658/*
659 * sysfs interface
660 */
661static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
662			     char *buf)
663{
664	char guid_string[37];
665	struct wmi_block *wblock;
666
667	wblock = dev_get_drvdata(dev);
668	if (!wblock) {
669		strcat(buf, "\n");
670		return strlen(buf);
671	}
672
673	wmi_gtoa(wblock->gblock.guid, guid_string);
674
675	return sprintf(buf, "wmi:%s\n", guid_string);
676}
677static DEVICE_ATTR_RO(modalias);
678
679static struct attribute *wmi_attrs[] = {
680	&dev_attr_modalias.attr,
681	NULL,
682};
683ATTRIBUTE_GROUPS(wmi);
684
685static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
686{
687	char guid_string[37];
688
689	struct wmi_block *wblock;
690
691	if (add_uevent_var(env, "MODALIAS="))
692		return -ENOMEM;
693
694	wblock = dev_get_drvdata(dev);
695	if (!wblock)
696		return -ENOMEM;
697
698	wmi_gtoa(wblock->gblock.guid, guid_string);
699
700	strcpy(&env->buf[env->buflen - 1], "wmi:");
701	memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
702	env->buflen += 40;
703
704	return 0;
705}
706
707static void wmi_dev_free(struct device *dev)
708{
709	struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
710
711	kfree(wmi_block);
712}
713
714static struct class wmi_class = {
715	.name = "wmi",
716	.dev_release = wmi_dev_free,
717	.dev_uevent = wmi_dev_uevent,
718	.dev_groups = wmi_groups,
719};
720
721static int wmi_create_device(const struct guid_block *gblock,
722			     struct wmi_block *wblock, acpi_handle handle)
723{
724	char guid_string[37];
725
726	wblock->dev.class = &wmi_class;
727
728	wmi_gtoa(gblock->guid, guid_string);
729	dev_set_name(&wblock->dev, "%s", guid_string);
730
731	dev_set_drvdata(&wblock->dev, wblock);
732
733	return device_register(&wblock->dev);
734}
735
736static void wmi_free_devices(void)
737{
738	struct wmi_block *wblock, *next;
739
740	/* Delete devices for all the GUIDs */
741	list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
742		list_del(&wblock->list);
743		if (wblock->dev.class)
744			device_unregister(&wblock->dev);
745		else
746			kfree(wblock);
747	}
748}
749
750static bool guid_already_parsed(const char *guid_string)
751{
752	struct wmi_block *wblock;
753
754	list_for_each_entry(wblock, &wmi_block_list, list)
755		if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
756			return true;
757
758	return false;
759}
760
761/*
762 * Parse the _WDG method for the GUID data blocks
763 */
764static int parse_wdg(acpi_handle handle)
765{
766	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
767	union acpi_object *obj;
768	const struct guid_block *gblock;
769	struct wmi_block *wblock;
770	acpi_status status;
771	int retval;
772	u32 i, total;
773
774	status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
775	if (ACPI_FAILURE(status))
776		return -ENXIO;
777
778	obj = (union acpi_object *) out.pointer;
779	if (!obj)
780		return -ENXIO;
781
782	if (obj->type != ACPI_TYPE_BUFFER) {
783		retval = -ENXIO;
784		goto out_free_pointer;
785	}
786
787	gblock = (const struct guid_block *)obj->buffer.pointer;
788	total = obj->buffer.length / sizeof(struct guid_block);
789
790	for (i = 0; i < total; i++) {
791		if (debug_dump_wdg)
792			wmi_dump_wdg(&gblock[i]);
793
794		wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
795		if (!wblock)
796			return -ENOMEM;
797
798		wblock->handle = handle;
799		wblock->gblock = gblock[i];
800
801		/*
802		  Some WMI devices, like those for nVidia hooks, have a
803		  duplicate GUID. It's not clear what we should do in this
804		  case yet, so for now, we'll just ignore the duplicate
805		  for device creation.
806		*/
807		if (!guid_already_parsed(gblock[i].guid)) {
808			retval = wmi_create_device(&gblock[i], wblock, handle);
809			if (retval) {
810				wmi_free_devices();
811				goto out_free_pointer;
812			}
813		}
814
815		list_add_tail(&wblock->list, &wmi_block_list);
816
817		if (debug_event) {
818			wblock->handler = wmi_notify_debug;
819			wmi_method_enable(wblock, 1);
820		}
821	}
822
823	retval = 0;
824
825out_free_pointer:
826	kfree(out.pointer);
827
828	return retval;
829}
830
831/*
832 * WMI can have EmbeddedControl access regions. In which case, we just want to
833 * hand these off to the EC driver.
834 */
835static acpi_status
836acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
837		      u32 bits, u64 *value,
838		      void *handler_context, void *region_context)
839{
840	int result = 0, i = 0;
841	u8 temp = 0;
842
843	if ((address > 0xFF) || !value)
844		return AE_BAD_PARAMETER;
845
846	if (function != ACPI_READ && function != ACPI_WRITE)
847		return AE_BAD_PARAMETER;
848
849	if (bits != 8)
850		return AE_BAD_PARAMETER;
851
852	if (function == ACPI_READ) {
853		result = ec_read(address, &temp);
854		(*value) |= ((u64)temp) << i;
855	} else {
856		temp = 0xff & ((*value) >> i);
857		result = ec_write(address, temp);
858	}
859
860	switch (result) {
861	case -EINVAL:
862		return AE_BAD_PARAMETER;
863		break;
864	case -ENODEV:
865		return AE_NOT_FOUND;
866		break;
867	case -ETIME:
868		return AE_TIME;
869		break;
870	default:
871		return AE_OK;
872	}
873}
874
875static void acpi_wmi_notify(struct acpi_device *device, u32 event)
876{
877	struct guid_block *block;
878	struct wmi_block *wblock;
879	struct list_head *p;
880	char guid_string[37];
881
882	list_for_each(p, &wmi_block_list) {
883		wblock = list_entry(p, struct wmi_block, list);
884		block = &wblock->gblock;
885
886		if ((block->flags & ACPI_WMI_EVENT) &&
887			(block->notify_id == event)) {
888			if (wblock->handler)
889				wblock->handler(event, wblock->handler_data);
890			if (debug_event) {
891				wmi_gtoa(wblock->gblock.guid, guid_string);
892				pr_info("DEBUG Event GUID: %s\n", guid_string);
893			}
894
895			acpi_bus_generate_netlink_event(
896				device->pnp.device_class, dev_name(&device->dev),
897				event, 0);
898			break;
899		}
900	}
901}
902
903static int acpi_wmi_remove(struct acpi_device *device)
904{
905	acpi_remove_address_space_handler(device->handle,
906				ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
907	wmi_free_devices();
908
909	return 0;
910}
911
912static int acpi_wmi_add(struct acpi_device *device)
913{
914	acpi_status status;
915	int error;
916
917	status = acpi_install_address_space_handler(device->handle,
918						    ACPI_ADR_SPACE_EC,
919						    &acpi_wmi_ec_space_handler,
920						    NULL, NULL);
921	if (ACPI_FAILURE(status)) {
922		pr_err("Error installing EC region handler\n");
923		return -ENODEV;
924	}
925
926	error = parse_wdg(device->handle);
927	if (error) {
928		acpi_remove_address_space_handler(device->handle,
929						  ACPI_ADR_SPACE_EC,
930						  &acpi_wmi_ec_space_handler);
931		pr_err("Failed to parse WDG method\n");
932		return error;
933	}
934
935	return 0;
936}
937
938static int __init acpi_wmi_init(void)
939{
940	int error;
941
942	if (acpi_disabled)
943		return -ENODEV;
944
945	error = class_register(&wmi_class);
946	if (error)
947		return error;
948
949	error = acpi_bus_register_driver(&acpi_wmi_driver);
950	if (error) {
951		pr_err("Error loading mapper\n");
952		class_unregister(&wmi_class);
953		return error;
954	}
955
956	pr_info("Mapper loaded\n");
957	return 0;
958}
959
960static void __exit acpi_wmi_exit(void)
961{
962	acpi_bus_unregister_driver(&acpi_wmi_driver);
963	class_unregister(&wmi_class);
964
965	pr_info("Mapper unloaded\n");
966}
967
968subsys_initcall(acpi_wmi_init);
969module_exit(acpi_wmi_exit);
970