hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
kernel/drivers/media/v4l2-core/v4l2-async.c
....@@ -1,11 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * V4L2 asynchronous subdevice registration API
34 *
45 * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5
- *
6
- * This program is free software; you can redistribute it and/or modify
7
- * it under the terms of the GNU General Public License version 2 as
8
- * published by the Free Software Foundation.
96 */
107
118 #include <linux/device.h>
....@@ -53,10 +50,12 @@
5350 return n->ops->complete(n);
5451 }
5552
56
-static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
53
+static bool match_i2c(struct v4l2_async_notifier *notifier,
54
+ struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
5755 {
5856 #if IS_ENABLED(CONFIG_I2C)
5957 struct i2c_client *client = i2c_verify_client(sd->dev);
58
+
6059 return client &&
6160 asd->match.i2c.adapter_id == client->adapter->nr &&
6261 asd->match.i2c.address == client->addr;
....@@ -65,18 +64,83 @@
6564 #endif
6665 }
6766
68
-static bool match_devname(struct v4l2_subdev *sd,
69
- struct v4l2_async_subdev *asd)
67
+static bool match_devname(struct v4l2_async_notifier *notifier,
68
+ struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
7069 {
7170 return !strcmp(asd->match.device_name, dev_name(sd->dev));
7271 }
7372
74
-static bool match_fwnode(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
73
+static bool match_fwnode(struct v4l2_async_notifier *notifier,
74
+ struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
7575 {
76
- return sd->fwnode == asd->match.fwnode;
76
+ struct fwnode_handle *other_fwnode;
77
+ struct fwnode_handle *dev_fwnode;
78
+ bool asd_fwnode_is_ep;
79
+ bool sd_fwnode_is_ep;
80
+ struct device *dev;
81
+
82
+ /*
83
+ * Both the subdev and the async subdev can provide either an endpoint
84
+ * fwnode or a device fwnode. Start with the simple case of direct
85
+ * fwnode matching.
86
+ */
87
+ if (sd->fwnode == asd->match.fwnode)
88
+ return true;
89
+
90
+ /*
91
+ * Otherwise, check if the sd fwnode and the asd fwnode refer to an
92
+ * endpoint or a device. If they're of the same type, there's no match.
93
+ * Technically speaking this checks if the nodes refer to a connected
94
+ * endpoint, which is the simplest check that works for both OF and
95
+ * ACPI. This won't make a difference, as drivers should not try to
96
+ * match unconnected endpoints.
97
+ */
98
+ sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd->fwnode);
99
+ asd_fwnode_is_ep = fwnode_graph_is_endpoint(asd->match.fwnode);
100
+
101
+ if (sd_fwnode_is_ep == asd_fwnode_is_ep)
102
+ return false;
103
+
104
+ /*
105
+ * The sd and asd fwnodes are of different types. Get the device fwnode
106
+ * parent of the endpoint fwnode, and compare it with the other fwnode.
107
+ */
108
+ if (sd_fwnode_is_ep) {
109
+ dev_fwnode = fwnode_graph_get_port_parent(sd->fwnode);
110
+ other_fwnode = asd->match.fwnode;
111
+ } else {
112
+ dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
113
+ other_fwnode = sd->fwnode;
114
+ }
115
+
116
+ fwnode_handle_put(dev_fwnode);
117
+
118
+ if (dev_fwnode != other_fwnode)
119
+ return false;
120
+
121
+ /*
122
+ * We have a heterogeneous match. Retrieve the struct device of the side
123
+ * that matched on a device fwnode to print its driver name.
124
+ */
125
+ if (sd_fwnode_is_ep)
126
+ dev = notifier->v4l2_dev ? notifier->v4l2_dev->dev
127
+ : notifier->sd->dev;
128
+ else
129
+ dev = sd->dev;
130
+
131
+ if (dev && dev->driver) {
132
+ if (sd_fwnode_is_ep)
133
+ dev_warn(dev, "Driver %s uses device fwnode, incorrect match may occur\n",
134
+ dev->driver->name);
135
+ dev_notice(dev, "Consider updating driver %s to match on endpoints\n",
136
+ dev->driver->name);
137
+ }
138
+
139
+ return true;
77140 }
78141
79
-static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
142
+static bool match_custom(struct v4l2_async_notifier *notifier,
143
+ struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
80144 {
81145 if (!asd->match.custom.match)
82146 /* Match always */
....@@ -89,10 +153,12 @@
89153 static LIST_HEAD(notifier_list);
90154 static DEFINE_MUTEX(list_lock);
91155
92
-static struct v4l2_async_subdev *v4l2_async_find_match(
93
- struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd)
156
+static struct v4l2_async_subdev *
157
+v4l2_async_find_match(struct v4l2_async_notifier *notifier,
158
+ struct v4l2_subdev *sd)
94159 {
95
- bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *);
160
+ bool (*match)(struct v4l2_async_notifier *notifier,
161
+ struct v4l2_subdev *sd, struct v4l2_async_subdev *asd);
96162 struct v4l2_async_subdev *asd;
97163
98164 list_for_each_entry(asd, &notifier->waiting, list) {
....@@ -117,16 +183,41 @@
117183 }
118184
119185 /* match cannot be NULL here */
120
- if (match(sd, asd))
186
+ if (match(notifier, sd, asd))
121187 return asd;
122188 }
123189
124190 return NULL;
125191 }
126192
193
+/* Compare two async sub-device descriptors for equivalence */
194
+static bool asd_equal(struct v4l2_async_subdev *asd_x,
195
+ struct v4l2_async_subdev *asd_y)
196
+{
197
+ if (asd_x->match_type != asd_y->match_type)
198
+ return false;
199
+
200
+ switch (asd_x->match_type) {
201
+ case V4L2_ASYNC_MATCH_DEVNAME:
202
+ return strcmp(asd_x->match.device_name,
203
+ asd_y->match.device_name) == 0;
204
+ case V4L2_ASYNC_MATCH_I2C:
205
+ return asd_x->match.i2c.adapter_id ==
206
+ asd_y->match.i2c.adapter_id &&
207
+ asd_x->match.i2c.address ==
208
+ asd_y->match.i2c.address;
209
+ case V4L2_ASYNC_MATCH_FWNODE:
210
+ return asd_x->match.fwnode == asd_y->match.fwnode;
211
+ default:
212
+ break;
213
+ }
214
+
215
+ return false;
216
+}
217
+
127218 /* Find the sub-device notifier registered by a sub-device driver. */
128
-static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier(
129
- struct v4l2_subdev *sd)
219
+static struct v4l2_async_notifier *
220
+v4l2_async_find_subdev_notifier(struct v4l2_subdev *sd)
130221 {
131222 struct v4l2_async_notifier *n;
132223
....@@ -138,8 +229,8 @@
138229 }
139230
140231 /* Get v4l2_device related to the notifier if one can be found. */
141
-static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev(
142
- struct v4l2_async_notifier *notifier)
232
+static struct v4l2_device *
233
+v4l2_async_notifier_find_v4l2_dev(struct v4l2_async_notifier *notifier)
143234 {
144235 while (notifier->parent)
145236 notifier = notifier->parent;
....@@ -150,8 +241,8 @@
150241 /*
151242 * Return true if all child sub-device notifiers are complete, false otherwise.
152243 */
153
-static bool v4l2_async_notifier_can_complete(
154
- struct v4l2_async_notifier *notifier)
244
+static bool
245
+v4l2_async_notifier_can_complete(struct v4l2_async_notifier *notifier)
155246 {
156247 struct v4l2_subdev *sd;
157248
....@@ -174,8 +265,8 @@
174265 * Complete the master notifier if possible. This is done when all async
175266 * sub-devices have been bound; v4l2_device is also available then.
176267 */
177
-static int v4l2_async_notifier_try_complete(
178
- struct v4l2_async_notifier *notifier)
268
+static int
269
+v4l2_async_notifier_try_complete(struct v4l2_async_notifier *notifier)
179270 {
180271 /* Quick check whether there are still more sub-devices here. */
181272 if (!list_empty(&notifier->waiting))
....@@ -196,8 +287,8 @@
196287 return v4l2_async_notifier_call_complete(notifier);
197288 }
198289
199
-static int v4l2_async_notifier_try_all_subdevs(
200
- struct v4l2_async_notifier *notifier);
290
+static int
291
+v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier);
201292
202293 static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
203294 struct v4l2_device *v4l2_dev,
....@@ -243,8 +334,8 @@
243334 }
244335
245336 /* Test all async sub-devices in a notifier for a match. */
246
-static int v4l2_async_notifier_try_all_subdevs(
247
- struct v4l2_async_notifier *notifier)
337
+static int
338
+v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier)
248339 {
249340 struct v4l2_device *v4l2_dev =
250341 v4l2_async_notifier_find_v4l2_dev(notifier);
....@@ -281,14 +372,17 @@
281372 static void v4l2_async_cleanup(struct v4l2_subdev *sd)
282373 {
283374 v4l2_device_unregister_subdev(sd);
284
- /* Subdevice driver will reprobe and put the subdev back onto the list */
375
+ /*
376
+ * Subdevice driver will reprobe and put the subdev back
377
+ * onto the list
378
+ */
285379 list_del_init(&sd->async_list);
286380 sd->asd = NULL;
287381 }
288382
289383 /* Unbind all sub-devices in the notifier tree. */
290
-static void v4l2_async_notifier_unbind_all_subdevs(
291
- struct v4l2_async_notifier *notifier)
384
+static void
385
+v4l2_async_notifier_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
292386 {
293387 struct v4l2_subdev *sd, *tmp;
294388
....@@ -308,29 +402,23 @@
308402 notifier->parent = NULL;
309403 }
310404
311
-/* See if an fwnode can be found in a notifier's lists. */
312
-static bool __v4l2_async_notifier_fwnode_has_async_subdev(
313
- struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
405
+/* See if an async sub-device can be found in a notifier's lists. */
406
+static bool
407
+__v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
408
+ struct v4l2_async_subdev *asd)
314409 {
315
- struct v4l2_async_subdev *asd;
410
+ struct v4l2_async_subdev *asd_y;
316411 struct v4l2_subdev *sd;
317412
318
- list_for_each_entry(asd, &notifier->waiting, list) {
319
- if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
320
- continue;
321
-
322
- if (asd->match.fwnode == fwnode)
413
+ list_for_each_entry(asd_y, &notifier->waiting, list)
414
+ if (asd_equal(asd, asd_y))
323415 return true;
324
- }
325416
326417 list_for_each_entry(sd, &notifier->done, async_list) {
327418 if (WARN_ON(!sd->asd))
328419 continue;
329420
330
- if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
331
- continue;
332
-
333
- if (sd->asd->match.fwnode == fwnode)
421
+ if (asd_equal(asd, sd->asd))
334422 return true;
335423 }
336424
....@@ -338,76 +426,87 @@
338426 }
339427
340428 /*
341
- * Find out whether an async sub-device was set up for an fwnode already or
429
+ * Find out whether an async sub-device was set up already or
342430 * whether it exists in a given notifier before @this_index.
431
+ * If @this_index < 0, search the notifier's entire @asd_list.
343432 */
344
-static bool v4l2_async_notifier_fwnode_has_async_subdev(
345
- struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
346
- unsigned int this_index)
433
+static bool
434
+v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
435
+ struct v4l2_async_subdev *asd,
436
+ int this_index)
347437 {
348
- unsigned int j;
438
+ struct v4l2_async_subdev *asd_y;
439
+ int j = 0;
349440
350441 lockdep_assert_held(&list_lock);
351442
352
- /* Check that an fwnode is not being added more than once. */
353
- for (j = 0; j < this_index; j++) {
354
- struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
355
- struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
356
-
357
- if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
358
- asd->match.fwnode ==
359
- other_asd->match.fwnode)
443
+ /* Check that an asd is not being added more than once. */
444
+ list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
445
+ if (this_index >= 0 && j++ >= this_index)
446
+ break;
447
+ if (asd_equal(asd, asd_y))
360448 return true;
361449 }
362450
363
- /* Check than an fwnode did not exist in other notifiers. */
451
+ /* Check that an asd does not exist in other notifiers. */
364452 list_for_each_entry(notifier, &notifier_list, list)
365
- if (__v4l2_async_notifier_fwnode_has_async_subdev(
366
- notifier, fwnode))
453
+ if (__v4l2_async_notifier_has_async_subdev(notifier, asd))
367454 return true;
368455
369456 return false;
370457 }
371458
372
-static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
459
+static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier,
460
+ struct v4l2_async_subdev *asd,
461
+ int this_index)
373462 {
374463 struct device *dev =
375464 notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
376
- struct v4l2_async_subdev *asd;
377
- int ret;
378
- int i;
379465
380
- if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
466
+ if (!asd)
381467 return -EINVAL;
468
+
469
+ switch (asd->match_type) {
470
+ case V4L2_ASYNC_MATCH_CUSTOM:
471
+ case V4L2_ASYNC_MATCH_DEVNAME:
472
+ case V4L2_ASYNC_MATCH_I2C:
473
+ case V4L2_ASYNC_MATCH_FWNODE:
474
+ if (v4l2_async_notifier_has_async_subdev(notifier, asd,
475
+ this_index)) {
476
+ dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
477
+ return -EEXIST;
478
+ }
479
+ break;
480
+ default:
481
+ dev_err(dev, "Invalid match type %u on %p\n",
482
+ asd->match_type, asd);
483
+ return -EINVAL;
484
+ }
485
+
486
+ return 0;
487
+}
488
+
489
+void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier)
490
+{
491
+ INIT_LIST_HEAD(&notifier->asd_list);
492
+}
493
+EXPORT_SYMBOL(v4l2_async_notifier_init);
494
+
495
+static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
496
+{
497
+ struct v4l2_async_subdev *asd;
498
+ int ret, i = 0;
382499
383500 INIT_LIST_HEAD(&notifier->waiting);
384501 INIT_LIST_HEAD(&notifier->done);
385502
386503 mutex_lock(&list_lock);
387504
388
- for (i = 0; i < notifier->num_subdevs; i++) {
389
- asd = notifier->subdevs[i];
390
-
391
- switch (asd->match_type) {
392
- case V4L2_ASYNC_MATCH_CUSTOM:
393
- case V4L2_ASYNC_MATCH_DEVNAME:
394
- case V4L2_ASYNC_MATCH_I2C:
395
- break;
396
- case V4L2_ASYNC_MATCH_FWNODE:
397
- if (v4l2_async_notifier_fwnode_has_async_subdev(
398
- notifier, asd->match.fwnode, i)) {
399
- dev_err(dev,
400
- "fwnode has already been registered or in notifier's subdev list\n");
401
- ret = -EEXIST;
402
- goto err_unlock;
403
- }
404
- break;
405
- default:
406
- dev_err(dev, "Invalid match type %u on %p\n",
407
- asd->match_type, asd);
408
- ret = -EINVAL;
505
+ list_for_each_entry(asd, &notifier->asd_list, asd_list) {
506
+ ret = v4l2_async_notifier_asd_valid(notifier, asd, i++);
507
+ if (ret)
409508 goto err_unlock;
410
- }
509
+
411510 list_add_tail(&asd->list, &notifier->waiting);
412511 }
413512
....@@ -456,6 +555,7 @@
456555 }
457556 EXPORT_SYMBOL(v4l2_async_notifier_register);
458557
558
+#if IS_ENABLED(CONFIG_NO_GKI)
459559 static int __v4l2_async_notifier_clr_unready_dev(
460560 struct v4l2_async_notifier *notifier)
461561 {
....@@ -507,6 +607,7 @@
507607 return ret;
508608 }
509609 EXPORT_SYMBOL(v4l2_async_notifier_clr_unready_dev);
610
+#endif
510611
511612 int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
512613 struct v4l2_async_notifier *notifier)
....@@ -526,8 +627,8 @@
526627 }
527628 EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
528629
529
-static void __v4l2_async_notifier_unregister(
530
- struct v4l2_async_notifier *notifier)
630
+static void
631
+__v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
531632 {
532633 if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
533634 return;
....@@ -550,35 +651,155 @@
550651 }
551652 EXPORT_SYMBOL(v4l2_async_notifier_unregister);
552653
553
-void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
654
+static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
554655 {
555
- unsigned int i;
656
+ struct v4l2_async_subdev *asd, *tmp;
556657
557
- if (!notifier || !notifier->max_subdevs)
658
+ if (!notifier || !notifier->asd_list.next)
558659 return;
559660
560
- for (i = 0; i < notifier->num_subdevs; i++) {
561
- struct v4l2_async_subdev *asd = notifier->subdevs[i];
562
-
661
+ list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
563662 switch (asd->match_type) {
564663 case V4L2_ASYNC_MATCH_FWNODE:
565664 fwnode_handle_put(asd->match.fwnode);
566665 break;
567666 default:
568
- WARN_ON_ONCE(true);
569667 break;
570668 }
571669
670
+ list_del(&asd->asd_list);
572671 kfree(asd);
573672 }
673
+}
574674
575
- notifier->max_subdevs = 0;
576
- notifier->num_subdevs = 0;
675
+void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
676
+{
677
+ mutex_lock(&list_lock);
577678
578
- kvfree(notifier->subdevs);
579
- notifier->subdevs = NULL;
679
+ __v4l2_async_notifier_cleanup(notifier);
680
+
681
+ mutex_unlock(&list_lock);
580682 }
581683 EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
684
+
685
+int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier,
686
+ struct v4l2_async_subdev *asd)
687
+{
688
+ int ret;
689
+
690
+ mutex_lock(&list_lock);
691
+
692
+ ret = v4l2_async_notifier_asd_valid(notifier, asd, -1);
693
+ if (ret)
694
+ goto unlock;
695
+
696
+ list_add_tail(&asd->asd_list, &notifier->asd_list);
697
+
698
+unlock:
699
+ mutex_unlock(&list_lock);
700
+ return ret;
701
+}
702
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_subdev);
703
+
704
+struct v4l2_async_subdev *
705
+v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,
706
+ struct fwnode_handle *fwnode,
707
+ unsigned int asd_struct_size)
708
+{
709
+ struct v4l2_async_subdev *asd;
710
+ int ret;
711
+
712
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
713
+ if (!asd)
714
+ return ERR_PTR(-ENOMEM);
715
+
716
+ asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
717
+ asd->match.fwnode = fwnode_handle_get(fwnode);
718
+
719
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
720
+ if (ret) {
721
+ fwnode_handle_put(fwnode);
722
+ kfree(asd);
723
+ return ERR_PTR(ret);
724
+ }
725
+
726
+ return asd;
727
+}
728
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev);
729
+
730
+struct v4l2_async_subdev *
731
+v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif,
732
+ struct fwnode_handle *endpoint,
733
+ unsigned int asd_struct_size)
734
+{
735
+ struct v4l2_async_subdev *asd;
736
+ struct fwnode_handle *remote;
737
+
738
+ remote = fwnode_graph_get_remote_port_parent(endpoint);
739
+ if (!remote)
740
+ return ERR_PTR(-ENOTCONN);
741
+
742
+ asd = v4l2_async_notifier_add_fwnode_subdev(notif, remote,
743
+ asd_struct_size);
744
+ /*
745
+ * Calling v4l2_async_notifier_add_fwnode_subdev grabs a refcount,
746
+ * so drop the one we got in fwnode_graph_get_remote_port_parent.
747
+ */
748
+ fwnode_handle_put(remote);
749
+ return asd;
750
+}
751
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_remote_subdev);
752
+
753
+struct v4l2_async_subdev *
754
+v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier,
755
+ int adapter_id, unsigned short address,
756
+ unsigned int asd_struct_size)
757
+{
758
+ struct v4l2_async_subdev *asd;
759
+ int ret;
760
+
761
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
762
+ if (!asd)
763
+ return ERR_PTR(-ENOMEM);
764
+
765
+ asd->match_type = V4L2_ASYNC_MATCH_I2C;
766
+ asd->match.i2c.adapter_id = adapter_id;
767
+ asd->match.i2c.address = address;
768
+
769
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
770
+ if (ret) {
771
+ kfree(asd);
772
+ return ERR_PTR(ret);
773
+ }
774
+
775
+ return asd;
776
+}
777
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_i2c_subdev);
778
+
779
+struct v4l2_async_subdev *
780
+v4l2_async_notifier_add_devname_subdev(struct v4l2_async_notifier *notifier,
781
+ const char *device_name,
782
+ unsigned int asd_struct_size)
783
+{
784
+ struct v4l2_async_subdev *asd;
785
+ int ret;
786
+
787
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
788
+ if (!asd)
789
+ return ERR_PTR(-ENOMEM);
790
+
791
+ asd->match_type = V4L2_ASYNC_MATCH_DEVNAME;
792
+ asd->match.device_name = device_name;
793
+
794
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
795
+ if (ret) {
796
+ kfree(asd);
797
+ return ERR_PTR(ret);
798
+ }
799
+
800
+ return asd;
801
+}
802
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_devname_subdev);
582803
583804 int v4l2_async_register_subdev(struct v4l2_subdev *sd)
584805 {
....@@ -653,7 +874,7 @@
653874 mutex_lock(&list_lock);
654875
655876 __v4l2_async_notifier_unregister(sd->subdev_notifier);
656
- v4l2_async_notifier_cleanup(sd->subdev_notifier);
877
+ __v4l2_async_notifier_cleanup(sd->subdev_notifier);
657878 kfree(sd->subdev_notifier);
658879 sd->subdev_notifier = NULL;
659880