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#include <linux/kernel.h>
  31#include <linux/init.h>
  32#include <linux/types.h>
  33#include <linux/device.h>
  34#include <linux/list.h>
  35#include <linux/acpi.h>
  36#include <linux/slab.h>
  37#include <acpi/acpi_bus.h>
  38#include <acpi/acpi_drivers.h>
  39
  40ACPI_MODULE_NAME("wmi");
  41MODULE_AUTHOR("Carlos Corbacho");
  42MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
  43MODULE_LICENSE("GPL");
  44
  45#define ACPI_WMI_CLASS "wmi"
  46
  47#define PREFIX "ACPI: WMI: "
  48
  49static DEFINE_MUTEX(wmi_data_lock);
  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
  73static struct wmi_block wmi_blocks;
  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        unsigned int x; /* For correct wrapping */
 132        int h;
 133
 134        /* high part */
 135        x = src[0];
 136        if (x - '0' <= '9' - '0') {
 137                h = x - '0';
 138        } else if (x - 'a' <= 'f' - 'a') {
 139                h = x - 'a' + 10;
 140        } else if (x - 'A' <= 'F' - 'A') {
 141                h = x - 'A' + 10;
 142        } else {
 143                return -1;
 144        }
 145        h <<= 4;
 146
 147        /* low part */
 148        x = src[1];
 149        if (x - '0' <= '9' - '0')
 150                return h | (x - '0');
 151        if (x - 'a' <= 'f' - 'a')
 152                return h | (x - 'a' + 10);
 153        if (x - 'A' <= 'F' - 'A')
 154                return h | (x - 'A' + 10);
 155        return -1;
 156}
 157
 158/**
 159 * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
 160 * @src:   Memory block holding binary GUID (16 bytes)
 161 * @dest:  Memory block to hold byte swapped binary GUID (16 bytes)
 162 *
 163 * Byte swap a binary GUID to match it's real GUID value
 164 */
 165static void wmi_swap_bytes(u8 *src, u8 *dest)
 166{
 167        int i;
 168
 169        for (i = 0; i <= 3; i++)
 170                memcpy(dest + i, src + (3 - i), 1);
 171
 172        for (i = 0; i <= 1; i++)
 173                memcpy(dest + 4 + i, src + (5 - i), 1);
 174
 175        for (i = 0; i <= 1; i++)
 176                memcpy(dest + 6 + i, src + (7 - i), 1);
 177
 178        memcpy(dest + 8, src + 8, 8);
 179}
 180
 181/**
 182 * wmi_parse_guid - Convert GUID from ASCII to binary
 183 * @src:   36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 184 * @dest:  Memory block to hold binary GUID (16 bytes)
 185 *
 186 * N.B. The GUID need not be NULL terminated.
 187 *
 188 * Return:  'true'   @dest contains binary GUID
 189 *          'false'  @dest contents are undefined
 190 */
 191static bool wmi_parse_guid(const u8 *src, u8 *dest)
 192{
 193        static const int size[] = { 4, 2, 2, 2, 6 };
 194        int i, j, v;
 195
 196        if (src[8]  != '-' || src[13] != '-' ||
 197                src[18] != '-' || src[23] != '-')
 198                return false;
 199
 200        for (j = 0; j < 5; j++, src++) {
 201                for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
 202                        v = wmi_parse_hexbyte(src);
 203                        if (v < 0)
 204                                return false;
 205                }
 206        }
 207
 208        return true;
 209}
 210
 211/*
 212 * Convert a raw GUID to the ACII string representation
 213 */
 214static int wmi_gtoa(const char *in, char *out)
 215{
 216        int i;
 217
 218        for (i = 3; i >= 0; i--)
 219                out += sprintf(out, "%02X", in[i] & 0xFF);
 220
 221        out += sprintf(out, "-");
 222        out += sprintf(out, "%02X", in[5] & 0xFF);
 223        out += sprintf(out, "%02X", in[4] & 0xFF);
 224        out += sprintf(out, "-");
 225        out += sprintf(out, "%02X", in[7] & 0xFF);
 226        out += sprintf(out, "%02X", in[6] & 0xFF);
 227        out += sprintf(out, "-");
 228        out += sprintf(out, "%02X", in[8] & 0xFF);
 229        out += sprintf(out, "%02X", in[9] & 0xFF);
 230        out += sprintf(out, "-");
 231
 232        for (i = 10; i <= 15; i++)
 233                out += sprintf(out, "%02X", in[i] & 0xFF);
 234
 235        out = '\0';
 236        return 0;
 237}
 238
 239static bool find_guid(const char *guid_string, struct wmi_block **out)
 240{
 241        char tmp[16], guid_input[16];
 242        struct wmi_block *wblock;
 243        struct guid_block *block;
 244        struct list_head *p;
 245
 246        wmi_parse_guid(guid_string, tmp);
 247        wmi_swap_bytes(tmp, guid_input);
 248
 249        list_for_each(p, &wmi_blocks.list) {
 250                wblock = list_entry(p, struct wmi_block, list);
 251                block = &wblock->gblock;
 252
 253                if (memcmp(block->guid, guid_input, 16) == 0) {
 254                        if (out)
 255                                *out = wblock;
 256                        return 1;
 257                }
 258        }
 259        return 0;
 260}
 261
 262static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
 263{
 264        struct guid_block *block = NULL;
 265        char method[5];
 266        struct acpi_object_list input;
 267        union acpi_object params[1];
 268        acpi_status status;
 269        acpi_handle handle;
 270
 271        block = &wblock->gblock;
 272        handle = wblock->handle;
 273
 274        if (!block)
 275                return AE_NOT_EXIST;
 276
 277        input.count = 1;
 278        input.pointer = params;
 279        params[0].type = ACPI_TYPE_INTEGER;
 280        params[0].integer.value = enable;
 281
 282        snprintf(method, 5, "WE%02X", block->notify_id);
 283        status = acpi_evaluate_object(handle, method, &input, NULL);
 284
 285        if (status != AE_OK && status != AE_NOT_FOUND)
 286                return status;
 287        else
 288                return AE_OK;
 289}
 290
 291/*
 292 * Exported WMI functions
 293 */
 294/**
 295 * wmi_evaluate_method - Evaluate a WMI method
 296 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 297 * @instance: Instance index
 298 * @method_id: Method ID to call
 299 * &in: Buffer containing input for the method call
 300 * &out: Empty buffer to return the method results
 301 *
 302 * Call an ACPI-WMI method
 303 */
 304acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
 305u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
 306{
 307        struct guid_block *block = NULL;
 308        struct wmi_block *wblock = NULL;
 309        acpi_handle handle;
 310        acpi_status status;
 311        struct acpi_object_list input;
 312        union acpi_object params[3];
 313        char method[5] = "WM";
 314
 315        if (!find_guid(guid_string, &wblock))
 316                return AE_ERROR;
 317
 318        block = &wblock->gblock;
 319        handle = wblock->handle;
 320
 321        if (!(block->flags & ACPI_WMI_METHOD))
 322                return AE_BAD_DATA;
 323
 324        if (block->instance_count < instance)
 325                return AE_BAD_PARAMETER;
 326
 327        input.count = 2;
 328        input.pointer = params;
 329        params[0].type = ACPI_TYPE_INTEGER;
 330        params[0].integer.value = instance;
 331        params[1].type = ACPI_TYPE_INTEGER;
 332        params[1].integer.value = method_id;
 333
 334        if (in) {
 335                input.count = 3;
 336
 337                if (block->flags & ACPI_WMI_STRING) {
 338                        params[2].type = ACPI_TYPE_STRING;
 339                } else {
 340                        params[2].type = ACPI_TYPE_BUFFER;
 341                }
 342                params[2].buffer.length = in->length;
 343                params[2].buffer.pointer = in->pointer;
 344        }
 345
 346        strncat(method, block->object_id, 2);
 347
 348        status = acpi_evaluate_object(handle, method, &input, out);
 349
 350        return status;
 351}
 352EXPORT_SYMBOL_GPL(wmi_evaluate_method);
 353
 354/**
 355 * wmi_query_block - Return contents of a WMI block
 356 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 357 * @instance: Instance index
 358 * &out: Empty buffer to return the contents of the data block to
 359 *
 360 * Return the contents of an ACPI-WMI data block to a buffer
 361 */
 362acpi_status wmi_query_block(const char *guid_string, u8 instance,
 363struct acpi_buffer *out)
 364{
 365        struct guid_block *block = NULL;
 366        struct wmi_block *wblock = NULL;
 367        acpi_handle handle, wc_handle;
 368        acpi_status status, wc_status = AE_ERROR;
 369        struct acpi_object_list input, wc_input;
 370        union acpi_object wc_params[1], wq_params[1];
 371        char method[5];
 372        char wc_method[5] = "WC";
 373
 374        if (!guid_string || !out)
 375                return AE_BAD_PARAMETER;
 376
 377        if (!find_guid(guid_string, &wblock))
 378                return AE_ERROR;
 379
 380        block = &wblock->gblock;
 381        handle = wblock->handle;
 382
 383        if (block->instance_count < instance)
 384                return AE_BAD_PARAMETER;
 385
 386        /* Check GUID is a data block */
 387        if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
 388                return AE_ERROR;
 389
 390        input.count = 1;
 391        input.pointer = wq_params;
 392        wq_params[0].type = ACPI_TYPE_INTEGER;
 393        wq_params[0].integer.value = instance;
 394
 395        /*
 396         * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
 397         * enable collection.
 398         */
 399        if (block->flags & ACPI_WMI_EXPENSIVE) {
 400                wc_input.count = 1;
 401                wc_input.pointer = wc_params;
 402                wc_params[0].type = ACPI_TYPE_INTEGER;
 403                wc_params[0].integer.value = 1;
 404
 405                strncat(wc_method, block->object_id, 2);
 406
 407                /*
 408                 * Some GUIDs break the specification by declaring themselves
 409                 * expensive, but have no corresponding WCxx method. So we
 410                 * should not fail if this happens.
 411                 */
 412                wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
 413                if (ACPI_SUCCESS(wc_status))
 414                        wc_status = acpi_evaluate_object(handle, wc_method,
 415                                &wc_input, NULL);
 416        }
 417
 418        strcpy(method, "WQ");
 419        strncat(method, block->object_id, 2);
 420
 421        status = acpi_evaluate_object(handle, method, &input, out);
 422
 423        /*
 424         * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
 425         * the WQxx method failed - we should disable collection anyway.
 426         */
 427        if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
 428                wc_params[0].integer.value = 0;
 429                status = acpi_evaluate_object(handle,
 430                wc_method, &wc_input, NULL);
 431        }
 432
 433        return status;
 434}
 435EXPORT_SYMBOL_GPL(wmi_query_block);
 436
 437/**
 438 * wmi_set_block - Write to a WMI block
 439 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 440 * @instance: Instance index
 441 * &in: Buffer containing new values for the data block
 442 *
 443 * Write the contents of the input buffer to an ACPI-WMI data block
 444 */
 445acpi_status wmi_set_block(const char *guid_string, u8 instance,
 446const struct acpi_buffer *in)
 447{
 448        struct guid_block *block = NULL;
 449        struct wmi_block *wblock = NULL;
 450        acpi_handle handle;
 451        struct acpi_object_list input;
 452        union acpi_object params[2];
 453        char method[5] = "WS";
 454
 455        if (!guid_string || !in)
 456                return AE_BAD_DATA;
 457
 458        if (!find_guid(guid_string, &wblock))
 459                return AE_ERROR;
 460
 461        block = &wblock->gblock;
 462        handle = wblock->handle;
 463
 464        if (block->instance_count < instance)
 465                return AE_BAD_PARAMETER;
 466
 467        /* Check GUID is a data block */
 468        if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
 469                return AE_ERROR;
 470
 471        input.count = 2;
 472        input.pointer = params;
 473        params[0].type = ACPI_TYPE_INTEGER;
 474        params[0].integer.value = instance;
 475
 476        if (block->flags & ACPI_WMI_STRING) {
 477                params[1].type = ACPI_TYPE_STRING;
 478        } else {
 479                params[1].type = ACPI_TYPE_BUFFER;
 480        }
 481        params[1].buffer.length = in->length;
 482        params[1].buffer.pointer = in->pointer;
 483
 484        strncat(method, block->object_id, 2);
 485
 486        return acpi_evaluate_object(handle, method, &input, NULL);
 487}
 488EXPORT_SYMBOL_GPL(wmi_set_block);
 489
 490static void wmi_dump_wdg(struct guid_block *g)
 491{
 492        char guid_string[37];
 493
 494        wmi_gtoa(g->guid, guid_string);
 495        printk(KERN_INFO PREFIX "%s:\n", guid_string);
 496        printk(KERN_INFO PREFIX "\tobject_id: %c%c\n",
 497               g->object_id[0], g->object_id[1]);
 498        printk(KERN_INFO PREFIX "\tnotify_id: %02X\n", g->notify_id);
 499        printk(KERN_INFO PREFIX "\treserved: %02X\n", g->reserved);
 500        printk(KERN_INFO PREFIX "\tinstance_count: %d\n", g->instance_count);
 501        printk(KERN_INFO PREFIX "\tflags: %#x", g->flags);
 502        if (g->flags) {
 503                printk(" ");
 504                if (g->flags & ACPI_WMI_EXPENSIVE)
 505                        printk("ACPI_WMI_EXPENSIVE ");
 506                if (g->flags & ACPI_WMI_METHOD)
 507                        printk("ACPI_WMI_METHOD ");
 508                if (g->flags & ACPI_WMI_STRING)
 509                        printk("ACPI_WMI_STRING ");
 510                if (g->flags & ACPI_WMI_EVENT)
 511                        printk("ACPI_WMI_EVENT ");
 512        }
 513        printk("\n");
 514
 515}
 516
 517static void wmi_notify_debug(u32 value, void *context)
 518{
 519        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
 520        union acpi_object *obj;
 521
 522        wmi_get_event_data(value, &response);
 523
 524        obj = (union acpi_object *)response.pointer;
 525
 526        if (!obj)
 527                return;
 528
 529        printk(KERN_INFO PREFIX "DEBUG Event ");
 530        switch(obj->type) {
 531        case ACPI_TYPE_BUFFER:
 532                printk("BUFFER_TYPE - length %d\n", obj->buffer.length);
 533                break;
 534        case ACPI_TYPE_STRING:
 535                printk("STRING_TYPE - %s\n", obj->string.pointer);
 536                break;
 537        case ACPI_TYPE_INTEGER:
 538                printk("INTEGER_TYPE - %llu\n", obj->integer.value);
 539                break;
 540        case ACPI_TYPE_PACKAGE:
 541                printk("PACKAGE_TYPE - %d elements\n", obj->package.count);
 542                break;
 543        default:
 544                printk("object type 0x%X\n", obj->type);
 545        }
 546}
 547
 548/**
 549 * wmi_install_notify_handler - Register handler for WMI events
 550 * @handler: Function to handle notifications
 551 * @data: Data to be returned to handler when event is fired
 552 *
 553 * Register a handler for events sent to the ACPI-WMI mapper device.
 554 */
 555acpi_status wmi_install_notify_handler(const char *guid,
 556wmi_notify_handler handler, void *data)
 557{
 558        struct wmi_block *block;
 559        acpi_status status;
 560
 561        if (!guid || !handler)
 562                return AE_BAD_PARAMETER;
 563
 564        if (!find_guid(guid, &block))
 565                return AE_NOT_EXIST;
 566
 567        if (block->handler && block->handler != wmi_notify_debug)
 568                return AE_ALREADY_ACQUIRED;
 569
 570        block->handler = handler;
 571        block->handler_data = data;
 572
 573        status = wmi_method_enable(block, 1);
 574
 575        return status;
 576}
 577EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
 578
 579/**
 580 * wmi_uninstall_notify_handler - Unregister handler for WMI events
 581 *
 582 * Unregister handler for events sent to the ACPI-WMI mapper device.
 583 */
 584acpi_status wmi_remove_notify_handler(const char *guid)
 585{
 586        struct wmi_block *block;
 587        acpi_status status = AE_OK;
 588
 589        if (!guid)
 590                return AE_BAD_PARAMETER;
 591
 592        if (!find_guid(guid, &block))
 593                return AE_NOT_EXIST;
 594
 595        if (!block->handler || block->handler == wmi_notify_debug)
 596                return AE_NULL_ENTRY;
 597
 598        if (debug_event) {
 599                block->handler = wmi_notify_debug;
 600        } else {
 601                status = wmi_method_enable(block, 0);
 602                block->handler = NULL;
 603                block->handler_data = NULL;
 604        }
 605        return status;
 606}
 607EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
 608
 609/**
 610 * wmi_get_event_data - Get WMI data associated with an event
 611 *
 612 * @event: Event to find
 613 * @out: Buffer to hold event data. out->pointer should be freed with kfree()
 614 *
 615 * Returns extra data associated with an event in WMI.
 616 */
 617acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
 618{
 619        struct acpi_object_list input;
 620        union acpi_object params[1];
 621        struct guid_block *gblock;
 622        struct wmi_block *wblock;
 623        struct list_head *p;
 624
 625        input.count = 1;
 626        input.pointer = params;
 627        params[0].type = ACPI_TYPE_INTEGER;
 628        params[0].integer.value = event;
 629
 630        list_for_each(p, &wmi_blocks.list) {
 631                wblock = list_entry(p, struct wmi_block, list);
 632                gblock = &wblock->gblock;
 633
 634                if ((gblock->flags & ACPI_WMI_EVENT) &&
 635                        (gblock->notify_id == event))
 636                        return acpi_evaluate_object(wblock->handle, "_WED",
 637                                &input, out);
 638        }
 639
 640        return AE_NOT_FOUND;
 641}
 642EXPORT_SYMBOL_GPL(wmi_get_event_data);
 643
 644/**
 645 * wmi_has_guid - Check if a GUID is available
 646 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 647 *
 648 * Check if a given GUID is defined by _WDG
 649 */
 650bool wmi_has_guid(const char *guid_string)
 651{
 652        return find_guid(guid_string, NULL);
 653}
 654EXPORT_SYMBOL_GPL(wmi_has_guid);
 655
 656/*
 657 * sysfs interface
 658 */
 659static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
 660                             char *buf)
 661{
 662        char guid_string[37];
 663        struct wmi_block *wblock;
 664
 665        wblock = dev_get_drvdata(dev);
 666        if (!wblock)
 667                return -ENOMEM;
 668
 669        wmi_gtoa(wblock->gblock.guid, guid_string);
 670
 671        return sprintf(buf, "wmi:%s\n", guid_string);
 672}
 673static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 674
 675static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 676{
 677        char guid_string[37];
 678
 679        struct wmi_block *wblock;
 680
 681        if (add_uevent_var(env, "MODALIAS="))
 682                return -ENOMEM;
 683
 684        wblock = dev_get_drvdata(dev);
 685        if (!wblock)
 686                return -ENOMEM;
 687
 688        wmi_gtoa(wblock->gblock.guid, guid_string);
 689
 690        strcpy(&env->buf[env->buflen - 1], "wmi:");
 691        memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
 692        env->buflen += 40;
 693
 694        return 0;
 695}
 696
 697static void wmi_dev_free(struct device *dev)
 698{
 699        kfree(dev);
 700}
 701
 702static struct class wmi_class = {
 703        .name = "wmi",
 704        .dev_release = wmi_dev_free,
 705        .dev_uevent = wmi_dev_uevent,
 706};
 707
 708static int wmi_create_devs(void)
 709{
 710        int result;
 711        char guid_string[37];
 712        struct guid_block *gblock;
 713        struct wmi_block *wblock;
 714        struct list_head *p;
 715        struct device *guid_dev;
 716
 717        /* Create devices for all the GUIDs */
 718        list_for_each(p, &wmi_blocks.list) {
 719                wblock = list_entry(p, struct wmi_block, list);
 720
 721                guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
 722                if (!guid_dev)
 723                        return -ENOMEM;
 724
 725                wblock->dev = guid_dev;
 726
 727                guid_dev->class = &wmi_class;
 728                dev_set_drvdata(guid_dev, wblock);
 729
 730                gblock = &wblock->gblock;
 731
 732                wmi_gtoa(gblock->guid, guid_string);
 733                dev_set_name(guid_dev, guid_string);
 734
 735                result = device_register(guid_dev);
 736                if (result)
 737                        return result;
 738
 739                result = device_create_file(guid_dev, &dev_attr_modalias);
 740                if (result)
 741                        return result;
 742        }
 743
 744        return 0;
 745}
 746
 747static void wmi_remove_devs(void)
 748{
 749        struct guid_block *gblock;
 750        struct wmi_block *wblock;
 751        struct list_head *p;
 752        struct device *guid_dev;
 753
 754        /* Delete devices for all the GUIDs */
 755        list_for_each(p, &wmi_blocks.list) {
 756                wblock = list_entry(p, struct wmi_block, list);
 757
 758                guid_dev = wblock->dev;
 759                gblock = &wblock->gblock;
 760
 761                device_remove_file(guid_dev, &dev_attr_modalias);
 762
 763                device_unregister(guid_dev);
 764        }
 765}
 766
 767static void wmi_class_exit(void)
 768{
 769        wmi_remove_devs();
 770        class_unregister(&wmi_class);
 771}
 772
 773static int wmi_class_init(void)
 774{
 775        int ret;
 776
 777        ret = class_register(&wmi_class);
 778        if (ret)
 779                return ret;
 780
 781        ret = wmi_create_devs();
 782        if (ret)
 783                wmi_class_exit();
 784
 785        return ret;
 786}
 787
 788static bool guid_already_parsed(const char *guid_string)
 789{
 790        struct guid_block *gblock;
 791        struct wmi_block *wblock;
 792        struct list_head *p;
 793
 794        list_for_each(p, &wmi_blocks.list) {
 795                wblock = list_entry(p, struct wmi_block, list);
 796                gblock = &wblock->gblock;
 797
 798                if (strncmp(gblock->guid, guid_string, 16) == 0)
 799                        return true;
 800        }
 801        return false;
 802}
 803
 804/*
 805 * Parse the _WDG method for the GUID data blocks
 806 */
 807static __init acpi_status parse_wdg(acpi_handle handle)
 808{
 809        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
 810        union acpi_object *obj;
 811        struct guid_block *gblock;
 812        struct wmi_block *wblock;
 813        char guid_string[37];
 814        acpi_status status;
 815        u32 i, total;
 816
 817        status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
 818
 819        if (ACPI_FAILURE(status))
 820                return status;
 821
 822        obj = (union acpi_object *) out.pointer;
 823
 824        if (obj->type != ACPI_TYPE_BUFFER)
 825                return AE_ERROR;
 826
 827        total = obj->buffer.length / sizeof(struct guid_block);
 828
 829        gblock = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL);
 830        if (!gblock)
 831                return AE_NO_MEMORY;
 832
 833        for (i = 0; i < total; i++) {
 834                /*
 835                  Some WMI devices, like those for nVidia hooks, have a
 836                  duplicate GUID. It's not clear what we should do in this
 837                  case yet, so for now, we'll just ignore the duplicate.
 838                  Anyone who wants to add support for that device can come
 839                  up with a better workaround for the mess then.
 840                */
 841                if (guid_already_parsed(gblock[i].guid) == true) {
 842                        wmi_gtoa(gblock[i].guid, guid_string);
 843                        printk(KERN_INFO PREFIX "Skipping duplicate GUID %s\n",
 844                                guid_string);
 845                        continue;
 846                }
 847                if (debug_dump_wdg)
 848                        wmi_dump_wdg(&gblock[i]);
 849
 850                wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
 851                if (!wblock)
 852                        return AE_NO_MEMORY;
 853
 854                wblock->gblock = gblock[i];
 855                wblock->handle = handle;
 856                if (debug_event) {
 857                        wblock->handler = wmi_notify_debug;
 858                        status = wmi_method_enable(wblock, 1);
 859                }
 860                list_add_tail(&wblock->list, &wmi_blocks.list);
 861        }
 862
 863        kfree(out.pointer);
 864        kfree(gblock);
 865
 866        return status;
 867}
 868
 869/*
 870 * WMI can have EmbeddedControl access regions. In which case, we just want to
 871 * hand these off to the EC driver.
 872 */
 873static acpi_status
 874acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
 875                      u32 bits, u64 *value,
 876                      void *handler_context, void *region_context)
 877{
 878        int result = 0, i = 0;
 879        u8 temp = 0;
 880
 881        if ((address > 0xFF) || !value)
 882                return AE_BAD_PARAMETER;
 883
 884        if (function != ACPI_READ && function != ACPI_WRITE)
 885                return AE_BAD_PARAMETER;
 886
 887        if (bits != 8)
 888                return AE_BAD_PARAMETER;
 889
 890        if (function == ACPI_READ) {
 891                result = ec_read(address, &temp);
 892                (*value) |= ((u64)temp) << i;
 893        } else {
 894                temp = 0xff & ((*value) >> i);
 895                result = ec_write(address, temp);
 896        }
 897
 898        switch (result) {
 899        case -EINVAL:
 900                return AE_BAD_PARAMETER;
 901                break;
 902        case -ENODEV:
 903                return AE_NOT_FOUND;
 904                break;
 905        case -ETIME:
 906                return AE_TIME;
 907                break;
 908        default:
 909                return AE_OK;
 910        }
 911}
 912
 913static void acpi_wmi_notify(struct acpi_device *device, u32 event)
 914{
 915        struct guid_block *block;
 916        struct wmi_block *wblock;
 917        struct list_head *p;
 918        char guid_string[37];
 919
 920        list_for_each(p, &wmi_blocks.list) {
 921                wblock = list_entry(p, struct wmi_block, list);
 922                block = &wblock->gblock;
 923
 924                if ((block->flags & ACPI_WMI_EVENT) &&
 925                        (block->notify_id == event)) {
 926                        if (wblock->handler)
 927                                wblock->handler(event, wblock->handler_data);
 928                        if (debug_event) {
 929                                wmi_gtoa(wblock->gblock.guid, guid_string);
 930                                printk(KERN_INFO PREFIX "DEBUG Event GUID:"
 931                                       " %s\n", guid_string);
 932                        }
 933
 934                        acpi_bus_generate_netlink_event(
 935                                device->pnp.device_class, dev_name(&device->dev),
 936                                event, 0);
 937                        break;
 938                }
 939        }
 940}
 941
 942static int acpi_wmi_remove(struct acpi_device *device, int type)
 943{
 944        acpi_remove_address_space_handler(device->handle,
 945                                ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
 946
 947        return 0;
 948}
 949
 950static int __init acpi_wmi_add(struct acpi_device *device)
 951{
 952        acpi_status status;
 953        int result = 0;
 954
 955        status = acpi_install_address_space_handler(device->handle,
 956                                                    ACPI_ADR_SPACE_EC,
 957                                                    &acpi_wmi_ec_space_handler,
 958                                                    NULL, NULL);
 959        if (ACPI_FAILURE(status))
 960                return -ENODEV;
 961
 962        status = parse_wdg(device->handle);
 963        if (ACPI_FAILURE(status)) {
 964                printk(KERN_ERR PREFIX "Error installing EC region handler\n");
 965                return -ENODEV;
 966        }
 967
 968        return result;
 969}
 970
 971static int __init acpi_wmi_init(void)
 972{
 973        int result;
 974
 975        INIT_LIST_HEAD(&wmi_blocks.list);
 976
 977        if (acpi_disabled)
 978                return -ENODEV;
 979
 980        result = acpi_bus_register_driver(&acpi_wmi_driver);
 981
 982        if (result < 0) {
 983                printk(KERN_INFO PREFIX "Error loading mapper\n");
 984                return -ENODEV;
 985        }
 986
 987        result = wmi_class_init();
 988        if (result) {
 989                acpi_bus_unregister_driver(&acpi_wmi_driver);
 990                return result;
 991        }
 992
 993        printk(KERN_INFO PREFIX "Mapper loaded\n");
 994
 995        return result;
 996}
 997
 998static void __exit acpi_wmi_exit(void)
 999{
1000        struct list_head *p, *tmp;
1001        struct wmi_block *wblock;
1002
1003        wmi_class_exit();
1004
1005        acpi_bus_unregister_driver(&acpi_wmi_driver);
1006
1007        list_for_each_safe(p, tmp, &wmi_blocks.list) {
1008                wblock = list_entry(p, struct wmi_block, list);
1009
1010                list_del(p);
1011                kfree(wblock);
1012        }
1013
1014        printk(KERN_INFO PREFIX "Mapper unloaded\n");
1015}
1016
1017subsys_initcall(acpi_wmi_init);
1018module_exit(acpi_wmi_exit);
1019
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.