From 102a0743326a03cd1a1202ceda21e175b7d3575c Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Tue, 20 Feb 2024 01:20:52 +0000 Subject: [PATCH] add new system file --- kernel/drivers/base/soc.c | 92 ++++++++++++++++++++++++--------------------- 1 files changed, 49 insertions(+), 43 deletions(-) diff --git a/kernel/drivers/base/soc.c b/kernel/drivers/base/soc.c index 61638ac..d34609b 100644 --- a/kernel/drivers/base/soc.c +++ b/kernel/drivers/base/soc.c @@ -17,9 +17,9 @@ static DEFINE_IDA(soc_ida); -static ssize_t soc_info_get(struct device *dev, - struct device_attribute *attr, - char *buf); +/* Prototype to allow declarations of DEVICE_ATTR(<foo>) before soc_info_show */ +static ssize_t soc_info_show(struct device *dev, struct device_attribute *attr, + char *buf); struct soc_device { struct device dev; @@ -31,63 +31,65 @@ .name = "soc", }; -static DEVICE_ATTR(machine, S_IRUGO, soc_info_get, NULL); -static DEVICE_ATTR(family, S_IRUGO, soc_info_get, NULL); -static DEVICE_ATTR(soc_id, S_IRUGO, soc_info_get, NULL); -static DEVICE_ATTR(revision, S_IRUGO, soc_info_get, NULL); +static DEVICE_ATTR(machine, 0444, soc_info_show, NULL); +static DEVICE_ATTR(family, 0444, soc_info_show, NULL); +static DEVICE_ATTR(serial_number, 0444, soc_info_show, NULL); +static DEVICE_ATTR(soc_id, 0444, soc_info_show, NULL); +static DEVICE_ATTR(revision, 0444, soc_info_show, NULL); struct device *soc_device_to_device(struct soc_device *soc_dev) { return &soc_dev->dev; } -EXPORT_SYMBOL_GPL(soc_device_to_device); static umode_t soc_attribute_mode(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); - if ((attr == &dev_attr_machine.attr) - && (soc_dev->attr->machine != NULL)) + if ((attr == &dev_attr_machine.attr) && soc_dev->attr->machine) return attr->mode; - if ((attr == &dev_attr_family.attr) - && (soc_dev->attr->family != NULL)) + if ((attr == &dev_attr_family.attr) && soc_dev->attr->family) return attr->mode; - if ((attr == &dev_attr_revision.attr) - && (soc_dev->attr->revision != NULL)) + if ((attr == &dev_attr_revision.attr) && soc_dev->attr->revision) return attr->mode; - if ((attr == &dev_attr_soc_id.attr) - && (soc_dev->attr->soc_id != NULL)) + if ((attr == &dev_attr_serial_number.attr) && soc_dev->attr->serial_number) + return attr->mode; + if ((attr == &dev_attr_soc_id.attr) && soc_dev->attr->soc_id) return attr->mode; - /* Unknown or unfilled attribute. */ + /* Unknown or unfilled attribute */ return 0; } -static ssize_t soc_info_get(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t soc_info_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); + const char *output; if (attr == &dev_attr_machine) - return sprintf(buf, "%s\n", soc_dev->attr->machine); - if (attr == &dev_attr_family) - return sprintf(buf, "%s\n", soc_dev->attr->family); - if (attr == &dev_attr_revision) - return sprintf(buf, "%s\n", soc_dev->attr->revision); - if (attr == &dev_attr_soc_id) - return sprintf(buf, "%s\n", soc_dev->attr->soc_id); + output = soc_dev->attr->machine; + else if (attr == &dev_attr_family) + output = soc_dev->attr->family; + else if (attr == &dev_attr_revision) + output = soc_dev->attr->revision; + else if (attr == &dev_attr_serial_number) + output = soc_dev->attr->serial_number; + else if (attr == &dev_attr_soc_id) + output = soc_dev->attr->soc_id; + else + return -EINVAL; - return -EINVAL; - + return sysfs_emit(buf, "%s\n", output); } static struct attribute *soc_attr[] = { &dev_attr_machine.attr, &dev_attr_family.attr, + &dev_attr_serial_number.attr, &dev_attr_soc_id.attr, &dev_attr_revision.attr, NULL, @@ -98,15 +100,12 @@ .is_visible = soc_attribute_mode, }; -static const struct attribute_group *soc_attr_groups[] = { - &soc_attr_group, - NULL, -}; - static void soc_release(struct device *dev) { struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); + ida_simple_remove(&soc_ida, soc_dev->soc_dev_num); + kfree(soc_dev->dev.groups); kfree(soc_dev); } @@ -115,6 +114,7 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr) { struct soc_device *soc_dev; + const struct attribute_group **soc_attr_groups; int ret; if (!soc_bus_type.p) { @@ -130,10 +130,18 @@ goto out1; } + soc_attr_groups = kcalloc(3, sizeof(*soc_attr_groups), GFP_KERNEL); + if (!soc_attr_groups) { + ret = -ENOMEM; + goto out2; + } + soc_attr_groups[0] = &soc_attr_group; + soc_attr_groups[1] = soc_dev_attr->custom_attr_group; + /* Fetch a unique (reclaimable) SOC ID. */ ret = ida_simple_get(&soc_ida, 0, 0, GFP_KERNEL); if (ret < 0) - goto out2; + goto out3; soc_dev->soc_dev_num = ret; soc_dev->attr = soc_dev_attr; @@ -144,15 +152,15 @@ dev_set_name(&soc_dev->dev, "soc%d", soc_dev->soc_dev_num); ret = device_register(&soc_dev->dev); - if (ret) - goto out3; + if (ret) { + put_device(&soc_dev->dev); + return ERR_PTR(ret); + } return soc_dev; out3: - ida_simple_remove(&soc_ida, soc_dev->soc_dev_num); - put_device(&soc_dev->dev); - soc_dev = NULL; + kfree(soc_attr_groups); out2: kfree(soc_dev); out1: @@ -163,8 +171,6 @@ /* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */ void soc_device_unregister(struct soc_device *soc_dev) { - ida_simple_remove(&soc_ida, soc_dev->soc_dev_num); - device_unregister(&soc_dev->dev); early_soc_dev_attr = NULL; } -- Gitblit v1.6.2