@@ -128,11 +128,109 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
128128 return NULL ;
129129}
130130
131+ /* Find the sub-device notifier registered by a sub-device driver. */
132+ static struct v4l2_async_notifier * v4l2_async_find_subdev_notifier (
133+ struct v4l2_subdev * sd )
134+ {
135+ struct v4l2_async_notifier * n ;
136+
137+ list_for_each_entry (n , & notifier_list , list )
138+ if (n -> sd == sd )
139+ return n ;
140+
141+ return NULL ;
142+ }
143+
144+ /* Get v4l2_device related to the notifier if one can be found. */
145+ static struct v4l2_device * v4l2_async_notifier_find_v4l2_dev (
146+ struct v4l2_async_notifier * notifier )
147+ {
148+ while (notifier -> parent )
149+ notifier = notifier -> parent ;
150+
151+ return notifier -> v4l2_dev ;
152+ }
153+
154+ /*
155+ * Return true if all child sub-device notifiers are complete, false otherwise.
156+ */
157+ static bool v4l2_async_notifier_can_complete (
158+ struct v4l2_async_notifier * notifier )
159+ {
160+ struct v4l2_subdev * sd ;
161+
162+ if (!list_empty (& notifier -> waiting ))
163+ return false;
164+
165+ list_for_each_entry (sd , & notifier -> done , async_list ) {
166+ struct v4l2_async_notifier * subdev_notifier =
167+ v4l2_async_find_subdev_notifier (sd );
168+
169+ if (subdev_notifier &&
170+ !v4l2_async_notifier_can_complete (subdev_notifier ))
171+ return false;
172+ }
173+
174+ return true;
175+ }
176+
177+ /* Complete all notifiers. Call on the root notifier. */
178+ static int v4l2_async_notifier_complete (
179+ struct v4l2_async_notifier * notifier )
180+ {
181+ struct v4l2_subdev * sd ;
182+
183+ list_for_each_entry (sd , & notifier -> done , async_list ) {
184+ struct v4l2_async_notifier * subdev_notifier =
185+ v4l2_async_find_subdev_notifier (sd );
186+ int ret ;
187+
188+ if (!subdev_notifier )
189+ continue ;
190+
191+ ret = v4l2_async_notifier_complete (subdev_notifier );
192+ if (ret )
193+ return ret ;
194+ }
195+
196+ return v4l2_async_notifier_call_complete (notifier );
197+ }
198+
199+ /*
200+ * Complete notifiers if possible. This is done when all async sub-devices have
201+ * been bound; v4l2_device is also available then.
202+ */
203+ static int v4l2_async_notifier_try_complete (
204+ struct v4l2_async_notifier * notifier )
205+ {
206+ /* Quick check whether there are still more sub-devices here. */
207+ if (!list_empty (& notifier -> waiting ))
208+ return 0 ;
209+
210+ /* Check the entire notifier tree; find the root notifier first. */
211+ while (notifier -> parent )
212+ notifier = notifier -> parent ;
213+
214+ /* This is root if it has v4l2_dev. */
215+ if (!notifier -> v4l2_dev )
216+ return 0 ;
217+
218+ /* Is everything ready? */
219+ if (!v4l2_async_notifier_can_complete (notifier ))
220+ return 0 ;
221+
222+ return v4l2_async_notifier_complete (notifier );
223+ }
224+
225+ static int v4l2_async_notifier_try_all_subdevs (
226+ struct v4l2_async_notifier * notifier );
227+
131228static int v4l2_async_match_notify (struct v4l2_async_notifier * notifier ,
132229 struct v4l2_device * v4l2_dev ,
133230 struct v4l2_subdev * sd ,
134231 struct v4l2_async_subdev * asd )
135232{
233+ struct v4l2_async_notifier * subdev_notifier ;
136234 int ret ;
137235
138236 ret = v4l2_device_register_subdev (v4l2_dev , sd );
@@ -153,8 +251,17 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
153251 /* Move from the global subdevice list to notifier's done */
154252 list_move (& sd -> async_list , & notifier -> done );
155253
156- if (list_empty (& notifier -> waiting ))
157- return v4l2_async_notifier_call_complete (notifier );
254+ /*
255+ * See if the sub-device has a notifier. If it does, proceed
256+ * with checking for its async sub-devices.
257+ */
258+ subdev_notifier = v4l2_async_find_subdev_notifier (sd );
259+ if (subdev_notifier && !subdev_notifier -> parent ) {
260+ subdev_notifier -> parent = notifier ;
261+ ret = v4l2_async_notifier_try_all_subdevs (subdev_notifier );
262+ if (ret )
263+ return ret ;
264+ }
158265
159266 return 0 ;
160267}
@@ -163,10 +270,15 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
163270static int v4l2_async_notifier_try_all_subdevs (
164271 struct v4l2_async_notifier * notifier )
165272{
166- struct v4l2_device * v4l2_dev = notifier -> v4l2_dev ;
167- struct v4l2_subdev * sd , * tmp ;
273+ struct v4l2_device * v4l2_dev =
274+ v4l2_async_notifier_find_v4l2_dev (notifier );
275+ struct v4l2_subdev * sd ;
168276
169- list_for_each_entry_safe (sd , tmp , & subdev_list , async_list ) {
277+ if (!v4l2_dev )
278+ return 0 ;
279+
280+ again :
281+ list_for_each_entry (sd , & subdev_list , async_list ) {
170282 struct v4l2_async_subdev * asd ;
171283 int ret ;
172284
@@ -175,10 +287,16 @@ static int v4l2_async_notifier_try_all_subdevs(
175287 continue ;
176288
177289 ret = v4l2_async_match_notify (notifier , v4l2_dev , sd , asd );
178- if (ret < 0 ) {
179- mutex_unlock (& list_lock );
290+ if (ret < 0 )
180291 return ret ;
181- }
292+
293+ /*
294+ * v4l2_async_match_notify() may lead to registering a
295+ * new notifier and thus changing the async subdevs
296+ * list. In order to proceed safely from here, restart
297+ * parsing the list from the beginning.
298+ */
299+ goto again ;
182300 }
183301
184302 return 0 ;
@@ -210,6 +328,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
210328
211329 ret = v4l2_async_notifier_call_complete (notifier );
212330 notifier -> v4l2_dev = NULL ;
331+ notifier -> sd = NULL ;
213332
214333 return ret ;
215334 }
@@ -240,6 +359,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
240359 return ret ;
241360 }
242361
362+ ret = v4l2_async_notifier_try_complete (notifier );
363+
243364 /* Keep also completed notifiers on the list */
244365 list_add (& notifier -> list , & notifier_list );
245366
@@ -251,7 +372,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
251372int v4l2_async_notifier_register (struct v4l2_device * v4l2_dev ,
252373 struct v4l2_async_notifier * notifier )
253374{
254- if (WARN_ON (!v4l2_dev ))
375+ if (WARN_ON (!v4l2_dev || notifier -> sd ))
255376 return - EINVAL ;
256377
257378 notifier -> v4l2_dev = v4l2_dev ;
@@ -260,28 +381,56 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
260381}
261382EXPORT_SYMBOL (v4l2_async_notifier_register );
262383
263- void v4l2_async_notifier_unregister (struct v4l2_async_notifier * notifier )
384+ int v4l2_async_subdev_notifier_register (struct v4l2_subdev * sd ,
385+ struct v4l2_async_notifier * notifier )
264386{
265- struct v4l2_subdev * sd , * tmp ;
387+ if (WARN_ON (!sd || notifier -> v4l2_dev ))
388+ return - EINVAL ;
266389
267- if (!notifier -> v4l2_dev )
268- return ;
390+ notifier -> sd = sd ;
269391
270- mutex_lock (& list_lock );
392+ return __v4l2_async_notifier_register (notifier );
393+ }
394+ EXPORT_SYMBOL (v4l2_async_subdev_notifier_register );
271395
272- list_del (& notifier -> list );
396+ /* Unbind all sub-devices in the notifier tree. */
397+ static void v4l2_async_notifier_unbind_all_subdevs (
398+ struct v4l2_async_notifier * notifier )
399+ {
400+ struct v4l2_subdev * sd , * tmp ;
273401
274402 list_for_each_entry_safe (sd , tmp , & notifier -> done , async_list ) {
403+ struct v4l2_async_notifier * subdev_notifier =
404+ v4l2_async_find_subdev_notifier (sd );
405+
406+ if (subdev_notifier )
407+ v4l2_async_notifier_unbind_all_subdevs (subdev_notifier );
408+
275409 v4l2_async_cleanup (sd );
276410
277411 v4l2_async_notifier_call_unbind (notifier , sd , sd -> asd );
278412
279413 list_move (& sd -> async_list , & subdev_list );
280414 }
281415
282- mutex_unlock (& list_lock );
416+ notifier -> parent = NULL ;
417+ }
283418
419+ void v4l2_async_notifier_unregister (struct v4l2_async_notifier * notifier )
420+ {
421+ if (!notifier -> v4l2_dev && !notifier -> sd )
422+ return ;
423+
424+ mutex_lock (& list_lock );
425+
426+ v4l2_async_notifier_unbind_all_subdevs (notifier );
427+
428+ notifier -> sd = NULL ;
284429 notifier -> v4l2_dev = NULL ;
430+
431+ list_del (& notifier -> list );
432+
433+ mutex_unlock (& list_lock );
285434}
286435EXPORT_SYMBOL (v4l2_async_notifier_unregister );
287436
@@ -331,14 +480,25 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
331480 INIT_LIST_HEAD (& sd -> async_list );
332481
333482 list_for_each_entry (notifier , & notifier_list , list ) {
334- struct v4l2_async_subdev * asd = v4l2_async_find_match (notifier ,
335- sd );
336- if (asd ) {
337- int ret = v4l2_async_match_notify (
338- notifier , notifier -> v4l2_dev , sd , asd );
339- mutex_unlock (& list_lock );
340- return ret ;
341- }
483+ struct v4l2_device * v4l2_dev =
484+ v4l2_async_notifier_find_v4l2_dev (notifier );
485+ struct v4l2_async_subdev * asd ;
486+ int ret ;
487+
488+ if (!v4l2_dev )
489+ continue ;
490+
491+ asd = v4l2_async_find_match (notifier , sd );
492+ if (!asd )
493+ continue ;
494+
495+ ret = v4l2_async_match_notify (notifier , v4l2_dev , sd , asd );
496+
497+ if (!ret )
498+ ret = v4l2_async_notifier_try_complete (notifier );
499+
500+ mutex_unlock (& list_lock );
501+ return ret ;
342502 }
343503
344504 /* None matched, wait for hot-plugging */
0 commit comments