[ACPICA]
[reactos.git] / reactos / drivers / bus / acpi / busmgr / utils.c
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 <precomp.h>
27
28 #define NDEBUG
29 #include <debug.h>
30
31 /* Modified for ReactOS and latest ACPICA
32 * Copyright (C)2009 Samuel Serapion
33 */
34
35 #define _COMPONENT ACPI_BUS_COMPONENT
36 ACPI_MODULE_NAME ("acpi_utils")
37
38 static void
39 acpi_util_eval_error(ACPI_HANDLE h, ACPI_STRING p, ACPI_STATUS s)
40 {
41 #ifdef ACPI_DEBUG_OUTPUT
42 char prefix[80] = {'\0'};
43 ACPI_BUFFER buffer = {sizeof(prefix), prefix};
44 AcpiGetName(h, ACPI_FULL_PATHNAME, &buffer);
45 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",
46 (char *) prefix, p, AcpiFormatException(s)));
47 #else
48 return;
49 #endif
50 }
51
52
53 /* --------------------------------------------------------------------------
54 Object Evaluation Helpers
55 -------------------------------------------------------------------------- */
56
57
58 ACPI_STATUS
59 acpi_extract_package (
60 ACPI_OBJECT *package,
61 ACPI_BUFFER *format,
62 ACPI_BUFFER *buffer)
63 {
64 UINT32 size_required = 0;
65 UINT32 tail_offset = 0;
66 char *format_string = NULL;
67 UINT32 format_count = 0;
68 UINT32 i = 0;
69 UINT8 *head = NULL;
70 UINT8 *tail = NULL;
71
72 if (!package || (package->Type != ACPI_TYPE_PACKAGE) || (package->Package.Count < 1)) {
73 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'package' argument\n"));
74 return_ACPI_STATUS(AE_BAD_PARAMETER);
75 }
76
77 if (!format || !format->Pointer || (format->Length < 1)) {
78 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'format' argument\n"));
79 return_ACPI_STATUS(AE_BAD_PARAMETER);
80 }
81
82 if (!buffer) {
83 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'buffer' argument\n"));
84 return_ACPI_STATUS(AE_BAD_PARAMETER);
85 }
86
87 format_count = (format->Length/sizeof(char)) - 1;
88 if (format_count > package->Package.Count) {
89 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Format specifies more objects [%d] than exist in package [%d].", format_count, package->package.count));
90 return_ACPI_STATUS(AE_BAD_DATA);
91 }
92
93 format_string = format->Pointer;
94
95 /*
96 * Calculate size_required.
97 */
98 for (i=0; i<format_count; i++) {
99
100 ACPI_OBJECT *element = &(package->Package.Elements[i]);
101
102 if (!element) {
103 return_ACPI_STATUS(AE_BAD_DATA);
104 }
105
106 switch (element->Type) {
107
108 case ACPI_TYPE_INTEGER:
109 switch (format_string[i]) {
110 case 'N':
111 size_required += sizeof(ACPI_INTEGER);
112 tail_offset += sizeof(ACPI_INTEGER);
113 break;
114 case 'S':
115 size_required += sizeof(char*) + sizeof(ACPI_INTEGER) + sizeof(char);
116 tail_offset += sizeof(char*);
117 break;
118 default:
119 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid package element [%d]: got number, expecing [%c].\n", i, format_string[i]));
120 return_ACPI_STATUS(AE_BAD_DATA);
121 break;
122 }
123 break;
124
125 case ACPI_TYPE_STRING:
126 case ACPI_TYPE_BUFFER:
127 switch (format_string[i]) {
128 case 'S':
129 size_required += sizeof(char*) + (element->String.Length * sizeof(char)) + sizeof(char);
130 tail_offset += sizeof(char*);
131 break;
132 case 'B':
133 size_required += sizeof(UINT8*) + (element->Buffer.Length * sizeof(UINT8));
134 tail_offset += sizeof(UINT8*);
135 break;
136 default:
137 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid package element [%d] got string/buffer, expecing [%c].\n", i, format_string[i]));
138 return_ACPI_STATUS(AE_BAD_DATA);
139 break;
140 }
141 break;
142
143 case ACPI_TYPE_PACKAGE:
144 default:
145 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unsupported element at index=%d\n", i));
146 /* TBD: handle nested packages... */
147 return_ACPI_STATUS(AE_SUPPORT);
148 break;
149 }
150 }
151
152 /*
153 * Validate output buffer.
154 */
155 if (buffer->Length < size_required) {
156 buffer->Length = size_required;
157 return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
158 }
159 else if (buffer->Length != size_required || !buffer->Pointer) {
160 return_ACPI_STATUS(AE_BAD_PARAMETER);
161 }
162
163 head = buffer->Pointer;
164 tail = ((PUCHAR)buffer->Pointer) + tail_offset;
165
166 /*
167 * Extract package data.
168 */
169 for (i=0; i<format_count; i++) {
170
171 UINT8 **pointer = NULL;
172 ACPI_OBJECT *element = &(package->Package.Elements[i]);
173
174 if (!element) {
175 return_ACPI_STATUS(AE_BAD_DATA);
176 }
177
178 switch (element->Type) {
179
180 case ACPI_TYPE_INTEGER:
181 switch (format_string[i]) {
182 case 'N':
183 *((ACPI_INTEGER*)head) = element->Integer.Value;
184 head += sizeof(ACPI_INTEGER);
185 break;
186 case 'S':
187 pointer = (UINT8**)head;
188 *pointer = tail;
189 *((ACPI_INTEGER*)tail) = element->Integer.Value;
190 head += sizeof(ACPI_INTEGER*);
191 tail += sizeof(ACPI_INTEGER);
192 /* NULL terminate string */
193 *tail = (char)0;
194 tail += sizeof(char);
195 break;
196 default:
197 /* Should never get here */
198 break;
199 }
200 break;
201
202 case ACPI_TYPE_STRING:
203 case ACPI_TYPE_BUFFER:
204 switch (format_string[i]) {
205 case 'S':
206 pointer = (UINT8**)head;
207 *pointer = tail;
208 memcpy(tail, element->String.Pointer, element->String.Length);
209 head += sizeof(char*);
210 tail += element->String.Length * sizeof(char);
211 /* NULL terminate string */
212 *tail = (char)0;
213 tail += sizeof(char);
214 break;
215 case 'B':
216 pointer = (UINT8**)head;
217 *pointer = tail;
218 memcpy(tail, element->Buffer.Pointer, element->Buffer.Length);
219 head += sizeof(UINT8*);
220 tail += element->Buffer.Length * sizeof(UINT8);
221 break;
222 default:
223 /* Should never get here */
224 break;
225 }
226 break;
227
228 case ACPI_TYPE_PACKAGE:
229 /* TBD: handle nested packages... */
230 default:
231 /* Should never get here */
232 break;
233 }
234 }
235
236 return_ACPI_STATUS(AE_OK);
237 }
238
239
240 ACPI_STATUS
241 acpi_evaluate_integer (
242 ACPI_HANDLE handle,
243 ACPI_STRING pathname,
244 ACPI_OBJECT_LIST *arguments,
245 unsigned long long *data)
246 {
247 ACPI_STATUS status = AE_OK;
248 ACPI_OBJECT element;
249 ACPI_BUFFER buffer = {sizeof(ACPI_OBJECT), &element};
250
251 ACPI_FUNCTION_TRACE("acpi_evaluate_integer");
252
253 if (!data)
254 return_ACPI_STATUS(AE_BAD_PARAMETER);
255
256 status = AcpiEvaluateObject(handle, pathname, arguments, &buffer);
257 if (ACPI_FAILURE(status)) {
258 acpi_util_eval_error(handle, pathname, status);
259 return_ACPI_STATUS(status);
260 }
261
262 if (element.Type != ACPI_TYPE_INTEGER) {
263 acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
264 return_ACPI_STATUS(AE_BAD_DATA);
265 }
266
267 *data = element.Integer.Value;
268
269 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%lu]\n", *data));
270
271 return_ACPI_STATUS(AE_OK);
272 }
273
274
275 ACPI_STATUS
276 acpi_evaluate_reference (
277 ACPI_HANDLE handle,
278 ACPI_STRING pathname,
279 ACPI_OBJECT_LIST *arguments,
280 struct acpi_handle_list *list)
281 {
282 ACPI_STATUS status = AE_OK;
283 ACPI_OBJECT *package = NULL;
284 ACPI_OBJECT *element = NULL;
285 ACPI_BUFFER buffer = {ACPI_ALLOCATE_BUFFER, NULL};
286 UINT32 i = 0;
287
288 ACPI_FUNCTION_TRACE("acpi_evaluate_reference");
289
290 if (!list) {
291 return_ACPI_STATUS(AE_BAD_PARAMETER);
292 }
293
294 /* Evaluate object. */
295
296 status = AcpiEvaluateObject(handle, pathname, arguments, &buffer);
297 if (ACPI_FAILURE(status))
298 goto end;
299
300 package = (ACPI_OBJECT *) buffer.Pointer;
301
302 if ((buffer.Length == 0) || !package) {
303 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
304 "No return object (len %X ptr %p)\n",
305 buffer.Length, package));
306 status = AE_BAD_DATA;
307 acpi_util_eval_error(handle, pathname, status);
308 goto end;
309 }
310 if (package->Type != ACPI_TYPE_PACKAGE) {
311 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
312 "Expecting a [Package], found type %X\n",
313 package->Type));
314 status = AE_BAD_DATA;
315 acpi_util_eval_error(handle, pathname, status);
316 goto end;
317 }
318 if (!package->Package.Count) {
319 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
320 "[Package] has zero elements (%p)\n",
321 package));
322 status = AE_BAD_DATA;
323 acpi_util_eval_error(handle, pathname, status);
324 goto end;
325 }
326
327 if (package->Package.Count > ACPI_MAX_HANDLES) {
328 return AE_NO_MEMORY;
329 }
330 list->count = package->Package.Count;
331
332 /* Extract package data. */
333
334 for (i = 0; i < list->count; i++) {
335
336 element = &(package->Package.Elements[i]);
337
338 if (element->Type != ACPI_TYPE_LOCAL_REFERENCE) {
339 status = AE_BAD_DATA;
340 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
341 "Expecting a [Reference] package element, found type %X\n",
342 element->type));
343 acpi_util_eval_error(handle, pathname, status);
344 break;
345 }
346
347 if (!element->Reference.Handle) {
348 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid reference in"
349 " package %s\n", pathname));
350 status = AE_NULL_ENTRY;
351 break;
352 }
353 /* Get the ACPI_HANDLE. */
354
355 list->handles[i] = element->Reference.Handle;
356 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found reference [%p]\n",
357 list->handles[i]));
358 }
359
360 end:
361 if (ACPI_FAILURE(status)) {
362 list->count = 0;
363 //ExFreePool(list->handles);
364 }
365
366 if (buffer.Pointer)
367 AcpiOsFree(buffer.Pointer);
368
369 return_ACPI_STATUS(status);
370 }
371
372