1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /******************************************************************************* |
3 | * |
4 | * Module Name: dbconvert - debugger miscellaneous conversion routines |
5 | * |
6 | ******************************************************************************/ |
7 | |
8 | #include <acpi/acpi.h> |
9 | #include "accommon.h" |
10 | #include "acdebug.h" |
11 | |
12 | #define _COMPONENT ACPI_CA_DEBUGGER |
13 | ACPI_MODULE_NAME("dbconvert" ) |
14 | |
15 | #define DB_DEFAULT_PKG_ELEMENTS 33 |
16 | /******************************************************************************* |
17 | * |
18 | * FUNCTION: acpi_db_hex_char_to_value |
19 | * |
20 | * PARAMETERS: hex_char - Ascii Hex digit, 0-9|a-f|A-F |
21 | * return_value - Where the converted value is returned |
22 | * |
23 | * RETURN: Status |
24 | * |
25 | * DESCRIPTION: Convert a single hex character to a 4-bit number (0-16). |
26 | * |
27 | ******************************************************************************/ |
28 | acpi_status acpi_db_hex_char_to_value(int hex_char, u8 *return_value) |
29 | { |
30 | u8 value; |
31 | |
32 | /* Digit must be ascii [0-9a-fA-F] */ |
33 | |
34 | if (!isxdigit(hex_char)) { |
35 | return (AE_BAD_HEX_CONSTANT); |
36 | } |
37 | |
38 | if (hex_char <= 0x39) { |
39 | value = (u8)(hex_char - 0x30); |
40 | } else { |
41 | value = (u8)(toupper(hex_char) - 0x37); |
42 | } |
43 | |
44 | *return_value = value; |
45 | return (AE_OK); |
46 | } |
47 | |
48 | /******************************************************************************* |
49 | * |
50 | * FUNCTION: acpi_db_hex_byte_to_binary |
51 | * |
52 | * PARAMETERS: hex_byte - Double hex digit (0x00 - 0xFF) in format: |
53 | * hi_byte then lo_byte. |
54 | * return_value - Where the converted value is returned |
55 | * |
56 | * RETURN: Status |
57 | * |
58 | * DESCRIPTION: Convert two hex characters to an 8 bit number (0 - 255). |
59 | * |
60 | ******************************************************************************/ |
61 | |
62 | static acpi_status acpi_db_hex_byte_to_binary(char *hex_byte, u8 *return_value) |
63 | { |
64 | u8 local0; |
65 | u8 local1; |
66 | acpi_status status; |
67 | |
68 | /* High byte */ |
69 | |
70 | status = acpi_db_hex_char_to_value(hex_char: hex_byte[0], return_value: &local0); |
71 | if (ACPI_FAILURE(status)) { |
72 | return (status); |
73 | } |
74 | |
75 | /* Low byte */ |
76 | |
77 | status = acpi_db_hex_char_to_value(hex_char: hex_byte[1], return_value: &local1); |
78 | if (ACPI_FAILURE(status)) { |
79 | return (status); |
80 | } |
81 | |
82 | *return_value = (u8)((local0 << 4) | local1); |
83 | return (AE_OK); |
84 | } |
85 | |
86 | /******************************************************************************* |
87 | * |
88 | * FUNCTION: acpi_db_convert_to_buffer |
89 | * |
90 | * PARAMETERS: string - Input string to be converted |
91 | * object - Where the buffer object is returned |
92 | * |
93 | * RETURN: Status |
94 | * |
95 | * DESCRIPTION: Convert a string to a buffer object. String is treated a list |
96 | * of buffer elements, each separated by a space or comma. |
97 | * |
98 | ******************************************************************************/ |
99 | |
100 | static acpi_status |
101 | acpi_db_convert_to_buffer(char *string, union acpi_object *object) |
102 | { |
103 | u32 i; |
104 | u32 j; |
105 | u32 length; |
106 | u8 *buffer; |
107 | acpi_status status; |
108 | |
109 | /* Skip all preceding white space */ |
110 | |
111 | acpi_ut_remove_whitespace(string: &string); |
112 | |
113 | /* Generate the final buffer length */ |
114 | |
115 | for (i = 0, length = 0; string[i];) { |
116 | i += 2; |
117 | length++; |
118 | |
119 | while (string[i] && ((string[i] == ',') || (string[i] == ' '))) { |
120 | i++; |
121 | } |
122 | } |
123 | |
124 | buffer = ACPI_ALLOCATE(length); |
125 | if (!buffer) { |
126 | return (AE_NO_MEMORY); |
127 | } |
128 | |
129 | /* Convert the command line bytes to the buffer */ |
130 | |
131 | for (i = 0, j = 0; string[i];) { |
132 | status = acpi_db_hex_byte_to_binary(hex_byte: &string[i], return_value: &buffer[j]); |
133 | if (ACPI_FAILURE(status)) { |
134 | ACPI_FREE(buffer); |
135 | return (status); |
136 | } |
137 | |
138 | j++; |
139 | i += 2; |
140 | while (string[i] && ((string[i] == ',') || (string[i] == ' '))) { |
141 | i++; |
142 | } |
143 | } |
144 | |
145 | object->type = ACPI_TYPE_BUFFER; |
146 | object->buffer.pointer = buffer; |
147 | object->buffer.length = length; |
148 | return (AE_OK); |
149 | } |
150 | |
151 | /******************************************************************************* |
152 | * |
153 | * FUNCTION: acpi_db_convert_to_package |
154 | * |
155 | * PARAMETERS: string - Input string to be converted |
156 | * object - Where the package object is returned |
157 | * |
158 | * RETURN: Status |
159 | * |
160 | * DESCRIPTION: Convert a string to a package object. Handles nested packages |
161 | * via recursion with acpi_db_convert_to_object. |
162 | * |
163 | ******************************************************************************/ |
164 | |
165 | acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object) |
166 | { |
167 | char *this; |
168 | char *next; |
169 | u32 i; |
170 | acpi_object_type type; |
171 | union acpi_object *elements; |
172 | acpi_status status; |
173 | |
174 | elements = |
175 | ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS * |
176 | sizeof(union acpi_object)); |
177 | |
178 | this = string; |
179 | for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) { |
180 | this = acpi_db_get_next_token(string: this, next: &next, return_type: &type); |
181 | if (!this) { |
182 | break; |
183 | } |
184 | |
185 | /* Recursive call to convert each package element */ |
186 | |
187 | status = acpi_db_convert_to_object(type, string: this, object: &elements[i]); |
188 | if (ACPI_FAILURE(status)) { |
189 | acpi_db_delete_objects(count: i + 1, objects: elements); |
190 | ACPI_FREE(elements); |
191 | return (status); |
192 | } |
193 | |
194 | this = next; |
195 | } |
196 | |
197 | object->type = ACPI_TYPE_PACKAGE; |
198 | object->package.count = i; |
199 | object->package.elements = elements; |
200 | return (AE_OK); |
201 | } |
202 | |
203 | /******************************************************************************* |
204 | * |
205 | * FUNCTION: acpi_db_convert_to_object |
206 | * |
207 | * PARAMETERS: type - Object type as determined by parser |
208 | * string - Input string to be converted |
209 | * object - Where the new object is returned |
210 | * |
211 | * RETURN: Status |
212 | * |
213 | * DESCRIPTION: Convert a typed and tokenized string to a union acpi_object. Typing: |
214 | * 1) String objects were surrounded by quotes. |
215 | * 2) Buffer objects were surrounded by parentheses. |
216 | * 3) Package objects were surrounded by brackets "[]". |
217 | * 4) All standalone tokens are treated as integers. |
218 | * |
219 | ******************************************************************************/ |
220 | |
221 | acpi_status |
222 | acpi_db_convert_to_object(acpi_object_type type, |
223 | char *string, union acpi_object *object) |
224 | { |
225 | acpi_status status = AE_OK; |
226 | |
227 | switch (type) { |
228 | case ACPI_TYPE_STRING: |
229 | |
230 | object->type = ACPI_TYPE_STRING; |
231 | object->string.pointer = string; |
232 | object->string.length = (u32)strlen(string); |
233 | break; |
234 | |
235 | case ACPI_TYPE_BUFFER: |
236 | |
237 | status = acpi_db_convert_to_buffer(string, object); |
238 | break; |
239 | |
240 | case ACPI_TYPE_PACKAGE: |
241 | |
242 | status = acpi_db_convert_to_package(string, object); |
243 | break; |
244 | |
245 | default: |
246 | |
247 | object->type = ACPI_TYPE_INTEGER; |
248 | status = acpi_ut_strtoul64(string, ret_integer: &object->integer.value); |
249 | break; |
250 | } |
251 | |
252 | return (status); |
253 | } |
254 | |
255 | /******************************************************************************* |
256 | * |
257 | * FUNCTION: acpi_db_encode_pld_buffer |
258 | * |
259 | * PARAMETERS: pld_info - _PLD buffer struct (Using local struct) |
260 | * |
261 | * RETURN: Encode _PLD buffer suitable for return value from _PLD |
262 | * |
263 | * DESCRIPTION: Bit-packs a _PLD buffer struct. Used to test the _PLD macros |
264 | * |
265 | ******************************************************************************/ |
266 | |
267 | u8 *acpi_db_encode_pld_buffer(struct acpi_pld_info *pld_info) |
268 | { |
269 | u32 *buffer; |
270 | u32 dword; |
271 | |
272 | buffer = ACPI_ALLOCATE_ZEROED(ACPI_PLD_BUFFER_SIZE); |
273 | if (!buffer) { |
274 | return (NULL); |
275 | } |
276 | |
277 | /* First 32 bits */ |
278 | |
279 | dword = 0; |
280 | ACPI_PLD_SET_REVISION(&dword, pld_info->revision); |
281 | ACPI_PLD_SET_IGNORE_COLOR(&dword, pld_info->ignore_color); |
282 | ACPI_PLD_SET_RED(&dword, pld_info->red); |
283 | ACPI_PLD_SET_GREEN(&dword, pld_info->green); |
284 | ACPI_PLD_SET_BLUE(&dword, pld_info->blue); |
285 | ACPI_MOVE_32_TO_32(&buffer[0], &dword); |
286 | |
287 | /* Second 32 bits */ |
288 | |
289 | dword = 0; |
290 | ACPI_PLD_SET_WIDTH(&dword, pld_info->width); |
291 | ACPI_PLD_SET_HEIGHT(&dword, pld_info->height); |
292 | ACPI_MOVE_32_TO_32(&buffer[1], &dword); |
293 | |
294 | /* Third 32 bits */ |
295 | |
296 | dword = 0; |
297 | ACPI_PLD_SET_USER_VISIBLE(&dword, pld_info->user_visible); |
298 | ACPI_PLD_SET_DOCK(&dword, pld_info->dock); |
299 | ACPI_PLD_SET_LID(&dword, pld_info->lid); |
300 | ACPI_PLD_SET_PANEL(&dword, pld_info->panel); |
301 | ACPI_PLD_SET_VERTICAL(&dword, pld_info->vertical_position); |
302 | ACPI_PLD_SET_HORIZONTAL(&dword, pld_info->horizontal_position); |
303 | ACPI_PLD_SET_SHAPE(&dword, pld_info->shape); |
304 | ACPI_PLD_SET_ORIENTATION(&dword, pld_info->group_orientation); |
305 | ACPI_PLD_SET_TOKEN(&dword, pld_info->group_token); |
306 | ACPI_PLD_SET_POSITION(&dword, pld_info->group_position); |
307 | ACPI_PLD_SET_BAY(&dword, pld_info->bay); |
308 | ACPI_MOVE_32_TO_32(&buffer[2], &dword); |
309 | |
310 | /* Fourth 32 bits */ |
311 | |
312 | dword = 0; |
313 | ACPI_PLD_SET_EJECTABLE(&dword, pld_info->ejectable); |
314 | ACPI_PLD_SET_OSPM_EJECT(&dword, pld_info->ospm_eject_required); |
315 | ACPI_PLD_SET_CABINET(&dword, pld_info->cabinet_number); |
316 | ACPI_PLD_SET_CARD_CAGE(&dword, pld_info->card_cage_number); |
317 | ACPI_PLD_SET_REFERENCE(&dword, pld_info->reference); |
318 | ACPI_PLD_SET_ROTATION(&dword, pld_info->rotation); |
319 | ACPI_PLD_SET_ORDER(&dword, pld_info->order); |
320 | ACPI_MOVE_32_TO_32(&buffer[3], &dword); |
321 | |
322 | if (pld_info->revision >= 2) { |
323 | |
324 | /* Fifth 32 bits */ |
325 | |
326 | dword = 0; |
327 | ACPI_PLD_SET_VERT_OFFSET(&dword, pld_info->vertical_offset); |
328 | ACPI_PLD_SET_HORIZ_OFFSET(&dword, pld_info->horizontal_offset); |
329 | ACPI_MOVE_32_TO_32(&buffer[4], &dword); |
330 | } |
331 | |
332 | return (ACPI_CAST_PTR(u8, buffer)); |
333 | } |
334 | |
335 | /******************************************************************************* |
336 | * |
337 | * FUNCTION: acpi_db_dump_pld_buffer |
338 | * |
339 | * PARAMETERS: obj_desc - Object returned from _PLD method |
340 | * |
341 | * RETURN: None. |
342 | * |
343 | * DESCRIPTION: Dumps formatted contents of a _PLD return buffer. |
344 | * |
345 | ******************************************************************************/ |
346 | |
347 | #define ACPI_PLD_OUTPUT "%20s : %-6X\n" |
348 | |
349 | void acpi_db_dump_pld_buffer(union acpi_object *obj_desc) |
350 | { |
351 | union acpi_object *buffer_desc; |
352 | struct acpi_pld_info *pld_info; |
353 | u8 *new_buffer; |
354 | acpi_status status; |
355 | |
356 | /* Object must be of type Package with at least one Buffer element */ |
357 | |
358 | if (obj_desc->type != ACPI_TYPE_PACKAGE) { |
359 | return; |
360 | } |
361 | |
362 | buffer_desc = &obj_desc->package.elements[0]; |
363 | if (buffer_desc->type != ACPI_TYPE_BUFFER) { |
364 | return; |
365 | } |
366 | |
367 | /* Convert _PLD buffer to local _PLD struct */ |
368 | |
369 | status = acpi_decode_pld_buffer(in_buffer: buffer_desc->buffer.pointer, |
370 | length: buffer_desc->buffer.length, return_buffer: &pld_info); |
371 | if (ACPI_FAILURE(status)) { |
372 | return; |
373 | } |
374 | |
375 | /* Encode local _PLD struct back to a _PLD buffer */ |
376 | |
377 | new_buffer = acpi_db_encode_pld_buffer(pld_info); |
378 | if (!new_buffer) { |
379 | goto exit; |
380 | } |
381 | |
382 | /* The two bit-packed buffers should match */ |
383 | |
384 | if (memcmp(p: new_buffer, q: buffer_desc->buffer.pointer, |
385 | size: buffer_desc->buffer.length)) { |
386 | acpi_os_printf |
387 | (format: "Converted _PLD buffer does not compare. New:\n" ); |
388 | |
389 | acpi_ut_dump_buffer(buffer: new_buffer, |
390 | count: buffer_desc->buffer.length, DB_BYTE_DISPLAY, |
391 | offset: 0); |
392 | } |
393 | |
394 | /* First 32-bit dword */ |
395 | |
396 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Revision" , pld_info->revision); |
397 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_IgnoreColor" , |
398 | pld_info->ignore_color); |
399 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Red" , pld_info->red); |
400 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Green" , pld_info->green); |
401 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Blue" , pld_info->blue); |
402 | |
403 | /* Second 32-bit dword */ |
404 | |
405 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Width" , pld_info->width); |
406 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Height" , pld_info->height); |
407 | |
408 | /* Third 32-bit dword */ |
409 | |
410 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_UserVisible" , |
411 | pld_info->user_visible); |
412 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Dock" , pld_info->dock); |
413 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Lid" , pld_info->lid); |
414 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Panel" , pld_info->panel); |
415 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_VerticalPosition" , |
416 | pld_info->vertical_position); |
417 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_HorizontalPosition" , |
418 | pld_info->horizontal_position); |
419 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Shape" , pld_info->shape); |
420 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupOrientation" , |
421 | pld_info->group_orientation); |
422 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupToken" , |
423 | pld_info->group_token); |
424 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_GroupPosition" , |
425 | pld_info->group_position); |
426 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Bay" , pld_info->bay); |
427 | |
428 | /* Fourth 32-bit dword */ |
429 | |
430 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Ejectable" , pld_info->ejectable); |
431 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_EjectRequired" , |
432 | pld_info->ospm_eject_required); |
433 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_CabinetNumber" , |
434 | pld_info->cabinet_number); |
435 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_CardCageNumber" , |
436 | pld_info->card_cage_number); |
437 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Reference" , pld_info->reference); |
438 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Rotation" , pld_info->rotation); |
439 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_Order" , pld_info->order); |
440 | |
441 | /* Fifth 32-bit dword */ |
442 | |
443 | if (buffer_desc->buffer.length > 16) { |
444 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_VerticalOffset" , |
445 | pld_info->vertical_offset); |
446 | acpi_os_printf(ACPI_PLD_OUTPUT, "PLD_HorizontalOffset" , |
447 | pld_info->horizontal_offset); |
448 | } |
449 | |
450 | ACPI_FREE(new_buffer); |
451 | exit: |
452 | ACPI_FREE(pld_info); |
453 | } |
454 | |