On Thu, Oct 05, 2017 at 12:50:19AM +0300, Sakari Ailus wrote: > Hi folks, > > I've dropped the full set from devicetree and linux-acpi lists; > let me know if you want it back. The entire set is posted to > linux-media list. Here's the diff between v14 and v15. The patches can be found here, with the dependencies: <URL:https://git.linuxtv.org/sailus/media_tree.git/log/?h=fwnode-parse> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 5aae5cb38b81..ae026eee3d03 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -248,18 +248,20 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, list_move(&sd->async_list, ¬ifier->done); /* - * See if the sub-device has a notifier. If it does, proceed - * with checking for its async sub-devices. + * See if the sub-device has a notifier. If not, return here. */ subdev_notifier = v4l2_async_find_subdev_notifier(sd); - if (subdev_notifier && !subdev_notifier->parent) { - subdev_notifier->parent = notifier; - ret = v4l2_async_notifier_try_all_subdevs(subdev_notifier); - if (ret) - return ret; - } + if (!subdev_notifier || subdev_notifier->parent) + return 0; - return 0; + /* + * Proceed with checking for the sub-device notifier's async + * sub-devices, and return the result. The error will be handled by the + * caller. + */ + subdev_notifier->parent = notifier; + + return v4l2_async_notifier_try_all_subdevs(subdev_notifier); } /* Test all async sub-devices in a notifier for a match. */ @@ -304,7 +306,28 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) /* Subdevice driver will reprobe and put the subdev back onto the list */ list_del_init(&sd->async_list); sd->asd = NULL; - sd->dev = NULL; +} + +/* Unbind all sub-devices in the notifier tree. */ +static void v4l2_async_notifier_unbind_all_subdevs( + struct v4l2_async_notifier *notifier) +{ + struct v4l2_subdev *sd, *tmp; + + list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { + struct v4l2_async_notifier *subdev_notifier = + v4l2_async_find_subdev_notifier(sd); + + if (subdev_notifier) + v4l2_async_notifier_unbind_all_subdevs(subdev_notifier); + + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); + v4l2_async_cleanup(sd); + + list_move(&sd->async_list, &subdev_list); + } + + notifier->parent = NULL; } /* See if an fwnode can be found in a notifier's lists. */ @@ -412,9 +435,11 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) ret = v4l2_async_notifier_try_all_subdevs(notifier); if (ret) - goto out_unlock; + goto err_unbind; ret = v4l2_async_notifier_try_complete(notifier); + if (ret) + goto err_unbind; /* Keep also completed notifiers on the list */ list_add(¬ifier->list, ¬ifier_list); @@ -422,69 +447,74 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) out_unlock: mutex_unlock(&list_lock); + return 0; + +err_unbind: + /* + * On failure, unbind all sub-devices registered through this notifier. + */ + v4l2_async_notifier_unbind_all_subdevs(notifier); + + mutex_unlock(&list_lock); + return ret; } int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, struct v4l2_async_notifier *notifier) { + int ret; + if (WARN_ON(!v4l2_dev || notifier->sd)) return -EINVAL; notifier->v4l2_dev = v4l2_dev; - return __v4l2_async_notifier_register(notifier); + ret = __v4l2_async_notifier_register(notifier); + if (ret) + notifier->v4l2_dev = NULL; + + return ret; } EXPORT_SYMBOL(v4l2_async_notifier_register); int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd, struct v4l2_async_notifier *notifier) { + int ret; + if (WARN_ON(!sd || notifier->v4l2_dev)) return -EINVAL; notifier->sd = sd; - return __v4l2_async_notifier_register(notifier); + ret = __v4l2_async_notifier_register(notifier); + if (ret) + notifier->sd = NULL; + + return ret; } EXPORT_SYMBOL(v4l2_async_subdev_notifier_register); -/* Unbind all sub-devices in the notifier tree. */ -static void v4l2_async_notifier_unbind_all_subdevs( +static void __v4l2_async_notifier_unregister( struct v4l2_async_notifier *notifier) { - struct v4l2_subdev *sd, *tmp; - - list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { - struct v4l2_async_notifier *subdev_notifier = - v4l2_async_find_subdev_notifier(sd); - - if (subdev_notifier) - v4l2_async_notifier_unbind_all_subdevs(subdev_notifier); - - v4l2_async_cleanup(sd); + if (!notifier || (!notifier->v4l2_dev && !notifier->sd)) + return; - v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); + v4l2_async_notifier_unbind_all_subdevs(notifier); - list_move(&sd->async_list, &subdev_list); - } + notifier->sd = NULL; + notifier->v4l2_dev = NULL; - notifier->parent = NULL; + list_del(¬ifier->list); } void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) { - if (!notifier->v4l2_dev && !notifier->sd) - return; - mutex_lock(&list_lock); - v4l2_async_notifier_unbind_all_subdevs(notifier); - - notifier->sd = NULL; - notifier->v4l2_dev = NULL; - - list_del(¬ifier->list); + __v4l2_async_notifier_unregister(notifier); mutex_unlock(&list_lock); } @@ -522,7 +552,9 @@ EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup); int v4l2_async_register_subdev(struct v4l2_subdev *sd) { + struct v4l2_async_notifier *subdev_notifier; struct v4l2_async_notifier *notifier; + int ret; /* * No reference taken. The reference is held by the device @@ -549,47 +581,64 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) if (!asd) continue; - ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd); + ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd, + asd); + if (ret) + goto err_unbind; - if (!ret) - ret = v4l2_async_notifier_try_complete(notifier); + ret = v4l2_async_notifier_try_complete(notifier); + if (ret) + goto err_unbind; - mutex_unlock(&list_lock); - return ret; + goto out_unlock; } /* None matched, wait for hot-plugging */ list_add(&sd->async_list, &subdev_list); +out_unlock: mutex_unlock(&list_lock); return 0; + +err_unbind: + /* + * Complete failed. Unbind the sub-devices bound through registering + * this async sub-device. + */ + subdev_notifier = v4l2_async_find_subdev_notifier(sd); + if (subdev_notifier) + v4l2_async_notifier_unbind_all_subdevs(subdev_notifier); + + if (sd->asd) + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); + v4l2_async_cleanup(sd); + + mutex_unlock(&list_lock); + + return ret; } EXPORT_SYMBOL(v4l2_async_register_subdev); void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) { - struct v4l2_async_notifier *notifier = sd->notifier; + mutex_lock(&list_lock); - if (sd->subdev_notifier) - v4l2_async_notifier_unregister(sd->subdev_notifier); + __v4l2_async_notifier_unregister(sd->subdev_notifier); v4l2_async_notifier_cleanup(sd->subdev_notifier); kfree(sd->subdev_notifier); + sd->subdev_notifier = NULL; - if (!sd->asd) { - if (!list_empty(&sd->async_list)) - v4l2_async_cleanup(sd); - return; - } + if (sd->asd) { + struct v4l2_async_notifier *notifier = sd->notifier; - mutex_lock(&list_lock); + list_add(&sd->asd->list, ¬ifier->waiting); - list_add(&sd->asd->list, ¬ifier->waiting); + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); + } v4l2_async_cleanup(sd); - v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); - mutex_unlock(&list_lock); } EXPORT_SYMBOL(v4l2_async_unregister_subdev); diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index 74f2ea27d117..65f87e80081a 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -201,5 +201,4 @@ int __must_check v4l2_async_register_subdev_sensor_common( * @sd: pointer to &struct v4l2_subdev */ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd); - #endif diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index 834e74246412..43fd1a278bcc 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -137,7 +137,7 @@ struct v4l2_fwnode_link { int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep); -/* +/** * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by * v4l2_fwnode_endpoint_alloc_parse() * @vep - the V4L2 fwnode the resources of which are to be released -- Sakari Ailus e-mail: sakari.ailus@xxxxxx -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html