Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / commands / acpihalt.c
blobda68b5b528ded1ae008c06b545c9568e2c20c5a8
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #ifdef GRUB_DSDT_TEST
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <errno.h>
27 #define grub_dprintf(cond, args...) printf ( args )
28 #define grub_printf printf
29 typedef uint64_t grub_uint64_t;
30 typedef uint32_t grub_uint32_t;
31 typedef uint16_t grub_uint16_t;
32 typedef uint8_t grub_uint8_t;
34 #endif
36 #include <grub/acpi.h>
37 #ifndef GRUB_DSDT_TEST
38 #include <grub/i18n.h>
39 #else
40 #define _(x) x
41 #define N_(x) x
42 #endif
44 #ifndef GRUB_DSDT_TEST
45 #include <grub/mm.h>
46 #include <grub/misc.h>
47 #include <grub/time.h>
48 #include <grub/cpu/io.h>
49 #endif
51 static inline grub_uint32_t
52 decode_length (const grub_uint8_t *ptr, int *numlen)
54 int num_bytes, i;
55 grub_uint32_t ret;
56 if (*ptr < 64)
58 if (numlen)
59 *numlen = 1;
60 return *ptr;
62 num_bytes = *ptr >> 6;
63 if (numlen)
64 *numlen = num_bytes + 1;
65 ret = *ptr & 0xf;
66 ptr++;
67 for (i = 0; i < num_bytes; i++)
69 ret |= *ptr << (8 * i + 4);
70 ptr++;
72 return ret;
75 static inline grub_uint32_t
76 skip_name_string (const grub_uint8_t *ptr, const grub_uint8_t *end)
78 const grub_uint8_t *ptr0 = ptr;
80 while (ptr < end && (*ptr == '^' || *ptr == '\\'))
81 ptr++;
82 switch (*ptr)
84 case '.':
85 ptr++;
86 ptr += 8;
87 break;
88 case '/':
89 ptr++;
90 ptr += 1 + (*ptr) * 4;
91 break;
92 case 0:
93 ptr++;
94 break;
95 default:
96 ptr += 4;
97 break;
99 return ptr - ptr0;
102 static inline grub_uint32_t
103 skip_data_ref_object (const grub_uint8_t *ptr, const grub_uint8_t *end)
105 grub_dprintf ("acpi", "data type = 0x%x\n", *ptr);
106 switch (*ptr)
108 case GRUB_ACPI_OPCODE_PACKAGE:
109 case GRUB_ACPI_OPCODE_BUFFER:
110 return 1 + decode_length (ptr + 1, 0);
111 case GRUB_ACPI_OPCODE_ZERO:
112 case GRUB_ACPI_OPCODE_ONES:
113 case GRUB_ACPI_OPCODE_ONE:
114 return 1;
115 case GRUB_ACPI_OPCODE_BYTE_CONST:
116 return 2;
117 case GRUB_ACPI_OPCODE_WORD_CONST:
118 return 3;
119 case GRUB_ACPI_OPCODE_DWORD_CONST:
120 return 5;
121 case GRUB_ACPI_OPCODE_STRING_CONST:
123 const grub_uint8_t *ptr0 = ptr;
124 for (ptr++; ptr < end && *ptr; ptr++);
125 if (ptr == end)
126 return 0;
127 return ptr - ptr0 + 1;
129 default:
130 if (*ptr == '^' || *ptr == '\\' || *ptr == '_'
131 || (*ptr >= 'A' && *ptr <= 'Z'))
132 return skip_name_string (ptr, end);
133 grub_printf ("Unknown opcode 0x%x\n", *ptr);
134 return 0;
138 static inline grub_uint32_t
139 skip_term (const grub_uint8_t *ptr, const grub_uint8_t *end)
141 grub_uint32_t add;
142 const grub_uint8_t *ptr0 = ptr;
144 switch(*ptr)
146 case GRUB_ACPI_OPCODE_ADD:
147 case GRUB_ACPI_OPCODE_AND:
148 case GRUB_ACPI_OPCODE_CONCAT:
149 case GRUB_ACPI_OPCODE_CONCATRES:
150 case GRUB_ACPI_OPCODE_DIVIDE:
151 case GRUB_ACPI_OPCODE_INDEX:
152 case GRUB_ACPI_OPCODE_LSHIFT:
153 case GRUB_ACPI_OPCODE_MOD:
154 case GRUB_ACPI_OPCODE_MULTIPLY:
155 case GRUB_ACPI_OPCODE_NAND:
156 case GRUB_ACPI_OPCODE_NOR:
157 case GRUB_ACPI_OPCODE_OR:
158 case GRUB_ACPI_OPCODE_RSHIFT:
159 case GRUB_ACPI_OPCODE_SUBTRACT:
160 case GRUB_ACPI_OPCODE_TOSTRING:
161 case GRUB_ACPI_OPCODE_XOR:
163 * Parameters for these opcodes: TermArg, TermArg Target, see ACPI
164 * spec r5.0, page 828f.
166 ptr++;
167 ptr += add = skip_term (ptr, end);
168 if (!add)
169 return 0;
170 ptr += add = skip_term (ptr, end);
171 if (!add)
172 return 0;
173 ptr += skip_name_string (ptr, end);
174 break;
175 default:
176 return skip_data_ref_object (ptr, end);
178 return ptr - ptr0;
181 static inline grub_uint32_t
182 skip_ext_op (const grub_uint8_t *ptr, const grub_uint8_t *end)
184 const grub_uint8_t *ptr0 = ptr;
185 int add;
186 grub_dprintf ("acpi", "Extended opcode: 0x%x\n", *ptr);
187 switch (*ptr)
189 case GRUB_ACPI_EXTOPCODE_MUTEX:
190 ptr++;
191 ptr += skip_name_string (ptr, end);
192 ptr++;
193 break;
194 case GRUB_ACPI_EXTOPCODE_EVENT_OP:
195 ptr++;
196 ptr += skip_name_string (ptr, end);
197 break;
198 case GRUB_ACPI_EXTOPCODE_OPERATION_REGION:
199 ptr++;
200 ptr += skip_name_string (ptr, end);
201 ptr++;
202 ptr += add = skip_term (ptr, end);
203 if (!add)
204 return 0;
205 ptr += add = skip_term (ptr, end);
206 if (!add)
207 return 0;
208 break;
209 case GRUB_ACPI_EXTOPCODE_FIELD_OP:
210 case GRUB_ACPI_EXTOPCODE_DEVICE_OP:
211 case GRUB_ACPI_EXTOPCODE_PROCESSOR_OP:
212 case GRUB_ACPI_EXTOPCODE_POWER_RES_OP:
213 case GRUB_ACPI_EXTOPCODE_THERMAL_ZONE_OP:
214 case GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP:
215 case GRUB_ACPI_EXTOPCODE_BANK_FIELD_OP:
216 ptr++;
217 ptr += decode_length (ptr, 0);
218 break;
219 default:
220 grub_printf ("Unexpected extended opcode: 0x%x\n", *ptr);
221 return 0;
223 return ptr - ptr0;
227 static int
228 get_sleep_type (grub_uint8_t *table, grub_uint8_t *ptr, grub_uint8_t *end,
229 grub_uint8_t *scope, int scope_len)
231 grub_uint8_t *prev = table;
233 if (!ptr)
234 ptr = table + sizeof (struct grub_acpi_table_header);
235 while (ptr < end && prev < ptr)
237 int add;
238 prev = ptr;
239 grub_dprintf ("acpi", "Opcode 0x%x\n", *ptr);
240 grub_dprintf ("acpi", "Tell %x\n", (unsigned) (ptr - table));
241 switch (*ptr)
243 case GRUB_ACPI_OPCODE_EXTOP:
244 ptr++;
245 ptr += add = skip_ext_op (ptr, end);
246 if (!add)
247 return -1;
248 break;
249 case GRUB_ACPI_OPCODE_CREATE_WORD_FIELD:
250 case GRUB_ACPI_OPCODE_CREATE_BYTE_FIELD:
252 ptr += 5;
253 ptr += add = skip_data_ref_object (ptr, end);
254 if (!add)
255 return -1;
256 ptr += 4;
257 break;
259 case GRUB_ACPI_OPCODE_NAME:
260 ptr++;
261 if ((!scope || grub_memcmp (scope, "\\", scope_len) == 0) &&
262 (grub_memcmp (ptr, "_S5_", 4) == 0 || grub_memcmp (ptr, "\\_S5_", 4) == 0))
264 int ll;
265 grub_uint8_t *ptr2 = ptr;
266 grub_dprintf ("acpi", "S5 found\n");
267 ptr2 += skip_name_string (ptr, end);
268 if (*ptr2 != 0x12)
270 grub_printf ("Unknown opcode in _S5: 0x%x\n", *ptr2);
271 return -1;
273 ptr2++;
274 decode_length (ptr2, &ll);
275 ptr2 += ll;
276 ptr2++;
277 switch (*ptr2)
279 case GRUB_ACPI_OPCODE_ZERO:
280 return 0;
281 case GRUB_ACPI_OPCODE_ONE:
282 return 1;
283 case GRUB_ACPI_OPCODE_BYTE_CONST:
284 return ptr2[1];
285 default:
286 grub_printf ("Unknown data type in _S5: 0x%x\n", *ptr2);
287 return -1;
290 ptr += add = skip_name_string (ptr, end);
291 if (!add)
292 return -1;
293 ptr += add = skip_data_ref_object (ptr, end);
294 if (!add)
295 return -1;
296 break;
297 case GRUB_ACPI_OPCODE_ALIAS:
298 ptr++;
299 /* We need to skip two name strings */
300 ptr += add = skip_name_string (ptr, end);
301 if (!add)
302 return -1;
303 ptr += add = skip_name_string (ptr, end);
304 if (!add)
305 return -1;
306 break;
308 case GRUB_ACPI_OPCODE_SCOPE:
310 int scope_sleep_type;
311 int ll;
312 grub_uint8_t *name;
313 int name_len;
315 ptr++;
316 add = decode_length (ptr, &ll);
317 name = ptr + ll;
318 name_len = skip_name_string (name, ptr + add);
319 if (!name_len)
320 return -1;
321 scope_sleep_type = get_sleep_type (table, name + name_len,
322 ptr + add, name, name_len);
323 if (scope_sleep_type != -2)
324 return scope_sleep_type;
325 ptr += add;
326 break;
328 case GRUB_ACPI_OPCODE_IF:
329 case GRUB_ACPI_OPCODE_METHOD:
331 ptr++;
332 ptr += decode_length (ptr, 0);
333 break;
335 default:
336 grub_printf ("Unknown opcode 0x%x\n", *ptr);
337 return -1;
341 return -2;
344 #ifdef GRUB_DSDT_TEST
346 main (int argc, char **argv)
348 FILE *f;
349 size_t len;
350 unsigned char *buf;
351 if (argc < 2)
352 printf ("Usage: %s FILE\n", argv[0]);
353 f = grub_util_fopen (argv[1], "rb");
354 if (!f)
356 printf ("Couldn't open file\n");
357 return 1;
359 fseek (f, 0, SEEK_END);
360 len = ftell (f);
361 fseek (f, 0, SEEK_SET);
362 buf = malloc (len);
363 if (!buf)
365 printf (_("error: %s.\n"), _("out of memory"));
366 fclose (f);
367 return 2;
369 if (fread (buf, 1, len, f) != len)
371 printf (_("cannot read `%s': %s"), argv[1], strerror (errno));
372 free (buf);
373 fclose (f);
374 return 2;
377 printf ("Sleep type = %d\n", get_sleep_type (buf, NULL, buf + len, NULL, 0));
378 free (buf);
379 fclose (f);
380 return 0;
383 #else
385 void
386 grub_acpi_halt (void)
388 struct grub_acpi_rsdp_v20 *rsdp2;
389 struct grub_acpi_rsdp_v10 *rsdp1;
390 struct grub_acpi_table_header *rsdt;
391 grub_uint32_t *entry_ptr;
392 grub_uint32_t port = 0;
393 int sleep_type = -1;
395 rsdp2 = grub_acpi_get_rsdpv2 ();
396 if (rsdp2)
397 rsdp1 = &(rsdp2->rsdpv1);
398 else
399 rsdp1 = grub_acpi_get_rsdpv1 ();
400 grub_dprintf ("acpi", "rsdp1=%p\n", rsdp1);
401 if (!rsdp1)
402 return;
404 rsdt = (struct grub_acpi_table_header *) (grub_addr_t) rsdp1->rsdt_addr;
405 for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
406 entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt)
407 + rsdt->length);
408 entry_ptr++)
410 if (grub_memcmp ((void *) (grub_addr_t) *entry_ptr, "FACP", 4) == 0)
412 struct grub_acpi_fadt *fadt
413 = ((struct grub_acpi_fadt *) (grub_addr_t) *entry_ptr);
414 struct grub_acpi_table_header *dsdt
415 = (struct grub_acpi_table_header *) (grub_addr_t) fadt->dsdt_addr;
416 grub_uint8_t *buf = (grub_uint8_t *) dsdt;
418 port = fadt->pm1a;
420 grub_dprintf ("acpi", "PM1a port=%x\n", port);
422 if (grub_memcmp (dsdt->signature, "DSDT",
423 sizeof (dsdt->signature)) == 0
424 && sleep_type < 0)
425 sleep_type = get_sleep_type (buf, NULL, buf + dsdt->length,
426 NULL, 0);
428 else if (grub_memcmp ((void *) (grub_addr_t) *entry_ptr, "SSDT", 4) == 0
429 && sleep_type < 0)
431 struct grub_acpi_table_header *ssdt
432 = (struct grub_acpi_table_header *) (grub_addr_t) *entry_ptr;
433 grub_uint8_t *buf = (grub_uint8_t *) ssdt;
435 grub_dprintf ("acpi", "SSDT = %p\n", ssdt);
437 sleep_type = get_sleep_type (buf, NULL, buf + ssdt->length, NULL, 0);
441 grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n", sleep_type, port);
442 if (port && sleep_type >= 0 && sleep_type < 8)
443 grub_outw (GRUB_ACPI_SLP_EN | (sleep_type << GRUB_ACPI_SLP_TYP_OFFSET),
444 port & 0xffff);
446 grub_millisleep (1500);
448 /* TRANSLATORS: It's computer shutdown using ACPI, not disabling ACPI. */
449 grub_puts_ (N_("ACPI shutdown failed"));
451 #endif