From d4c5f047ae2a33296774e41abc2ac5c89283f736 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 14 Jun 2007 17:43:07 +0800 Subject: ACPI: Populate /sys/firmware/acpi/tables/ The file name is the signature, such as DSDT, and the contents are the binary table image. Some tables, such as the SSDT, can have multiple instances. If just one, the file is SSDT, but if 3 instances, for example, it will be SSDT1, SSDT2, SSDT3 All static tables (besides teh RSDP and RSDT themselves are exported. Dynamic tables, such as SSDT op-regions that are not declared in the RSDT, will be added in a subsequent patch. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/system.c | 165 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 144 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 83a8d309790..edee2806e37 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -39,15 +39,12 @@ ACPI_MODULE_NAME("system"); #define ACPI_SYSTEM_CLASS "system" #define ACPI_SYSTEM_DEVICE_NAME "System" -#define ACPI_SYSTEM_FILE_INFO "info" -#define ACPI_SYSTEM_FILE_EVENT "event" -#define ACPI_SYSTEM_FILE_DSDT "dsdt" -#define ACPI_SYSTEM_FILE_FADT "fadt" /* * Make ACPICA version work as module param */ -static int param_get_acpica_version(char *buffer, struct kernel_param *kp) { +static int param_get_acpica_version(char *buffer, struct kernel_param *kp) +{ int result; result = sprintf(buffer, "%x", ACPI_CA_VERSION); @@ -57,10 +54,127 @@ static int param_get_acpica_version(char *buffer, struct kernel_param *kp) { module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); +/* -------------------------------------------------------------------------- + FS Interface (/sys) + -------------------------------------------------------------------------- */ +static LIST_HEAD(acpi_table_attr_list); +static struct kobject tables_kobj; + +struct acpi_table_attr { + struct bin_attribute attr; + char name[8]; + int instance; + struct list_head node; +}; + +static ssize_t acpi_table_show(struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t offset, size_t count) +{ + struct acpi_table_attr *table_attr = + container_of(bin_attr, struct acpi_table_attr, attr); + struct acpi_table_header *table_header = NULL; + acpi_status status; + ssize_t ret_count = count; + + status = + acpi_get_table(table_attr->name, table_attr->instance, + &table_header); + if (ACPI_FAILURE(status)) + return -ENODEV; + + if (offset >= table_header->length) { + ret_count = 0; + goto end; + } + + if (offset + ret_count > table_header->length) + ret_count = table_header->length - offset; + + memcpy(buf, ((char *)table_header) + offset, ret_count); + + end: + return ret_count; +} + +static void acpi_table_attr_init(struct acpi_table_attr *table_attr, + struct acpi_table_header *table_header) +{ + struct acpi_table_header *header = NULL; + struct acpi_table_attr *attr = NULL; + + memcpy(table_attr->name, table_header->signature, ACPI_NAME_SIZE); + + list_for_each_entry(attr, &acpi_table_attr_list, node) { + if (!memcmp(table_header->signature, attr->name, + ACPI_NAME_SIZE)) + if (table_attr->instance < attr->instance) + table_attr->instance = attr->instance; + } + table_attr->instance++; + + if (table_attr->instance > 1 || (table_attr->instance == 1 && + !acpi_get_table(table_header-> + signature, 2, + &header))) + sprintf(table_attr->name + 4, "%d", table_attr->instance); + + table_attr->attr.size = 0; + table_attr->attr.read = acpi_table_show; + table_attr->attr.attr.name = table_attr->name; + table_attr->attr.attr.mode = 0444; + table_attr->attr.attr.owner = THIS_MODULE; + + return; +} + +static int acpi_system_sysfs_init(void) +{ + struct acpi_table_attr *table_attr; + struct acpi_table_header *table_header = NULL; + int table_index = 0; + int result; + + tables_kobj.parent = &acpi_subsys.kobj; + kobject_set_name(&tables_kobj, "tables"); + result = kobject_register(&tables_kobj); + if (result) + return result; + + do { + result = acpi_get_table_by_index(table_index, &table_header); + if (!result) { + table_index++; + table_attr = NULL; + table_attr = + kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL); + if (!table_attr) + return -ENOMEM; + + acpi_table_attr_init(table_attr, table_header); + result = + sysfs_create_bin_file(&tables_kobj, + &table_attr->attr); + if (result) { + kfree(table_attr); + return result; + } else + list_add_tail(&table_attr->node, + &acpi_table_attr_list); + } + } while (!result); + + return 0; +} + /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ #ifdef CONFIG_ACPI_PROCFS +#define ACPI_SYSTEM_FILE_INFO "info" +#define ACPI_SYSTEM_FILE_EVENT "event" +#define ACPI_SYSTEM_FILE_DSDT "dsdt" +#define ACPI_SYSTEM_FILE_FADT "fadt" static int acpi_system_read_info(struct seq_file *seq, void *offset) { @@ -80,7 +194,6 @@ static const struct file_operations acpi_system_info_ops = { .llseek = seq_lseek, .release = single_release, }; -#endif static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t, loff_t *); @@ -97,13 +210,11 @@ acpi_system_read_dsdt(struct file *file, struct acpi_table_header *dsdt = NULL; ssize_t res; - status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt); if (ACPI_FAILURE(status)) return -ENODEV; - res = simple_read_from_buffer(buffer, count, ppos, - dsdt, dsdt->length); + res = simple_read_from_buffer(buffer, count, ppos, dsdt, dsdt->length); return res; } @@ -123,28 +234,21 @@ acpi_system_read_fadt(struct file *file, struct acpi_table_header *fadt = NULL; ssize_t res; - status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt); if (ACPI_FAILURE(status)) return -ENODEV; - res = simple_read_from_buffer(buffer, count, ppos, - fadt, fadt->length); + res = simple_read_from_buffer(buffer, count, ppos, fadt, fadt->length); return res; } -static int __init acpi_system_init(void) +static int acpi_system_procfs_init(void) { struct proc_dir_entry *entry; int error = 0; char *name; - - if (acpi_disabled) - return 0; - -#ifdef CONFIG_ACPI_PROCFS /* 'info' [R] */ name = ACPI_SYSTEM_FILE_INFO; entry = create_proc_entry(name, S_IRUGO, acpi_root_dir); @@ -153,7 +257,6 @@ static int __init acpi_system_init(void) else { entry->proc_fops = &acpi_system_info_ops; } -#endif /* 'dsdt' [R] */ name = ACPI_SYSTEM_FILE_DSDT; @@ -177,12 +280,32 @@ static int __init acpi_system_init(void) Error: remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir); remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir); -#ifdef CONFIG_ACPI_PROCFS remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir); -#endif error = -EFAULT; goto Done; } +#else +static int acpi_system_procfs_init(void) +{ + return 0; +} +#endif + +static int __init acpi_system_init(void) +{ + int result = 0; + + if (acpi_disabled) + return 0; + + result = acpi_system_procfs_init(); + if (result) + return result; + + result = acpi_system_sysfs_init(); + + return result; +} subsys_initcall(acpi_system_init); -- cgit v1.2.3