Subject: [PATCH] [acpi driver model] Update sysfs support - Add acpi_dev_show() and acpi_dev_store() methods that will forward calls down to the real show/store methods - Add create_one() and remove_one() helpers that check for (and call if necessary) the ->ad_test() method; also fill in the ->ad_show() and ->ad_store() methods. - Fix acpi_sysfs_device_register() so that we only remove the attributes that have been added if one fails to be created (instead of trying to remove all of them). - Update comments. Signed-off-by: Patrick Mochel --- drivers/acpi/drivers/core/sysfs.c | 125 +++++++++++++++++++++++++++++++++---- 1 files changed, 113 insertions(+), 12 deletions(-) applies-to: 707209fffa694e9df00ee82733e188d4ce29089b 57ea0b929e7b3de1c15ac89d715c2ea27d12b72c diff --git a/drivers/acpi/drivers/core/sysfs.c b/drivers/acpi/drivers/core/sysfs.c index f442d50..efd295e 100644 --- a/drivers/acpi/drivers/core/sysfs.c +++ b/drivers/acpi/drivers/core/sysfs.c @@ -79,32 +79,133 @@ static struct acpi_dev_attr acpi_dev_att }; + +static struct acpi_dev_attr * to_ada(struct device_attribute * da) +{ + return container_of(da, struct acpi_dev_attr, ad_attr); +} + +static ssize_t acpi_dev_show(struct device * dev, + struct device_attribute * attr, + char * buf) +{ + struct acpi_dev * ad = to_acpi_dev(dev); + struct acpi_dev_attr * ada = to_ada(attr); + ssize_t ret = 0; + + if (ad) { + if (ada->ad_show) + ret = ada->ad_show(ad, buf); + } else + ret = -ENODEV; + return ret; +} + + +static ssize_t acpi_dev_store(struct device * dev, + struct device_attribute * attr, + const char * buf, size_t len) +{ + struct acpi_dev * ad = to_acpi_dev(dev); + struct acpi_dev_attr * ada = to_ada(attr); + ssize_t ret = 0; + + if (ad) { + if (ada->ad_store) + ret = ada->ad_store(ad, buf, len); + } else + ret = -ENODEV; + return ret; +} + +/** + * create_one - Add a single sysfs file for an ACPI device. + * @ad: The ACPI device + * @a: The attribute that we may be adding. + * + * Check for a test function, and if + * - it's not there, or + * - it's there, and returns TRUE (1) + * Then fill in the read and/or write methods and add the file. + */ + +static int create_one(struct acpi_dev * ad, struct acpi_dev_attr * a) +{ + int ret = 0; + + if (!a->ad_test || (a->ad_test && a->ad_test(ad))) { + if (a->ad_attr.attr.mode & S_IRUGO) + a->ad_attr.show = acpi_dev_show; + if (a->ad_attr.attr.mode & S_IWUGO) + a->ad_attr.store = acpi_dev_store; + ret = device_create_file(&ad->dev, &a->ad_attr); + } + return ret; +} + + +/** + * remove_one - Remove a single file for a device + * @ad: The ACPI device + * @a: The attribute we may be removing. + * + * Check for a test function, and if + * - it doesn't exist, or + * - it exists and returns TRUE (1) + * Then remove the file. + */ + +static void remove_one(struct acpi_dev * ad, struct acpi_dev_attr * a) +{ + if (!a->ad_test || (a->ad_test && a->ad_test(ad))) + device_remove_file(&ad->dev, &a->ad_attr); +} + + +/** + * acpi_sysfs_device_unregister - Remove default sysfs files + * @ad: The ACPI device we're removing files for. + * + * Loop over the default attributes (defined above) and call + * remove_one() for each. + */ + void acpi_sysfs_device_unregister(struct acpi_dev * ad) { int num = ARRAY_SIZE(acpi_dev_attrs); int i; - for (i = 0; i < num; i++) { - if (acpi_dev_attrs[i].ad_test(ad)) - device_remove_file(&ad->dev, &acpi_dev_attrs[i].ad_attr); - } + for (i = 0; i < num; i++) + remove_one(ad, &acpi_dev_attrs[i]); } + +/** + * acpi_sysfs_device_register - Add default sysfs files + * @ad: The ACPI device we're removing files for. + * + * Loop over the default attributes (defined above) and call + * create_one() for each. + * + * If one fails, remove the ones that we've added so far. + */ + int acpi_sysfs_device_register(struct acpi_dev * ad) { int num = ARRAY_SIZE(acpi_dev_attrs); - int i; int ret = 0; + int i; for (i = 0; i < num; i++) { - if (acpi_dev_attrs[i].ad_test(ad)) { - ret = device_create_file(&ad->dev, &acpi_dev_attrs[i].ad_attr); - if (ret) { - acpi_sysfs_device_unregister(ad); - break; - } - } + ret = create_one(ad, &acpi_dev_attrs[i]); + if (ret) + goto Fail; } + return 0; + + Fail: + while (--i > 0) + remove_one(ad, &acpi_dev_attrs[i]); return ret; } --- 0.99.9.GIT