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); 971