Re: [ACPI] Re: [PATCH] filling in ACPI method access via sysfsnamespace

From: Alex Williamson
Date: Sat Apr 10 2004 - 22:24:44 EST


On Sat, 2004-04-10 at 14:42, Alex Williamson wrote:
>
> Ok, I took a look. The open/write/read/close interface seems to be
> the best approach. It shouldn't be too hard, except the read/write
> interfaces don't pass in the attribute pointer like they do for the
> show/store interface.

I made the assumption that this wasn't that big of a stretch to the
bin file interface and extended it to add the arribute pointer. Below
is what I came up with. There are luckly only a handful of places using
the current sysfs bin file interface, so the additional changes are
pretty small. I'm guessing I can probably get rid of the spinlocks I
added for the previous implementation, but they're not hurting anything
for now. Am I getting closer? Thanks,

Alex

drivers/acpi/scan.c | 236 +++++++++++++++++++++++++++++++++++++++-
drivers/base/firmware_class.c | 8 -
drivers/i2c/chips/eeprom.c | 3
drivers/pci/pci-sysfs.c | 6 -
drivers/scsi/qla2xxx/qla_os.c | 32 ++---
drivers/video/aty/radeon_base.c | 6 -
drivers/zorro/zorro-sysfs.c | 4
fs/sysfs/bin.c | 4
include/linux/sysfs.h | 6 -
9 files changed, 273 insertions(+), 32 deletions(-)

===== drivers/acpi/scan.c 1.22 vs edited =====
--- 1.22/drivers/acpi/scan.c Tue Feb 3 22:29:19 2004
+++ edited/drivers/acpi/scan.c Sat Apr 10 20:55:30 2004
@@ -25,6 +25,238 @@
static LIST_HEAD(acpi_device_list);
static spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED;

+struct acpi_handle_attribute {
+ struct attribute attr;
+ size_t size;
+ ssize_t (*read)(struct kobject *, struct attribute *,
+ char *, loff_t, size_t);
+ ssize_t (*write)(struct kobject *, struct attribute *,
+ char *, loff_t, size_t);
+ union acpi_object *args;
+ size_t length;
+ spinlock_t lock;
+};
+
+#define to_acpi_device(n) container_of(n, struct acpi_device, kobj)
+#define to_handle_attr(n) container_of(n, struct acpi_handle_attribute, attr);
+
+static ssize_t
+acpi_device_write_raw(
+ struct kobject *kobj,
+ struct attribute *attr,
+ char *buf,
+ loff_t off,
+ size_t length)
+{
+ struct acpi_handle_attribute *attrib = to_handle_attr(attr);
+
+ /*
+ * Not sure if offsets should be ignored or enforced, suppose we could
+ * pass multiple arguments that way, but this interface already
+ * accepts multiple arguments packed into an acpi_object array
+ */
+ if (off)
+ return -ENODEV;
+
+ spin_lock(&attrib->lock);
+ if (attrib->args) {
+ kfree(attrib->args);
+ attrib->args = NULL;
+ attrib->length = 0;
+ }
+
+ attrib->args = kmalloc(length, GFP_KERNEL);
+ if (!attrib->args) {
+ spin_unlock(&attrib->lock);
+ return -ENODEV;
+ }
+
+ memcpy(attrib->args, buf, length);
+ attrib->length = length;
+ spin_unlock(&attrib->lock);
+
+ return length;
+}
+
+static ssize_t
+acpi_device_read_raw(
+ struct kobject *kobj,
+ struct attribute *attr,
+ char *buf,
+ loff_t off,
+ size_t length)
+{
+ struct acpi_device *device = to_acpi_device(kobj);
+ struct acpi_handle_attribute *attrib = to_handle_attr(attr);
+ struct acpi_object_list *arg_list = NULL;
+ union acpi_object **cur_arg, *args = NULL;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_status status;
+ u32 count, i;
+ size_t size;
+
+ /* Ditto, see comment above */
+ if (off)
+ return -ENODEV;
+
+ spin_lock(&attrib->lock);
+
+ /*
+ * For convenience, handle cases where the last argument
+ * is too small.
+ */
+ count = attrib->length / sizeof(union acpi_object);
+ if (attrib->length % sizeof(union acpi_object))
+ count++;
+
+ if (count) {
+ size = sizeof(struct acpi_object_list) +
+ ((count - 1) * sizeof(union acpi_object *));
+
+ arg_list = kmalloc(size, GFP_KERNEL);
+ if (!arg_list) {
+ spin_unlock(&attrib->lock);
+ return -ENODEV;
+ }
+
+ memset(arg_list, 0, size);
+ arg_list->count = count;
+
+ size = count * sizeof(union acpi_object);
+ args = kmalloc(size, GFP_KERNEL);
+ if (!args) {
+ kfree(arg_list);
+ spin_unlock(&attrib->lock);
+ return -ENODEV;
+ }
+ memset(args, 0, size);
+ memcpy(args, attrib->args, min(attrib->length, size));
+
+ cur_arg = &arg_list->pointer;
+ for (i = 0 ; i < count ; i++)
+ cur_arg[i] = &args[i];
+
+ kfree(attrib->args);
+ attrib->args = NULL;
+ attrib->length = 0;
+ }
+ spin_unlock(&attrib->lock);
+
+ status = acpi_evaluate_object(device->handle, attrib->attr.name,
+ arg_list, &buffer);
+ if (arg_list)
+ kfree(arg_list);
+ if (args)
+ kfree(args);
+
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ size = min((unsigned long)buffer.length, PAGE_SIZE);
+ memcpy(buf, buffer.pointer, size);
+ acpi_os_free(buffer.pointer);
+
+ return size;
+}
+
+static void
+create_sysfs_files(struct acpi_device *dev)
+{
+ acpi_handle chandle = 0;
+ char pathname[ACPI_PATHNAME_MAX];
+ acpi_status status;
+ struct acpi_buffer buffer;
+ struct bin_attribute *attrib;
+ int error;
+
+ buffer.length = sizeof(pathname);
+ buffer.pointer = pathname;
+
+ while (ACPI_SUCCESS(acpi_get_next_object(ACPI_TYPE_METHOD, dev->handle,
+ chandle, &chandle))) {
+
+ memset(pathname, 0 , sizeof(pathname));
+
+ status = acpi_get_name(chandle, ACPI_SINGLE_NAME, &buffer);
+ if (ACPI_FAILURE(status))
+ continue;
+
+ attrib = kmalloc(sizeof(struct acpi_handle_attribute),
+ GFP_KERNEL);
+ if (!attrib)
+ continue;
+
+ memset(attrib, 0, sizeof(struct acpi_handle_attribute));
+
+ attrib->attr.name = kmalloc(strlen(pathname), GFP_KERNEL);
+ if (!attrib->attr.name) {
+ kfree(attrib);
+ continue;
+ }
+
+ strcpy(attrib->attr.name, pathname);
+
+ attrib->size = PAGE_SIZE;
+ attrib->attr.mode = S_IFREG | S_IRUSR |
+ S_IWUSR | S_IRGRP | S_IWGRP;
+ attrib->read = acpi_device_read_raw;
+ attrib->write = acpi_device_write_raw;
+ spin_lock_init(&((struct acpi_handle_attribute *)attrib)->lock);
+
+ error = sysfs_create_bin_file(&dev->kobj, attrib);
+ if (error) {
+ kfree(attrib->attr.name);
+ kfree(attrib);
+ continue;
+ }
+ }
+}
+
+extern struct dentry * sysfs_get_dentry(struct dentry *, const char *);
+
+static void
+remove_sysfs_files(struct acpi_device *dev)
+{
+ acpi_handle chandle = 0;
+ char pathname[ACPI_PATHNAME_MAX];
+ acpi_status status;
+ struct acpi_buffer buffer;
+ struct bin_attribute *old_attrib;
+ struct dentry *dentry;
+
+ buffer.length = sizeof(pathname);
+ buffer.pointer = pathname;
+
+ while (ACPI_SUCCESS(acpi_get_next_object(ACPI_TYPE_METHOD, dev->handle,
+ chandle, &chandle))) {
+
+ memset(pathname, 0 , sizeof(pathname));
+
+ status = acpi_get_name(chandle, ACPI_SINGLE_NAME, &buffer);
+ if (ACPI_FAILURE(status))
+ continue;
+
+ down(&(dev->kobj.dentry->d_inode->i_sem));
+ dentry = sysfs_get_dentry(dev->kobj.dentry, pathname);
+ if (!IS_ERR(dentry))
+ old_attrib = dentry->d_fsdata;
+ else
+ old_attrib = NULL;
+ up(&(dev->kobj.dentry->d_inode->i_sem));
+
+ if (old_attrib) {
+ if (strncmp(pathname, old_attrib->attr.name,
+ strlen(pathname)) != 0)
+ continue;
+
+ sysfs_remove_bin_file(&dev->kobj, old_attrib);
+
+ kfree(old_attrib->attr.name);
+ kfree(old_attrib);
+ }
+ }
+}
+
static void acpi_device_release(struct kobject * kobj)
{
struct acpi_device * dev = container_of(kobj,struct acpi_device,kobj);
@@ -72,6 +304,7 @@
device->kobj.ktype = &ktype_acpi_ns;
device->kobj.kset = &acpi_namespace_kset;
kobject_add(&device->kobj);
+ create_sysfs_files(device);
}

static int
@@ -79,6 +312,7 @@
struct acpi_device *device,
int type)
{
+ remove_sysfs_files(device);
kobject_unregister(&device->kobj);
return 0;
}
@@ -706,7 +940,7 @@
switch (type) {
case ACPI_BUS_TYPE_DEVICE:
result = acpi_bus_get_status(device);
- if (ACPI_FAILURE(result) || !device->status.present) {
+ if (ACPI_FAILURE(result)) {
result = -ENOENT;
goto end;
}
===== drivers/base/firmware_class.c 1.16 vs edited =====
--- 1.16/drivers/base/firmware_class.c Mon Mar 1 20:01:49 2004
+++ edited/drivers/base/firmware_class.c Sat Apr 10 15:31:43 2004
@@ -167,8 +167,8 @@
firmware_loading_show, firmware_loading_store);

static ssize_t
-firmware_data_read(struct kobject *kobj,
- char *buffer, loff_t offset, size_t count)
+firmware_data_read(struct kobject *kobj, struct attribute *attr,
+ char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
@@ -227,8 +227,8 @@
* the driver as a firmware image.
**/
static ssize_t
-firmware_data_write(struct kobject *kobj,
- char *buffer, loff_t offset, size_t count)
+firmware_data_write(struct kobject *kobj, struct attribute *attr,
+ char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
===== drivers/i2c/chips/eeprom.c 1.6 vs edited =====
--- 1.6/drivers/i2c/chips/eeprom.c Mon Mar 15 03:38:36 2004
+++ edited/drivers/i2c/chips/eeprom.c Sat Apr 10 15:32:02 2004
@@ -122,7 +122,8 @@
up(&data->update_lock);
}

-static ssize_t eeprom_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t eeprom_read(struct kobject *kobj, struct attribute *attr,
+ char *buf, loff_t off, size_t count)
{
struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
struct eeprom_data *data = i2c_get_clientdata(client);
===== drivers/pci/pci-sysfs.c 1.8 vs edited =====
--- 1.8/drivers/pci/pci-sysfs.c Mon Feb 9 21:55:42 2004
+++ edited/drivers/pci/pci-sysfs.c Sat Apr 10 20:39:02 2004
@@ -63,7 +63,8 @@
static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL);

static ssize_t
-pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+pci_read_config(struct kobject *kobj, struct attribute *attr,
+ char *buf, loff_t off, size_t count)
{
struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
unsigned int size = 64;
@@ -117,7 +118,8 @@
}

static ssize_t
-pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+pci_write_config(struct kobject *kobj, struct attribute *attr,
+ char *buf, loff_t off, size_t count)
{
struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
unsigned int size = count;
===== drivers/scsi/qla2xxx/qla_os.c 1.6 vs edited =====
--- 1.6/drivers/scsi/qla2xxx/qla_os.c Wed Feb 18 20:42:35 2004
+++ edited/drivers/scsi/qla2xxx/qla_os.c Sat Apr 10 15:34:14 2004
@@ -435,10 +435,10 @@
int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
void qla2x00_free_sp_pool(scsi_qla_host_t *ha);

-static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *, char *, loff_t,
- size_t);
-static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *, char *, loff_t,
- size_t);
+static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *, struct attribute *,
+ char *, loff_t, size_t);
+static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *, struct attribute *,
+ char *, loff_t, size_t);
static struct bin_attribute sysfs_fw_dump_attr = {
.attr = {
.name = "fw_dump",
@@ -448,10 +448,10 @@
.read = qla2x00_sysfs_read_fw_dump,
.write = qla2x00_sysfs_write_fw_dump,
};
-static ssize_t qla2x00_sysfs_read_nvram(struct kobject *, char *, loff_t,
- size_t);
-static ssize_t qla2x00_sysfs_write_nvram(struct kobject *, char *, loff_t,
- size_t);
+static ssize_t qla2x00_sysfs_read_nvram(struct kobject *, struct attribute *,
+ char *, loff_t, size_t);
+static ssize_t qla2x00_sysfs_write_nvram(struct kobject *, struct attribute *,
+ char *, loff_t, size_t);
static struct bin_attribute sysfs_nvram_attr = {
.attr = {
.name = "nvram",
@@ -473,8 +473,8 @@


/* SysFS attributes. */
-static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf,
- loff_t off, size_t count)
+static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
+ struct attribute *attr, char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -491,8 +491,8 @@
return (count);
}

-static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf,
- loff_t off, size_t count)
+static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *kobj,
+ struct attribute *attr, char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -546,8 +546,8 @@
return (count);
}

-static ssize_t qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf,
- loff_t off, size_t count)
+static ssize_t qla2x00_sysfs_read_nvram(struct kobject *kobj,
+ struct attribute *attr, char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -573,8 +573,8 @@
return (count);
}

-static ssize_t qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf,
- loff_t off, size_t count)
+static ssize_t qla2x00_sysfs_write_nvram(struct kobject *kobj,
+ struct attribute *attr, char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
===== drivers/video/aty/radeon_base.c 1.12 vs edited =====
--- 1.12/drivers/video/aty/radeon_base.c Fri Mar 5 03:40:50 2004
+++ edited/drivers/video/aty/radeon_base.c Sat Apr 10 15:35:04 2004
@@ -2014,7 +2014,8 @@
}


-static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t radeon_show_edid1(struct kobject *kobj, struct attribute *attr,
+ char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct pci_dev *pdev = to_pci_dev(dev);
@@ -2025,7 +2026,8 @@
}


-static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t radeon_show_edid2(struct kobject *kobj, struct attribute *attr,
+ char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct pci_dev *pdev = to_pci_dev(dev);
===== drivers/zorro/zorro-sysfs.c 1.1 vs edited =====
--- 1.1/drivers/zorro/zorro-sysfs.c Sun Jan 18 23:35:41 2004
+++ edited/drivers/zorro/zorro-sysfs.c Sat Apr 10 15:35:55 2004
@@ -47,8 +47,8 @@

static DEVICE_ATTR(resource, S_IRUGO, zorro_show_resource, NULL);

-static ssize_t zorro_read_config(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t zorro_read_config(struct kobject *kobj, struct attribute *attr,
+ char *buf, loff_t off, size_t count)
{
struct zorro_dev *z = to_zorro_dev(container_of(kobj, struct device,
kobj));
===== fs/sysfs/bin.c 1.12 vs edited =====
--- 1.12/fs/sysfs/bin.c Fri Aug 29 10:40:51 2003
+++ edited/fs/sysfs/bin.c Sat Apr 10 15:36:38 2004
@@ -20,7 +20,7 @@
struct bin_attribute * attr = dentry->d_fsdata;
struct kobject * kobj = dentry->d_parent->d_fsdata;

- return attr->read(kobj, buffer, off, count);
+ return attr->read(kobj, &attr->attr, buffer, off, count);
}

static ssize_t
@@ -63,7 +63,7 @@
struct bin_attribute *attr = dentry->d_fsdata;
struct kobject *kobj = dentry->d_parent->d_fsdata;

- return attr->write(kobj, buffer, offset, count);
+ return attr->write(kobj, &attr->attr, buffer, offset, count);
}

static ssize_t write(struct file * file, const char __user * userbuf,
===== include/linux/sysfs.h 1.32 vs edited =====
--- 1.32/include/linux/sysfs.h Tue Aug 12 09:53:51 2003
+++ edited/include/linux/sysfs.h Sat Apr 10 16:32:12 2004
@@ -21,8 +21,10 @@
struct bin_attribute {
struct attribute attr;
size_t size;
- ssize_t (*read)(struct kobject *, char *, loff_t, size_t);
- ssize_t (*write)(struct kobject *, char *, loff_t, size_t);
+ ssize_t (*read)(struct kobject *, struct attribute *,
+ char *, loff_t, size_t);
+ ssize_t (*write)(struct kobject *, struct attribute *,
+ char *, loff_t, size_t);
};

int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr);


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/