xref: /openbmc/linux/drivers/platform/x86/wmi.c (revision e8e0929d)
1 /*
2  *  ACPI-WMI mapping driver
3  *
4  *  Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
5  *
6  *  GUID parsing code from ldm.c is:
7  *   Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
8  *   Copyright (c) 2001-2007 Anton Altaparmakov
9  *   Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
10  *
11  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12  *
13  *  This program is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2 of the License, or (at
16  *  your option) any later version.
17  *
18  *  This program is distributed in the hope that it will be useful, but
19  *  WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  *  General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License along
24  *  with this program; if not, write to the Free Software Foundation, Inc.,
25  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26  *
27  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28  */
29 
30 #include <linux/kernel.h>
31 #include <linux/init.h>
32 #include <linux/types.h>
33 #include <linux/list.h>
34 #include <linux/acpi.h>
35 #include <acpi/acpi_bus.h>
36 #include <acpi/acpi_drivers.h>
37 
38 ACPI_MODULE_NAME("wmi");
39 MODULE_AUTHOR("Carlos Corbacho");
40 MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
41 MODULE_LICENSE("GPL");
42 
43 #define ACPI_WMI_CLASS "wmi"
44 
45 #define PREFIX "ACPI: WMI: "
46 
47 static DEFINE_MUTEX(wmi_data_lock);
48 
49 struct guid_block {
50 	char guid[16];
51 	union {
52 		char object_id[2];
53 		struct {
54 			unsigned char notify_id;
55 			unsigned char reserved;
56 		};
57 	};
58 	u8 instance_count;
59 	u8 flags;
60 };
61 
62 struct wmi_block {
63 	struct list_head list;
64 	struct guid_block gblock;
65 	acpi_handle handle;
66 	wmi_notify_handler handler;
67 	void *handler_data;
68 };
69 
70 static struct wmi_block wmi_blocks;
71 
72 /*
73  * If the GUID data block is marked as expensive, we must enable and
74  * explicitily disable data collection.
75  */
76 #define ACPI_WMI_EXPENSIVE   0x1
77 #define ACPI_WMI_METHOD      0x2	/* GUID is a method */
78 #define ACPI_WMI_STRING      0x4	/* GUID takes & returns a string */
79 #define ACPI_WMI_EVENT       0x8	/* GUID is an event */
80 
81 static int acpi_wmi_remove(struct acpi_device *device, int type);
82 static int acpi_wmi_add(struct acpi_device *device);
83 static void acpi_wmi_notify(struct acpi_device *device, u32 event);
84 
85 static const struct acpi_device_id wmi_device_ids[] = {
86 	{"PNP0C14", 0},
87 	{"pnp0c14", 0},
88 	{"", 0},
89 };
90 MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
91 
92 static struct acpi_driver acpi_wmi_driver = {
93 	.name = "wmi",
94 	.class = ACPI_WMI_CLASS,
95 	.ids = wmi_device_ids,
96 	.ops = {
97 		.add = acpi_wmi_add,
98 		.remove = acpi_wmi_remove,
99 		.notify = acpi_wmi_notify,
100 		},
101 };
102 
103 /*
104  * GUID parsing functions
105  */
106 
107 /**
108  * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
109  * @src:  Pointer to at least 2 characters to convert.
110  *
111  * Convert a two character ASCII hex string to a number.
112  *
113  * Return:  0-255  Success, the byte was parsed correctly
114  *          -1     Error, an invalid character was supplied
115  */
116 static int wmi_parse_hexbyte(const u8 *src)
117 {
118 	unsigned int x; /* For correct wrapping */
119 	int h;
120 
121 	/* high part */
122 	x = src[0];
123 	if (x - '0' <= '9' - '0') {
124 		h = x - '0';
125 	} else if (x - 'a' <= 'f' - 'a') {
126 		h = x - 'a' + 10;
127 	} else if (x - 'A' <= 'F' - 'A') {
128 		h = x - 'A' + 10;
129 	} else {
130 		return -1;
131 	}
132 	h <<= 4;
133 
134 	/* low part */
135 	x = src[1];
136 	if (x - '0' <= '9' - '0')
137 		return h | (x - '0');
138 	if (x - 'a' <= 'f' - 'a')
139 		return h | (x - 'a' + 10);
140 	if (x - 'A' <= 'F' - 'A')
141 		return h | (x - 'A' + 10);
142 	return -1;
143 }
144 
145 /**
146  * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
147  * @src:   Memory block holding binary GUID (16 bytes)
148  * @dest:  Memory block to hold byte swapped binary GUID (16 bytes)
149  *
150  * Byte swap a binary GUID to match it's real GUID value
151  */
152 static void wmi_swap_bytes(u8 *src, u8 *dest)
153 {
154 	int i;
155 
156 	for (i = 0; i <= 3; i++)
157 		memcpy(dest + i, src + (3 - i), 1);
158 
159 	for (i = 0; i <= 1; i++)
160 		memcpy(dest + 4 + i, src + (5 - i), 1);
161 
162 	for (i = 0; i <= 1; i++)
163 		memcpy(dest + 6 + i, src + (7 - i), 1);
164 
165 	memcpy(dest + 8, src + 8, 8);
166 }
167 
168 /**
169  * wmi_parse_guid - Convert GUID from ASCII to binary
170  * @src:   36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
171  * @dest:  Memory block to hold binary GUID (16 bytes)
172  *
173  * N.B. The GUID need not be NULL terminated.
174  *
175  * Return:  'true'   @dest contains binary GUID
176  *          'false'  @dest contents are undefined
177  */
178 static bool wmi_parse_guid(const u8 *src, u8 *dest)
179 {
180 	static const int size[] = { 4, 2, 2, 2, 6 };
181 	int i, j, v;
182 
183 	if (src[8]  != '-' || src[13] != '-' ||
184 		src[18] != '-' || src[23] != '-')
185 		return false;
186 
187 	for (j = 0; j < 5; j++, src++) {
188 		for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
189 			v = wmi_parse_hexbyte(src);
190 			if (v < 0)
191 				return false;
192 		}
193 	}
194 
195 	return true;
196 }
197 
198 static bool find_guid(const char *guid_string, struct wmi_block **out)
199 {
200 	char tmp[16], guid_input[16];
201 	struct wmi_block *wblock;
202 	struct guid_block *block;
203 	struct list_head *p;
204 
205 	wmi_parse_guid(guid_string, tmp);
206 	wmi_swap_bytes(tmp, guid_input);
207 
208 	list_for_each(p, &wmi_blocks.list) {
209 		wblock = list_entry(p, struct wmi_block, list);
210 		block = &wblock->gblock;
211 
212 		if (memcmp(block->guid, guid_input, 16) == 0) {
213 			if (out)
214 				*out = wblock;
215 			return 1;
216 		}
217 	}
218 	return 0;
219 }
220 
221 static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
222 {
223 	struct guid_block *block = NULL;
224 	char method[5];
225 	struct acpi_object_list input;
226 	union acpi_object params[1];
227 	acpi_status status;
228 	acpi_handle handle;
229 
230 	block = &wblock->gblock;
231 	handle = wblock->handle;
232 
233 	if (!block)
234 		return AE_NOT_EXIST;
235 
236 	input.count = 1;
237 	input.pointer = params;
238 	params[0].type = ACPI_TYPE_INTEGER;
239 	params[0].integer.value = enable;
240 
241 	snprintf(method, 5, "WE%02X", block->notify_id);
242 	status = acpi_evaluate_object(handle, method, &input, NULL);
243 
244 	if (status != AE_OK && status != AE_NOT_FOUND)
245 		return status;
246 	else
247 		return AE_OK;
248 }
249 
250 /*
251  * Exported WMI functions
252  */
253 /**
254  * wmi_evaluate_method - Evaluate a WMI method
255  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
256  * @instance: Instance index
257  * @method_id: Method ID to call
258  * &in: Buffer containing input for the method call
259  * &out: Empty buffer to return the method results
260  *
261  * Call an ACPI-WMI method
262  */
263 acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
264 u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
265 {
266 	struct guid_block *block = NULL;
267 	struct wmi_block *wblock = NULL;
268 	acpi_handle handle;
269 	acpi_status status;
270 	struct acpi_object_list input;
271 	union acpi_object params[3];
272 	char method[5] = "WM";
273 
274 	if (!find_guid(guid_string, &wblock))
275 		return AE_ERROR;
276 
277 	block = &wblock->gblock;
278 	handle = wblock->handle;
279 
280 	if (!(block->flags & ACPI_WMI_METHOD))
281 		return AE_BAD_DATA;
282 
283 	if (block->instance_count < instance)
284 		return AE_BAD_PARAMETER;
285 
286 	input.count = 2;
287 	input.pointer = params;
288 	params[0].type = ACPI_TYPE_INTEGER;
289 	params[0].integer.value = instance;
290 	params[1].type = ACPI_TYPE_INTEGER;
291 	params[1].integer.value = method_id;
292 
293 	if (in) {
294 		input.count = 3;
295 
296 		if (block->flags & ACPI_WMI_STRING) {
297 			params[2].type = ACPI_TYPE_STRING;
298 		} else {
299 			params[2].type = ACPI_TYPE_BUFFER;
300 		}
301 		params[2].buffer.length = in->length;
302 		params[2].buffer.pointer = in->pointer;
303 	}
304 
305 	strncat(method, block->object_id, 2);
306 
307 	status = acpi_evaluate_object(handle, method, &input, out);
308 
309 	return status;
310 }
311 EXPORT_SYMBOL_GPL(wmi_evaluate_method);
312 
313 /**
314  * wmi_query_block - Return contents of a WMI block
315  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
316  * @instance: Instance index
317  * &out: Empty buffer to return the contents of the data block to
318  *
319  * Return the contents of an ACPI-WMI data block to a buffer
320  */
321 acpi_status wmi_query_block(const char *guid_string, u8 instance,
322 struct acpi_buffer *out)
323 {
324 	struct guid_block *block = NULL;
325 	struct wmi_block *wblock = NULL;
326 	acpi_handle handle, wc_handle;
327 	acpi_status status, wc_status = AE_ERROR;
328 	struct acpi_object_list input, wc_input;
329 	union acpi_object wc_params[1], wq_params[1];
330 	char method[5];
331 	char wc_method[5] = "WC";
332 
333 	if (!guid_string || !out)
334 		return AE_BAD_PARAMETER;
335 
336 	if (!find_guid(guid_string, &wblock))
337 		return AE_ERROR;
338 
339 	block = &wblock->gblock;
340 	handle = wblock->handle;
341 
342 	if (block->instance_count < instance)
343 		return AE_BAD_PARAMETER;
344 
345 	/* Check GUID is a data block */
346 	if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
347 		return AE_ERROR;
348 
349 	input.count = 1;
350 	input.pointer = wq_params;
351 	wq_params[0].type = ACPI_TYPE_INTEGER;
352 	wq_params[0].integer.value = instance;
353 
354 	/*
355 	 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
356 	 * enable collection.
357 	 */
358 	if (block->flags & ACPI_WMI_EXPENSIVE) {
359 		wc_input.count = 1;
360 		wc_input.pointer = wc_params;
361 		wc_params[0].type = ACPI_TYPE_INTEGER;
362 		wc_params[0].integer.value = 1;
363 
364 		strncat(wc_method, block->object_id, 2);
365 
366 		/*
367 		 * Some GUIDs break the specification by declaring themselves
368 		 * expensive, but have no corresponding WCxx method. So we
369 		 * should not fail if this happens.
370 		 */
371 		wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
372 		if (ACPI_SUCCESS(wc_status))
373 			wc_status = acpi_evaluate_object(handle, wc_method,
374 				&wc_input, NULL);
375 	}
376 
377 	strcpy(method, "WQ");
378 	strncat(method, block->object_id, 2);
379 
380 	status = acpi_evaluate_object(handle, method, &input, out);
381 
382 	/*
383 	 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
384 	 * the WQxx method failed - we should disable collection anyway.
385 	 */
386 	if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
387 		wc_params[0].integer.value = 0;
388 		status = acpi_evaluate_object(handle,
389 		wc_method, &wc_input, NULL);
390 	}
391 
392 	return status;
393 }
394 EXPORT_SYMBOL_GPL(wmi_query_block);
395 
396 /**
397  * wmi_set_block - Write to a WMI block
398  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
399  * @instance: Instance index
400  * &in: Buffer containing new values for the data block
401  *
402  * Write the contents of the input buffer to an ACPI-WMI data block
403  */
404 acpi_status wmi_set_block(const char *guid_string, u8 instance,
405 const struct acpi_buffer *in)
406 {
407 	struct guid_block *block = NULL;
408 	struct wmi_block *wblock = NULL;
409 	acpi_handle handle;
410 	struct acpi_object_list input;
411 	union acpi_object params[2];
412 	char method[5] = "WS";
413 
414 	if (!guid_string || !in)
415 		return AE_BAD_DATA;
416 
417 	if (!find_guid(guid_string, &wblock))
418 		return AE_ERROR;
419 
420 	block = &wblock->gblock;
421 	handle = wblock->handle;
422 
423 	if (block->instance_count < instance)
424 		return AE_BAD_PARAMETER;
425 
426 	/* Check GUID is a data block */
427 	if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
428 		return AE_ERROR;
429 
430 	input.count = 2;
431 	input.pointer = params;
432 	params[0].type = ACPI_TYPE_INTEGER;
433 	params[0].integer.value = instance;
434 
435 	if (block->flags & ACPI_WMI_STRING) {
436 		params[1].type = ACPI_TYPE_STRING;
437 	} else {
438 		params[1].type = ACPI_TYPE_BUFFER;
439 	}
440 	params[1].buffer.length = in->length;
441 	params[1].buffer.pointer = in->pointer;
442 
443 	strncat(method, block->object_id, 2);
444 
445 	return acpi_evaluate_object(handle, method, &input, NULL);
446 }
447 EXPORT_SYMBOL_GPL(wmi_set_block);
448 
449 /**
450  * wmi_install_notify_handler - Register handler for WMI events
451  * @handler: Function to handle notifications
452  * @data: Data to be returned to handler when event is fired
453  *
454  * Register a handler for events sent to the ACPI-WMI mapper device.
455  */
456 acpi_status wmi_install_notify_handler(const char *guid,
457 wmi_notify_handler handler, void *data)
458 {
459 	struct wmi_block *block;
460 	acpi_status status;
461 
462 	if (!guid || !handler)
463 		return AE_BAD_PARAMETER;
464 
465 	find_guid(guid, &block);
466 	if (!block)
467 		return AE_NOT_EXIST;
468 
469 	if (block->handler)
470 		return AE_ALREADY_ACQUIRED;
471 
472 	block->handler = handler;
473 	block->handler_data = data;
474 
475 	status = wmi_method_enable(block, 1);
476 
477 	return status;
478 }
479 EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
480 
481 /**
482  * wmi_uninstall_notify_handler - Unregister handler for WMI events
483  *
484  * Unregister handler for events sent to the ACPI-WMI mapper device.
485  */
486 acpi_status wmi_remove_notify_handler(const char *guid)
487 {
488 	struct wmi_block *block;
489 	acpi_status status;
490 
491 	if (!guid)
492 		return AE_BAD_PARAMETER;
493 
494 	find_guid(guid, &block);
495 	if (!block)
496 		return AE_NOT_EXIST;
497 
498 	if (!block->handler)
499 		return AE_NULL_ENTRY;
500 
501 	status = wmi_method_enable(block, 0);
502 
503 	block->handler = NULL;
504 	block->handler_data = NULL;
505 
506 	return status;
507 }
508 EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
509 
510 /**
511  * wmi_get_event_data - Get WMI data associated with an event
512  *
513  * @event - Event to find
514  * &out - Buffer to hold event data
515  *
516  * Returns extra data associated with an event in WMI.
517  */
518 acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
519 {
520 	struct acpi_object_list input;
521 	union acpi_object params[1];
522 	struct guid_block *gblock;
523 	struct wmi_block *wblock;
524 	struct list_head *p;
525 
526 	input.count = 1;
527 	input.pointer = params;
528 	params[0].type = ACPI_TYPE_INTEGER;
529 	params[0].integer.value = event;
530 
531 	list_for_each(p, &wmi_blocks.list) {
532 		wblock = list_entry(p, struct wmi_block, list);
533 		gblock = &wblock->gblock;
534 
535 		if ((gblock->flags & ACPI_WMI_EVENT) &&
536 			(gblock->notify_id == event))
537 			return acpi_evaluate_object(wblock->handle, "_WED",
538 				&input, out);
539 	}
540 
541 	return AE_NOT_FOUND;
542 }
543 EXPORT_SYMBOL_GPL(wmi_get_event_data);
544 
545 /**
546  * wmi_has_guid - Check if a GUID is available
547  * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
548  *
549  * Check if a given GUID is defined by _WDG
550  */
551 bool wmi_has_guid(const char *guid_string)
552 {
553 	return find_guid(guid_string, NULL);
554 }
555 EXPORT_SYMBOL_GPL(wmi_has_guid);
556 
557 /*
558  * Parse the _WDG method for the GUID data blocks
559  */
560 static __init acpi_status parse_wdg(acpi_handle handle)
561 {
562 	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
563 	union acpi_object *obj;
564 	struct guid_block *gblock;
565 	struct wmi_block *wblock;
566 	acpi_status status;
567 	u32 i, total;
568 
569 	status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
570 
571 	if (ACPI_FAILURE(status))
572 		return status;
573 
574 	obj = (union acpi_object *) out.pointer;
575 
576 	if (obj->type != ACPI_TYPE_BUFFER)
577 		return AE_ERROR;
578 
579 	total = obj->buffer.length / sizeof(struct guid_block);
580 
581 	gblock = kzalloc(obj->buffer.length, GFP_KERNEL);
582 	if (!gblock)
583 		return AE_NO_MEMORY;
584 
585 	memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
586 
587 	for (i = 0; i < total; i++) {
588 		wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
589 		if (!wblock)
590 			return AE_NO_MEMORY;
591 
592 		wblock->gblock = gblock[i];
593 		wblock->handle = handle;
594 		list_add_tail(&wblock->list, &wmi_blocks.list);
595 	}
596 
597 	kfree(out.pointer);
598 	kfree(gblock);
599 
600 	return status;
601 }
602 
603 /*
604  * WMI can have EmbeddedControl access regions. In which case, we just want to
605  * hand these off to the EC driver.
606  */
607 static acpi_status
608 acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
609 		      u32 bits, acpi_integer * value,
610 		      void *handler_context, void *region_context)
611 {
612 	int result = 0, i = 0;
613 	u8 temp = 0;
614 
615 	if ((address > 0xFF) || !value)
616 		return AE_BAD_PARAMETER;
617 
618 	if (function != ACPI_READ && function != ACPI_WRITE)
619 		return AE_BAD_PARAMETER;
620 
621 	if (bits != 8)
622 		return AE_BAD_PARAMETER;
623 
624 	if (function == ACPI_READ) {
625 		result = ec_read(address, &temp);
626 		(*value) |= ((acpi_integer)temp) << i;
627 	} else {
628 		temp = 0xff & ((*value) >> i);
629 		result = ec_write(address, temp);
630 	}
631 
632 	switch (result) {
633 	case -EINVAL:
634 		return AE_BAD_PARAMETER;
635 		break;
636 	case -ENODEV:
637 		return AE_NOT_FOUND;
638 		break;
639 	case -ETIME:
640 		return AE_TIME;
641 		break;
642 	default:
643 		return AE_OK;
644 	}
645 }
646 
647 static void acpi_wmi_notify(struct acpi_device *device, u32 event)
648 {
649 	struct guid_block *block;
650 	struct wmi_block *wblock;
651 	struct list_head *p;
652 
653 	list_for_each(p, &wmi_blocks.list) {
654 		wblock = list_entry(p, struct wmi_block, list);
655 		block = &wblock->gblock;
656 
657 		if ((block->flags & ACPI_WMI_EVENT) &&
658 			(block->notify_id == event)) {
659 			if (wblock->handler)
660 				wblock->handler(event, wblock->handler_data);
661 
662 			acpi_bus_generate_netlink_event(
663 				device->pnp.device_class, dev_name(&device->dev),
664 				event, 0);
665 			break;
666 		}
667 	}
668 }
669 
670 static int acpi_wmi_remove(struct acpi_device *device, int type)
671 {
672 	acpi_remove_address_space_handler(device->handle,
673 				ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
674 
675 	return 0;
676 }
677 
678 static int __init acpi_wmi_add(struct acpi_device *device)
679 {
680 	acpi_status status;
681 	int result = 0;
682 
683 	status = acpi_install_address_space_handler(device->handle,
684 						    ACPI_ADR_SPACE_EC,
685 						    &acpi_wmi_ec_space_handler,
686 						    NULL, NULL);
687 	if (ACPI_FAILURE(status))
688 		return -ENODEV;
689 
690 	status = parse_wdg(device->handle);
691 	if (ACPI_FAILURE(status)) {
692 		printk(KERN_ERR PREFIX "Error installing EC region handler\n");
693 		return -ENODEV;
694 	}
695 
696 	return result;
697 }
698 
699 static int __init acpi_wmi_init(void)
700 {
701 	int result;
702 
703 	INIT_LIST_HEAD(&wmi_blocks.list);
704 
705 	if (acpi_disabled)
706 		return -ENODEV;
707 
708 	result = acpi_bus_register_driver(&acpi_wmi_driver);
709 
710 	if (result < 0) {
711 		printk(KERN_INFO PREFIX "Error loading mapper\n");
712 	} else {
713 		printk(KERN_INFO PREFIX "Mapper loaded\n");
714 	}
715 
716 	return result;
717 }
718 
719 static void __exit acpi_wmi_exit(void)
720 {
721 	struct list_head *p, *tmp;
722 	struct wmi_block *wblock;
723 
724 	acpi_bus_unregister_driver(&acpi_wmi_driver);
725 
726 	list_for_each_safe(p, tmp, &wmi_blocks.list) {
727 		wblock = list_entry(p, struct wmi_block, list);
728 
729 		list_del(p);
730 		kfree(wblock);
731 	}
732 
733 	printk(KERN_INFO PREFIX "Mapper unloaded\n");
734 }
735 
736 subsys_initcall(acpi_wmi_init);
737 module_exit(acpi_wmi_exit);
738