linux/drivers/platform/x86/wmi.c
<<
>>
Prefs
   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                if (wblock->dev.class)
 759                        device_unregister(&wblock->dev);
 760}
 761
 762static bool guid_already_parsed(const char *guid_string)
 763{
 764        struct wmi_block *wblock;
 765
 766        list_for_each_entry(wblock, &wmi_block_list, list)
 767                if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
 768                        return true;
 769
 770        return false;
 771}
 772
 773/*
 774 * Parse the _WDG method for the GUID data blocks
 775 */
 776static acpi_status parse_wdg(acpi_handle handle)
 777{
 778        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
 779        union acpi_object *obj;
 780        const struct guid_block *gblock;
 781        struct wmi_block *wblock;
 782        acpi_status status;
 783        int retval;
 784        u32 i, total;
 785
 786        status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
 787        if (ACPI_FAILURE(status))
 788                return -ENXIO;
 789
 790        obj = (union acpi_object *) out.pointer;
 791        if (!obj)
 792                return -ENXIO;
 793
 794        if (obj->type != ACPI_TYPE_BUFFER) {
 795                retval = -ENXIO;
 796                goto out_free_pointer;
 797        }
 798
 799        gblock = (const struct guid_block *)obj->buffer.pointer;
 800        total = obj->buffer.length / sizeof(struct guid_block);
 801
 802        for (i = 0; i < total; i++) {
 803                if (debug_dump_wdg)
 804                        wmi_dump_wdg(&gblock[i]);
 805
 806                wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
 807                if (!wblock)
 808                        return AE_NO_MEMORY;
 809
 810                wblock->handle = handle;
 811                wblock->gblock = gblock[i];
 812
 813                /*
 814                  Some WMI devices, like those for nVidia hooks, have a
 815                  duplicate GUID. It's not clear what we should do in this
 816                  case yet, so for now, we'll just ignore the duplicate
 817                  for device creation.
 818                */
 819                if (!guid_already_parsed(gblock[i].guid)) {
 820                        retval = wmi_create_device(&gblock[i], wblock, handle);
 821                        if (retval) {
 822                                wmi_free_devices();
 823                                goto out_free_pointer;
 824                        }
 825                }
 826
 827                list_add_tail(&wblock->list, &wmi_block_list);
 828
 829                if (debug_event) {
 830                        wblock->handler = wmi_notify_debug;
 831                        wmi_method_enable(wblock, 1);
 832                }
 833        }
 834
 835        retval = 0;
 836
 837out_free_pointer:
 838        kfree(out.pointer);
 839
 840        return retval;
 841}
 842
 843/*
 844 * WMI can have EmbeddedControl access regions. In which case, we just want to
 845 * hand these off to the EC driver.
 846 */
 847static acpi_status
 848acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
 849                      u32 bits, u64 *value,
 850                      void *handler_context, void *region_context)
 851{
 852        int result = 0, i = 0;
 853        u8 temp = 0;
 854
 855        if ((address > 0xFF) || !value)
 856                return AE_BAD_PARAMETER;
 857
 858        if (function != ACPI_READ && function != ACPI_WRITE)
 859                return AE_BAD_PARAMETER;
 860
 861        if (bits != 8)
 862                return AE_BAD_PARAMETER;
 863
 864        if (function == ACPI_READ) {
 865                result = ec_read(address, &temp);
 866                (*value) |= ((u64)temp) << i;
 867        } else {
 868                temp = 0xff & ((*value) >> i);
 869                result = ec_write(address, temp);
 870        }
 871
 872        switch (result) {
 873        case -EINVAL:
 874                return AE_BAD_PARAMETER;
 875                break;
 876        case -ENODEV:
 877                return AE_NOT_FOUND;
 878                break;
 879        case -ETIME:
 880                return AE_TIME;
 881                break;
 882        default:
 883                return AE_OK;
 884        }
 885}
 886
 887static void acpi_wmi_notify(struct acpi_device *device, u32 event)
 888{
 889        struct guid_block *block;
 890        struct wmi_block *wblock;
 891        struct list_head *p;
 892        char guid_string[37];
 893
 894        list_for_each(p, &wmi_block_list) {
 895                wblock = list_entry(p, struct wmi_block, list);
 896                block = &wblock->gblock;
 897
 898                if ((block->flags & ACPI_WMI_EVENT) &&
 899                        (block->notify_id == event)) {
 900                        if (wblock->handler)
 901                                wblock->handler(event, wblock->handler_data);
 902                        if (debug_event) {
 903                                wmi_gtoa(wblock->gblock.guid, guid_string);
 904                                pr_info("DEBUG Event GUID: %s\n", guid_string);
 905                        }
 906
 907                        acpi_bus_generate_netlink_event(
 908                                device->pnp.device_class, dev_name(&device->dev),
 909                                event, 0);
 910                        break;
 911                }
 912        }
 913}
 914
 915static int acpi_wmi_remove(struct acpi_device *device, int type)
 916{
 917        acpi_remove_address_space_handler(device->handle,
 918                                ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
 919        wmi_free_devices();
 920
 921        return 0;
 922}
 923
 924static int acpi_wmi_add(struct acpi_device *device)
 925{
 926        acpi_status status;
 927        int error;
 928
 929        status = acpi_install_address_space_handler(device->handle,
 930                                                    ACPI_ADR_SPACE_EC,
 931                                                    &acpi_wmi_ec_space_handler,
 932                                                    NULL, NULL);
 933        if (ACPI_FAILURE(status)) {
 934                pr_err("Error installing EC region handler\n");
 935                return -ENODEV;
 936        }
 937
 938        error = parse_wdg(device->handle);
 939        if (error) {
 940                acpi_remove_address_space_handler(device->handle,
 941                                                  ACPI_ADR_SPACE_EC,
 942                                                  &acpi_wmi_ec_space_handler);
 943                pr_err("Failed to parse WDG method\n");
 944                return error;
 945        }
 946
 947        return 0;
 948}
 949
 950static int __init acpi_wmi_init(void)
 951{
 952        int error;
 953
 954        if (acpi_disabled)
 955                return -ENODEV;
 956
 957        error = class_register(&wmi_class);
 958        if (error)
 959                return error;
 960
 961        error = acpi_bus_register_driver(&acpi_wmi_driver);
 962        if (error) {
 963                pr_err("Error loading mapper\n");
 964                class_unregister(&wmi_class);
 965                return error;
 966        }
 967
 968        pr_info("Mapper loaded\n");
 969        return 0;
 970}
 971
 972static void __exit acpi_wmi_exit(void)
 973{
 974        acpi_bus_unregister_driver(&acpi_wmi_driver);
 975        class_unregister(&wmi_class);
 976
 977        pr_info("Mapper unloaded\n");
 978}
 979
 980subsys_initcall(acpi_wmi_init);
 981module_exit(acpi_wmi_exit);
 982