1/* 2 * sysfs.c - ACPI sysfs interface to userspace. 3 */ 4 5#include <linux/init.h> 6#include <linux/kernel.h> 7#include <linux/moduleparam.h> 8#include <linux/acpi.h> 9 10#include "internal.h" 11 12#define _COMPONENT ACPI_SYSTEM_COMPONENT 13ACPI_MODULE_NAME("sysfs"); 14 15#ifdef CONFIG_ACPI_DEBUG 16/* 17 * ACPI debug sysfs I/F, including: 18 * /sys/modules/acpi/parameters/debug_layer 19 * /sys/modules/acpi/parameters/debug_level 20 * /sys/modules/acpi/parameters/trace_method_name 21 * /sys/modules/acpi/parameters/trace_state 22 * /sys/modules/acpi/parameters/trace_debug_layer 23 * /sys/modules/acpi/parameters/trace_debug_level 24 */ 25 26struct acpi_dlayer { 27 const char *name; 28 unsigned long value; 29}; 30struct acpi_dlevel { 31 const char *name; 32 unsigned long value; 33}; 34#define ACPI_DEBUG_INIT(v) { .name = #v, .value = v } 35 36static const struct acpi_dlayer acpi_debug_layers[] = { 37 ACPI_DEBUG_INIT(ACPI_UTILITIES), 38 ACPI_DEBUG_INIT(ACPI_HARDWARE), 39 ACPI_DEBUG_INIT(ACPI_EVENTS), 40 ACPI_DEBUG_INIT(ACPI_TABLES), 41 ACPI_DEBUG_INIT(ACPI_NAMESPACE), 42 ACPI_DEBUG_INIT(ACPI_PARSER), 43 ACPI_DEBUG_INIT(ACPI_DISPATCHER), 44 ACPI_DEBUG_INIT(ACPI_EXECUTER), 45 ACPI_DEBUG_INIT(ACPI_RESOURCES), 46 ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER), 47 ACPI_DEBUG_INIT(ACPI_OS_SERVICES), 48 ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER), 49 ACPI_DEBUG_INIT(ACPI_COMPILER), 50 ACPI_DEBUG_INIT(ACPI_TOOLS), 51 52 ACPI_DEBUG_INIT(ACPI_BUS_COMPONENT), 53 ACPI_DEBUG_INIT(ACPI_AC_COMPONENT), 54 ACPI_DEBUG_INIT(ACPI_BATTERY_COMPONENT), 55 ACPI_DEBUG_INIT(ACPI_BUTTON_COMPONENT), 56 ACPI_DEBUG_INIT(ACPI_SBS_COMPONENT), 57 ACPI_DEBUG_INIT(ACPI_FAN_COMPONENT), 58 ACPI_DEBUG_INIT(ACPI_PCI_COMPONENT), 59 ACPI_DEBUG_INIT(ACPI_POWER_COMPONENT), 60 ACPI_DEBUG_INIT(ACPI_CONTAINER_COMPONENT), 61 ACPI_DEBUG_INIT(ACPI_SYSTEM_COMPONENT), 62 ACPI_DEBUG_INIT(ACPI_THERMAL_COMPONENT), 63 ACPI_DEBUG_INIT(ACPI_MEMORY_DEVICE_COMPONENT), 64 ACPI_DEBUG_INIT(ACPI_VIDEO_COMPONENT), 65 ACPI_DEBUG_INIT(ACPI_PROCESSOR_COMPONENT), 66}; 67 68static const struct acpi_dlevel acpi_debug_levels[] = { 69 ACPI_DEBUG_INIT(ACPI_LV_INIT), 70 ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT), 71 ACPI_DEBUG_INIT(ACPI_LV_INFO), 72 73 ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES), 74 ACPI_DEBUG_INIT(ACPI_LV_PARSE), 75 ACPI_DEBUG_INIT(ACPI_LV_LOAD), 76 ACPI_DEBUG_INIT(ACPI_LV_DISPATCH), 77 ACPI_DEBUG_INIT(ACPI_LV_EXEC), 78 ACPI_DEBUG_INIT(ACPI_LV_NAMES), 79 ACPI_DEBUG_INIT(ACPI_LV_OPREGION), 80 ACPI_DEBUG_INIT(ACPI_LV_BFIELD), 81 ACPI_DEBUG_INIT(ACPI_LV_TABLES), 82 ACPI_DEBUG_INIT(ACPI_LV_VALUES), 83 ACPI_DEBUG_INIT(ACPI_LV_OBJECTS), 84 ACPI_DEBUG_INIT(ACPI_LV_RESOURCES), 85 ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS), 86 ACPI_DEBUG_INIT(ACPI_LV_PACKAGE), 87 88 ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS), 89 ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS), 90 ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS), 91 92 ACPI_DEBUG_INIT(ACPI_LV_MUTEX), 93 ACPI_DEBUG_INIT(ACPI_LV_THREADS), 94 ACPI_DEBUG_INIT(ACPI_LV_IO), 95 ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS), 96 97 ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE), 98 ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO), 99 ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES), 100 ACPI_DEBUG_INIT(ACPI_LV_EVENTS), 101}; 102 103static int param_get_debug_layer(char *buffer, const struct kernel_param *kp) 104{ 105 int result = 0; 106 int i; 107 108 result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); 109 110 for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) { 111 result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n", 112 acpi_debug_layers[i].name, 113 acpi_debug_layers[i].value, 114 (acpi_dbg_layer & acpi_debug_layers[i].value) 115 ? '*' : ' '); 116 } 117 result += 118 sprintf(buffer + result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS", 119 ACPI_ALL_DRIVERS, 120 (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 121 ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS) 122 == 0 ? ' ' : '-'); 123 result += 124 sprintf(buffer + result, 125 "--\ndebug_layer = 0x%08X ( * = enabled)\n", 126 acpi_dbg_layer); 127 128 return result; 129} 130 131static int param_get_debug_level(char *buffer, const struct kernel_param *kp) 132{ 133 int result = 0; 134 int i; 135 136 result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); 137 138 for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) { 139 result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n", 140 acpi_debug_levels[i].name, 141 acpi_debug_levels[i].value, 142 (acpi_dbg_level & acpi_debug_levels[i].value) 143 ? '*' : ' '); 144 } 145 result += 146 sprintf(buffer + result, "--\ndebug_level = 0x%08X (* = enabled)\n", 147 acpi_dbg_level); 148 149 return result; 150} 151 152static const struct kernel_param_ops param_ops_debug_layer = { 153 .set = param_set_uint, 154 .get = param_get_debug_layer, 155}; 156 157static const struct kernel_param_ops param_ops_debug_level = { 158 .set = param_set_uint, 159 .get = param_get_debug_level, 160}; 161 162module_param_cb(debug_layer, ¶m_ops_debug_layer, &acpi_dbg_layer, 0644); 163module_param_cb(debug_level, ¶m_ops_debug_level, &acpi_dbg_level, 0644); 164 165static char trace_method_name[6]; 166module_param_string(trace_method_name, trace_method_name, 6, 0644); 167static unsigned int trace_debug_layer; 168module_param(trace_debug_layer, uint, 0644); 169static unsigned int trace_debug_level; 170module_param(trace_debug_level, uint, 0644); 171 172static int param_set_trace_state(const char *val, struct kernel_param *kp) 173{ 174 int result = 0; 175 176 if (!strncmp(val, "enable", sizeof("enable") - 1)) { 177 result = acpi_debug_trace(trace_method_name, trace_debug_level, 178 trace_debug_layer, 0); 179 if (result) 180 result = -EBUSY; 181 goto exit; 182 } 183 184 if (!strncmp(val, "disable", sizeof("disable") - 1)) { 185 int name = 0; 186 result = acpi_debug_trace((char *)&name, trace_debug_level, 187 trace_debug_layer, 0); 188 if (result) 189 result = -EBUSY; 190 goto exit; 191 } 192 193 if (!strncmp(val, "1", 1)) { 194 result = acpi_debug_trace(trace_method_name, trace_debug_level, 195 trace_debug_layer, 1); 196 if (result) 197 result = -EBUSY; 198 goto exit; 199 } 200 201 result = -EINVAL; 202exit: 203 return result; 204} 205 206static int param_get_trace_state(char *buffer, struct kernel_param *kp) 207{ 208 if (!acpi_gbl_trace_method_name) 209 return sprintf(buffer, "disable"); 210 else { 211 if (acpi_gbl_trace_flags & 1) 212 return sprintf(buffer, "1"); 213 else 214 return sprintf(buffer, "enable"); 215 } 216 return 0; 217} 218 219module_param_call(trace_state, param_set_trace_state, param_get_trace_state, 220 NULL, 0644); 221#endif /* CONFIG_ACPI_DEBUG */ 222 223 224/* /sys/modules/acpi/parameters/aml_debug_output */ 225 226module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object, 227 byte, 0644); 228MODULE_PARM_DESC(aml_debug_output, 229 "To enable/disable the ACPI Debug Object output."); 230 231/* /sys/module/acpi/parameters/acpica_version */ 232static int param_get_acpica_version(char *buffer, struct kernel_param *kp) 233{ 234 int result; 235 236 result = sprintf(buffer, "%x", ACPI_CA_VERSION); 237 238 return result; 239} 240 241module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); 242 243/* 244 * ACPI table sysfs I/F: 245 * /sys/firmware/acpi/tables/ 246 * /sys/firmware/acpi/tables/dynamic/ 247 */ 248 249static LIST_HEAD(acpi_table_attr_list); 250static struct kobject *tables_kobj; 251static struct kobject *dynamic_tables_kobj; 252static struct kobject *hotplug_kobj; 253 254struct acpi_table_attr { 255 struct bin_attribute attr; 256 char name[8]; 257 int instance; 258 struct list_head node; 259}; 260 261static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj, 262 struct bin_attribute *bin_attr, char *buf, 263 loff_t offset, size_t count) 264{ 265 struct acpi_table_attr *table_attr = 266 container_of(bin_attr, struct acpi_table_attr, attr); 267 struct acpi_table_header *table_header = NULL; 268 acpi_status status; 269 char name[ACPI_NAME_SIZE]; 270 271 if (strncmp(table_attr->name, "NULL", 4)) 272 memcpy(name, table_attr->name, ACPI_NAME_SIZE); 273 else 274 memcpy(name, "\0\0\0\0", 4); 275 276 status = acpi_get_table(name, table_attr->instance, &table_header); 277 if (ACPI_FAILURE(status)) 278 return -ENODEV; 279 280 return memory_read_from_buffer(buf, count, &offset, 281 table_header, table_header->length); 282} 283 284static void acpi_table_attr_init(struct acpi_table_attr *table_attr, 285 struct acpi_table_header *table_header) 286{ 287 struct acpi_table_header *header = NULL; 288 struct acpi_table_attr *attr = NULL; 289 290 sysfs_attr_init(&table_attr->attr.attr); 291 if (table_header->signature[0] != '\0') 292 memcpy(table_attr->name, table_header->signature, 293 ACPI_NAME_SIZE); 294 else 295 memcpy(table_attr->name, "NULL", 4); 296 297 list_for_each_entry(attr, &acpi_table_attr_list, node) { 298 if (!memcmp(table_attr->name, attr->name, ACPI_NAME_SIZE)) 299 if (table_attr->instance < attr->instance) 300 table_attr->instance = attr->instance; 301 } 302 table_attr->instance++; 303 304 if (table_attr->instance > 1 || (table_attr->instance == 1 && 305 !acpi_get_table 306 (table_header->signature, 2, &header))) 307 sprintf(table_attr->name + ACPI_NAME_SIZE, "%d", 308 table_attr->instance); 309 310 table_attr->attr.size = table_header->length; 311 table_attr->attr.read = acpi_table_show; 312 table_attr->attr.attr.name = table_attr->name; 313 table_attr->attr.attr.mode = 0400; 314 315 return; 316} 317 318static acpi_status 319acpi_sysfs_table_handler(u32 event, void *table, void *context) 320{ 321 struct acpi_table_attr *table_attr; 322 323 switch (event) { 324 case ACPI_TABLE_EVENT_LOAD: 325 table_attr = 326 kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL); 327 if (!table_attr) 328 return AE_NO_MEMORY; 329 330 acpi_table_attr_init(table_attr, table); 331 if (sysfs_create_bin_file(dynamic_tables_kobj, 332 &table_attr->attr)) { 333 kfree(table_attr); 334 return AE_ERROR; 335 } else 336 list_add_tail(&table_attr->node, &acpi_table_attr_list); 337 break; 338 case ACPI_TABLE_EVENT_UNLOAD: 339 /* 340 * we do not need to do anything right now 341 * because the table is not deleted from the 342 * global table list when unloading it. 343 */ 344 break; 345 default: 346 return AE_BAD_PARAMETER; 347 } 348 return AE_OK; 349} 350 351static int acpi_tables_sysfs_init(void) 352{ 353 struct acpi_table_attr *table_attr; 354 struct acpi_table_header *table_header = NULL; 355 int table_index; 356 acpi_status status; 357 int ret; 358 359 tables_kobj = kobject_create_and_add("tables", acpi_kobj); 360 if (!tables_kobj) 361 goto err; 362 363 dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj); 364 if (!dynamic_tables_kobj) 365 goto err_dynamic_tables; 366 367 for (table_index = 0;; table_index++) { 368 status = acpi_get_table_by_index(table_index, &table_header); 369 370 if (status == AE_BAD_PARAMETER) 371 break; 372 373 if (ACPI_FAILURE(status)) 374 continue; 375 376 table_attr = NULL; 377 table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL); 378 if (!table_attr) 379 return -ENOMEM; 380 381 acpi_table_attr_init(table_attr, table_header); 382 ret = sysfs_create_bin_file(tables_kobj, &table_attr->attr); 383 if (ret) { 384 kfree(table_attr); 385 return ret; 386 } 387 list_add_tail(&table_attr->node, &acpi_table_attr_list); 388 } 389 390 kobject_uevent(tables_kobj, KOBJ_ADD); 391 kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); 392 status = acpi_install_table_handler(acpi_sysfs_table_handler, NULL); 393 394 return ACPI_FAILURE(status) ? -EINVAL : 0; 395err_dynamic_tables: 396 kobject_put(tables_kobj); 397err: 398 return -ENOMEM; 399} 400 401/* 402 * Detailed ACPI IRQ counters: 403 * /sys/firmware/acpi/interrupts/ 404 */ 405 406u32 acpi_irq_handled; 407u32 acpi_irq_not_handled; 408 409#define COUNT_GPE 0 410#define COUNT_SCI 1 /* acpi_irq_handled */ 411#define COUNT_SCI_NOT 2 /* acpi_irq_not_handled */ 412#define COUNT_ERROR 3 /* other */ 413#define NUM_COUNTERS_EXTRA 4 414 415struct event_counter { 416 u32 count; 417 u32 flags; 418}; 419 420static struct event_counter *all_counters; 421static u32 num_gpes; 422static u32 num_counters; 423static struct attribute **all_attrs; 424static u32 acpi_gpe_count; 425 426static struct attribute_group interrupt_stats_attr_group = { 427 .name = "interrupts", 428}; 429 430static struct kobj_attribute *counter_attrs; 431 432static void delete_gpe_attr_array(void) 433{ 434 struct event_counter *tmp = all_counters; 435 436 all_counters = NULL; 437 kfree(tmp); 438 439 if (counter_attrs) { 440 int i; 441 442 for (i = 0; i < num_gpes; i++) 443 kfree(counter_attrs[i].attr.name); 444 445 kfree(counter_attrs); 446 } 447 kfree(all_attrs); 448 449 return; 450} 451 452static void gpe_count(u32 gpe_number) 453{ 454 acpi_gpe_count++; 455 456 if (!all_counters) 457 return; 458 459 if (gpe_number < num_gpes) 460 all_counters[gpe_number].count++; 461 else 462 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + 463 COUNT_ERROR].count++; 464 465 return; 466} 467 468static void fixed_event_count(u32 event_number) 469{ 470 if (!all_counters) 471 return; 472 473 if (event_number < ACPI_NUM_FIXED_EVENTS) 474 all_counters[num_gpes + event_number].count++; 475 else 476 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + 477 COUNT_ERROR].count++; 478 479 return; 480} 481 482static void acpi_global_event_handler(u32 event_type, acpi_handle device, 483 u32 event_number, void *context) 484{ 485 if (event_type == ACPI_EVENT_TYPE_GPE) 486 gpe_count(event_number); 487 488 if (event_type == ACPI_EVENT_TYPE_FIXED) 489 fixed_event_count(event_number); 490} 491 492static int get_status(u32 index, acpi_event_status *status, 493 acpi_handle *handle) 494{ 495 int result = 0; 496 497 if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) 498 goto end; 499 500 if (index < num_gpes) { 501 result = acpi_get_gpe_device(index, handle); 502 if (result) { 503 ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND, 504 "Invalid GPE 0x%x", index)); 505 goto end; 506 } 507 result = acpi_get_gpe_status(*handle, index, status); 508 } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS)) 509 result = acpi_get_event_status(index - num_gpes, status); 510 511end: 512 return result; 513} 514 515static ssize_t counter_show(struct kobject *kobj, 516 struct kobj_attribute *attr, char *buf) 517{ 518 int index = attr - counter_attrs; 519 int size; 520 acpi_handle handle; 521 acpi_event_status status; 522 int result = 0; 523 524 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI].count = 525 acpi_irq_handled; 526 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT].count = 527 acpi_irq_not_handled; 528 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count = 529 acpi_gpe_count; 530 size = sprintf(buf, "%8u", all_counters[index].count); 531 532 /* "gpe_all" or "sci" */ 533 if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS) 534 goto end; 535 536 result = get_status(index, &status, &handle); 537 if (result) 538 goto end; 539 540 if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) 541 size += sprintf(buf + size, " invalid"); 542 else if (status & ACPI_EVENT_FLAG_ENABLED) 543 size += sprintf(buf + size, " enabled"); 544 else if (status & ACPI_EVENT_FLAG_WAKE_ENABLED) 545 size += sprintf(buf + size, " wake_enabled"); 546 else 547 size += sprintf(buf + size, " disabled"); 548 549end: 550 size += sprintf(buf + size, "\n"); 551 return result ? result : size; 552} 553 554/* 555 * counter_set() sets the specified counter. 556 * setting the total "sci" file to any value clears all counters. 557 * enable/disable/clear a gpe/fixed event in user space. 558 */ 559static ssize_t counter_set(struct kobject *kobj, 560 struct kobj_attribute *attr, const char *buf, 561 size_t size) 562{ 563 int index = attr - counter_attrs; 564 acpi_event_status status; 565 acpi_handle handle; 566 int result = 0; 567 unsigned long tmp; 568 569 if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) { 570 int i; 571 for (i = 0; i < num_counters; ++i) 572 all_counters[i].count = 0; 573 acpi_gpe_count = 0; 574 acpi_irq_handled = 0; 575 acpi_irq_not_handled = 0; 576 goto end; 577 } 578 579 /* show the event status for both GPEs and Fixed Events */ 580 result = get_status(index, &status, &handle); 581 if (result) 582 goto end; 583 584 if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) { 585 printk(KERN_WARNING PREFIX 586 "Can not change Invalid GPE/Fixed Event status\n"); 587 return -EINVAL; 588 } 589 590 if (index < num_gpes) { 591 if (!strcmp(buf, "disable\n") && 592 (status & ACPI_EVENT_FLAG_ENABLED)) 593 result = acpi_disable_gpe(handle, index); 594 else if (!strcmp(buf, "enable\n") && 595 !(status & ACPI_EVENT_FLAG_ENABLED)) 596 result = acpi_enable_gpe(handle, index); 597 else if (!strcmp(buf, "clear\n") && 598 (status & ACPI_EVENT_FLAG_SET)) 599 result = acpi_clear_gpe(handle, index); 600 else if (!kstrtoul(buf, 0, &tmp)) 601 all_counters[index].count = tmp; 602 else 603 result = -EINVAL; 604 } else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) { 605 int event = index - num_gpes; 606 if (!strcmp(buf, "disable\n") && 607 (status & ACPI_EVENT_FLAG_ENABLED)) 608 result = acpi_disable_event(event, ACPI_NOT_ISR); 609 else if (!strcmp(buf, "enable\n") && 610 !(status & ACPI_EVENT_FLAG_ENABLED)) 611 result = acpi_enable_event(event, ACPI_NOT_ISR); 612 else if (!strcmp(buf, "clear\n") && 613 (status & ACPI_EVENT_FLAG_SET)) 614 result = acpi_clear_event(event); 615 else if (!kstrtoul(buf, 0, &tmp)) 616 all_counters[index].count = tmp; 617 else 618 result = -EINVAL; 619 } else 620 all_counters[index].count = strtoul(buf, NULL, 0); 621 622 if (ACPI_FAILURE(result)) 623 result = -EINVAL; 624end: 625 return result ? result : size; 626} 627 628void acpi_irq_stats_init(void) 629{ 630 acpi_status status; 631 int i; 632 633 if (all_counters) 634 return; 635 636 num_gpes = acpi_current_gpe_count; 637 num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA; 638 639 all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1), 640 GFP_KERNEL); 641 if (all_attrs == NULL) 642 return; 643 644 all_counters = kzalloc(sizeof(struct event_counter) * (num_counters), 645 GFP_KERNEL); 646 if (all_counters == NULL) 647 goto fail; 648 649 status = acpi_install_global_event_handler(acpi_global_event_handler, NULL); 650 if (ACPI_FAILURE(status)) 651 goto fail; 652 653 counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters), 654 GFP_KERNEL); 655 if (counter_attrs == NULL) 656 goto fail; 657 658 for (i = 0; i < num_counters; ++i) { 659 char buffer[12]; 660 char *name; 661 662 if (i < num_gpes) 663 sprintf(buffer, "gpe%02X", i); 664 else if (i == num_gpes + ACPI_EVENT_PMTIMER) 665 sprintf(buffer, "ff_pmtimer"); 666 else if (i == num_gpes + ACPI_EVENT_GLOBAL) 667 sprintf(buffer, "ff_gbl_lock"); 668 else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON) 669 sprintf(buffer, "ff_pwr_btn"); 670 else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON) 671 sprintf(buffer, "ff_slp_btn"); 672 else if (i == num_gpes + ACPI_EVENT_RTC) 673 sprintf(buffer, "ff_rt_clk"); 674 else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE) 675 sprintf(buffer, "gpe_all"); 676 else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) 677 sprintf(buffer, "sci"); 678 else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI_NOT) 679 sprintf(buffer, "sci_not"); 680 else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR) 681 sprintf(buffer, "error"); 682 else 683 sprintf(buffer, "bug%02X", i); 684 685 name = kstrdup(buffer, GFP_KERNEL); 686 if (name == NULL) 687 goto fail; 688 689 sysfs_attr_init(&counter_attrs[i].attr); 690 counter_attrs[i].attr.name = name; 691 counter_attrs[i].attr.mode = 0644; 692 counter_attrs[i].show = counter_show; 693 counter_attrs[i].store = counter_set; 694 695 all_attrs[i] = &counter_attrs[i].attr; 696 } 697 698 interrupt_stats_attr_group.attrs = all_attrs; 699 if (!sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group)) 700 return; 701 702fail: 703 delete_gpe_attr_array(); 704 return; 705} 706 707static void __exit interrupt_stats_exit(void) 708{ 709 sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group); 710 711 delete_gpe_attr_array(); 712 713 return; 714} 715 716static ssize_t 717acpi_show_profile(struct device *dev, struct device_attribute *attr, 718 char *buf) 719{ 720 return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile); 721} 722 723static const struct device_attribute pm_profile_attr = 724 __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); 725 726static ssize_t hotplug_enabled_show(struct kobject *kobj, 727 struct kobj_attribute *attr, char *buf) 728{ 729 struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj); 730 731 return sprintf(buf, "%d\n", hotplug->enabled); 732} 733 734static ssize_t hotplug_enabled_store(struct kobject *kobj, 735 struct kobj_attribute *attr, 736 const char *buf, size_t size) 737{ 738 struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj); 739 unsigned int val; 740 741 if (kstrtouint(buf, 10, &val) || val > 1) 742 return -EINVAL; 743 744 acpi_scan_hotplug_enabled(hotplug, val); 745 return size; 746} 747 748static struct kobj_attribute hotplug_enabled_attr = 749 __ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show, 750 hotplug_enabled_store); 751 752static struct attribute *hotplug_profile_attrs[] = { 753 &hotplug_enabled_attr.attr, 754 NULL 755}; 756 757static struct kobj_type acpi_hotplug_profile_ktype = { 758 .sysfs_ops = &kobj_sysfs_ops, 759 .default_attrs = hotplug_profile_attrs, 760}; 761 762void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, 763 const char *name) 764{ 765 int error; 766 767 if (!hotplug_kobj) 768 goto err_out; 769 770 error = kobject_init_and_add(&hotplug->kobj, 771 &acpi_hotplug_profile_ktype, hotplug_kobj, "%s", name); 772 if (error) 773 goto err_out; 774 775 kobject_uevent(&hotplug->kobj, KOBJ_ADD); 776 return; 777 778 err_out: 779 pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name); 780} 781 782static ssize_t force_remove_show(struct kobject *kobj, 783 struct kobj_attribute *attr, char *buf) 784{ 785 return sprintf(buf, "%d\n", !!acpi_force_hot_remove); 786} 787 788static ssize_t force_remove_store(struct kobject *kobj, 789 struct kobj_attribute *attr, 790 const char *buf, size_t size) 791{ 792 bool val; 793 int ret; 794 795 ret = strtobool(buf, &val); 796 if (ret < 0) 797 return ret; 798 799 lock_device_hotplug(); 800 acpi_force_hot_remove = val; 801 unlock_device_hotplug(); 802 return size; 803} 804 805static const struct kobj_attribute force_remove_attr = 806 __ATTR(force_remove, S_IRUGO | S_IWUSR, force_remove_show, 807 force_remove_store); 808 809int __init acpi_sysfs_init(void) 810{ 811 int result; 812 813 result = acpi_tables_sysfs_init(); 814 if (result) 815 return result; 816 817 hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj); 818 result = sysfs_create_file(hotplug_kobj, &force_remove_attr.attr); 819 if (result) 820 return result; 821 822 result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); 823 return result; 824} 825