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