Ported ACPI CA (from the nice guys at Intel) to ReactOS (ACPI bus driver).
[reactos.git] / reactos / drivers / bus / acpi / executer / amnames.c
1
2 /******************************************************************************
3 *
4 * Module Name: amnames - interpreter/scanner name load/execute
5 * $Revision: 1.1 $
6 *
7 *****************************************************************************/
8
9 /*
10 * Copyright (C) 2000, 2001 R. Byron Moore
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27
28 #include "acpi.h"
29 #include "acinterp.h"
30 #include "amlcode.h"
31 #include "acnamesp.h"
32
33 #define _COMPONENT ACPI_EXECUTER
34 MODULE_NAME ("amnames")
35
36
37 /* AML Package Length encodings */
38
39 #define ACPI_AML_PACKAGE_TYPE1 0x40
40 #define ACPI_AML_PACKAGE_TYPE2 0x4000
41 #define ACPI_AML_PACKAGE_TYPE3 0x400000
42 #define ACPI_AML_PACKAGE_TYPE4 0x40000000
43
44
45 /*******************************************************************************
46 *
47 * FUNCTION: Acpi_aml_allocate_name_string
48 *
49 * PARAMETERS: Prefix_count - Count of parent levels. Special cases:
50 * (-1) = root, 0 = none
51 * Num_name_segs - count of 4-character name segments
52 *
53 * RETURN: A pointer to the allocated string segment. This segment must
54 * be deleted by the caller.
55 *
56 * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name
57 * string is long enough, and set up prefix if any.
58 *
59 ******************************************************************************/
60
61 NATIVE_CHAR *
62 acpi_aml_allocate_name_string (
63 u32 prefix_count,
64 u32 num_name_segs)
65 {
66 NATIVE_CHAR *temp_ptr;
67 NATIVE_CHAR *name_string;
68 u32 size_needed;
69
70
71 /*
72 * Allow room for all \ and ^ prefixes, all segments, and a Multi_name_prefix.
73 * Also, one byte for the null terminator.
74 * This may actually be somewhat longer than needed.
75 */
76
77 if (prefix_count == (u32) -1) {
78 /* Special case for root */
79
80 size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1;
81 }
82 else {
83 size_needed = prefix_count + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1;
84 }
85
86 /*
87 * Allocate a buffer for the name.
88 * This buffer must be deleted by the caller!
89 */
90
91 name_string = acpi_cm_allocate (size_needed);
92 if (!name_string) {
93 REPORT_ERROR (("Aml_allocate_name_string: name allocation failure\n"));
94 return (NULL);
95 }
96
97 temp_ptr = name_string;
98
99 /* Set up Root or Parent prefixes if needed */
100
101 if (prefix_count == (u32) -1) {
102 *temp_ptr++ = AML_ROOT_PREFIX;
103 }
104
105 else {
106 while (prefix_count--) {
107 *temp_ptr++ = AML_PARENT_PREFIX;
108 }
109 }
110
111
112 /* Set up Dual or Multi prefixes if needed */
113
114 if (num_name_segs > 2) {
115 /* Set up multi prefixes */
116
117 *temp_ptr++ = AML_MULTI_NAME_PREFIX_OP;
118 *temp_ptr++ = (char) num_name_segs;
119 }
120
121 else if (2 == num_name_segs) {
122 /* Set up dual prefixes */
123
124 *temp_ptr++ = AML_DUAL_NAME_PREFIX;
125 }
126
127 /*
128 * Terminate string following prefixes. Acpi_aml_exec_name_segment() will
129 * append the segment(s)
130 */
131
132 *temp_ptr = 0;
133
134 return (name_string);
135 }
136
137 /*******************************************************************************
138 *
139 * FUNCTION: Acpi_aml_exec_name_segment
140 *
141 * PARAMETERS: Interpreter_mode - Current running mode (load1/Load2/Exec)
142 *
143 * RETURN: Status
144 *
145 * DESCRIPTION: Execute a name segment (4 bytes)
146 *
147 ******************************************************************************/
148
149 ACPI_STATUS
150 acpi_aml_exec_name_segment (
151 u8 **in_aml_address,
152 NATIVE_CHAR *name_string)
153 {
154 u8 *aml_address = *in_aml_address;
155 ACPI_STATUS status = AE_OK;
156 u32 index;
157 NATIVE_CHAR char_buf[5];
158
159
160 /*
161 * If first character is a digit, then we know that we aren't looking at a
162 * valid name segment
163 */
164
165 char_buf[0] = *aml_address;
166
167 if ('0' <= char_buf[0] && char_buf[0] <= '9') {
168 return (AE_CTRL_PENDING);
169 }
170
171 for (index = 4;
172 (index > 0) && (acpi_cm_valid_acpi_character (*aml_address));
173 --index) {
174 char_buf[4 - index] = *aml_address++;
175 }
176
177
178 /* Valid name segment */
179
180 if (0 == index) {
181 /* Found 4 valid characters */
182
183 char_buf[4] = '\0';
184
185 if (name_string) {
186 STRCAT (name_string, char_buf);
187 }
188
189 }
190
191 else if (4 == index) {
192 /*
193 * First character was not a valid name character,
194 * so we are looking at something other than a name.
195 */
196 status = AE_CTRL_PENDING;
197 }
198
199 else {
200 /* Segment started with one or more valid characters, but fewer than 4 */
201
202 status = AE_AML_BAD_NAME;
203 }
204
205 *in_aml_address = aml_address;
206
207 return (status);
208 }
209
210
211 /*******************************************************************************
212 *
213 * FUNCTION: Acpi_aml_get_name_string
214 *
215 * PARAMETERS: Data_type - Data type to be associated with this name
216 *
217 * RETURN: Status
218 *
219 * DESCRIPTION: Get a name, including any prefixes.
220 *
221 ******************************************************************************/
222
223
224 ACPI_STATUS
225 acpi_aml_get_name_string (
226 OBJECT_TYPE_INTERNAL data_type,
227 u8 *in_aml_address,
228 NATIVE_CHAR **out_name_string,
229 u32 *out_name_length)
230 {
231 ACPI_STATUS status = AE_OK;
232 u8 *aml_address = in_aml_address;
233 NATIVE_CHAR *name_string = NULL;
234 u32 num_segments;
235 u32 prefix_count = 0;
236 u8 prefix = 0;
237 u8 has_prefix = FALSE;
238
239
240 if (INTERNAL_TYPE_DEF_FIELD == data_type ||
241 INTERNAL_TYPE_BANK_FIELD == data_type ||
242 INTERNAL_TYPE_INDEX_FIELD == data_type) {
243 /* Disallow prefixes for types associated with field names */
244
245 name_string = acpi_aml_allocate_name_string (0, 1);
246 if (!name_string) {
247 status = AE_NO_MEMORY;
248 }
249 else {
250 status = acpi_aml_exec_name_segment (&aml_address, name_string);
251 }
252 }
253
254 else {
255 /*
256 * Data_type is not a field name.
257 * Examine first character of name for root or parent prefix operators
258 */
259
260 switch (*aml_address) {
261
262 case AML_ROOT_PREFIX:
263
264 prefix = *aml_address++;
265 /*
266 * Remember that we have a Root_prefix --
267 * see comment in Acpi_aml_allocate_name_string()
268 */
269 prefix_count = (u32) -1;
270 has_prefix = TRUE;
271 break;
272
273
274 case AML_PARENT_PREFIX:
275
276 /* Increment past possibly multiple parent prefixes */
277
278 do {
279 prefix = *aml_address++;
280 ++prefix_count;
281
282 } while (*aml_address == AML_PARENT_PREFIX);
283 has_prefix = TRUE;
284 break;
285
286
287 default:
288
289 break;
290 }
291
292
293 /* Examine first character of name for name segment prefix operator */
294
295 switch (*aml_address) {
296
297 case AML_DUAL_NAME_PREFIX:
298
299 prefix = *aml_address++;
300 name_string = acpi_aml_allocate_name_string (prefix_count, 2);
301 if (!name_string) {
302 status = AE_NO_MEMORY;
303 break;
304 }
305
306 /* Indicate that we processed a prefix */
307 has_prefix = TRUE;
308
309 status = acpi_aml_exec_name_segment (&aml_address, name_string);
310 if (ACPI_SUCCESS (status)) {
311 status = acpi_aml_exec_name_segment (&aml_address, name_string);
312 }
313 break;
314
315
316 case AML_MULTI_NAME_PREFIX_OP:
317
318 prefix = *aml_address++;
319 /* Fetch count of segments remaining in name path */
320
321 num_segments = *aml_address++;
322
323 name_string = acpi_aml_allocate_name_string (prefix_count, num_segments);
324 if (!name_string) {
325 status = AE_NO_MEMORY;
326 break;
327 }
328
329 /* Indicate that we processed a prefix */
330 has_prefix = TRUE;
331
332 while (num_segments &&
333 (status = acpi_aml_exec_name_segment (&aml_address, name_string)) == AE_OK) {
334 --num_segments;
335 }
336
337 break;
338
339
340 case 0:
341
342 /* Null_name valid as of 8-12-98 ASL/AML Grammar Update */
343
344
345 /* Consume the NULL byte */
346
347 aml_address++;
348 name_string = acpi_aml_allocate_name_string (prefix_count, 0);
349 if (!name_string) {
350 status = AE_NO_MEMORY;
351 break;
352 }
353
354 break;
355
356
357 default:
358
359 /* Name segment string */
360
361 name_string = acpi_aml_allocate_name_string (prefix_count, 1);
362 if (!name_string) {
363 status = AE_NO_MEMORY;
364 break;
365 }
366
367 status = acpi_aml_exec_name_segment (&aml_address, name_string);
368 break;
369
370 } /* Switch (Peek_op ()) */
371 }
372
373
374 if (AE_CTRL_PENDING == status && has_prefix) {
375 /* Ran out of segments after processing a prefix */
376
377 REPORT_ERROR (
378 ("Aml_do_name: Malformed Name at %p\n", name_string));
379 status = AE_AML_BAD_NAME;
380 }
381
382
383 *out_name_string = name_string;
384 *out_name_length = (u32) (aml_address - in_aml_address);
385
386 return (status);
387 }
388
389