11c8fce27SZhang Rui /* 21c8fce27SZhang Rui * sysfs.c - ACPI sysfs interface to userspace. 31c8fce27SZhang Rui */ 41c8fce27SZhang Rui 51c8fce27SZhang Rui #include <linux/init.h> 61c8fce27SZhang Rui #include <linux/kernel.h> 71c8fce27SZhang Rui #include <linux/moduleparam.h> 81c8fce27SZhang Rui #include <acpi/acpi_drivers.h> 91c8fce27SZhang Rui 103f8055c3SRafael J. Wysocki #include "internal.h" 113f8055c3SRafael J. Wysocki 121c8fce27SZhang Rui #define _COMPONENT ACPI_SYSTEM_COMPONENT 131c8fce27SZhang Rui ACPI_MODULE_NAME("sysfs"); 141c8fce27SZhang Rui 151c8fce27SZhang Rui #define PREFIX "ACPI: " 161c8fce27SZhang Rui 171c8fce27SZhang Rui #ifdef CONFIG_ACPI_DEBUG 181c8fce27SZhang Rui /* 191c8fce27SZhang Rui * ACPI debug sysfs I/F, including: 201c8fce27SZhang Rui * /sys/modules/acpi/parameters/debug_layer 211c8fce27SZhang Rui * /sys/modules/acpi/parameters/debug_level 221c8fce27SZhang Rui * /sys/modules/acpi/parameters/trace_method_name 231c8fce27SZhang Rui * /sys/modules/acpi/parameters/trace_state 241c8fce27SZhang Rui * /sys/modules/acpi/parameters/trace_debug_layer 251c8fce27SZhang Rui * /sys/modules/acpi/parameters/trace_debug_level 261c8fce27SZhang Rui */ 271c8fce27SZhang Rui 281c8fce27SZhang Rui struct acpi_dlayer { 291c8fce27SZhang Rui const char *name; 301c8fce27SZhang Rui unsigned long value; 311c8fce27SZhang Rui }; 321c8fce27SZhang Rui struct acpi_dlevel { 331c8fce27SZhang Rui const char *name; 341c8fce27SZhang Rui unsigned long value; 351c8fce27SZhang Rui }; 361c8fce27SZhang Rui #define ACPI_DEBUG_INIT(v) { .name = #v, .value = v } 371c8fce27SZhang Rui 381c8fce27SZhang Rui static const struct acpi_dlayer acpi_debug_layers[] = { 391c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_UTILITIES), 401c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_HARDWARE), 411c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_EVENTS), 421c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_TABLES), 431c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_NAMESPACE), 441c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_PARSER), 451c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_DISPATCHER), 461c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_EXECUTER), 471c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_RESOURCES), 481c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER), 491c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_OS_SERVICES), 501c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER), 511c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_COMPILER), 521c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_TOOLS), 531c8fce27SZhang Rui 541c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_BUS_COMPONENT), 551c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_AC_COMPONENT), 561c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_BATTERY_COMPONENT), 571c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_BUTTON_COMPONENT), 581c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_SBS_COMPONENT), 591c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_FAN_COMPONENT), 601c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_PCI_COMPONENT), 611c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_POWER_COMPONENT), 621c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_CONTAINER_COMPONENT), 631c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_SYSTEM_COMPONENT), 641c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_THERMAL_COMPONENT), 651c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_MEMORY_DEVICE_COMPONENT), 661c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_VIDEO_COMPONENT), 671c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_PROCESSOR_COMPONENT), 681c8fce27SZhang Rui }; 691c8fce27SZhang Rui 701c8fce27SZhang Rui static const struct acpi_dlevel acpi_debug_levels[] = { 711c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_INIT), 721c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT), 731c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_INFO), 741c8fce27SZhang Rui 751c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES), 761c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_PARSE), 771c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_LOAD), 781c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_DISPATCH), 791c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_EXEC), 801c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_NAMES), 811c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_OPREGION), 821c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_BFIELD), 831c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_TABLES), 841c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_VALUES), 851c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_OBJECTS), 861c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_RESOURCES), 871c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS), 881c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_PACKAGE), 891c8fce27SZhang Rui 901c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS), 911c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS), 921c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS), 931c8fce27SZhang Rui 941c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_MUTEX), 951c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_THREADS), 961c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_IO), 971c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS), 981c8fce27SZhang Rui 991c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE), 1001c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO), 1011c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES), 1021c8fce27SZhang Rui ACPI_DEBUG_INIT(ACPI_LV_EVENTS), 1031c8fce27SZhang Rui }; 1041c8fce27SZhang Rui 105ec652b35SZhang Rui static int param_get_debug_layer(char *buffer, const struct kernel_param *kp) 1061c8fce27SZhang Rui { 1071c8fce27SZhang Rui int result = 0; 1081c8fce27SZhang Rui int i; 1091c8fce27SZhang Rui 1101c8fce27SZhang Rui result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); 1111c8fce27SZhang Rui 1121c8fce27SZhang Rui for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) { 1131c8fce27SZhang Rui result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n", 1141c8fce27SZhang Rui acpi_debug_layers[i].name, 1151c8fce27SZhang Rui acpi_debug_layers[i].value, 1161c8fce27SZhang Rui (acpi_dbg_layer & acpi_debug_layers[i].value) 1171c8fce27SZhang Rui ? '*' : ' '); 1181c8fce27SZhang Rui } 1191c8fce27SZhang Rui result += 1201c8fce27SZhang Rui sprintf(buffer + result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS", 1211c8fce27SZhang Rui ACPI_ALL_DRIVERS, 1221c8fce27SZhang Rui (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 1231c8fce27SZhang Rui ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS) 1241c8fce27SZhang Rui == 0 ? ' ' : '-'); 1251c8fce27SZhang Rui result += 1261c8fce27SZhang Rui sprintf(buffer + result, 1271c8fce27SZhang Rui "--\ndebug_layer = 0x%08X ( * = enabled)\n", 1281c8fce27SZhang Rui acpi_dbg_layer); 1291c8fce27SZhang Rui 1301c8fce27SZhang Rui return result; 1311c8fce27SZhang Rui } 1321c8fce27SZhang Rui 133ec652b35SZhang Rui static int param_get_debug_level(char *buffer, const struct kernel_param *kp) 1341c8fce27SZhang Rui { 1351c8fce27SZhang Rui int result = 0; 1361c8fce27SZhang Rui int i; 1371c8fce27SZhang Rui 1381c8fce27SZhang Rui result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); 1391c8fce27SZhang Rui 1401c8fce27SZhang Rui for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) { 1411c8fce27SZhang Rui result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n", 1421c8fce27SZhang Rui acpi_debug_levels[i].name, 1431c8fce27SZhang Rui acpi_debug_levels[i].value, 1441c8fce27SZhang Rui (acpi_dbg_level & acpi_debug_levels[i].value) 1451c8fce27SZhang Rui ? '*' : ' '); 1461c8fce27SZhang Rui } 1471c8fce27SZhang Rui result += 1481c8fce27SZhang Rui sprintf(buffer + result, "--\ndebug_level = 0x%08X (* = enabled)\n", 1491c8fce27SZhang Rui acpi_dbg_level); 1501c8fce27SZhang Rui 1511c8fce27SZhang Rui return result; 1521c8fce27SZhang Rui } 1531c8fce27SZhang Rui 1549c8b04beSVasiliy Kulikov static const struct kernel_param_ops param_ops_debug_layer = { 155ec652b35SZhang Rui .set = param_set_uint, 156ec652b35SZhang Rui .get = param_get_debug_layer, 157ec652b35SZhang Rui }; 158ec652b35SZhang Rui 1599c8b04beSVasiliy Kulikov static const struct kernel_param_ops param_ops_debug_level = { 160ec652b35SZhang Rui .set = param_set_uint, 161ec652b35SZhang Rui .get = param_get_debug_level, 162ec652b35SZhang Rui }; 163ec652b35SZhang Rui 164ec652b35SZhang Rui module_param_cb(debug_layer, ¶m_ops_debug_layer, &acpi_dbg_layer, 0644); 165ec652b35SZhang Rui module_param_cb(debug_level, ¶m_ops_debug_level, &acpi_dbg_level, 0644); 1661c8fce27SZhang Rui 1671c8fce27SZhang Rui static char trace_method_name[6]; 1681c8fce27SZhang Rui module_param_string(trace_method_name, trace_method_name, 6, 0644); 1691c8fce27SZhang Rui static unsigned int trace_debug_layer; 1701c8fce27SZhang Rui module_param(trace_debug_layer, uint, 0644); 1711c8fce27SZhang Rui static unsigned int trace_debug_level; 1721c8fce27SZhang Rui module_param(trace_debug_level, uint, 0644); 1731c8fce27SZhang Rui 1741c8fce27SZhang Rui static int param_set_trace_state(const char *val, struct kernel_param *kp) 1751c8fce27SZhang Rui { 1761c8fce27SZhang Rui int result = 0; 1771c8fce27SZhang Rui 178869639f9SLen Brown if (!strncmp(val, "enable", sizeof("enable") - 1)) { 1791c8fce27SZhang Rui result = acpi_debug_trace(trace_method_name, trace_debug_level, 1801c8fce27SZhang Rui trace_debug_layer, 0); 1811c8fce27SZhang Rui if (result) 1821c8fce27SZhang Rui result = -EBUSY; 1831c8fce27SZhang Rui goto exit; 1841c8fce27SZhang Rui } 1851c8fce27SZhang Rui 186869639f9SLen Brown if (!strncmp(val, "disable", sizeof("disable") - 1)) { 1871c8fce27SZhang Rui int name = 0; 1881c8fce27SZhang Rui result = acpi_debug_trace((char *)&name, trace_debug_level, 1891c8fce27SZhang Rui trace_debug_layer, 0); 1901c8fce27SZhang Rui if (result) 1911c8fce27SZhang Rui result = -EBUSY; 1921c8fce27SZhang Rui goto exit; 1931c8fce27SZhang Rui } 1941c8fce27SZhang Rui 1951c8fce27SZhang Rui if (!strncmp(val, "1", 1)) { 1961c8fce27SZhang Rui result = acpi_debug_trace(trace_method_name, trace_debug_level, 1971c8fce27SZhang Rui trace_debug_layer, 1); 1981c8fce27SZhang Rui if (result) 1991c8fce27SZhang Rui result = -EBUSY; 2001c8fce27SZhang Rui goto exit; 2011c8fce27SZhang Rui } 2021c8fce27SZhang Rui 2031c8fce27SZhang Rui result = -EINVAL; 2041c8fce27SZhang Rui exit: 2051c8fce27SZhang Rui return result; 2061c8fce27SZhang Rui } 2071c8fce27SZhang Rui 2081c8fce27SZhang Rui static int param_get_trace_state(char *buffer, struct kernel_param *kp) 2091c8fce27SZhang Rui { 2101c8fce27SZhang Rui if (!acpi_gbl_trace_method_name) 2111c8fce27SZhang Rui return sprintf(buffer, "disable"); 2121c8fce27SZhang Rui else { 2131c8fce27SZhang Rui if (acpi_gbl_trace_flags & 1) 2141c8fce27SZhang Rui return sprintf(buffer, "1"); 2151c8fce27SZhang Rui else 2161c8fce27SZhang Rui return sprintf(buffer, "enable"); 2171c8fce27SZhang Rui } 2181c8fce27SZhang Rui return 0; 2191c8fce27SZhang Rui } 2201c8fce27SZhang Rui 2211c8fce27SZhang Rui module_param_call(trace_state, param_set_trace_state, param_get_trace_state, 2221c8fce27SZhang Rui NULL, 0644); 2231c8fce27SZhang Rui #endif /* CONFIG_ACPI_DEBUG */ 2241c8fce27SZhang Rui 225aecad432SThomas Renninger 226aecad432SThomas Renninger /* /sys/modules/acpi/parameters/aml_debug_output */ 227aecad432SThomas Renninger 228aecad432SThomas Renninger module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object, 229aecad432SThomas Renninger bool, 0644); 230aecad432SThomas Renninger MODULE_PARM_DESC(aml_debug_output, 231aecad432SThomas Renninger "To enable/disable the ACPI Debug Object output."); 232aecad432SThomas Renninger 2331c8fce27SZhang Rui /* /sys/module/acpi/parameters/acpica_version */ 2341c8fce27SZhang Rui static int param_get_acpica_version(char *buffer, struct kernel_param *kp) 2351c8fce27SZhang Rui { 2361c8fce27SZhang Rui int result; 2371c8fce27SZhang Rui 2381c8fce27SZhang Rui result = sprintf(buffer, "%x", ACPI_CA_VERSION); 2391c8fce27SZhang Rui 2401c8fce27SZhang Rui return result; 2411c8fce27SZhang Rui } 2421c8fce27SZhang Rui 2431c8fce27SZhang Rui module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); 2441c8fce27SZhang Rui 2451c8fce27SZhang Rui /* 2461c8fce27SZhang Rui * ACPI table sysfs I/F: 2471c8fce27SZhang Rui * /sys/firmware/acpi/tables/ 2481c8fce27SZhang Rui * /sys/firmware/acpi/tables/dynamic/ 2491c8fce27SZhang Rui */ 2501c8fce27SZhang Rui 2511c8fce27SZhang Rui static LIST_HEAD(acpi_table_attr_list); 2521c8fce27SZhang Rui static struct kobject *tables_kobj; 2531c8fce27SZhang Rui static struct kobject *dynamic_tables_kobj; 2543f8055c3SRafael J. Wysocki static struct kobject *hotplug_kobj; 2551c8fce27SZhang Rui 2561c8fce27SZhang Rui struct acpi_table_attr { 2571c8fce27SZhang Rui struct bin_attribute attr; 2581c8fce27SZhang Rui char name[8]; 2591c8fce27SZhang Rui int instance; 2601c8fce27SZhang Rui struct list_head node; 2611c8fce27SZhang Rui }; 2621c8fce27SZhang Rui 2631c8fce27SZhang Rui static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj, 2641c8fce27SZhang Rui struct bin_attribute *bin_attr, char *buf, 2651c8fce27SZhang Rui loff_t offset, size_t count) 2661c8fce27SZhang Rui { 2671c8fce27SZhang Rui struct acpi_table_attr *table_attr = 2681c8fce27SZhang Rui container_of(bin_attr, struct acpi_table_attr, attr); 2691c8fce27SZhang Rui struct acpi_table_header *table_header = NULL; 2701c8fce27SZhang Rui acpi_status status; 2711c8fce27SZhang Rui char name[ACPI_NAME_SIZE]; 2721c8fce27SZhang Rui 2731c8fce27SZhang Rui if (strncmp(table_attr->name, "NULL", 4)) 2741c8fce27SZhang Rui memcpy(name, table_attr->name, ACPI_NAME_SIZE); 2751c8fce27SZhang Rui else 2761c8fce27SZhang Rui memcpy(name, "\0\0\0\0", 4); 2771c8fce27SZhang Rui 2781c8fce27SZhang Rui status = acpi_get_table(name, table_attr->instance, &table_header); 2791c8fce27SZhang Rui if (ACPI_FAILURE(status)) 2801c8fce27SZhang Rui return -ENODEV; 2811c8fce27SZhang Rui 2821c8fce27SZhang Rui return memory_read_from_buffer(buf, count, &offset, 2831c8fce27SZhang Rui table_header, table_header->length); 2841c8fce27SZhang Rui } 2851c8fce27SZhang Rui 2861c8fce27SZhang Rui static void acpi_table_attr_init(struct acpi_table_attr *table_attr, 2871c8fce27SZhang Rui struct acpi_table_header *table_header) 2881c8fce27SZhang Rui { 2891c8fce27SZhang Rui struct acpi_table_header *header = NULL; 2901c8fce27SZhang Rui struct acpi_table_attr *attr = NULL; 2911c8fce27SZhang Rui 2921c8fce27SZhang Rui sysfs_attr_init(&table_attr->attr.attr); 2931c8fce27SZhang Rui if (table_header->signature[0] != '\0') 2941c8fce27SZhang Rui memcpy(table_attr->name, table_header->signature, 2951c8fce27SZhang Rui ACPI_NAME_SIZE); 2961c8fce27SZhang Rui else 2971c8fce27SZhang Rui memcpy(table_attr->name, "NULL", 4); 2981c8fce27SZhang Rui 2991c8fce27SZhang Rui list_for_each_entry(attr, &acpi_table_attr_list, node) { 3001c8fce27SZhang Rui if (!memcmp(table_attr->name, attr->name, ACPI_NAME_SIZE)) 3011c8fce27SZhang Rui if (table_attr->instance < attr->instance) 3021c8fce27SZhang Rui table_attr->instance = attr->instance; 3031c8fce27SZhang Rui } 3041c8fce27SZhang Rui table_attr->instance++; 3051c8fce27SZhang Rui 3061c8fce27SZhang Rui if (table_attr->instance > 1 || (table_attr->instance == 1 && 3071c8fce27SZhang Rui !acpi_get_table 3081c8fce27SZhang Rui (table_header->signature, 2, &header))) 3091c8fce27SZhang Rui sprintf(table_attr->name + ACPI_NAME_SIZE, "%d", 3101c8fce27SZhang Rui table_attr->instance); 3111c8fce27SZhang Rui 3121c8fce27SZhang Rui table_attr->attr.size = 0; 3131c8fce27SZhang Rui table_attr->attr.read = acpi_table_show; 3141c8fce27SZhang Rui table_attr->attr.attr.name = table_attr->name; 3151c8fce27SZhang Rui table_attr->attr.attr.mode = 0400; 3161c8fce27SZhang Rui 3171c8fce27SZhang Rui return; 3181c8fce27SZhang Rui } 3191c8fce27SZhang Rui 3201c8fce27SZhang Rui static acpi_status 3211c8fce27SZhang Rui acpi_sysfs_table_handler(u32 event, void *table, void *context) 3221c8fce27SZhang Rui { 3231c8fce27SZhang Rui struct acpi_table_attr *table_attr; 3241c8fce27SZhang Rui 3251c8fce27SZhang Rui switch (event) { 3261c8fce27SZhang Rui case ACPI_TABLE_EVENT_LOAD: 3271c8fce27SZhang Rui table_attr = 3281c8fce27SZhang Rui kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL); 3291c8fce27SZhang Rui if (!table_attr) 3301c8fce27SZhang Rui return AE_NO_MEMORY; 3311c8fce27SZhang Rui 3321c8fce27SZhang Rui acpi_table_attr_init(table_attr, table); 3331c8fce27SZhang Rui if (sysfs_create_bin_file(dynamic_tables_kobj, 3341c8fce27SZhang Rui &table_attr->attr)) { 3351c8fce27SZhang Rui kfree(table_attr); 3361c8fce27SZhang Rui return AE_ERROR; 3371c8fce27SZhang Rui } else 3381c8fce27SZhang Rui list_add_tail(&table_attr->node, &acpi_table_attr_list); 3391c8fce27SZhang Rui break; 3401c8fce27SZhang Rui case ACPI_TABLE_EVENT_UNLOAD: 3411c8fce27SZhang Rui /* 3421c8fce27SZhang Rui * we do not need to do anything right now 3431c8fce27SZhang Rui * because the table is not deleted from the 3441c8fce27SZhang Rui * global table list when unloading it. 3451c8fce27SZhang Rui */ 3461c8fce27SZhang Rui break; 3471c8fce27SZhang Rui default: 3481c8fce27SZhang Rui return AE_BAD_PARAMETER; 3491c8fce27SZhang Rui } 3501c8fce27SZhang Rui return AE_OK; 3511c8fce27SZhang Rui } 3521c8fce27SZhang Rui 3531c8fce27SZhang Rui static int acpi_tables_sysfs_init(void) 3541c8fce27SZhang Rui { 3551c8fce27SZhang Rui struct acpi_table_attr *table_attr; 3561c8fce27SZhang Rui struct acpi_table_header *table_header = NULL; 3571c8fce27SZhang Rui int table_index = 0; 3581c8fce27SZhang Rui int result; 3591c8fce27SZhang Rui 3601c8fce27SZhang Rui tables_kobj = kobject_create_and_add("tables", acpi_kobj); 3611c8fce27SZhang Rui if (!tables_kobj) 3621c8fce27SZhang Rui goto err; 3631c8fce27SZhang Rui 3641c8fce27SZhang Rui dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj); 3651c8fce27SZhang Rui if (!dynamic_tables_kobj) 3661c8fce27SZhang Rui goto err_dynamic_tables; 3671c8fce27SZhang Rui 3681c8fce27SZhang Rui do { 3691c8fce27SZhang Rui result = acpi_get_table_by_index(table_index, &table_header); 3701c8fce27SZhang Rui if (!result) { 3711c8fce27SZhang Rui table_index++; 3721c8fce27SZhang Rui table_attr = NULL; 3731c8fce27SZhang Rui table_attr = 3741c8fce27SZhang Rui kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL); 3751c8fce27SZhang Rui if (!table_attr) 3761c8fce27SZhang Rui return -ENOMEM; 3771c8fce27SZhang Rui 3781c8fce27SZhang Rui acpi_table_attr_init(table_attr, table_header); 3791c8fce27SZhang Rui result = 3801c8fce27SZhang Rui sysfs_create_bin_file(tables_kobj, 3811c8fce27SZhang Rui &table_attr->attr); 3821c8fce27SZhang Rui if (result) { 3831c8fce27SZhang Rui kfree(table_attr); 3841c8fce27SZhang Rui return result; 3851c8fce27SZhang Rui } else 3861c8fce27SZhang Rui list_add_tail(&table_attr->node, 3871c8fce27SZhang Rui &acpi_table_attr_list); 3881c8fce27SZhang Rui } 3891c8fce27SZhang Rui } while (!result); 3901c8fce27SZhang Rui kobject_uevent(tables_kobj, KOBJ_ADD); 3911c8fce27SZhang Rui kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); 3921c8fce27SZhang Rui result = acpi_install_table_handler(acpi_sysfs_table_handler, NULL); 3931c8fce27SZhang Rui 3941c8fce27SZhang Rui return result == AE_OK ? 0 : -EINVAL; 3951c8fce27SZhang Rui err_dynamic_tables: 3961c8fce27SZhang Rui kobject_put(tables_kobj); 3971c8fce27SZhang Rui err: 3981c8fce27SZhang Rui return -ENOMEM; 3991c8fce27SZhang Rui } 4001c8fce27SZhang Rui 4011c8fce27SZhang Rui /* 4021c8fce27SZhang Rui * Detailed ACPI IRQ counters: 4031c8fce27SZhang Rui * /sys/firmware/acpi/interrupts/ 4041c8fce27SZhang Rui */ 4051c8fce27SZhang Rui 4061c8fce27SZhang Rui u32 acpi_irq_handled; 4071c8fce27SZhang Rui u32 acpi_irq_not_handled; 4081c8fce27SZhang Rui 4091c8fce27SZhang Rui #define COUNT_GPE 0 4101c8fce27SZhang Rui #define COUNT_SCI 1 /* acpi_irq_handled */ 4111c8fce27SZhang Rui #define COUNT_SCI_NOT 2 /* acpi_irq_not_handled */ 4121c8fce27SZhang Rui #define COUNT_ERROR 3 /* other */ 4131c8fce27SZhang Rui #define NUM_COUNTERS_EXTRA 4 4141c8fce27SZhang Rui 4151c8fce27SZhang Rui struct event_counter { 4161c8fce27SZhang Rui u32 count; 4171c8fce27SZhang Rui u32 flags; 4181c8fce27SZhang Rui }; 4191c8fce27SZhang Rui 4201c8fce27SZhang Rui static struct event_counter *all_counters; 4211c8fce27SZhang Rui static u32 num_gpes; 4221c8fce27SZhang Rui static u32 num_counters; 4231c8fce27SZhang Rui static struct attribute **all_attrs; 4241c8fce27SZhang Rui static u32 acpi_gpe_count; 4251c8fce27SZhang Rui 4261c8fce27SZhang Rui static struct attribute_group interrupt_stats_attr_group = { 4271c8fce27SZhang Rui .name = "interrupts", 4281c8fce27SZhang Rui }; 4291c8fce27SZhang Rui 4301c8fce27SZhang Rui static struct kobj_attribute *counter_attrs; 4311c8fce27SZhang Rui 4321c8fce27SZhang Rui static void delete_gpe_attr_array(void) 4331c8fce27SZhang Rui { 4341c8fce27SZhang Rui struct event_counter *tmp = all_counters; 4351c8fce27SZhang Rui 4361c8fce27SZhang Rui all_counters = NULL; 4371c8fce27SZhang Rui kfree(tmp); 4381c8fce27SZhang Rui 4391c8fce27SZhang Rui if (counter_attrs) { 4401c8fce27SZhang Rui int i; 4411c8fce27SZhang Rui 4421c8fce27SZhang Rui for (i = 0; i < num_gpes; i++) 4431c8fce27SZhang Rui kfree(counter_attrs[i].attr.name); 4441c8fce27SZhang Rui 4451c8fce27SZhang Rui kfree(counter_attrs); 4461c8fce27SZhang Rui } 4471c8fce27SZhang Rui kfree(all_attrs); 4481c8fce27SZhang Rui 4491c8fce27SZhang Rui return; 4501c8fce27SZhang Rui } 4511c8fce27SZhang Rui 452a0fcdb23SLin Ming static void gpe_count(u32 gpe_number) 4531c8fce27SZhang Rui { 4541c8fce27SZhang Rui acpi_gpe_count++; 4551c8fce27SZhang Rui 4561c8fce27SZhang Rui if (!all_counters) 4571c8fce27SZhang Rui return; 4581c8fce27SZhang Rui 4591c8fce27SZhang Rui if (gpe_number < num_gpes) 4601c8fce27SZhang Rui all_counters[gpe_number].count++; 4611c8fce27SZhang Rui else 4621c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + 4631c8fce27SZhang Rui COUNT_ERROR].count++; 4641c8fce27SZhang Rui 4651c8fce27SZhang Rui return; 4661c8fce27SZhang Rui } 4671c8fce27SZhang Rui 468a0fcdb23SLin Ming static void fixed_event_count(u32 event_number) 4691c8fce27SZhang Rui { 4701c8fce27SZhang Rui if (!all_counters) 4711c8fce27SZhang Rui return; 4721c8fce27SZhang Rui 4731c8fce27SZhang Rui if (event_number < ACPI_NUM_FIXED_EVENTS) 4741c8fce27SZhang Rui all_counters[num_gpes + event_number].count++; 4751c8fce27SZhang Rui else 4761c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + 4771c8fce27SZhang Rui COUNT_ERROR].count++; 4781c8fce27SZhang Rui 4791c8fce27SZhang Rui return; 4801c8fce27SZhang Rui } 4811c8fce27SZhang Rui 482644ef74eSLv Zheng static void acpi_global_event_handler(u32 event_type, acpi_handle device, 483a0fcdb23SLin Ming u32 event_number, void *context) 484a0fcdb23SLin Ming { 485a0fcdb23SLin Ming if (event_type == ACPI_EVENT_TYPE_GPE) 486a0fcdb23SLin Ming gpe_count(event_number); 487a0fcdb23SLin Ming 488a0fcdb23SLin Ming if (event_type == ACPI_EVENT_TYPE_FIXED) 489a0fcdb23SLin Ming fixed_event_count(event_number); 490a0fcdb23SLin Ming } 491a0fcdb23SLin Ming 4921c8fce27SZhang Rui static int get_status(u32 index, acpi_event_status *status, 4931c8fce27SZhang Rui acpi_handle *handle) 4941c8fce27SZhang Rui { 4951c8fce27SZhang Rui int result = 0; 4961c8fce27SZhang Rui 4971c8fce27SZhang Rui if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) 4981c8fce27SZhang Rui goto end; 4991c8fce27SZhang Rui 5001c8fce27SZhang Rui if (index < num_gpes) { 5011c8fce27SZhang Rui result = acpi_get_gpe_device(index, handle); 5021c8fce27SZhang Rui if (result) { 5031c8fce27SZhang Rui ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND, 504c6284237SColin Ian King "Invalid GPE 0x%x", index)); 5051c8fce27SZhang Rui goto end; 5061c8fce27SZhang Rui } 5071c8fce27SZhang Rui result = acpi_get_gpe_status(*handle, index, status); 5081c8fce27SZhang Rui } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS)) 5091c8fce27SZhang Rui result = acpi_get_event_status(index - num_gpes, status); 5101c8fce27SZhang Rui 5111c8fce27SZhang Rui end: 5121c8fce27SZhang Rui return result; 5131c8fce27SZhang Rui } 5141c8fce27SZhang Rui 5151c8fce27SZhang Rui static ssize_t counter_show(struct kobject *kobj, 5161c8fce27SZhang Rui struct kobj_attribute *attr, char *buf) 5171c8fce27SZhang Rui { 5181c8fce27SZhang Rui int index = attr - counter_attrs; 5191c8fce27SZhang Rui int size; 5201c8fce27SZhang Rui acpi_handle handle; 5211c8fce27SZhang Rui acpi_event_status status; 5221c8fce27SZhang Rui int result = 0; 5231c8fce27SZhang Rui 5241c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI].count = 5251c8fce27SZhang Rui acpi_irq_handled; 5261c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT].count = 5271c8fce27SZhang Rui acpi_irq_not_handled; 5281c8fce27SZhang Rui all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count = 5291c8fce27SZhang Rui acpi_gpe_count; 5301c8fce27SZhang Rui size = sprintf(buf, "%8d", all_counters[index].count); 5311c8fce27SZhang Rui 5321c8fce27SZhang Rui /* "gpe_all" or "sci" */ 5331c8fce27SZhang Rui if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) 5341c8fce27SZhang Rui goto end; 5351c8fce27SZhang Rui 5361c8fce27SZhang Rui result = get_status(index, &status, &handle); 5371c8fce27SZhang Rui if (result) 5381c8fce27SZhang Rui goto end; 5391c8fce27SZhang Rui 5401c8fce27SZhang Rui if (!(status & ACPI_EVENT_FLAG_HANDLE)) 5411c8fce27SZhang Rui size += sprintf(buf + size, " invalid"); 5421c8fce27SZhang Rui else if (status & ACPI_EVENT_FLAG_ENABLED) 5431c8fce27SZhang Rui size += sprintf(buf + size, " enabled"); 5441c8fce27SZhang Rui else if (status & ACPI_EVENT_FLAG_WAKE_ENABLED) 5451c8fce27SZhang Rui size += sprintf(buf + size, " wake_enabled"); 5461c8fce27SZhang Rui else 5471c8fce27SZhang Rui size += sprintf(buf + size, " disabled"); 5481c8fce27SZhang Rui 5491c8fce27SZhang Rui end: 5501c8fce27SZhang Rui size += sprintf(buf + size, "\n"); 5511c8fce27SZhang Rui return result ? result : size; 5521c8fce27SZhang Rui } 5531c8fce27SZhang Rui 5541c8fce27SZhang Rui /* 5551c8fce27SZhang Rui * counter_set() sets the specified counter. 5561c8fce27SZhang Rui * setting the total "sci" file to any value clears all counters. 5571c8fce27SZhang Rui * enable/disable/clear a gpe/fixed event in user space. 5581c8fce27SZhang Rui */ 5591c8fce27SZhang Rui static ssize_t counter_set(struct kobject *kobj, 5601c8fce27SZhang Rui struct kobj_attribute *attr, const char *buf, 5611c8fce27SZhang Rui size_t size) 5621c8fce27SZhang Rui { 5631c8fce27SZhang Rui int index = attr - counter_attrs; 5641c8fce27SZhang Rui acpi_event_status status; 5651c8fce27SZhang Rui acpi_handle handle; 5661c8fce27SZhang Rui int result = 0; 5671c8fce27SZhang Rui 5681c8fce27SZhang Rui if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) { 5691c8fce27SZhang Rui int i; 5701c8fce27SZhang Rui for (i = 0; i < num_counters; ++i) 5711c8fce27SZhang Rui all_counters[i].count = 0; 5721c8fce27SZhang Rui acpi_gpe_count = 0; 5731c8fce27SZhang Rui acpi_irq_handled = 0; 5741c8fce27SZhang Rui acpi_irq_not_handled = 0; 5751c8fce27SZhang Rui goto end; 5761c8fce27SZhang Rui } 5771c8fce27SZhang Rui 5781c8fce27SZhang Rui /* show the event status for both GPEs and Fixed Events */ 5791c8fce27SZhang Rui result = get_status(index, &status, &handle); 5801c8fce27SZhang Rui if (result) 5811c8fce27SZhang Rui goto end; 5821c8fce27SZhang Rui 5831c8fce27SZhang Rui if (!(status & ACPI_EVENT_FLAG_HANDLE)) { 5841c8fce27SZhang Rui printk(KERN_WARNING PREFIX 5851c8fce27SZhang Rui "Can not change Invalid GPE/Fixed Event status\n"); 5861c8fce27SZhang Rui return -EINVAL; 5871c8fce27SZhang Rui } 5881c8fce27SZhang Rui 5891c8fce27SZhang Rui if (index < num_gpes) { 5901c8fce27SZhang Rui if (!strcmp(buf, "disable\n") && 5911c8fce27SZhang Rui (status & ACPI_EVENT_FLAG_ENABLED)) 5921c8fce27SZhang Rui result = acpi_disable_gpe(handle, index); 5931c8fce27SZhang Rui else if (!strcmp(buf, "enable\n") && 5941c8fce27SZhang Rui !(status & ACPI_EVENT_FLAG_ENABLED)) 5951c8fce27SZhang Rui result = acpi_enable_gpe(handle, index); 5961c8fce27SZhang Rui else if (!strcmp(buf, "clear\n") && 5971c8fce27SZhang Rui (status & ACPI_EVENT_FLAG_SET)) 5981c8fce27SZhang Rui result = acpi_clear_gpe(handle, index); 5991c8fce27SZhang Rui else 6001c8fce27SZhang Rui all_counters[index].count = strtoul(buf, NULL, 0); 6011c8fce27SZhang Rui } else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) { 6021c8fce27SZhang Rui int event = index - num_gpes; 6031c8fce27SZhang Rui if (!strcmp(buf, "disable\n") && 6041c8fce27SZhang Rui (status & ACPI_EVENT_FLAG_ENABLED)) 6051c8fce27SZhang Rui result = acpi_disable_event(event, ACPI_NOT_ISR); 6061c8fce27SZhang Rui else if (!strcmp(buf, "enable\n") && 6071c8fce27SZhang Rui !(status & ACPI_EVENT_FLAG_ENABLED)) 6081c8fce27SZhang Rui result = acpi_enable_event(event, ACPI_NOT_ISR); 6091c8fce27SZhang Rui else if (!strcmp(buf, "clear\n") && 6101c8fce27SZhang Rui (status & ACPI_EVENT_FLAG_SET)) 6111c8fce27SZhang Rui result = acpi_clear_event(event); 6121c8fce27SZhang Rui else 6131c8fce27SZhang Rui all_counters[index].count = strtoul(buf, NULL, 0); 6141c8fce27SZhang Rui } else 6151c8fce27SZhang Rui all_counters[index].count = strtoul(buf, NULL, 0); 6161c8fce27SZhang Rui 6171c8fce27SZhang Rui if (ACPI_FAILURE(result)) 6181c8fce27SZhang Rui result = -EINVAL; 6191c8fce27SZhang Rui end: 6201c8fce27SZhang Rui return result ? result : size; 6211c8fce27SZhang Rui } 6221c8fce27SZhang Rui 6231c8fce27SZhang Rui void acpi_irq_stats_init(void) 6241c8fce27SZhang Rui { 625a0fcdb23SLin Ming acpi_status status; 6261c8fce27SZhang Rui int i; 6271c8fce27SZhang Rui 6281c8fce27SZhang Rui if (all_counters) 6291c8fce27SZhang Rui return; 6301c8fce27SZhang Rui 6311c8fce27SZhang Rui num_gpes = acpi_current_gpe_count; 6321c8fce27SZhang Rui num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA; 6331c8fce27SZhang Rui 6341c8fce27SZhang Rui all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1), 6351c8fce27SZhang Rui GFP_KERNEL); 6361c8fce27SZhang Rui if (all_attrs == NULL) 6371c8fce27SZhang Rui return; 6381c8fce27SZhang Rui 6391c8fce27SZhang Rui all_counters = kzalloc(sizeof(struct event_counter) * (num_counters), 6401c8fce27SZhang Rui GFP_KERNEL); 6411c8fce27SZhang Rui if (all_counters == NULL) 6421c8fce27SZhang Rui goto fail; 6431c8fce27SZhang Rui 644644ef74eSLv Zheng status = acpi_install_global_event_handler(acpi_global_event_handler, NULL); 645a0fcdb23SLin Ming if (ACPI_FAILURE(status)) 646a0fcdb23SLin Ming goto fail; 647a0fcdb23SLin Ming 6481c8fce27SZhang Rui counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters), 6491c8fce27SZhang Rui GFP_KERNEL); 6501c8fce27SZhang Rui if (counter_attrs == NULL) 6511c8fce27SZhang Rui goto fail; 6521c8fce27SZhang Rui 6531c8fce27SZhang Rui for (i = 0; i < num_counters; ++i) { 6541c8fce27SZhang Rui char buffer[12]; 6551c8fce27SZhang Rui char *name; 6561c8fce27SZhang Rui 6571c8fce27SZhang Rui if (i < num_gpes) 6581c8fce27SZhang Rui sprintf(buffer, "gpe%02X", i); 6591c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_PMTIMER) 6601c8fce27SZhang Rui sprintf(buffer, "ff_pmtimer"); 6611c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_GLOBAL) 6621c8fce27SZhang Rui sprintf(buffer, "ff_gbl_lock"); 6631c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON) 6641c8fce27SZhang Rui sprintf(buffer, "ff_pwr_btn"); 6651c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON) 6661c8fce27SZhang Rui sprintf(buffer, "ff_slp_btn"); 6671c8fce27SZhang Rui else if (i == num_gpes + ACPI_EVENT_RTC) 6681c8fce27SZhang Rui sprintf(buffer, "ff_rt_clk"); 6691c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE) 6701c8fce27SZhang Rui sprintf(buffer, "gpe_all"); 6711c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) 6721c8fce27SZhang Rui sprintf(buffer, "sci"); 6731c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT) 6741c8fce27SZhang Rui sprintf(buffer, "sci_not"); 6751c8fce27SZhang Rui else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR) 6761c8fce27SZhang Rui sprintf(buffer, "error"); 6771c8fce27SZhang Rui else 6781c8fce27SZhang Rui sprintf(buffer, "bug%02X", i); 6791c8fce27SZhang Rui 6801c8fce27SZhang Rui name = kzalloc(strlen(buffer) + 1, GFP_KERNEL); 6811c8fce27SZhang Rui if (name == NULL) 6821c8fce27SZhang Rui goto fail; 6831c8fce27SZhang Rui strncpy(name, buffer, strlen(buffer) + 1); 6841c8fce27SZhang Rui 6851c8fce27SZhang Rui sysfs_attr_init(&counter_attrs[i].attr); 6861c8fce27SZhang Rui counter_attrs[i].attr.name = name; 6871c8fce27SZhang Rui counter_attrs[i].attr.mode = 0644; 6881c8fce27SZhang Rui counter_attrs[i].show = counter_show; 6891c8fce27SZhang Rui counter_attrs[i].store = counter_set; 6901c8fce27SZhang Rui 6911c8fce27SZhang Rui all_attrs[i] = &counter_attrs[i].attr; 6921c8fce27SZhang Rui } 6931c8fce27SZhang Rui 6941c8fce27SZhang Rui interrupt_stats_attr_group.attrs = all_attrs; 6951c8fce27SZhang Rui if (!sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group)) 6961c8fce27SZhang Rui return; 6971c8fce27SZhang Rui 6981c8fce27SZhang Rui fail: 6991c8fce27SZhang Rui delete_gpe_attr_array(); 7001c8fce27SZhang Rui return; 7011c8fce27SZhang Rui } 7021c8fce27SZhang Rui 7031c8fce27SZhang Rui static void __exit interrupt_stats_exit(void) 7041c8fce27SZhang Rui { 7051c8fce27SZhang Rui sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group); 7061c8fce27SZhang Rui 7071c8fce27SZhang Rui delete_gpe_attr_array(); 7081c8fce27SZhang Rui 7091c8fce27SZhang Rui return; 7101c8fce27SZhang Rui } 7111c8fce27SZhang Rui 712362b6460SThomas Renninger static ssize_t 713362b6460SThomas Renninger acpi_show_profile(struct device *dev, struct device_attribute *attr, 714362b6460SThomas Renninger char *buf) 715362b6460SThomas Renninger { 716362b6460SThomas Renninger return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile); 717362b6460SThomas Renninger } 718362b6460SThomas Renninger 719362b6460SThomas Renninger static const struct device_attribute pm_profile_attr = 720362b6460SThomas Renninger __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); 721362b6460SThomas Renninger 7223f8055c3SRafael J. Wysocki static ssize_t hotplug_enabled_show(struct kobject *kobj, 7233f8055c3SRafael J. Wysocki struct kobj_attribute *attr, char *buf) 7243f8055c3SRafael J. Wysocki { 7253f8055c3SRafael J. Wysocki struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj); 7263f8055c3SRafael J. Wysocki 7273f8055c3SRafael J. Wysocki return sprintf(buf, "%d\n", hotplug->enabled); 7283f8055c3SRafael J. Wysocki } 7293f8055c3SRafael J. Wysocki 7303f8055c3SRafael J. Wysocki static ssize_t hotplug_enabled_store(struct kobject *kobj, 7313f8055c3SRafael J. Wysocki struct kobj_attribute *attr, 7323f8055c3SRafael J. Wysocki const char *buf, size_t size) 7333f8055c3SRafael J. Wysocki { 7343f8055c3SRafael J. Wysocki struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj); 7353f8055c3SRafael J. Wysocki unsigned int val; 7363f8055c3SRafael J. Wysocki 7373f8055c3SRafael J. Wysocki if (kstrtouint(buf, 10, &val) || val > 1) 7383f8055c3SRafael J. Wysocki return -EINVAL; 7393f8055c3SRafael J. Wysocki 7403f8055c3SRafael J. Wysocki acpi_scan_hotplug_enabled(hotplug, val); 7413f8055c3SRafael J. Wysocki return size; 7423f8055c3SRafael J. Wysocki } 7433f8055c3SRafael J. Wysocki 7443f8055c3SRafael J. Wysocki static struct kobj_attribute hotplug_enabled_attr = 7453f8055c3SRafael J. Wysocki __ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show, 7463f8055c3SRafael J. Wysocki hotplug_enabled_store); 7473f8055c3SRafael J. Wysocki 7483f8055c3SRafael J. Wysocki static struct attribute *hotplug_profile_attrs[] = { 7493f8055c3SRafael J. Wysocki &hotplug_enabled_attr.attr, 7503f8055c3SRafael J. Wysocki NULL 7513f8055c3SRafael J. Wysocki }; 7523f8055c3SRafael J. Wysocki 753b09753ecSRafael J. Wysocki static struct kobj_type acpi_hotplug_profile_ktype = { 7543f8055c3SRafael J. Wysocki .sysfs_ops = &kobj_sysfs_ops, 7553f8055c3SRafael J. Wysocki .default_attrs = hotplug_profile_attrs, 7563f8055c3SRafael J. Wysocki }; 7573f8055c3SRafael J. Wysocki 7583f8055c3SRafael J. Wysocki void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, 7593f8055c3SRafael J. Wysocki const char *name) 7603f8055c3SRafael J. Wysocki { 7613f8055c3SRafael J. Wysocki int error; 7623f8055c3SRafael J. Wysocki 7633f8055c3SRafael J. Wysocki if (!hotplug_kobj) 7643f8055c3SRafael J. Wysocki goto err_out; 7653f8055c3SRafael J. Wysocki 7663f8055c3SRafael J. Wysocki kobject_init(&hotplug->kobj, &acpi_hotplug_profile_ktype); 7673f8055c3SRafael J. Wysocki error = kobject_set_name(&hotplug->kobj, "%s", name); 7683f8055c3SRafael J. Wysocki if (error) 7693f8055c3SRafael J. Wysocki goto err_out; 7703f8055c3SRafael J. Wysocki 7713f8055c3SRafael J. Wysocki hotplug->kobj.parent = hotplug_kobj; 7723f8055c3SRafael J. Wysocki error = kobject_add(&hotplug->kobj, hotplug_kobj, NULL); 7733f8055c3SRafael J. Wysocki if (error) 7743f8055c3SRafael J. Wysocki goto err_out; 7753f8055c3SRafael J. Wysocki 7763f8055c3SRafael J. Wysocki kobject_uevent(&hotplug->kobj, KOBJ_ADD); 7773f8055c3SRafael J. Wysocki return; 7783f8055c3SRafael J. Wysocki 7793f8055c3SRafael J. Wysocki err_out: 7803f8055c3SRafael J. Wysocki pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name); 7813f8055c3SRafael J. Wysocki } 7823f8055c3SRafael J. Wysocki 7831c8fce27SZhang Rui int __init acpi_sysfs_init(void) 7841c8fce27SZhang Rui { 7851c8fce27SZhang Rui int result; 7861c8fce27SZhang Rui 7871c8fce27SZhang Rui result = acpi_tables_sysfs_init(); 788362b6460SThomas Renninger if (result) 789362b6460SThomas Renninger return result; 7903f8055c3SRafael J. Wysocki 7913f8055c3SRafael J. Wysocki hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj); 792362b6460SThomas Renninger result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); 7931c8fce27SZhang Rui return result; 7941c8fce27SZhang Rui } 795