/drivers/platform/x86/wmi.c
C | 985 lines | 662 code | 170 blank | 153 comment | 116 complexity | 7d87c6656c1fe403176eda1b6192e382 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
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 42ACPI_MODULE_NAME("wmi"); 43MODULE_AUTHOR("Carlos Corbacho"); 44MODULE_DESCRIPTION("ACPI-WMI Mapping Driver"); 45MODULE_LICENSE("GPL"); 46 47#define ACPI_WMI_CLASS "wmi" 48 49static DEFINE_MUTEX(wmi_data_lock); 50static LIST_HEAD(wmi_block_list); 51 52struct 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 65struct 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 84static int debug_event; 85module_param(debug_event, bool, 0444); 86MODULE_PARM_DESC(debug_event, 87 "Log WMI Events [0/1]"); 88 89static int debug_dump_wdg; 90module_param(debug_dump_wdg, bool, 0444); 91MODULE_PARM_DESC(debug_dump_wdg, 92 "Dump available WMI interfaces [0/1]"); 93 94static int acpi_wmi_remove(struct acpi_device *device, int type); 95static int acpi_wmi_add(struct acpi_device *device); 96static void acpi_wmi_notify(struct acpi_device *device, u32 event); 97 98static const struct acpi_device_id wmi_device_ids[] = { 99 {"PNP0C14", 0}, 100 {"pnp0c14", 0}, 101 {"", 0}, 102}; 103MODULE_DEVICE_TABLE(acpi, wmi_device_ids); 104 105static 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 */ 129static 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 */ 153static 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 */ 179static 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 */ 202static 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 227static 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 250static 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 */ 292acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, 293u32 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} 340EXPORT_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 */ 350acpi_status wmi_query_block(const char *guid_string, u8 instance, 351struct 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} 423EXPORT_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 */ 433acpi_status wmi_set_block(const char *guid_string, u8 instance, 434const 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} 476EXPORT_SYMBOL_GPL(wmi_set_block); 477 478static 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 504static 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 */ 548acpi_status wmi_install_notify_handler(const char *guid, 549wmi_notify_handler handler, void *data) 550{ 551 struct wmi_block *block; 552 acpi_status status = AE_NOT_EXIST; 553 char tmp[16], guid_input[16]; 554 struct list_head *p; 555 556 if (!guid || !handler) 557 return AE_BAD_PARAMETER; 558 559 wmi_parse_guid(guid, tmp); 560 wmi_swap_bytes(tmp, guid_input); 561 562 list_for_each(p, &wmi_block_list) { 563 acpi_status wmi_status; 564 block = list_entry(p, struct wmi_block, list); 565 566 if (memcmp(block->gblock.guid, guid_input, 16) == 0) { 567 if (block->handler && 568 block->handler != wmi_notify_debug) 569 return AE_ALREADY_ACQUIRED; 570 571 block->handler = handler; 572 block->handler_data = data; 573 574 wmi_status = wmi_method_enable(block, 1); 575 if ((wmi_status != AE_OK) || 576 ((wmi_status == AE_OK) && (status == AE_NOT_EXIST))) 577 status = wmi_status; 578 } 579 } 580 581 return status; 582} 583EXPORT_SYMBOL_GPL(wmi_install_notify_handler); 584 585/** 586 * wmi_uninstall_notify_handler - Unregister handler for WMI events 587 * 588 * Unregister handler for events sent to the ACPI-WMI mapper device. 589 */ 590acpi_status wmi_remove_notify_handler(const char *guid) 591{ 592 struct wmi_block *block; 593 acpi_status status = AE_NOT_EXIST; 594 char tmp[16], guid_input[16]; 595 struct list_head *p; 596 597 if (!guid) 598 return AE_BAD_PARAMETER; 599 600 wmi_parse_guid(guid, tmp); 601 wmi_swap_bytes(tmp, guid_input); 602 603 list_for_each(p, &wmi_block_list) { 604 acpi_status wmi_status; 605 block = list_entry(p, struct wmi_block, list); 606 607 if (memcmp(block->gblock.guid, guid_input, 16) == 0) { 608 if (!block->handler || 609 block->handler == wmi_notify_debug) 610 return AE_NULL_ENTRY; 611 612 if (debug_event) { 613 block->handler = wmi_notify_debug; 614 status = AE_OK; 615 } else { 616 wmi_status = wmi_method_enable(block, 0); 617 block->handler = NULL; 618 block->handler_data = NULL; 619 if ((wmi_status != AE_OK) || 620 ((wmi_status == AE_OK) && 621 (status == AE_NOT_EXIST))) 622 status = wmi_status; 623 } 624 } 625 } 626 627 return status; 628} 629EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); 630 631/** 632 * wmi_get_event_data - Get WMI data associated with an event 633 * 634 * @event: Event to find 635 * @out: Buffer to hold event data. out->pointer should be freed with kfree() 636 * 637 * Returns extra data associated with an event in WMI. 638 */ 639acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) 640{ 641 struct acpi_object_list input; 642 union acpi_object params[1]; 643 struct guid_block *gblock; 644 struct wmi_block *wblock; 645 struct list_head *p; 646 647 input.count = 1; 648 input.pointer = params; 649 params[0].type = ACPI_TYPE_INTEGER; 650 params[0].integer.value = event; 651 652 list_for_each(p, &wmi_block_list) { 653 wblock = list_entry(p, struct wmi_block, list); 654 gblock = &wblock->gblock; 655 656 if ((gblock->flags & ACPI_WMI_EVENT) && 657 (gblock->notify_id == event)) 658 return acpi_evaluate_object(wblock->handle, "_WED", 659 &input, out); 660 } 661 662 return AE_NOT_FOUND; 663} 664EXPORT_SYMBOL_GPL(wmi_get_event_data); 665 666/** 667 * wmi_has_guid - Check if a GUID is available 668 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba 669 * 670 * Check if a given GUID is defined by _WDG 671 */ 672bool wmi_has_guid(const char *guid_string) 673{ 674 return find_guid(guid_string, NULL); 675} 676EXPORT_SYMBOL_GPL(wmi_has_guid); 677 678/* 679 * sysfs interface 680 */ 681static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, 682 char *buf) 683{ 684 char guid_string[37]; 685 struct wmi_block *wblock; 686 687 wblock = dev_get_drvdata(dev); 688 if (!wblock) 689 return -ENOMEM; 690 691 wmi_gtoa(wblock->gblock.guid, guid_string); 692 693 return sprintf(buf, "wmi:%s\n", guid_string); 694} 695 696static struct device_attribute wmi_dev_attrs[] = { 697 __ATTR_RO(modalias), 698 __ATTR_NULL 699}; 700 701static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) 702{ 703 char guid_string[37]; 704 705 struct wmi_block *wblock; 706 707 if (add_uevent_var(env, "MODALIAS=")) 708 return -ENOMEM; 709 710 wblock = dev_get_drvdata(dev); 711 if (!wblock) 712 return -ENOMEM; 713 714 wmi_gtoa(wblock->gblock.guid, guid_string); 715 716 strcpy(&env->buf[env->buflen - 1], "wmi:"); 717 memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36); 718 env->buflen += 40; 719 720 return 0; 721} 722 723static void wmi_dev_free(struct device *dev) 724{ 725 struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev); 726 727 kfree(wmi_block); 728} 729 730static struct class wmi_class = { 731 .name = "wmi", 732 .dev_release = wmi_dev_free, 733 .dev_uevent = wmi_dev_uevent, 734 .dev_attrs = wmi_dev_attrs, 735}; 736 737static int wmi_create_device(const struct guid_block *gblock, 738 struct wmi_block *wblock, acpi_handle handle) 739{ 740 char guid_string[37]; 741 742 wblock->dev.class = &wmi_class; 743 744 wmi_gtoa(gblock->guid, guid_string); 745 dev_set_name(&wblock->dev, guid_string); 746 747 dev_set_drvdata(&wblock->dev, wblock); 748 749 return device_register(&wblock->dev); 750} 751 752static void wmi_free_devices(void) 753{ 754 struct wmi_block *wblock, *next; 755 756 /* Delete devices for all the GUIDs */ 757 list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { 758 list_del(&wblock->list); 759 if (wblock->dev.class) 760 device_unregister(&wblock->dev); 761 else 762 kfree(wblock); 763 } 764} 765 766static bool guid_already_parsed(const char *guid_string) 767{ 768 struct wmi_block *wblock; 769 770 list_for_each_entry(wblock, &wmi_block_list, list) 771 if (memcmp(wblock->gblock.guid, guid_string, 16) == 0) 772 return true; 773 774 return false; 775} 776 777/* 778 * Parse the _WDG method for the GUID data blocks 779 */ 780static acpi_status parse_wdg(acpi_handle handle) 781{ 782 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 783 union acpi_object *obj; 784 const struct guid_block *gblock; 785 struct wmi_block *wblock; 786 acpi_status status; 787 int retval; 788 u32 i, total; 789 790 status = acpi_evaluate_object(handle, "_WDG", NULL, &out); 791 if (ACPI_FAILURE(status)) 792 return -ENXIO; 793 794 obj = (union acpi_object *) out.pointer; 795 if (!obj) 796 return -ENXIO; 797 798 if (obj->type != ACPI_TYPE_BUFFER) { 799 retval = -ENXIO; 800 goto out_free_pointer; 801 } 802 803 gblock = (const struct guid_block *)obj->buffer.pointer; 804 total = obj->buffer.length / sizeof(struct guid_block); 805 806 for (i = 0; i < total; i++) { 807 if (debug_dump_wdg) 808 wmi_dump_wdg(&gblock[i]); 809 810 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); 811 if (!wblock) 812 return AE_NO_MEMORY; 813 814 wblock->handle = handle; 815 wblock->gblock = gblock[i]; 816 817 /* 818 Some WMI devices, like those for nVidia hooks, have a 819 duplicate GUID. It's not clear what we should do in this 820 case yet, so for now, we'll just ignore the duplicate 821 for device creation. 822 */ 823 if (!guid_already_parsed(gblock[i].guid)) { 824 retval = wmi_create_device(&gblock[i], wblock, handle); 825 if (retval) { 826 wmi_free_devices(); 827 goto out_free_pointer; 828 } 829 } 830 831 list_add_tail(&wblock->list, &wmi_block_list); 832 833 if (debug_event) { 834 wblock->handler = wmi_notify_debug; 835 wmi_method_enable(wblock, 1); 836 } 837 } 838 839 retval = 0; 840 841out_free_pointer: 842 kfree(out.pointer); 843 844 return retval; 845} 846 847/* 848 * WMI can have EmbeddedControl access regions. In which case, we just want to 849 * hand these off to the EC driver. 850 */ 851static acpi_status 852acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address, 853 u32 bits, u64 *value, 854 void *handler_context, void *region_context) 855{ 856 int result = 0, i = 0; 857 u8 temp = 0; 858 859 if ((address > 0xFF) || !value) 860 return AE_BAD_PARAMETER; 861 862 if (function != ACPI_READ && function != ACPI_WRITE) 863 return AE_BAD_PARAMETER; 864 865 if (bits != 8) 866 return AE_BAD_PARAMETER; 867 868 if (function == ACPI_READ) { 869 result = ec_read(address, &temp); 870 (*value) |= ((u64)temp) << i; 871 } else { 872 temp = 0xff & ((*value) >> i); 873 result = ec_write(address, temp); 874 } 875 876 switch (result) { 877 case -EINVAL: 878 return AE_BAD_PARAMETER; 879 break; 880 case -ENODEV: 881 return AE_NOT_FOUND; 882 break; 883 case -ETIME: 884 return AE_TIME; 885 break; 886 default: 887 return AE_OK; 888 } 889} 890 891static void acpi_wmi_notify(struct acpi_device *device, u32 event) 892{ 893 struct guid_block *block; 894 struct wmi_block *wblock; 895 struct list_head *p; 896 char guid_string[37]; 897 898 list_for_each(p, &wmi_block_list) { 899 wblock = list_entry(p, struct wmi_block, list); 900 block = &wblock->gblock; 901 902 if ((block->flags & ACPI_WMI_EVENT) && 903 (block->notify_id == event)) { 904 if (wblock->handler) 905 wblock->handler(event, wblock->handler_data); 906 if (debug_event) { 907 wmi_gtoa(wblock->gblock.guid, guid_string); 908 pr_info("DEBUG Event GUID: %s\n", guid_string); 909 } 910 911 acpi_bus_generate_netlink_event( 912 device->pnp.device_class, dev_name(&device->dev), 913 event, 0); 914 break; 915 } 916 } 917} 918 919static int acpi_wmi_remove(struct acpi_device *device, int type) 920{ 921 acpi_remove_address_space_handler(device->handle, 922 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); 923 wmi_free_devices(); 924 925 return 0; 926} 927 928static int acpi_wmi_add(struct acpi_device *device) 929{ 930 acpi_status status; 931 int error; 932 933 status = acpi_install_address_space_handler(device->handle, 934 ACPI_ADR_SPACE_EC, 935 &acpi_wmi_ec_space_handler, 936 NULL, NULL); 937 if (ACPI_FAILURE(status)) { 938 pr_err("Error installing EC region handler\n"); 939 return -ENODEV; 940 } 941 942 error = parse_wdg(device->handle); 943 if (error) { 944 acpi_remove_address_space_handler(device->handle, 945 ACPI_ADR_SPACE_EC, 946 &acpi_wmi_ec_space_handler); 947 pr_err("Failed to parse WDG method\n"); 948 return error; 949 } 950 951 return 0; 952} 953 954static int __init acpi_wmi_init(void) 955{ 956 int error; 957 958 if (acpi_disabled) 959 return -ENODEV; 960 961 error = class_register(&wmi_class); 962 if (error) 963 return error; 964 965 error = acpi_bus_register_driver(&acpi_wmi_driver); 966 if (error) { 967 pr_err("Error loading mapper\n"); 968 class_unregister(&wmi_class); 969 return error; 970 } 971 972 pr_info("Mapper loaded\n"); 973 return 0; 974} 975 976static void __exit acpi_wmi_exit(void) 977{ 978 acpi_bus_unregister_driver(&acpi_wmi_driver); 979 class_unregister(&wmi_class); 980 981 pr_info("Mapper unloaded\n"); 982} 983 984subsys_initcall(acpi_wmi_init); 985module_exit(acpi_wmi_exit);