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