diff options
Diffstat (limited to 'drivers/acpi/utils.c')
-rw-r--r-- | drivers/acpi/utils.c | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c new file mode 100644 index 000000000000..1ce2047c3804 --- /dev/null +++ b/drivers/acpi/utils.c | |||
@@ -0,0 +1,423 @@ | |||
1 | /* | ||
2 | * acpi_utils.c - ACPI Utility Functions ($Revision: 10 $) | ||
3 | * | ||
4 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> | ||
5 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | ||
6 | * | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or (at | ||
12 | * your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
22 | * | ||
23 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <acpi/acpi_bus.h> | ||
31 | #include <acpi/acpi_drivers.h> | ||
32 | |||
33 | |||
34 | #define _COMPONENT ACPI_BUS_COMPONENT | ||
35 | ACPI_MODULE_NAME ("acpi_utils") | ||
36 | |||
37 | |||
38 | /* -------------------------------------------------------------------------- | ||
39 | Object Evaluation Helpers | ||
40 | -------------------------------------------------------------------------- */ | ||
41 | |||
42 | #ifdef ACPI_DEBUG_OUTPUT | ||
43 | #define acpi_util_eval_error(h,p,s) {\ | ||
44 | char prefix[80] = {'\0'};\ | ||
45 | struct acpi_buffer buffer = {sizeof(prefix), prefix};\ | ||
46 | acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ | ||
47 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",\ | ||
48 | (char *) prefix, p, acpi_format_exception(s))); } | ||
49 | #else | ||
50 | #define acpi_util_eval_error(h,p,s) | ||
51 | #endif | ||
52 | |||
53 | |||
54 | acpi_status | ||
55 | acpi_extract_package ( | ||
56 | union acpi_object *package, | ||
57 | struct acpi_buffer *format, | ||
58 | struct acpi_buffer *buffer) | ||
59 | { | ||
60 | u32 size_required = 0; | ||
61 | u32 tail_offset = 0; | ||
62 | char *format_string = NULL; | ||
63 | u32 format_count = 0; | ||
64 | u32 i = 0; | ||
65 | u8 *head = NULL; | ||
66 | u8 *tail = NULL; | ||
67 | |||
68 | ACPI_FUNCTION_TRACE("acpi_extract_package"); | ||
69 | |||
70 | if (!package || (package->type != ACPI_TYPE_PACKAGE) || (package->package.count < 1)) { | ||
71 | ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'package' argument\n")); | ||
72 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
73 | } | ||
74 | |||
75 | if (!format || !format->pointer || (format->length < 1)) { | ||
76 | ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'format' argument\n")); | ||
77 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
78 | } | ||
79 | |||
80 | if (!buffer) { | ||
81 | ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'buffer' argument\n")); | ||
82 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
83 | } | ||
84 | |||
85 | format_count = (format->length/sizeof(char)) - 1; | ||
86 | if (format_count > package->package.count) { | ||
87 | ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Format specifies more objects [%d] than exist in package [%d].", format_count, package->package.count)); | ||
88 | return_ACPI_STATUS(AE_BAD_DATA); | ||
89 | } | ||
90 | |||
91 | format_string = (char*)format->pointer; | ||
92 | |||
93 | /* | ||
94 | * Calculate size_required. | ||
95 | */ | ||
96 | for (i=0; i<format_count; i++) { | ||
97 | |||
98 | union acpi_object *element = &(package->package.elements[i]); | ||
99 | |||
100 | if (!element) { | ||
101 | return_ACPI_STATUS(AE_BAD_DATA); | ||
102 | } | ||
103 | |||
104 | switch (element->type) { | ||
105 | |||
106 | case ACPI_TYPE_INTEGER: | ||
107 | switch (format_string[i]) { | ||
108 | case 'N': | ||
109 | size_required += sizeof(acpi_integer); | ||
110 | tail_offset += sizeof(acpi_integer); | ||
111 | break; | ||
112 | case 'S': | ||
113 | size_required += sizeof(char*) + sizeof(acpi_integer) + sizeof(char); | ||
114 | tail_offset += sizeof(char*); | ||
115 | break; | ||
116 | default: | ||
117 | ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid package element [%d]: got number, expecing [%c].\n", i, format_string[i])); | ||
118 | return_ACPI_STATUS(AE_BAD_DATA); | ||
119 | break; | ||
120 | } | ||
121 | break; | ||
122 | |||
123 | case ACPI_TYPE_STRING: | ||
124 | case ACPI_TYPE_BUFFER: | ||
125 | switch (format_string[i]) { | ||
126 | case 'S': | ||
127 | size_required += sizeof(char*) + (element->string.length * sizeof(char)) + sizeof(char); | ||
128 | tail_offset += sizeof(char*); | ||
129 | break; | ||
130 | case 'B': | ||
131 | size_required += sizeof(u8*) + (element->buffer.length * sizeof(u8)); | ||
132 | tail_offset += sizeof(u8*); | ||
133 | break; | ||
134 | default: | ||
135 | ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid package element [%d] got string/buffer, expecing [%c].\n", i, format_string[i])); | ||
136 | return_ACPI_STATUS(AE_BAD_DATA); | ||
137 | break; | ||
138 | } | ||
139 | break; | ||
140 | |||
141 | case ACPI_TYPE_PACKAGE: | ||
142 | default: | ||
143 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unsupported element at index=%d\n", i)); | ||
144 | /* TBD: handle nested packages... */ | ||
145 | return_ACPI_STATUS(AE_SUPPORT); | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * Validate output buffer. | ||
152 | */ | ||
153 | if (buffer->length < size_required) { | ||
154 | buffer->length = size_required; | ||
155 | return_ACPI_STATUS(AE_BUFFER_OVERFLOW); | ||
156 | } | ||
157 | else if (buffer->length != size_required || !buffer->pointer) { | ||
158 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
159 | } | ||
160 | |||
161 | head = buffer->pointer; | ||
162 | tail = buffer->pointer + tail_offset; | ||
163 | |||
164 | /* | ||
165 | * Extract package data. | ||
166 | */ | ||
167 | for (i=0; i<format_count; i++) { | ||
168 | |||
169 | u8 **pointer = NULL; | ||
170 | union acpi_object *element = &(package->package.elements[i]); | ||
171 | |||
172 | if (!element) { | ||
173 | return_ACPI_STATUS(AE_BAD_DATA); | ||
174 | } | ||
175 | |||
176 | switch (element->type) { | ||
177 | |||
178 | case ACPI_TYPE_INTEGER: | ||
179 | switch (format_string[i]) { | ||
180 | case 'N': | ||
181 | *((acpi_integer*)head) = element->integer.value; | ||
182 | head += sizeof(acpi_integer); | ||
183 | break; | ||
184 | case 'S': | ||
185 | pointer = (u8**)head; | ||
186 | *pointer = tail; | ||
187 | *((acpi_integer*)tail) = element->integer.value; | ||
188 | head += sizeof(acpi_integer*); | ||
189 | tail += sizeof(acpi_integer); | ||
190 | /* NULL terminate string */ | ||
191 | *tail = (char)0; | ||
192 | tail += sizeof(char); | ||
193 | break; | ||
194 | default: | ||
195 | /* Should never get here */ | ||
196 | break; | ||
197 | } | ||
198 | break; | ||
199 | |||
200 | case ACPI_TYPE_STRING: | ||
201 | case ACPI_TYPE_BUFFER: | ||
202 | switch (format_string[i]) { | ||
203 | case 'S': | ||
204 | pointer = (u8**)head; | ||
205 | *pointer = tail; | ||
206 | memcpy(tail, element->string.pointer, element->string.length); | ||
207 | head += sizeof(char*); | ||
208 | tail += element->string.length * sizeof(char); | ||
209 | /* NULL terminate string */ | ||
210 | *tail = (char)0; | ||
211 | tail += sizeof(char); | ||
212 | break; | ||
213 | case 'B': | ||
214 | pointer = (u8**)head; | ||
215 | *pointer = tail; | ||
216 | memcpy(tail, element->buffer.pointer, element->buffer.length); | ||
217 | head += sizeof(u8*); | ||
218 | tail += element->buffer.length * sizeof(u8); | ||
219 | break; | ||
220 | default: | ||
221 | /* Should never get here */ | ||
222 | break; | ||
223 | } | ||
224 | break; | ||
225 | |||
226 | case ACPI_TYPE_PACKAGE: | ||
227 | /* TBD: handle nested packages... */ | ||
228 | default: | ||
229 | /* Should never get here */ | ||
230 | break; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | return_ACPI_STATUS(AE_OK); | ||
235 | } | ||
236 | EXPORT_SYMBOL(acpi_extract_package); | ||
237 | |||
238 | |||
239 | acpi_status | ||
240 | acpi_evaluate_integer ( | ||
241 | acpi_handle handle, | ||
242 | acpi_string pathname, | ||
243 | struct acpi_object_list *arguments, | ||
244 | unsigned long *data) | ||
245 | { | ||
246 | acpi_status status = AE_OK; | ||
247 | union acpi_object *element; | ||
248 | struct acpi_buffer buffer = {0,NULL}; | ||
249 | |||
250 | ACPI_FUNCTION_TRACE("acpi_evaluate_integer"); | ||
251 | |||
252 | if (!data) | ||
253 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
254 | |||
255 | element = kmalloc(sizeof(union acpi_object), GFP_KERNEL); | ||
256 | if(!element) | ||
257 | return_ACPI_STATUS(AE_NO_MEMORY); | ||
258 | |||
259 | memset(element, 0, sizeof(union acpi_object)); | ||
260 | buffer.length = sizeof(union acpi_object); | ||
261 | buffer.pointer = element; | ||
262 | status = acpi_evaluate_object(handle, pathname, arguments, &buffer); | ||
263 | if (ACPI_FAILURE(status)) { | ||
264 | acpi_util_eval_error(handle, pathname, status); | ||
265 | return_ACPI_STATUS(status); | ||
266 | } | ||
267 | |||
268 | if (element->type != ACPI_TYPE_INTEGER) { | ||
269 | acpi_util_eval_error(handle, pathname, AE_BAD_DATA); | ||
270 | return_ACPI_STATUS(AE_BAD_DATA); | ||
271 | } | ||
272 | |||
273 | *data = element->integer.value; | ||
274 | kfree(element); | ||
275 | |||
276 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%lu]\n", *data)); | ||
277 | |||
278 | return_ACPI_STATUS(AE_OK); | ||
279 | } | ||
280 | EXPORT_SYMBOL(acpi_evaluate_integer); | ||
281 | |||
282 | |||
283 | #if 0 | ||
284 | acpi_status | ||
285 | acpi_evaluate_string ( | ||
286 | acpi_handle handle, | ||
287 | acpi_string pathname, | ||
288 | acpi_object_list *arguments, | ||
289 | acpi_string *data) | ||
290 | { | ||
291 | acpi_status status = AE_OK; | ||
292 | acpi_object *element = NULL; | ||
293 | acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
294 | |||
295 | ACPI_FUNCTION_TRACE("acpi_evaluate_string"); | ||
296 | |||
297 | if (!data) | ||
298 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
299 | |||
300 | status = acpi_evaluate_object(handle, pathname, arguments, &buffer); | ||
301 | if (ACPI_FAILURE(status)) { | ||
302 | acpi_util_eval_error(handle, pathname, status); | ||
303 | return_ACPI_STATUS(status); | ||
304 | } | ||
305 | |||
306 | element = (acpi_object *) buffer.pointer; | ||
307 | |||
308 | if ((element->type != ACPI_TYPE_STRING) | ||
309 | || (element->type != ACPI_TYPE_BUFFER) | ||
310 | || !element->string.length) { | ||
311 | acpi_util_eval_error(handle, pathname, AE_BAD_DATA); | ||
312 | return_ACPI_STATUS(AE_BAD_DATA); | ||
313 | } | ||
314 | |||
315 | *data = kmalloc(element->string.length + 1, GFP_KERNEL); | ||
316 | if (!data) { | ||
317 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n")); | ||
318 | return_VALUE(-ENOMEM); | ||
319 | } | ||
320 | memset(*data, 0, element->string.length + 1); | ||
321 | |||
322 | memcpy(*data, element->string.pointer, element->string.length); | ||
323 | |||
324 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%s]\n", *data)); | ||
325 | |||
326 | acpi_os_free(buffer.pointer); | ||
327 | |||
328 | return_ACPI_STATUS(AE_OK); | ||
329 | } | ||
330 | #endif | ||
331 | |||
332 | |||
333 | acpi_status | ||
334 | acpi_evaluate_reference ( | ||
335 | acpi_handle handle, | ||
336 | acpi_string pathname, | ||
337 | struct acpi_object_list *arguments, | ||
338 | struct acpi_handle_list *list) | ||
339 | { | ||
340 | acpi_status status = AE_OK; | ||
341 | union acpi_object *package = NULL; | ||
342 | union acpi_object *element = NULL; | ||
343 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
344 | u32 i = 0; | ||
345 | |||
346 | ACPI_FUNCTION_TRACE("acpi_evaluate_reference"); | ||
347 | |||
348 | if (!list) { | ||
349 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
350 | } | ||
351 | |||
352 | /* Evaluate object. */ | ||
353 | |||
354 | status = acpi_evaluate_object(handle, pathname, arguments, &buffer); | ||
355 | if (ACPI_FAILURE(status)) | ||
356 | goto end; | ||
357 | |||
358 | package = (union acpi_object *) buffer.pointer; | ||
359 | |||
360 | if ((buffer.length == 0) || !package) { | ||
361 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
362 | "No return object (len %X ptr %p)\n", | ||
363 | (unsigned)buffer.length, package)); | ||
364 | status = AE_BAD_DATA; | ||
365 | acpi_util_eval_error(handle, pathname, status); | ||
366 | goto end; | ||
367 | } | ||
368 | if (package->type != ACPI_TYPE_PACKAGE) { | ||
369 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
370 | "Expecting a [Package], found type %X\n", | ||
371 | package->type)); | ||
372 | status = AE_BAD_DATA; | ||
373 | acpi_util_eval_error(handle, pathname, status); | ||
374 | goto end; | ||
375 | } | ||
376 | if (!package->package.count) { | ||
377 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
378 | "[Package] has zero elements (%p)\n", | ||
379 | package)); | ||
380 | status = AE_BAD_DATA; | ||
381 | acpi_util_eval_error(handle, pathname, status); | ||
382 | goto end; | ||
383 | } | ||
384 | |||
385 | if (package->package.count > ACPI_MAX_HANDLES) { | ||
386 | return_ACPI_STATUS(AE_NO_MEMORY); | ||
387 | } | ||
388 | list->count = package->package.count; | ||
389 | |||
390 | /* Extract package data. */ | ||
391 | |||
392 | for (i = 0; i < list->count; i++) { | ||
393 | |||
394 | element = &(package->package.elements[i]); | ||
395 | |||
396 | if (element->type != ACPI_TYPE_ANY) { | ||
397 | status = AE_BAD_DATA; | ||
398 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
399 | "Expecting a [Reference] package element, found type %X\n", | ||
400 | element->type)); | ||
401 | acpi_util_eval_error(handle, pathname, status); | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | /* Get the acpi_handle. */ | ||
406 | |||
407 | list->handles[i] = element->reference.handle; | ||
408 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found reference [%p]\n", | ||
409 | list->handles[i])); | ||
410 | } | ||
411 | |||
412 | end: | ||
413 | if (ACPI_FAILURE(status)) { | ||
414 | list->count = 0; | ||
415 | //kfree(list->handles); | ||
416 | } | ||
417 | |||
418 | acpi_os_free(buffer.pointer); | ||
419 | |||
420 | return_ACPI_STATUS(status); | ||
421 | } | ||
422 | EXPORT_SYMBOL(acpi_evaluate_reference); | ||
423 | |||