Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * media-dev-allocator.c - Media Controller Device Allocator API
0004  *
0005  * Copyright (c) 2019 Shuah Khan <shuah@kernel.org>
0006  *
0007  * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
0008  */
0009 
0010 /*
0011  * This file adds a global refcounted Media Controller Device Instance API.
0012  * A system wide global media device list is managed and each media device
0013  * includes a kref count. The last put on the media device releases the media
0014  * device instance.
0015  *
0016  */
0017 
0018 #include <linux/kref.h>
0019 #include <linux/module.h>
0020 #include <linux/slab.h>
0021 #include <linux/usb.h>
0022 
0023 #include <media/media-device.h>
0024 #include <media/media-dev-allocator.h>
0025 
0026 static LIST_HEAD(media_device_list);
0027 static DEFINE_MUTEX(media_device_lock);
0028 
0029 struct media_device_instance {
0030     struct media_device mdev;
0031     struct module *owner;
0032     struct list_head list;
0033     struct kref refcount;
0034 };
0035 
0036 static inline struct media_device_instance *
0037 to_media_device_instance(struct media_device *mdev)
0038 {
0039     return container_of(mdev, struct media_device_instance, mdev);
0040 }
0041 
0042 static void media_device_instance_release(struct kref *kref)
0043 {
0044     struct media_device_instance *mdi =
0045         container_of(kref, struct media_device_instance, refcount);
0046 
0047     dev_dbg(mdi->mdev.dev, "%s: releasing Media Device\n", __func__);
0048 
0049     mutex_lock(&media_device_lock);
0050 
0051     media_device_unregister(&mdi->mdev);
0052     media_device_cleanup(&mdi->mdev);
0053 
0054     list_del(&mdi->list);
0055     mutex_unlock(&media_device_lock);
0056 
0057     kfree(mdi);
0058 }
0059 
0060 /* Callers should hold media_device_lock when calling this function */
0061 static struct media_device *__media_device_get(struct device *dev,
0062                         const char *module_name,
0063                         struct module *owner)
0064 {
0065     struct media_device_instance *mdi;
0066 
0067     list_for_each_entry(mdi, &media_device_list, list) {
0068         if (mdi->mdev.dev != dev)
0069             continue;
0070 
0071         kref_get(&mdi->refcount);
0072 
0073         /* get module reference for the media_device owner */
0074         if (owner != mdi->owner && !try_module_get(mdi->owner))
0075             dev_err(dev,
0076                 "%s: module %s get owner reference error\n",
0077                     __func__, module_name);
0078         else
0079             dev_dbg(dev, "%s: module %s got owner reference\n",
0080                     __func__, module_name);
0081         return &mdi->mdev;
0082     }
0083 
0084     mdi = kzalloc(sizeof(*mdi), GFP_KERNEL);
0085     if (!mdi)
0086         return NULL;
0087 
0088     mdi->owner = owner;
0089     kref_init(&mdi->refcount);
0090     list_add_tail(&mdi->list, &media_device_list);
0091 
0092     dev_dbg(dev, "%s: Allocated media device for owner %s\n",
0093             __func__, module_name);
0094     return &mdi->mdev;
0095 }
0096 
0097 struct media_device *media_device_usb_allocate(struct usb_device *udev,
0098                            const char *module_name,
0099                            struct module *owner)
0100 {
0101     struct media_device *mdev;
0102 
0103     mutex_lock(&media_device_lock);
0104     mdev = __media_device_get(&udev->dev, module_name, owner);
0105     if (!mdev) {
0106         mutex_unlock(&media_device_lock);
0107         return ERR_PTR(-ENOMEM);
0108     }
0109 
0110     /* check if media device is already initialized */
0111     if (!mdev->dev)
0112         __media_device_usb_init(mdev, udev, udev->product,
0113                     module_name);
0114     mutex_unlock(&media_device_lock);
0115     return mdev;
0116 }
0117 EXPORT_SYMBOL_GPL(media_device_usb_allocate);
0118 
0119 void media_device_delete(struct media_device *mdev, const char *module_name,
0120              struct module *owner)
0121 {
0122     struct media_device_instance *mdi = to_media_device_instance(mdev);
0123 
0124     mutex_lock(&media_device_lock);
0125     /* put module reference for the media_device owner */
0126     if (mdi->owner != owner) {
0127         module_put(mdi->owner);
0128         dev_dbg(mdi->mdev.dev,
0129             "%s: module %s put owner module reference\n",
0130             __func__, module_name);
0131     }
0132     mutex_unlock(&media_device_lock);
0133     kref_put(&mdi->refcount, media_device_instance_release);
0134 }
0135 EXPORT_SYMBOL_GPL(media_device_delete);