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