list_for_each_entry(asc, ¬ifier->waiting_list, asc_entry) { /* bus_type has been verified valid before */ switch (asc->match.type) { case V4L2_ASYNC_MATCH_TYPE_I2C:
match = match_i2c; break; case V4L2_ASYNC_MATCH_TYPE_FWNODE:
match = match_fwnode; break; default: /* Cannot happen, unless someone breaks us */
WARN_ON(true); return NULL;
}
/* match cannot be NULL here */ if (match(notifier, sd, &asc->match)) return asc;
}
return NULL;
}
/* Compare two async match descriptors for equivalence */ staticbool v4l2_async_match_equal(struct v4l2_async_match_desc *match1, struct v4l2_async_match_desc *match2)
{ if (match1->type != match2->type) returnfalse;
/* Find the sub-device notifier registered by a sub-device driver. */ staticstruct v4l2_async_notifier *
v4l2_async_find_subdev_notifier(struct v4l2_subdev *sd)
{ struct v4l2_async_notifier *n;
list_for_each_entry(n, ¬ifier_list, notifier_entry) if (n->sd == sd) return n;
return NULL;
}
/* Get v4l2_device related to the notifier if one can be found. */ staticstruct v4l2_device *
v4l2_async_nf_find_v4l2_dev(struct v4l2_async_notifier *notifier)
{ while (notifier->parent)
notifier = notifier->parent;
return notifier->v4l2_dev;
}
/* * Return true if all child sub-device notifiers are complete, false otherwise.
*/ staticbool
v4l2_async_nf_can_complete(struct v4l2_async_notifier *notifier)
{ struct v4l2_async_connection *asc;
if (!list_empty(¬ifier->waiting_list)) returnfalse;
if (subdev_notifier &&
!v4l2_async_nf_can_complete(subdev_notifier)) returnfalse;
}
returntrue;
}
/* * Complete the master notifier if possible. This is done when all async * sub-devices have been bound; v4l2_device is also available then.
*/ staticint
v4l2_async_nf_try_complete(struct v4l2_async_notifier *notifier)
{ struct v4l2_async_notifier *__notifier = notifier;
/* Quick check whether there are still more sub-devices here. */ if (!list_empty(¬ifier->waiting_list)) return 0;
if (notifier->sd)
dev_dbg(notifier_dev(notifier), "v4l2-async: trying to complete\n");
/* Check the entire notifier tree; find the root notifier first. */ while (notifier->parent)
notifier = notifier->parent;
/* This is root if it has v4l2_dev. */ if (!notifier->v4l2_dev) {
dev_dbg(notifier_dev(__notifier), "v4l2-async: V4L2 device not available\n"); return 0;
}
/* Is everything ready? */ if (!v4l2_async_nf_can_complete(notifier)) return 0;
if (list_empty(&sd->asc_list)) {
ret = __v4l2_device_register_subdev(v4l2_dev, sd, sd->owner); if (ret < 0) return ret;
registered = true;
}
ret = v4l2_async_nf_call_bound(notifier, sd, asc); if (ret < 0) { if (asc->match.type == V4L2_ASYNC_MATCH_TYPE_FWNODE)
dev_dbg(notifier_dev(notifier), "failed binding %pfw (%d)\n",
asc->match.fwnode, ret); goto err_unregister_subdev;
}
if (registered) { /* * Depending of the function of the entities involved, we may * want to create links between them (for example between a * sensor and its lens or between a sensor's source pad and the * connected device's sink pad).
*/
ret = v4l2_async_create_ancillary_links(notifier, sd); if (ret) { if (asc->match.type == V4L2_ASYNC_MATCH_TYPE_FWNODE)
dev_dbg(notifier_dev(notifier), "failed creating links for %pfw (%d)\n",
asc->match.fwnode, ret); goto err_call_unbind;
}
}
/* * 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) 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;
err_unregister_subdev: if (registered)
v4l2_device_unregister_subdev(sd);
return ret;
}
/* Test all async sub-devices in a notifier for a match. */ staticint
v4l2_async_nf_try_all_subdevs(struct v4l2_async_notifier *notifier)
{ struct v4l2_device *v4l2_dev =
v4l2_async_nf_find_v4l2_dev(notifier); struct v4l2_subdev *sd;
if (!v4l2_dev) return 0;
dev_dbg(notifier_dev(notifier), "v4l2-async: trying all sub-devices\n");
again:
list_for_each_entry(sd, &subdev_list, async_list) { struct v4l2_async_connection *asc; int ret;
asc = v4l2_async_find_match(notifier, sd); if (!asc) continue;
dev_dbg(notifier_dev(notifier), "v4l2-async: match found, subdev %s\n", sd->name);
ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asc); if (ret < 0) return ret;
/* * v4l2_async_match_notify() may lead to registering a * new notifier and thus changing the async subdevs * list. In order to proceed safely from here, restart * parsing the list from the beginning.
*/ goto again;
}
if (subdev_notifier)
v4l2_async_nf_unbind_all_subdevs(subdev_notifier);
v4l2_async_unbind_subdev_one(notifier, asc);
}
notifier->parent = NULL;
}
/* See if an async sub-device can be found in a notifier's lists. */ staticbool
v4l2_async_nf_has_async_match_entry(struct v4l2_async_notifier *notifier, struct v4l2_async_match_desc *match)
{ struct v4l2_async_connection *asc;
list_for_each_entry(asc, ¬ifier->waiting_list, asc_entry) if (v4l2_async_match_equal(&asc->match, match)) returntrue;
list_for_each_entry(asc, ¬ifier->done_list, asc_entry) if (v4l2_async_match_equal(&asc->match, match)) returntrue;
returnfalse;
}
/* * Find out whether an async sub-device was set up already or whether it exists * in a given notifier.
*/ staticbool
v4l2_async_nf_has_async_match(struct v4l2_async_notifier *notifier, struct v4l2_async_match_desc *match)
{ struct list_head *heads[] = {
¬ifier->waiting_list,
¬ifier->done_list,
}; unsignedint i;
lockdep_assert_held(&list_lock);
/* Check that an asd is not being added more than once. */ for (i = 0; i < ARRAY_SIZE(heads); i++) { struct v4l2_async_connection *asc;
list_for_each_entry(asc, heads[i], asc_entry) { if (&asc->match == match) continue; if (v4l2_async_match_equal(&asc->match, match)) returntrue;
}
}
/* Check that an asc does not exist in other notifiers. */
list_for_each_entry(notifier, ¬ifier_list, notifier_entry) if (v4l2_async_nf_has_async_match_entry(notifier, match)) returntrue;
switch (match->type) { case V4L2_ASYNC_MATCH_TYPE_I2C: case V4L2_ASYNC_MATCH_TYPE_FWNODE: if (v4l2_async_nf_has_async_match(notifier, match)) {
dev_dbg(dev, "v4l2-async: match descriptor already listed in a notifier\n"); return -EEXIST;
} break; default:
dev_err(dev, "v4l2-async: Invalid match type %u on %p\n",
match->type, match); return -EINVAL;
}
remote = fwnode_graph_get_remote_endpoint(endpoint); if (!remote) return ERR_PTR(-ENOTCONN);
asc = __v4l2_async_nf_add_fwnode(notif, remote, asc_struct_size); /* * Calling __v4l2_async_nf_add_fwnode grabs a refcount, * so drop the one we got in fwnode_graph_get_remote_port_parent.
*/
fwnode_handle_put(remote); return asc;
}
EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_fwnode_remote);
int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module)
{ struct v4l2_async_notifier *subdev_notifier; struct v4l2_async_notifier *notifier; struct v4l2_async_connection *asc; int ret;
INIT_LIST_HEAD(&sd->asc_list);
/* * No reference taken. The reference is held by the device (struct * v4l2_subdev.dev), and async sub-device does not exist independently * of the device at any point of time. * * The async sub-device shall always be registered for its device node, * not the endpoint node.
*/ if (!sd->fwnode && sd->dev) {
sd->fwnode = dev_fwnode(sd->dev);
} elseif (fwnode_graph_is_endpoint(sd->fwnode)) {
dev_warn(sd->dev, "sub-device fwnode is an endpoint!\n"); return -EINVAL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.