Lines Matching +full:sub +full:- +full:module
1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2012-2013, Guennadi Liakhovetski <[email protected]>
14 #include <linux/module.h>
22 #include <media/v4l2-async.h>
23 #include <media/v4l2-device.h>
24 #include <media/v4l2-fwnode.h>
25 #include <media/v4l2-subdev.h>
27 #include "v4l2-subdev-priv.h"
33 if (!n->ops || !n->ops->bound) in v4l2_async_nf_call_bound()
36 return n->ops->bound(n, subdev, asc); in v4l2_async_nf_call_bound()
43 if (!n->ops || !n->ops->unbind) in v4l2_async_nf_call_unbind()
46 n->ops->unbind(n, subdev, asc); in v4l2_async_nf_call_unbind()
51 if (!n->ops || !n->ops->complete) in v4l2_async_nf_call_complete()
54 return n->ops->complete(n); in v4l2_async_nf_call_complete()
60 if (!n->ops || !n->ops->destroy) in v4l2_async_nf_call_destroy()
63 n->ops->destroy(asc); in v4l2_async_nf_call_destroy()
71 struct i2c_client *client = i2c_verify_client(sd->dev); in match_i2c()
74 match->i2c.adapter_id == client->adapter->nr && in match_i2c()
75 match->i2c.address == client->addr; in match_i2c()
83 if (notifier->sd) in notifier_dev()
84 return notifier->sd->dev; in notifier_dev()
86 if (notifier->v4l2_dev) in notifier_dev()
87 return notifier->v4l2_dev->dev; in notifier_dev()
101 "v4l2-async: fwnode match: need %pfw, trying %pfw\n", in match_fwnode_one()
102 sd_fwnode, match->fwnode); in match_fwnode_one()
104 if (sd_fwnode == match->fwnode) { in match_fwnode_one()
106 "v4l2-async: direct match found\n"); in match_fwnode_one()
110 if (!fwnode_graph_is_endpoint(match->fwnode)) { in match_fwnode_one()
112 "v4l2-async: direct match not found\n"); in match_fwnode_one()
116 asd_dev_fwnode = fwnode_graph_get_port_parent(match->fwnode); in match_fwnode_one()
123 "v4l2-async: device--endpoint match %sfound\n", in match_fwnode_one()
134 "v4l2-async: matching for notifier %pfw, sd fwnode %pfw\n", in match_fwnode()
135 dev_fwnode(notifier_dev(notifier)), sd->fwnode); in match_fwnode()
137 if (!list_empty(&sd->async_subdev_endpoint_list)) { in match_fwnode()
140 dev_dbg(sd->dev, in match_fwnode()
141 "v4l2-async: endpoint fwnode list available, looking for %pfw\n", in match_fwnode()
142 match->fwnode); in match_fwnode()
144 list_for_each_entry(ase, &sd->async_subdev_endpoint_list, in match_fwnode()
146 bool matched = ase->endpoint == match->fwnode; in match_fwnode()
148 dev_dbg(sd->dev, in match_fwnode()
149 "v4l2-async: endpoint-endpoint match %sfound with %pfw\n", in match_fwnode()
150 matched ? "" : "not ", ase->endpoint); in match_fwnode()
156 dev_dbg(sd->dev, "async: no endpoint matched\n"); in match_fwnode()
161 if (match_fwnode_one(notifier, sd, sd->fwnode, match)) in match_fwnode()
165 if (IS_ERR_OR_NULL(sd->fwnode->secondary)) in match_fwnode()
169 "v4l2-async: trying secondary fwnode match\n"); in match_fwnode()
171 return match_fwnode_one(notifier, sd, sd->fwnode->secondary, match); in match_fwnode()
187 list_for_each_entry(asc, ¬ifier->waiting_list, asc_entry) { in v4l2_async_find_match()
189 switch (asc->match.type) { in v4l2_async_find_match()
203 if (match(notifier, sd, &asc->match)) in v4l2_async_find_match()
214 if (match1->type != match2->type) in v4l2_async_match_equal()
217 switch (match1->type) { in v4l2_async_match_equal()
219 return match1->i2c.adapter_id == match2->i2c.adapter_id && in v4l2_async_match_equal()
220 match1->i2c.address == match2->i2c.address; in v4l2_async_match_equal()
222 return match1->fwnode == match2->fwnode; in v4l2_async_match_equal()
230 /* Find the sub-device notifier registered by a sub-device driver. */
237 if (n->sd == sd) in v4l2_async_find_subdev_notifier()
247 while (notifier->parent) in v4l2_async_nf_find_v4l2_dev()
248 notifier = notifier->parent; in v4l2_async_nf_find_v4l2_dev()
250 return notifier->v4l2_dev; in v4l2_async_nf_find_v4l2_dev()
254 * Return true if all child sub-device notifiers are complete, false otherwise.
261 if (!list_empty(¬ifier->waiting_list)) in v4l2_async_nf_can_complete()
264 list_for_each_entry(asc, ¬ifier->done_list, asc_entry) { in v4l2_async_nf_can_complete()
266 v4l2_async_find_subdev_notifier(asc->sd); in v4l2_async_nf_can_complete()
278 * sub-devices have been bound; v4l2_device is also available then.
285 /* Quick check whether there are still more sub-devices here. */ in v4l2_async_nf_try_complete()
286 if (!list_empty(¬ifier->waiting_list)) in v4l2_async_nf_try_complete()
289 if (notifier->sd) in v4l2_async_nf_try_complete()
291 "v4l2-async: trying to complete\n"); in v4l2_async_nf_try_complete()
294 while (notifier->parent) in v4l2_async_nf_try_complete()
295 notifier = notifier->parent; in v4l2_async_nf_try_complete()
298 if (!notifier->v4l2_dev) { in v4l2_async_nf_try_complete()
300 "v4l2-async: V4L2 device not available\n"); in v4l2_async_nf_try_complete()
308 dev_dbg(notifier_dev(__notifier), "v4l2-async: complete\n"); in v4l2_async_nf_try_complete()
322 if (sd->entity.function != MEDIA_ENT_F_LENS && in v4l2_async_create_ancillary_links()
323 sd->entity.function != MEDIA_ENT_F_FLASH) in v4l2_async_create_ancillary_links()
326 if (!n->sd) { in v4l2_async_create_ancillary_links()
328 "not a sub-device notifier, not creating an ancillary link for %s!\n", in v4l2_async_create_ancillary_links()
329 dev_name(sd->dev)); in v4l2_async_create_ancillary_links()
333 link = media_create_ancillary_link(&n->sd->entity, &sd->entity); in v4l2_async_create_ancillary_links()
350 if (list_empty(&sd->asc_list)) { in v4l2_async_match_notify()
351 ret = __v4l2_device_register_subdev(v4l2_dev, sd, sd->owner); in v4l2_async_match_notify()
359 if (asc->match.type == V4L2_ASYNC_MATCH_TYPE_FWNODE) in v4l2_async_match_notify()
362 asc->match.fwnode, ret); in v4l2_async_match_notify()
375 if (asc->match.type == V4L2_ASYNC_MATCH_TYPE_FWNODE) in v4l2_async_match_notify()
378 asc->match.fwnode, ret); in v4l2_async_match_notify()
383 list_add(&asc->asc_subdev_entry, &sd->asc_list); in v4l2_async_match_notify()
384 asc->sd = sd; in v4l2_async_match_notify()
387 list_move(&asc->asc_entry, ¬ifier->done_list); in v4l2_async_match_notify()
389 dev_dbg(notifier_dev(notifier), "v4l2-async: %s bound (ret %d)\n", in v4l2_async_match_notify()
390 dev_name(sd->dev), ret); in v4l2_async_match_notify()
393 * See if the sub-device has a notifier. If not, return here. in v4l2_async_match_notify()
396 if (!subdev_notifier || subdev_notifier->parent) in v4l2_async_match_notify()
400 * Proceed with checking for the sub-device notifier's async in v4l2_async_match_notify()
401 * sub-devices, and return the result. The error will be handled by the in v4l2_async_match_notify()
404 subdev_notifier->parent = notifier; in v4l2_async_match_notify()
410 list_del(&asc->asc_subdev_entry); in v4l2_async_match_notify()
419 /* Test all async sub-devices in a notifier for a match. */
430 dev_dbg(notifier_dev(notifier), "v4l2-async: trying all sub-devices\n"); in v4l2_async_nf_try_all_subdevs()
442 "v4l2-async: match found, subdev %s\n", sd->name); in v4l2_async_nf_try_all_subdevs()
463 list_move_tail(&asc->asc_entry, ¬ifier->waiting_list); in v4l2_async_unbind_subdev_one()
464 if (list_is_singular(&asc->asc_subdev_entry)) { in v4l2_async_unbind_subdev_one()
465 v4l2_async_nf_call_unbind(notifier, asc->sd, asc); in v4l2_async_unbind_subdev_one()
466 v4l2_device_unregister_subdev(asc->sd); in v4l2_async_unbind_subdev_one()
467 asc->sd = NULL; in v4l2_async_unbind_subdev_one()
469 list_del(&asc->asc_subdev_entry); in v4l2_async_unbind_subdev_one()
472 /* Unbind all sub-devices in the notifier tree. */
478 list_for_each_entry_safe(asc, asc_tmp, ¬ifier->done_list, in v4l2_async_nf_unbind_all_subdevs()
481 v4l2_async_find_subdev_notifier(asc->sd); in v4l2_async_nf_unbind_all_subdevs()
489 notifier->parent = NULL; in v4l2_async_nf_unbind_all_subdevs()
492 /* See if an async sub-device can be found in a notifier's lists. */
499 list_for_each_entry(asc, ¬ifier->waiting_list, asc_entry) in v4l2_async_nf_has_async_match_entry()
500 if (v4l2_async_match_equal(&asc->match, match)) in v4l2_async_nf_has_async_match_entry()
503 list_for_each_entry(asc, ¬ifier->done_list, asc_entry) in v4l2_async_nf_has_async_match_entry()
504 if (v4l2_async_match_equal(&asc->match, match)) in v4l2_async_nf_has_async_match_entry()
511 * Find out whether an async sub-device was set up already or whether it exists
519 ¬ifier->waiting_list, in v4l2_async_nf_has_async_match()
520 ¬ifier->done_list, in v4l2_async_nf_has_async_match()
531 if (&asc->match == match) in v4l2_async_nf_has_async_match()
533 if (v4l2_async_match_equal(&asc->match, match)) in v4l2_async_nf_has_async_match()
551 switch (match->type) { in v4l2_async_nf_match_valid()
555 dev_dbg(dev, "v4l2-async: match descriptor already listed in a notifier\n"); in v4l2_async_nf_match_valid()
556 return -EEXIST; in v4l2_async_nf_match_valid()
560 dev_err(dev, "v4l2-async: Invalid match type %u on %p\n", in v4l2_async_nf_match_valid()
561 match->type, match); in v4l2_async_nf_match_valid()
562 return -EINVAL; in v4l2_async_nf_match_valid()
571 INIT_LIST_HEAD(¬ifier->waiting_list); in v4l2_async_nf_init()
572 INIT_LIST_HEAD(¬ifier->done_list); in v4l2_async_nf_init()
573 INIT_LIST_HEAD(¬ifier->notifier_entry); in v4l2_async_nf_init()
574 notifier->v4l2_dev = v4l2_dev; in v4l2_async_nf_init()
581 INIT_LIST_HEAD(¬ifier->waiting_list); in v4l2_async_subdev_nf_init()
582 INIT_LIST_HEAD(¬ifier->done_list); in v4l2_async_subdev_nf_init()
583 INIT_LIST_HEAD(¬ifier->notifier_entry); in v4l2_async_subdev_nf_init()
584 notifier->sd = sd; in v4l2_async_subdev_nf_init()
595 list_for_each_entry(asc, ¬ifier->waiting_list, asc_entry) { in __v4l2_async_nf_register()
596 ret = v4l2_async_nf_match_valid(notifier, &asc->match); in __v4l2_async_nf_register()
610 list_add(¬ifier->notifier_entry, ¬ifier_list); in __v4l2_async_nf_register()
618 * On failure, unbind all sub-devices registered through this notifier. in __v4l2_async_nf_register()
630 if (WARN_ON(!notifier->v4l2_dev == !notifier->sd)) in v4l2_async_nf_register()
631 return -EINVAL; in v4l2_async_nf_register()
640 if (!notifier || (!notifier->v4l2_dev && !notifier->sd)) in __v4l2_async_nf_unregister()
645 list_del_init(¬ifier->notifier_entry); in __v4l2_async_nf_unregister()
662 if (!notifier || !notifier->waiting_list.next) in __v4l2_async_nf_cleanup()
665 WARN_ON(!list_empty(¬ifier->done_list)); in __v4l2_async_nf_cleanup()
667 list_for_each_entry_safe(asc, tmp, ¬ifier->waiting_list, asc_entry) { in __v4l2_async_nf_cleanup()
668 list_del(&asc->asc_entry); in __v4l2_async_nf_cleanup()
671 if (asc->match.type == V4L2_ASYNC_MATCH_TYPE_FWNODE) in __v4l2_async_nf_cleanup()
672 fwnode_handle_put(asc->match.fwnode); in __v4l2_async_nf_cleanup()
677 notifier->sd = NULL; in __v4l2_async_nf_cleanup()
678 notifier->v4l2_dev = NULL; in __v4l2_async_nf_cleanup()
696 list_add_tail(&asc->asc_entry, ¬ifier->waiting_list); in __v4l2_async_nf_add_connection()
710 return ERR_PTR(-ENOMEM); in __v4l2_async_nf_add_fwnode()
712 asc->notifier = notifier; in __v4l2_async_nf_add_fwnode()
713 asc->match.type = V4L2_ASYNC_MATCH_TYPE_FWNODE; in __v4l2_async_nf_add_fwnode()
714 asc->match.fwnode = fwnode_handle_get(fwnode); in __v4l2_async_nf_add_fwnode()
732 return ERR_PTR(-ENOTCONN); in __v4l2_async_nf_add_fwnode_remote()
752 return ERR_PTR(-ENOMEM); in __v4l2_async_nf_add_i2c()
754 asc->notifier = notifier; in __v4l2_async_nf_add_i2c()
755 asc->match.type = V4L2_ASYNC_MATCH_TYPE_I2C; in __v4l2_async_nf_add_i2c()
756 asc->match.i2c.adapter_id = adapter_id; in __v4l2_async_nf_add_i2c()
757 asc->match.i2c.address = address; in __v4l2_async_nf_add_i2c()
772 return -ENOMEM; in v4l2_async_subdev_endpoint_add()
774 ase->endpoint = fwnode; in v4l2_async_subdev_endpoint_add()
775 list_add(&ase->async_subdev_endpoint_entry, in v4l2_async_subdev_endpoint_add()
776 &sd->async_subdev_endpoint_list); in v4l2_async_subdev_endpoint_add()
785 if (!list_is_singular(&sd->asc_list)) in v4l2_async_connection_unique()
788 return list_first_entry(&sd->asc_list, in v4l2_async_connection_unique()
793 int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module) in __v4l2_async_register_subdev() argument
800 INIT_LIST_HEAD(&sd->asc_list); in __v4l2_async_register_subdev()
804 * v4l2_subdev.dev), and async sub-device does not exist independently in __v4l2_async_register_subdev()
807 * The async sub-device shall always be registered for its device node, in __v4l2_async_register_subdev()
810 if (!sd->fwnode && sd->dev) { in __v4l2_async_register_subdev()
811 sd->fwnode = dev_fwnode(sd->dev); in __v4l2_async_register_subdev()
812 } else if (fwnode_graph_is_endpoint(sd->fwnode)) { in __v4l2_async_register_subdev()
813 dev_warn(sd->dev, "sub-device fwnode is an endpoint!\n"); in __v4l2_async_register_subdev()
814 return -EINVAL; in __v4l2_async_register_subdev()
817 sd->owner = module; in __v4l2_async_register_subdev()
840 /* None matched, wait for hot-plugging */ in __v4l2_async_register_subdev()
841 list_add(&sd->async_list, &subdev_list); in __v4l2_async_register_subdev()
849 * Complete failed. Unbind the sub-devices bound through registering in __v4l2_async_register_subdev()
850 * this async sub-device. in __v4l2_async_register_subdev()
861 sd->owner = NULL; in __v4l2_async_register_subdev()
871 if (!sd->async_list.next) in v4l2_async_unregister_subdev()
878 __v4l2_async_nf_unregister(sd->subdev_notifier); in v4l2_async_unregister_subdev()
879 __v4l2_async_nf_cleanup(sd->subdev_notifier); in v4l2_async_unregister_subdev()
880 kfree(sd->subdev_notifier); in v4l2_async_unregister_subdev()
881 sd->subdev_notifier = NULL; in v4l2_async_unregister_subdev()
883 if (sd->asc_list.next) { in v4l2_async_unregister_subdev()
884 list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list, in v4l2_async_unregister_subdev()
886 v4l2_async_unbind_subdev_one(asc->notifier, asc); in v4l2_async_unregister_subdev()
890 list_del(&sd->async_list); in v4l2_async_unregister_subdev()
891 sd->async_list.next = NULL; in v4l2_async_unregister_subdev()
900 switch (match->type) { in print_waiting_match()
902 seq_printf(s, " [i2c] dev=%d-%04x\n", match->i2c.adapter_id, in print_waiting_match()
903 match->i2c.address); in print_waiting_match()
906 struct fwnode_handle *devnode, *fwnode = match->fwnode; in print_waiting_match()
913 devnode->dev ? dev_name(devnode->dev) : "nil", in print_waiting_match()
925 if (notifier->v4l2_dev) in v4l2_async_nf_name()
926 return notifier->v4l2_dev->name; in v4l2_async_nf_name()
927 else if (notifier->sd) in v4l2_async_nf_name()
928 return notifier->sd->name; in v4l2_async_nf_name()
942 list_for_each_entry(asc, ¬if->waiting_list, asc_entry) in pending_subdevs_show()
943 print_waiting_match(s, &asc->match); in pending_subdevs_show()
956 v4l2_async_debugfs_dir = debugfs_create_dir("v4l2-async", NULL); in v4l2_async_init()