2 * ACPI-WMI mapping driver
4 * Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
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>
11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
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.
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.
27 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30 #include <linux/kernel.h>
31 #include <linux/init.h>
32 #include <linux/types.h>
33 #include <linux/device.h>
34 #include <linux/list.h>
35 #include <linux/acpi.h>
36 #include <acpi/acpi_bus.h>
37 #include <acpi/acpi_drivers.h>
39 ACPI_MODULE_NAME("wmi");
40 MODULE_AUTHOR("Carlos Corbacho");
41 MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
42 MODULE_LICENSE("GPL");
44 #define ACPI_WMI_CLASS "wmi"
46 #define PREFIX "ACPI: WMI: "
48 static DEFINE_MUTEX(wmi_data_lock
);
55 unsigned char notify_id
;
56 unsigned char reserved
;
64 struct list_head list
;
65 struct guid_block gblock
;
67 wmi_notify_handler handler
;
72 static struct wmi_block wmi_blocks
;
75 * If the GUID data block is marked as expensive, we must enable and
76 * explicitily disable data collection.
78 #define ACPI_WMI_EXPENSIVE 0x1
79 #define ACPI_WMI_METHOD 0x2 /* GUID is a method */
80 #define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */
81 #define ACPI_WMI_EVENT 0x8 /* GUID is an event */
83 static int acpi_wmi_remove(struct acpi_device
*device
, int type
);
84 static int acpi_wmi_add(struct acpi_device
*device
);
85 static void acpi_wmi_notify(struct acpi_device
*device
, u32 event
);
87 static const struct acpi_device_id wmi_device_ids
[] = {
92 MODULE_DEVICE_TABLE(acpi
, wmi_device_ids
);
94 static struct acpi_driver acpi_wmi_driver
= {
96 .class = ACPI_WMI_CLASS
,
97 .ids
= wmi_device_ids
,
100 .remove
= acpi_wmi_remove
,
101 .notify
= acpi_wmi_notify
,
106 * GUID parsing functions
110 * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
111 * @src: Pointer to at least 2 characters to convert.
113 * Convert a two character ASCII hex string to a number.
115 * Return: 0-255 Success, the byte was parsed correctly
116 * -1 Error, an invalid character was supplied
118 static int wmi_parse_hexbyte(const u8
*src
)
120 unsigned int x
; /* For correct wrapping */
125 if (x
- '0' <= '9' - '0') {
127 } else if (x
- 'a' <= 'f' - 'a') {
129 } else if (x
- 'A' <= 'F' - 'A') {
138 if (x
- '0' <= '9' - '0')
139 return h
| (x
- '0');
140 if (x
- 'a' <= 'f' - 'a')
141 return h
| (x
- 'a' + 10);
142 if (x
- 'A' <= 'F' - 'A')
143 return h
| (x
- 'A' + 10);
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)
152 * Byte swap a binary GUID to match it's real GUID value
154 static void wmi_swap_bytes(u8
*src
, u8
*dest
)
158 for (i
= 0; i
<= 3; i
++)
159 memcpy(dest
+ i
, src
+ (3 - i
), 1);
161 for (i
= 0; i
<= 1; i
++)
162 memcpy(dest
+ 4 + i
, src
+ (5 - i
), 1);
164 for (i
= 0; i
<= 1; i
++)
165 memcpy(dest
+ 6 + i
, src
+ (7 - i
), 1);
167 memcpy(dest
+ 8, src
+ 8, 8);
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)
175 * N.B. The GUID need not be NULL terminated.
177 * Return: 'true' @dest contains binary GUID
178 * 'false' @dest contents are undefined
180 static bool wmi_parse_guid(const u8
*src
, u8
*dest
)
182 static const int size
[] = { 4, 2, 2, 2, 6 };
185 if (src
[8] != '-' || src
[13] != '-' ||
186 src
[18] != '-' || src
[23] != '-')
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
);
201 * Convert a raw GUID to the ACII string representation
203 static int wmi_gtoa(const char *in
, char *out
)
207 for (i
= 3; i
>= 0; i
--)
208 out
+= sprintf(out
, "%02X", in
[i
] & 0xFF);
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
, "-");
221 for (i
= 10; i
<= 15; i
++)
222 out
+= sprintf(out
, "%02X", in
[i
] & 0xFF);
228 static bool find_guid(const char *guid_string
, struct wmi_block
**out
)
230 char tmp
[16], guid_input
[16];
231 struct wmi_block
*wblock
;
232 struct guid_block
*block
;
235 wmi_parse_guid(guid_string
, tmp
);
236 wmi_swap_bytes(tmp
, guid_input
);
238 list_for_each(p
, &wmi_blocks
.list
) {
239 wblock
= list_entry(p
, struct wmi_block
, list
);
240 block
= &wblock
->gblock
;
242 if (memcmp(block
->guid
, guid_input
, 16) == 0) {
251 static acpi_status
wmi_method_enable(struct wmi_block
*wblock
, int enable
)
253 struct guid_block
*block
= NULL
;
255 struct acpi_object_list input
;
256 union acpi_object params
[1];
260 block
= &wblock
->gblock
;
261 handle
= wblock
->handle
;
267 input
.pointer
= params
;
268 params
[0].type
= ACPI_TYPE_INTEGER
;
269 params
[0].integer
.value
= enable
;
271 snprintf(method
, 5, "WE%02X", block
->notify_id
);
272 status
= acpi_evaluate_object(handle
, method
, &input
, NULL
);
274 if (status
!= AE_OK
&& status
!= AE_NOT_FOUND
)
281 * Exported WMI functions
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
291 * Call an ACPI-WMI method
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
)
296 struct guid_block
*block
= NULL
;
297 struct wmi_block
*wblock
= NULL
;
300 struct acpi_object_list input
;
301 union acpi_object params
[3];
302 char method
[5] = "WM";
304 if (!find_guid(guid_string
, &wblock
))
307 block
= &wblock
->gblock
;
308 handle
= wblock
->handle
;
310 if (!(block
->flags
& ACPI_WMI_METHOD
))
313 if (block
->instance_count
< instance
)
314 return AE_BAD_PARAMETER
;
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
;
326 if (block
->flags
& ACPI_WMI_STRING
) {
327 params
[2].type
= ACPI_TYPE_STRING
;
329 params
[2].type
= ACPI_TYPE_BUFFER
;
331 params
[2].buffer
.length
= in
->length
;
332 params
[2].buffer
.pointer
= in
->pointer
;
335 strncat(method
, block
->object_id
, 2);
337 status
= acpi_evaluate_object(handle
, method
, &input
, out
);
341 EXPORT_SYMBOL_GPL(wmi_evaluate_method
);
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
349 * Return the contents of an ACPI-WMI data block to a buffer
351 acpi_status
wmi_query_block(const char *guid_string
, u8 instance
,
352 struct acpi_buffer
*out
)
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];
361 char wc_method
[5] = "WC";
363 if (!guid_string
|| !out
)
364 return AE_BAD_PARAMETER
;
366 if (!find_guid(guid_string
, &wblock
))
369 block
= &wblock
->gblock
;
370 handle
= wblock
->handle
;
372 if (block
->instance_count
< instance
)
373 return AE_BAD_PARAMETER
;
375 /* Check GUID is a data block */
376 if (block
->flags
& (ACPI_WMI_EVENT
| ACPI_WMI_METHOD
))
380 input
.pointer
= wq_params
;
381 wq_params
[0].type
= ACPI_TYPE_INTEGER
;
382 wq_params
[0].integer
.value
= instance
;
385 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
388 if (block
->flags
& ACPI_WMI_EXPENSIVE
) {
390 wc_input
.pointer
= wc_params
;
391 wc_params
[0].type
= ACPI_TYPE_INTEGER
;
392 wc_params
[0].integer
.value
= 1;
394 strncat(wc_method
, block
->object_id
, 2);
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.
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
,
407 strcpy(method
, "WQ");
408 strncat(method
, block
->object_id
, 2);
410 status
= acpi_evaluate_object(handle
, method
, &input
, out
);
413 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
414 * the WQxx method failed - we should disable collection anyway.
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
);
424 EXPORT_SYMBOL_GPL(wmi_query_block
);
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
432 * Write the contents of the input buffer to an ACPI-WMI data block
434 acpi_status
wmi_set_block(const char *guid_string
, u8 instance
,
435 const struct acpi_buffer
*in
)
437 struct guid_block
*block
= NULL
;
438 struct wmi_block
*wblock
= NULL
;
440 struct acpi_object_list input
;
441 union acpi_object params
[2];
442 char method
[5] = "WS";
444 if (!guid_string
|| !in
)
447 if (!find_guid(guid_string
, &wblock
))
450 block
= &wblock
->gblock
;
451 handle
= wblock
->handle
;
453 if (block
->instance_count
< instance
)
454 return AE_BAD_PARAMETER
;
456 /* Check GUID is a data block */
457 if (block
->flags
& (ACPI_WMI_EVENT
| ACPI_WMI_METHOD
))
461 input
.pointer
= params
;
462 params
[0].type
= ACPI_TYPE_INTEGER
;
463 params
[0].integer
.value
= instance
;
465 if (block
->flags
& ACPI_WMI_STRING
) {
466 params
[1].type
= ACPI_TYPE_STRING
;
468 params
[1].type
= ACPI_TYPE_BUFFER
;
470 params
[1].buffer
.length
= in
->length
;
471 params
[1].buffer
.pointer
= in
->pointer
;
473 strncat(method
, block
->object_id
, 2);
475 return acpi_evaluate_object(handle
, method
, &input
, NULL
);
477 EXPORT_SYMBOL_GPL(wmi_set_block
);
480 * wmi_install_notify_handler - Register handler for WMI events
481 * @handler: Function to handle notifications
482 * @data: Data to be returned to handler when event is fired
484 * Register a handler for events sent to the ACPI-WMI mapper device.
486 acpi_status
wmi_install_notify_handler(const char *guid
,
487 wmi_notify_handler handler
, void *data
)
489 struct wmi_block
*block
;
492 if (!guid
|| !handler
)
493 return AE_BAD_PARAMETER
;
495 if (!find_guid(guid
, &block
))
499 return AE_ALREADY_ACQUIRED
;
501 block
->handler
= handler
;
502 block
->handler_data
= data
;
504 status
= wmi_method_enable(block
, 1);
508 EXPORT_SYMBOL_GPL(wmi_install_notify_handler
);
511 * wmi_uninstall_notify_handler - Unregister handler for WMI events
513 * Unregister handler for events sent to the ACPI-WMI mapper device.
515 acpi_status
wmi_remove_notify_handler(const char *guid
)
517 struct wmi_block
*block
;
521 return AE_BAD_PARAMETER
;
523 if (!find_guid(guid
, &block
))
527 return AE_NULL_ENTRY
;
529 status
= wmi_method_enable(block
, 0);
531 block
->handler
= NULL
;
532 block
->handler_data
= NULL
;
536 EXPORT_SYMBOL_GPL(wmi_remove_notify_handler
);
539 * wmi_get_event_data - Get WMI data associated with an event
541 * @event: Event to find
542 * @out: Buffer to hold event data. out->pointer should be freed with kfree()
544 * Returns extra data associated with an event in WMI.
546 acpi_status
wmi_get_event_data(u32 event
, struct acpi_buffer
*out
)
548 struct acpi_object_list input
;
549 union acpi_object params
[1];
550 struct guid_block
*gblock
;
551 struct wmi_block
*wblock
;
555 input
.pointer
= params
;
556 params
[0].type
= ACPI_TYPE_INTEGER
;
557 params
[0].integer
.value
= event
;
559 list_for_each(p
, &wmi_blocks
.list
) {
560 wblock
= list_entry(p
, struct wmi_block
, list
);
561 gblock
= &wblock
->gblock
;
563 if ((gblock
->flags
& ACPI_WMI_EVENT
) &&
564 (gblock
->notify_id
== event
))
565 return acpi_evaluate_object(wblock
->handle
, "_WED",
571 EXPORT_SYMBOL_GPL(wmi_get_event_data
);
574 * wmi_has_guid - Check if a GUID is available
575 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
577 * Check if a given GUID is defined by _WDG
579 bool wmi_has_guid(const char *guid_string
)
581 return find_guid(guid_string
, NULL
);
583 EXPORT_SYMBOL_GPL(wmi_has_guid
);
588 static ssize_t
show_modalias(struct device
*dev
, struct device_attribute
*attr
,
591 char guid_string
[37];
592 struct wmi_block
*wblock
;
594 wblock
= dev_get_drvdata(dev
);
598 wmi_gtoa(wblock
->gblock
.guid
, guid_string
);
600 return sprintf(buf
, "wmi:%s\n", guid_string
);
602 static DEVICE_ATTR(modalias
, S_IRUGO
, show_modalias
, NULL
);
604 static int wmi_dev_uevent(struct device
*dev
, struct kobj_uevent_env
*env
)
606 char guid_string
[37];
608 struct wmi_block
*wblock
;
610 if (add_uevent_var(env
, "MODALIAS="))
613 wblock
= dev_get_drvdata(dev
);
617 wmi_gtoa(wblock
->gblock
.guid
, guid_string
);
619 strcpy(&env
->buf
[env
->buflen
- 1], "wmi:");
620 memcpy(&env
->buf
[env
->buflen
- 1 + 4], guid_string
, 36);
626 static void wmi_dev_free(struct device
*dev
)
631 static struct class wmi_class
= {
633 .dev_release
= wmi_dev_free
,
634 .dev_uevent
= wmi_dev_uevent
,
637 static int wmi_create_devs(void)
640 char guid_string
[37];
641 struct guid_block
*gblock
;
642 struct wmi_block
*wblock
;
644 struct device
*guid_dev
;
646 /* Create devices for all the GUIDs */
647 list_for_each(p
, &wmi_blocks
.list
) {
648 wblock
= list_entry(p
, struct wmi_block
, list
);
650 guid_dev
= kzalloc(sizeof(struct device
), GFP_KERNEL
);
654 wblock
->dev
= guid_dev
;
656 guid_dev
->class = &wmi_class
;
657 dev_set_drvdata(guid_dev
, wblock
);
659 gblock
= &wblock
->gblock
;
661 wmi_gtoa(gblock
->guid
, guid_string
);
662 dev_set_name(guid_dev
, guid_string
);
664 result
= device_register(guid_dev
);
668 result
= device_create_file(guid_dev
, &dev_attr_modalias
);
676 static void wmi_remove_devs(void)
678 struct guid_block
*gblock
;
679 struct wmi_block
*wblock
;
681 struct device
*guid_dev
;
683 /* Delete devices for all the GUIDs */
684 list_for_each(p
, &wmi_blocks
.list
) {
685 wblock
= list_entry(p
, struct wmi_block
, list
);
687 guid_dev
= wblock
->dev
;
688 gblock
= &wblock
->gblock
;
690 device_remove_file(guid_dev
, &dev_attr_modalias
);
692 device_unregister(guid_dev
);
696 static void wmi_class_exit(void)
699 class_unregister(&wmi_class
);
702 static int wmi_class_init(void)
706 ret
= class_register(&wmi_class
);
710 ret
= wmi_create_devs();
717 static bool guid_already_parsed(const char *guid_string
)
719 struct guid_block
*gblock
;
720 struct wmi_block
*wblock
;
723 list_for_each(p
, &wmi_blocks
.list
) {
724 wblock
= list_entry(p
, struct wmi_block
, list
);
725 gblock
= &wblock
->gblock
;
727 if (strncmp(gblock
->guid
, guid_string
, 16) == 0)
734 * Parse the _WDG method for the GUID data blocks
736 static __init acpi_status
parse_wdg(acpi_handle handle
)
738 struct acpi_buffer out
= {ACPI_ALLOCATE_BUFFER
, NULL
};
739 union acpi_object
*obj
;
740 struct guid_block
*gblock
;
741 struct wmi_block
*wblock
;
742 char guid_string
[37];
746 status
= acpi_evaluate_object(handle
, "_WDG", NULL
, &out
);
748 if (ACPI_FAILURE(status
))
751 obj
= (union acpi_object
*) out
.pointer
;
753 if (obj
->type
!= ACPI_TYPE_BUFFER
)
756 total
= obj
->buffer
.length
/ sizeof(struct guid_block
);
758 gblock
= kzalloc(obj
->buffer
.length
, GFP_KERNEL
);
762 memcpy(gblock
, obj
->buffer
.pointer
, obj
->buffer
.length
);
764 for (i
= 0; i
< total
; i
++) {
766 Some WMI devices, like those for nVidia hooks, have a
767 duplicate GUID. It's not clear what we should do in this
768 case yet, so for now, we'll just ignore the duplicate.
769 Anyone who wants to add support for that device can come
770 up with a better workaround for the mess then.
772 if (guid_already_parsed(gblock
[i
].guid
) == true) {
773 wmi_gtoa(gblock
[i
].guid
, guid_string
);
774 printk(KERN_INFO PREFIX
"Skipping duplicate GUID %s\n",
778 wblock
= kzalloc(sizeof(struct wmi_block
), GFP_KERNEL
);
782 wblock
->gblock
= gblock
[i
];
783 wblock
->handle
= handle
;
784 list_add_tail(&wblock
->list
, &wmi_blocks
.list
);
794 * WMI can have EmbeddedControl access regions. In which case, we just want to
795 * hand these off to the EC driver.
798 acpi_wmi_ec_space_handler(u32 function
, acpi_physical_address address
,
799 u32 bits
, u64
*value
,
800 void *handler_context
, void *region_context
)
802 int result
= 0, i
= 0;
805 if ((address
> 0xFF) || !value
)
806 return AE_BAD_PARAMETER
;
808 if (function
!= ACPI_READ
&& function
!= ACPI_WRITE
)
809 return AE_BAD_PARAMETER
;
812 return AE_BAD_PARAMETER
;
814 if (function
== ACPI_READ
) {
815 result
= ec_read(address
, &temp
);
816 (*value
) |= ((u64
)temp
) << i
;
818 temp
= 0xff & ((*value
) >> i
);
819 result
= ec_write(address
, temp
);
824 return AE_BAD_PARAMETER
;
837 static void acpi_wmi_notify(struct acpi_device
*device
, u32 event
)
839 struct guid_block
*block
;
840 struct wmi_block
*wblock
;
843 list_for_each(p
, &wmi_blocks
.list
) {
844 wblock
= list_entry(p
, struct wmi_block
, list
);
845 block
= &wblock
->gblock
;
847 if ((block
->flags
& ACPI_WMI_EVENT
) &&
848 (block
->notify_id
== event
)) {
850 wblock
->handler(event
, wblock
->handler_data
);
852 acpi_bus_generate_netlink_event(
853 device
->pnp
.device_class
, dev_name(&device
->dev
),
860 static int acpi_wmi_remove(struct acpi_device
*device
, int type
)
862 acpi_remove_address_space_handler(device
->handle
,
863 ACPI_ADR_SPACE_EC
, &acpi_wmi_ec_space_handler
);
868 static int __init
acpi_wmi_add(struct acpi_device
*device
)
873 status
= acpi_install_address_space_handler(device
->handle
,
875 &acpi_wmi_ec_space_handler
,
877 if (ACPI_FAILURE(status
))
880 status
= parse_wdg(device
->handle
);
881 if (ACPI_FAILURE(status
)) {
882 printk(KERN_ERR PREFIX
"Error installing EC region handler\n");
889 static int __init
acpi_wmi_init(void)
893 INIT_LIST_HEAD(&wmi_blocks
.list
);
898 result
= acpi_bus_register_driver(&acpi_wmi_driver
);
901 printk(KERN_INFO PREFIX
"Error loading mapper\n");
905 result
= wmi_class_init();
907 acpi_bus_unregister_driver(&acpi_wmi_driver
);
911 printk(KERN_INFO PREFIX
"Mapper loaded\n");
916 static void __exit
acpi_wmi_exit(void)
918 struct list_head
*p
, *tmp
;
919 struct wmi_block
*wblock
;
923 acpi_bus_unregister_driver(&acpi_wmi_driver
);
925 list_for_each_safe(p
, tmp
, &wmi_blocks
.list
) {
926 wblock
= list_entry(p
, struct wmi_block
, list
);
932 printk(KERN_INFO PREFIX
"Mapper unloaded\n");
935 subsys_initcall(acpi_wmi_init
);
936 module_exit(acpi_wmi_exit
);