Merge branches 'acpi-sysfs', 'acpi-apei' and 'acpi-blacklist'
[linux-2.6-block.git] / drivers / acpi / sysfs.c
index e414fabf73158d77fba356be2c10354647e81a44..78a5a23010ab4522923ccae5709d4100458cfbbb 100644 (file)
@@ -2,6 +2,8 @@
  * sysfs.c - ACPI sysfs interface to userspace.
  */
 
+#define pr_fmt(fmt) "ACPI: " fmt
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/moduleparam.h>
@@ -306,11 +308,13 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
 /*
  * ACPI table sysfs I/F:
  * /sys/firmware/acpi/tables/
+ * /sys/firmware/acpi/tables/data/
  * /sys/firmware/acpi/tables/dynamic/
  */
 
 static LIST_HEAD(acpi_table_attr_list);
 static struct kobject *tables_kobj;
+static struct kobject *tables_data_kobj;
 static struct kobject *dynamic_tables_kobj;
 static struct kobject *hotplug_kobj;
 
@@ -325,6 +329,11 @@ struct acpi_table_attr {
        struct list_head node;
 };
 
+struct acpi_data_attr {
+       struct bin_attribute attr;
+       u64     addr;
+};
+
 static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj,
                               struct bin_attribute *bin_attr, char *buf,
                               loff_t offset, size_t count)
@@ -420,6 +429,70 @@ acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context)
        return AE_OK;
 }
 
+static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj,
+                             struct bin_attribute *bin_attr, char *buf,
+                             loff_t offset, size_t count)
+{
+       struct acpi_data_attr *data_attr;
+       void __iomem *base;
+       ssize_t rc;
+
+       data_attr = container_of(bin_attr, struct acpi_data_attr, attr);
+
+       base = acpi_os_map_memory(data_attr->addr, data_attr->attr.size);
+       if (!base)
+               return -ENOMEM;
+       rc = memory_read_from_buffer(buf, count, &offset, base,
+                                    data_attr->attr.size);
+       acpi_os_unmap_memory(base, data_attr->attr.size);
+
+       return rc;
+}
+
+static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr)
+{
+       struct acpi_table_bert *bert = th;
+
+       if (bert->header.length < sizeof(struct acpi_table_bert) ||
+           bert->region_length < sizeof(struct acpi_hest_generic_status)) {
+               kfree(data_attr);
+               return -EINVAL;
+       }
+       data_attr->addr = bert->address;
+       data_attr->attr.size = bert->region_length;
+       data_attr->attr.attr.name = "BERT";
+
+       return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr);
+}
+
+static struct acpi_data_obj {
+       char *name;
+       int (*fn)(void *, struct acpi_data_attr *);
+} acpi_data_objs[] = {
+       { ACPI_SIG_BERT, acpi_bert_data_init },
+};
+
+#define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs)
+
+static int acpi_table_data_init(struct acpi_table_header *th)
+{
+       struct acpi_data_attr *data_attr;
+       int i;
+
+       for (i = 0; i < NUM_ACPI_DATA_OBJS; i++) {
+               if (ACPI_COMPARE_NAME(th->signature, acpi_data_objs[i].name)) {
+                       data_attr = kzalloc(sizeof(*data_attr), GFP_KERNEL);
+                       if (!data_attr)
+                               return -ENOMEM;
+                       sysfs_attr_init(&data_attr->attr.attr);
+                       data_attr->attr.read = acpi_data_show;
+                       data_attr->attr.attr.mode = 0400;
+                       return acpi_data_objs[i].fn(th, data_attr);
+               }
+       }
+       return 0;
+}
+
 static int acpi_tables_sysfs_init(void)
 {
        struct acpi_table_attr *table_attr;
@@ -432,6 +505,10 @@ static int acpi_tables_sysfs_init(void)
        if (!tables_kobj)
                goto err;
 
+       tables_data_kobj = kobject_create_and_add("data", tables_kobj);
+       if (!tables_data_kobj)
+               goto err_tables_data;
+
        dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj);
        if (!dynamic_tables_kobj)
                goto err_dynamic_tables;
@@ -456,13 +533,17 @@ static int acpi_tables_sysfs_init(void)
                        return ret;
                }
                list_add_tail(&table_attr->node, &acpi_table_attr_list);
+               acpi_table_data_init(table_header);
        }
 
        kobject_uevent(tables_kobj, KOBJ_ADD);
+       kobject_uevent(tables_data_kobj, KOBJ_ADD);
        kobject_uevent(dynamic_tables_kobj, KOBJ_ADD);
 
        return 0;
 err_dynamic_tables:
+       kobject_put(tables_data_kobj);
+err_tables_data:
        kobject_put(tables_kobj);
 err:
        return -ENOMEM;
@@ -552,11 +633,15 @@ static void fixed_event_count(u32 event_number)
 static void acpi_global_event_handler(u32 event_type, acpi_handle device,
        u32 event_number, void *context)
 {
-       if (event_type == ACPI_EVENT_TYPE_GPE)
+       if (event_type == ACPI_EVENT_TYPE_GPE) {
                gpe_count(event_number);
-
-       if (event_type == ACPI_EVENT_TYPE_FIXED)
+               pr_debug("GPE event 0x%02x\n", event_number);
+       } else if (event_type == ACPI_EVENT_TYPE_FIXED) {
                fixed_event_count(event_number);
+               pr_debug("Fixed event 0x%02x\n", event_number);
+       } else {
+               pr_debug("Other event 0x%02x\n", event_number);
+       }
 }
 
 static int get_status(u32 index, acpi_event_status *status,