diff options
Diffstat (limited to 'drivers/acpi/sysfs.c')
-rw-r--r-- | drivers/acpi/sysfs.c | 91 |
1 files changed, 88 insertions, 3 deletions
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index e414fabf7315..78a5a23010ab 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c | |||
@@ -2,6 +2,8 @@ | |||
2 | * sysfs.c - ACPI sysfs interface to userspace. | 2 | * sysfs.c - ACPI sysfs interface to userspace. |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #define pr_fmt(fmt) "ACPI: " fmt | ||
6 | |||
5 | #include <linux/init.h> | 7 | #include <linux/init.h> |
6 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
7 | #include <linux/moduleparam.h> | 9 | #include <linux/moduleparam.h> |
@@ -306,11 +308,13 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); | |||
306 | /* | 308 | /* |
307 | * ACPI table sysfs I/F: | 309 | * ACPI table sysfs I/F: |
308 | * /sys/firmware/acpi/tables/ | 310 | * /sys/firmware/acpi/tables/ |
311 | * /sys/firmware/acpi/tables/data/ | ||
309 | * /sys/firmware/acpi/tables/dynamic/ | 312 | * /sys/firmware/acpi/tables/dynamic/ |
310 | */ | 313 | */ |
311 | 314 | ||
312 | static LIST_HEAD(acpi_table_attr_list); | 315 | static LIST_HEAD(acpi_table_attr_list); |
313 | static struct kobject *tables_kobj; | 316 | static struct kobject *tables_kobj; |
317 | static struct kobject *tables_data_kobj; | ||
314 | static struct kobject *dynamic_tables_kobj; | 318 | static struct kobject *dynamic_tables_kobj; |
315 | static struct kobject *hotplug_kobj; | 319 | static struct kobject *hotplug_kobj; |
316 | 320 | ||
@@ -325,6 +329,11 @@ struct acpi_table_attr { | |||
325 | struct list_head node; | 329 | struct list_head node; |
326 | }; | 330 | }; |
327 | 331 | ||
332 | struct acpi_data_attr { | ||
333 | struct bin_attribute attr; | ||
334 | u64 addr; | ||
335 | }; | ||
336 | |||
328 | static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj, | 337 | static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj, |
329 | struct bin_attribute *bin_attr, char *buf, | 338 | struct bin_attribute *bin_attr, char *buf, |
330 | loff_t offset, size_t count) | 339 | loff_t offset, size_t count) |
@@ -420,6 +429,70 @@ acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context) | |||
420 | return AE_OK; | 429 | return AE_OK; |
421 | } | 430 | } |
422 | 431 | ||
432 | static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj, | ||
433 | struct bin_attribute *bin_attr, char *buf, | ||
434 | loff_t offset, size_t count) | ||
435 | { | ||
436 | struct acpi_data_attr *data_attr; | ||
437 | void __iomem *base; | ||
438 | ssize_t rc; | ||
439 | |||
440 | data_attr = container_of(bin_attr, struct acpi_data_attr, attr); | ||
441 | |||
442 | base = acpi_os_map_memory(data_attr->addr, data_attr->attr.size); | ||
443 | if (!base) | ||
444 | return -ENOMEM; | ||
445 | rc = memory_read_from_buffer(buf, count, &offset, base, | ||
446 | data_attr->attr.size); | ||
447 | acpi_os_unmap_memory(base, data_attr->attr.size); | ||
448 | |||
449 | return rc; | ||
450 | } | ||
451 | |||
452 | static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr) | ||
453 | { | ||
454 | struct acpi_table_bert *bert = th; | ||
455 | |||
456 | if (bert->header.length < sizeof(struct acpi_table_bert) || | ||
457 | bert->region_length < sizeof(struct acpi_hest_generic_status)) { | ||
458 | kfree(data_attr); | ||
459 | return -EINVAL; | ||
460 | } | ||
461 | data_attr->addr = bert->address; | ||
462 | data_attr->attr.size = bert->region_length; | ||
463 | data_attr->attr.attr.name = "BERT"; | ||
464 | |||
465 | return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr); | ||
466 | } | ||
467 | |||
468 | static struct acpi_data_obj { | ||
469 | char *name; | ||
470 | int (*fn)(void *, struct acpi_data_attr *); | ||
471 | } acpi_data_objs[] = { | ||
472 | { ACPI_SIG_BERT, acpi_bert_data_init }, | ||
473 | }; | ||
474 | |||
475 | #define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs) | ||
476 | |||
477 | static int acpi_table_data_init(struct acpi_table_header *th) | ||
478 | { | ||
479 | struct acpi_data_attr *data_attr; | ||
480 | int i; | ||
481 | |||
482 | for (i = 0; i < NUM_ACPI_DATA_OBJS; i++) { | ||
483 | if (ACPI_COMPARE_NAME(th->signature, acpi_data_objs[i].name)) { | ||
484 | data_attr = kzalloc(sizeof(*data_attr), GFP_KERNEL); | ||
485 | if (!data_attr) | ||
486 | return -ENOMEM; | ||
487 | sysfs_attr_init(&data_attr->attr.attr); | ||
488 | data_attr->attr.read = acpi_data_show; | ||
489 | data_attr->attr.attr.mode = 0400; | ||
490 | return acpi_data_objs[i].fn(th, data_attr); | ||
491 | } | ||
492 | } | ||
493 | return 0; | ||
494 | } | ||
495 | |||
423 | static int acpi_tables_sysfs_init(void) | 496 | static int acpi_tables_sysfs_init(void) |
424 | { | 497 | { |
425 | struct acpi_table_attr *table_attr; | 498 | struct acpi_table_attr *table_attr; |
@@ -432,6 +505,10 @@ static int acpi_tables_sysfs_init(void) | |||
432 | if (!tables_kobj) | 505 | if (!tables_kobj) |
433 | goto err; | 506 | goto err; |
434 | 507 | ||
508 | tables_data_kobj = kobject_create_and_add("data", tables_kobj); | ||
509 | if (!tables_data_kobj) | ||
510 | goto err_tables_data; | ||
511 | |||
435 | dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj); | 512 | dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj); |
436 | if (!dynamic_tables_kobj) | 513 | if (!dynamic_tables_kobj) |
437 | goto err_dynamic_tables; | 514 | goto err_dynamic_tables; |
@@ -456,13 +533,17 @@ static int acpi_tables_sysfs_init(void) | |||
456 | return ret; | 533 | return ret; |
457 | } | 534 | } |
458 | list_add_tail(&table_attr->node, &acpi_table_attr_list); | 535 | list_add_tail(&table_attr->node, &acpi_table_attr_list); |
536 | acpi_table_data_init(table_header); | ||
459 | } | 537 | } |
460 | 538 | ||
461 | kobject_uevent(tables_kobj, KOBJ_ADD); | 539 | kobject_uevent(tables_kobj, KOBJ_ADD); |
540 | kobject_uevent(tables_data_kobj, KOBJ_ADD); | ||
462 | kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); | 541 | kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); |
463 | 542 | ||
464 | return 0; | 543 | return 0; |
465 | err_dynamic_tables: | 544 | err_dynamic_tables: |
545 | kobject_put(tables_data_kobj); | ||
546 | err_tables_data: | ||
466 | kobject_put(tables_kobj); | 547 | kobject_put(tables_kobj); |
467 | err: | 548 | err: |
468 | return -ENOMEM; | 549 | return -ENOMEM; |
@@ -552,11 +633,15 @@ static void fixed_event_count(u32 event_number) | |||
552 | static void acpi_global_event_handler(u32 event_type, acpi_handle device, | 633 | static void acpi_global_event_handler(u32 event_type, acpi_handle device, |
553 | u32 event_number, void *context) | 634 | u32 event_number, void *context) |
554 | { | 635 | { |
555 | if (event_type == ACPI_EVENT_TYPE_GPE) | 636 | if (event_type == ACPI_EVENT_TYPE_GPE) { |
556 | gpe_count(event_number); | 637 | gpe_count(event_number); |
557 | 638 | pr_debug("GPE event 0x%02x\n", event_number); | |
558 | if (event_type == ACPI_EVENT_TYPE_FIXED) | 639 | } else if (event_type == ACPI_EVENT_TYPE_FIXED) { |
559 | fixed_event_count(event_number); | 640 | fixed_event_count(event_number); |
641 | pr_debug("Fixed event 0x%02x\n", event_number); | ||
642 | } else { | ||
643 | pr_debug("Other event 0x%02x\n", event_number); | ||
644 | } | ||
560 | } | 645 | } |
561 | 646 | ||
562 | static int get_status(u32 index, acpi_event_status *status, | 647 | static int get_status(u32 index, acpi_event_status *status, |