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