diff options
Diffstat (limited to 'drivers/base/faux.c')
-rw-r--r-- | drivers/base/faux.c | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/drivers/base/faux.c b/drivers/base/faux.c index 531e9d789ee0..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); } @@ -102,7 +116,9 @@ static void faux_device_release(struct device *dev) * * Note, when this function is called, the functions specified in struct * faux_ops can be called before the function returns, so be prepared for - * everything to be properly initialized before that point in time. + * everything to be properly initialized before that point in time. If the + * probe callback (if one is present) does NOT succeed, the creation of the + * device will fail and NULL will be returned. * * Return: * * NULL if an error happened with creating the device @@ -122,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; @@ -136,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); @@ -147,6 +163,17 @@ struct faux_device *faux_device_create_with_groups(const char *name, return NULL; } + /* + * Verify that we did bind the driver to the device (i.e. probe worked), + * if not, let's fail the creation as trying to guess if probe was + * successful is almost impossible to determine by the caller. + */ + if (!dev->driver) { + dev_err(dev, "probe did not succeed, tearing down the device\n"); + faux_device_destroy(faux_dev); + faux_dev = NULL; + } + return faux_dev; } EXPORT_SYMBOL_GPL(faux_device_create_with_groups); |