blob: a6d91370838d934295d812051e8d7c55f35adc2d [file] [log] [blame]
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -03001/*
2 * V4L2 asynchronous subdevice registration API
3 *
4 * 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.
9 */
10
11#include <linux/device.h>
12#include <linux/err.h>
13#include <linux/i2c.h>
14#include <linux/list.h>
Tomasz Figa758d90e2017-06-19 00:53:43 -030015#include <linux/mm.h>
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030016#include <linux/module.h>
17#include <linux/mutex.h>
Sakari Ailusecdf0cf2016-08-16 06:54:59 -030018#include <linux/of.h>
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030019#include <linux/platform_device.h>
20#include <linux/slab.h>
21#include <linux/types.h>
22
23#include <media/v4l2-async.h>
24#include <media/v4l2-device.h>
Sakari Ailus9ca46532017-08-17 11:28:21 -040025#include <media/v4l2-fwnode.h>
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030026#include <media/v4l2-subdev.h>
27
Sakari Ailusddddc182017-09-01 08:27:32 -040028static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
29 struct v4l2_subdev *subdev,
30 struct v4l2_async_subdev *asd)
31{
32 if (!n->ops || !n->ops->bound)
33 return 0;
34
35 return n->ops->bound(n, subdev, asd);
36}
37
38static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
39 struct v4l2_subdev *subdev,
40 struct v4l2_async_subdev *asd)
41{
42 if (!n->ops || !n->ops->unbind)
43 return;
44
45 n->ops->unbind(n, subdev, asd);
46}
47
48static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
49{
50 if (!n->ops || !n->ops->complete)
51 return 0;
52
53 return n->ops->complete(n);
54}
55
Sakari Ailus86217652015-06-11 12:18:01 -070056static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030057{
Guennadi Liakhovetskife05e142013-06-24 05:13:51 -030058#if IS_ENABLED(CONFIG_I2C)
Sakari Ailus86217652015-06-11 12:18:01 -070059 struct i2c_client *client = i2c_verify_client(sd->dev);
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -040060
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030061 return client &&
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030062 asd->match.i2c.adapter_id == client->adapter->nr &&
63 asd->match.i2c.address == client->addr;
Guennadi Liakhovetskife05e142013-06-24 05:13:51 -030064#else
65 return false;
66#endif
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030067}
68
Sakari Ailus86217652015-06-11 12:18:01 -070069static bool match_devname(struct v4l2_subdev *sd,
70 struct v4l2_async_subdev *asd)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030071{
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -040072 return !strcmp(asd->match.device_name, dev_name(sd->dev));
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030073}
74
Sakari Ailusecdf0cf2016-08-16 06:54:59 -030075static bool match_fwnode(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
76{
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -040077 return sd->fwnode == asd->match.fwnode;
Sakari Ailusecdf0cf2016-08-16 06:54:59 -030078}
79
Sakari Ailus86217652015-06-11 12:18:01 -070080static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
81{
82 if (!asd->match.custom.match)
83 /* Match always */
84 return true;
85
86 return asd->match.custom.match(sd->dev, asd);
Sylwester Nawrockie7359f82013-07-19 12:21:29 -030087}
88
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030089static LIST_HEAD(subdev_list);
90static LIST_HEAD(notifier_list);
91static DEFINE_MUTEX(list_lock);
92
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -040093static struct v4l2_async_subdev *
94v4l2_async_find_match(struct v4l2_async_notifier *notifier,
95 struct v4l2_subdev *sd)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030096{
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -040097 bool (*match)(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030098 struct v4l2_async_subdev *asd;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -030099
100 list_for_each_entry(asd, &notifier->waiting, list) {
101 /* bus_type has been verified valid before */
Sylwester Nawrockicfca7642013-07-19 12:14:46 -0300102 switch (asd->match_type) {
103 case V4L2_ASYNC_MATCH_CUSTOM:
Sakari Ailus86217652015-06-11 12:18:01 -0700104 match = match_custom;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300105 break;
Sylwester Nawrockicfca7642013-07-19 12:14:46 -0300106 case V4L2_ASYNC_MATCH_DEVNAME:
107 match = match_devname;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300108 break;
Sylwester Nawrockicfca7642013-07-19 12:14:46 -0300109 case V4L2_ASYNC_MATCH_I2C:
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300110 match = match_i2c;
111 break;
Sakari Ailusecdf0cf2016-08-16 06:54:59 -0300112 case V4L2_ASYNC_MATCH_FWNODE:
113 match = match_fwnode;
114 break;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300115 default:
116 /* Cannot happen, unless someone breaks us */
117 WARN_ON(true);
118 return NULL;
119 }
120
121 /* match cannot be NULL here */
Sakari Ailus86217652015-06-11 12:18:01 -0700122 if (match(sd, asd))
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300123 return asd;
124 }
125
126 return NULL;
127}
128
Steve Longerbeama6e70032018-09-29 15:54:05 -0400129/* Compare two async sub-device descriptors for equivalence */
130static bool asd_equal(struct v4l2_async_subdev *asd_x,
131 struct v4l2_async_subdev *asd_y)
132{
133 if (asd_x->match_type != asd_y->match_type)
134 return false;
135
136 switch (asd_x->match_type) {
137 case V4L2_ASYNC_MATCH_DEVNAME:
138 return strcmp(asd_x->match.device_name,
139 asd_y->match.device_name) == 0;
140 case V4L2_ASYNC_MATCH_I2C:
141 return asd_x->match.i2c.adapter_id ==
142 asd_y->match.i2c.adapter_id &&
143 asd_x->match.i2c.address ==
144 asd_y->match.i2c.address;
145 case V4L2_ASYNC_MATCH_FWNODE:
146 return asd_x->match.fwnode == asd_y->match.fwnode;
147 default:
148 break;
149 }
150
151 return false;
152}
153
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400154/* Find the sub-device notifier registered by a sub-device driver. */
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -0400155static struct v4l2_async_notifier *
156v4l2_async_find_subdev_notifier(struct v4l2_subdev *sd)
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400157{
158 struct v4l2_async_notifier *n;
159
160 list_for_each_entry(n, &notifier_list, list)
161 if (n->sd == sd)
162 return n;
163
164 return NULL;
165}
166
167/* Get v4l2_device related to the notifier if one can be found. */
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -0400168static struct v4l2_device *
169v4l2_async_notifier_find_v4l2_dev(struct v4l2_async_notifier *notifier)
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400170{
171 while (notifier->parent)
172 notifier = notifier->parent;
173
174 return notifier->v4l2_dev;
175}
176
177/*
178 * Return true if all child sub-device notifiers are complete, false otherwise.
179 */
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -0400180static bool
181v4l2_async_notifier_can_complete(struct v4l2_async_notifier *notifier)
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400182{
183 struct v4l2_subdev *sd;
184
185 if (!list_empty(&notifier->waiting))
186 return false;
187
188 list_for_each_entry(sd, &notifier->done, async_list) {
189 struct v4l2_async_notifier *subdev_notifier =
190 v4l2_async_find_subdev_notifier(sd);
191
192 if (subdev_notifier &&
193 !v4l2_async_notifier_can_complete(subdev_notifier))
194 return false;
195 }
196
197 return true;
198}
199
200/*
201 * Complete the master notifier if possible. This is done when all async
202 * sub-devices have been bound; v4l2_device is also available then.
203 */
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -0400204static int
205v4l2_async_notifier_try_complete(struct v4l2_async_notifier *notifier)
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400206{
207 /* Quick check whether there are still more sub-devices here. */
208 if (!list_empty(&notifier->waiting))
209 return 0;
210
211 /* Check the entire notifier tree; find the root notifier first. */
212 while (notifier->parent)
213 notifier = notifier->parent;
214
215 /* This is root if it has v4l2_dev. */
216 if (!notifier->v4l2_dev)
217 return 0;
218
219 /* Is everything ready? */
220 if (!v4l2_async_notifier_can_complete(notifier))
221 return 0;
222
223 return v4l2_async_notifier_call_complete(notifier);
224}
225
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -0400226static int
227v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier);
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400228
Sakari Ailusc8114d92017-09-04 12:44:39 -0400229static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
Sakari Ailusa3620cb2017-09-24 20:48:08 -0400230 struct v4l2_device *v4l2_dev,
Sakari Ailusc8114d92017-09-04 12:44:39 -0400231 struct v4l2_subdev *sd,
232 struct v4l2_async_subdev *asd)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300233{
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400234 struct v4l2_async_notifier *subdev_notifier;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300235 int ret;
236
Sakari Ailusa3620cb2017-09-24 20:48:08 -0400237 ret = v4l2_device_register_subdev(v4l2_dev, sd);
Sakari Ailusddddc182017-09-01 08:27:32 -0400238 if (ret < 0)
239 return ret;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300240
Sakari Ailus24def9b2017-07-17 10:04:20 -0400241 ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300242 if (ret < 0) {
Sakari Ailus24def9b2017-07-17 10:04:20 -0400243 v4l2_device_unregister_subdev(sd);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300244 return ret;
245 }
246
Tuukka Toivonen47b037a2017-01-27 08:32:56 -0200247 /* Remove from the waiting list */
248 list_del(&asd->list);
249 sd->asd = asd;
250 sd->notifier = notifier;
251
252 /* Move from the global subdevice list to notifier's done */
253 list_move(&sd->async_list, &notifier->done);
254
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400255 /*
256 * See if the sub-device has a notifier. If not, return here.
257 */
258 subdev_notifier = v4l2_async_find_subdev_notifier(sd);
259 if (!subdev_notifier || subdev_notifier->parent)
260 return 0;
261
262 /*
263 * Proceed with checking for the sub-device notifier's async
264 * sub-devices, and return the result. The error will be handled by the
265 * caller.
266 */
267 subdev_notifier->parent = notifier;
268
269 return v4l2_async_notifier_try_all_subdevs(subdev_notifier);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300270}
271
Sakari Ailusa3620cb2017-09-24 20:48:08 -0400272/* Test all async sub-devices in a notifier for a match. */
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -0400273static int
274v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier)
Sakari Ailusa3620cb2017-09-24 20:48:08 -0400275{
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400276 struct v4l2_device *v4l2_dev =
277 v4l2_async_notifier_find_v4l2_dev(notifier);
278 struct v4l2_subdev *sd;
Sakari Ailusa3620cb2017-09-24 20:48:08 -0400279
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400280 if (!v4l2_dev)
281 return 0;
282
283again:
284 list_for_each_entry(sd, &subdev_list, async_list) {
Sakari Ailusa3620cb2017-09-24 20:48:08 -0400285 struct v4l2_async_subdev *asd;
286 int ret;
287
288 asd = v4l2_async_find_match(notifier, sd);
289 if (!asd)
290 continue;
291
292 ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
293 if (ret < 0)
294 return ret;
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400295
296 /*
297 * v4l2_async_match_notify() may lead to registering a
298 * new notifier and thus changing the async subdevs
299 * list. In order to proceed safely from here, restart
300 * parsing the list from the beginning.
301 */
302 goto again;
Sakari Ailusa3620cb2017-09-24 20:48:08 -0400303 }
304
305 return 0;
306}
307
Sylwester Nawrockib426b3a2013-07-22 08:01:33 -0300308static void v4l2_async_cleanup(struct v4l2_subdev *sd)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300309{
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300310 v4l2_device_unregister_subdev(sd);
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -0400311 /*
312 * Subdevice driver will reprobe and put the subdev back
313 * onto the list
314 */
Sylwester Nawrockib426b3a2013-07-22 08:01:33 -0300315 list_del_init(&sd->async_list);
316 sd->asd = NULL;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300317}
318
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400319/* Unbind all sub-devices in the notifier tree. */
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -0400320static void
321v4l2_async_notifier_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
Sakari Ailusfb45f432017-10-02 06:24:54 -0400322{
323 struct v4l2_subdev *sd, *tmp;
324
325 list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400326 struct v4l2_async_notifier *subdev_notifier =
327 v4l2_async_find_subdev_notifier(sd);
328
329 if (subdev_notifier)
330 v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
331
Sakari Ailusddddc182017-09-01 08:27:32 -0400332 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400333 v4l2_async_cleanup(sd);
334
335 list_move(&sd->async_list, &subdev_list);
336 }
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400337
338 notifier->parent = NULL;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400339}
340
Steve Longerbeama6e70032018-09-29 15:54:05 -0400341/* See if an async sub-device can be found in a notifier's lists. */
342static bool
343__v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
344 struct v4l2_async_subdev *asd)
Sakari Ailus466cae62017-09-20 03:51:54 -0400345{
Steve Longerbeama6e70032018-09-29 15:54:05 -0400346 struct v4l2_async_subdev *asd_y;
Sakari Ailus466cae62017-09-20 03:51:54 -0400347 struct v4l2_subdev *sd;
348
Steve Longerbeama6e70032018-09-29 15:54:05 -0400349 list_for_each_entry(asd_y, &notifier->waiting, list)
350 if (asd_equal(asd, asd_y))
Sakari Ailus466cae62017-09-20 03:51:54 -0400351 return true;
Sakari Ailus466cae62017-09-20 03:51:54 -0400352
353 list_for_each_entry(sd, &notifier->done, async_list) {
354 if (WARN_ON(!sd->asd))
355 continue;
356
Steve Longerbeama6e70032018-09-29 15:54:05 -0400357 if (asd_equal(asd, sd->asd))
Sakari Ailus466cae62017-09-20 03:51:54 -0400358 return true;
359 }
360
361 return false;
362}
363
364/*
Steve Longerbeama6e70032018-09-29 15:54:05 -0400365 * Find out whether an async sub-device was set up already or
Sakari Ailus466cae62017-09-20 03:51:54 -0400366 * whether it exists in a given notifier before @this_index.
Steve Longerbeam66beb322018-09-29 15:54:19 -0400367 * If @this_index < 0, search the notifier's entire @asd_list.
Sakari Ailus466cae62017-09-20 03:51:54 -0400368 */
Steve Longerbeama6e70032018-09-29 15:54:05 -0400369static bool
370v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
371 struct v4l2_async_subdev *asd,
Steve Longerbeam66beb322018-09-29 15:54:19 -0400372 int this_index)
Sakari Ailus466cae62017-09-20 03:51:54 -0400373{
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400374 struct v4l2_async_subdev *asd_y;
Steve Longerbeam66beb322018-09-29 15:54:19 -0400375 int j = 0;
Sakari Ailus466cae62017-09-20 03:51:54 -0400376
377 lockdep_assert_held(&list_lock);
378
Steve Longerbeama6e70032018-09-29 15:54:05 -0400379 /* Check that an asd is not being added more than once. */
Steve Longerbeam66beb322018-09-29 15:54:19 -0400380 list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
381 if (this_index >= 0 && j++ >= this_index)
382 break;
383 if (asd_equal(asd, asd_y))
384 return true;
Sakari Ailus466cae62017-09-20 03:51:54 -0400385 }
386
Steve Longerbeama6e70032018-09-29 15:54:05 -0400387 /* Check that an asd does not exist in other notifiers. */
Sakari Ailus466cae62017-09-20 03:51:54 -0400388 list_for_each_entry(notifier, &notifier_list, list)
Steve Longerbeama6e70032018-09-29 15:54:05 -0400389 if (__v4l2_async_notifier_has_async_subdev(notifier, asd))
Sakari Ailus466cae62017-09-20 03:51:54 -0400390 return true;
391
392 return false;
393}
394
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400395static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier,
396 struct v4l2_async_subdev *asd,
Steve Longerbeam66beb322018-09-29 15:54:19 -0400397 int this_index)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300398{
Sakari Ailus466cae62017-09-20 03:51:54 -0400399 struct device *dev =
400 notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400401
402 if (!asd)
403 return -EINVAL;
404
405 switch (asd->match_type) {
406 case V4L2_ASYNC_MATCH_CUSTOM:
407 case V4L2_ASYNC_MATCH_DEVNAME:
408 case V4L2_ASYNC_MATCH_I2C:
409 case V4L2_ASYNC_MATCH_FWNODE:
410 if (v4l2_async_notifier_has_async_subdev(notifier, asd,
411 this_index)) {
412 dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
413 return -EEXIST;
414 }
415 break;
416 default:
417 dev_err(dev, "Invalid match type %u on %p\n",
418 asd->match_type, asd);
419 return -EINVAL;
420 }
421
422 return 0;
423}
424
425void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier)
426{
427 mutex_lock(&list_lock);
428
429 INIT_LIST_HEAD(&notifier->asd_list);
430
431 mutex_unlock(&list_lock);
432}
433EXPORT_SYMBOL(v4l2_async_notifier_init);
434
435static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
436{
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300437 struct v4l2_async_subdev *asd;
Steve Longerbeam66beb322018-09-29 15:54:19 -0400438 int ret, i = 0;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300439
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300440 INIT_LIST_HEAD(&notifier->waiting);
441 INIT_LIST_HEAD(&notifier->done);
442
Sakari Ailus466cae62017-09-20 03:51:54 -0400443 mutex_lock(&list_lock);
444
Steve Longerbeam66beb322018-09-29 15:54:19 -0400445 list_for_each_entry(asd, &notifier->asd_list, asd_list) {
446 ret = v4l2_async_notifier_asd_valid(notifier, asd, i++);
447 if (ret)
448 goto err_unlock;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300449
Steve Longerbeam66beb322018-09-29 15:54:19 -0400450 list_add_tail(&asd->list, &notifier->waiting);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300451 }
452
Sakari Ailusa3620cb2017-09-24 20:48:08 -0400453 ret = v4l2_async_notifier_try_all_subdevs(notifier);
Sakari Ailus466cae62017-09-20 03:51:54 -0400454 if (ret < 0)
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400455 goto err_unbind;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300456
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400457 ret = v4l2_async_notifier_try_complete(notifier);
Sakari Ailus466cae62017-09-20 03:51:54 -0400458 if (ret < 0)
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400459 goto err_unbind;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400460
Tuukka Toivonen47b037a2017-01-27 08:32:56 -0200461 /* Keep also completed notifiers on the list */
462 list_add(&notifier->list, &notifier_list);
463
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300464 mutex_unlock(&list_lock);
465
466 return 0;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400467
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400468err_unbind:
469 /*
470 * On failure, unbind all sub-devices registered through this notifier.
471 */
Sakari Ailusfb45f432017-10-02 06:24:54 -0400472 v4l2_async_notifier_unbind_all_subdevs(notifier);
473
Sakari Ailus466cae62017-09-20 03:51:54 -0400474err_unlock:
Sakari Ailusfb45f432017-10-02 06:24:54 -0400475 mutex_unlock(&list_lock);
476
477 return ret;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300478}
Sakari Ailusa3620cb2017-09-24 20:48:08 -0400479
480int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
481 struct v4l2_async_notifier *notifier)
482{
483 int ret;
484
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400485 if (WARN_ON(!v4l2_dev || notifier->sd))
Sakari Ailusa3620cb2017-09-24 20:48:08 -0400486 return -EINVAL;
487
488 notifier->v4l2_dev = v4l2_dev;
489
490 ret = __v4l2_async_notifier_register(notifier);
491 if (ret)
492 notifier->v4l2_dev = NULL;
493
494 return ret;
495}
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300496EXPORT_SYMBOL(v4l2_async_notifier_register);
497
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400498int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
499 struct v4l2_async_notifier *notifier)
500{
501 int ret;
502
503 if (WARN_ON(!sd || notifier->v4l2_dev))
504 return -EINVAL;
505
506 notifier->sd = sd;
507
508 ret = __v4l2_async_notifier_register(notifier);
509 if (ret)
510 notifier->sd = NULL;
511
512 return ret;
513}
514EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
515
Mauro Carvalho Chehab6087b212018-10-04 17:10:46 -0400516static void
517__v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300518{
Sakari Ailusaef69d52017-09-24 18:47:44 -0400519 if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
Laurent Pinchart8e3fbfe2013-07-03 07:49:06 -0300520 return;
521
Sakari Ailusfb45f432017-10-02 06:24:54 -0400522 v4l2_async_notifier_unbind_all_subdevs(notifier);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300523
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400524 notifier->sd = NULL;
Laurent Pinchart8e3fbfe2013-07-03 07:49:06 -0300525 notifier->v4l2_dev = NULL;
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400526
527 list_del(&notifier->list);
Sakari Ailusaef69d52017-09-24 18:47:44 -0400528}
529
530void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
531{
532 mutex_lock(&list_lock);
533
534 __v4l2_async_notifier_unregister(notifier);
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400535
536 mutex_unlock(&list_lock);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300537}
538EXPORT_SYMBOL(v4l2_async_notifier_unregister);
539
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400540static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
Sakari Ailus9ca46532017-08-17 11:28:21 -0400541{
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400542 struct v4l2_async_subdev *asd, *tmp;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400543
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400544 if (!notifier)
Sakari Ailus9ca46532017-08-17 11:28:21 -0400545 return;
546
Steve Longerbeam66beb322018-09-29 15:54:19 -0400547 list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
548 switch (asd->match_type) {
549 case V4L2_ASYNC_MATCH_FWNODE:
550 fwnode_handle_put(asd->match.fwnode);
551 break;
552 default:
553 break;
Sakari Ailus9ca46532017-08-17 11:28:21 -0400554 }
555
Steve Longerbeam66beb322018-09-29 15:54:19 -0400556 list_del(&asd->asd_list);
557 kfree(asd);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400558 }
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400559}
Sakari Ailus9ca46532017-08-17 11:28:21 -0400560
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400561void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
562{
563 mutex_lock(&list_lock);
564
565 __v4l2_async_notifier_cleanup(notifier);
566
567 mutex_unlock(&list_lock);
Sakari Ailus9ca46532017-08-17 11:28:21 -0400568}
569EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
570
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400571int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier,
572 struct v4l2_async_subdev *asd)
573{
574 int ret;
575
576 mutex_lock(&list_lock);
577
Steve Longerbeam66beb322018-09-29 15:54:19 -0400578 ret = v4l2_async_notifier_asd_valid(notifier, asd, -1);
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400579 if (ret)
580 goto unlock;
581
582 list_add_tail(&asd->asd_list, &notifier->asd_list);
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400583
584unlock:
585 mutex_unlock(&list_lock);
586 return ret;
587}
588EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_subdev);
589
Steve Longerbeam23989b42018-09-29 15:54:07 -0400590struct v4l2_async_subdev *
591v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,
592 struct fwnode_handle *fwnode,
593 unsigned int asd_struct_size)
594{
595 struct v4l2_async_subdev *asd;
596 int ret;
597
598 asd = kzalloc(asd_struct_size, GFP_KERNEL);
599 if (!asd)
600 return ERR_PTR(-ENOMEM);
601
602 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
603 asd->match.fwnode = fwnode;
604
605 ret = v4l2_async_notifier_add_subdev(notifier, asd);
606 if (ret) {
607 kfree(asd);
608 return ERR_PTR(ret);
609 }
610
611 return asd;
612}
613EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev);
614
615struct v4l2_async_subdev *
616v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier,
617 int adapter_id, unsigned short address,
618 unsigned int asd_struct_size)
619{
620 struct v4l2_async_subdev *asd;
621 int ret;
622
623 asd = kzalloc(asd_struct_size, GFP_KERNEL);
624 if (!asd)
625 return ERR_PTR(-ENOMEM);
626
627 asd->match_type = V4L2_ASYNC_MATCH_I2C;
628 asd->match.i2c.adapter_id = adapter_id;
629 asd->match.i2c.address = address;
630
631 ret = v4l2_async_notifier_add_subdev(notifier, asd);
632 if (ret) {
633 kfree(asd);
634 return ERR_PTR(ret);
635 }
636
637 return asd;
638}
639EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_i2c_subdev);
640
641struct v4l2_async_subdev *
642v4l2_async_notifier_add_devname_subdev(struct v4l2_async_notifier *notifier,
643 const char *device_name,
644 unsigned int asd_struct_size)
645{
646 struct v4l2_async_subdev *asd;
647 int ret;
648
649 asd = kzalloc(asd_struct_size, GFP_KERNEL);
650 if (!asd)
651 return ERR_PTR(-ENOMEM);
652
653 asd->match_type = V4L2_ASYNC_MATCH_DEVNAME;
654 asd->match.device_name = device_name;
655
656 ret = v4l2_async_notifier_add_subdev(notifier, asd);
657 if (ret) {
658 kfree(asd);
659 return ERR_PTR(ret);
660 }
661
662 return asd;
663}
664EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_devname_subdev);
665
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300666int v4l2_async_register_subdev(struct v4l2_subdev *sd)
667{
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400668 struct v4l2_async_notifier *subdev_notifier;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300669 struct v4l2_async_notifier *notifier;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400670 int ret;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300671
Sakari Ailus86217652015-06-11 12:18:01 -0700672 /*
673 * No reference taken. The reference is held by the device
674 * (struct v4l2_subdev.dev), and async sub-device does not
675 * exist independently of the device at any point of time.
676 */
Sakari Ailus859969b2016-08-26 20:17:25 -0300677 if (!sd->fwnode && sd->dev)
678 sd->fwnode = dev_fwnode(sd->dev);
Sakari Ailus86217652015-06-11 12:18:01 -0700679
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300680 mutex_lock(&list_lock);
681
Sylwester Nawrockib426b3a2013-07-22 08:01:33 -0300682 INIT_LIST_HEAD(&sd->async_list);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300683
684 list_for_each_entry(notifier, &notifier_list, list) {
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400685 struct v4l2_device *v4l2_dev =
686 v4l2_async_notifier_find_v4l2_dev(notifier);
687 struct v4l2_async_subdev *asd;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400688
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400689 if (!v4l2_dev)
690 continue;
691
692 asd = v4l2_async_find_match(notifier, sd);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400693 if (!asd)
694 continue;
695
Niklas Söderlund487cc852017-11-15 10:43:58 -0500696 ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400697 if (ret)
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400698 goto err_unbind;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400699
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400700 ret = v4l2_async_notifier_try_complete(notifier);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400701 if (ret)
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400702 goto err_unbind;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400703
704 goto out_unlock;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300705 }
706
707 /* None matched, wait for hot-plugging */
Sylwester Nawrockib426b3a2013-07-22 08:01:33 -0300708 list_add(&sd->async_list, &subdev_list);
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300709
Sakari Ailusfb45f432017-10-02 06:24:54 -0400710out_unlock:
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300711 mutex_unlock(&list_lock);
712
713 return 0;
Sakari Ailusfb45f432017-10-02 06:24:54 -0400714
Sakari Ailus2cab00b2017-09-24 20:54:31 -0400715err_unbind:
716 /*
717 * Complete failed. Unbind the sub-devices bound through registering
718 * this async sub-device.
719 */
720 subdev_notifier = v4l2_async_find_subdev_notifier(sd);
721 if (subdev_notifier)
722 v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
723
724 if (sd->asd)
725 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
Sakari Ailusfb45f432017-10-02 06:24:54 -0400726 v4l2_async_cleanup(sd);
727
Sakari Ailusfb45f432017-10-02 06:24:54 -0400728 mutex_unlock(&list_lock);
729
730 return ret;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300731}
732EXPORT_SYMBOL(v4l2_async_register_subdev);
733
734void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
735{
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300736 mutex_lock(&list_lock);
737
Sakari Ailusaef69d52017-09-24 18:47:44 -0400738 __v4l2_async_notifier_unregister(sd->subdev_notifier);
Steve Longerbeamb47d7ff2018-09-29 15:54:06 -0400739 __v4l2_async_notifier_cleanup(sd->subdev_notifier);
Sakari Ailusaef69d52017-09-24 18:47:44 -0400740 kfree(sd->subdev_notifier);
741 sd->subdev_notifier = NULL;
742
Sakari Ailus7fc4fdb2017-10-03 02:26:32 -0400743 if (sd->asd) {
744 struct v4l2_async_notifier *notifier = sd->notifier;
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300745
Sakari Ailus7fc4fdb2017-10-03 02:26:32 -0400746 list_add(&sd->asd->list, &notifier->waiting);
747
Sakari Ailusddddc182017-09-01 08:27:32 -0400748 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
Sakari Ailus7fc4fdb2017-10-03 02:26:32 -0400749 }
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300750
Niklas Söderlund633d1852017-10-02 16:16:52 -0400751 v4l2_async_cleanup(sd);
752
Guennadi Liakhovetskie9e31042013-01-08 07:06:31 -0300753 mutex_unlock(&list_lock);
754}
755EXPORT_SYMBOL(v4l2_async_unregister_subdev);