LCOV - code coverage report
Current view: top level - drivers/media/v4l2-core - v4l2-device.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 12 119 10.1 %
Date: 2020-09-30 20:25:40 Functions: 1 11 9.1 %
Branches: 5 98 5.1 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :     V4L2 device support.
       4                 :            : 
       5                 :            :     Copyright (C) 2008  Hans Verkuil <hverkuil@xs4all.nl>
       6                 :            : 
       7                 :            :  */
       8                 :            : 
       9                 :            : #include <linux/types.h>
      10                 :            : #include <linux/ioctl.h>
      11                 :            : #include <linux/module.h>
      12                 :            : #include <linux/slab.h>
      13                 :            : #include <linux/videodev2.h>
      14                 :            : #include <media/v4l2-device.h>
      15                 :            : #include <media/v4l2-ctrls.h>
      16                 :            : 
      17                 :        828 : int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
      18                 :            : {
      19         [ +  - ]:        828 :         if (v4l2_dev == NULL)
      20                 :            :                 return -EINVAL;
      21                 :            : 
      22                 :        828 :         INIT_LIST_HEAD(&v4l2_dev->subdevs);
      23                 :        828 :         spin_lock_init(&v4l2_dev->lock);
      24                 :        828 :         v4l2_prio_init(&v4l2_dev->prio);
      25                 :            :         kref_init(&v4l2_dev->ref);
      26                 :        828 :         get_device(dev);
      27                 :        828 :         v4l2_dev->dev = dev;
      28         [ -  + ]:        828 :         if (dev == NULL) {
      29                 :            :                 /* If dev == NULL, then name must be filled in by the caller */
      30   [ #  #  #  # ]:          0 :                 if (WARN_ON(!v4l2_dev->name[0]))
      31                 :            :                         return -EINVAL;
      32                 :          0 :                 return 0;
      33                 :            :         }
      34                 :            : 
      35                 :            :         /* Set name to driver name + device name if it is empty. */
      36         [ +  - ]:        828 :         if (!v4l2_dev->name[0])
      37                 :       2484 :                 snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
      38                 :        828 :                         dev->driver->name, dev_name(dev));
      39         [ +  + ]:        828 :         if (!dev_get_drvdata(dev))
      40                 :            :                 dev_set_drvdata(dev, v4l2_dev);
      41                 :            :         return 0;
      42                 :            : }
      43                 :            : EXPORT_SYMBOL_GPL(v4l2_device_register);
      44                 :            : 
      45                 :          0 : static void v4l2_device_release(struct kref *ref)
      46                 :            : {
      47                 :            :         struct v4l2_device *v4l2_dev =
      48                 :          0 :                 container_of(ref, struct v4l2_device, ref);
      49                 :            : 
      50         [ #  # ]:          0 :         if (v4l2_dev->release)
      51                 :          0 :                 v4l2_dev->release(v4l2_dev);
      52                 :          0 : }
      53                 :            : 
      54                 :          0 : int v4l2_device_put(struct v4l2_device *v4l2_dev)
      55                 :            : {
      56                 :          0 :         return kref_put(&v4l2_dev->ref, v4l2_device_release);
      57                 :            : }
      58                 :            : EXPORT_SYMBOL_GPL(v4l2_device_put);
      59                 :            : 
      60                 :          0 : int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
      61                 :            :                                                 atomic_t *instance)
      62                 :            : {
      63                 :          0 :         int num = atomic_inc_return(instance) - 1;
      64                 :          0 :         int len = strlen(basename);
      65                 :            : 
      66         [ #  # ]:          0 :         if (basename[len - 1] >= '0' && basename[len - 1] <= '9')
      67                 :          0 :                 snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
      68                 :            :                                 "%s-%d", basename, num);
      69                 :            :         else
      70                 :          0 :                 snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
      71                 :            :                                 "%s%d", basename, num);
      72                 :          0 :         return num;
      73                 :            : }
      74                 :            : EXPORT_SYMBOL_GPL(v4l2_device_set_name);
      75                 :            : 
      76                 :          0 : void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
      77                 :            : {
      78         [ #  # ]:          0 :         if (v4l2_dev->dev == NULL)
      79                 :          0 :                 return;
      80                 :            : 
      81         [ #  # ]:          0 :         if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
      82                 :            :                 dev_set_drvdata(v4l2_dev->dev, NULL);
      83                 :          0 :         put_device(v4l2_dev->dev);
      84                 :          0 :         v4l2_dev->dev = NULL;
      85                 :            : }
      86                 :            : EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
      87                 :            : 
      88                 :          0 : void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
      89                 :            : {
      90                 :            :         struct v4l2_subdev *sd, *next;
      91                 :            : 
      92                 :            :         /* Just return if v4l2_dev is NULL or if it was already
      93                 :            :          * unregistered before. */
      94   [ #  #  #  # ]:          0 :         if (v4l2_dev == NULL || !v4l2_dev->name[0])
      95                 :          0 :                 return;
      96                 :          0 :         v4l2_device_disconnect(v4l2_dev);
      97                 :            : 
      98                 :            :         /* Unregister subdevs */
      99         [ #  # ]:          0 :         list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {
     100                 :          0 :                 v4l2_device_unregister_subdev(sd);
     101         [ #  # ]:          0 :                 if (sd->flags & V4L2_SUBDEV_FL_IS_I2C)
     102                 :          0 :                         v4l2_i2c_subdev_unregister(sd);
     103         [ #  # ]:          0 :                 else if (sd->flags & V4L2_SUBDEV_FL_IS_SPI)
     104                 :          0 :                         v4l2_spi_subdev_unregister(sd);
     105                 :            :         }
     106                 :            :         /* Mark as unregistered, thus preventing duplicate unregistrations */
     107                 :          0 :         v4l2_dev->name[0] = '\0';
     108                 :            : }
     109                 :            : EXPORT_SYMBOL_GPL(v4l2_device_unregister);
     110                 :            : 
     111                 :          0 : int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
     112                 :            :                                 struct v4l2_subdev *sd)
     113                 :            : {
     114                 :            : #if defined(CONFIG_MEDIA_CONTROLLER)
     115                 :          0 :         struct media_entity *entity = &sd->entity;
     116                 :            : #endif
     117                 :            :         int err;
     118                 :            : 
     119                 :            :         /* Check for valid input */
     120   [ #  #  #  #  :          0 :         if (!v4l2_dev || !sd || sd->v4l2_dev || !sd->name[0])
                   #  # ]
     121                 :            :                 return -EINVAL;
     122                 :            : 
     123                 :            :         /*
     124                 :            :          * The reason to acquire the module here is to avoid unloading
     125                 :            :          * a module of sub-device which is registered to a media
     126                 :            :          * device. To make it possible to unload modules for media
     127                 :            :          * devices that also register sub-devices, do not
     128                 :            :          * try_module_get() such sub-device owners.
     129                 :            :          */
     130   [ #  #  #  #  :          0 :         sd->owner_v4l2_dev = v4l2_dev->dev && v4l2_dev->dev->driver &&
                   #  # ]
     131                 :          0 :                 sd->owner == v4l2_dev->dev->driver->owner;
     132                 :            : 
     133   [ #  #  #  # ]:          0 :         if (!sd->owner_v4l2_dev && !try_module_get(sd->owner))
     134                 :            :                 return -ENODEV;
     135                 :            : 
     136                 :          0 :         sd->v4l2_dev = v4l2_dev;
     137                 :            :         /* This just returns 0 if either of the two args is NULL */
     138                 :          0 :         err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler,
     139                 :            :                                     NULL, true);
     140         [ #  # ]:          0 :         if (err)
     141                 :            :                 goto error_module;
     142                 :            : 
     143                 :            : #if defined(CONFIG_MEDIA_CONTROLLER)
     144                 :            :         /* Register the entity. */
     145         [ #  # ]:          0 :         if (v4l2_dev->mdev) {
     146                 :          0 :                 err = media_device_register_entity(v4l2_dev->mdev, entity);
     147         [ #  # ]:          0 :                 if (err < 0)
     148                 :            :                         goto error_module;
     149                 :            :         }
     150                 :            : #endif
     151                 :            : 
     152   [ #  #  #  # ]:          0 :         if (sd->internal_ops && sd->internal_ops->registered) {
     153                 :          0 :                 err = sd->internal_ops->registered(sd);
     154         [ #  # ]:          0 :                 if (err)
     155                 :            :                         goto error_unregister;
     156                 :            :         }
     157                 :            : 
     158                 :            :         spin_lock(&v4l2_dev->lock);
     159                 :          0 :         list_add_tail(&sd->list, &v4l2_dev->subdevs);
     160                 :            :         spin_unlock(&v4l2_dev->lock);
     161                 :            : 
     162                 :          0 :         return 0;
     163                 :            : 
     164                 :            : error_unregister:
     165                 :            : #if defined(CONFIG_MEDIA_CONTROLLER)
     166                 :          0 :         media_device_unregister_entity(entity);
     167                 :            : #endif
     168                 :            : error_module:
     169         [ #  # ]:          0 :         if (!sd->owner_v4l2_dev)
     170                 :          0 :                 module_put(sd->owner);
     171                 :          0 :         sd->v4l2_dev = NULL;
     172                 :          0 :         return err;
     173                 :            : }
     174                 :            : EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
     175                 :            : 
     176                 :          0 : static void v4l2_subdev_release(struct v4l2_subdev *sd)
     177                 :            : {
     178         [ #  # ]:          0 :         struct module *owner = !sd->owner_v4l2_dev ? sd->owner : NULL;
     179                 :            : 
     180   [ #  #  #  # ]:          0 :         if (sd->internal_ops && sd->internal_ops->release)
     181                 :          0 :                 sd->internal_ops->release(sd);
     182                 :          0 :         sd->devnode = NULL;
     183                 :          0 :         module_put(owner);
     184                 :          0 : }
     185                 :            : 
     186                 :          0 : static void v4l2_device_release_subdev_node(struct video_device *vdev)
     187                 :            : {
     188                 :          0 :         v4l2_subdev_release(video_get_drvdata(vdev));
     189                 :          0 :         kfree(vdev);
     190                 :          0 : }
     191                 :            : 
     192                 :          0 : int __v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev,
     193                 :            :                                         bool read_only)
     194                 :            : {
     195                 :            :         struct video_device *vdev;
     196                 :            :         struct v4l2_subdev *sd;
     197                 :            :         int err;
     198                 :            : 
     199                 :            :         /* Register a device node for every subdev marked with the
     200                 :            :          * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
     201                 :            :          */
     202         [ #  # ]:          0 :         list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
     203         [ #  # ]:          0 :                 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
     204                 :          0 :                         continue;
     205                 :            : 
     206         [ #  # ]:          0 :                 if (sd->devnode)
     207                 :          0 :                         continue;
     208                 :            : 
     209                 :          0 :                 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
     210         [ #  # ]:          0 :                 if (!vdev) {
     211                 :            :                         err = -ENOMEM;
     212                 :            :                         goto clean_up;
     213                 :            :                 }
     214                 :            : 
     215                 :            :                 video_set_drvdata(vdev, sd);
     216                 :          0 :                 strscpy(vdev->name, sd->name, sizeof(vdev->name));
     217                 :          0 :                 vdev->dev_parent = sd->dev;
     218                 :          0 :                 vdev->v4l2_dev = v4l2_dev;
     219                 :          0 :                 vdev->fops = &v4l2_subdev_fops;
     220                 :          0 :                 vdev->release = v4l2_device_release_subdev_node;
     221                 :          0 :                 vdev->ctrl_handler = sd->ctrl_handler;
     222         [ #  # ]:          0 :                 if (read_only)
     223                 :          0 :                         set_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags);
     224                 :          0 :                 err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
     225                 :            :                                               sd->owner);
     226         [ #  # ]:          0 :                 if (err < 0) {
     227                 :          0 :                         kfree(vdev);
     228                 :          0 :                         goto clean_up;
     229                 :            :                 }
     230                 :          0 :                 sd->devnode = vdev;
     231                 :            : #if defined(CONFIG_MEDIA_CONTROLLER)
     232                 :          0 :                 sd->entity.info.dev.major = VIDEO_MAJOR;
     233                 :          0 :                 sd->entity.info.dev.minor = vdev->minor;
     234                 :            : 
     235                 :            :                 /* Interface is created by __video_register_device() */
     236         [ #  # ]:          0 :                 if (vdev->v4l2_dev->mdev) {
     237                 :            :                         struct media_link *link;
     238                 :            : 
     239                 :          0 :                         link = media_create_intf_link(&sd->entity,
     240                 :          0 :                                                       &vdev->intf_devnode->intf,
     241                 :            :                                                       MEDIA_LNK_FL_ENABLED |
     242                 :            :                                                       MEDIA_LNK_FL_IMMUTABLE);
     243         [ #  # ]:          0 :                         if (!link) {
     244                 :            :                                 err = -ENOMEM;
     245                 :            :                                 goto clean_up;
     246                 :            :                         }
     247                 :            :                 }
     248                 :            : #endif
     249                 :            :         }
     250                 :            :         return 0;
     251                 :            : 
     252                 :            : clean_up:
     253         [ #  # ]:          0 :         list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
     254         [ #  # ]:          0 :                 if (!sd->devnode)
     255                 :            :                         break;
     256                 :          0 :                 video_unregister_device(sd->devnode);
     257                 :            :         }
     258                 :            : 
     259                 :            :         return err;
     260                 :            : }
     261                 :            : EXPORT_SYMBOL_GPL(__v4l2_device_register_subdev_nodes);
     262                 :            : 
     263                 :          0 : void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
     264                 :            : {
     265                 :            :         struct v4l2_device *v4l2_dev;
     266                 :            : 
     267                 :            :         /* return if it isn't registered */
     268   [ #  #  #  # ]:          0 :         if (sd == NULL || sd->v4l2_dev == NULL)
     269                 :          0 :                 return;
     270                 :            : 
     271                 :            :         v4l2_dev = sd->v4l2_dev;
     272                 :            : 
     273                 :            :         spin_lock(&v4l2_dev->lock);
     274                 :            :         list_del(&sd->list);
     275                 :            :         spin_unlock(&v4l2_dev->lock);
     276                 :            : 
     277   [ #  #  #  # ]:          0 :         if (sd->internal_ops && sd->internal_ops->unregistered)
     278                 :          0 :                 sd->internal_ops->unregistered(sd);
     279                 :          0 :         sd->v4l2_dev = NULL;
     280                 :            : 
     281                 :            : #if defined(CONFIG_MEDIA_CONTROLLER)
     282         [ #  # ]:          0 :         if (v4l2_dev->mdev) {
     283                 :            :                 /*
     284                 :            :                  * No need to explicitly remove links, as both pads and
     285                 :            :                  * links are removed by the function below, in the right order
     286                 :            :                  */
     287                 :          0 :                 media_device_unregister_entity(&sd->entity);
     288                 :            :         }
     289                 :            : #endif
     290         [ #  # ]:          0 :         if (sd->devnode)
     291                 :          0 :                 video_unregister_device(sd->devnode);
     292                 :            :         else
     293                 :          0 :                 v4l2_subdev_release(sd);
     294                 :            : }
     295                 :            : EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);

Generated by: LCOV version 1.14