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