#include #include #include #include #include #include #include #ifndef UACPI_BAREBONES_MODE struct registered_interface { const uacpi_char *name; uacpi_u8 weight; uacpi_u8 kind; // Only applicable for predefined host interfaces uacpi_u8 host_type; // Only applicable for predefined interfaces uacpi_u8 disabled : 1; uacpi_u8 dynamic : 1; struct registered_interface *next; }; static uacpi_handle interface_mutex; static struct registered_interface *registered_interfaces; static uacpi_interface_handler interface_handler; static uacpi_u32 latest_queried_interface; #define WINDOWS(string, interface) \ { \ .name = "Windows "string, \ .weight = UACPI_VENDOR_INTERFACE_WINDOWS_##interface, \ .kind = UACPI_INTERFACE_KIND_VENDOR, \ .host_type = 0, \ .disabled = 0, \ .dynamic = 0, \ .next = UACPI_NULL \ } #define HOST_FEATURE(string, type) \ { \ .name = string, \ .weight = 0, \ .kind = UACPI_INTERFACE_KIND_FEATURE, \ .host_type = UACPI_HOST_INTERFACE_##type, \ .disabled = 1, \ .dynamic = 0, \ .next = UACPI_NULL, \ } static struct registered_interface predefined_interfaces[] = { // Vendor strings WINDOWS("2000", 2000), WINDOWS("2001", XP), WINDOWS("2001 SP1", XP_SP1), WINDOWS("2001.1", SERVER_2003), WINDOWS("2001 SP2", XP_SP2), WINDOWS("2001.1 SP1", SERVER_2003_SP1), WINDOWS("2006", VISTA), WINDOWS("2006.1", SERVER_2008), WINDOWS("2006 SP1", VISTA_SP1), WINDOWS("2006 SP2", VISTA_SP2), WINDOWS("2009", 7), WINDOWS("2012", 8), WINDOWS("2013", 8_1), WINDOWS("2015", 10), WINDOWS("2016", 10_RS1), WINDOWS("2017", 10_RS2), WINDOWS("2017.2", 10_RS3), WINDOWS("2018", 10_RS4), WINDOWS("2018.2", 10_RS5), WINDOWS("2019", 10_19H1), WINDOWS("2020", 10_20H1), WINDOWS("2021", 11), WINDOWS("2022", 11_22H2), // Feature strings HOST_FEATURE("Module Device", MODULE_DEVICE), HOST_FEATURE("Processor Device", PROCESSOR_DEVICE), HOST_FEATURE("3.0 Thermal Model", 3_0_THERMAL_MODEL), HOST_FEATURE("3.0 _SCP Extensions", 3_0_SCP_EXTENSIONS), HOST_FEATURE("Processor Aggregator Device", PROCESSOR_AGGREGATOR_DEVICE), // Interpreter features { .name = "Extended Address Space Descriptor" }, }; uacpi_status uacpi_initialize_interfaces(void) { uacpi_size i; registered_interfaces = &predefined_interfaces[0]; interface_mutex = uacpi_kernel_create_mutex(); if (uacpi_unlikely(interface_mutex == UACPI_NULL)) return UACPI_STATUS_OUT_OF_MEMORY; for (i = 0; i < (UACPI_ARRAY_SIZE(predefined_interfaces) - 1); ++i) predefined_interfaces[i].next = &predefined_interfaces[i + 1]; return UACPI_STATUS_OK; } void uacpi_deinitialize_interfaces(void) { struct registered_interface *iface, *next_iface = registered_interfaces; while (next_iface) { iface = next_iface; next_iface = iface->next; iface->next = UACPI_NULL; if (iface->dynamic) { uacpi_free_dynamic_string(iface->name); uacpi_free(iface, sizeof(*iface)); continue; } // Only features are disabled by default iface->disabled = iface->kind == UACPI_INTERFACE_KIND_FEATURE ? UACPI_TRUE : UACPI_FALSE; } if (interface_mutex) uacpi_kernel_free_mutex(interface_mutex); interface_mutex = UACPI_NULL; interface_handler = UACPI_NULL; latest_queried_interface = 0; registered_interfaces = UACPI_NULL; } uacpi_vendor_interface uacpi_latest_queried_vendor_interface(void) { return uacpi_atomic_load32(&latest_queried_interface); } static struct registered_interface *find_interface_unlocked( const uacpi_char *name ) { struct registered_interface *interface = registered_interfaces; while (interface) { if (uacpi_strcmp(interface->name, name) == 0) return interface; interface = interface->next; } return UACPI_NULL; } static struct registered_interface *find_host_interface_unlocked( uacpi_host_interface type ) { struct registered_interface *interface = registered_interfaces; while (interface) { if (interface->host_type == type) return interface; interface = interface->next; } return UACPI_NULL; } uacpi_status uacpi_install_interface( const uacpi_char *name, uacpi_interface_kind kind ) { struct registered_interface *interface; uacpi_status ret; uacpi_char *name_copy; uacpi_size name_size; UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED); ret = uacpi_acquire_native_mutex(interface_mutex); if (uacpi_unlikely_error(ret)) return ret; interface = find_interface_unlocked(name); if (interface != UACPI_NULL) { if (interface->disabled) interface->disabled = UACPI_FALSE; ret = UACPI_STATUS_ALREADY_EXISTS; goto out; } interface = uacpi_kernel_alloc(sizeof(*interface)); if (uacpi_unlikely(interface == UACPI_NULL)) { ret = UACPI_STATUS_OUT_OF_MEMORY; goto out; } name_size = uacpi_strlen(name) + 1; name_copy = uacpi_kernel_alloc(name_size); if (uacpi_unlikely(name_copy == UACPI_NULL)) { uacpi_free(interface, sizeof(*interface)); ret = UACPI_STATUS_OUT_OF_MEMORY; goto out; } uacpi_memcpy(name_copy, name, name_size); interface->name = name_copy; interface->weight = 0; interface->kind = kind; interface->host_type = 0; interface->disabled = 0; interface->dynamic = 1; interface->next = registered_interfaces; registered_interfaces = interface; out: uacpi_release_native_mutex(interface_mutex); return ret; } uacpi_status uacpi_uninstall_interface(const uacpi_char *name) { struct registered_interface *cur, *prev; uacpi_status ret; UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED); ret = uacpi_acquire_native_mutex(interface_mutex); if (uacpi_unlikely_error(ret)) return ret; cur = registered_interfaces; prev = cur; ret = UACPI_STATUS_NOT_FOUND; while (cur) { if (uacpi_strcmp(cur->name, name) != 0) { prev = cur; cur = cur->next; continue; } if (cur->dynamic) { if (prev == cur) { registered_interfaces = cur->next; } else { prev->next = cur->next; } uacpi_release_native_mutex(interface_mutex); uacpi_free_dynamic_string(cur->name); uacpi_free(cur, sizeof(*cur)); return UACPI_STATUS_OK; } /* * If this interface was already disabled, pretend we didn't actually * find it and keep ret as UACPI_STATUS_NOT_FOUND. The fact that it's * still in the registered list is an implementation detail of * predefined interfaces. */ if (!cur->disabled) { cur->disabled = UACPI_TRUE; ret = UACPI_STATUS_OK; } break; } uacpi_release_native_mutex(interface_mutex); return ret; } static uacpi_status configure_host_interface( uacpi_host_interface type, uacpi_bool enabled ) { struct registered_interface *interface; uacpi_status ret; UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED); ret = uacpi_acquire_native_mutex(interface_mutex); if (uacpi_unlikely_error(ret)) return ret; interface = find_host_interface_unlocked(type); if (interface == UACPI_NULL) { ret = UACPI_STATUS_NOT_FOUND; goto out; } interface->disabled = !enabled; out: uacpi_release_native_mutex(interface_mutex); return ret; } uacpi_status uacpi_enable_host_interface(uacpi_host_interface type) { return configure_host_interface(type, UACPI_TRUE); } uacpi_status uacpi_disable_host_interface(uacpi_host_interface type) { return configure_host_interface(type, UACPI_FALSE); } uacpi_status uacpi_set_interface_query_handler( uacpi_interface_handler handler ) { uacpi_status ret; UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED); ret = uacpi_acquire_native_mutex(interface_mutex); if (uacpi_unlikely_error(ret)) return ret; if (interface_handler != UACPI_NULL && handler != UACPI_NULL) { ret = UACPI_STATUS_ALREADY_EXISTS; goto out; } interface_handler = handler; out: uacpi_release_native_mutex(interface_mutex); return ret; } uacpi_status uacpi_bulk_configure_interfaces( uacpi_interface_action action, uacpi_interface_kind kind ) { uacpi_status ret; struct registered_interface *interface; UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED); ret = uacpi_acquire_native_mutex(interface_mutex); if (uacpi_unlikely_error(ret)) return ret; interface = registered_interfaces; while (interface) { if (kind & interface->kind) interface->disabled = (action == UACPI_INTERFACE_ACTION_DISABLE); interface = interface->next; } uacpi_release_native_mutex(interface_mutex); return ret; } uacpi_status uacpi_handle_osi(const uacpi_char *string, uacpi_bool *out_value) { uacpi_status ret; struct registered_interface *interface; uacpi_bool is_supported = UACPI_FALSE; ret = uacpi_acquire_native_mutex(interface_mutex); if (uacpi_unlikely_error(ret)) return ret; interface = find_interface_unlocked(string); if (interface == UACPI_NULL) goto out; if (interface->weight > latest_queried_interface) uacpi_atomic_store32(&latest_queried_interface, interface->weight); is_supported = !interface->disabled; if (interface_handler) is_supported = interface_handler(string, is_supported); out: uacpi_release_native_mutex(interface_mutex); *out_value = is_supported; return UACPI_STATUS_OK; } #endif // !UACPI_BAREBONES_MODE