LCOV - code coverage report
Current view: top level - drivers/media/v4l2-core - v4l2-async.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 0 243 0.0 %
Date: 2020-09-30 20:25:40 Functions: 0 29 0.0 %
Branches: 0 215 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * V4L2 asynchronous subdevice registration API
       4                 :            :  *
       5                 :            :  * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
       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   [ #  #  #  # ]:          0 :         if (!n->ops || !n->ops->bound)
      30                 :            :                 return 0;
      31                 :            : 
      32                 :          0 :         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   [ #  #  #  #  :          0 :         if (!n->ops || !n->ops->unbind)
          #  #  #  #  #  
                #  #  # ]
      40                 :            :                 return;
      41                 :            : 
      42                 :          0 :         n->ops->unbind(n, subdev, asd);
      43                 :            : }
      44                 :            : 
      45                 :            : static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
      46                 :            : {
      47   [ #  #  #  # ]:          0 :         if (!n->ops || !n->ops->complete)
      48                 :            :                 return 0;
      49                 :            : 
      50                 :          0 :         return n->ops->complete(n);
      51                 :            : }
      52                 :            : 
      53                 :          0 : static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
      54                 :            : {
      55                 :            : #if IS_ENABLED(CONFIG_I2C)
      56                 :          0 :         struct i2c_client *client = i2c_verify_client(sd->dev);
      57                 :            : 
      58         [ #  # ]:          0 :         return client &&
      59   [ #  #  #  # ]:          0 :                 asd->match.i2c.adapter_id == client->adapter->nr &&
      60                 :          0 :                 asd->match.i2c.address == client->addr;
      61                 :            : #else
      62                 :            :         return false;
      63                 :            : #endif
      64                 :            : }
      65                 :            : 
      66                 :          0 : static bool match_devname(struct v4l2_subdev *sd,
      67                 :            :                           struct v4l2_async_subdev *asd)
      68                 :            : {
      69                 :          0 :         return !strcmp(asd->match.device_name, dev_name(sd->dev));
      70                 :            : }
      71                 :            : 
      72                 :          0 : static bool match_fwnode(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
      73                 :            : {
      74                 :          0 :         return sd->fwnode == asd->match.fwnode;
      75                 :            : }
      76                 :            : 
      77                 :          0 : static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
      78                 :            : {
      79         [ #  # ]:          0 :         if (!asd->match.custom.match)
      80                 :            :                 /* Match always */
      81                 :            :                 return true;
      82                 :            : 
      83                 :          0 :         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                 :          0 : 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         [ #  # ]:          0 :         list_for_each_entry(asd, &notifier->waiting, list) {
      98                 :            :                 /* bus_type has been verified valid before */
      99   [ #  #  #  #  :          0 :                 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                 :          0 :                         break;
     106                 :            :                 case V4L2_ASYNC_MATCH_I2C:
     107                 :            :                         match = match_i2c;
     108                 :          0 :                         break;
     109                 :            :                 case V4L2_ASYNC_MATCH_FWNODE:
     110                 :            :                         match = match_fwnode;
     111                 :          0 :                         break;
     112                 :            :                 default:
     113                 :            :                         /* Cannot happen, unless someone breaks us */
     114                 :          0 :                         WARN_ON(true);
     115                 :          0 :                         return NULL;
     116                 :            :                 }
     117                 :            : 
     118                 :            :                 /* match cannot be NULL here */
     119         [ #  # ]:          0 :                 if (match(sd, asd))
     120                 :          0 :                         return asd;
     121                 :            :         }
     122                 :            : 
     123                 :            :         return NULL;
     124                 :            : }
     125                 :            : 
     126                 :            : /* Compare two async sub-device descriptors for equivalence */
     127                 :          0 : static bool asd_equal(struct v4l2_async_subdev *asd_x,
     128                 :            :                       struct v4l2_async_subdev *asd_y)
     129                 :            : {
     130         [ #  # ]:          0 :         if (asd_x->match_type != asd_y->match_type)
     131                 :            :                 return false;
     132                 :            : 
     133   [ #  #  #  # ]:          0 :         switch (asd_x->match_type) {
     134                 :            :         case V4L2_ASYNC_MATCH_DEVNAME:
     135                 :          0 :                 return strcmp(asd_x->match.device_name,
     136                 :            :                               asd_y->match.device_name) == 0;
     137                 :            :         case V4L2_ASYNC_MATCH_I2C:
     138                 :          0 :                 return asd_x->match.i2c.adapter_id ==
     139   [ #  #  #  # ]:          0 :                         asd_y->match.i2c.adapter_id &&
     140                 :          0 :                         asd_x->match.i2c.address ==
     141                 :          0 :                         asd_y->match.i2c.address;
     142                 :            :         case V4L2_ASYNC_MATCH_FWNODE:
     143                 :          0 :                 return asd_x->match.fwnode == asd_y->match.fwnode;
     144                 :            :         default:
     145                 :            :                 break;
     146                 :            :         }
     147                 :            : 
     148                 :            :         return false;
     149                 :            : }
     150                 :            : 
     151                 :            : /* Find the sub-device notifier registered by a sub-device driver. */
     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   [ #  #  #  #  :          0 :         list_for_each_entry(n, &notifier_list, list)
             #  #  #  # ]
     158   [ #  #  #  #  :          0 :                 if (n->sd == sd)
             #  #  #  # ]
     159                 :          0 :                         return n;
     160                 :            : 
     161                 :            :         return NULL;
     162                 :            : }
     163                 :            : 
     164                 :            : /* Get v4l2_device related to the notifier if one can be found. */
     165                 :            : static struct v4l2_device *
     166                 :            : v4l2_async_notifier_find_v4l2_dev(struct v4l2_async_notifier *notifier)
     167                 :            : {
     168   [ #  #  #  # ]:          0 :         while (notifier->parent)
     169                 :            :                 notifier = notifier->parent;
     170                 :            : 
     171                 :          0 :         return notifier->v4l2_dev;
     172                 :            : }
     173                 :            : 
     174                 :            : /*
     175                 :            :  * Return true if all child sub-device notifiers are complete, false otherwise.
     176                 :            :  */
     177                 :            : static bool
     178                 :          0 : v4l2_async_notifier_can_complete(struct v4l2_async_notifier *notifier)
     179                 :            : {
     180                 :            :         struct v4l2_subdev *sd;
     181                 :            : 
     182         [ #  # ]:          0 :         if (!list_empty(&notifier->waiting))
     183                 :            :                 return false;
     184                 :            : 
     185         [ #  # ]:          0 :         list_for_each_entry(sd, &notifier->done, async_list) {
     186                 :            :                 struct v4l2_async_notifier *subdev_notifier =
     187                 :            :                         v4l2_async_find_subdev_notifier(sd);
     188                 :            : 
     189   [ #  #  #  # ]:          0 :                 if (subdev_notifier &&
     190                 :          0 :                     !v4l2_async_notifier_can_complete(subdev_notifier))
     191                 :            :                         return false;
     192                 :            :         }
     193                 :            : 
     194                 :            :         return true;
     195                 :            : }
     196                 :            : 
     197                 :            : /*
     198                 :            :  * Complete the master notifier if possible. This is done when all async
     199                 :            :  * sub-devices have been bound; v4l2_device is also available then.
     200                 :            :  */
     201                 :            : static int
     202                 :          0 : v4l2_async_notifier_try_complete(struct v4l2_async_notifier *notifier)
     203                 :            : {
     204                 :            :         /* Quick check whether there are still more sub-devices here. */
     205         [ #  # ]:          0 :         if (!list_empty(&notifier->waiting))
     206                 :            :                 return 0;
     207                 :            : 
     208                 :            :         /* Check the entire notifier tree; find the root notifier first. */
     209         [ #  # ]:          0 :         while (notifier->parent)
     210                 :            :                 notifier = notifier->parent;
     211                 :            : 
     212                 :            :         /* This is root if it has v4l2_dev. */
     213         [ #  # ]:          0 :         if (!notifier->v4l2_dev)
     214                 :            :                 return 0;
     215                 :            : 
     216                 :            :         /* Is everything ready? */
     217         [ #  # ]:          0 :         if (!v4l2_async_notifier_can_complete(notifier))
     218                 :            :                 return 0;
     219                 :            : 
     220                 :          0 :         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                 :          0 : 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                 :          0 :         ret = v4l2_device_register_subdev(v4l2_dev, sd);
     235         [ #  # ]:          0 :         if (ret < 0)
     236                 :            :                 return ret;
     237                 :            : 
     238                 :            :         ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
     239         [ #  # ]:          0 :         if (ret < 0) {
     240                 :          0 :                 v4l2_device_unregister_subdev(sd);
     241                 :          0 :                 return ret;
     242                 :            :         }
     243                 :            : 
     244                 :            :         /* Remove from the waiting list */
     245                 :            :         list_del(&asd->list);
     246                 :          0 :         sd->asd = asd;
     247                 :          0 :         sd->notifier = notifier;
     248                 :            : 
     249                 :            :         /* Move from the global subdevice list to notifier's done */
     250                 :          0 :         list_move(&sd->async_list, &notifier->done);
     251                 :            : 
     252                 :            :         /*
     253                 :            :          * See if the sub-device has a notifier. If not, return here.
     254                 :            :          */
     255                 :            :         subdev_notifier = v4l2_async_find_subdev_notifier(sd);
     256   [ #  #  #  # ]:          0 :         if (!subdev_notifier || subdev_notifier->parent)
     257                 :            :                 return 0;
     258                 :            : 
     259                 :            :         /*
     260                 :            :          * Proceed with checking for the sub-device notifier's async
     261                 :            :          * sub-devices, and return the result. The error will be handled by the
     262                 :            :          * caller.
     263                 :            :          */
     264                 :          0 :         subdev_notifier->parent = notifier;
     265                 :            : 
     266                 :          0 :         return v4l2_async_notifier_try_all_subdevs(subdev_notifier);
     267                 :            : }
     268                 :            : 
     269                 :            : /* Test all async sub-devices in a notifier for a match. */
     270                 :            : static int
     271                 :          0 : 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         [ #  # ]:          0 :         if (!v4l2_dev)
     278                 :            :                 return 0;
     279                 :            : 
     280                 :            : again:
     281         [ #  # ]:          0 :         list_for_each_entry(sd, &subdev_list, async_list) {
     282                 :            :                 struct v4l2_async_subdev *asd;
     283                 :            :                 int ret;
     284                 :            : 
     285                 :          0 :                 asd = v4l2_async_find_match(notifier, sd);
     286         [ #  # ]:          0 :                 if (!asd)
     287                 :          0 :                         continue;
     288                 :            : 
     289                 :          0 :                 ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
     290         [ #  # ]:          0 :                 if (ret < 0)
     291                 :          0 :                         return ret;
     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;
     300                 :            :         }
     301                 :            : 
     302                 :            :         return 0;
     303                 :            : }
     304                 :            : 
     305                 :            : static void v4l2_async_cleanup(struct v4l2_subdev *sd)
     306                 :            : {
     307                 :          0 :         v4l2_device_unregister_subdev(sd);
     308                 :            :         /*
     309                 :            :          * Subdevice driver will reprobe and put the subdev back
     310                 :            :          * onto the list
     311                 :            :          */
     312                 :          0 :         list_del_init(&sd->async_list);
     313                 :          0 :         sd->asd = NULL;
     314                 :            : }
     315                 :            : 
     316                 :            : /* Unbind all sub-devices in the notifier tree. */
     317                 :            : static void
     318                 :          0 : v4l2_async_notifier_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
     319                 :            : {
     320                 :            :         struct v4l2_subdev *sd, *tmp;
     321                 :            : 
     322         [ #  # ]:          0 :         list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
     323                 :            :                 struct v4l2_async_notifier *subdev_notifier =
     324                 :            :                         v4l2_async_find_subdev_notifier(sd);
     325                 :            : 
     326         [ #  # ]:          0 :                 if (subdev_notifier)
     327                 :          0 :                         v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
     328                 :            : 
     329                 :          0 :                 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                 :          0 :         notifier->parent = NULL;
     336                 :          0 : }
     337                 :            : 
     338                 :            : /* See if an async sub-device can be found in a notifier's lists. */
     339                 :            : static bool
     340                 :          0 : __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         [ #  # ]:          0 :         list_for_each_entry(asd_y, &notifier->waiting, list)
     347         [ #  # ]:          0 :                 if (asd_equal(asd, asd_y))
     348                 :            :                         return true;
     349                 :            : 
     350         [ #  # ]:          0 :         list_for_each_entry(sd, &notifier->done, async_list) {
     351   [ #  #  #  # ]:          0 :                 if (WARN_ON(!sd->asd))
     352                 :          0 :                         continue;
     353                 :            : 
     354         [ #  # ]:          0 :                 if (asd_equal(asd, sd->asd))
     355                 :            :                         return true;
     356                 :            :         }
     357                 :            : 
     358                 :            :         return false;
     359                 :            : }
     360                 :            : 
     361                 :            : /*
     362                 :            :  * Find out whether an async sub-device was set up already or
     363                 :            :  * whether it exists in a given notifier before @this_index.
     364                 :            :  * If @this_index < 0, search the notifier's entire @asd_list.
     365                 :            :  */
     366                 :            : static bool
     367                 :          0 : 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                 :            :         /* Check that an asd is not being added more than once. */
     377         [ #  # ]:          0 :         list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
     378   [ #  #  #  # ]:          0 :                 if (this_index >= 0 && j++ >= this_index)
     379                 :            :                         break;
     380         [ #  # ]:          0 :                 if (asd_equal(asd, asd_y))
     381                 :            :                         return true;
     382                 :            :         }
     383                 :            : 
     384                 :            :         /* Check that an asd does not exist in other notifiers. */
     385         [ #  # ]:          0 :         list_for_each_entry(notifier, &notifier_list, list)
     386         [ #  # ]:          0 :                 if (__v4l2_async_notifier_has_async_subdev(notifier, asd))
     387                 :            :                         return true;
     388                 :            : 
     389                 :            :         return false;
     390                 :            : }
     391                 :            : 
     392                 :          0 : 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         [ #  # ]:          0 :                 notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
     398                 :            : 
     399         [ #  # ]:          0 :         if (!asd)
     400                 :            :                 return -EINVAL;
     401                 :            : 
     402         [ #  # ]:          0 :         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         [ #  # ]:          0 :                 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                 :          0 :                 dev_err(dev, "Invalid match type %u on %p\n",
     415                 :            :                         asd->match_type, asd);
     416                 :          0 :                 return -EINVAL;
     417                 :            :         }
     418                 :            : 
     419                 :          0 :         return 0;
     420                 :            : }
     421                 :            : 
     422                 :          0 : void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier)
     423                 :            : {
     424                 :          0 :         INIT_LIST_HEAD(&notifier->asd_list);
     425                 :          0 : }
     426                 :            : EXPORT_SYMBOL(v4l2_async_notifier_init);
     427                 :            : 
     428                 :          0 : 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                 :          0 :         INIT_LIST_HEAD(&notifier->waiting);
     434                 :          0 :         INIT_LIST_HEAD(&notifier->done);
     435                 :            : 
     436                 :          0 :         mutex_lock(&list_lock);
     437                 :            : 
     438         [ #  # ]:          0 :         list_for_each_entry(asd, &notifier->asd_list, asd_list) {
     439                 :          0 :                 ret = v4l2_async_notifier_asd_valid(notifier, asd, i++);
     440         [ #  # ]:          0 :                 if (ret)
     441                 :            :                         goto err_unlock;
     442                 :            : 
     443                 :          0 :                 list_add_tail(&asd->list, &notifier->waiting);
     444                 :            :         }
     445                 :            : 
     446                 :          0 :         ret = v4l2_async_notifier_try_all_subdevs(notifier);
     447         [ #  # ]:          0 :         if (ret < 0)
     448                 :            :                 goto err_unbind;
     449                 :            : 
     450                 :          0 :         ret = v4l2_async_notifier_try_complete(notifier);
     451         [ #  # ]:          0 :         if (ret < 0)
     452                 :            :                 goto err_unbind;
     453                 :            : 
     454                 :            :         /* Keep also completed notifiers on the list */
     455                 :          0 :         list_add(&notifier->list, &notifier_list);
     456                 :            : 
     457                 :          0 :         mutex_unlock(&list_lock);
     458                 :            : 
     459                 :          0 :         return 0;
     460                 :            : 
     461                 :            : err_unbind:
     462                 :            :         /*
     463                 :            :          * On failure, unbind all sub-devices registered through this notifier.
     464                 :            :          */
     465                 :          0 :         v4l2_async_notifier_unbind_all_subdevs(notifier);
     466                 :            : 
     467                 :            : err_unlock:
     468                 :          0 :         mutex_unlock(&list_lock);
     469                 :            : 
     470                 :          0 :         return ret;
     471                 :            : }
     472                 :            : 
     473                 :          0 : int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
     474                 :            :                                  struct v4l2_async_notifier *notifier)
     475                 :            : {
     476                 :            :         int ret;
     477                 :            : 
     478   [ #  #  #  #  :          0 :         if (WARN_ON(!v4l2_dev || notifier->sd))
             #  #  #  # ]
     479                 :            :                 return -EINVAL;
     480                 :            : 
     481                 :          0 :         notifier->v4l2_dev = v4l2_dev;
     482                 :            : 
     483                 :          0 :         ret = __v4l2_async_notifier_register(notifier);
     484         [ #  # ]:          0 :         if (ret)
     485                 :          0 :                 notifier->v4l2_dev = NULL;
     486                 :            : 
     487                 :          0 :         return ret;
     488                 :            : }
     489                 :            : EXPORT_SYMBOL(v4l2_async_notifier_register);
     490                 :            : 
     491                 :          0 : int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
     492                 :            :                                         struct v4l2_async_notifier *notifier)
     493                 :            : {
     494                 :            :         int ret;
     495                 :            : 
     496   [ #  #  #  #  :          0 :         if (WARN_ON(!sd || notifier->v4l2_dev))
             #  #  #  # ]
     497                 :            :                 return -EINVAL;
     498                 :            : 
     499                 :          0 :         notifier->sd = sd;
     500                 :            : 
     501                 :          0 :         ret = __v4l2_async_notifier_register(notifier);
     502         [ #  # ]:          0 :         if (ret)
     503                 :          0 :                 notifier->sd = NULL;
     504                 :            : 
     505                 :          0 :         return ret;
     506                 :            : }
     507                 :            : EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
     508                 :            : 
     509                 :            : static void
     510                 :          0 : __v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
     511                 :            : {
     512   [ #  #  #  #  :          0 :         if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
                   #  # ]
     513                 :          0 :                 return;
     514                 :            : 
     515                 :          0 :         v4l2_async_notifier_unbind_all_subdevs(notifier);
     516                 :            : 
     517                 :          0 :         notifier->sd = NULL;
     518                 :          0 :         notifier->v4l2_dev = NULL;
     519                 :            : 
     520                 :            :         list_del(&notifier->list);
     521                 :            : }
     522                 :            : 
     523                 :          0 : void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
     524                 :            : {
     525                 :          0 :         mutex_lock(&list_lock);
     526                 :            : 
     527                 :          0 :         __v4l2_async_notifier_unregister(notifier);
     528                 :            : 
     529                 :          0 :         mutex_unlock(&list_lock);
     530                 :          0 : }
     531                 :            : EXPORT_SYMBOL(v4l2_async_notifier_unregister);
     532                 :            : 
     533                 :          0 : static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
     534                 :            : {
     535                 :            :         struct v4l2_async_subdev *asd, *tmp;
     536                 :            : 
     537   [ #  #  #  # ]:          0 :         if (!notifier || !notifier->asd_list.next)
     538                 :          0 :                 return;
     539                 :            : 
     540         [ #  # ]:          0 :         list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
     541         [ #  # ]:          0 :                 switch (asd->match_type) {
     542                 :            :                 case V4L2_ASYNC_MATCH_FWNODE:
     543                 :          0 :                         fwnode_handle_put(asd->match.fwnode);
     544                 :          0 :                         break;
     545                 :            :                 default:
     546                 :            :                         break;
     547                 :            :                 }
     548                 :            : 
     549                 :            :                 list_del(&asd->asd_list);
     550                 :          0 :                 kfree(asd);
     551                 :            :         }
     552                 :            : }
     553                 :            : 
     554                 :          0 : void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
     555                 :            : {
     556                 :          0 :         mutex_lock(&list_lock);
     557                 :            : 
     558                 :          0 :         __v4l2_async_notifier_cleanup(notifier);
     559                 :            : 
     560                 :          0 :         mutex_unlock(&list_lock);
     561                 :          0 : }
     562                 :            : EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
     563                 :            : 
     564                 :          0 : int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier,
     565                 :            :                                    struct v4l2_async_subdev *asd)
     566                 :            : {
     567                 :            :         int ret;
     568                 :            : 
     569                 :          0 :         mutex_lock(&list_lock);
     570                 :            : 
     571                 :          0 :         ret = v4l2_async_notifier_asd_valid(notifier, asd, -1);
     572         [ #  # ]:          0 :         if (ret)
     573                 :            :                 goto unlock;
     574                 :            : 
     575                 :          0 :         list_add_tail(&asd->asd_list, &notifier->asd_list);
     576                 :            : 
     577                 :            : unlock:
     578                 :          0 :         mutex_unlock(&list_lock);
     579                 :          0 :         return ret;
     580                 :            : }
     581                 :            : EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_subdev);
     582                 :            : 
     583                 :            : struct v4l2_async_subdev *
     584                 :          0 : 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                 :          0 :         asd = kzalloc(asd_struct_size, GFP_KERNEL);
     592         [ #  # ]:          0 :         if (!asd)
     593                 :            :                 return ERR_PTR(-ENOMEM);
     594                 :            : 
     595                 :          0 :         asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
     596                 :          0 :         asd->match.fwnode = fwnode_handle_get(fwnode);
     597                 :            : 
     598                 :          0 :         ret = v4l2_async_notifier_add_subdev(notifier, asd);
     599         [ #  # ]:          0 :         if (ret) {
     600                 :          0 :                 fwnode_handle_put(fwnode);
     601                 :          0 :                 kfree(asd);
     602                 :          0 :                 return ERR_PTR(ret);
     603                 :            :         }
     604                 :            : 
     605                 :            :         return asd;
     606                 :            : }
     607                 :            : EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev);
     608                 :            : 
     609                 :            : int
     610                 :          0 : 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                 :          0 :         remote = fwnode_graph_get_remote_port_parent(endpoint);
     618         [ #  # ]:          0 :         if (!remote)
     619                 :            :                 return -ENOTCONN;
     620                 :            : 
     621                 :          0 :         asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
     622                 :          0 :         asd->match.fwnode = remote;
     623                 :            : 
     624                 :          0 :         ret = v4l2_async_notifier_add_subdev(notif, asd);
     625         [ #  # ]:          0 :         if (ret)
     626                 :          0 :                 fwnode_handle_put(remote);
     627                 :            : 
     628                 :          0 :         return ret;
     629                 :            : }
     630                 :            : EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_remote_subdev);
     631                 :            : 
     632                 :            : struct v4l2_async_subdev *
     633                 :          0 : 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                 :          0 :         asd = kzalloc(asd_struct_size, GFP_KERNEL);
     641         [ #  # ]:          0 :         if (!asd)
     642                 :            :                 return ERR_PTR(-ENOMEM);
     643                 :            : 
     644                 :          0 :         asd->match_type = V4L2_ASYNC_MATCH_I2C;
     645                 :          0 :         asd->match.i2c.adapter_id = adapter_id;
     646                 :          0 :         asd->match.i2c.address = address;
     647                 :            : 
     648                 :          0 :         ret = v4l2_async_notifier_add_subdev(notifier, asd);
     649         [ #  # ]:          0 :         if (ret) {
     650                 :          0 :                 kfree(asd);
     651                 :          0 :                 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                 :          0 : 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                 :          0 :         asd = kzalloc(asd_struct_size, GFP_KERNEL);
     667         [ #  # ]:          0 :         if (!asd)
     668                 :            :                 return ERR_PTR(-ENOMEM);
     669                 :            : 
     670                 :          0 :         asd->match_type = V4L2_ASYNC_MATCH_DEVNAME;
     671                 :          0 :         asd->match.device_name = device_name;
     672                 :            : 
     673                 :          0 :         ret = v4l2_async_notifier_add_subdev(notifier, asd);
     674         [ #  # ]:          0 :         if (ret) {
     675                 :          0 :                 kfree(asd);
     676                 :          0 :                 return ERR_PTR(ret);
     677                 :            :         }
     678                 :            : 
     679                 :            :         return asd;
     680                 :            : }
     681                 :            : EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_devname_subdev);
     682                 :            : 
     683                 :          0 : 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                 :            :          * No reference taken. The reference is held by the device
     691                 :            :          * (struct v4l2_subdev.dev), and async sub-device does not
     692                 :            :          * exist independently of the device at any point of time.
     693                 :            :          */
     694   [ #  #  #  # ]:          0 :         if (!sd->fwnode && sd->dev)
     695                 :          0 :                 sd->fwnode = dev_fwnode(sd->dev);
     696                 :            : 
     697                 :          0 :         mutex_lock(&list_lock);
     698                 :            : 
     699                 :          0 :         INIT_LIST_HEAD(&sd->async_list);
     700                 :            : 
     701         [ #  # ]:          0 :         list_for_each_entry(notifier, &notifier_list, list) {
     702                 :            :                 struct v4l2_device *v4l2_dev =
     703                 :            :                         v4l2_async_notifier_find_v4l2_dev(notifier);
     704                 :            :                 struct v4l2_async_subdev *asd;
     705                 :            : 
     706         [ #  # ]:          0 :                 if (!v4l2_dev)
     707                 :          0 :                         continue;
     708                 :            : 
     709                 :          0 :                 asd = v4l2_async_find_match(notifier, sd);
     710         [ #  # ]:          0 :                 if (!asd)
     711                 :          0 :                         continue;
     712                 :            : 
     713                 :          0 :                 ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
     714         [ #  # ]:          0 :                 if (ret)
     715                 :            :                         goto err_unbind;
     716                 :            : 
     717                 :          0 :                 ret = v4l2_async_notifier_try_complete(notifier);
     718         [ #  # ]:          0 :                 if (ret)
     719                 :            :                         goto err_unbind;
     720                 :            : 
     721                 :            :                 goto out_unlock;
     722                 :            :         }
     723                 :            : 
     724                 :            :         /* None matched, wait for hot-plugging */
     725                 :            :         list_add(&sd->async_list, &subdev_list);
     726                 :            : 
     727                 :            : out_unlock:
     728                 :          0 :         mutex_unlock(&list_lock);
     729                 :            : 
     730                 :          0 :         return 0;
     731                 :            : 
     732                 :            : err_unbind:
     733                 :            :         /*
     734                 :            :          * Complete failed. Unbind the sub-devices bound through registering
     735                 :            :          * this async sub-device.
     736                 :            :          */
     737                 :            :         subdev_notifier = v4l2_async_find_subdev_notifier(sd);
     738         [ #  # ]:          0 :         if (subdev_notifier)
     739                 :          0 :                 v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
     740                 :            : 
     741         [ #  # ]:          0 :         if (sd->asd)
     742                 :            :                 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
     743                 :            :         v4l2_async_cleanup(sd);
     744                 :            : 
     745                 :          0 :         mutex_unlock(&list_lock);
     746                 :            : 
     747                 :          0 :         return ret;
     748                 :            : }
     749                 :            : EXPORT_SYMBOL(v4l2_async_register_subdev);
     750                 :            : 
     751                 :          0 : void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
     752                 :            : {
     753                 :          0 :         mutex_lock(&list_lock);
     754                 :            : 
     755                 :          0 :         __v4l2_async_notifier_unregister(sd->subdev_notifier);
     756                 :          0 :         __v4l2_async_notifier_cleanup(sd->subdev_notifier);
     757                 :          0 :         kfree(sd->subdev_notifier);
     758                 :          0 :         sd->subdev_notifier = NULL;
     759                 :            : 
     760         [ #  # ]:          0 :         if (sd->asd) {
     761                 :          0 :                 struct v4l2_async_notifier *notifier = sd->notifier;
     762                 :            : 
     763                 :          0 :                 list_add(&sd->asd->list, &notifier->waiting);
     764                 :            : 
     765                 :          0 :                 v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
     766                 :            :         }
     767                 :            : 
     768                 :            :         v4l2_async_cleanup(sd);
     769                 :            : 
     770                 :          0 :         mutex_unlock(&list_lock);
     771                 :          0 : }
     772                 :            : EXPORT_SYMBOL(v4l2_async_unregister_subdev);

Generated by: LCOV version 1.14