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/list.h> 34 #include <linux/acpi.h> 35 #include <acpi/acpi_bus.h> 36 #include <acpi/acpi_drivers.h> 37 38 ACPI_MODULE_NAME("wmi"); 39 MODULE_AUTHOR("Carlos Corbacho"); 40 MODULE_DESCRIPTION("ACPI-WMI Mapping Driver"); 41 MODULE_LICENSE("GPL"); 42 43 #define ACPI_WMI_CLASS "wmi" 44 45 #undef PREFIX 46 #define PREFIX "ACPI: WMI: " 47 48 static DEFINE_MUTEX(wmi_data_lock); 49 50 struct guid_block { 51 char guid[16]; 52 union { 53 char object_id[2]; 54 struct { 55 unsigned char notify_id; 56 unsigned char reserved; 57 }; 58 }; 59 u8 instance_count; 60 u8 flags; 61 }; 62 63 struct wmi_block { 64 struct list_head list; 65 struct guid_block gblock; 66 acpi_handle handle; 67 wmi_notify_handler handler; 68 void *handler_data; 69 }; 70 71 static struct wmi_block wmi_blocks; 72 73 /* 74 * If the GUID data block is marked as expensive, we must enable and 75 * explicitily disable data collection. 76 */ 77 #define ACPI_WMI_EXPENSIVE 0x1 78 #define ACPI_WMI_METHOD 0x2 /* GUID is a method */ 79 #define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */ 80 #define ACPI_WMI_EVENT 0x8 /* GUID is an event */ 81 82 static int acpi_wmi_remove(struct acpi_device *device, int type); 83 static int acpi_wmi_add(struct acpi_device *device); 84 85 static const struct acpi_device_id wmi_device_ids[] = { 86 {"PNP0C14", 0}, 87 {"pnp0c14", 0}, 88 {"", 0}, 89 }; 90 MODULE_DEVICE_TABLE(acpi, wmi_device_ids); 91 92 static struct acpi_driver acpi_wmi_driver = { 93 .name = "wmi", 94 .class = ACPI_WMI_CLASS, 95 .ids = wmi_device_ids, 96 .ops = { 97 .add = acpi_wmi_add, 98 .remove = acpi_wmi_remove, 99 }, 100 }; 101 102 /* 103 * GUID parsing functions 104 */ 105 106 /** 107 * wmi_parse_hexbyte - Convert a ASCII hex number to a byte 108 * @src: Pointer to at least 2 characters to convert. 109 * 110 * Convert a two character ASCII hex string to a number. 111 * 112 * Return: 0-255 Success, the byte was parsed correctly 113 * -1 Error, an invalid character was supplied 114 */ 115 static int wmi_parse_hexbyte(const u8 *src) 116 { 117 unsigned int x; /* For correct wrapping */ 118 int h; 119 120 /* high part */ 121 x = src[0]; 122 if (x - '0' <= '9' - '0') { 123 h = x - '0'; 124 } else if (x - 'a' <= 'f' - 'a') { 125 h = x - 'a' + 10; 126 } else if (x - 'A' <= 'F' - 'A') { 127 h = x - 'A' + 10; 128 } else { 129 return -1; 130 } 131 h <<= 4; 132 133 /* low part */ 134 x = src[1]; 135 if (x - '0' <= '9' - '0') 136 return h | (x - '0'); 137 if (x - 'a' <= 'f' - 'a') 138 return h | (x - 'a' + 10); 139 if (x - 'A' <= 'F' - 'A') 140 return h | (x - 'A' + 10); 141 return -1; 142 } 143 144 /** 145 * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary 146 * @src: Memory block holding binary GUID (16 bytes) 147 * @dest: Memory block to hold byte swapped binary GUID (16 bytes) 148 * 149 * Byte swap a binary GUID to match it's real GUID value 150 */ 151 static void wmi_swap_bytes(u8 *src, u8 *dest) 152 { 153 int i; 154 155 for (i = 0; i <= 3; i++) 156 memcpy(dest + i, src + (3 - i), 1); 157 158 for (i = 0; i <= 1; i++) 159 memcpy(dest + 4 + i, src + (5 - i), 1); 160 161 for (i = 0; i <= 1; i++) 162 memcpy(dest + 6 + i, src + (7 - i), 1); 163 164 memcpy(dest + 8, src + 8, 8); 165 } 166 167 /** 168 * wmi_parse_guid - Convert GUID from ASCII to binary 169 * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba 170 * @dest: Memory block to hold binary GUID (16 bytes) 171 * 172 * N.B. The GUID need not be NULL terminated. 173 * 174 * Return: 'true' @dest contains binary GUID 175 * 'false' @dest contents are undefined 176 */ 177 static bool wmi_parse_guid(const u8 *src, u8 *dest) 178 { 179 static const int size[] = { 4, 2, 2, 2, 6 }; 180 int i, j, v; 181 182 if (src[8] != '-' || src[13] != '-' || 183 src[18] != '-' || src[23] != '-') 184 return false; 185 186 for (j = 0; j < 5; j++, src++) { 187 for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) { 188 v = wmi_parse_hexbyte(src); 189 if (v < 0) 190 return false; 191 } 192 } 193 194 return true; 195 } 196 197 static bool find_guid(const char *guid_string, struct wmi_block **out) 198 { 199 char tmp[16], guid_input[16]; 200 struct wmi_block *wblock; 201 struct guid_block *block; 202 struct list_head *p; 203 204 wmi_parse_guid(guid_string, tmp); 205 wmi_swap_bytes(tmp, guid_input); 206 207 list_for_each(p, &wmi_blocks.list) { 208 wblock = list_entry(p, struct wmi_block, list); 209 block = &wblock->gblock; 210 211 if (memcmp(block->guid, guid_input, 16) == 0) { 212 if (out) 213 *out = wblock; 214 return 1; 215 } 216 } 217 return 0; 218 } 219 220 static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable) 221 { 222 struct guid_block *block = NULL; 223 char method[5]; 224 struct acpi_object_list input; 225 union acpi_object params[1]; 226 acpi_status status; 227 acpi_handle handle; 228 229 block = &wblock->gblock; 230 handle = wblock->handle; 231 232 if (!block) 233 return AE_NOT_EXIST; 234 235 input.count = 1; 236 input.pointer = params; 237 params[0].type = ACPI_TYPE_INTEGER; 238 params[0].integer.value = enable; 239 240 snprintf(method, 5, "WE%02X", block->notify_id); 241 status = acpi_evaluate_object(handle, method, &input, NULL); 242 243 if (status != AE_OK && status != AE_NOT_FOUND) 244 return status; 245 else 246 return AE_OK; 247 } 248 249 /* 250 * Exported WMI functions 251 */ 252 /** 253 * wmi_evaluate_method - Evaluate a WMI method 254 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba 255 * @instance: Instance index 256 * @method_id: Method ID to call 257 * &in: Buffer containing input for the method call 258 * &out: Empty buffer to return the method results 259 * 260 * Call an ACPI-WMI method 261 */ 262 acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, 263 u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) 264 { 265 struct guid_block *block = NULL; 266 struct wmi_block *wblock = NULL; 267 acpi_handle handle; 268 acpi_status status; 269 struct acpi_object_list input; 270 union acpi_object params[3]; 271 char method[4] = "WM"; 272 273 if (!find_guid(guid_string, &wblock)) 274 return AE_ERROR; 275 276 block = &wblock->gblock; 277 handle = wblock->handle; 278 279 if (!(block->flags & ACPI_WMI_METHOD)) 280 return AE_BAD_DATA; 281 282 if (block->instance_count < instance) 283 return AE_BAD_PARAMETER; 284 285 input.count = 2; 286 input.pointer = params; 287 params[0].type = ACPI_TYPE_INTEGER; 288 params[0].integer.value = instance; 289 params[1].type = ACPI_TYPE_INTEGER; 290 params[1].integer.value = method_id; 291 292 if (in) { 293 input.count = 3; 294 295 if (block->flags & ACPI_WMI_STRING) { 296 params[2].type = ACPI_TYPE_STRING; 297 } else { 298 params[2].type = ACPI_TYPE_BUFFER; 299 } 300 params[2].buffer.length = in->length; 301 params[2].buffer.pointer = in->pointer; 302 } 303 304 strncat(method, block->object_id, 2); 305 306 status = acpi_evaluate_object(handle, method, &input, out); 307 308 return status; 309 } 310 EXPORT_SYMBOL_GPL(wmi_evaluate_method); 311 312 /** 313 * wmi_query_block - Return contents of a WMI block 314 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba 315 * @instance: Instance index 316 * &out: Empty buffer to return the contents of the data block to 317 * 318 * Return the contents of an ACPI-WMI data block to a buffer 319 */ 320 acpi_status wmi_query_block(const char *guid_string, u8 instance, 321 struct acpi_buffer *out) 322 { 323 struct guid_block *block = NULL; 324 struct wmi_block *wblock = NULL; 325 acpi_handle handle, wc_handle; 326 acpi_status status, wc_status = AE_ERROR; 327 struct acpi_object_list input, wc_input; 328 union acpi_object wc_params[1], wq_params[1]; 329 char method[4]; 330 char wc_method[4] = "WC"; 331 332 if (!guid_string || !out) 333 return AE_BAD_PARAMETER; 334 335 if (!find_guid(guid_string, &wblock)) 336 return AE_ERROR; 337 338 block = &wblock->gblock; 339 handle = wblock->handle; 340 341 if (block->instance_count < instance) 342 return AE_BAD_PARAMETER; 343 344 /* Check GUID is a data block */ 345 if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) 346 return AE_ERROR; 347 348 input.count = 1; 349 input.pointer = wq_params; 350 wq_params[0].type = ACPI_TYPE_INTEGER; 351 wq_params[0].integer.value = instance; 352 353 /* 354 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to 355 * enable collection. 356 */ 357 if (block->flags & ACPI_WMI_EXPENSIVE) { 358 wc_input.count = 1; 359 wc_input.pointer = wc_params; 360 wc_params[0].type = ACPI_TYPE_INTEGER; 361 wc_params[0].integer.value = 1; 362 363 strncat(wc_method, block->object_id, 2); 364 365 /* 366 * Some GUIDs break the specification by declaring themselves 367 * expensive, but have no corresponding WCxx method. So we 368 * should not fail if this happens. 369 */ 370 wc_status = acpi_get_handle(handle, wc_method, &wc_handle); 371 if (ACPI_SUCCESS(wc_status)) 372 wc_status = acpi_evaluate_object(handle, wc_method, 373 &wc_input, NULL); 374 } 375 376 strcpy(method, "WQ"); 377 strncat(method, block->object_id, 2); 378 379 status = acpi_evaluate_object(handle, method, &input, out); 380 381 /* 382 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if 383 * the WQxx method failed - we should disable collection anyway. 384 */ 385 if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) { 386 wc_params[0].integer.value = 0; 387 status = acpi_evaluate_object(handle, 388 wc_method, &wc_input, NULL); 389 } 390 391 return status; 392 } 393 EXPORT_SYMBOL_GPL(wmi_query_block); 394 395 /** 396 * wmi_set_block - Write to a WMI block 397 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba 398 * @instance: Instance index 399 * &in: Buffer containing new values for the data block 400 * 401 * Write the contents of the input buffer to an ACPI-WMI data block 402 */ 403 acpi_status wmi_set_block(const char *guid_string, u8 instance, 404 const struct acpi_buffer *in) 405 { 406 struct guid_block *block = NULL; 407 struct wmi_block *wblock = NULL; 408 acpi_handle handle; 409 struct acpi_object_list input; 410 union acpi_object params[2]; 411 char method[4] = "WS"; 412 413 if (!guid_string || !in) 414 return AE_BAD_DATA; 415 416 if (!find_guid(guid_string, &wblock)) 417 return AE_ERROR; 418 419 block = &wblock->gblock; 420 handle = wblock->handle; 421 422 if (block->instance_count < instance) 423 return AE_BAD_PARAMETER; 424 425 /* Check GUID is a data block */ 426 if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) 427 return AE_ERROR; 428 429 input.count = 2; 430 input.pointer = params; 431 params[0].type = ACPI_TYPE_INTEGER; 432 params[0].integer.value = instance; 433 434 if (block->flags & ACPI_WMI_STRING) { 435 params[1].type = ACPI_TYPE_STRING; 436 } else { 437 params[1].type = ACPI_TYPE_BUFFER; 438 } 439 params[1].buffer.length = in->length; 440 params[1].buffer.pointer = in->pointer; 441 442 strncat(method, block->object_id, 2); 443 444 return acpi_evaluate_object(handle, method, &input, NULL); 445 } 446 EXPORT_SYMBOL_GPL(wmi_set_block); 447 448 /** 449 * wmi_install_notify_handler - Register handler for WMI events 450 * @handler: Function to handle notifications 451 * @data: Data to be returned to handler when event is fired 452 * 453 * Register a handler for events sent to the ACPI-WMI mapper device. 454 */ 455 acpi_status wmi_install_notify_handler(const char *guid, 456 wmi_notify_handler handler, void *data) 457 { 458 struct wmi_block *block; 459 acpi_status status; 460 461 if (!guid || !handler) 462 return AE_BAD_PARAMETER; 463 464 find_guid(guid, &block); 465 if (!block) 466 return AE_NOT_EXIST; 467 468 if (block->handler) 469 return AE_ALREADY_ACQUIRED; 470 471 block->handler = handler; 472 block->handler_data = data; 473 474 status = wmi_method_enable(block, 1); 475 476 return status; 477 } 478 EXPORT_SYMBOL_GPL(wmi_install_notify_handler); 479 480 /** 481 * wmi_uninstall_notify_handler - Unregister handler for WMI events 482 * 483 * Unregister handler for events sent to the ACPI-WMI mapper device. 484 */ 485 acpi_status wmi_remove_notify_handler(const char *guid) 486 { 487 struct wmi_block *block; 488 acpi_status status; 489 490 if (!guid) 491 return AE_BAD_PARAMETER; 492 493 find_guid(guid, &block); 494 if (!block) 495 return AE_NOT_EXIST; 496 497 if (!block->handler) 498 return AE_NULL_ENTRY; 499 500 status = wmi_method_enable(block, 0); 501 502 block->handler = NULL; 503 block->handler_data = NULL; 504 505 return status; 506 } 507 EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); 508 509 /** 510 * wmi_get_event_data - Get WMI data associated with an event 511 * 512 * @event - Event to find 513 * &out - Buffer to hold event data 514 * 515 * Returns extra data associated with an event in WMI. 516 */ 517 acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) 518 { 519 struct acpi_object_list input; 520 union acpi_object params[1]; 521 struct guid_block *gblock; 522 struct wmi_block *wblock; 523 struct list_head *p; 524 525 input.count = 1; 526 input.pointer = params; 527 params[0].type = ACPI_TYPE_INTEGER; 528 params[0].integer.value = event; 529 530 list_for_each(p, &wmi_blocks.list) { 531 wblock = list_entry(p, struct wmi_block, list); 532 gblock = &wblock->gblock; 533 534 if ((gblock->flags & ACPI_WMI_EVENT) && 535 (gblock->notify_id == event)) 536 return acpi_evaluate_object(wblock->handle, "_WED", 537 &input, out); 538 } 539 540 return AE_NOT_FOUND; 541 } 542 EXPORT_SYMBOL_GPL(wmi_get_event_data); 543 544 /** 545 * wmi_has_guid - Check if a GUID is available 546 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba 547 * 548 * Check if a given GUID is defined by _WDG 549 */ 550 bool wmi_has_guid(const char *guid_string) 551 { 552 return find_guid(guid_string, NULL); 553 } 554 EXPORT_SYMBOL_GPL(wmi_has_guid); 555 556 /* 557 * Parse the _WDG method for the GUID data blocks 558 */ 559 static __init acpi_status parse_wdg(acpi_handle handle) 560 { 561 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 562 union acpi_object *obj; 563 struct guid_block *gblock; 564 struct wmi_block *wblock; 565 acpi_status status; 566 u32 i, total; 567 568 status = acpi_evaluate_object(handle, "_WDG", NULL, &out); 569 570 if (ACPI_FAILURE(status)) 571 return status; 572 573 obj = (union acpi_object *) out.pointer; 574 575 if (obj->type != ACPI_TYPE_BUFFER) 576 return AE_ERROR; 577 578 total = obj->buffer.length / sizeof(struct guid_block); 579 580 gblock = kzalloc(obj->buffer.length, GFP_KERNEL); 581 if (!gblock) 582 return AE_NO_MEMORY; 583 584 memcpy(gblock, obj->buffer.pointer, obj->buffer.length); 585 586 for (i = 0; i < total; i++) { 587 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); 588 if (!wblock) 589 return AE_NO_MEMORY; 590 591 wblock->gblock = gblock[i]; 592 wblock->handle = handle; 593 list_add_tail(&wblock->list, &wmi_blocks.list); 594 } 595 596 kfree(out.pointer); 597 kfree(gblock); 598 599 return status; 600 } 601 602 /* 603 * WMI can have EmbeddedControl access regions. In which case, we just want to 604 * hand these off to the EC driver. 605 */ 606 static acpi_status 607 acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address, 608 u32 bits, acpi_integer * value, 609 void *handler_context, void *region_context) 610 { 611 int result = 0, i = 0; 612 u8 temp = 0; 613 614 if ((address > 0xFF) || !value) 615 return AE_BAD_PARAMETER; 616 617 if (function != ACPI_READ && function != ACPI_WRITE) 618 return AE_BAD_PARAMETER; 619 620 if (bits != 8) 621 return AE_BAD_PARAMETER; 622 623 if (function == ACPI_READ) { 624 result = ec_read(address, &temp); 625 (*value) |= ((acpi_integer)temp) << i; 626 } else { 627 temp = 0xff & ((*value) >> i); 628 result = ec_write(address, temp); 629 } 630 631 switch (result) { 632 case -EINVAL: 633 return AE_BAD_PARAMETER; 634 break; 635 case -ENODEV: 636 return AE_NOT_FOUND; 637 break; 638 case -ETIME: 639 return AE_TIME; 640 break; 641 default: 642 return AE_OK; 643 } 644 } 645 646 static void acpi_wmi_notify(acpi_handle handle, u32 event, void *data) 647 { 648 struct guid_block *block; 649 struct wmi_block *wblock; 650 struct list_head *p; 651 struct acpi_device *device = data; 652 653 list_for_each(p, &wmi_blocks.list) { 654 wblock = list_entry(p, struct wmi_block, list); 655 block = &wblock->gblock; 656 657 if ((block->flags & ACPI_WMI_EVENT) && 658 (block->notify_id == event)) { 659 if (wblock->handler) 660 wblock->handler(event, wblock->handler_data); 661 662 acpi_bus_generate_netlink_event( 663 device->pnp.device_class, dev_name(&device->dev), 664 event, 0); 665 break; 666 } 667 } 668 } 669 670 static int acpi_wmi_remove(struct acpi_device *device, int type) 671 { 672 acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, 673 acpi_wmi_notify); 674 675 acpi_remove_address_space_handler(device->handle, 676 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); 677 678 return 0; 679 } 680 681 static int __init acpi_wmi_add(struct acpi_device *device) 682 { 683 acpi_status status; 684 int result = 0; 685 686 status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, 687 acpi_wmi_notify, device); 688 if (ACPI_FAILURE(status)) { 689 printk(KERN_ERR PREFIX "Error installing notify handler\n"); 690 return -ENODEV; 691 } 692 693 status = acpi_install_address_space_handler(device->handle, 694 ACPI_ADR_SPACE_EC, 695 &acpi_wmi_ec_space_handler, 696 NULL, NULL); 697 if (ACPI_FAILURE(status)) 698 return -ENODEV; 699 700 status = parse_wdg(device->handle); 701 if (ACPI_FAILURE(status)) { 702 printk(KERN_ERR PREFIX "Error installing EC region handler\n"); 703 return -ENODEV; 704 } 705 706 return result; 707 } 708 709 static int __init acpi_wmi_init(void) 710 { 711 int result; 712 713 INIT_LIST_HEAD(&wmi_blocks.list); 714 715 if (acpi_disabled) 716 return -ENODEV; 717 718 result = acpi_bus_register_driver(&acpi_wmi_driver); 719 720 if (result < 0) { 721 printk(KERN_INFO PREFIX "Error loading mapper\n"); 722 } else { 723 printk(KERN_INFO PREFIX "Mapper loaded\n"); 724 } 725 726 return result; 727 } 728 729 static void __exit acpi_wmi_exit(void) 730 { 731 struct list_head *p, *tmp; 732 struct wmi_block *wblock; 733 734 acpi_bus_unregister_driver(&acpi_wmi_driver); 735 736 list_for_each_safe(p, tmp, &wmi_blocks.list) { 737 wblock = list_entry(p, struct wmi_block, list); 738 739 list_del(p); 740 kfree(wblock); 741 } 742 743 printk(KERN_INFO PREFIX "Mapper unloaded\n"); 744 } 745 746 subsys_initcall(acpi_wmi_init); 747 module_exit(acpi_wmi_exit); 748