This source file includes following definitions.
- v4l2_async_notifier_call_bound
- v4l2_async_notifier_call_unbind
- v4l2_async_notifier_call_complete
- match_i2c
- match_devname
- match_fwnode
- match_custom
- v4l2_async_find_match
- asd_equal
- v4l2_async_find_subdev_notifier
- v4l2_async_notifier_find_v4l2_dev
- v4l2_async_notifier_can_complete
- v4l2_async_notifier_try_complete
- v4l2_async_match_notify
- v4l2_async_notifier_try_all_subdevs
- v4l2_async_cleanup
- v4l2_async_notifier_unbind_all_subdevs
- __v4l2_async_notifier_has_async_subdev
- v4l2_async_notifier_has_async_subdev
- v4l2_async_notifier_asd_valid
- v4l2_async_notifier_init
- __v4l2_async_notifier_register
- v4l2_async_notifier_register
- v4l2_async_subdev_notifier_register
- __v4l2_async_notifier_unregister
- v4l2_async_notifier_unregister
- __v4l2_async_notifier_cleanup
- v4l2_async_notifier_cleanup
- v4l2_async_notifier_add_subdev
- v4l2_async_notifier_add_fwnode_subdev
- v4l2_async_notifier_add_fwnode_remote_subdev
- v4l2_async_notifier_add_i2c_subdev
- v4l2_async_notifier_add_devname_subdev
- v4l2_async_register_subdev
- v4l2_async_unregister_subdev
1
2
3
4
5
6
7
8 #include <linux/device.h>
9 #include <linux/err.h>
10 #include <linux/i2c.h>
11 #include <linux/list.h>
12 #include <linux/mm.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
18 #include <linux/types.h>
19
20 #include <media/v4l2-async.h>
21 #include <media/v4l2-device.h>
22 #include <media/v4l2-fwnode.h>
23 #include <media/v4l2-subdev.h>
24
25 static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
26 struct v4l2_subdev *subdev,
27 struct v4l2_async_subdev *asd)
28 {
29 if (!n->ops || !n->ops->bound)
30 return 0;
31
32 return n->ops->bound(n, subdev, asd);
33 }
34
35 static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
36 struct v4l2_subdev *subdev,
37 struct v4l2_async_subdev *asd)
38 {
39 if (!n->ops || !n->ops->unbind)
40 return;
41
42 n->ops->unbind(n, subdev, asd);
43 }
44
45 static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
46 {
47 if (!n->ops || !n->ops->complete)
48 return 0;
49
50 return n->ops->complete(n);
51 }
52
53 static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
54 {
55 #if IS_ENABLED(CONFIG_I2C)
56 struct i2c_client *client = i2c_verify_client(sd->dev);
57
58 return client &&
59 asd->match.i2c.adapter_id == client->adapter->nr &&
60 asd->match.i2c.address == client->addr;
61 #else
62 return false;
63 #endif
64 }
65
66 static bool match_devname(struct v4l2_subdev *sd,
67 struct v4l2_async_subdev *asd)
68 {
69 return !strcmp(asd->match.device_name, dev_name(sd->dev));
70 }
71
72 static bool match_fwnode(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
73 {
74 return sd->fwnode == asd->match.fwnode;
75 }
76
77 static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
78 {
79 if (!asd->match.custom.match)
80
81 return true;
82
83 return asd->match.custom.match(sd->dev, asd);
84 }
85
86 static LIST_HEAD(subdev_list);
87 static LIST_HEAD(notifier_list);
88 static DEFINE_MUTEX(list_lock);
89
90 static struct v4l2_async_subdev *
91 v4l2_async_find_match(struct v4l2_async_notifier *notifier,
92 struct v4l2_subdev *sd)
93 {
94 bool (*match)(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd);
95 struct v4l2_async_subdev *asd;
96
97 list_for_each_entry(asd, ¬ifier->waiting, list) {
98
99 switch (asd->match_type) {
100 case V4L2_ASYNC_MATCH_CUSTOM:
101 match = match_custom;
102 break;
103 case V4L2_ASYNC_MATCH_DEVNAME:
104 match = match_devname;
105 break;
106 case V4L2_ASYNC_MATCH_I2C:
107 match = match_i2c;
108 break;
109 case V4L2_ASYNC_MATCH_FWNODE:
110 match = match_fwnode;
111 break;
112 default:
113
114 WARN_ON(true);
115 return NULL;
116 }
117
118
119 if (match(sd, asd))
120 return asd;
121 }
122
123 return NULL;
124 }
125
126
127 static bool asd_equal(struct v4l2_async_subdev *asd_x,
128 struct v4l2_async_subdev *asd_y)
129 {
130 if (asd_x->match_type != asd_y->match_type)
131 return false;
132
133 switch (asd_x->match_type) {
134 case V4L2_ASYNC_MATCH_DEVNAME:
135 return strcmp(asd_x->match.device_name,
136 asd_y->match.device_name) == 0;
137 case V4L2_ASYNC_MATCH_I2C:
138 return asd_x->match.i2c.adapter_id ==
139 asd_y->match.i2c.adapter_id &&
140 asd_x->match.i2c.address ==
141 asd_y->match.i2c.address;
142 case V4L2_ASYNC_MATCH_FWNODE:
143 return asd_x->match.fwnode == asd_y->match.fwnode;
144 default:
145 break;
146 }
147
148 return false;
149 }
150
151
152 static struct v4l2_async_notifier *
153 v4l2_async_find_subdev_notifier(struct v4l2_subdev *sd)
154 {
155 struct v4l2_async_notifier *n;
156
157 list_for_each_entry(n, ¬ifier_list, list)
158 if (n->sd == sd)
159 return n;
160
161 return NULL;
162 }
163
164
165 static struct v4l2_device *
166 v4l2_async_notifier_find_v4l2_dev(struct v4l2_async_notifier *notifier)
167 {
168 while (notifier->parent)
169 notifier = notifier->parent;
170
171 return notifier->v4l2_dev;
172 }
173
174
175
176
177 static bool
178 v4l2_async_notifier_can_complete(struct v4l2_async_notifier *notifier)
179 {
180 struct v4l2_subdev *sd;
181
182 if (!list_empty(¬ifier->waiting))
183 return false;
184
185 list_for_each_entry(sd, ¬ifier->done, async_list) {
186 struct v4l2_async_notifier *subdev_notifier =
187 v4l2_async_find_subdev_notifier(sd);
188
189 if (subdev_notifier &&
190 !v4l2_async_notifier_can_complete(subdev_notifier))
191 return false;
192 }
193
194 return true;
195 }
196
197
198
199
200
201 static int
202 v4l2_async_notifier_try_complete(struct v4l2_async_notifier *notifier)
203 {
204
205 if (!list_empty(¬ifier->waiting))
206 return 0;
207
208
209 while (notifier->parent)
210 notifier = notifier->parent;
211
212
213 if (!notifier->v4l2_dev)
214 return 0;
215
216
217 if (!v4l2_async_notifier_can_complete(notifier))
218 return 0;
219
220 return v4l2_async_notifier_call_complete(notifier);
221 }
222
223 static int
224 v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier);
225
226 static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
227 struct v4l2_device *v4l2_dev,
228 struct v4l2_subdev *sd,
229 struct v4l2_async_subdev *asd)
230 {
231 struct v4l2_async_notifier *subdev_notifier;
232 int ret;
233
234 ret = v4l2_device_register_subdev(v4l2_dev, sd);
235 if (ret < 0)
236 return ret;
237
238 ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
239 if (ret < 0) {
240 v4l2_device_unregister_subdev(sd);
241 return ret;
242 }
243
244
245 list_del(&asd->list);
246 sd->asd = asd;
247 sd->notifier = notifier;
248
249
250 list_move(&sd->async_list, ¬ifier->done);
251
252
253
254
255 subdev_notifier = v4l2_async_find_subdev_notifier(sd);
256 if (!subdev_notifier || subdev_notifier->parent)
257 return 0;
258
259
260
261
262
263
264 subdev_notifier->parent = notifier;
265
266 return v4l2_async_notifier_try_all_subdevs(subdev_notifier);
267 }
268
269
270 static int
271 v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier)
272 {
273 struct v4l2_device *v4l2_dev =
274 v4l2_async_notifier_find_v4l2_dev(notifier);
275 struct v4l2_subdev *sd;
276
277 if (!v4l2_dev)
278 return 0;
279
280 again:
281 list_for_each_entry(sd, &subdev_list, async_list) {
282 struct v4l2_async_subdev *asd;
283 int ret;
284
285 asd = v4l2_async_find_match(notifier, sd);
286 if (!asd)
287 continue;
288
289 ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
290 if (ret < 0)
291 return ret;
292
293
294
295
296
297
298
299 goto again;
300 }
301
302 return 0;
303 }
304
305 static void v4l2_async_cleanup(struct v4l2_subdev *sd)
306 {
307 v4l2_device_unregister_subdev(sd);
308
309
310
311
312 list_del_init(&sd->async_list);
313 sd->asd = NULL;
314 }
315
316
317 static void
318 v4l2_async_notifier_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
319 {
320 struct v4l2_subdev *sd, *tmp;
321
322 list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) {
323 struct v4l2_async_notifier *subdev_notifier =
324 v4l2_async_find_subdev_notifier(sd);
325
326 if (subdev_notifier)
327 v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
328
329 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
330 v4l2_async_cleanup(sd);
331
332 list_move(&sd->async_list, &subdev_list);
333 }
334
335 notifier->parent = NULL;
336 }
337
338
339 static bool
340 __v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
341 struct v4l2_async_subdev *asd)
342 {
343 struct v4l2_async_subdev *asd_y;
344 struct v4l2_subdev *sd;
345
346 list_for_each_entry(asd_y, ¬ifier->waiting, list)
347 if (asd_equal(asd, asd_y))
348 return true;
349
350 list_for_each_entry(sd, ¬ifier->done, async_list) {
351 if (WARN_ON(!sd->asd))
352 continue;
353
354 if (asd_equal(asd, sd->asd))
355 return true;
356 }
357
358 return false;
359 }
360
361
362
363
364
365
366 static bool
367 v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
368 struct v4l2_async_subdev *asd,
369 int this_index)
370 {
371 struct v4l2_async_subdev *asd_y;
372 int j = 0;
373
374 lockdep_assert_held(&list_lock);
375
376
377 list_for_each_entry(asd_y, ¬ifier->asd_list, asd_list) {
378 if (this_index >= 0 && j++ >= this_index)
379 break;
380 if (asd_equal(asd, asd_y))
381 return true;
382 }
383
384
385 list_for_each_entry(notifier, ¬ifier_list, list)
386 if (__v4l2_async_notifier_has_async_subdev(notifier, asd))
387 return true;
388
389 return false;
390 }
391
392 static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier,
393 struct v4l2_async_subdev *asd,
394 int this_index)
395 {
396 struct device *dev =
397 notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
398
399 if (!asd)
400 return -EINVAL;
401
402 switch (asd->match_type) {
403 case V4L2_ASYNC_MATCH_CUSTOM:
404 case V4L2_ASYNC_MATCH_DEVNAME:
405 case V4L2_ASYNC_MATCH_I2C:
406 case V4L2_ASYNC_MATCH_FWNODE:
407 if (v4l2_async_notifier_has_async_subdev(notifier, asd,
408 this_index)) {
409 dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
410 return -EEXIST;
411 }
412 break;
413 default:
414 dev_err(dev, "Invalid match type %u on %p\n",
415 asd->match_type, asd);
416 return -EINVAL;
417 }
418
419 return 0;
420 }
421
422 void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier)
423 {
424 INIT_LIST_HEAD(¬ifier->asd_list);
425 }
426 EXPORT_SYMBOL(v4l2_async_notifier_init);
427
428 static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
429 {
430 struct v4l2_async_subdev *asd;
431 int ret, i = 0;
432
433 INIT_LIST_HEAD(¬ifier->waiting);
434 INIT_LIST_HEAD(¬ifier->done);
435
436 mutex_lock(&list_lock);
437
438 list_for_each_entry(asd, ¬ifier->asd_list, asd_list) {
439 ret = v4l2_async_notifier_asd_valid(notifier, asd, i++);
440 if (ret)
441 goto err_unlock;
442
443 list_add_tail(&asd->list, ¬ifier->waiting);
444 }
445
446 ret = v4l2_async_notifier_try_all_subdevs(notifier);
447 if (ret < 0)
448 goto err_unbind;
449
450 ret = v4l2_async_notifier_try_complete(notifier);
451 if (ret < 0)
452 goto err_unbind;
453
454
455 list_add(¬ifier->list, ¬ifier_list);
456
457 mutex_unlock(&list_lock);
458
459 return 0;
460
461 err_unbind:
462
463
464
465 v4l2_async_notifier_unbind_all_subdevs(notifier);
466
467 err_unlock:
468 mutex_unlock(&list_lock);
469
470 return ret;
471 }
472
473 int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
474 struct v4l2_async_notifier *notifier)
475 {
476 int ret;
477
478 if (WARN_ON(!v4l2_dev || notifier->sd))
479 return -EINVAL;
480
481 notifier->v4l2_dev = v4l2_dev;
482
483 ret = __v4l2_async_notifier_register(notifier);
484 if (ret)
485 notifier->v4l2_dev = NULL;
486
487 return ret;
488 }
489 EXPORT_SYMBOL(v4l2_async_notifier_register);
490
491 int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
492 struct v4l2_async_notifier *notifier)
493 {
494 int ret;
495
496 if (WARN_ON(!sd || notifier->v4l2_dev))
497 return -EINVAL;
498
499 notifier->sd = sd;
500
501 ret = __v4l2_async_notifier_register(notifier);
502 if (ret)
503 notifier->sd = NULL;
504
505 return ret;
506 }
507 EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
508
509 static void
510 __v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
511 {
512 if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
513 return;
514
515 v4l2_async_notifier_unbind_all_subdevs(notifier);
516
517 notifier->sd = NULL;
518 notifier->v4l2_dev = NULL;
519
520 list_del(¬ifier->list);
521 }
522
523 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
524 {
525 mutex_lock(&list_lock);
526
527 __v4l2_async_notifier_unregister(notifier);
528
529 mutex_unlock(&list_lock);
530 }
531 EXPORT_SYMBOL(v4l2_async_notifier_unregister);
532
533 static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
534 {
535 struct v4l2_async_subdev *asd, *tmp;
536
537 if (!notifier || !notifier->asd_list.next)
538 return;
539
540 list_for_each_entry_safe(asd, tmp, ¬ifier->asd_list, asd_list) {
541 switch (asd->match_type) {
542 case V4L2_ASYNC_MATCH_FWNODE:
543 fwnode_handle_put(asd->match.fwnode);
544 break;
545 default:
546 break;
547 }
548
549 list_del(&asd->asd_list);
550 kfree(asd);
551 }
552 }
553
554 void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
555 {
556 mutex_lock(&list_lock);
557
558 __v4l2_async_notifier_cleanup(notifier);
559
560 mutex_unlock(&list_lock);
561 }
562 EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
563
564 int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier,
565 struct v4l2_async_subdev *asd)
566 {
567 int ret;
568
569 mutex_lock(&list_lock);
570
571 ret = v4l2_async_notifier_asd_valid(notifier, asd, -1);
572 if (ret)
573 goto unlock;
574
575 list_add_tail(&asd->asd_list, ¬ifier->asd_list);
576
577 unlock:
578 mutex_unlock(&list_lock);
579 return ret;
580 }
581 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_subdev);
582
583 struct v4l2_async_subdev *
584 v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,
585 struct fwnode_handle *fwnode,
586 unsigned int asd_struct_size)
587 {
588 struct v4l2_async_subdev *asd;
589 int ret;
590
591 asd = kzalloc(asd_struct_size, GFP_KERNEL);
592 if (!asd)
593 return ERR_PTR(-ENOMEM);
594
595 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
596 asd->match.fwnode = fwnode_handle_get(fwnode);
597
598 ret = v4l2_async_notifier_add_subdev(notifier, asd);
599 if (ret) {
600 fwnode_handle_put(fwnode);
601 kfree(asd);
602 return ERR_PTR(ret);
603 }
604
605 return asd;
606 }
607 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev);
608
609 int
610 v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif,
611 struct fwnode_handle *endpoint,
612 struct v4l2_async_subdev *asd)
613 {
614 struct fwnode_handle *remote;
615 int ret;
616
617 remote = fwnode_graph_get_remote_port_parent(endpoint);
618 if (!remote)
619 return -ENOTCONN;
620
621 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
622 asd->match.fwnode = remote;
623
624 ret = v4l2_async_notifier_add_subdev(notif, asd);
625 if (ret)
626 fwnode_handle_put(remote);
627
628 return ret;
629 }
630 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_remote_subdev);
631
632 struct v4l2_async_subdev *
633 v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier,
634 int adapter_id, unsigned short address,
635 unsigned int asd_struct_size)
636 {
637 struct v4l2_async_subdev *asd;
638 int ret;
639
640 asd = kzalloc(asd_struct_size, GFP_KERNEL);
641 if (!asd)
642 return ERR_PTR(-ENOMEM);
643
644 asd->match_type = V4L2_ASYNC_MATCH_I2C;
645 asd->match.i2c.adapter_id = adapter_id;
646 asd->match.i2c.address = address;
647
648 ret = v4l2_async_notifier_add_subdev(notifier, asd);
649 if (ret) {
650 kfree(asd);
651 return ERR_PTR(ret);
652 }
653
654 return asd;
655 }
656 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_i2c_subdev);
657
658 struct v4l2_async_subdev *
659 v4l2_async_notifier_add_devname_subdev(struct v4l2_async_notifier *notifier,
660 const char *device_name,
661 unsigned int asd_struct_size)
662 {
663 struct v4l2_async_subdev *asd;
664 int ret;
665
666 asd = kzalloc(asd_struct_size, GFP_KERNEL);
667 if (!asd)
668 return ERR_PTR(-ENOMEM);
669
670 asd->match_type = V4L2_ASYNC_MATCH_DEVNAME;
671 asd->match.device_name = device_name;
672
673 ret = v4l2_async_notifier_add_subdev(notifier, asd);
674 if (ret) {
675 kfree(asd);
676 return ERR_PTR(ret);
677 }
678
679 return asd;
680 }
681 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_devname_subdev);
682
683 int v4l2_async_register_subdev(struct v4l2_subdev *sd)
684 {
685 struct v4l2_async_notifier *subdev_notifier;
686 struct v4l2_async_notifier *notifier;
687 int ret;
688
689
690
691
692
693
694 if (!sd->fwnode && sd->dev)
695 sd->fwnode = dev_fwnode(sd->dev);
696
697 mutex_lock(&list_lock);
698
699 INIT_LIST_HEAD(&sd->async_list);
700
701 list_for_each_entry(notifier, ¬ifier_list, list) {
702 struct v4l2_device *v4l2_dev =
703 v4l2_async_notifier_find_v4l2_dev(notifier);
704 struct v4l2_async_subdev *asd;
705
706 if (!v4l2_dev)
707 continue;
708
709 asd = v4l2_async_find_match(notifier, sd);
710 if (!asd)
711 continue;
712
713 ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
714 if (ret)
715 goto err_unbind;
716
717 ret = v4l2_async_notifier_try_complete(notifier);
718 if (ret)
719 goto err_unbind;
720
721 goto out_unlock;
722 }
723
724
725 list_add(&sd->async_list, &subdev_list);
726
727 out_unlock:
728 mutex_unlock(&list_lock);
729
730 return 0;
731
732 err_unbind:
733
734
735
736
737 subdev_notifier = v4l2_async_find_subdev_notifier(sd);
738 if (subdev_notifier)
739 v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
740
741 if (sd->asd)
742 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
743 v4l2_async_cleanup(sd);
744
745 mutex_unlock(&list_lock);
746
747 return ret;
748 }
749 EXPORT_SYMBOL(v4l2_async_register_subdev);
750
751 void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
752 {
753 mutex_lock(&list_lock);
754
755 __v4l2_async_notifier_unregister(sd->subdev_notifier);
756 __v4l2_async_notifier_cleanup(sd->subdev_notifier);
757 kfree(sd->subdev_notifier);
758 sd->subdev_notifier = NULL;
759
760 if (sd->asd) {
761 struct v4l2_async_notifier *notifier = sd->notifier;
762
763 list_add(&sd->asd->list, ¬ifier->waiting);
764
765 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
766 }
767
768 v4l2_async_cleanup(sd);
769
770 mutex_unlock(&list_lock);
771 }
772 EXPORT_SYMBOL(v4l2_async_unregister_subdev);