1 /*
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>
15 #include <linux/mm.h>
16 #include <linux/module.h>
17 #include <linux/mutex.h>
18 #include <linux/of.h>
19 #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>
25 #include <media/v4l2-fwnode.h>
26 #include <media/v4l2-subdev.h>
27 
28 static 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 
38 static 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 
48 static 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 
56 static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
57 {
58 #if IS_ENABLED(CONFIG_I2C)
59 	struct i2c_client *client = i2c_verify_client(sd->dev);
60 
61 	return client &&
62 		asd->match.i2c.adapter_id == client->adapter->nr &&
63 		asd->match.i2c.address == client->addr;
64 #else
65 	return false;
66 #endif
67 }
68 
69 static bool match_devname(struct v4l2_subdev *sd,
70 			  struct v4l2_async_subdev *asd)
71 {
72 	return !strcmp(asd->match.device_name, dev_name(sd->dev));
73 }
74 
75 static bool match_fwnode(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
76 {
77 	return sd->fwnode == asd->match.fwnode;
78 }
79 
80 static 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);
87 }
88 
89 static LIST_HEAD(subdev_list);
90 static LIST_HEAD(notifier_list);
91 static DEFINE_MUTEX(list_lock);
92 
93 static struct v4l2_async_subdev *
94 v4l2_async_find_match(struct v4l2_async_notifier *notifier,
95 		      struct v4l2_subdev *sd)
96 {
97 	bool (*match)(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd);
98 	struct v4l2_async_subdev *asd;
99 
100 	list_for_each_entry(asd, &notifier->waiting, list) {
101 		/* bus_type has been verified valid before */
102 		switch (asd->match_type) {
103 		case V4L2_ASYNC_MATCH_CUSTOM:
104 			match = match_custom;
105 			break;
106 		case V4L2_ASYNC_MATCH_DEVNAME:
107 			match = match_devname;
108 			break;
109 		case V4L2_ASYNC_MATCH_I2C:
110 			match = match_i2c;
111 			break;
112 		case V4L2_ASYNC_MATCH_FWNODE:
113 			match = match_fwnode;
114 			break;
115 		default:
116 			/* Cannot happen, unless someone breaks us */
117 			WARN_ON(true);
118 			return NULL;
119 		}
120 
121 		/* match cannot be NULL here */
122 		if (match(sd, asd))
123 			return asd;
124 	}
125 
126 	return NULL;
127 }
128 
129 /* Compare two async sub-device descriptors for equivalence */
130 static 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 
154 /* Find the sub-device notifier registered by a sub-device driver. */
155 static struct v4l2_async_notifier *
156 v4l2_async_find_subdev_notifier(struct v4l2_subdev *sd)
157 {
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. */
168 static struct v4l2_device *
169 v4l2_async_notifier_find_v4l2_dev(struct v4l2_async_notifier *notifier)
170 {
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  */
180 static bool
181 v4l2_async_notifier_can_complete(struct v4l2_async_notifier *notifier)
182 {
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  */
204 static int
205 v4l2_async_notifier_try_complete(struct v4l2_async_notifier *notifier)
206 {
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 
226 static int
227 v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier);
228 
229 static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
230 				   struct v4l2_device *v4l2_dev,
231 				   struct v4l2_subdev *sd,
232 				   struct v4l2_async_subdev *asd)
233 {
234 	struct v4l2_async_notifier *subdev_notifier;
235 	int ret;
236 
237 	ret = v4l2_device_register_subdev(v4l2_dev, sd);
238 	if (ret < 0)
239 		return ret;
240 
241 	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
242 	if (ret < 0) {
243 		v4l2_device_unregister_subdev(sd);
244 		return ret;
245 	}
246 
247 	/* 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 
255 	/*
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);
270 }
271 
272 /* Test all async sub-devices in a notifier for a match. */
273 static int
274 v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier)
275 {
276 	struct v4l2_device *v4l2_dev =
277 		v4l2_async_notifier_find_v4l2_dev(notifier);
278 	struct v4l2_subdev *sd;
279 
280 	if (!v4l2_dev)
281 		return 0;
282 
283 again:
284 	list_for_each_entry(sd, &subdev_list, async_list) {
285 		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;
295 
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;
303 	}
304 
305 	return 0;
306 }
307 
308 static void v4l2_async_cleanup(struct v4l2_subdev *sd)
309 {
310 	v4l2_device_unregister_subdev(sd);
311 	/*
312 	 * Subdevice driver will reprobe and put the subdev back
313 	 * onto the list
314 	 */
315 	list_del_init(&sd->async_list);
316 	sd->asd = NULL;
317 }
318 
319 /* Unbind all sub-devices in the notifier tree. */
320 static void
321 v4l2_async_notifier_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
322 {
323 	struct v4l2_subdev *sd, *tmp;
324 
325 	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
326 		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 
332 		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
333 		v4l2_async_cleanup(sd);
334 
335 		list_move(&sd->async_list, &subdev_list);
336 	}
337 
338 	notifier->parent = NULL;
339 }
340 
341 /* See if an async sub-device can be found in a notifier's lists. */
342 static bool
343 __v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
344 				       struct v4l2_async_subdev *asd)
345 {
346 	struct v4l2_async_subdev *asd_y;
347 	struct v4l2_subdev *sd;
348 
349 	list_for_each_entry(asd_y, &notifier->waiting, list)
350 		if (asd_equal(asd, asd_y))
351 			return true;
352 
353 	list_for_each_entry(sd, &notifier->done, async_list) {
354 		if (WARN_ON(!sd->asd))
355 			continue;
356 
357 		if (asd_equal(asd, sd->asd))
358 			return true;
359 	}
360 
361 	return false;
362 }
363 
364 /*
365  * Find out whether an async sub-device was set up already or
366  * whether it exists in a given notifier before @this_index.
367  * If @this_index < 0, search the notifier's entire @asd_list.
368  */
369 static bool
370 v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
371 				     struct v4l2_async_subdev *asd,
372 				     int this_index)
373 {
374 	struct v4l2_async_subdev *asd_y;
375 	int j = 0;
376 
377 	lockdep_assert_held(&list_lock);
378 
379 	/* Check that an asd is not being added more than once. */
380 	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;
385 	}
386 
387 	/* Check that an asd does not exist in other notifiers. */
388 	list_for_each_entry(notifier, &notifier_list, list)
389 		if (__v4l2_async_notifier_has_async_subdev(notifier, asd))
390 			return true;
391 
392 	return false;
393 }
394 
395 static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier,
396 					 struct v4l2_async_subdev *asd,
397 					 int this_index)
398 {
399 	struct device *dev =
400 		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
401 
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 
425 void 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 }
433 EXPORT_SYMBOL(v4l2_async_notifier_init);
434 
435 static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
436 {
437 	struct v4l2_async_subdev *asd;
438 	int ret, i = 0;
439 
440 	INIT_LIST_HEAD(&notifier->waiting);
441 	INIT_LIST_HEAD(&notifier->done);
442 
443 	mutex_lock(&list_lock);
444 
445 	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;
449 
450 		list_add_tail(&asd->list, &notifier->waiting);
451 	}
452 
453 	ret = v4l2_async_notifier_try_all_subdevs(notifier);
454 	if (ret < 0)
455 		goto err_unbind;
456 
457 	ret = v4l2_async_notifier_try_complete(notifier);
458 	if (ret < 0)
459 		goto err_unbind;
460 
461 	/* Keep also completed notifiers on the list */
462 	list_add(&notifier->list, &notifier_list);
463 
464 	mutex_unlock(&list_lock);
465 
466 	return 0;
467 
468 err_unbind:
469 	/*
470 	 * On failure, unbind all sub-devices registered through this notifier.
471 	 */
472 	v4l2_async_notifier_unbind_all_subdevs(notifier);
473 
474 err_unlock:
475 	mutex_unlock(&list_lock);
476 
477 	return ret;
478 }
479 
480 int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
481 				 struct v4l2_async_notifier *notifier)
482 {
483 	int ret;
484 
485 	if (WARN_ON(!v4l2_dev || notifier->sd))
486 		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 }
496 EXPORT_SYMBOL(v4l2_async_notifier_register);
497 
498 int 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 }
514 EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
515 
516 static void
517 __v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
518 {
519 	if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
520 		return;
521 
522 	v4l2_async_notifier_unbind_all_subdevs(notifier);
523 
524 	notifier->sd = NULL;
525 	notifier->v4l2_dev = NULL;
526 
527 	list_del(&notifier->list);
528 }
529 
530 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
531 {
532 	mutex_lock(&list_lock);
533 
534 	__v4l2_async_notifier_unregister(notifier);
535 
536 	mutex_unlock(&list_lock);
537 }
538 EXPORT_SYMBOL(v4l2_async_notifier_unregister);
539 
540 static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
541 {
542 	struct v4l2_async_subdev *asd, *tmp;
543 
544 	if (!notifier)
545 		return;
546 
547 	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;
554 		}
555 
556 		list_del(&asd->asd_list);
557 		kfree(asd);
558 	}
559 }
560 
561 void 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);
568 }
569 EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
570 
571 int 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 
578 	ret = v4l2_async_notifier_asd_valid(notifier, asd, -1);
579 	if (ret)
580 		goto unlock;
581 
582 	list_add_tail(&asd->asd_list, &notifier->asd_list);
583 
584 unlock:
585 	mutex_unlock(&list_lock);
586 	return ret;
587 }
588 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_subdev);
589 
590 struct v4l2_async_subdev *
591 v4l2_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 }
613 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev);
614 
615 struct v4l2_async_subdev *
616 v4l2_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 }
639 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_i2c_subdev);
640 
641 struct v4l2_async_subdev *
642 v4l2_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 }
664 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_devname_subdev);
665 
666 int v4l2_async_register_subdev(struct v4l2_subdev *sd)
667 {
668 	struct v4l2_async_notifier *subdev_notifier;
669 	struct v4l2_async_notifier *notifier;
670 	int ret;
671 
672 	/*
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 	 */
677 	if (!sd->fwnode && sd->dev)
678 		sd->fwnode = dev_fwnode(sd->dev);
679 
680 	mutex_lock(&list_lock);
681 
682 	INIT_LIST_HEAD(&sd->async_list);
683 
684 	list_for_each_entry(notifier, &notifier_list, list) {
685 		struct v4l2_device *v4l2_dev =
686 			v4l2_async_notifier_find_v4l2_dev(notifier);
687 		struct v4l2_async_subdev *asd;
688 
689 		if (!v4l2_dev)
690 			continue;
691 
692 		asd = v4l2_async_find_match(notifier, sd);
693 		if (!asd)
694 			continue;
695 
696 		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
697 		if (ret)
698 			goto err_unbind;
699 
700 		ret = v4l2_async_notifier_try_complete(notifier);
701 		if (ret)
702 			goto err_unbind;
703 
704 		goto out_unlock;
705 	}
706 
707 	/* None matched, wait for hot-plugging */
708 	list_add(&sd->async_list, &subdev_list);
709 
710 out_unlock:
711 	mutex_unlock(&list_lock);
712 
713 	return 0;
714 
715 err_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);
726 	v4l2_async_cleanup(sd);
727 
728 	mutex_unlock(&list_lock);
729 
730 	return ret;
731 }
732 EXPORT_SYMBOL(v4l2_async_register_subdev);
733 
734 void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
735 {
736 	mutex_lock(&list_lock);
737 
738 	__v4l2_async_notifier_unregister(sd->subdev_notifier);
739 	__v4l2_async_notifier_cleanup(sd->subdev_notifier);
740 	kfree(sd->subdev_notifier);
741 	sd->subdev_notifier = NULL;
742 
743 	if (sd->asd) {
744 		struct v4l2_async_notifier *notifier = sd->notifier;
745 
746 		list_add(&sd->asd->list, &notifier->waiting);
747 
748 		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
749 	}
750 
751 	v4l2_async_cleanup(sd);
752 
753 	mutex_unlock(&list_lock);
754 }
755 EXPORT_SYMBOL(v4l2_async_unregister_subdev);
756