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