LCOV - code coverage report
Current view: top level - drivers/media/mc - mc-dev-allocator.c (source / functions) Hit Total Coverage
Test: Real Lines: 0 37 0.0 %
Date: 2020-10-17 15:46:16 Functions: 0 4 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * media-dev-allocator.c - Media Controller Device Allocator API
       4                 :            :  *
       5                 :            :  * Copyright (c) 2019 Shuah Khan <shuah@kernel.org>
       6                 :            :  *
       7                 :            :  * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
       8                 :            :  */
       9                 :            : 
      10                 :            : /*
      11                 :            :  * This file adds a global refcounted Media Controller Device Instance API.
      12                 :            :  * A system wide global media device list is managed and each media device
      13                 :            :  * includes a kref count. The last put on the media device releases the media
      14                 :            :  * device instance.
      15                 :            :  *
      16                 :            :  */
      17                 :            : 
      18                 :            : #include <linux/kref.h>
      19                 :            : #include <linux/module.h>
      20                 :            : #include <linux/slab.h>
      21                 :            : #include <linux/usb.h>
      22                 :            : 
      23                 :            : #include <media/media-device.h>
      24                 :            : #include <media/media-dev-allocator.h>
      25                 :            : 
      26                 :            : static LIST_HEAD(media_device_list);
      27                 :            : static DEFINE_MUTEX(media_device_lock);
      28                 :            : 
      29                 :            : struct media_device_instance {
      30                 :            :         struct media_device mdev;
      31                 :            :         struct module *owner;
      32                 :            :         struct list_head list;
      33                 :            :         struct kref refcount;
      34                 :            : };
      35                 :            : 
      36                 :            : static inline struct media_device_instance *
      37                 :            : to_media_device_instance(struct media_device *mdev)
      38                 :            : {
      39                 :            :         return container_of(mdev, struct media_device_instance, mdev);
      40                 :            : }
      41                 :            : 
      42                 :          0 : static void media_device_instance_release(struct kref *kref)
      43                 :            : {
      44                 :            :         struct media_device_instance *mdi =
      45                 :          0 :                 container_of(kref, struct media_device_instance, refcount);
      46                 :            : 
      47                 :            :         dev_dbg(mdi->mdev.dev, "%s: releasing Media Device\n", __func__);
      48                 :            : 
      49                 :          0 :         mutex_lock(&media_device_lock);
      50                 :            : 
      51                 :          0 :         media_device_unregister(&mdi->mdev);
      52                 :          0 :         media_device_cleanup(&mdi->mdev);
      53                 :            : 
      54                 :            :         list_del(&mdi->list);
      55                 :          0 :         mutex_unlock(&media_device_lock);
      56                 :            : 
      57                 :          0 :         kfree(mdi);
      58                 :          0 : }
      59                 :            : 
      60                 :            : /* Callers should hold media_device_lock when calling this function */
      61                 :          0 : static struct media_device *__media_device_get(struct device *dev,
      62                 :            :                                                 const char *module_name,
      63                 :            :                                                 struct module *owner)
      64                 :            : {
      65                 :            :         struct media_device_instance *mdi;
      66                 :            : 
      67                 :          0 :         list_for_each_entry(mdi, &media_device_list, list) {
      68                 :          0 :                 if (mdi->mdev.dev != dev)
      69                 :          0 :                         continue;
      70                 :            : 
      71                 :            :                 kref_get(&mdi->refcount);
      72                 :            : 
      73                 :            :                 /* get module reference for the media_device owner */
      74                 :          0 :                 if (owner != mdi->owner && !try_module_get(mdi->owner))
      75                 :          0 :                         dev_err(dev,
      76                 :            :                                 "%s: module %s get owner reference error\n",
      77                 :            :                                         __func__, module_name);
      78                 :            :                 else
      79                 :            :                         dev_dbg(dev, "%s: module %s got owner reference\n",
      80                 :            :                                         __func__, module_name);
      81                 :          0 :                 return &mdi->mdev;
      82                 :            :         }
      83                 :            : 
      84                 :          0 :         mdi = kzalloc(sizeof(*mdi), GFP_KERNEL);
      85                 :          0 :         if (!mdi)
      86                 :            :                 return NULL;
      87                 :            : 
      88                 :          0 :         mdi->owner = owner;
      89                 :            :         kref_init(&mdi->refcount);
      90                 :          0 :         list_add_tail(&mdi->list, &media_device_list);
      91                 :            : 
      92                 :            :         dev_dbg(dev, "%s: Allocated media device for owner %s\n",
      93                 :            :                         __func__, module_name);
      94                 :          0 :         return &mdi->mdev;
      95                 :            : }
      96                 :            : 
      97                 :          0 : struct media_device *media_device_usb_allocate(struct usb_device *udev,
      98                 :            :                                                const char *module_name,
      99                 :            :                                                struct module *owner)
     100                 :            : {
     101                 :            :         struct media_device *mdev;
     102                 :            : 
     103                 :          0 :         mutex_lock(&media_device_lock);
     104                 :          0 :         mdev = __media_device_get(&udev->dev, module_name, owner);
     105                 :          0 :         if (!mdev) {
     106                 :          0 :                 mutex_unlock(&media_device_lock);
     107                 :          0 :                 return ERR_PTR(-ENOMEM);
     108                 :            :         }
     109                 :            : 
     110                 :            :         /* check if media device is already initialized */
     111                 :          0 :         if (!mdev->dev)
     112                 :          0 :                 __media_device_usb_init(mdev, udev, udev->product,
     113                 :            :                                         module_name);
     114                 :          0 :         mutex_unlock(&media_device_lock);
     115                 :          0 :         return mdev;
     116                 :            : }
     117                 :            : EXPORT_SYMBOL_GPL(media_device_usb_allocate);
     118                 :            : 
     119                 :          0 : void media_device_delete(struct media_device *mdev, const char *module_name,
     120                 :            :                          struct module *owner)
     121                 :            : {
     122                 :            :         struct media_device_instance *mdi = to_media_device_instance(mdev);
     123                 :            : 
     124                 :          0 :         mutex_lock(&media_device_lock);
     125                 :            :         /* put module reference for the media_device owner */
     126                 :          0 :         if (mdi->owner != owner) {
     127                 :          0 :                 module_put(mdi->owner);
     128                 :            :                 dev_dbg(mdi->mdev.dev,
     129                 :            :                         "%s: module %s put owner module reference\n",
     130                 :            :                         __func__, module_name);
     131                 :            :         }
     132                 :          0 :         mutex_unlock(&media_device_lock);
     133                 :          0 :         kref_put(&mdi->refcount, media_device_instance_release);
     134                 :          0 : }
     135                 :            : EXPORT_SYMBOL_GPL(media_device_delete);
    

Generated by: LCOV version 1.14