- Make ACPI use PCH. Cuts down compile time to 9 seconds on gcc.
[reactos.git] / reactos / drivers / bus / acpi / ospm / busmgr / bmutils.c
1 /*****************************************************************************
2 *
3 * Module Name: bmutils.c
4 * $Revision: 1.1 $
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 Andrew Grover
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include <acpi.h>
28
29 #define _COMPONENT ACPI_BUS_MANAGER
30 MODULE_NAME ("bmutils")
31
32
33 #ifdef ACPI_DEBUG
34 #define DEBUG_EVAL_ERROR(l,h,p,s) bm_print_eval_error(l,h,p,s)
35 #else
36 #define DEBUG_EVAL_ERROR(l,h,p,s)
37 #endif
38
39
40 /****************************************************************************
41 * External Functions
42 ****************************************************************************/
43
44 /****************************************************************************
45 *
46 * FUNCTION: bm_print_eval_error
47 *
48 * PARAMETERS: <TBD>
49 *
50 * RETURN: <TBD>
51 *
52 * DESCRIPTION: <TBD>
53 *
54 ****************************************************************************/
55
56 void
57 bm_print_eval_error (
58 u32 debug_level,
59 ACPI_HANDLE acpi_handle,
60 ACPI_STRING pathname,
61 ACPI_STATUS status)
62 {
63 ACPI_BUFFER buffer;
64 ACPI_STRING status_string = NULL;
65
66 buffer.length = 256;
67 buffer.pointer = acpi_os_callocate(buffer.length);
68 if (!buffer.pointer) {
69 return;
70 }
71
72 status_string = acpi_cm_format_exception(status);
73
74 status = acpi_get_name(acpi_handle, ACPI_FULL_PATHNAME, &buffer);
75 if (ACPI_FAILURE(status)) {
76 DEBUG_PRINT(debug_level, ("Evaluate object [0x%08x], %s\n", acpi_handle, status_string));
77 return;
78 }
79
80 if (pathname) {
81 DEBUG_PRINT(ACPI_INFO, ("Evaluate object [%s.%s], %s\n", buffer.pointer, pathname, status_string));
82 }
83 else {
84 DEBUG_PRINT(ACPI_INFO, ("Evaluate object [%s], %s\n", buffer.pointer, status_string));
85 }
86
87 acpi_os_free(buffer.pointer);
88 }
89
90
91 /****************************************************************************
92 *
93 * FUNCTION: bm_copy_to_buffer
94 *
95 * PARAMETERS: <TBD>
96 *
97 * RETURN: <TBD>
98 *
99 * DESCRIPTION: <TBD>
100 *
101 ****************************************************************************/
102
103 ACPI_STATUS
104 bm_copy_to_buffer (
105 ACPI_BUFFER *buffer,
106 void *data,
107 u32 length)
108 {
109 FUNCTION_TRACE("bm_copy_to_buffer");
110
111 if (!buffer || (!buffer->pointer) || !data || (length == 0)) {
112 return_ACPI_STATUS(AE_BAD_PARAMETER);
113 }
114
115 if (length > buffer->length) {
116 buffer->length = length;
117 return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
118 }
119
120 buffer->length = length;
121 MEMCPY(buffer->pointer, data, length);
122
123 return_ACPI_STATUS(AE_OK);
124 }
125
126
127 /****************************************************************************
128 *
129 * FUNCTION: bm_cast_buffer
130 *
131 * PARAMETERS: <TBD>
132 *
133 * RETURN: <TBD>
134 *
135 * DESCRIPTION: <TBD>
136 *
137 ****************************************************************************/
138
139 ACPI_STATUS
140 bm_cast_buffer (
141 ACPI_BUFFER *buffer,
142 void **pointer,
143 u32 length)
144 {
145 FUNCTION_TRACE("bm_cast_buffer");
146
147 if (!buffer || !buffer->pointer || !pointer || length == 0) {
148 return_ACPI_STATUS(AE_BAD_PARAMETER);
149 }
150
151 if (length > buffer->length) {
152 return_ACPI_STATUS(AE_BAD_DATA);
153 }
154
155 *pointer = buffer->pointer;
156
157 return_ACPI_STATUS(AE_OK);
158 }
159
160
161 /****************************************************************************
162 *
163 * FUNCTION: bm_extract_package_data
164 *
165 * PARAMETERS: <TBD>
166 *
167 * RETURN: <TBD>
168 *
169 * DESCRIPTION: <TBD>
170 *
171 ****************************************************************************/
172
173 /*
174 TODO: Don't assume numbers (in ASL) are 32-bit values!!!! (IA64)
175 TODO: Issue with 'assumed' types coming out of interpreter...
176 (e.g. toshiba _BIF)
177 */
178
179 ACPI_STATUS
180 bm_extract_package_data (
181 ACPI_OBJECT *package,
182 ACPI_BUFFER *package_format,
183 ACPI_BUFFER *buffer)
184 {
185 ACPI_STATUS status = AE_OK;
186 u8 *head = NULL;
187 u8 *tail = NULL;
188 u8 **pointer = NULL;
189 u32 tail_offset = 0;
190 ACPI_OBJECT *element = NULL;
191 u32 size_required = 0;
192 char* format = NULL;
193 u32 format_count = 0;
194 u32 i = 0;
195
196 FUNCTION_TRACE("bm_extract_package_data");
197
198 if (!package || (package->type != ACPI_TYPE_PACKAGE) ||
199 (package->package.count == 0) || !package_format ||
200 (package_format->length < 1) ||
201 (!package_format->pointer) || !buffer) {
202 return_ACPI_STATUS(AE_BAD_PARAMETER);
203 }
204
205 format_count = package_format->length - 1;
206
207 if (format_count > package->package.count) {
208 DEBUG_PRINT(ACPI_WARN, ("Format specifies more objects [%d] than exist in package [%d].", format_count, package->package.count));
209 return_ACPI_STATUS(AE_BAD_DATA);
210 }
211
212 format = (char*)package_format->pointer;
213
214 /*
215 * Calculate size_required.
216 */
217 for (i=0; i<format_count; i++) {
218 element = &(package->package.elements[i]);
219
220 switch (element->type) {
221
222 case ACPI_TYPE_INTEGER:
223 switch (format[i]) {
224 case 'N':
225 size_required += sizeof(ACPI_INTEGER);
226 tail_offset += sizeof(ACPI_INTEGER);
227 break;
228 case 'S':
229 size_required += sizeof(u8*) +
230 sizeof(ACPI_INTEGER) + 1;
231 tail_offset += sizeof(ACPI_INTEGER);
232 break;
233 default:
234 DEBUG_PRINT(ACPI_WARN, ("Invalid package element [%d]: got number, expecing [%c].\n", i, format[i]));
235 return_ACPI_STATUS(AE_BAD_DATA);
236 break;
237 }
238 break;
239
240 case ACPI_TYPE_STRING:
241 case ACPI_TYPE_BUFFER:
242 switch (format[i]) {
243 case 'S':
244 size_required += sizeof(u8*) +
245 element->string.length + 1;
246 tail_offset += sizeof(u8*);
247 break;
248 case 'B':
249 size_required += sizeof(u8*) +
250 element->buffer.length;
251 tail_offset += sizeof(u8*);
252 break;
253 default:
254 DEBUG_PRINT(ACPI_WARN, ("Invalid package element [%d] got string/buffer, expecing [%c].\n", i, format[i]));
255 return_ACPI_STATUS(AE_BAD_DATA);
256 break;
257 }
258 break;
259
260 case ACPI_TYPE_PACKAGE:
261 default:
262 /* TODO: handle nested packages... */
263 return_ACPI_STATUS(AE_SUPPORT);
264 break;
265 }
266 }
267
268 if (size_required > buffer->length) {
269 buffer->length = size_required;
270 return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
271 }
272
273 buffer->length = size_required;
274
275 if (!buffer->pointer) {
276 return_ACPI_STATUS(AE_BAD_PARAMETER);
277 }
278
279 head = buffer->pointer;
280 tail = head + tail_offset;
281
282 /*
283 * Extract package data:
284 */
285 for (i=0; i<format_count; i++) {
286
287 element = &(package->package.elements[i]);
288
289 switch (element->type) {
290
291 case ACPI_TYPE_INTEGER:
292 switch (format[i]) {
293 case 'N':
294 *((ACPI_INTEGER*)head) =
295 element->integer.value;
296 head += sizeof(ACPI_INTEGER);
297 break;
298 case 'S':
299 pointer = (u8**)head;
300 *pointer = tail;
301 *((ACPI_INTEGER*)tail) =
302 element->integer.value;
303 head += sizeof(ACPI_INTEGER*);
304 tail += sizeof(ACPI_INTEGER);
305 /* NULL terminate string */
306 *tail = 0;
307 tail++;
308 break;
309 default:
310 /* Should never get here */
311 break;
312 }
313 break;
314
315 case ACPI_TYPE_STRING:
316 case ACPI_TYPE_BUFFER:
317 switch (format[i]) {
318 case 'S':
319 pointer = (u8**)head;
320 *pointer = tail;
321 memcpy(tail, element->string.pointer,
322 element->string.length);
323 head += sizeof(u8*);
324 tail += element->string.length;
325 /* NULL terminate string */
326 *tail = 0;
327 tail++;
328 break;
329 case 'B':
330 pointer = (u8**)head;
331 *pointer = tail;
332 memcpy(tail, element->buffer.pointer,
333 element->buffer.length);
334 head += sizeof(u8*);
335 tail += element->buffer.length;
336 break;
337 default:
338 /* Should never get here */
339 break;
340 }
341 break;
342
343 case ACPI_TYPE_PACKAGE:
344 /* TODO: handle nested packages... */
345 default:
346 /* Should never get here */
347 break;
348 }
349 }
350
351 return_ACPI_STATUS(status);
352 }
353
354
355 /****************************************************************************
356 *
357 * FUNCTION: bm_evaluate_object
358 *
359 * PARAMETERS: <TBD>
360 *
361 * RETURN: AE_OK
362 * AE_BUFFER_OVERFLOW Evaluated object returned data, but
363 * caller did not provide buffer.
364 *
365 * DESCRIPTION: Helper for acpi_evaluate_object that handles buffer
366 * allocation. Note that the caller is responsible for
367 * freeing buffer->pointer!
368 *
369 ****************************************************************************/
370
371 ACPI_STATUS
372 bm_evaluate_object (
373 ACPI_HANDLE acpi_handle,
374 ACPI_STRING pathname,
375 ACPI_OBJECT_LIST *arguments,
376 ACPI_BUFFER *buffer)
377 {
378 ACPI_STATUS status = AE_OK;
379
380 FUNCTION_TRACE("bm_evaluate_object");
381
382 /* If caller provided a buffer it must be unallocated/zero'd. */
383 if ((buffer) && (buffer->length != 0 || buffer->pointer)) {
384 return_ACPI_STATUS(AE_BAD_PARAMETER);
385 }
386
387 /*
388 * Evalute Object:
389 * ---------------
390 * The first attempt is just to get the size of the object data
391 * (that is unless there's no return data, e.g. _INI); the second
392 * gets the data.
393 */
394 status = acpi_evaluate_object(acpi_handle, pathname, arguments, buffer);
395 if (ACPI_SUCCESS(status)) {
396 return_ACPI_STATUS(status);
397 }
398
399 else if ((buffer) && (status == AE_BUFFER_OVERFLOW)) {
400
401 /* Gotta allocate -- CALLER MUST FREE! */
402 buffer->pointer = acpi_os_callocate(buffer->length);
403 if (!buffer->pointer) {
404 return_ACPI_STATUS(AE_NO_MEMORY);
405 }
406
407 /* Re-evaluate -- this time it should work */
408 status = acpi_evaluate_object(acpi_handle, pathname,
409 arguments, buffer);
410 }
411
412 if (ACPI_FAILURE(status)) {
413 DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status);
414 if (buffer && buffer->pointer) {
415 acpi_os_free(buffer->pointer);
416 buffer->pointer = NULL;
417 buffer->length = 0;
418 }
419 }
420
421 return_ACPI_STATUS(status);
422 }
423
424
425 /****************************************************************************
426 *
427 * FUNCTION: bm_evaluate_simple_integer
428 *
429 * PARAMETERS: <TBD>
430 *
431 * RETURN: <TBD>
432 *
433 * DESCRIPTION: <TBD>
434 *
435 ****************************************************************************/
436
437 ACPI_STATUS
438 bm_evaluate_simple_integer (
439 ACPI_HANDLE acpi_handle,
440 ACPI_STRING pathname,
441 u32 *data)
442 {
443 ACPI_STATUS status = AE_OK;
444 ACPI_OBJECT *element = NULL;
445 ACPI_BUFFER buffer;
446
447 FUNCTION_TRACE("bm_evaluate_simple_integer");
448
449 if (!data) {
450 return_ACPI_STATUS(AE_BAD_PARAMETER);
451 }
452
453 MEMSET(&buffer, 0, sizeof(ACPI_BUFFER));
454
455 /*
456 * Evaluate Object:
457 * ----------------
458 */
459 status = bm_evaluate_object(acpi_handle, pathname, NULL, &buffer);
460 if (ACPI_FAILURE(status)) {
461 goto end;
462 }
463
464 /*
465 * Validate Data:
466 * --------------
467 */
468 status = bm_cast_buffer(&buffer, (void**)&element,
469 sizeof(ACPI_OBJECT));
470 if (ACPI_FAILURE(status)) {
471 DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status);
472 goto end;
473 }
474
475 if (element->type != ACPI_TYPE_INTEGER) {
476 status = AE_BAD_DATA;
477 DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status);
478 goto end;
479 }
480
481 *data = element->integer.value;
482
483 end:
484 acpi_os_free(buffer.pointer);
485
486 return_ACPI_STATUS(status);
487 }
488
489
490 /****************************************************************************
491 *
492 * FUNCTION: bm_evaluate_reference_list
493 *
494 * PARAMETERS: <TBD>
495 *
496 * RETURN: <TBD>
497 *
498 * DESCRIPTION: <TBD>
499 *
500 ****************************************************************************/
501
502 ACPI_STATUS
503 bm_evaluate_reference_list (
504 ACPI_HANDLE acpi_handle,
505 ACPI_STRING pathname,
506 BM_HANDLE_LIST *reference_list)
507 {
508 ACPI_STATUS status = AE_OK;
509 ACPI_OBJECT *package = NULL;
510 ACPI_OBJECT *element = NULL;
511 ACPI_HANDLE reference_handle = NULL;
512 ACPI_BUFFER buffer;
513 u32 i = 0;
514
515 FUNCTION_TRACE("bm_evaluate_reference_list");
516
517 if (!reference_list) {
518 return_ACPI_STATUS(AE_BAD_PARAMETER);
519 }
520
521 MEMSET(&buffer, 0, sizeof(ACPI_BUFFER));
522
523 /*
524 * Evaluate Object:
525 * ----------------
526 */
527 status = bm_evaluate_object(acpi_handle, pathname, NULL, &buffer);
528 if (ACPI_FAILURE(status)) {
529 goto end;
530 }
531
532 /*
533 * Validate Package:
534 * -----------------
535 */
536 status = bm_cast_buffer(&buffer, (void**)&package,
537 sizeof(ACPI_OBJECT));
538 if (ACPI_FAILURE(status)) {
539 DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status);
540 goto end;
541 }
542
543 if (package->type != ACPI_TYPE_PACKAGE) {
544 status = AE_BAD_DATA;
545 DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status);
546 goto end;
547 }
548
549 if (package->package.count > BM_HANDLES_MAX) {
550 package->package.count = BM_HANDLES_MAX;
551 }
552
553 /*
554 * Parse Package Data:
555 * -------------------
556 */
557 for (i = 0; i < package->package.count; i++) {
558
559 element = &(package->package.elements[i]);
560
561 if (!element || (element->type != ACPI_TYPE_STRING)) {
562 status = AE_BAD_DATA;
563 DEBUG_PRINT(ACPI_WARN, ("Invalid element in package (not a device reference).\n"));
564 DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status);
565 break;
566 }
567
568 /*
569 * Resolve reference string (e.g. "\_PR_.CPU_") to an
570 * ACPI_HANDLE.
571 */
572 status = acpi_get_handle(acpi_handle,
573 element->string.pointer, &reference_handle);
574 if (ACPI_FAILURE(status)) {
575 status = AE_BAD_DATA;
576 DEBUG_PRINT(ACPI_WARN, ("Unable to resolve device reference [%s].\n", element->string.pointer));
577 DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status);
578 break;
579 }
580
581 /*
582 * Resolve ACPI_HANDLE to BM_HANDLE.
583 */
584 status = bm_get_handle(reference_handle,
585 &(reference_list->handles[i]));
586 if (ACPI_FAILURE(status)) {
587 status = AE_BAD_DATA;
588 DEBUG_PRINT(ACPI_WARN, ("Unable to resolve device reference for [0x%08x].\n", reference_handle));
589 DEBUG_EVAL_ERROR(ACPI_WARN, acpi_handle, pathname, status);
590 break;
591 }
592
593 DEBUG_PRINT(ACPI_INFO, ("Resolved reference [%s]->[0x%08x]->[0x%02x]\n", element->string.pointer, reference_handle, reference_list->handles[i]));
594
595 (reference_list->count)++;
596 }
597
598 end:
599 acpi_os_free(buffer.pointer);
600
601 return_ACPI_STATUS(status);
602 }
603
604