1 | #include <uacpi/types.h> |
2 | #include <uacpi/status.h> |
3 | |
4 | #include <uacpi/internal/context.h> |
5 | #include <uacpi/internal/utilities.h> |
6 | #include <uacpi/internal/log.h> |
7 | #include <uacpi/uacpi.h> |
8 | |
9 | void uacpi_eisa_id_to_string(uacpi_u32 id, uacpi_char *out_string) |
10 | { |
11 | static uacpi_char hex_to_ascii[16] = { |
12 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', |
13 | 'A', 'B', 'C', 'D', 'E', 'F' |
14 | }; |
15 | |
16 | /* |
17 | * For whatever reason bits are encoded upper to lower here, swap |
18 | * them around so that we don't have to do ridiculous bit shifts |
19 | * everywhere. |
20 | */ |
21 | union { |
22 | uacpi_u8 bytes[4]; |
23 | uacpi_u32 dword; |
24 | } orig, swapped; |
25 | |
26 | orig.dword = id; |
27 | swapped.bytes[0] = orig.bytes[3]; |
28 | swapped.bytes[1] = orig.bytes[2]; |
29 | swapped.bytes[2] = orig.bytes[1]; |
30 | swapped.bytes[3] = orig.bytes[0]; |
31 | |
32 | /* |
33 | * Bit 16 - 20: 3rd character (- 0x40) of mfg code |
34 | * Bit 21 - 25: 2nd character (- 0x40) of mfg code |
35 | * Bit 26 - 30: 1st character (- 0x40) of mfg code |
36 | */ |
37 | out_string[0] = (uacpi_char)(0x40 + ((swapped.dword >> 26) & 0x1F)); |
38 | out_string[1] = (uacpi_char)(0x40 + ((swapped.dword >> 21) & 0x1F)); |
39 | out_string[2] = (uacpi_char)(0x40 + ((swapped.dword >> 16) & 0x1F)); |
40 | |
41 | /* |
42 | * Bit 0 - 3 : 4th hex digit of product number |
43 | * Bit 4 - 7 : 3rd hex digit of product number |
44 | * Bit 8 - 11: 2nd hex digit of product number |
45 | * Bit 12 - 15: 1st hex digit of product number |
46 | */ |
47 | out_string[3] = hex_to_ascii[(swapped.dword >> 12) & 0x0F]; |
48 | out_string[4] = hex_to_ascii[(swapped.dword >> 8 ) & 0x0F]; |
49 | out_string[5] = hex_to_ascii[(swapped.dword >> 4 ) & 0x0F]; |
50 | out_string[6] = hex_to_ascii[(swapped.dword >> 0 ) & 0x0F]; |
51 | |
52 | out_string[7] = '\0'; |
53 | } |
54 | |
55 | enum char_type { |
56 | CHAR_TYPE_CONTROL = 1 << 0, |
57 | CHAR_TYPE_SPACE = 1 << 1, |
58 | CHAR_TYPE_BLANK = 1 << 2, |
59 | CHAR_TYPE_PUNCTUATION = 1 << 3, |
60 | CHAR_TYPE_LOWER = 1 << 4, |
61 | CHAR_TYPE_UPPER = 1 << 5, |
62 | CHAR_TYPE_DIGIT = 1 << 6, |
63 | CHAR_TYPE_HEX_DIGIT = 1 << 7, |
64 | CHAR_TYPE_ALPHA = CHAR_TYPE_LOWER | CHAR_TYPE_UPPER, |
65 | CHAR_TYPE_ALHEX = CHAR_TYPE_ALPHA | CHAR_TYPE_HEX_DIGIT, |
66 | CHAR_TYPE_ALNUM = CHAR_TYPE_ALPHA | CHAR_TYPE_DIGIT, |
67 | }; |
68 | |
69 | static const uacpi_u8 ascii_map[256] = { |
70 | CHAR_TYPE_CONTROL, // 0 |
71 | CHAR_TYPE_CONTROL, // 1 |
72 | CHAR_TYPE_CONTROL, // 2 |
73 | CHAR_TYPE_CONTROL, // 3 |
74 | CHAR_TYPE_CONTROL, // 4 |
75 | CHAR_TYPE_CONTROL, // 5 |
76 | CHAR_TYPE_CONTROL, // 6 |
77 | CHAR_TYPE_CONTROL, // 7 |
78 | CHAR_TYPE_CONTROL, // -> 8 control codes |
79 | |
80 | CHAR_TYPE_CONTROL | CHAR_TYPE_SPACE | CHAR_TYPE_BLANK, // 9 tab |
81 | |
82 | CHAR_TYPE_CONTROL | CHAR_TYPE_SPACE, // 10 |
83 | CHAR_TYPE_CONTROL | CHAR_TYPE_SPACE, // 11 |
84 | CHAR_TYPE_CONTROL | CHAR_TYPE_SPACE, // 12 |
85 | CHAR_TYPE_CONTROL | CHAR_TYPE_SPACE, // -> 13 whitespaces |
86 | |
87 | CHAR_TYPE_CONTROL, // 14 |
88 | CHAR_TYPE_CONTROL, // 15 |
89 | CHAR_TYPE_CONTROL, // 16 |
90 | CHAR_TYPE_CONTROL, // 17 |
91 | CHAR_TYPE_CONTROL, // 18 |
92 | CHAR_TYPE_CONTROL, // 19 |
93 | CHAR_TYPE_CONTROL, // 20 |
94 | CHAR_TYPE_CONTROL, // 21 |
95 | CHAR_TYPE_CONTROL, // 22 |
96 | CHAR_TYPE_CONTROL, // 23 |
97 | CHAR_TYPE_CONTROL, // 24 |
98 | CHAR_TYPE_CONTROL, // 25 |
99 | CHAR_TYPE_CONTROL, // 26 |
100 | CHAR_TYPE_CONTROL, // 27 |
101 | CHAR_TYPE_CONTROL, // 28 |
102 | CHAR_TYPE_CONTROL, // 29 |
103 | CHAR_TYPE_CONTROL, // 30 |
104 | CHAR_TYPE_CONTROL, // -> 31 control codes |
105 | |
106 | CHAR_TYPE_SPACE | CHAR_TYPE_BLANK, // 32 space |
107 | |
108 | CHAR_TYPE_PUNCTUATION, // 33 |
109 | CHAR_TYPE_PUNCTUATION, // 34 |
110 | CHAR_TYPE_PUNCTUATION, // 35 |
111 | CHAR_TYPE_PUNCTUATION, // 36 |
112 | CHAR_TYPE_PUNCTUATION, // 37 |
113 | CHAR_TYPE_PUNCTUATION, // 38 |
114 | CHAR_TYPE_PUNCTUATION, // 39 |
115 | CHAR_TYPE_PUNCTUATION, // 40 |
116 | CHAR_TYPE_PUNCTUATION, // 41 |
117 | CHAR_TYPE_PUNCTUATION, // 42 |
118 | CHAR_TYPE_PUNCTUATION, // 43 |
119 | CHAR_TYPE_PUNCTUATION, // 44 |
120 | CHAR_TYPE_PUNCTUATION, // 45 |
121 | CHAR_TYPE_PUNCTUATION, // 46 |
122 | CHAR_TYPE_PUNCTUATION, // -> 47 punctuation |
123 | |
124 | CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 48 |
125 | CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 49 |
126 | CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 50 |
127 | CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 51 |
128 | CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 52 |
129 | CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 53 |
130 | CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 54 |
131 | CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 55 |
132 | CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // 56 |
133 | CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT, // -> 57 digits |
134 | |
135 | CHAR_TYPE_PUNCTUATION, // 58 |
136 | CHAR_TYPE_PUNCTUATION, // 59 |
137 | CHAR_TYPE_PUNCTUATION, // 60 |
138 | CHAR_TYPE_PUNCTUATION, // 61 |
139 | CHAR_TYPE_PUNCTUATION, // 62 |
140 | CHAR_TYPE_PUNCTUATION, // 63 |
141 | CHAR_TYPE_PUNCTUATION, // -> 64 punctuation |
142 | |
143 | CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // 65 |
144 | CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // 66 |
145 | CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // 67 |
146 | CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // 68 |
147 | CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // 69 |
148 | CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT, // -> 70 ABCDEF |
149 | |
150 | CHAR_TYPE_UPPER, // 71 |
151 | CHAR_TYPE_UPPER, // 72 |
152 | CHAR_TYPE_UPPER, // 73 |
153 | CHAR_TYPE_UPPER, // 74 |
154 | CHAR_TYPE_UPPER, // 75 |
155 | CHAR_TYPE_UPPER, // 76 |
156 | CHAR_TYPE_UPPER, // 77 |
157 | CHAR_TYPE_UPPER, // 78 |
158 | CHAR_TYPE_UPPER, // 79 |
159 | CHAR_TYPE_UPPER, // 80 |
160 | CHAR_TYPE_UPPER, // 81 |
161 | CHAR_TYPE_UPPER, // 82 |
162 | CHAR_TYPE_UPPER, // 83 |
163 | CHAR_TYPE_UPPER, // 84 |
164 | CHAR_TYPE_UPPER, // 85 |
165 | CHAR_TYPE_UPPER, // 86 |
166 | CHAR_TYPE_UPPER, // 87 |
167 | CHAR_TYPE_UPPER, // 88 |
168 | CHAR_TYPE_UPPER, // 89 |
169 | CHAR_TYPE_UPPER, // -> 90 the rest of UPPERCASE alphabet |
170 | |
171 | CHAR_TYPE_PUNCTUATION, // 91 |
172 | CHAR_TYPE_PUNCTUATION, // 92 |
173 | CHAR_TYPE_PUNCTUATION, // 93 |
174 | CHAR_TYPE_PUNCTUATION, // 94 |
175 | CHAR_TYPE_PUNCTUATION, // 95 |
176 | CHAR_TYPE_PUNCTUATION, // -> 96 punctuation |
177 | |
178 | CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // 97 |
179 | CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // 98 |
180 | CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // 99 |
181 | CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // 100 |
182 | CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // 101 |
183 | CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT, // -> 102 abcdef |
184 | |
185 | CHAR_TYPE_LOWER, // 103 |
186 | CHAR_TYPE_LOWER, // 104 |
187 | CHAR_TYPE_LOWER, // 105 |
188 | CHAR_TYPE_LOWER, // 106 |
189 | CHAR_TYPE_LOWER, // 107 |
190 | CHAR_TYPE_LOWER, // 108 |
191 | CHAR_TYPE_LOWER, // 109 |
192 | CHAR_TYPE_LOWER, // 110 |
193 | CHAR_TYPE_LOWER, // 111 |
194 | CHAR_TYPE_LOWER, // 112 |
195 | CHAR_TYPE_LOWER, // 113 |
196 | CHAR_TYPE_LOWER, // 114 |
197 | CHAR_TYPE_LOWER, // 115 |
198 | CHAR_TYPE_LOWER, // 116 |
199 | CHAR_TYPE_LOWER, // 117 |
200 | CHAR_TYPE_LOWER, // 118 |
201 | CHAR_TYPE_LOWER, // 119 |
202 | CHAR_TYPE_LOWER, // 120 |
203 | CHAR_TYPE_LOWER, // 121 |
204 | CHAR_TYPE_LOWER, // -> 122 the rest of UPPERCASE alphabet |
205 | |
206 | CHAR_TYPE_PUNCTUATION, // 123 |
207 | CHAR_TYPE_PUNCTUATION, // 124 |
208 | CHAR_TYPE_PUNCTUATION, // 125 |
209 | CHAR_TYPE_PUNCTUATION, // -> 126 punctuation |
210 | |
211 | CHAR_TYPE_CONTROL // 127 backspace |
212 | }; |
213 | |
214 | static inline uacpi_bool is_valid_name_byte(uacpi_u8 c) |
215 | { |
216 | // ‘_’ := 0x5F |
217 | if (c == 0x5F) |
218 | return UACPI_TRUE; |
219 | |
220 | /* |
221 | * LeadNameChar := ‘A’-‘Z’ | ‘_’ |
222 | * DigitChar := ‘0’ - ‘9’ |
223 | * NameChar := DigitChar | LeadNameChar |
224 | * ‘A’-‘Z’ := 0x41 - 0x5A |
225 | * ‘0’-‘9’ := 0x30 - 0x39 |
226 | */ |
227 | return (ascii_map[c] & (CHAR_TYPE_DIGIT | CHAR_TYPE_UPPER)) != 0; |
228 | } |
229 | |
230 | uacpi_bool uacpi_is_valid_nameseg(uacpi_u8 *nameseg) |
231 | { |
232 | return is_valid_name_byte(c: nameseg[0]) && |
233 | is_valid_name_byte(c: nameseg[1]) && |
234 | is_valid_name_byte(c: nameseg[2]) && |
235 | is_valid_name_byte(c: nameseg[3]); |
236 | } |
237 | |
238 | static uacpi_bool is_char(uacpi_char c, enum char_type type) |
239 | { |
240 | return (ascii_map[(uacpi_u8)c] & type) == type; |
241 | } |
242 | |
243 | static uacpi_char to_lower(uacpi_char c) |
244 | { |
245 | if (is_char(c, type: CHAR_TYPE_UPPER)) |
246 | return c + ('a' - 'A'); |
247 | |
248 | return c; |
249 | } |
250 | |
251 | static uacpi_bool peek_one( |
252 | const uacpi_char **str, const uacpi_size *size, uacpi_char *out_char |
253 | ) |
254 | { |
255 | if (*size == 0) |
256 | return UACPI_FALSE; |
257 | |
258 | *out_char = **str; |
259 | return UACPI_TRUE; |
260 | } |
261 | |
262 | static uacpi_bool consume_one( |
263 | const uacpi_char **str, uacpi_size *size, uacpi_char *out_char |
264 | ) |
265 | { |
266 | if (!peek_one(str, size, out_char)) |
267 | return UACPI_FALSE; |
268 | |
269 | *str += 1; |
270 | *size -= 1; |
271 | return UACPI_TRUE; |
272 | } |
273 | |
274 | static uacpi_bool consume_if( |
275 | const uacpi_char **str, uacpi_size *size, enum char_type type |
276 | ) |
277 | { |
278 | uacpi_char c; |
279 | |
280 | if (!peek_one(str, size, out_char: &c) || !is_char(c, type)) |
281 | return UACPI_FALSE; |
282 | |
283 | *str += 1; |
284 | *size -= 1; |
285 | return UACPI_TRUE; |
286 | } |
287 | |
288 | static uacpi_bool consume_if_equals( |
289 | const uacpi_char **str, uacpi_size *size, uacpi_char c |
290 | ) |
291 | { |
292 | uacpi_char c1; |
293 | |
294 | if (!peek_one(str, size, out_char: &c1) || to_lower(c: c1) != c) |
295 | return UACPI_FALSE; |
296 | |
297 | *str += 1; |
298 | *size -= 1; |
299 | return UACPI_TRUE; |
300 | } |
301 | |
302 | uacpi_status uacpi_string_to_integer( |
303 | const uacpi_char *str, uacpi_size max_chars, enum uacpi_base base, |
304 | uacpi_u64 *out_value |
305 | ) |
306 | { |
307 | uacpi_status ret = UACPI_STATUS_INVALID_ARGUMENT; |
308 | uacpi_bool negative = UACPI_FALSE; |
309 | uacpi_u64 next, value = 0; |
310 | uacpi_char c = '\0'; |
311 | |
312 | while (consume_if(str: &str, size: &max_chars, type: CHAR_TYPE_SPACE)); |
313 | |
314 | if (consume_if_equals(str: &str, size: &max_chars, c: '-')) |
315 | negative = UACPI_TRUE; |
316 | else |
317 | consume_if_equals(str: &str, size: &max_chars, c: '+'); |
318 | |
319 | if (base == UACPI_BASE_AUTO) { |
320 | base = UACPI_BASE_DEC; |
321 | |
322 | if (consume_if_equals(str: &str, size: &max_chars, c: '0')) { |
323 | base = UACPI_BASE_OCT; |
324 | if (consume_if_equals(str: &str, size: &max_chars, c: 'x')) |
325 | base = UACPI_BASE_HEX; |
326 | } |
327 | } |
328 | |
329 | while (consume_one(str: &str, size: &max_chars, out_char: &c)) { |
330 | switch (ascii_map[(uacpi_u8)c] & (CHAR_TYPE_DIGIT | CHAR_TYPE_ALHEX)) { |
331 | case CHAR_TYPE_DIGIT | CHAR_TYPE_HEX_DIGIT: |
332 | next = c - '0'; |
333 | if (base == UACPI_BASE_OCT && next > 7) |
334 | goto out; |
335 | break; |
336 | case CHAR_TYPE_LOWER | CHAR_TYPE_HEX_DIGIT: |
337 | case CHAR_TYPE_UPPER | CHAR_TYPE_HEX_DIGIT: |
338 | if (base != UACPI_BASE_HEX) |
339 | goto out; |
340 | next = 10 + (to_lower(c) - 'a'); |
341 | break; |
342 | default: |
343 | goto out; |
344 | } |
345 | |
346 | next = (value * base) + next; |
347 | if ((next / base) != value) { |
348 | value = 0xFFFFFFFFFFFFFFFF; |
349 | goto out; |
350 | } |
351 | |
352 | value = next; |
353 | } |
354 | |
355 | out: |
356 | if (negative) |
357 | value = -((uacpi_i64)value); |
358 | |
359 | *out_value = value; |
360 | if (max_chars == 0 || c == '\0') |
361 | ret = UACPI_STATUS_OK; |
362 | |
363 | return ret; |
364 | } |
365 | |
366 | #define PNP_ID_LENGTH 8 |
367 | |
368 | uacpi_status uacpi_eval_hid(uacpi_namespace_node *node, uacpi_id_string **out_id) |
369 | { |
370 | uacpi_status ret; |
371 | uacpi_object *hid_ret; |
372 | uacpi_id_string *id; |
373 | uacpi_u32 size; |
374 | |
375 | ret = uacpi_eval_typed( |
376 | parent: node, path: "_HID" , UACPI_NULL, |
377 | UACPI_OBJECT_INTEGER_BIT | UACPI_OBJECT_STRING_BIT, |
378 | ret: &hid_ret |
379 | ); |
380 | if (ret != UACPI_STATUS_OK) |
381 | return ret; |
382 | |
383 | size = sizeof(uacpi_id_string); |
384 | |
385 | switch (hid_ret->type) { |
386 | case UACPI_OBJECT_STRING: { |
387 | uacpi_buffer *buf = hid_ret->buffer; |
388 | |
389 | size += buf->size; |
390 | if (uacpi_unlikely(buf->size == 0 || size < buf->size)) { |
391 | uacpi_error( |
392 | "%.4s._HID: empty/invalid EISA ID string (%zu bytes)\n" , |
393 | uacpi_namespace_node_name(node).text, buf->size |
394 | ); |
395 | ret = UACPI_STATUS_AML_BAD_ENCODING; |
396 | break; |
397 | } |
398 | |
399 | id = uacpi_kernel_alloc(size); |
400 | if (uacpi_unlikely(id == UACPI_NULL)) { |
401 | ret = UACPI_STATUS_OUT_OF_MEMORY; |
402 | break; |
403 | } |
404 | id->size = buf->size; |
405 | id->value = UACPI_PTR_ADD(id, sizeof(uacpi_id_string)); |
406 | |
407 | uacpi_memcpy(dest: id->value, src: buf->text, count: buf->size); |
408 | id->value[buf->size - 1] = '\0'; |
409 | break; |
410 | } |
411 | |
412 | case UACPI_OBJECT_INTEGER: |
413 | size += PNP_ID_LENGTH; |
414 | |
415 | id = uacpi_kernel_alloc(size); |
416 | if (uacpi_unlikely(id == UACPI_NULL)) { |
417 | ret = UACPI_STATUS_OUT_OF_MEMORY; |
418 | break; |
419 | } |
420 | id->size = PNP_ID_LENGTH; |
421 | id->value = UACPI_PTR_ADD(id, sizeof(uacpi_id_string)); |
422 | |
423 | uacpi_eisa_id_to_string(id: hid_ret->integer, out_string: id->value); |
424 | break; |
425 | } |
426 | |
427 | uacpi_object_unref(obj: hid_ret); |
428 | if (uacpi_likely_success(ret)) |
429 | *out_id = id; |
430 | return ret; |
431 | } |
432 | |
433 | void uacpi_free_id_string(uacpi_id_string *id) |
434 | { |
435 | if (id == UACPI_NULL) |
436 | return; |
437 | |
438 | uacpi_free(id, sizeof(uacpi_id_string) + id->size); |
439 | } |
440 | |
441 | uacpi_status uacpi_eval_cid( |
442 | uacpi_namespace_node *node, uacpi_pnp_id_list **out_list |
443 | ) |
444 | { |
445 | uacpi_status ret; |
446 | uacpi_object *object, *cid_ret; |
447 | uacpi_object **objects; |
448 | uacpi_size num_ids, i; |
449 | uacpi_u32 size; |
450 | uacpi_id_string *id; |
451 | uacpi_char *id_buffer; |
452 | uacpi_pnp_id_list *list; |
453 | |
454 | ret = uacpi_eval_typed( |
455 | parent: node, path: "_CID" , UACPI_NULL, |
456 | UACPI_OBJECT_INTEGER_BIT | UACPI_OBJECT_STRING_BIT | |
457 | UACPI_OBJECT_PACKAGE_BIT, |
458 | ret: &cid_ret |
459 | ); |
460 | if (ret != UACPI_STATUS_OK) |
461 | return ret; |
462 | |
463 | switch (cid_ret->type) { |
464 | case UACPI_OBJECT_PACKAGE: |
465 | objects = cid_ret->package->objects; |
466 | num_ids = cid_ret->package->count; |
467 | break; |
468 | default: |
469 | objects = &cid_ret; |
470 | num_ids = 1; |
471 | break; |
472 | } |
473 | |
474 | size = sizeof(uacpi_pnp_id_list); |
475 | size += num_ids * sizeof(uacpi_id_string); |
476 | |
477 | for (i = 0; i < num_ids; ++i) { |
478 | object = objects[i]; |
479 | |
480 | switch (object->type) { |
481 | case UACPI_OBJECT_STRING: { |
482 | uacpi_size buf_size = object->buffer->size; |
483 | |
484 | if (uacpi_unlikely(buf_size == 0)) { |
485 | uacpi_error( |
486 | "%.4s._CID: empty EISA ID string (sub-object %zu)\n" , |
487 | uacpi_namespace_node_name(node).text, i |
488 | ); |
489 | return UACPI_STATUS_AML_INCOMPATIBLE_OBJECT_TYPE; |
490 | } |
491 | |
492 | size += buf_size; |
493 | if (uacpi_unlikely(size < buf_size)) { |
494 | uacpi_error( |
495 | "%.4s._CID: buffer size overflow (+ %zu)\n" , |
496 | uacpi_namespace_node_name(node).text, buf_size |
497 | ); |
498 | return UACPI_STATUS_AML_BAD_ENCODING; |
499 | } |
500 | |
501 | break; |
502 | } |
503 | |
504 | case UACPI_OBJECT_INTEGER: |
505 | size += PNP_ID_LENGTH; |
506 | break; |
507 | default: |
508 | uacpi_error( |
509 | "%.4s._CID: invalid package sub-object %zu type: %s\n" , |
510 | uacpi_namespace_node_name(node).text, i, |
511 | uacpi_object_type_to_string(object->type) |
512 | ); |
513 | return UACPI_STATUS_AML_INCOMPATIBLE_OBJECT_TYPE; |
514 | } |
515 | } |
516 | |
517 | list = uacpi_kernel_alloc(size); |
518 | if (uacpi_unlikely(list == UACPI_NULL)) |
519 | return UACPI_STATUS_OUT_OF_MEMORY; |
520 | list->num_ids = num_ids; |
521 | list->size = size - sizeof(uacpi_pnp_id_list); |
522 | |
523 | id_buffer = UACPI_PTR_ADD(list, sizeof(uacpi_pnp_id_list)); |
524 | id_buffer += num_ids * sizeof(uacpi_id_string); |
525 | |
526 | for (i = 0; i < num_ids; ++i) { |
527 | object = objects[i]; |
528 | id = &list->ids[i]; |
529 | |
530 | switch (object->type) { |
531 | case UACPI_OBJECT_STRING: { |
532 | uacpi_buffer *buf = object->buffer; |
533 | |
534 | id->size = buf->size; |
535 | id->value = id_buffer; |
536 | |
537 | uacpi_memcpy(dest: id->value, src: buf->text, count: id->size); |
538 | id->value[id->size - 1] = '\0'; |
539 | break; |
540 | } |
541 | |
542 | case UACPI_OBJECT_INTEGER: |
543 | id->size = PNP_ID_LENGTH; |
544 | id->value = id_buffer; |
545 | uacpi_eisa_id_to_string(id: object->integer, out_string: id_buffer); |
546 | break; |
547 | } |
548 | |
549 | id_buffer += id->size; |
550 | } |
551 | |
552 | uacpi_object_unref(obj: cid_ret); |
553 | *out_list = list; |
554 | return ret; |
555 | } |
556 | |
557 | void uacpi_free_pnp_id_list(uacpi_pnp_id_list *list) |
558 | { |
559 | if (list == UACPI_NULL) |
560 | return; |
561 | |
562 | uacpi_free(list, sizeof(uacpi_pnp_id_list) + list->size); |
563 | } |
564 | |
565 | uacpi_status uacpi_eval_sta(uacpi_namespace_node *node, uacpi_u32 *flags) |
566 | { |
567 | uacpi_status ret; |
568 | uacpi_u64 value = 0; |
569 | |
570 | ret = uacpi_eval_integer(parent: node, path: "_STA" , UACPI_NULL, out_value: &value); |
571 | |
572 | /* |
573 | * ACPI 6.5 specification: |
574 | * If a device object (including the processor object) does not have |
575 | * an _STA object, then OSPM assumes that all of the above bits are |
576 | * set (i.e., the device is present, enabled, shown in the UI, |
577 | * and functioning). |
578 | */ |
579 | if (ret == UACPI_STATUS_NOT_FOUND) { |
580 | value = 0xFFFFFFFF; |
581 | ret = UACPI_STATUS_OK; |
582 | } |
583 | |
584 | *flags = value; |
585 | return ret; |
586 | } |
587 | |
588 | uacpi_status uacpi_eval_adr(uacpi_namespace_node *node, uacpi_u64 *out) |
589 | { |
590 | return uacpi_eval_integer(parent: node, path: "_ADR" , UACPI_NULL, out_value: out); |
591 | } |
592 | |
593 | #define CLS_REPR_SIZE 7 |
594 | |
595 | static uacpi_u8 (uacpi_package *pkg, uacpi_size i) |
596 | { |
597 | uacpi_object *obj; |
598 | |
599 | if (uacpi_unlikely(pkg->count <= i)) |
600 | return 0; |
601 | |
602 | obj = pkg->objects[i]; |
603 | if (uacpi_unlikely(obj->type != UACPI_OBJECT_INTEGER)) |
604 | return 0; |
605 | |
606 | return obj->integer; |
607 | } |
608 | |
609 | uacpi_status uacpi_eval_cls( |
610 | uacpi_namespace_node *node, uacpi_id_string **out_id |
611 | ) |
612 | { |
613 | uacpi_status ret; |
614 | uacpi_object *obj; |
615 | uacpi_package *pkg; |
616 | uacpi_u8 class_codes[3]; |
617 | uacpi_id_string *id_string; |
618 | |
619 | ret = uacpi_eval_typed( |
620 | parent: node, path: "_CLS" , UACPI_NULL, UACPI_OBJECT_PACKAGE_BIT, ret: &obj |
621 | ); |
622 | if (ret != UACPI_STATUS_OK) |
623 | return ret; |
624 | |
625 | pkg = obj->package; |
626 | class_codes[0] = extract_package_byte_or_zero(pkg, i: 0); |
627 | class_codes[1] = extract_package_byte_or_zero(pkg, i: 1); |
628 | class_codes[2] = extract_package_byte_or_zero(pkg, i: 2); |
629 | |
630 | id_string = uacpi_kernel_alloc(size: sizeof(uacpi_id_string) + CLS_REPR_SIZE); |
631 | if (uacpi_unlikely(id_string == UACPI_NULL)) { |
632 | ret = UACPI_STATUS_OUT_OF_MEMORY; |
633 | goto out; |
634 | } |
635 | |
636 | id_string->size = CLS_REPR_SIZE; |
637 | id_string->value = UACPI_PTR_ADD(id_string, sizeof(uacpi_id_string)); |
638 | |
639 | uacpi_snprintf( |
640 | buffer: id_string->value, CLS_REPR_SIZE, fmt: "%02X%02X%02X" , |
641 | class_codes[0], class_codes[1], class_codes[2] |
642 | ); |
643 | |
644 | out: |
645 | if (uacpi_likely_success(ret)) |
646 | *out_id = id_string; |
647 | |
648 | uacpi_object_unref(obj); |
649 | return ret; |
650 | } |
651 | |
652 | uacpi_status uacpi_eval_uid( |
653 | uacpi_namespace_node *node, uacpi_id_string **out_uid |
654 | ) |
655 | { |
656 | uacpi_status ret; |
657 | uacpi_object *obj; |
658 | uacpi_id_string *id_string; |
659 | uacpi_u32 size; |
660 | |
661 | ret = uacpi_eval_typed( |
662 | parent: node, path: "_UID" , UACPI_NULL, |
663 | UACPI_OBJECT_INTEGER_BIT | UACPI_OBJECT_STRING_BIT, |
664 | ret: &obj |
665 | ); |
666 | if (ret != UACPI_STATUS_OK) |
667 | return ret; |
668 | |
669 | if (obj->type == UACPI_OBJECT_STRING) { |
670 | size = obj->buffer->size; |
671 | if (uacpi_unlikely(size == 0 || size > 0xE0000000)) { |
672 | uacpi_error( |
673 | "invalid %.4s._UID string size: %u\n" , |
674 | uacpi_namespace_node_name(node).text, size |
675 | ); |
676 | ret = UACPI_STATUS_AML_BAD_ENCODING; |
677 | goto out; |
678 | } |
679 | } else { |
680 | size = uacpi_snprintf( |
681 | UACPI_NULL, capacity: 0, fmt: "%" UACPI_PRIu64, UACPI_FMT64(obj->integer) |
682 | ) + 1; |
683 | } |
684 | |
685 | id_string = uacpi_kernel_alloc(size: sizeof(uacpi_id_string) + size); |
686 | if (uacpi_unlikely(id_string == UACPI_NULL)) { |
687 | ret = UACPI_STATUS_OUT_OF_MEMORY; |
688 | goto out; |
689 | } |
690 | |
691 | id_string->value = UACPI_PTR_ADD(id_string, sizeof(uacpi_id_string)); |
692 | id_string->size = size; |
693 | |
694 | if (obj->type == UACPI_OBJECT_STRING) { |
695 | uacpi_memcpy(dest: id_string->value, src: obj->buffer->text, count: size); |
696 | id_string->value[size - 1] = '\0'; |
697 | } else { |
698 | uacpi_snprintf( |
699 | buffer: id_string->value, capacity: id_string->size, fmt: "%" UACPI_PRIu64, |
700 | UACPI_FMT64(obj->integer) |
701 | ); |
702 | } |
703 | |
704 | out: |
705 | if (uacpi_likely_success(ret)) |
706 | *out_uid = id_string; |
707 | |
708 | uacpi_object_unref(obj); |
709 | return ret; |
710 | } |
711 | |
712 | static uacpi_bool matches_any( |
713 | uacpi_id_string *id, const uacpi_char *const *ids |
714 | ) |
715 | { |
716 | uacpi_size i; |
717 | |
718 | for (i = 0; ids[i]; ++i) { |
719 | if (uacpi_strcmp(lhs: id->value, rhs: ids[i]) == 0) |
720 | return UACPI_TRUE; |
721 | } |
722 | |
723 | return UACPI_FALSE; |
724 | } |
725 | |
726 | static uacpi_status uacpi_eval_dstate_method_template( |
727 | uacpi_namespace_node *parent, uacpi_char *template, uacpi_u8 num_methods, |
728 | uacpi_u8 *out_values |
729 | ) |
730 | { |
731 | uacpi_u8 i; |
732 | uacpi_status ret = UACPI_STATUS_NOT_FOUND, eval_ret; |
733 | uacpi_object *obj; |
734 | |
735 | // We expect either _SxD or _SxW, so increment template[2] |
736 | for (i = 0; i < num_methods; ++i, template[2]++) { |
737 | eval_ret = uacpi_eval_typed( |
738 | parent, path: template, UACPI_NULL, UACPI_OBJECT_INTEGER_BIT, ret: &obj |
739 | ); |
740 | if (eval_ret == UACPI_STATUS_OK) { |
741 | ret = UACPI_STATUS_OK; |
742 | out_values[i] = obj->integer; |
743 | uacpi_object_unref(obj); |
744 | continue; |
745 | } |
746 | |
747 | out_values[i] = 0xFF; |
748 | if (uacpi_unlikely(eval_ret != UACPI_STATUS_NOT_FOUND)) { |
749 | const char *path; |
750 | |
751 | path = uacpi_namespace_node_generate_absolute_path(node: parent); |
752 | uacpi_warn( |
753 | "failed to evaluate %s.%s: %s\n" , |
754 | path, template, uacpi_status_to_string(eval_ret) |
755 | ); |
756 | uacpi_free_dynamic_string(str: path); |
757 | } |
758 | } |
759 | |
760 | return ret; |
761 | } |
762 | |
763 | #define NODE_INFO_EVAL_ADD_ID(name) \ |
764 | if (uacpi_eval_##name(node, &name) == UACPI_STATUS_OK) { \ |
765 | size += name->size; \ |
766 | if (uacpi_unlikely(size < name->size)) { \ |
767 | ret = UACPI_STATUS_AML_BAD_ENCODING; \ |
768 | goto out; \ |
769 | } \ |
770 | } |
771 | |
772 | #define NODE_INFO_COPY_ID(name, flag) \ |
773 | if (name != UACPI_NULL) { \ |
774 | flags |= UACPI_NS_NODE_INFO_HAS_##flag; \ |
775 | info->name.value = cursor; \ |
776 | info->name.size = name->size; \ |
777 | uacpi_memcpy(cursor, name->value, name->size); \ |
778 | cursor += name->size; \ |
779 | } else { \ |
780 | uacpi_memzero(&info->name, sizeof(*name)); \ |
781 | } \ |
782 | |
783 | uacpi_status uacpi_get_namespace_node_info( |
784 | uacpi_namespace_node *node, uacpi_namespace_node_info **out_info |
785 | ) |
786 | { |
787 | uacpi_status ret = UACPI_STATUS_OK; |
788 | uacpi_u32 size = sizeof(uacpi_namespace_node_info); |
789 | uacpi_object *obj; |
790 | uacpi_namespace_node_info *info; |
791 | uacpi_id_string *hid = UACPI_NULL, *uid = UACPI_NULL, *cls = UACPI_NULL; |
792 | uacpi_pnp_id_list *cid = UACPI_NULL; |
793 | uacpi_char *cursor; |
794 | uacpi_u64 adr = 0; |
795 | uacpi_u8 flags = 0; |
796 | uacpi_u8 sxd[4], sxw[5]; |
797 | |
798 | obj = uacpi_namespace_node_get_object(node); |
799 | if (uacpi_unlikely(obj == UACPI_NULL)) |
800 | return UACPI_STATUS_INVALID_ARGUMENT; |
801 | |
802 | if (obj->type == UACPI_OBJECT_DEVICE || |
803 | obj->type == UACPI_OBJECT_PROCESSOR) { |
804 | char dstate_method_template[5] = { '_', 'S', '1', 'D', '\0' }; |
805 | |
806 | NODE_INFO_EVAL_ADD_ID(hid) |
807 | NODE_INFO_EVAL_ADD_ID(uid) |
808 | NODE_INFO_EVAL_ADD_ID(cls) |
809 | NODE_INFO_EVAL_ADD_ID(cid) |
810 | |
811 | if (uacpi_eval_adr(node, out: &adr) == UACPI_STATUS_OK) |
812 | flags |= UACPI_NS_NODE_INFO_HAS_ADR; |
813 | |
814 | if (uacpi_eval_dstate_method_template( |
815 | parent: node, template: dstate_method_template, num_methods: sizeof(sxd), out_values: sxd |
816 | ) == UACPI_STATUS_OK) |
817 | flags |= UACPI_NS_NODE_INFO_HAS_SXD; |
818 | |
819 | dstate_method_template[2] = '0'; |
820 | dstate_method_template[3] = 'W'; |
821 | |
822 | if (uacpi_eval_dstate_method_template( |
823 | parent: node, template: dstate_method_template, num_methods: sizeof(sxw), out_values: sxw |
824 | ) == UACPI_STATUS_OK) |
825 | flags |= UACPI_NS_NODE_INFO_HAS_SXW; |
826 | } |
827 | |
828 | info = uacpi_kernel_alloc(size); |
829 | if (uacpi_unlikely(info == UACPI_NULL)) { |
830 | ret = UACPI_STATUS_OUT_OF_MEMORY; |
831 | goto out; |
832 | } |
833 | info->size = size; |
834 | cursor = UACPI_PTR_ADD(info, sizeof(uacpi_namespace_node_info)); |
835 | info->name = uacpi_namespace_node_name(node); |
836 | info->type = obj->type; |
837 | info->num_params = info->type == UACPI_OBJECT_METHOD ? obj->method->args : 0; |
838 | |
839 | info->adr = adr; |
840 | if (flags & UACPI_NS_NODE_INFO_HAS_SXD) |
841 | uacpi_memcpy(dest: info->sxd, src: sxd, count: sizeof(sxd)); |
842 | else |
843 | uacpi_memzero(info->sxd, sizeof(info->sxd)); |
844 | |
845 | if (flags & UACPI_NS_NODE_INFO_HAS_SXW) |
846 | uacpi_memcpy(dest: info->sxw, src: sxw, count: sizeof(sxw)); |
847 | else |
848 | uacpi_memzero(info->sxw, sizeof(info->sxw)); |
849 | |
850 | if (cid != UACPI_NULL) { |
851 | uacpi_u32 i; |
852 | |
853 | uacpi_memcpy(dest: &info->cid, src: cid, count: cid->size + sizeof(*cid)); |
854 | cursor += cid->num_ids * sizeof(uacpi_id_string); |
855 | |
856 | for (i = 0; i < cid->num_ids; ++i) { |
857 | info->cid.ids[i].value = cursor; |
858 | cursor += info->cid.ids[i].size; |
859 | } |
860 | |
861 | flags |= UACPI_NS_NODE_INFO_HAS_CID; |
862 | } else { |
863 | uacpi_memzero(&info->cid, sizeof(*cid)); |
864 | } |
865 | |
866 | NODE_INFO_COPY_ID(hid, HID) |
867 | NODE_INFO_COPY_ID(uid, UID) |
868 | NODE_INFO_COPY_ID(cls, CLS) |
869 | |
870 | out: |
871 | if (uacpi_likely_success(ret)) { |
872 | info->flags = flags; |
873 | *out_info = info; |
874 | } |
875 | |
876 | uacpi_free_id_string(id: hid); |
877 | uacpi_free_id_string(id: uid); |
878 | uacpi_free_id_string(id: cls); |
879 | uacpi_free_pnp_id_list(list: cid); |
880 | return ret; |
881 | } |
882 | |
883 | void uacpi_free_namespace_node_info(uacpi_namespace_node_info *info) |
884 | { |
885 | if (info == UACPI_NULL) |
886 | return; |
887 | |
888 | uacpi_free(info, info->size); |
889 | } |
890 | |
891 | uacpi_bool uacpi_device_matches_pnp_id( |
892 | uacpi_namespace_node *node, const uacpi_char *const *ids |
893 | ) |
894 | { |
895 | uacpi_status st; |
896 | uacpi_bool ret = UACPI_FALSE; |
897 | uacpi_id_string *id = UACPI_NULL; |
898 | uacpi_pnp_id_list *id_list = UACPI_NULL; |
899 | |
900 | st = uacpi_eval_hid(node, out_id: &id); |
901 | if (st == UACPI_STATUS_OK && matches_any(id, ids)) { |
902 | ret = UACPI_TRUE; |
903 | goto out; |
904 | } |
905 | |
906 | st = uacpi_eval_cid(node, out_list: &id_list); |
907 | if (st == UACPI_STATUS_OK) { |
908 | uacpi_size i; |
909 | |
910 | for (i = 0; i < id_list->num_ids; ++i) { |
911 | if (matches_any(id: &id_list->ids[i], ids)) { |
912 | ret = UACPI_TRUE; |
913 | goto out; |
914 | } |
915 | } |
916 | } |
917 | |
918 | out: |
919 | uacpi_free_id_string(id); |
920 | uacpi_free_pnp_id_list(list: id_list); |
921 | return ret; |
922 | } |
923 | |
924 | struct device_find_ctx { |
925 | const uacpi_char *const *target_hids; |
926 | void *user; |
927 | uacpi_iteration_callback cb; |
928 | }; |
929 | |
930 | enum uacpi_ns_iteration_decision find_one_device( |
931 | void *opaque, uacpi_namespace_node *node |
932 | ) |
933 | { |
934 | struct device_find_ctx *ctx = opaque; |
935 | uacpi_status ret; |
936 | uacpi_u32 flags; |
937 | uacpi_object *obj; |
938 | |
939 | obj = uacpi_namespace_node_get_object(node); |
940 | if (uacpi_unlikely(obj == UACPI_NULL)) |
941 | return UACPI_NS_ITERATION_DECISION_CONTINUE; |
942 | if (obj->type != UACPI_OBJECT_DEVICE) |
943 | return UACPI_NS_ITERATION_DECISION_CONTINUE; |
944 | |
945 | if (!uacpi_device_matches_pnp_id(node, ids: ctx->target_hids)) |
946 | return UACPI_NS_ITERATION_DECISION_CONTINUE; |
947 | |
948 | ret = uacpi_eval_sta(node, flags: &flags); |
949 | if (uacpi_unlikely_error(ret)) |
950 | return UACPI_NS_ITERATION_DECISION_NEXT_PEER; |
951 | |
952 | if (!(flags & ACPI_STA_RESULT_DEVICE_PRESENT) && |
953 | !(flags & ACPI_STA_RESULT_DEVICE_FUNCTIONING)) |
954 | return UACPI_NS_ITERATION_DECISION_NEXT_PEER; |
955 | |
956 | return ctx->cb(ctx->user, node); |
957 | } |
958 | |
959 | |
960 | uacpi_status uacpi_find_devices_at( |
961 | uacpi_namespace_node *parent, const uacpi_char *const *hids, |
962 | uacpi_iteration_callback cb, void *user |
963 | ) |
964 | { |
965 | UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_NAMESPACE_LOADED); |
966 | |
967 | struct device_find_ctx ctx = { |
968 | .target_hids = hids, |
969 | .user = user, |
970 | .cb = cb, |
971 | }; |
972 | |
973 | uacpi_namespace_for_each_node_depth_first(parent, callback: find_one_device, user: &ctx); |
974 | return UACPI_STATUS_OK; |
975 | } |
976 | |
977 | uacpi_status uacpi_find_devices( |
978 | const uacpi_char *hid, uacpi_iteration_callback cb, void *user |
979 | ) |
980 | { |
981 | const uacpi_char *hids[] = { |
982 | hid, UACPI_NULL |
983 | }; |
984 | |
985 | return uacpi_find_devices_at(parent: uacpi_namespace_root(), hids, cb, user); |
986 | } |
987 | |
988 | uacpi_status uacpi_set_interrupt_model(uacpi_interrupt_model model) |
989 | { |
990 | uacpi_status ret; |
991 | uacpi_object *arg; |
992 | uacpi_args args; |
993 | |
994 | UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_NAMESPACE_LOADED); |
995 | |
996 | arg = uacpi_create_object(type: UACPI_OBJECT_INTEGER); |
997 | if (uacpi_unlikely(arg == UACPI_NULL)) |
998 | return UACPI_STATUS_OUT_OF_MEMORY; |
999 | |
1000 | arg->integer = model; |
1001 | args.objects = &arg; |
1002 | args.count = 1; |
1003 | |
1004 | ret = uacpi_eval(parent: uacpi_namespace_root(), path: "_PIC" , args: &args, UACPI_NULL); |
1005 | uacpi_object_unref(obj: arg); |
1006 | |
1007 | if (ret == UACPI_STATUS_NOT_FOUND) |
1008 | ret = UACPI_STATUS_OK; |
1009 | |
1010 | return ret; |
1011 | } |
1012 | |
1013 | uacpi_status uacpi_get_pci_routing_table( |
1014 | uacpi_namespace_node *parent, uacpi_pci_routing_table **out_table |
1015 | ) |
1016 | { |
1017 | uacpi_status ret; |
1018 | uacpi_object *obj, *entry_obj, *elem_obj; |
1019 | uacpi_package *table_pkg, *entry_pkg; |
1020 | uacpi_pci_routing_table_entry *entry; |
1021 | uacpi_pci_routing_table *table; |
1022 | uacpi_size size, i; |
1023 | |
1024 | UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_NAMESPACE_LOADED); |
1025 | |
1026 | obj = uacpi_namespace_node_get_object(node: parent); |
1027 | if (uacpi_unlikely(obj == UACPI_NULL || obj->type != UACPI_OBJECT_DEVICE)) |
1028 | return UACPI_STATUS_INVALID_ARGUMENT; |
1029 | |
1030 | ret = uacpi_eval_typed( |
1031 | parent, path: "_PRT" , UACPI_NULL, UACPI_OBJECT_PACKAGE_BIT, ret: &obj |
1032 | ); |
1033 | if (uacpi_unlikely_error(ret)) |
1034 | return ret; |
1035 | |
1036 | table_pkg = obj->package; |
1037 | if (uacpi_unlikely(table_pkg->count == 0 || table_pkg->count > 1024)) { |
1038 | uacpi_error("invalid number of _PRT entries: %zu\n" , table_pkg->count); |
1039 | uacpi_object_unref(obj); |
1040 | return UACPI_STATUS_AML_BAD_ENCODING; |
1041 | } |
1042 | |
1043 | size = table_pkg->count * sizeof(uacpi_pci_routing_table_entry); |
1044 | table = uacpi_kernel_alloc(size: sizeof(uacpi_pci_routing_table) + size); |
1045 | if (uacpi_unlikely(table == UACPI_NULL)) { |
1046 | uacpi_object_unref(obj); |
1047 | return UACPI_STATUS_OUT_OF_MEMORY; |
1048 | } |
1049 | table->num_entries = table_pkg->count; |
1050 | |
1051 | for (i = 0; i < table_pkg->count; ++i) { |
1052 | entry_obj = table_pkg->objects[i]; |
1053 | |
1054 | if (uacpi_unlikely(entry_obj->type != UACPI_OBJECT_PACKAGE)) { |
1055 | uacpi_error("_PRT sub-object %zu is not a package: %s\n" , |
1056 | i, uacpi_object_type_to_string(entry_obj->type)); |
1057 | goto out_bad_encoding; |
1058 | } |
1059 | |
1060 | entry_pkg = entry_obj->package; |
1061 | if (uacpi_unlikely(entry_pkg->count != 4)) { |
1062 | uacpi_error("invalid _PRT sub-package entry count %zu\n" , |
1063 | entry_pkg->count); |
1064 | goto out_bad_encoding; |
1065 | } |
1066 | |
1067 | entry = &table->entries[i]; |
1068 | |
1069 | elem_obj = entry_pkg->objects[0]; |
1070 | if (uacpi_unlikely(elem_obj->type != UACPI_OBJECT_INTEGER)) { |
1071 | uacpi_error("invalid _PRT sub-package %zu address type: %s\n" , |
1072 | i, uacpi_object_type_to_string(elem_obj->type)); |
1073 | goto out_bad_encoding; |
1074 | } |
1075 | entry->address = elem_obj->integer; |
1076 | |
1077 | elem_obj = entry_pkg->objects[1]; |
1078 | if (uacpi_unlikely(elem_obj->type != UACPI_OBJECT_INTEGER)) { |
1079 | uacpi_error("invalid _PRT sub-package %zu pin type: %s\n" , |
1080 | i, uacpi_object_type_to_string(elem_obj->type)); |
1081 | goto out_bad_encoding; |
1082 | } |
1083 | entry->pin = elem_obj->integer; |
1084 | |
1085 | elem_obj = entry_pkg->objects[2]; |
1086 | switch (elem_obj->type) { |
1087 | case UACPI_OBJECT_STRING: |
1088 | entry->source = uacpi_namespace_node_resolve_from_aml_namepath( |
1089 | scope: parent, path: elem_obj->buffer->text |
1090 | ); |
1091 | if (uacpi_unlikely(entry->source == UACPI_NULL)) { |
1092 | uacpi_error("unable to lookup _PRT source: %s\n" , |
1093 | elem_obj->buffer->text); |
1094 | goto out_bad_encoding; |
1095 | } |
1096 | break; |
1097 | case UACPI_OBJECT_INTEGER: |
1098 | entry->source = UACPI_NULL; |
1099 | break; |
1100 | default: |
1101 | uacpi_error("invalid _PRT sub-package %zu source type: %s\n" , |
1102 | i, uacpi_object_type_to_string(elem_obj->type)); |
1103 | goto out_bad_encoding; |
1104 | } |
1105 | |
1106 | elem_obj = entry_pkg->objects[3]; |
1107 | if (uacpi_unlikely(elem_obj->type != UACPI_OBJECT_INTEGER)) { |
1108 | uacpi_error("invalid _PRT sub-package %zu source index type: %s\n" , |
1109 | i, uacpi_object_type_to_string(elem_obj->type)); |
1110 | goto out_bad_encoding; |
1111 | } |
1112 | entry->index = elem_obj->integer; |
1113 | } |
1114 | |
1115 | uacpi_object_unref(obj); |
1116 | *out_table = table; |
1117 | return UACPI_STATUS_OK; |
1118 | |
1119 | out_bad_encoding: |
1120 | uacpi_object_unref(obj); |
1121 | uacpi_free_pci_routing_table(table); |
1122 | return UACPI_STATUS_AML_BAD_ENCODING; |
1123 | } |
1124 | |
1125 | void uacpi_free_pci_routing_table(uacpi_pci_routing_table *table) |
1126 | { |
1127 | if (table == UACPI_NULL) |
1128 | return; |
1129 | |
1130 | uacpi_free( |
1131 | table, |
1132 | sizeof(uacpi_pci_routing_table) + |
1133 | table->num_entries * sizeof(uacpi_pci_routing_table_entry) |
1134 | ); |
1135 | } |
1136 | |
1137 | void uacpi_free_dynamic_string(const uacpi_char *str) |
1138 | { |
1139 | if (str == UACPI_NULL) |
1140 | return; |
1141 | |
1142 | uacpi_free((void*)str, uacpi_strlen(str) + 1); |
1143 | } |
1144 | |