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