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