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