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