1/** @file
2  ACPI Sdt Protocol Driver
3
4  Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved. <BR>
5  This program and the accompanying materials
6  are licensed and made available under the terms and conditions of the BSD License
7  which accompanies this distribution.  The full text of the license may be found at
8  http://opensource.org/licenses/bsd-license.php
9
10  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "AcpiTable.h"
16
17/**
18  Check if it is AML Root name
19
20  @param[in]    Buffer AML path.
21
22  @retval       TRUE  AML path is root.
23  @retval       FALSE AML path is not root.
24**/
25BOOLEAN
26AmlIsRootPath (
27  IN UINT8              *Buffer
28  )
29{
30  if ((Buffer[0] == AML_ROOT_CHAR) && (Buffer[1] == 0)) {
31    return TRUE;
32  } else {
33    return FALSE;
34  }
35}
36
37/**
38  Check if it is AML LeadName.
39
40  @param[in]    Ch   Char.
41
42  @retval       TRUE  Char is AML LeadName.
43  @retval       FALSE Char is not AML LeadName.
44**/
45BOOLEAN
46AmlIsLeadName (
47  IN CHAR8 Ch
48  )
49{
50  if ((Ch == '_') || (Ch >= 'A' && Ch <= 'Z')) {
51    return TRUE;
52  } else {
53    return FALSE;
54  }
55}
56
57/**
58  Check if it is AML Name.
59
60  @param[in]    Ch   Char.
61
62  @retval       TRUE  Char is AML Name.
63  @retval       FALSE Char is not AML Name.
64**/
65BOOLEAN
66AmlIsName (
67  IN CHAR8 Ch
68  )
69{
70  if (AmlIsLeadName (Ch) || (Ch >= '0' && Ch <= '9')) {
71    return TRUE;
72  } else {
73    return FALSE;
74  }
75}
76
77/**
78  Return is buffer is AML NameSeg.
79
80  @param[in]    Buffer     AML NameSement.
81
82  @retval       TRUE       It is AML NameSegment.
83  @retval       FALSE      It is not AML NameSegment.
84**/
85BOOLEAN
86AmlIsNameSeg (
87  IN  UINT8              *Buffer
88  )
89{
90  UINTN  Index;
91  if (!AmlIsLeadName (Buffer[0])) {
92    return FALSE;
93  }
94  for (Index = 1; Index < AML_NAME_SEG_SIZE; Index++) {
95    if (!AmlIsName (Buffer[Index])) {
96      return FALSE;
97    }
98  }
99  return TRUE;
100}
101
102/**
103  Get AML NameString size.
104
105  @param[in]    Buffer     AML NameString.
106  @param[out]   BufferSize AML NameString size
107
108  @retval       EFI_SUCCESS           Success.
109  @retval       EFI_INVALID_PARAMETER Buffer does not refer to a valid AML NameString.
110**/
111EFI_STATUS
112AmlGetNameStringSize (
113  IN  UINT8              *Buffer,
114  OUT UINTN              *BufferSize
115  )
116{
117  UINTN                 SegCount;
118  UINTN                 Length;
119  UINTN                 Index;
120
121  Length = 0;
122
123  //
124  // Parse root or parent prefix
125  //
126  if (*Buffer == AML_ROOT_CHAR) {
127    Buffer ++;
128    Length ++;
129  } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
130    do {
131      Buffer ++;
132      Length ++;
133    } while (*Buffer == AML_PARENT_PREFIX_CHAR);
134  }
135
136  //
137  // Parse name segment
138  //
139  if (*Buffer == AML_DUAL_NAME_PREFIX) {
140    Buffer ++;
141    Length ++;
142    SegCount = 2;
143  } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
144    Buffer ++;
145    Length ++;
146    SegCount = *Buffer;
147    Buffer ++;
148    Length ++;
149  } else if (*Buffer == 0) {
150    //
151    // NULL Name, only for Root
152    //
153    SegCount = 0;
154    Buffer --;
155    if ((Length == 1) && (*Buffer == AML_ROOT_CHAR)) {
156      *BufferSize = 2;
157      return EFI_SUCCESS;
158    } else {
159      return EFI_INVALID_PARAMETER;
160    }
161  } else {
162    //
163    // NameSeg
164    //
165    SegCount = 1;
166  }
167
168  Index = 0;
169  do {
170    if (!AmlIsNameSeg (Buffer)) {
171      return EFI_INVALID_PARAMETER;
172    }
173    Buffer += AML_NAME_SEG_SIZE;
174    Length += AML_NAME_SEG_SIZE;
175    Index ++;
176  } while (Index < SegCount);
177
178  *BufferSize = Length;
179  return EFI_SUCCESS;
180}
181
182/**
183  Check if it is ASL LeadName.
184
185  @param[in]    Ch   Char.
186
187  @retval       TRUE  Char is ASL LeadName.
188  @retval       FALSE Char is not ASL LeadName.
189**/
190BOOLEAN
191AmlIsAslLeadName (
192  IN CHAR8 Ch
193  )
194{
195  if (AmlIsLeadName (Ch) || (Ch >= 'a' && Ch <= 'z')) {
196    return TRUE;
197  } else {
198    return FALSE;
199  }
200}
201
202/**
203  Check if it is ASL Name.
204
205  @param[in]    Ch   Char.
206
207  @retval       TRUE  Char is ASL Name.
208  @retval       FALSE Char is not ASL Name.
209**/
210BOOLEAN
211AmlIsAslName (
212  IN CHAR8 Ch
213  )
214{
215  if (AmlIsAslLeadName (Ch) || (Ch >= '0' && Ch <= '9')) {
216    return TRUE;
217  } else {
218    return FALSE;
219  }
220}
221
222/**
223  Get ASL NameString size.
224
225  @param[in]    Buffer   ASL NameString.
226
227  @return       ASL NameString size.
228**/
229UINTN
230AmlGetAslNameSegLength (
231  IN UINT8 *Buffer
232  )
233{
234  UINTN Length;
235  UINTN Index;
236
237  if (*Buffer == 0) {
238    return 0;
239  }
240
241  Length = 0;
242  //
243  // 1st
244  //
245  if (AmlIsAslLeadName (*Buffer)) {
246    Length ++;
247    Buffer ++;
248  }
249  if ((*Buffer == 0) || (*Buffer == '.')) {
250    return Length;
251  }
252  //
253  // 2, 3, 4 name char
254  //
255  for (Index = 0; Index < 3; Index++) {
256    if (AmlIsAslName (*Buffer)) {
257      Length ++;
258      Buffer ++;
259    }
260    if ((*Buffer == 0) || (*Buffer == '.')) {
261      return Length;
262    }
263  }
264
265  //
266  // Invalid ASL name
267  //
268  return 0;
269}
270
271/**
272  Get ASL NameString size.
273
274  @param[in]    Buffer   ASL NameString.
275  @param[out]   Root     On return, points to Root char number.
276  @param[out]   Parent   On return, points to Parent char number.
277  @param[out]   SegCount On return, points to Segment count.
278
279  @return       ASL NameString size.
280**/
281UINTN
282AmlGetAslNameStringSize (
283  IN UINT8              *Buffer,
284  OUT UINTN             *Root,
285  OUT UINTN             *Parent,
286  OUT UINTN             *SegCount
287  )
288{
289  UINTN NameLength;
290  UINTN TotalLength;
291
292  *Root   = 0;
293  *Parent = 0;
294  *SegCount = 0;
295  TotalLength = 0;
296  NameLength = 0;
297  if (*Buffer == AML_ROOT_CHAR) {
298    *Root = 1;
299    Buffer ++;
300  } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
301    do {
302      Buffer ++;
303      (*Parent) ++;
304    } while (*Buffer == AML_PARENT_PREFIX_CHAR);
305  }
306
307  //
308  // Now parse name
309  //
310  while (*Buffer != 0) {
311    NameLength = AmlGetAslNameSegLength (Buffer);
312    if ((NameLength == 0) || (NameLength > AML_NAME_SEG_SIZE)) {
313      return 0;
314    }
315    (*SegCount) ++;
316    Buffer += NameLength;
317    if (*Buffer == 0) {
318      break;
319    }
320    Buffer ++;
321  }
322
323  //
324  // Check SegCoount
325  //
326  if (*SegCount > 0xFF) {
327    return 0;
328  }
329
330  //
331  // Calculate total length
332  //
333  TotalLength = *Root + *Parent + (*SegCount) * AML_NAME_SEG_SIZE;
334  if (*SegCount > 2) {
335    TotalLength += 2;
336  } else if (*SegCount == 2) {
337    TotalLength += 1;
338  }
339
340  //
341  // Add NULL char
342  //
343  TotalLength ++;
344
345  return TotalLength;
346}
347
348/**
349  Copy mem, and cast all the char in dest to be upper case.
350
351  @param[in]    DstBuffer   Destination buffer.
352  @param[in]    SrcBuffer   Source buffer.
353  @param[in]    Length      Buffer length.
354**/
355VOID
356AmlUpperCaseCopyMem (
357  IN UINT8 *DstBuffer,
358  IN UINT8 *SrcBuffer,
359  IN UINTN Length
360  )
361{
362  UINTN Index;
363
364  for (Index = 0; Index < Length; Index++) {
365    if (SrcBuffer[Index] >= 'a' && SrcBuffer[Index] <= 'z') {
366      DstBuffer[Index] = (UINT8)(SrcBuffer[Index] - 'a' + 'A');
367    } else {
368      DstBuffer[Index] = SrcBuffer[Index];
369    }
370  }
371}
372
373/**
374  Return AML name according to ASL name.
375  The caller need free the AmlName returned.
376
377  @param[in]    AslPath     ASL name.
378
379  @return AmlName
380**/
381UINT8 *
382AmlNameFromAslName (
383  IN UINT8 *AslPath
384  )
385{
386  UINTN Root;
387  UINTN Parent;
388  UINTN SegCount;
389  UINTN TotalLength;
390  UINTN NameLength;
391  UINT8 *Buffer;
392  UINT8 *AmlPath;
393  UINT8 *AmlBuffer;
394
395  TotalLength = AmlGetAslNameStringSize (AslPath, &Root, &Parent, &SegCount);
396  if (TotalLength == 0) {
397    return NULL;
398  }
399
400  AmlPath = AllocatePool (TotalLength);
401  ASSERT (AmlPath != NULL);
402
403  AmlBuffer = AmlPath;
404  Buffer = AslPath;
405
406  //
407  // Handle Root and Parent
408  //
409  if (Root == 1) {
410    *AmlBuffer = AML_ROOT_CHAR;
411    AmlBuffer ++;
412    Buffer ++;
413  } else if (Parent > 0) {
414    SetMem (AmlBuffer, Parent, AML_PARENT_PREFIX_CHAR);
415    AmlBuffer += Parent;
416    Buffer += Parent;
417  }
418
419  //
420  // Handle SegCount
421  //
422  if (SegCount > 2) {
423    *AmlBuffer = AML_MULTI_NAME_PREFIX;
424    AmlBuffer ++;
425    *AmlBuffer = (UINT8)SegCount;
426    AmlBuffer ++;
427  } else if (SegCount == 2) {
428    *AmlBuffer = AML_DUAL_NAME_PREFIX;
429    AmlBuffer ++;
430  }
431
432  //
433  // Now to name
434  //
435  while (*Buffer != 0) {
436    NameLength = AmlGetAslNameSegLength (Buffer);
437    ASSERT ((NameLength != 0) && (NameLength <= AML_NAME_SEG_SIZE));
438    AmlUpperCaseCopyMem (AmlBuffer, Buffer, NameLength);
439    SetMem (AmlBuffer + NameLength, AML_NAME_SEG_SIZE - NameLength, AML_NAME_CHAR__);
440    Buffer += NameLength;
441    AmlBuffer += AML_NAME_SEG_SIZE;
442    if (*Buffer == 0) {
443      break;
444    }
445    Buffer ++;
446  }
447
448  //
449  // Add NULL
450  //
451  AmlPath[TotalLength - 1] = 0;
452
453  return AmlPath;
454}
455
456/**
457  Print AML NameSeg.
458
459  @param[in] Buffer AML NameSeg.
460**/
461VOID
462AmlPrintNameSeg (
463  IN UINT8              *Buffer
464  )
465{
466  DEBUG ((EFI_D_ERROR, "%c", Buffer[0]));
467  if ((Buffer[1] == '_') && (Buffer[2] == '_') && (Buffer[3] == '_')) {
468    return ;
469  }
470  DEBUG ((EFI_D_ERROR, "%c", Buffer[1]));
471  if ((Buffer[2] == '_') && (Buffer[3] == '_')) {
472    return ;
473  }
474  DEBUG ((EFI_D_ERROR, "%c", Buffer[2]));
475  if (Buffer[3] == '_') {
476    return ;
477  }
478  DEBUG ((EFI_D_ERROR, "%c", Buffer[3]));
479  return ;
480}
481
482/**
483  Print AML NameString.
484
485  @param[in] Buffer AML NameString.
486**/
487VOID
488AmlPrintNameString (
489  IN UINT8              *Buffer
490  )
491{
492  UINT8                 SegCount;
493  UINT8                 Index;
494
495  if (*Buffer == AML_ROOT_CHAR) {
496    //
497    // RootChar
498    //
499    Buffer ++;
500    DEBUG ((EFI_D_ERROR, "\\"));
501  } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
502    //
503    // ParentPrefixChar
504    //
505    do {
506      Buffer ++;
507      DEBUG ((EFI_D_ERROR, "^"));
508    } while (*Buffer == AML_PARENT_PREFIX_CHAR);
509  }
510
511  if (*Buffer == AML_DUAL_NAME_PREFIX) {
512    //
513    // DualName
514    //
515    Buffer ++;
516    SegCount = 2;
517  } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
518    //
519    // MultiName
520    //
521    Buffer ++;
522    SegCount = *Buffer;
523    Buffer ++;
524  } else if (*Buffer == 0) {
525    //
526    // NULL Name
527    //
528    return ;
529  } else {
530    //
531    // NameSeg
532    //
533    SegCount = 1;
534  }
535
536  AmlPrintNameSeg (Buffer);
537  Buffer += AML_NAME_SEG_SIZE;
538  for (Index = 0; Index < SegCount - 1; Index++) {
539    DEBUG ((EFI_D_ERROR, "."));
540    AmlPrintNameSeg (Buffer);
541    Buffer += AML_NAME_SEG_SIZE;
542  }
543
544  return ;
545}
546