Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
wmi.c
Go to the documentation of this file.
1 /*
2  * ACPI-WMI mapping driver
3  *
4  * Copyright (C) 2007-2008 Carlos Corbacho <[email protected]>
5  *
6  * GUID parsing code from ldm.c is:
7  * Copyright (C) 2001,2002 Richard Russon <[email protected]>
8  * Copyright (c) 2001-2007 Anton Altaparmakov
9  * Copyright (C) 2001,2002 Jakob Kemi <[email protected]>
10  *
11  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or (at
16  * your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26  *
27  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28  */
29 
30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31 
32 #include <linux/kernel.h>
33 #include <linux/init.h>
34 #include <linux/types.h>
35 #include <linux/device.h>
36 #include <linux/list.h>
37 #include <linux/acpi.h>
38 #include <linux/slab.h>
39 #include <linux/module.h>
40 #include <acpi/acpi_bus.h>
41 #include <acpi/acpi_drivers.h>
42 
43 ACPI_MODULE_NAME("wmi");
44 MODULE_AUTHOR("Carlos Corbacho");
45 MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
46 MODULE_LICENSE("GPL");
47 
48 #define ACPI_WMI_CLASS "wmi"
49 
50 static DEFINE_MUTEX(wmi_data_lock);
51 static LIST_HEAD(wmi_block_list);
52 
53 struct guid_block {
54  char guid[16];
55  union {
56  char object_id[2];
57  struct {
58  unsigned char notify_id;
59  unsigned char reserved;
60  };
61  };
64 };
65 
66 struct wmi_block {
67  struct list_head list;
70  wmi_notify_handler handler;
71  void *handler_data;
72  struct device dev;
73 };
74 
75 
76 /*
77  * If the GUID data block is marked as expensive, we must enable and
78  * explicitily disable data collection.
79  */
80 #define ACPI_WMI_EXPENSIVE 0x1
81 #define ACPI_WMI_METHOD 0x2 /* GUID is a method */
82 #define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */
83 #define ACPI_WMI_EVENT 0x8 /* GUID is an event */
84 
85 static bool debug_event;
86 module_param(debug_event, bool, 0444);
87 MODULE_PARM_DESC(debug_event,
88  "Log WMI Events [0/1]");
89 
90 static bool debug_dump_wdg;
91 module_param(debug_dump_wdg, bool, 0444);
92 MODULE_PARM_DESC(debug_dump_wdg,
93  "Dump available WMI interfaces [0/1]");
94 
95 static int acpi_wmi_remove(struct acpi_device *device, int type);
96 static int acpi_wmi_add(struct acpi_device *device);
97 static void acpi_wmi_notify(struct acpi_device *device, u32 event);
98 
99 static const struct acpi_device_id wmi_device_ids[] = {
100  {"PNP0C14", 0},
101  {"pnp0c14", 0},
102  {"", 0},
103 };
104 MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
105 
106 static struct acpi_driver acpi_wmi_driver = {
107  .name = "wmi",
108  .class = ACPI_WMI_CLASS,
109  .ids = wmi_device_ids,
110  .ops = {
111  .add = acpi_wmi_add,
112  .remove = acpi_wmi_remove,
113  .notify = acpi_wmi_notify,
114  },
115 };
116 
117 /*
118  * GUID parsing functions
119  */
120 
130 static int wmi_parse_hexbyte(const u8 *src)
131 {
132  int h;
133  int value;
134 
135  /* high part */
136  h = value = hex_to_bin(src[0]);
137  if (value < 0)
138  return -1;
139 
140  /* low part */
141  value = hex_to_bin(src[1]);
142  if (value >= 0)
143  return (h << 4) | value;
144  return -1;
145 }
146 
154 static void wmi_swap_bytes(u8 *src, u8 *dest)
155 {
156  int i;
157 
158  for (i = 0; i <= 3; i++)
159  memcpy(dest + i, src + (3 - i), 1);
160 
161  for (i = 0; i <= 1; i++)
162  memcpy(dest + 4 + i, src + (5 - i), 1);
163 
164  for (i = 0; i <= 1; i++)
165  memcpy(dest + 6 + i, src + (7 - i), 1);
166 
167  memcpy(dest + 8, src + 8, 8);
168 }
169 
180 static bool wmi_parse_guid(const u8 *src, u8 *dest)
181 {
182  static const int size[] = { 4, 2, 2, 2, 6 };
183  int i, j, v;
184 
185  if (src[8] != '-' || src[13] != '-' ||
186  src[18] != '-' || src[23] != '-')
187  return false;
188 
189  for (j = 0; j < 5; j++, src++) {
190  for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
191  v = wmi_parse_hexbyte(src);
192  if (v < 0)
193  return false;
194  }
195  }
196 
197  return true;
198 }
199 
200 /*
201  * Convert a raw GUID to the ACII string representation
202  */
203 static int wmi_gtoa(const char *in, char *out)
204 {
205  int i;
206 
207  for (i = 3; i >= 0; i--)
208  out += sprintf(out, "%02X", in[i] & 0xFF);
209 
210  out += sprintf(out, "-");
211  out += sprintf(out, "%02X", in[5] & 0xFF);
212  out += sprintf(out, "%02X", in[4] & 0xFF);
213  out += sprintf(out, "-");
214  out += sprintf(out, "%02X", in[7] & 0xFF);
215  out += sprintf(out, "%02X", in[6] & 0xFF);
216  out += sprintf(out, "-");
217  out += sprintf(out, "%02X", in[8] & 0xFF);
218  out += sprintf(out, "%02X", in[9] & 0xFF);
219  out += sprintf(out, "-");
220 
221  for (i = 10; i <= 15; i++)
222  out += sprintf(out, "%02X", in[i] & 0xFF);
223 
224  *out = '\0';
225  return 0;
226 }
227 
228 static bool find_guid(const char *guid_string, struct wmi_block **out)
229 {
230  char tmp[16], guid_input[16];
231  struct wmi_block *wblock;
232  struct guid_block *block;
233  struct list_head *p;
234 
235  wmi_parse_guid(guid_string, tmp);
236  wmi_swap_bytes(tmp, guid_input);
237 
238  list_for_each(p, &wmi_block_list) {
239  wblock = list_entry(p, struct wmi_block, list);
240  block = &wblock->gblock;
241 
242  if (memcmp(block->guid, guid_input, 16) == 0) {
243  if (out)
244  *out = wblock;
245  return 1;
246  }
247  }
248  return 0;
249 }
250 
251 static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
252 {
253  struct guid_block *block = NULL;
254  char method[5];
255  struct acpi_object_list input;
256  union acpi_object params[1];
259 
260  block = &wblock->gblock;
261  handle = wblock->handle;
262 
263  if (!block)
264  return AE_NOT_EXIST;
265 
266  input.count = 1;
267  input.pointer = params;
268  params[0].type = ACPI_TYPE_INTEGER;
269  params[0].integer.value = enable;
270 
271  snprintf(method, 5, "WE%02X", block->notify_id);
272  status = acpi_evaluate_object(handle, method, &input, NULL);
273 
274  if (status != AE_OK && status != AE_NOT_FOUND)
275  return status;
276  else
277  return AE_OK;
278 }
279 
280 /*
281  * Exported WMI functions
282  */
293 acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
294 u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
295 {
296  struct guid_block *block = NULL;
297  struct wmi_block *wblock = NULL;
300  struct acpi_object_list input;
301  union acpi_object params[3];
302  char method[5] = "WM";
303 
304  if (!find_guid(guid_string, &wblock))
305  return AE_ERROR;
306 
307  block = &wblock->gblock;
308  handle = wblock->handle;
309 
310  if (!(block->flags & ACPI_WMI_METHOD))
311  return AE_BAD_DATA;
312 
313  if (block->instance_count < instance)
314  return AE_BAD_PARAMETER;
315 
316  input.count = 2;
317  input.pointer = params;
318  params[0].type = ACPI_TYPE_INTEGER;
319  params[0].integer.value = instance;
320  params[1].type = ACPI_TYPE_INTEGER;
321  params[1].integer.value = method_id;
322 
323  if (in) {
324  input.count = 3;
325 
326  if (block->flags & ACPI_WMI_STRING) {
327  params[2].type = ACPI_TYPE_STRING;
328  } else {
329  params[2].type = ACPI_TYPE_BUFFER;
330  }
331  params[2].buffer.length = in->length;
332  params[2].buffer.pointer = in->pointer;
333  }
334 
335  strncat(method, block->object_id, 2);
336 
337  status = acpi_evaluate_object(handle, method, &input, out);
338 
339  return status;
340 }
342 
351 acpi_status wmi_query_block(const char *guid_string, u8 instance,
352 struct acpi_buffer *out)
353 {
354  struct guid_block *block = NULL;
355  struct wmi_block *wblock = NULL;
356  acpi_handle handle, wc_handle;
357  acpi_status status, wc_status = AE_ERROR;
358  struct acpi_object_list input, wc_input;
359  union acpi_object wc_params[1], wq_params[1];
360  char method[5];
361  char wc_method[5] = "WC";
362 
363  if (!guid_string || !out)
364  return AE_BAD_PARAMETER;
365 
366  if (!find_guid(guid_string, &wblock))
367  return AE_ERROR;
368 
369  block = &wblock->gblock;
370  handle = wblock->handle;
371 
372  if (block->instance_count < instance)
373  return AE_BAD_PARAMETER;
374 
375  /* Check GUID is a data block */
376  if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
377  return AE_ERROR;
378 
379  input.count = 1;
380  input.pointer = wq_params;
381  wq_params[0].type = ACPI_TYPE_INTEGER;
382  wq_params[0].integer.value = instance;
383 
384  /*
385  * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
386  * enable collection.
387  */
388  if (block->flags & ACPI_WMI_EXPENSIVE) {
389  wc_input.count = 1;
390  wc_input.pointer = wc_params;
391  wc_params[0].type = ACPI_TYPE_INTEGER;
392  wc_params[0].integer.value = 1;
393 
394  strncat(wc_method, block->object_id, 2);
395 
396  /*
397  * Some GUIDs break the specification by declaring themselves
398  * expensive, but have no corresponding WCxx method. So we
399  * should not fail if this happens.
400  */
401  wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
402  if (ACPI_SUCCESS(wc_status))
403  wc_status = acpi_evaluate_object(handle, wc_method,
404  &wc_input, NULL);
405  }
406 
407  strcpy(method, "WQ");
408  strncat(method, block->object_id, 2);
409 
410  status = acpi_evaluate_object(handle, method, &input, out);
411 
412  /*
413  * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
414  * the WQxx method failed - we should disable collection anyway.
415  */
416  if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
417  wc_params[0].integer.value = 0;
418  status = acpi_evaluate_object(handle,
419  wc_method, &wc_input, NULL);
420  }
421 
422  return status;
423 }
425 
434 acpi_status wmi_set_block(const char *guid_string, u8 instance,
435 const struct acpi_buffer *in)
436 {
437  struct guid_block *block = NULL;
438  struct wmi_block *wblock = NULL;
440  struct acpi_object_list input;
441  union acpi_object params[2];
442  char method[5] = "WS";
443 
444  if (!guid_string || !in)
445  return AE_BAD_DATA;
446 
447  if (!find_guid(guid_string, &wblock))
448  return AE_ERROR;
449 
450  block = &wblock->gblock;
451  handle = wblock->handle;
452 
453  if (block->instance_count < instance)
454  return AE_BAD_PARAMETER;
455 
456  /* Check GUID is a data block */
457  if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
458  return AE_ERROR;
459 
460  input.count = 2;
461  input.pointer = params;
462  params[0].type = ACPI_TYPE_INTEGER;
463  params[0].integer.value = instance;
464 
465  if (block->flags & ACPI_WMI_STRING) {
466  params[1].type = ACPI_TYPE_STRING;
467  } else {
468  params[1].type = ACPI_TYPE_BUFFER;
469  }
470  params[1].buffer.length = in->length;
471  params[1].buffer.pointer = in->pointer;
472 
473  strncat(method, block->object_id, 2);
474 
475  return acpi_evaluate_object(handle, method, &input, NULL);
476 }
478 
479 static void wmi_dump_wdg(const struct guid_block *g)
480 {
481  char guid_string[37];
482 
483  wmi_gtoa(g->guid, guid_string);
484 
485  pr_info("%s:\n", guid_string);
486  pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
487  pr_info("\tnotify_id: %02X\n", g->notify_id);
488  pr_info("\treserved: %02X\n", g->reserved);
489  pr_info("\tinstance_count: %d\n", g->instance_count);
490  pr_info("\tflags: %#x", g->flags);
491  if (g->flags) {
492  if (g->flags & ACPI_WMI_EXPENSIVE)
493  pr_cont(" ACPI_WMI_EXPENSIVE");
494  if (g->flags & ACPI_WMI_METHOD)
495  pr_cont(" ACPI_WMI_METHOD");
496  if (g->flags & ACPI_WMI_STRING)
497  pr_cont(" ACPI_WMI_STRING");
498  if (g->flags & ACPI_WMI_EVENT)
499  pr_cont(" ACPI_WMI_EVENT");
500  }
501  pr_cont("\n");
502 
503 }
504 
505 static void wmi_notify_debug(u32 value, void *context)
506 {
508  union acpi_object *obj;
510 
511  status = wmi_get_event_data(value, &response);
512  if (status != AE_OK) {
513  pr_info("bad event status 0x%x\n", status);
514  return;
515  }
516 
517  obj = (union acpi_object *)response.pointer;
518 
519  if (!obj)
520  return;
521 
522  pr_info("DEBUG Event ");
523  switch(obj->type) {
524  case ACPI_TYPE_BUFFER:
525  pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
526  break;
527  case ACPI_TYPE_STRING:
528  pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
529  break;
530  case ACPI_TYPE_INTEGER:
531  pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
532  break;
533  case ACPI_TYPE_PACKAGE:
534  pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
535  break;
536  default:
537  pr_cont("object type 0x%X\n", obj->type);
538  }
539  kfree(obj);
540 }
541 
550 wmi_notify_handler handler, void *data)
551 {
552  struct wmi_block *block;
553  acpi_status status = AE_NOT_EXIST;
554  char tmp[16], guid_input[16];
555  struct list_head *p;
556 
557  if (!guid || !handler)
558  return AE_BAD_PARAMETER;
559 
560  wmi_parse_guid(guid, tmp);
561  wmi_swap_bytes(tmp, guid_input);
562 
563  list_for_each(p, &wmi_block_list) {
564  acpi_status wmi_status;
565  block = list_entry(p, struct wmi_block, list);
566 
567  if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
568  if (block->handler &&
569  block->handler != wmi_notify_debug)
570  return AE_ALREADY_ACQUIRED;
571 
572  block->handler = handler;
573  block->handler_data = data;
574 
575  wmi_status = wmi_method_enable(block, 1);
576  if ((wmi_status != AE_OK) ||
577  ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
578  status = wmi_status;
579  }
580  }
581 
582  return status;
583 }
585 
592 {
593  struct wmi_block *block;
594  acpi_status status = AE_NOT_EXIST;
595  char tmp[16], guid_input[16];
596  struct list_head *p;
597 
598  if (!guid)
599  return AE_BAD_PARAMETER;
600 
601  wmi_parse_guid(guid, tmp);
602  wmi_swap_bytes(tmp, guid_input);
603 
604  list_for_each(p, &wmi_block_list) {
605  acpi_status wmi_status;
606  block = list_entry(p, struct wmi_block, list);
607 
608  if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
609  if (!block->handler ||
610  block->handler == wmi_notify_debug)
611  return AE_NULL_ENTRY;
612 
613  if (debug_event) {
614  block->handler = wmi_notify_debug;
615  status = AE_OK;
616  } else {
617  wmi_status = wmi_method_enable(block, 0);
618  block->handler = NULL;
619  block->handler_data = NULL;
620  if ((wmi_status != AE_OK) ||
621  ((wmi_status == AE_OK) &&
622  (status == AE_NOT_EXIST)))
623  status = wmi_status;
624  }
625  }
626  }
627 
628  return status;
629 }
631 
641 {
642  struct acpi_object_list input;
643  union acpi_object params[1];
644  struct guid_block *gblock;
645  struct wmi_block *wblock;
646  struct list_head *p;
647 
648  input.count = 1;
649  input.pointer = params;
650  params[0].type = ACPI_TYPE_INTEGER;
651  params[0].integer.value = event;
652 
653  list_for_each(p, &wmi_block_list) {
654  wblock = list_entry(p, struct wmi_block, list);
655  gblock = &wblock->gblock;
656 
657  if ((gblock->flags & ACPI_WMI_EVENT) &&
658  (gblock->notify_id == event))
659  return acpi_evaluate_object(wblock->handle, "_WED",
660  &input, out);
661  }
662 
663  return AE_NOT_FOUND;
664 }
666 
673 bool wmi_has_guid(const char *guid_string)
674 {
675  return find_guid(guid_string, NULL);
676 }
678 
679 /*
680  * sysfs interface
681  */
682 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
683  char *buf)
684 {
685  char guid_string[37];
686  struct wmi_block *wblock;
687 
688  wblock = dev_get_drvdata(dev);
689  if (!wblock)
690  return -ENOMEM;
691 
692  wmi_gtoa(wblock->gblock.guid, guid_string);
693 
694  return sprintf(buf, "wmi:%s\n", guid_string);
695 }
696 
697 static struct device_attribute wmi_dev_attrs[] = {
698  __ATTR_RO(modalias),
700 };
701 
702 static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
703 {
704  char guid_string[37];
705 
706  struct wmi_block *wblock;
707 
708  if (add_uevent_var(env, "MODALIAS="))
709  return -ENOMEM;
710 
711  wblock = dev_get_drvdata(dev);
712  if (!wblock)
713  return -ENOMEM;
714 
715  wmi_gtoa(wblock->gblock.guid, guid_string);
716 
717  strcpy(&env->buf[env->buflen - 1], "wmi:");
718  memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
719  env->buflen += 40;
720 
721  return 0;
722 }
723 
724 static void wmi_dev_free(struct device *dev)
725 {
726  struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
727 
728  kfree(wmi_block);
729 }
730 
731 static struct class wmi_class = {
732  .name = "wmi",
733  .dev_release = wmi_dev_free,
734  .dev_uevent = wmi_dev_uevent,
735  .dev_attrs = wmi_dev_attrs,
736 };
737 
738 static int wmi_create_device(const struct guid_block *gblock,
739  struct wmi_block *wblock, acpi_handle handle)
740 {
741  char guid_string[37];
742 
743  wblock->dev.class = &wmi_class;
744 
745  wmi_gtoa(gblock->guid, guid_string);
746  dev_set_name(&wblock->dev, guid_string);
747 
748  dev_set_drvdata(&wblock->dev, wblock);
749 
750  return device_register(&wblock->dev);
751 }
752 
753 static void wmi_free_devices(void)
754 {
755  struct wmi_block *wblock, *next;
756 
757  /* Delete devices for all the GUIDs */
758  list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
759  list_del(&wblock->list);
760  if (wblock->dev.class)
761  device_unregister(&wblock->dev);
762  else
763  kfree(wblock);
764  }
765 }
766 
767 static bool guid_already_parsed(const char *guid_string)
768 {
769  struct wmi_block *wblock;
770 
771  list_for_each_entry(wblock, &wmi_block_list, list)
772  if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
773  return true;
774 
775  return false;
776 }
777 
778 /*
779  * Parse the _WDG method for the GUID data blocks
780  */
781 static acpi_status parse_wdg(acpi_handle handle)
782 {
783  struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
784  union acpi_object *obj;
785  const struct guid_block *gblock;
786  struct wmi_block *wblock;
788  int retval;
789  u32 i, total;
790 
791  status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
792  if (ACPI_FAILURE(status))
793  return -ENXIO;
794 
795  obj = (union acpi_object *) out.pointer;
796  if (!obj)
797  return -ENXIO;
798 
799  if (obj->type != ACPI_TYPE_BUFFER) {
800  retval = -ENXIO;
801  goto out_free_pointer;
802  }
803 
804  gblock = (const struct guid_block *)obj->buffer.pointer;
805  total = obj->buffer.length / sizeof(struct guid_block);
806 
807  for (i = 0; i < total; i++) {
808  if (debug_dump_wdg)
809  wmi_dump_wdg(&gblock[i]);
810 
811  wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
812  if (!wblock)
813  return AE_NO_MEMORY;
814 
815  wblock->handle = handle;
816  wblock->gblock = gblock[i];
817 
818  /*
819  Some WMI devices, like those for nVidia hooks, have a
820  duplicate GUID. It's not clear what we should do in this
821  case yet, so for now, we'll just ignore the duplicate
822  for device creation.
823  */
824  if (!guid_already_parsed(gblock[i].guid)) {
825  retval = wmi_create_device(&gblock[i], wblock, handle);
826  if (retval) {
827  wmi_free_devices();
828  goto out_free_pointer;
829  }
830  }
831 
832  list_add_tail(&wblock->list, &wmi_block_list);
833 
834  if (debug_event) {
835  wblock->handler = wmi_notify_debug;
836  wmi_method_enable(wblock, 1);
837  }
838  }
839 
840  retval = 0;
841 
842 out_free_pointer:
843  kfree(out.pointer);
844 
845  return retval;
846 }
847 
848 /*
849  * WMI can have EmbeddedControl access regions. In which case, we just want to
850  * hand these off to the EC driver.
851  */
852 static acpi_status
853 acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
854  u32 bits, u64 *value,
855  void *handler_context, void *region_context)
856 {
857  int result = 0, i = 0;
858  u8 temp = 0;
859 
860  if ((address > 0xFF) || !value)
861  return AE_BAD_PARAMETER;
862 
863  if (function != ACPI_READ && function != ACPI_WRITE)
864  return AE_BAD_PARAMETER;
865 
866  if (bits != 8)
867  return AE_BAD_PARAMETER;
868 
869  if (function == ACPI_READ) {
870  result = ec_read(address, &temp);
871  (*value) |= ((u64)temp) << i;
872  } else {
873  temp = 0xff & ((*value) >> i);
874  result = ec_write(address, temp);
875  }
876 
877  switch (result) {
878  case -EINVAL:
879  return AE_BAD_PARAMETER;
880  break;
881  case -ENODEV:
882  return AE_NOT_FOUND;
883  break;
884  case -ETIME:
885  return AE_TIME;
886  break;
887  default:
888  return AE_OK;
889  }
890 }
891 
892 static void acpi_wmi_notify(struct acpi_device *device, u32 event)
893 {
894  struct guid_block *block;
895  struct wmi_block *wblock;
896  struct list_head *p;
897  char guid_string[37];
898 
899  list_for_each(p, &wmi_block_list) {
900  wblock = list_entry(p, struct wmi_block, list);
901  block = &wblock->gblock;
902 
903  if ((block->flags & ACPI_WMI_EVENT) &&
904  (block->notify_id == event)) {
905  if (wblock->handler)
906  wblock->handler(event, wblock->handler_data);
907  if (debug_event) {
908  wmi_gtoa(wblock->gblock.guid, guid_string);
909  pr_info("DEBUG Event GUID: %s\n", guid_string);
910  }
911 
913  device->pnp.device_class, dev_name(&device->dev),
914  event, 0);
915  break;
916  }
917  }
918 }
919 
920 static int acpi_wmi_remove(struct acpi_device *device, int type)
921 {
922  acpi_remove_address_space_handler(device->handle,
923  ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
924  wmi_free_devices();
925 
926  return 0;
927 }
928 
929 static int acpi_wmi_add(struct acpi_device *device)
930 {
932  int error;
933 
934  status = acpi_install_address_space_handler(device->handle,
936  &acpi_wmi_ec_space_handler,
937  NULL, NULL);
938  if (ACPI_FAILURE(status)) {
939  pr_err("Error installing EC region handler\n");
940  return -ENODEV;
941  }
942 
943  error = parse_wdg(device->handle);
944  if (error) {
945  acpi_remove_address_space_handler(device->handle,
947  &acpi_wmi_ec_space_handler);
948  pr_err("Failed to parse WDG method\n");
949  return error;
950  }
951 
952  return 0;
953 }
954 
955 static int __init acpi_wmi_init(void)
956 {
957  int error;
958 
959  if (acpi_disabled)
960  return -ENODEV;
961 
962  error = class_register(&wmi_class);
963  if (error)
964  return error;
965 
966  error = acpi_bus_register_driver(&acpi_wmi_driver);
967  if (error) {
968  pr_err("Error loading mapper\n");
969  class_unregister(&wmi_class);
970  return error;
971  }
972 
973  pr_info("Mapper loaded\n");
974  return 0;
975 }
976 
977 static void __exit acpi_wmi_exit(void)
978 {
979  acpi_bus_unregister_driver(&acpi_wmi_driver);
980  class_unregister(&wmi_class);
981 
982  pr_info("Mapper unloaded\n");
983 }
984 
985 subsys_initcall(acpi_wmi_init);
986 module_exit(acpi_wmi_exit);