wmi.c 23 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 *  ACPI-WMI mapping driver
 *
 *  Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
 *
 *  GUID parsing code from ldm.c is:
 *   Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
 *   Copyright (c) 2001-2007 Anton Altaparmakov
 *   Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or (at
 *  your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

30 31
#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt

32 33 34
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
35
#include <linux/device.h>
36 37
#include <linux/list.h>
#include <linux/acpi.h>
38
#include <linux/slab.h>
39
#include <linux/module.h>
40 41 42 43 44 45 46 47 48 49 50
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>

ACPI_MODULE_NAME("wmi");
MODULE_AUTHOR("Carlos Corbacho");
MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
MODULE_LICENSE("GPL");

#define ACPI_WMI_CLASS "wmi"

static DEFINE_MUTEX(wmi_data_lock);
51
static LIST_HEAD(wmi_block_list);
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

struct guid_block {
	char guid[16];
	union {
		char object_id[2];
		struct {
			unsigned char notify_id;
			unsigned char reserved;
		};
	};
	u8 instance_count;
	u8 flags;
};

struct wmi_block {
	struct list_head list;
	struct guid_block gblock;
	acpi_handle handle;
	wmi_notify_handler handler;
	void *handler_data;
72
	struct device dev;
73 74 75 76 77 78 79 80 81 82 83 84
};


/*
 * If the GUID data block is marked as expensive, we must enable and
 * explicitily disable data collection.
 */
#define ACPI_WMI_EXPENSIVE   0x1
#define ACPI_WMI_METHOD      0x2	/* GUID is a method */
#define ACPI_WMI_STRING      0x4	/* GUID takes & returns a string */
#define ACPI_WMI_EVENT       0x8	/* GUID is an event */

85 86 87 88 89
static int debug_event;
module_param(debug_event, bool, 0444);
MODULE_PARM_DESC(debug_event,
		 "Log WMI Events [0/1]");

90 91 92 93 94
static int debug_dump_wdg;
module_param(debug_dump_wdg, bool, 0444);
MODULE_PARM_DESC(debug_dump_wdg,
		 "Dump available WMI interfaces [0/1]");

95 96
static int acpi_wmi_remove(struct acpi_device *device, int type);
static int acpi_wmi_add(struct acpi_device *device);
97
static void acpi_wmi_notify(struct acpi_device *device, u32 event);
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

static const struct acpi_device_id wmi_device_ids[] = {
	{"PNP0C14", 0},
	{"pnp0c14", 0},
	{"", 0},
};
MODULE_DEVICE_TABLE(acpi, wmi_device_ids);

static struct acpi_driver acpi_wmi_driver = {
	.name = "wmi",
	.class = ACPI_WMI_CLASS,
	.ids = wmi_device_ids,
	.ops = {
		.add = acpi_wmi_add,
		.remove = acpi_wmi_remove,
113
		.notify = acpi_wmi_notify,
114
	},
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
};

/*
 * GUID parsing functions
 */

/**
 * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
 * @src:  Pointer to at least 2 characters to convert.
 *
 * Convert a two character ASCII hex string to a number.
 *
 * Return:  0-255  Success, the byte was parsed correctly
 *          -1     Error, an invalid character was supplied
 */
static int wmi_parse_hexbyte(const u8 *src)
{
	int h;
133
	int value;
134 135

	/* high part */
136 137
	h = value = hex_to_bin(src[0]);
	if (value < 0)
138 139 140
		return -1;

	/* low part */
141 142 143
	value = hex_to_bin(src[1]);
	if (value >= 0)
		return (h << 4) | value;
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
	return -1;
}

/**
 * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
 * @src:   Memory block holding binary GUID (16 bytes)
 * @dest:  Memory block to hold byte swapped binary GUID (16 bytes)
 *
 * Byte swap a binary GUID to match it's real GUID value
 */
static void wmi_swap_bytes(u8 *src, u8 *dest)
{
	int i;

	for (i = 0; i <= 3; i++)
		memcpy(dest + i, src + (3 - i), 1);

	for (i = 0; i <= 1; i++)
		memcpy(dest + 4 + i, src + (5 - i), 1);

	for (i = 0; i <= 1; i++)
		memcpy(dest + 6 + i, src + (7 - i), 1);

	memcpy(dest + 8, src + 8, 8);
}

/**
 * wmi_parse_guid - Convert GUID from ASCII to binary
 * @src:   36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 * @dest:  Memory block to hold binary GUID (16 bytes)
 *
 * N.B. The GUID need not be NULL terminated.
 *
 * Return:  'true'   @dest contains binary GUID
 *          'false'  @dest contents are undefined
 */
static bool wmi_parse_guid(const u8 *src, u8 *dest)
{
	static const int size[] = { 4, 2, 2, 2, 6 };
	int i, j, v;

	if (src[8]  != '-' || src[13] != '-' ||
		src[18] != '-' || src[23] != '-')
		return false;

	for (j = 0; j < 5; j++, src++) {
		for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
			v = wmi_parse_hexbyte(src);
			if (v < 0)
				return false;
		}
	}

	return true;
}

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
/*
 * Convert a raw GUID to the ACII string representation
 */
static int wmi_gtoa(const char *in, char *out)
{
	int i;

	for (i = 3; i >= 0; i--)
		out += sprintf(out, "%02X", in[i] & 0xFF);

	out += sprintf(out, "-");
	out += sprintf(out, "%02X", in[5] & 0xFF);
	out += sprintf(out, "%02X", in[4] & 0xFF);
	out += sprintf(out, "-");
	out += sprintf(out, "%02X", in[7] & 0xFF);
	out += sprintf(out, "%02X", in[6] & 0xFF);
	out += sprintf(out, "-");
	out += sprintf(out, "%02X", in[8] & 0xFF);
	out += sprintf(out, "%02X", in[9] & 0xFF);
	out += sprintf(out, "-");

	for (i = 10; i <= 15; i++)
		out += sprintf(out, "%02X", in[i] & 0xFF);

224
	*out = '\0';
225 226 227
	return 0;
}

228 229 230 231 232 233 234 235 236 237
static bool find_guid(const char *guid_string, struct wmi_block **out)
{
	char tmp[16], guid_input[16];
	struct wmi_block *wblock;
	struct guid_block *block;
	struct list_head *p;

	wmi_parse_guid(guid_string, tmp);
	wmi_swap_bytes(tmp, guid_input);

238
	list_for_each(p, &wmi_block_list) {
239 240 241 242 243 244 245 246 247 248 249 250
		wblock = list_entry(p, struct wmi_block, list);
		block = &wblock->gblock;

		if (memcmp(block->guid, guid_input, 16) == 0) {
			if (out)
				*out = wblock;
			return 1;
		}
	}
	return 0;
}

251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
{
	struct guid_block *block = NULL;
	char method[5];
	struct acpi_object_list input;
	union acpi_object params[1];
	acpi_status status;
	acpi_handle handle;

	block = &wblock->gblock;
	handle = wblock->handle;

	if (!block)
		return AE_NOT_EXIST;

	input.count = 1;
	input.pointer = params;
	params[0].type = ACPI_TYPE_INTEGER;
	params[0].integer.value = enable;

	snprintf(method, 5, "WE%02X", block->notify_id);
	status = acpi_evaluate_object(handle, method, &input, NULL);

	if (status != AE_OK && status != AE_NOT_FOUND)
		return status;
	else
		return AE_OK;
}

280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
/*
 * Exported WMI functions
 */
/**
 * wmi_evaluate_method - Evaluate a WMI method
 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 * @instance: Instance index
 * @method_id: Method ID to call
 * &in: Buffer containing input for the method call
 * &out: Empty buffer to return the method results
 *
 * Call an ACPI-WMI method
 */
acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
{
	struct guid_block *block = NULL;
	struct wmi_block *wblock = NULL;
	acpi_handle handle;
	acpi_status status;
	struct acpi_object_list input;
	union acpi_object params[3];
302
	char method[5] = "WM";
303 304

	if (!find_guid(guid_string, &wblock))
305
		return AE_ERROR;
306 307 308 309

	block = &wblock->gblock;
	handle = wblock->handle;

Al Viro's avatar
Al Viro committed
310
	if (!(block->flags & ACPI_WMI_METHOD))
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
		return AE_BAD_DATA;

	if (block->instance_count < instance)
		return AE_BAD_PARAMETER;

	input.count = 2;
	input.pointer = params;
	params[0].type = ACPI_TYPE_INTEGER;
	params[0].integer.value = instance;
	params[1].type = ACPI_TYPE_INTEGER;
	params[1].integer.value = method_id;

	if (in) {
		input.count = 3;

		if (block->flags & ACPI_WMI_STRING) {
			params[2].type = ACPI_TYPE_STRING;
		} else {
			params[2].type = ACPI_TYPE_BUFFER;
		}
		params[2].buffer.length = in->length;
		params[2].buffer.pointer = in->pointer;
	}

	strncat(method, block->object_id, 2);

	status = acpi_evaluate_object(handle, method, &input, out);

	return status;
}
EXPORT_SYMBOL_GPL(wmi_evaluate_method);

/**
 * wmi_query_block - Return contents of a WMI block
 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 * @instance: Instance index
 * &out: Empty buffer to return the contents of the data block to
 *
 * Return the contents of an ACPI-WMI data block to a buffer
 */
acpi_status wmi_query_block(const char *guid_string, u8 instance,
struct acpi_buffer *out)
{
	struct guid_block *block = NULL;
	struct wmi_block *wblock = NULL;
356
	acpi_handle handle, wc_handle;
357 358 359
	acpi_status status, wc_status = AE_ERROR;
	struct acpi_object_list input, wc_input;
	union acpi_object wc_params[1], wq_params[1];
360 361
	char method[5];
	char wc_method[5] = "WC";
362 363 364 365 366

	if (!guid_string || !out)
		return AE_BAD_PARAMETER;

	if (!find_guid(guid_string, &wblock))
367
		return AE_ERROR;
368 369 370 371 372 373 374 375 376

	block = &wblock->gblock;
	handle = wblock->handle;

	if (block->instance_count < instance)
		return AE_BAD_PARAMETER;

	/* Check GUID is a data block */
	if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
377
		return AE_ERROR;
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400

	input.count = 1;
	input.pointer = wq_params;
	wq_params[0].type = ACPI_TYPE_INTEGER;
	wq_params[0].integer.value = instance;

	/*
	 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
	 * enable collection.
	 */
	if (block->flags & ACPI_WMI_EXPENSIVE) {
		wc_input.count = 1;
		wc_input.pointer = wc_params;
		wc_params[0].type = ACPI_TYPE_INTEGER;
		wc_params[0].integer.value = 1;

		strncat(wc_method, block->object_id, 2);

		/*
		 * Some GUIDs break the specification by declaring themselves
		 * expensive, but have no corresponding WCxx method. So we
		 * should not fail if this happens.
		 */
401 402 403 404
		wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
		if (ACPI_SUCCESS(wc_status))
			wc_status = acpi_evaluate_object(handle, wc_method,
				&wc_input, NULL);
405 406 407 408 409
	}

	strcpy(method, "WQ");
	strncat(method, block->object_id, 2);

410
	status = acpi_evaluate_object(handle, method, &input, out);
411 412 413 414 415

	/*
	 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
	 * the WQxx method failed - we should disable collection anyway.
	 */
416
	if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
		wc_params[0].integer.value = 0;
		status = acpi_evaluate_object(handle,
		wc_method, &wc_input, NULL);
	}

	return status;
}
EXPORT_SYMBOL_GPL(wmi_query_block);

/**
 * wmi_set_block - Write to a WMI block
 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 * @instance: Instance index
 * &in: Buffer containing new values for the data block
 *
 * Write the contents of the input buffer to an ACPI-WMI data block
 */
acpi_status wmi_set_block(const char *guid_string, u8 instance,
const struct acpi_buffer *in)
{
	struct guid_block *block = NULL;
	struct wmi_block *wblock = NULL;
	acpi_handle handle;
	struct acpi_object_list input;
	union acpi_object params[2];
442
	char method[5] = "WS";
443 444 445 446 447

	if (!guid_string || !in)
		return AE_BAD_DATA;

	if (!find_guid(guid_string, &wblock))
448
		return AE_ERROR;
449 450 451 452 453 454 455 456 457

	block = &wblock->gblock;
	handle = wblock->handle;

	if (block->instance_count < instance)
		return AE_BAD_PARAMETER;

	/* Check GUID is a data block */
	if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
458
		return AE_ERROR;
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478

	input.count = 2;
	input.pointer = params;
	params[0].type = ACPI_TYPE_INTEGER;
	params[0].integer.value = instance;

	if (block->flags & ACPI_WMI_STRING) {
		params[1].type = ACPI_TYPE_STRING;
	} else {
		params[1].type = ACPI_TYPE_BUFFER;
	}
	params[1].buffer.length = in->length;
	params[1].buffer.pointer = in->pointer;

	strncat(method, block->object_id, 2);

	return acpi_evaluate_object(handle, method, &input, NULL);
}
EXPORT_SYMBOL_GPL(wmi_set_block);

479
static void wmi_dump_wdg(const struct guid_block *g)
480 481 482 483
{
	char guid_string[37];

	wmi_gtoa(g->guid, guid_string);
484 485 486 487 488 489

	pr_info("%s:\n", guid_string);
	pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
	pr_info("\tnotify_id: %02X\n", g->notify_id);
	pr_info("\treserved: %02X\n", g->reserved);
	pr_info("\tinstance_count: %d\n", g->instance_count);
490
	pr_info("\tflags: %#x", g->flags);
491 492
	if (g->flags) {
		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 506 507 508
static void wmi_notify_debug(u32 value, void *context)
{
	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *obj;
509
	acpi_status status;
510

511 512
	status = wmi_get_event_data(value, &response);
	if (status != AE_OK) {
513
		pr_info("bad event status 0x%x\n", status);
514 515
		return;
	}
516 517 518 519 520 521

	obj = (union acpi_object *)response.pointer;

	if (!obj)
		return;

522
	pr_info("DEBUG Event ");
523 524
	switch(obj->type) {
	case ACPI_TYPE_BUFFER:
525
		pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
526 527
		break;
	case ACPI_TYPE_STRING:
528
		pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
529 530
		break;
	case ACPI_TYPE_INTEGER:
531
		pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
532 533
		break;
	case ACPI_TYPE_PACKAGE:
534
		pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
535 536
		break;
	default:
537
		pr_cont("object type 0x%X\n", obj->type);
538
	}
539
	kfree(obj);
540 541
}

542 543 544 545 546 547 548 549 550 551 552
/**
 * wmi_install_notify_handler - Register handler for WMI events
 * @handler: Function to handle notifications
 * @data: Data to be returned to handler when event is fired
 *
 * Register a handler for events sent to the ACPI-WMI mapper device.
 */
acpi_status wmi_install_notify_handler(const char *guid,
wmi_notify_handler handler, void *data)
{
	struct wmi_block *block;
553 554 555
	acpi_status status = AE_NOT_EXIST;
	char tmp[16], guid_input[16];
	struct list_head *p;
556 557 558 559

	if (!guid || !handler)
		return AE_BAD_PARAMETER;

560 561
	wmi_parse_guid(guid, tmp);
	wmi_swap_bytes(tmp, guid_input);
562

563 564 565 566 567 568 569 570
	list_for_each(p, &wmi_block_list) {
		acpi_status wmi_status;
		block = list_entry(p, struct wmi_block, list);

		if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
			if (block->handler &&
			    block->handler != wmi_notify_debug)
				return AE_ALREADY_ACQUIRED;
571

572 573
			block->handler = handler;
			block->handler_data = data;
574

575 576 577 578 579 580
			wmi_status = wmi_method_enable(block, 1);
			if ((wmi_status != AE_OK) ||
			    ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
				status = wmi_status;
		}
	}
581 582

	return status;
583 584 585 586 587 588 589 590 591 592 593
}
EXPORT_SYMBOL_GPL(wmi_install_notify_handler);

/**
 * wmi_uninstall_notify_handler - Unregister handler for WMI events
 *
 * Unregister handler for events sent to the ACPI-WMI mapper device.
 */
acpi_status wmi_remove_notify_handler(const char *guid)
{
	struct wmi_block *block;
594 595 596
	acpi_status status = AE_NOT_EXIST;
	char tmp[16], guid_input[16];
	struct list_head *p;
597 598 599 600

	if (!guid)
		return AE_BAD_PARAMETER;

601 602
	wmi_parse_guid(guid, tmp);
	wmi_swap_bytes(tmp, guid_input);
603

604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
	list_for_each(p, &wmi_block_list) {
		acpi_status wmi_status;
		block = list_entry(p, struct wmi_block, list);

		if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
			if (!block->handler ||
			    block->handler == wmi_notify_debug)
				return AE_NULL_ENTRY;

			if (debug_event) {
				block->handler = wmi_notify_debug;
				status = AE_OK;
			} else {
				wmi_status = wmi_method_enable(block, 0);
				block->handler = NULL;
				block->handler_data = NULL;
				if ((wmi_status != AE_OK) ||
				    ((wmi_status == AE_OK) &&
				     (status == AE_NOT_EXIST)))
					status = wmi_status;
			}
		}
626
	}
627

628
	return status;
629 630 631 632 633 634
}
EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);

/**
 * wmi_get_event_data - Get WMI data associated with an event
 *
635 636
 * @event: Event to find
 * @out: Buffer to hold event data. out->pointer should be freed with kfree()
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
 *
 * Returns extra data associated with an event in WMI.
 */
acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
{
	struct acpi_object_list input;
	union acpi_object params[1];
	struct guid_block *gblock;
	struct wmi_block *wblock;
	struct list_head *p;

	input.count = 1;
	input.pointer = params;
	params[0].type = ACPI_TYPE_INTEGER;
	params[0].integer.value = event;

653
	list_for_each(p, &wmi_block_list) {
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
		wblock = list_entry(p, struct wmi_block, list);
		gblock = &wblock->gblock;

		if ((gblock->flags & ACPI_WMI_EVENT) &&
			(gblock->notify_id == event))
			return acpi_evaluate_object(wblock->handle, "_WED",
				&input, out);
	}

	return AE_NOT_FOUND;
}
EXPORT_SYMBOL_GPL(wmi_get_event_data);

/**
 * wmi_has_guid - Check if a GUID is available
 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 *
 * Check if a given GUID is defined by _WDG
 */
bool wmi_has_guid(const char *guid_string)
{
	return find_guid(guid_string, NULL);
}
EXPORT_SYMBOL_GPL(wmi_has_guid);

679 680 681
/*
 * sysfs interface
 */
682
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
683 684 685 686 687 688 689 690 691 692 693 694 695
			     char *buf)
{
	char guid_string[37];
	struct wmi_block *wblock;

	wblock = dev_get_drvdata(dev);
	if (!wblock)
		return -ENOMEM;

	wmi_gtoa(wblock->gblock.guid, guid_string);

	return sprintf(buf, "wmi:%s\n", guid_string);
}
696 697 698 699 700

static struct device_attribute wmi_dev_attrs[] = {
	__ATTR_RO(modalias),
	__ATTR_NULL
};
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725

static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	char guid_string[37];

	struct wmi_block *wblock;

	if (add_uevent_var(env, "MODALIAS="))
		return -ENOMEM;

	wblock = dev_get_drvdata(dev);
	if (!wblock)
		return -ENOMEM;

	wmi_gtoa(wblock->gblock.guid, guid_string);

	strcpy(&env->buf[env->buflen - 1], "wmi:");
	memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
	env->buflen += 40;

	return 0;
}

static void wmi_dev_free(struct device *dev)
{
726 727 728
	struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);

	kfree(wmi_block);
729 730 731 732 733 734
}

static struct class wmi_class = {
	.name = "wmi",
	.dev_release = wmi_dev_free,
	.dev_uevent = wmi_dev_uevent,
735
	.dev_attrs = wmi_dev_attrs,
736 737
};

738 739
static int wmi_create_device(const struct guid_block *gblock,
			     struct wmi_block *wblock, acpi_handle handle)
740
{
741
	char guid_string[37];
742

743
	wblock->dev.class = &wmi_class;
744

745 746
	wmi_gtoa(gblock->guid, guid_string);
	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 759
	list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
		list_del(&wblock->list);
760 761
		if (wblock->dev.class)
			device_unregister(&wblock->dev);
762 763 764
		else
			kfree(wblock);
	}
765 766
}

767 768 769 770
static bool guid_already_parsed(const char *guid_string)
{
	struct wmi_block *wblock;

771
	list_for_each_entry(wblock, &wmi_block_list, list)
772
		if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
773 774
			return true;

775
	return false;
776 777
}

778 779 780
/*
 * Parse the _WDG method for the GUID data blocks
 */
781
static acpi_status parse_wdg(acpi_handle handle)
782 783 784
{
	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
	union acpi_object *obj;
785
	const struct guid_block *gblock;
786 787
	struct wmi_block *wblock;
	acpi_status status;
788
	int retval;
789 790 791 792
	u32 i, total;

	status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
	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 802
		goto out_free_pointer;
	}
803

804
	gblock = (const struct guid_block *)obj->buffer.pointer;
805 806 807
	total = obj->buffer.length / sizeof(struct guid_block);

	for (i = 0; i < total; i++) {
808 809 810 811 812 813 814 815 816 817
		if (debug_dump_wdg)
			wmi_dump_wdg(&gblock[i]);

		wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
		if (!wblock)
			return AE_NO_MEMORY;

		wblock->handle = handle;
		wblock->gblock = gblock[i];

818 819 820
		/*
		  Some WMI devices, like those for nVidia hooks, have a
		  duplicate GUID. It's not clear what we should do in this
821 822
		  case yet, so for now, we'll just ignore the duplicate
		  for device creation.
823
		*/
824 825 826 827
		if (!guid_already_parsed(gblock[i].guid)) {
			retval = wmi_create_device(&gblock[i], wblock, handle);
			if (retval) {
				wmi_free_devices();
828
				goto out_free_pointer;
829
			}
830
		}
831

832
		list_add_tail(&wblock->list, &wmi_block_list);
833

834 835
		if (debug_event) {
			wblock->handler = wmi_notify_debug;
836
			wmi_method_enable(wblock, 1);
837
		}
838 839
	}

840 841
	retval = 0;

Axel Lin's avatar
Axel Lin committed
842 843
out_free_pointer:
	kfree(out.pointer);
844

845
	return retval;
846 847 848 849 850 851 852 853
}

/*
 * WMI can have EmbeddedControl access regions. In which case, we just want to
 * hand these off to the EC driver.
 */
static acpi_status
acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
Lin Ming's avatar
Lin Ming committed
854
		      u32 bits, u64 *value,
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
		      void *handler_context, void *region_context)
{
	int result = 0, i = 0;
	u8 temp = 0;

	if ((address > 0xFF) || !value)
		return AE_BAD_PARAMETER;

	if (function != ACPI_READ && function != ACPI_WRITE)
		return AE_BAD_PARAMETER;

	if (bits != 8)
		return AE_BAD_PARAMETER;

	if (function == ACPI_READ) {
		result = ec_read(address, &temp);
Lin Ming's avatar
Lin Ming committed
871
		(*value) |= ((u64)temp) << i;
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
	} else {
		temp = 0xff & ((*value) >> i);
		result = ec_write(address, temp);
	}

	switch (result) {
	case -EINVAL:
		return AE_BAD_PARAMETER;
		break;
	case -ENODEV:
		return AE_NOT_FOUND;
		break;
	case -ETIME:
		return AE_TIME;
		break;
	default:
		return AE_OK;
	}
}

892
static void acpi_wmi_notify(struct acpi_device *device, u32 event)
893 894 895 896
{
	struct guid_block *block;
	struct wmi_block *wblock;
	struct list_head *p;
897
	char guid_string[37];
898

899
	list_for_each(p, &wmi_block_list) {
900 901 902 903 904 905 906
		wblock = list_entry(p, struct wmi_block, list);
		block = &wblock->gblock;

		if ((block->flags & ACPI_WMI_EVENT) &&
			(block->notify_id == event)) {
			if (wblock->handler)
				wblock->handler(event, wblock->handler_data);
907 908
			if (debug_event) {
				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 915 916 917 918 919 920 921 922 923
				event, 0);
			break;
		}
	}
}

static int acpi_wmi_remove(struct acpi_device *device, int type)
{
	acpi_remove_address_space_handler(device->handle,
				ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
924
	wmi_free_devices();
925 926 927 928

	return 0;
}

929
static int acpi_wmi_add(struct acpi_device *device)
930 931
{
	acpi_status status;
932
	int error;
933 934 935 936 937

	status = acpi_install_address_space_handler(device->handle,
						    ACPI_ADR_SPACE_EC,
						    &acpi_wmi_ec_space_handler,
						    NULL, NULL);
938
	if (ACPI_FAILURE(status)) {
939
		pr_err("Error installing EC region handler\n");
940
		return -ENODEV;
941
	}
942

943 944
	error = parse_wdg(device->handle);
	if (error) {
945 946 947
		acpi_remove_address_space_handler(device->handle,
						  ACPI_ADR_SPACE_EC,
						  &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 956
}

static int __init acpi_wmi_init(void)
{
957
	int error;
958 959 960 961

	if (acpi_disabled)
		return -ENODEV;

962 963 964
	error = class_register(&wmi_class);
	if (error)
		return error;
965

966 967 968 969 970
	error = acpi_bus_register_driver(&acpi_wmi_driver);
	if (error) {
		pr_err("Error loading mapper\n");
		class_unregister(&wmi_class);
		return error;
971 972
	}

973 974
	pr_info("Mapper loaded\n");
	return 0;
975 976 977 978 979
}

static void __exit acpi_wmi_exit(void)
{
	acpi_bus_unregister_driver(&acpi_wmi_driver);
980
	class_unregister(&wmi_class);
981

982
	pr_info("Mapper unloaded\n");
983 984 985 986
}

subsys_initcall(acpi_wmi_init);
module_exit(acpi_wmi_exit);