aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--drivers/base/auxiliary.c108
-rw-r--r--drivers/base/component.c3
-rw-r--r--drivers/base/devres.c9
-rw-r--r--drivers/base/faux.c22
-rw-r--r--drivers/base/platform.c2
-rw-r--r--drivers/base/swnode.c2
-rw-r--r--fs/sysfs/group.c6
-rw-r--r--include/linux/auxiliary_bus.h17
-rw-r--r--include/linux/sysfs.h27
9 files changed, 156 insertions, 40 deletions
diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c
index afa4df4c5a3f..a6d46c2759be 100644
--- a/drivers/base/auxiliary.c
+++ b/drivers/base/auxiliary.c
@@ -385,6 +385,114 @@ void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv)
}
EXPORT_SYMBOL_GPL(auxiliary_driver_unregister);
+static void auxiliary_device_release(struct device *dev)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+
+ kfree(auxdev);
+}
+
+/**
+ * auxiliary_device_create - create a device on the auxiliary bus
+ * @dev: parent device
+ * @modname: module name used to create the auxiliary driver name.
+ * @devname: auxiliary bus device name
+ * @platform_data: auxiliary bus device platform data
+ * @id: auxiliary bus device id
+ *
+ * Helper to create an auxiliary bus device.
+ * The device created matches driver 'modname.devname' on the auxiliary bus.
+ */
+struct auxiliary_device *auxiliary_device_create(struct device *dev,
+ const char *modname,
+ const char *devname,
+ void *platform_data,
+ int id)
+{
+ struct auxiliary_device *auxdev;
+ int ret;
+
+ auxdev = kzalloc(sizeof(*auxdev), GFP_KERNEL);
+ if (!auxdev)
+ return NULL;
+
+ auxdev->id = id;
+ auxdev->name = devname;
+ auxdev->dev.parent = dev;
+ auxdev->dev.platform_data = platform_data;
+ auxdev->dev.release = auxiliary_device_release;
+ device_set_of_node_from_dev(&auxdev->dev, dev);
+
+ ret = auxiliary_device_init(auxdev);
+ if (ret) {
+ kfree(auxdev);
+ return NULL;
+ }
+
+ ret = __auxiliary_device_add(auxdev, modname);
+ if (ret) {
+ /*
+ * It may look odd but auxdev should not be freed here.
+ * auxiliary_device_uninit() calls device_put() which call
+ * the device release function, freeing auxdev.
+ */
+ auxiliary_device_uninit(auxdev);
+ return NULL;
+ }
+
+ return auxdev;
+}
+EXPORT_SYMBOL_GPL(auxiliary_device_create);
+
+/**
+ * auxiliary_device_destroy - remove an auxiliary device
+ * @auxdev: pointer to the auxdev to be removed
+ *
+ * Helper to remove an auxiliary device created with
+ * auxiliary_device_create()
+ */
+void auxiliary_device_destroy(void *auxdev)
+{
+ struct auxiliary_device *_auxdev = auxdev;
+
+ auxiliary_device_delete(_auxdev);
+ auxiliary_device_uninit(_auxdev);
+}
+EXPORT_SYMBOL_GPL(auxiliary_device_destroy);
+
+/**
+ * __devm_auxiliary_device_create - create a managed device on the auxiliary bus
+ * @dev: parent device
+ * @modname: module name used to create the auxiliary driver name.
+ * @devname: auxiliary bus device name
+ * @platform_data: auxiliary bus device platform data
+ * @id: auxiliary bus device id
+ *
+ * Device managed helper to create an auxiliary bus device.
+ * The device created matches driver 'modname.devname' on the auxiliary bus.
+ */
+struct auxiliary_device *__devm_auxiliary_device_create(struct device *dev,
+ const char *modname,
+ const char *devname,
+ void *platform_data,
+ int id)
+{
+ struct auxiliary_device *auxdev;
+ int ret;
+
+ auxdev = auxiliary_device_create(dev, modname, devname, platform_data, id);
+ if (IS_ERR(auxdev))
+ return auxdev;
+
+ ret = devm_add_action_or_reset(dev, auxiliary_device_destroy,
+ auxdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return auxdev;
+}
+EXPORT_SYMBOL_GPL(__devm_auxiliary_device_create);
+
void __init auxiliary_bus_init(void)
{
WARN_ON(bus_register(&auxiliary_bus_type));
diff --git a/drivers/base/component.c b/drivers/base/component.c
index abe60eb45c55..024ad9471b8a 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -586,7 +586,8 @@ EXPORT_SYMBOL_GPL(component_master_is_bound);
static void component_unbind(struct component *component,
struct aggregate_device *adev, void *data)
{
- WARN_ON(!component->bound);
+ if (WARN_ON(!component->bound))
+ return;
dev_dbg(adev->parent, "unbinding %s component %p (ops %ps)\n",
dev_name(component->dev), component, component->ops);
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index d8a733ea5e1a..eee63bc1f062 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -976,17 +976,10 @@ EXPORT_SYMBOL_GPL(devm_krealloc);
*/
char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
{
- size_t size;
- char *buf;
-
if (!s)
return NULL;
- size = strlen(s) + 1;
- buf = devm_kmalloc(dev, size, gfp);
- if (buf)
- memcpy(buf, s, size);
- return buf;
+ return devm_kmemdup(dev, s, strlen(s) + 1, gfp);
}
EXPORT_SYMBOL_GPL(devm_kstrdup);
diff --git a/drivers/base/faux.c b/drivers/base/faux.c
index 407c1d1aad50..9054d346bd7f 100644
--- a/drivers/base/faux.c
+++ b/drivers/base/faux.c
@@ -25,6 +25,7 @@
struct faux_object {
struct faux_device faux_dev;
const struct faux_device_ops *faux_ops;
+ const struct attribute_group **groups;
};
#define to_faux_object(dev) container_of_const(dev, struct faux_object, faux_dev.dev)
@@ -43,10 +44,21 @@ static int faux_probe(struct device *dev)
struct faux_object *faux_obj = to_faux_object(dev);
struct faux_device *faux_dev = &faux_obj->faux_dev;
const struct faux_device_ops *faux_ops = faux_obj->faux_ops;
- int ret = 0;
+ int ret;
- if (faux_ops && faux_ops->probe)
+ if (faux_ops && faux_ops->probe) {
ret = faux_ops->probe(faux_dev);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Add groups after the probe succeeds to ensure resources are
+ * initialized correctly
+ */
+ ret = device_add_groups(dev, faux_obj->groups);
+ if (ret && faux_ops && faux_ops->remove)
+ faux_ops->remove(faux_dev);
return ret;
}
@@ -57,6 +69,8 @@ static void faux_remove(struct device *dev)
struct faux_device *faux_dev = &faux_obj->faux_dev;
const struct faux_device_ops *faux_ops = faux_obj->faux_ops;
+ device_remove_groups(dev, faux_obj->groups);
+
if (faux_ops && faux_ops->remove)
faux_ops->remove(faux_dev);
}
@@ -124,8 +138,9 @@ struct faux_device *faux_device_create_with_groups(const char *name,
if (!faux_obj)
return NULL;
- /* Save off the callbacks so we can use them in the future */
+ /* Save off the callbacks and groups so we can use them in the future */
faux_obj->faux_ops = faux_ops;
+ faux_obj->groups = groups;
/* Initialize the device portion and register it with the driver core */
faux_dev = &faux_obj->faux_dev;
@@ -138,7 +153,6 @@ struct faux_device *faux_device_create_with_groups(const char *name,
else
dev->parent = &faux_bus_root;
dev->bus = &faux_bus_type;
- dev->groups = groups;
dev_set_name(dev, "%s", name);
ret = device_add(dev);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 1813cfd0c4bd..63dfa41f0904 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -982,7 +982,7 @@ struct platform_device * __init_or_module __platform_create_bundle(
struct platform_device *pdev;
int error;
- pdev = platform_device_alloc(driver->driver.name, -1);
+ pdev = platform_device_alloc(driver->driver.name, PLATFORM_DEVID_NONE);
if (!pdev) {
error = -ENOMEM;
goto err_out;
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index b1726a3515f6..22bed2d35b2e 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -529,7 +529,7 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
if (prop->is_inline)
return -EINVAL;
- if (index * sizeof(*ref) >= prop->length)
+ if ((index + 1) * sizeof(*ref) > prop->length)
return -ENOENT;
ref_array = prop->pointer;
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 8b01a7eda5fb..2d78e94072a0 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -21,7 +21,7 @@ static void remove_files(struct kernfs_node *parent,
const struct attribute_group *grp)
{
struct attribute *const *attr;
- struct bin_attribute *const *bin_attr;
+ const struct bin_attribute *const *bin_attr;
if (grp->attrs)
for (attr = grp->attrs; *attr; attr++)
@@ -47,7 +47,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
const struct attribute_group *grp, int update)
{
struct attribute *const *attr;
- struct bin_attribute *const *bin_attr;
+ const struct bin_attribute *const *bin_attr;
int error = 0, i;
if (grp->attrs) {
@@ -521,7 +521,7 @@ static int sysfs_group_attrs_change_owner(struct kernfs_node *grp_kn,
}
if (grp->bin_attrs) {
- struct bin_attribute *const *bin_attr;
+ const struct bin_attribute *const *bin_attr;
for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
kn = kernfs_find_and_get(grp_kn, (*bin_attr)->attr.name);
diff --git a/include/linux/auxiliary_bus.h b/include/linux/auxiliary_bus.h
index 65dd7f154374..4086afd0cc6b 100644
--- a/include/linux/auxiliary_bus.h
+++ b/include/linux/auxiliary_bus.h
@@ -254,6 +254,23 @@ int __auxiliary_driver_register(struct auxiliary_driver *auxdrv, struct module *
void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv);
+struct auxiliary_device *auxiliary_device_create(struct device *dev,
+ const char *modname,
+ const char *devname,
+ void *platform_data,
+ int id);
+void auxiliary_device_destroy(void *auxdev);
+
+struct auxiliary_device *__devm_auxiliary_device_create(struct device *dev,
+ const char *modname,
+ const char *devname,
+ void *platform_data,
+ int id);
+
+#define devm_auxiliary_device_create(dev, devname, platform_data) \
+ __devm_auxiliary_device_create(dev, KBUILD_MODNAME, devname, \
+ platform_data, 0)
+
/**
* module_auxiliary_driver() - Helper macro for registering an auxiliary driver
* @__auxiliary_driver: auxiliary driver struct
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 18f7e1fd093c..f418aae4f113 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -107,7 +107,7 @@ struct attribute_group {
int);
struct attribute **attrs;
union {
- struct bin_attribute **bin_attrs;
+ const struct bin_attribute *const *bin_attrs;
const struct bin_attribute *const *bin_attrs_new;
};
};
@@ -306,11 +306,11 @@ struct bin_attribute {
size_t size;
void *private;
struct address_space *(*f_mapping)(void);
- ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *,
+ ssize_t (*read)(struct file *, struct kobject *, const struct bin_attribute *,
char *, loff_t, size_t);
ssize_t (*read_new)(struct file *, struct kobject *, const struct bin_attribute *,
char *, loff_t, size_t);
- ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *,
+ ssize_t (*write)(struct file *, struct kobject *, const struct bin_attribute *,
char *, loff_t, size_t);
ssize_t (*write_new)(struct file *, struct kobject *,
const struct bin_attribute *, char *, loff_t, size_t);
@@ -332,28 +332,11 @@ struct bin_attribute {
*/
#define sysfs_bin_attr_init(bin_attr) sysfs_attr_init(&(bin_attr)->attr)
-typedef ssize_t __sysfs_bin_rw_handler_new(struct file *, struct kobject *,
- const struct bin_attribute *, char *, loff_t, size_t);
-
/* macros to create static binary attributes easier */
#define __BIN_ATTR(_name, _mode, _read, _write, _size) { \
.attr = { .name = __stringify(_name), .mode = _mode }, \
- .read = _Generic(_read, \
- __sysfs_bin_rw_handler_new * : NULL, \
- default : _read \
- ), \
- .read_new = _Generic(_read, \
- __sysfs_bin_rw_handler_new * : _read, \
- default : NULL \
- ), \
- .write = _Generic(_write, \
- __sysfs_bin_rw_handler_new * : NULL, \
- default : _write \
- ), \
- .write_new = _Generic(_write, \
- __sysfs_bin_rw_handler_new * : _write, \
- default : NULL \
- ), \
+ .read = _read, \
+ .write = _write, \
.size = _size, \
}