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 <linux/module.h>
  40
  41ACPI_MODULE_NAME("wmi");
  42MODULE_AUTHOR("Carlos Corbacho");
  43MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
  44MODULE_LICENSE("GPL");
  45
  46#define ACPI_WMI_CLASS "wmi"
  47
  48static DEFINE_MUTEX(wmi_data_lock);
  49static LIST_HEAD(wmi_block_list);
  50
  51struct guid_block {
  52        char guid[16];
  53        union {
  54                char object_id[2];
  55                struct {
  56                        unsigned char notify_id;
  57                        unsigned char reserved;
  58                };
  59        };
  60        u8 instance_count;
  61        u8 flags;
  62};
  63
  64struct wmi_block {
  65        struct list_head list;
  66        struct guid_block gblock;
  67        acpi_handle handle;
  68        wmi_notify_handler handler;
  69        void *handler_data;
  70        struct device dev;
  71};
  72
  73
  74/*
  75 * If the GUID data block is marked as expensive, we must enable and
  76 * explicitily disable data collection.
  77 */
  78#define ACPI_WMI_EXPENSIVE   0x1
  79#define ACPI_WMI_METHOD      0x2        /* GUID is a method */
  80#define ACPI_WMI_STRING      0x4        /* GUID takes & returns a string */
  81#define ACPI_WMI_EVENT       0x8        /* GUID is an event */
  82
  83static bool debug_event;
  84module_param(debug_event, bool, 0444);
  85MODULE_PARM_DESC(debug_event,
  86                 "Log WMI Events [0/1]");
  87
  88static bool debug_dump_wdg;
  89module_param(debug_dump_wdg, bool, 0444);
  90MODULE_PARM_DESC(debug_dump_wdg,
  91                 "Dump available WMI interfaces [0/1]");
  92
  93static int acpi_wmi_remove(struct acpi_device *device);
  94static int acpi_wmi_add(struct acpi_device *device);
  95static void acpi_wmi_notify(struct acpi_device *device, u32 event);
  96
  97static const struct acpi_device_id wmi_device_ids[] = {
  98        {"PNP0C14", 0},
  99        {"pnp0c14", 0},
 100        {"", 0},
 101};
 102MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
 103
 104static struct acpi_driver acpi_wmi_driver = {
 105        .name = "wmi",
 106        .class = ACPI_WMI_CLASS,
 107        .ids = wmi_device_ids,
 108        .ops = {
 109                .add = acpi_wmi_add,
 110                .remove = acpi_wmi_remove,
 111                .notify = acpi_wmi_notify,
 112        },
 113};
 114
 115/*
 116 * GUID parsing functions
 117 */
 118
 119/**
 120 * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
 121 * @src:  Pointer to at least 2 characters to convert.
 122 *
 123 * Convert a two character ASCII hex string to a number.
 124 *
 125 * Return:  0-255  Success, the byte was parsed correctly
 126 *          -1     Error, an invalid character was supplied
 127 */
 128static int wmi_parse_hexbyte(const u8 *src)
 129{
 130        int h;
 131        int value;
 132
 133        /* high part */
 134        h = value = hex_to_bin(src[0]);
 135        if (value < 0)
 136                return -1;
 137
 138        /* low part */
 139        value = hex_to_bin(src[1]);
 140        if (value >= 0)
 141                return (h << 4) | value;
 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 */
 152static 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 */
 178static 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/*
 199 * Convert a raw GUID to the ACII string representation
 200 */
 201static int wmi_gtoa(const char *in, char *out)
 202{
 203        int i;
 204
 205        for (i = 3; i >= 0; i--)
 206                out += sprintf(out, "%02X", in[i] & 0xFF);
 207
 208        out += sprintf(out, "-");
 209        out += sprintf(out, "%02X", in[5] & 0xFF);
 210        out += sprintf(out, "%02X", in[4] & 0xFF);
 211        out += sprintf(out, "-");
 212        out += sprintf(out, "%02X", in[7] & 0xFF);
 213        out += sprintf(out, "%02X", in[6] & 0xFF);
 214        out += sprintf(out, "-");
 215        out += sprintf(out, "%02X", in[8] & 0xFF);
 216        out += sprintf(out, "%02X", in[9] & 0xFF);
 217        out += sprintf(out, "-");
 218
 219        for (i = 10; i <= 15; i++)
 220                out += sprintf(out, "%02X", in[i] & 0xFF);
 221
 222        *out = '\0';
 223        return 0;
 224}
 225
 226static bool find_guid(const char *guid_string, struct wmi_block **out)
 227{
 228        char tmp[16], guid_input[16];
 229        struct wmi_block *wblock;
 230        struct guid_block *block;
 231        struct list_head *p;
 232
 233        wmi_parse_guid(guid_string, tmp);
 234        wmi_swap_bytes(tmp, guid_input);
 235
 236        list_for_each(p, &wmi_block_list) {
 237                wblock = list_entry(p, struct wmi_block, list);
 238                block = &wblock->gblock;
 239
 240                if (memcmp(block->guid, guid_input, 16) == 0) {
 241                        if (out)
 242                                *out = wblock;
 243                        return 1;
 244                }
 245        }
 246        return 0;
 247}
 248
 249static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
 250{
 251        struct guid_block *block = NULL;
 252        char method[5];
 253        acpi_status status;
 254        acpi_handle handle;
 255
 256        block = &wblock->gblock;
 257        handle = wblock->handle;
 258
 259        if (!block)
 260                return AE_NOT_EXIST;
 261
 262
 263        snprintf(method, 5, "WE%02X", block->notify_id);
 264        status = acpi_execute_simple_method(handle, method, enable);
 265
 266        if (status != AE_OK && status != AE_NOT_FOUND)
 267                return status;
 268        else
 269                return AE_OK;
 270}
 271
 272/*
 273 * Exported WMI functions
 274 */
 275/**
 276 * wmi_evaluate_method - Evaluate a WMI method
 277 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 278 * @instance: Instance index
 279 * @method_id: Method ID to call
 280 * &in: Buffer containing input for the method call
 281 * &out: Empty buffer to return the method results
 282 *
 283 * Call an ACPI-WMI method
 284 */
 285acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
 286u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
 287{
 288        struct guid_block *block = NULL;
 289        struct wmi_block *wblock = NULL;
 290        acpi_handle handle;
 291        acpi_status status;
 292        struct acpi_object_list input;
 293        union acpi_object params[3];
 294        char method[5] = "WM";
 295
 296        if (!find_guid(guid_string, &wblock))
 297                return AE_ERROR;
 298
 299        block = &wblock->gblock;
 300        handle = wblock->handle;
 301
 302        if (!(block->flags & ACPI_WMI_METHOD))
 303                return AE_BAD_DATA;
 304
 305        if (block->instance_count < instance)
 306                return AE_BAD_PARAMETER;
 307
 308        input.count = 2;
 309        input.pointer = params;
 310        params[0].type = ACPI_TYPE_INTEGER;
 311        params[0].integer.value = instance;
 312        params[1].type = ACPI_TYPE_INTEGER;
 313        params[1].integer.value = method_id;
 314
 315        if (in) {
 316                input.count = 3;
 317
 318                if (block->flags & ACPI_WMI_STRING) {
 319                        params[2].type = ACPI_TYPE_STRING;
 320                } else {
 321                        params[2].type = ACPI_TYPE_BUFFER;
 322                }
 323                params[2].buffer.length = in->length;
 324                params[2].buffer.pointer = in->pointer;
 325        }
 326
 327        strncat(method, block->object_id, 2);
 328
 329        status = acpi_evaluate_object(handle, method, &input, out);
 330
 331        return status;
 332}
 333EXPORT_SYMBOL_GPL(wmi_evaluate_method);
 334
 335/**
 336 * wmi_query_block - Return contents of a WMI block
 337 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 338 * @instance: Instance index
 339 * &out: Empty buffer to return the contents of the data block to
 340 *
 341 * Return the contents of an ACPI-WMI data block to a buffer
 342 */
 343acpi_status wmi_query_block(const char *guid_string, u8 instance,
 344struct acpi_buffer *out)
 345{
 346        struct guid_block *block = NULL;
 347        struct wmi_block *wblock = NULL;
 348        acpi_handle handle;
 349        acpi_status status, wc_status = AE_ERROR;
 350        struct acpi_object_list input;
 351        union acpi_object wq_params[1];
 352        char method[5];
 353        char wc_method[5] = "WC";
 354
 355        if (!guid_string || !out)
 356                return AE_BAD_PARAMETER;
 357
 358        if (!find_guid(guid_string, &wblock))
 359                return AE_ERROR;
 360
 361        block = &wblock->gblock;
 362        handle = wblock->handle;
 363
 364        if (block->instance_count < instance)
 365                return AE_BAD_PARAMETER;
 366
 367        /* Check GUID is a data block */
 368        if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
 369                return AE_ERROR;
 370
 371        input.count = 1;
 372        input.pointer = wq_params;
 373        wq_params[0].type = ACPI_TYPE_INTEGER;
 374        wq_params[0].integer.value = instance;
 375
 376        /*
 377         * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
 378         * enable collection.
 379         */
 380        if (block->flags & ACPI_WMI_EXPENSIVE) {
 381                strncat(wc_method, block->object_id, 2);
 382
 383                /*
 384                 * Some GUIDs break the specification by declaring themselves
 385                 * expensive, but have no corresponding WCxx method. So we
 386                 * should not fail if this happens.
 387                 */
 388                if (acpi_has_method(handle, wc_method))
 389                        wc_status = acpi_execute_simple_method(handle,
 390                                                                wc_method, 1);
 391        }
 392
 393        strcpy(method, "WQ");
 394        strncat(method, block->object_id, 2);
 395
 396        status = acpi_evaluate_object(handle, method, &input, out);
 397
 398        /*
 399         * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
 400         * the WQxx method failed - we should disable collection anyway.
 401         */
 402        if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
 403                status = acpi_execute_simple_method(handle, wc_method, 0);
 404        }
 405
 406        return status;
 407}
 408EXPORT_SYMBOL_GPL(wmi_query_block);
 409
 410/**
 411 * wmi_set_block - Write to a WMI block
 412 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 413 * @instance: Instance index
 414 * &in: Buffer containing new values for the data block
 415 *
 416 * Write the contents of the input buffer to an ACPI-WMI data block
 417 */
 418acpi_status wmi_set_block(const char *guid_string, u8 instance,
 419const struct acpi_buffer *in)
 420{
 421        struct guid_block *block = NULL;
 422        struct wmi_block *wblock = NULL;
 423        acpi_handle handle;
 424        struct acpi_object_list input;
 425        union acpi_object params[2];
 426        char method[5] = "WS";
 427
 428        if (!guid_string || !in)
 429                return AE_BAD_DATA;
 430
 431        if (!find_guid(guid_string, &wblock))
 432                return AE_ERROR;
 433
 434        block = &wblock->gblock;
 435        handle = wblock->handle;
 436
 437        if (block->instance_count < instance)
 438                return AE_BAD_PARAMETER;
 439
 440        /* Check GUID is a data block */
 441        if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
 442                return AE_ERROR;
 443
 444        input.count = 2;
 445        input.pointer = params;
 446        params[0].type = ACPI_TYPE_INTEGER;
 447        params[0].integer.value = instance;
 448
 449        if (block->flags & ACPI_WMI_STRING) {
 450                params[1].type = ACPI_TYPE_STRING;
 451        } else {
 452                params[1].type = ACPI_TYPE_BUFFER;
 453        }
 454        params[1].buffer.length = in->length;
 455        params[1].buffer.pointer = in->pointer;
 456
 457        strncat(method, block->object_id, 2);
 458
 459        return acpi_evaluate_object(handle, method, &input, NULL);
 460}
 461EXPORT_SYMBOL_GPL(wmi_set_block);
 462
 463static void wmi_dump_wdg(const struct guid_block *g)
 464{
 465        char guid_string[37];
 466
 467        wmi_gtoa(g->guid, guid_string);
 468
 469        pr_info("%s:\n", guid_string);
 470        pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
 471        pr_info("\tnotify_id: %02X\n", g->notify_id);
 472        pr_info("\treserved: %02X\n", g->reserved);
 473        pr_info("\tinstance_count: %d\n", g->instance_count);
 474        pr_info("\tflags: %#x", g->flags);
 475        if (g->flags) {
 476                if (g->flags & ACPI_WMI_EXPENSIVE)
 477                        pr_cont(" ACPI_WMI_EXPENSIVE");
 478                if (g->flags & ACPI_WMI_METHOD)
 479                        pr_cont(" ACPI_WMI_METHOD");
 480                if (g->flags & ACPI_WMI_STRING)
 481                        pr_cont(" ACPI_WMI_STRING");
 482                if (g->flags & ACPI_WMI_EVENT)
 483                        pr_cont(" ACPI_WMI_EVENT");
 484        }
 485        pr_cont("\n");
 486
 487}
 488
 489static void wmi_notify_debug(u32 value, void *context)
 490{
 491        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
 492        union acpi_object *obj;
 493        acpi_status status;
 494
 495        status = wmi_get_event_data(value, &response);
 496        if (status != AE_OK) {
 497                pr_info("bad event status 0x%x\n", status);
 498                return;
 499        }
 500
 501        obj = (union acpi_object *)response.pointer;
 502
 503        if (!obj)
 504                return;
 505
 506        pr_info("DEBUG Event ");
 507        switch(obj->type) {
 508        case ACPI_TYPE_BUFFER:
 509                pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
 510                break;
 511        case ACPI_TYPE_STRING:
 512                pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
 513                break;
 514        case ACPI_TYPE_INTEGER:
 515                pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
 516                break;
 517        case ACPI_TYPE_PACKAGE:
 518                pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
 519                break;
 520        default:
 521                pr_cont("object type 0x%X\n", obj->type);
 522        }
 523        kfree(obj);
 524}
 525
 526/**
 527 * wmi_install_notify_handler - Register handler for WMI events
 528 * @handler: Function to handle notifications
 529 * @data: Data to be returned to handler when event is fired
 530 *
 531 * Register a handler for events sent to the ACPI-WMI mapper device.
 532 */
 533acpi_status wmi_install_notify_handler(const char *guid,
 534wmi_notify_handler handler, void *data)
 535{
 536        struct wmi_block *block;
 537        acpi_status status = AE_NOT_EXIST;
 538        char tmp[16], guid_input[16];
 539        struct list_head *p;
 540
 541        if (!guid || !handler)
 542                return AE_BAD_PARAMETER;
 543
 544        wmi_parse_guid(guid, tmp);
 545        wmi_swap_bytes(tmp, guid_input);
 546
 547        list_for_each(p, &wmi_block_list) {
 548                acpi_status wmi_status;
 549                block = list_entry(p, struct wmi_block, list);
 550
 551                if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
 552                        if (block->handler &&
 553                            block->handler != wmi_notify_debug)
 554                                return AE_ALREADY_ACQUIRED;
 555
 556                        block->handler = handler;
 557                        block->handler_data = data;
 558
 559                        wmi_status = wmi_method_enable(block, 1);
 560                        if ((wmi_status != AE_OK) ||
 561                            ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
 562                                status = wmi_status;
 563                }
 564        }
 565
 566        return status;
 567}
 568EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
 569
 570/**
 571 * wmi_uninstall_notify_handler - Unregister handler for WMI events
 572 *
 573 * Unregister handler for events sent to the ACPI-WMI mapper device.
 574 */
 575acpi_status wmi_remove_notify_handler(const char *guid)
 576{
 577        struct wmi_block *block;
 578        acpi_status status = AE_NOT_EXIST;
 579        char tmp[16], guid_input[16];
 580        struct list_head *p;
 581
 582        if (!guid)
 583                return AE_BAD_PARAMETER;
 584
 585        wmi_parse_guid(guid, tmp);
 586        wmi_swap_bytes(tmp, guid_input);
 587
 588        list_for_each(p, &wmi_block_list) {
 589                acpi_status wmi_status;
 590                block = list_entry(p, struct wmi_block, list);
 591
 592                if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
 593                        if (!block->handler ||
 594                            block->handler == wmi_notify_debug)
 595                                return AE_NULL_ENTRY;
 596
 597                        if (debug_event) {
 598                                block->handler = wmi_notify_debug;
 599                                status = AE_OK;
 600                        } else {
 601                                wmi_status = wmi_method_enable(block, 0);
 602                                block->handler = NULL;
 603                                block->handler_data = NULL;
 604                                if ((wmi_status != AE_OK) ||
 605                                    ((wmi_status == AE_OK) &&
 606                                     (status == AE_NOT_EXIST)))
 607                                        status = wmi_status;
 608                        }
 609                }
 610        }
 611
 612        return status;
 613}
 614EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
 615
 616/**
 617 * wmi_get_event_data - Get WMI data associated with an event
 618 *
 619 * @event: Event to find
 620 * @out: Buffer to hold event data. out->pointer should be freed with kfree()
 621 *
 622 * Returns extra data associated with an event in WMI.
 623 */
 624acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
 625{
 626        struct acpi_object_list input;
 627        union acpi_object params[1];
 628        struct guid_block *gblock;
 629        struct wmi_block *wblock;
 630        struct list_head *p;
 631
 632        input.count = 1;
 633        input.pointer = params;
 634        params[0].type = ACPI_TYPE_INTEGER;
 635        params[0].integer.value = event;
 636
 637        list_for_each(p, &wmi_block_list) {
 638                wblock = list_entry(p, struct wmi_block, list);
 639                gblock = &wblock->gblock;
 640
 641                if ((gblock->flags & ACPI_WMI_EVENT) &&
 642                        (gblock->notify_id == event))
 643                        return acpi_evaluate_object(wblock->handle, "_WED",
 644                                &input, out);
 645        }
 646
 647        return AE_NOT_FOUND;
 648}
 649EXPORT_SYMBOL_GPL(wmi_get_event_data);
 650
 651/**
 652 * wmi_has_guid - Check if a GUID is available
 653 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 654 *
 655 * Check if a given GUID is defined by _WDG
 656 */
 657bool wmi_has_guid(const char *guid_string)
 658{
 659        return find_guid(guid_string, NULL);
 660}
 661EXPORT_SYMBOL_GPL(wmi_has_guid);
 662
 663/*
 664 * sysfs interface
 665 */
 666static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
 667                             char *buf)
 668{
 669        char guid_string[37];
 670        struct wmi_block *wblock;
 671
 672        wblock = dev_get_drvdata(dev);
 673        if (!wblock) {
 674                strcat(buf, "\n");
 675                return strlen(buf);
 676        }
 677
 678        wmi_gtoa(wblock->gblock.guid, guid_string);
 679
 680        return sprintf(buf, "wmi:%s\n", guid_string);
 681}
 682static DEVICE_ATTR_RO(modalias);
 683
 684static struct attribute *wmi_attrs[] = {
 685        &dev_attr_modalias.attr,
 686        NULL,
 687};
 688ATTRIBUTE_GROUPS(wmi);
 689
 690static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 691{
 692        char guid_string[37];
 693
 694        struct wmi_block *wblock;
 695
 696        if (add_uevent_var(env, "MODALIAS="))
 697                return -ENOMEM;
 698
 699        wblock = dev_get_drvdata(dev);
 700        if (!wblock)
 701                return -ENOMEM;
 702
 703        wmi_gtoa(wblock->gblock.guid, guid_string);
 704
 705        strcpy(&env->buf[env->buflen - 1], "wmi:");
 706        memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
 707        env->buflen += 40;
 708
 709        return 0;
 710}
 711
 712static void wmi_dev_free(struct device *dev)
 713{
 714        struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
 715
 716        kfree(wmi_block);
 717}
 718
 719static struct class wmi_class = {
 720        .name = "wmi",
 721        .dev_release = wmi_dev_free,
 722        .dev_uevent = wmi_dev_uevent,
 723        .dev_groups = wmi_groups,
 724};
 725
 726static int wmi_create_device(const struct guid_block *gblock,
 727                             struct wmi_block *wblock, acpi_handle handle)
 728{
 729        char guid_string[37];
 730
 731        wblock->dev.class = &wmi_class;
 732
 733        wmi_gtoa(gblock->guid, guid_string);
 734        dev_set_name(&wblock->dev, "%s", guid_string);
 735
 736        dev_set_drvdata(&wblock->dev, wblock);
 737
 738        return device_register(&wblock->dev);
 739}
 740
 741static void wmi_free_devices(void)
 742{
 743        struct wmi_block *wblock, *next;
 744
 745        /* Delete devices for all the GUIDs */
 746        list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
 747                list_del(&wblock->list);
 748                if (wblock->dev.class)
 749                        device_unregister(&wblock->dev);
 750                else
 751                        kfree(wblock);
 752        }
 753}
 754
 755static bool guid_already_parsed(const char *guid_string)
 756{
 757        struct wmi_block *wblock;
 758
 759        list_for_each_entry(wblock, &wmi_block_list, list)
 760                if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
 761                        return true;
 762
 763        return false;
 764}
 765
 766/*
 767 * Parse the _WDG method for the GUID data blocks
 768 */
 769static int parse_wdg(acpi_handle handle)
 770{
 771        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
 772        union acpi_object *obj;
 773        const struct guid_block *gblock;
 774        struct wmi_block *wblock;
 775        acpi_status status;
 776        int retval;
 777        u32 i, total;
 778
 779        status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
 780        if (ACPI_FAILURE(status))
 781                return -ENXIO;
 782
 783        obj = (union acpi_object *) out.pointer;
 784        if (!obj)
 785                return -ENXIO;
 786
 787        if (obj->type != ACPI_TYPE_BUFFER) {
 788                retval = -ENXIO;
 789                goto out_free_pointer;
 790        }
 791
 792        gblock = (const struct guid_block *)obj->buffer.pointer;
 793        total = obj->buffer.length / sizeof(struct guid_block);
 794
 795        for (i = 0; i < total; i++) {
 796                if (debug_dump_wdg)
 797                        wmi_dump_wdg(&gblock[i]);
 798
 799                wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
 800                if (!wblock)
 801                        return -ENOMEM;
 802
 803                wblock->handle = handle;
 804                wblock->gblock = gblock[i];
 805
 806                /*
 807                  Some WMI devices, like those for nVidia hooks, have a
 808                  duplicate GUID. It's not clear what we should do in this
 809                  case yet, so for now, we'll just ignore the duplicate
 810                  for device creation.
 811                */
 812                if (!guid_already_parsed(gblock[i].guid)) {
 813                        retval = wmi_create_device(&gblock[i], wblock, handle);
 814                        if (retval) {
 815                                wmi_free_devices();
 816                                goto out_free_pointer;
 817                        }
 818                }
 819
 820                list_add_tail(&wblock->list, &wmi_block_list);
 821
 822                if (debug_event) {
 823                        wblock->handler = wmi_notify_debug;
 824                        wmi_method_enable(wblock, 1);
 825                }
 826        }
 827
 828        retval = 0;
 829
 830out_free_pointer:
 831        kfree(out.pointer);
 832
 833        return retval;
 834}
 835
 836/*
 837 * WMI can have EmbeddedControl access regions. In which case, we just want to
 838 * hand these off to the EC driver.
 839 */
 840static acpi_status
 841acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
 842                      u32 bits, u64 *value,
 843                      void *handler_context, void *region_context)
 844{
 845        int result = 0, i = 0;
 846        u8 temp = 0;
 847
 848        if ((address > 0xFF) || !value)
 849                return AE_BAD_PARAMETER;
 850
 851        if (function != ACPI_READ && function != ACPI_WRITE)
 852                return AE_BAD_PARAMETER;
 853
 854        if (bits != 8)
 855                return AE_BAD_PARAMETER;
 856
 857        if (function == ACPI_READ) {
 858                result = ec_read(address, &temp);
 859                (*value) |= ((u64)temp) << i;
 860        } else {
 861                temp = 0xff & ((*value) >> i);
 862                result = ec_write(address, temp);
 863        }
 864
 865        switch (result) {
 866        case -EINVAL:
 867                return AE_BAD_PARAMETER;
 868                break;
 869        case -ENODEV:
 870                return AE_NOT_FOUND;
 871                break;
 872        case -ETIME:
 873                return AE_TIME;
 874                break;
 875        default:
 876                return AE_OK;
 877        }
 878}
 879
 880static void acpi_wmi_notify(struct acpi_device *device, u32 event)
 881{
 882        struct guid_block *block;
 883        struct wmi_block *wblock;
 884        struct list_head *p;
 885        char guid_string[37];
 886
 887        list_for_each(p, &wmi_block_list) {
 888                wblock = list_entry(p, struct wmi_block, list);
 889                block = &wblock->gblock;
 890
 891                if ((block->flags & ACPI_WMI_EVENT) &&
 892                        (block->notify_id == event)) {
 893                        if (wblock->handler)
 894                                wblock->handler(event, wblock->handler_data);
 895                        if (debug_event) {
 896                                wmi_gtoa(wblock->gblock.guid, guid_string);
 897                                pr_info("DEBUG Event GUID: %s\n", guid_string);
 898                        }
 899
 900                        acpi_bus_generate_netlink_event(
 901                                device->pnp.device_class, dev_name(&device->dev),
 902                                event, 0);
 903                        break;
 904                }
 905        }
 906}
 907
 908static int acpi_wmi_remove(struct acpi_device *device)
 909{
 910        acpi_remove_address_space_handler(device->handle,
 911                                ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
 912        wmi_free_devices();
 913
 914        return 0;
 915}
 916
 917static int acpi_wmi_add(struct acpi_device *device)
 918{
 919        acpi_status status;
 920        int error;
 921
 922        status = acpi_install_address_space_handler(device->handle,
 923                                                    ACPI_ADR_SPACE_EC,
 924                                                    &acpi_wmi_ec_space_handler,
 925                                                    NULL, NULL);
 926        if (ACPI_FAILURE(status)) {
 927                pr_err("Error installing EC region handler\n");
 928                return -ENODEV;
 929        }
 930
 931        error = parse_wdg(device->handle);
 932        if (error) {
 933                acpi_remove_address_space_handler(device->handle,
 934                                                  ACPI_ADR_SPACE_EC,
 935                                                  &acpi_wmi_ec_space_handler);
 936                pr_err("Failed to parse WDG method\n");
 937                return error;
 938        }
 939
 940        return 0;
 941}
 942
 943static int __init acpi_wmi_init(void)
 944{
 945        int error;
 946
 947        if (acpi_disabled)
 948                return -ENODEV;
 949
 950        error = class_register(&wmi_class);
 951        if (error)
 952                return error;
 953
 954        error = acpi_bus_register_driver(&acpi_wmi_driver);
 955        if (error) {
 956                pr_err("Error loading mapper\n");
 957                class_unregister(&wmi_class);
 958                return error;
 959        }
 960
 961        pr_info("Mapper loaded\n");
 962        return 0;
 963}
 964
 965static void __exit acpi_wmi_exit(void)
 966{
 967        acpi_bus_unregister_driver(&acpi_wmi_driver);
 968        class_unregister(&wmi_class);
 969
 970        pr_info("Mapper unloaded\n");
 971}
 972
 973subsys_initcall(acpi_wmi_init);
 974module_exit(acpi_wmi_exit);
 975