~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/platform/x86/wmi.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

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