diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/x86/acpigen.c | 119 | ||||
-rw-r--r-- | src/arch/x86/include/arch/acpigen.h | 17 |
2 files changed, 78 insertions, 58 deletions
diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c index 5447752823..8ebdd0982c 100644 --- a/src/arch/x86/acpigen.c +++ b/src/arch/x86/acpigen.c @@ -1180,11 +1180,50 @@ void acpigen_write_return_string(const char *arg) acpigen_write_string(arg); } +void acpigen_write_dsm(const char *uuid, void (**callbacks)(void *), + size_t count, void *arg) +{ + struct dsm_uuid id = DSM_UUID(uuid, callbacks, count, arg); + acpigen_write_dsm_uuid_arr(&id, 1); +} + +static void acpigen_write_dsm_uuid(struct dsm_uuid *id) +{ + size_t i; + + /* If (LEqual (Local0, ToUUID(uuid))) */ + acpigen_write_if(); + acpigen_emit_byte(LEQUAL_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_uuid(id->uuid); + + /* ToInteger (Arg2, Local1) */ + acpigen_write_to_integer(ARG2_OP, LOCAL1_OP); + + for (i = 0; i < id->count; i++) { + /* If (LEqual (Local1, i)) */ + acpigen_write_if_lequal_op_int(LOCAL1_OP, i); + + /* Callback to write if handler. */ + if (id->callbacks[i]) + id->callbacks[i](id->arg); + + acpigen_pop_len(); /* If */ + } + + /* Default case: Return (Buffer (One) { 0x0 }) */ + acpigen_write_return_singleton_buffer(0x0); + + acpigen_pop_len(); /* If (LEqual (Local0, ToUUID(uuid))) */ + +} + /* * Generate ACPI AML code for _DSM method. - * This function takes as input uuid for the device, set of callbacks and - * argument to pass into the callbacks. Callbacks should ensure that Local0 and - * Local1 are left untouched. Use of Local2-Local7 is permitted in callbacks. + * This function takes as input array of uuid for the device, set of callbacks + * and argument to pass into the callbacks. Callbacks should ensure that Local0 + * and Local1 are left untouched. Use of Local2-Local7 is permitted in + * callbacks. * * Arguments passed into _DSM method: * Arg0 = UUID @@ -1194,26 +1233,26 @@ void acpigen_write_return_string(const char *arg) * * AML code generated would look like: * Method (_DSM, 4, Serialized) { - * ToBuffer (Arg0, Local0) - * If (LEqual (Local0, ToUUID(uuid))) { - * ToInteger (Arg2, Local1) - * If (LEqual (Local1, 0)) { - * <acpigen by callback[0]> - * } Else { - * ... - * If (LEqual (Local1, n)) { - * <acpigen by callback[n]> - * } Else { - * Return (Buffer (One) { 0x0 }) - * } - * } - * } Else { - * Return (Buffer (One) { 0x0 }) - * } + * ToBuffer (Arg0, Local0) + * If (LEqual (Local0, ToUUID(uuid))) { + * ToInteger (Arg2, Local1) + * If (LEqual (Local1, 0)) { + * <acpigen by callback[0]> + * } + * ... + * If (LEqual (Local1, n)) { + * <acpigen by callback[n]> + * } + * Return (Buffer (One) { 0x0 }) + * } + * ... + * If (LEqual (Local0, ToUUID(uuidn))) { + * ... + * } + * Return (Buffer (One) { 0x0 }) * } */ -void acpigen_write_dsm(const char *uuid, void (*callbacks[])(void *), - size_t count, void *arg) +void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count) { size_t i; @@ -1223,46 +1262,12 @@ void acpigen_write_dsm(const char *uuid, void (*callbacks[])(void *), /* ToBuffer (Arg0, Local0) */ acpigen_write_to_buffer(ARG0_OP, LOCAL0_OP); - /* If (LEqual (Local0, ToUUID(uuid))) */ - acpigen_write_if(); - acpigen_emit_byte(LEQUAL_OP); - acpigen_emit_byte(LOCAL0_OP); - acpigen_write_uuid(uuid); - - /* ToInteger (Arg2, Local1) */ - acpigen_write_to_integer(ARG2_OP, LOCAL1_OP); - acpigen_write_debug_op(LOCAL1_OP); - - for (i = 0; i < count; i++) { - /* If (Lequal (Local1, i)) */ - acpigen_write_if_lequal_op_int(LOCAL1_OP, i); - - /* Callback to write if handler. */ - if (callbacks[i]) - callbacks[i](arg); - - acpigen_pop_len(); /* If */ - - /* Else */ - acpigen_write_else(); - } - - /* Default case: Return (Buffer (One) { 0x0 }) */ - acpigen_write_return_singleton_buffer(0x0); - - /* Pop lengths for all the else clauses. */ for (i = 0; i < count; i++) - acpigen_pop_len(); - - acpigen_pop_len(); /* If (LEqual (Local0, ToUUID(uuid))) */ - - /* Else */ - acpigen_write_else(); + acpigen_write_dsm_uuid(&ids[i]); - /* Return (Buffer (One) { 0x0 }) */ + /* Return (Buffer (One) { 0x0 }) */ acpigen_write_return_singleton_buffer(0x0); - acpigen_pop_len(); /* Else */ acpigen_pop_len(); /* Method _DSM */ } diff --git a/src/arch/x86/include/arch/acpigen.h b/src/arch/x86/include/arch/acpigen.h index dcd8fb7a64..f76d85e9bc 100644 --- a/src/arch/x86/include/arch/acpigen.h +++ b/src/arch/x86/include/arch/acpigen.h @@ -144,6 +144,20 @@ struct opregion { unsigned long regionlen; }; +#define DSM_UUID(DSM_UUID, DSM_CALLBACKS, DSM_COUNT, DSM_ARG) \ + { .uuid = DSM_UUID, \ + .callbacks = DSM_CALLBACKS, \ + .count = DSM_COUNT, \ + .arg = DSM_ARG, \ + } + +struct dsm_uuid { + const char *uuid; + void (**callbacks)(void *); + size_t count; + void *arg; +}; + void acpigen_write_return_integer(uint64_t arg); void acpigen_write_return_string(const char *arg); void acpigen_write_len_f(void); @@ -235,8 +249,9 @@ void acpigen_write_return_byte(uint8_t arg); * argument to pass into the callbacks. Callbacks should ensure that Local0 and * Local1 are left untouched. Use of Local2-Local7 is permitted in callbacks. */ -void acpigen_write_dsm(const char *uuid, void (*callbacks[])(void *), +void acpigen_write_dsm(const char *uuid, void (**callbacks)(void *), size_t count, void *arg); +void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count); /* * Generate ACPI AML code for OperationRegion * This function takes input region name, region space, region offset & region |