:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / executer / amnames.c
1
2 /******************************************************************************
3  *
4  * Module Name: amnames - interpreter/scanner name load/execute
5  *              $Revision$
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