]> git.openfabrics.org - ~shefty/rdma-dev.git/blob - drivers/platform/x86/wmi.c
wmi: use memcmp instead of strncmp to compare GUIDs
[~shefty/rdma-dev.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 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
31
32 #include <linux/kernel.h>
33 #include <linux/init.h>
34 #include <linux/types.h>
35 #include <linux/device.h>
36 #include <linux/list.h>
37 #include <linux/acpi.h>
38 #include <linux/slab.h>
39 #include <acpi/acpi_bus.h>
40 #include <acpi/acpi_drivers.h>
41
42 ACPI_MODULE_NAME("wmi");
43 MODULE_AUTHOR("Carlos Corbacho");
44 MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
45 MODULE_LICENSE("GPL");
46
47 #define ACPI_WMI_CLASS "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
484         pr_info("%s:\n", guid_string);
485         pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
486         pr_info("\tnotify_id: %02X\n", g->notify_id);
487         pr_info("\treserved: %02X\n", g->reserved);
488         pr_info("\tinstance_count: %d\n", g->instance_count);
489         pr_info("\tflags: %#x ", g->flags);
490         if (g->flags) {
491                 if (g->flags & ACPI_WMI_EXPENSIVE)
492                         pr_cont("ACPI_WMI_EXPENSIVE ");
493                 if (g->flags & ACPI_WMI_METHOD)
494                         pr_cont("ACPI_WMI_METHOD ");
495                 if (g->flags & ACPI_WMI_STRING)
496                         pr_cont("ACPI_WMI_STRING ");
497                 if (g->flags & ACPI_WMI_EVENT)
498                         pr_cont("ACPI_WMI_EVENT ");
499         }
500         pr_cont("\n");
501
502 }
503
504 static void wmi_notify_debug(u32 value, void *context)
505 {
506         struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
507         union acpi_object *obj;
508         acpi_status status;
509
510         status = wmi_get_event_data(value, &response);
511         if (status != AE_OK) {
512                 pr_info("bad event status 0x%x\n", status);
513                 return;
514         }
515
516         obj = (union acpi_object *)response.pointer;
517
518         if (!obj)
519                 return;
520
521         pr_info("DEBUG Event ");
522         switch(obj->type) {
523         case ACPI_TYPE_BUFFER:
524                 pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
525                 break;
526         case ACPI_TYPE_STRING:
527                 pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
528                 break;
529         case ACPI_TYPE_INTEGER:
530                 pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
531                 break;
532         case ACPI_TYPE_PACKAGE:
533                 pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
534                 break;
535         default:
536                 pr_cont("object type 0x%X\n", obj->type);
537         }
538         kfree(obj);
539 }
540
541 /**
542  * wmi_install_notify_handler - Register handler for WMI events
543  * @handler: Function to handle notifications
544  * @data: Data to be returned to handler when event is fired
545  *
546  * Register a handler for events sent to the ACPI-WMI mapper device.
547  */
548 acpi_status wmi_install_notify_handler(const char *guid,
549 wmi_notify_handler handler, void *data)
550 {
551         struct wmi_block *block;
552         acpi_status status;
553
554         if (!guid || !handler)
555                 return AE_BAD_PARAMETER;
556
557         if (!find_guid(guid, &block))
558                 return AE_NOT_EXIST;
559
560         if (block->handler && block->handler != wmi_notify_debug)
561                 return AE_ALREADY_ACQUIRED;
562
563         block->handler = handler;
564         block->handler_data = data;
565
566         status = wmi_method_enable(block, 1);
567
568         return status;
569 }
570 EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
571
572 /**
573  * wmi_uninstall_notify_handler - Unregister handler for WMI events
574  *
575  * Unregister handler for events sent to the ACPI-WMI mapper device.
576  */
577 acpi_status wmi_remove_notify_handler(const char *guid)
578 {
579         struct wmi_block *block;
580         acpi_status status = AE_OK;
581
582         if (!guid)
583                 return AE_BAD_PARAMETER;
584
585         if (!find_guid(guid, &block))
586                 return AE_NOT_EXIST;
587
588         if (!block->handler || block->handler == wmi_notify_debug)
589                 return AE_NULL_ENTRY;
590
591         if (debug_event) {
592                 block->handler = wmi_notify_debug;
593         } else {
594                 status = wmi_method_enable(block, 0);
595                 block->handler = NULL;
596                 block->handler_data = NULL;
597         }
598         return status;
599 }
600 EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
601
602 /**
603  * wmi_get_event_data - Get WMI data associated with an event
604  *
605  * @event: Event to find
606  * @out: Buffer to hold event data. out->pointer should be freed with kfree()
607  *
608  * Returns extra data associated with an event in WMI.
609  */
610 acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
611 {
612         struct acpi_object_list input;
613         union acpi_object params[1];
614         struct guid_block *gblock;
615         struct wmi_block *wblock;
616         struct list_head *p;
617
618         input.count = 1;
619         input.pointer = params;
620         params[0].type = ACPI_TYPE_INTEGER;
621         params[0].integer.value = event;
622
623         list_for_each(p, &wmi_block_list) {
624                 wblock = list_entry(p, struct wmi_block, list);
625                 gblock = &wblock->gblock;
626
627                 if ((gblock->flags & ACPI_WMI_EVENT) &&
628                         (gblock->notify_id == event))
629                         return acpi_evaluate_object(wblock->handle, "_WED",
630                                 &input, out);
631         }
632
633         return AE_NOT_FOUND;
634 }
635 EXPORT_SYMBOL_GPL(wmi_get_event_data);
636
637 /**
638  * wmi_has_guid - Check if a GUID is available
639  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
640  *
641  * Check if a given GUID is defined by _WDG
642  */
643 bool wmi_has_guid(const char *guid_string)
644 {
645         return find_guid(guid_string, NULL);
646 }
647 EXPORT_SYMBOL_GPL(wmi_has_guid);
648
649 /*
650  * sysfs interface
651  */
652 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
653                              char *buf)
654 {
655         char guid_string[37];
656         struct wmi_block *wblock;
657
658         wblock = dev_get_drvdata(dev);
659         if (!wblock)
660                 return -ENOMEM;
661
662         wmi_gtoa(wblock->gblock.guid, guid_string);
663
664         return sprintf(buf, "wmi:%s\n", guid_string);
665 }
666
667 static struct device_attribute wmi_dev_attrs[] = {
668         __ATTR_RO(modalias),
669         __ATTR_NULL
670 };
671
672 static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
673 {
674         char guid_string[37];
675
676         struct wmi_block *wblock;
677
678         if (add_uevent_var(env, "MODALIAS="))
679                 return -ENOMEM;
680
681         wblock = dev_get_drvdata(dev);
682         if (!wblock)
683                 return -ENOMEM;
684
685         wmi_gtoa(wblock->gblock.guid, guid_string);
686
687         strcpy(&env->buf[env->buflen - 1], "wmi:");
688         memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
689         env->buflen += 40;
690
691         return 0;
692 }
693
694 static void wmi_dev_free(struct device *dev)
695 {
696         struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
697
698         kfree(wmi_block);
699 }
700
701 static struct class wmi_class = {
702         .name = "wmi",
703         .dev_release = wmi_dev_free,
704         .dev_uevent = wmi_dev_uevent,
705         .dev_attrs = wmi_dev_attrs,
706 };
707
708 static struct wmi_block *wmi_create_device(const struct guid_block *gblock,
709                                            acpi_handle handle)
710 {
711         struct wmi_block *wblock;
712         int error;
713         char guid_string[37];
714
715         wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
716         if (!wblock) {
717                 error = -ENOMEM;
718                 goto err_out;
719         }
720
721         wblock->handle = handle;
722         wblock->gblock = *gblock;
723
724         wblock->dev.class = &wmi_class;
725
726         wmi_gtoa(gblock->guid, guid_string);
727         dev_set_name(&wblock->dev, guid_string);
728
729         dev_set_drvdata(&wblock->dev, wblock);
730
731         error = device_register(&wblock->dev);
732         if (error)
733                 goto err_free;
734
735         list_add_tail(&wblock->list, &wmi_block_list);
736         return wblock;
737
738 err_free:
739         kfree(wblock);
740 err_out:
741         return ERR_PTR(error);
742 }
743
744 static void wmi_free_devices(void)
745 {
746         struct wmi_block *wblock, *next;
747
748         /* Delete devices for all the GUIDs */
749         list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
750                 device_unregister(&wblock->dev);
751 }
752
753 static bool guid_already_parsed(const char *guid_string)
754 {
755         struct wmi_block *wblock;
756
757         list_for_each_entry(wblock, &wmi_block_list, list)
758                 if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
759                         return true;
760
761         return false;
762 }
763
764 /*
765  * Parse the _WDG method for the GUID data blocks
766  */
767 static acpi_status parse_wdg(acpi_handle handle)
768 {
769         struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
770         union acpi_object *obj;
771         const struct guid_block *gblock;
772         struct wmi_block *wblock;
773         char guid_string[37];
774         acpi_status status;
775         int retval;
776         u32 i, total;
777
778         status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
779         if (ACPI_FAILURE(status))
780                 return -ENXIO;
781
782         obj = (union acpi_object *) out.pointer;
783         if (!obj)
784                 return -ENXIO;
785
786         if (obj->type != ACPI_TYPE_BUFFER) {
787                 retval = -ENXIO;
788                 goto out_free_pointer;
789         }
790
791         gblock = (const struct guid_block *)obj->buffer.pointer;
792         total = obj->buffer.length / sizeof(struct guid_block);
793
794         for (i = 0; i < total; i++) {
795                 /*
796                   Some WMI devices, like those for nVidia hooks, have a
797                   duplicate GUID. It's not clear what we should do in this
798                   case yet, so for now, we'll just ignore the duplicate.
799                   Anyone who wants to add support for that device can come
800                   up with a better workaround for the mess then.
801                 */
802                 if (guid_already_parsed(gblock[i].guid) == true) {
803                         wmi_gtoa(gblock[i].guid, guid_string);
804                         pr_info("Skipping duplicate GUID %s\n", guid_string);
805                         continue;
806                 }
807
808                 if (debug_dump_wdg)
809                         wmi_dump_wdg(&gblock[i]);
810
811                 wblock = wmi_create_device(&gblock[i], handle);
812                 if (IS_ERR(wblock)) {
813                         retval = PTR_ERR(wblock);
814                         wmi_free_devices();
815                         break;
816                 }
817
818                 if (debug_event) {
819                         wblock->handler = wmi_notify_debug;
820                         wmi_method_enable(wblock, 1);
821                 }
822         }
823
824         retval = 0;
825
826 out_free_pointer:
827         kfree(out.pointer);
828
829         return retval;
830 }
831
832 /*
833  * WMI can have EmbeddedControl access regions. In which case, we just want to
834  * hand these off to the EC driver.
835  */
836 static acpi_status
837 acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
838                       u32 bits, u64 *value,
839                       void *handler_context, void *region_context)
840 {
841         int result = 0, i = 0;
842         u8 temp = 0;
843
844         if ((address > 0xFF) || !value)
845                 return AE_BAD_PARAMETER;
846
847         if (function != ACPI_READ && function != ACPI_WRITE)
848                 return AE_BAD_PARAMETER;
849
850         if (bits != 8)
851                 return AE_BAD_PARAMETER;
852
853         if (function == ACPI_READ) {
854                 result = ec_read(address, &temp);
855                 (*value) |= ((u64)temp) << i;
856         } else {
857                 temp = 0xff & ((*value) >> i);
858                 result = ec_write(address, temp);
859         }
860
861         switch (result) {
862         case -EINVAL:
863                 return AE_BAD_PARAMETER;
864                 break;
865         case -ENODEV:
866                 return AE_NOT_FOUND;
867                 break;
868         case -ETIME:
869                 return AE_TIME;
870                 break;
871         default:
872                 return AE_OK;
873         }
874 }
875
876 static void acpi_wmi_notify(struct acpi_device *device, u32 event)
877 {
878         struct guid_block *block;
879         struct wmi_block *wblock;
880         struct list_head *p;
881         char guid_string[37];
882
883         list_for_each(p, &wmi_block_list) {
884                 wblock = list_entry(p, struct wmi_block, list);
885                 block = &wblock->gblock;
886
887                 if ((block->flags & ACPI_WMI_EVENT) &&
888                         (block->notify_id == event)) {
889                         if (wblock->handler)
890                                 wblock->handler(event, wblock->handler_data);
891                         if (debug_event) {
892                                 wmi_gtoa(wblock->gblock.guid, guid_string);
893                                 pr_info("DEBUG Event GUID: %s\n", guid_string);
894                         }
895
896                         acpi_bus_generate_netlink_event(
897                                 device->pnp.device_class, dev_name(&device->dev),
898                                 event, 0);
899                         break;
900                 }
901         }
902 }
903
904 static int acpi_wmi_remove(struct acpi_device *device, int type)
905 {
906         acpi_remove_address_space_handler(device->handle,
907                                 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
908         wmi_free_devices();
909
910         return 0;
911 }
912
913 static int acpi_wmi_add(struct acpi_device *device)
914 {
915         acpi_status status;
916         int error;
917
918         status = acpi_install_address_space_handler(device->handle,
919                                                     ACPI_ADR_SPACE_EC,
920                                                     &acpi_wmi_ec_space_handler,
921                                                     NULL, NULL);
922         if (ACPI_FAILURE(status)) {
923                 pr_err("Error installing EC region handler\n");
924                 return -ENODEV;
925         }
926
927         error = parse_wdg(device->handle);
928         if (error) {
929                 acpi_remove_address_space_handler(device->handle,
930                                                   ACPI_ADR_SPACE_EC,
931                                                   &acpi_wmi_ec_space_handler);
932                 pr_err("Failed to parse WDG method\n");
933                 return error;
934         }
935
936         return 0;
937 }
938
939 static int __init acpi_wmi_init(void)
940 {
941         int error;
942
943         if (acpi_disabled)
944                 return -ENODEV;
945
946         error = class_register(&wmi_class);
947         if (error)
948                 return error;
949
950         error = acpi_bus_register_driver(&acpi_wmi_driver);
951         if (error) {
952                 pr_err("Error loading mapper\n");
953                 class_unregister(&wmi_class);
954                 return error;
955         }
956
957         pr_info("Mapper loaded\n");
958         return 0;
959 }
960
961 static void __exit acpi_wmi_exit(void)
962 {
963         acpi_bus_unregister_driver(&acpi_wmi_driver);
964         class_unregister(&wmi_class);
965
966         pr_info("Mapper unloaded\n");
967 }
968
969 subsys_initcall(acpi_wmi_init);
970 module_exit(acpi_wmi_exit);