11590Srgrimes// SPDX-License-Identifier: GPL-2.0 21590Srgrimes/* 31590Srgrimes * media-dev-allocator.c - Media Controller Device Allocator API 41590Srgrimes * 51590Srgrimes * Copyright (c) 2019 Shuah Khan <shuah@kernel.org> 61590Srgrimes * 71590Srgrimes * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com> 81590Srgrimes */ 91590Srgrimes 101590Srgrimes/* 111590Srgrimes * This file adds a global refcounted Media Controller Device Instance API. 121590Srgrimes * A system wide global media device list is managed and each media device 131590Srgrimes * includes a kref count. The last put on the media device releases the media 141590Srgrimes * device instance. 151590Srgrimes * 161590Srgrimes */ 171590Srgrimes 181590Srgrimes#include <linux/kref.h> 191590Srgrimes#include <linux/module.h> 201590Srgrimes#include <linux/slab.h> 211590Srgrimes#include <linux/usb.h> 221590Srgrimes 231590Srgrimes#include <media/media-device.h> 241590Srgrimes#include <media/media-dev-allocator.h> 251590Srgrimes 261590Srgrimesstatic LIST_HEAD(media_device_list); 271590Srgrimesstatic DEFINE_MUTEX(media_device_lock); 281590Srgrimes 291590Srgrimesstruct media_device_instance { 301590Srgrimes struct media_device mdev; 311590Srgrimes struct module *owner; 321590Srgrimes struct list_head list; 331590Srgrimes struct kref refcount; 341590Srgrimes}; 351590Srgrimes 361590Srgrimesstatic inline struct media_device_instance * 371590Srgrimesto_media_device_instance(struct media_device *mdev) 381590Srgrimes{ 3928066Scharnier return container_of(mdev, struct media_device_instance, mdev); 401590Srgrimes} 411590Srgrimes 421590Srgrimesstatic void media_device_instance_release(struct kref *kref) 431590Srgrimes{ 441590Srgrimes struct media_device_instance *mdi = 4528066Scharnier container_of(kref, struct media_device_instance, refcount); 461590Srgrimes 4728066Scharnier dev_dbg(mdi->mdev.dev, "%s: releasing Media Device\n", __func__); 4828066Scharnier 4950477Speter mutex_lock(&media_device_lock); 501590Srgrimes 511590Srgrimes media_device_unregister(&mdi->mdev); 521590Srgrimes media_device_cleanup(&mdi->mdev); 531590Srgrimes 5428066Scharnier list_del(&mdi->list); 551590Srgrimes mutex_unlock(&media_device_lock); 561590Srgrimes 5717522Sache kfree(mdi); 581590Srgrimes} 591590Srgrimes 601590Srgrimes/* Callers should hold media_device_lock when calling this function */ 611590Srgrimesstatic struct media_device *__media_device_get(struct device *dev, 621590Srgrimes const char *module_name, 631590Srgrimes struct module *owner) 641590Srgrimes{ 651590Srgrimes struct media_device_instance *mdi; 661590Srgrimes 671590Srgrimes list_for_each_entry(mdi, &media_device_list, list) { 681590Srgrimes if (mdi->mdev.dev != dev) 691590Srgrimes continue; 701590Srgrimes 711590Srgrimes kref_get(&mdi->refcount); 721590Srgrimes 731590Srgrimes /* get module reference for the media_device owner */ 741590Srgrimes if (owner != mdi->owner && !try_module_get(mdi->owner)) 751590Srgrimes dev_err(dev, 761590Srgrimes "%s: module %s get owner reference error\n", 771590Srgrimes __func__, module_name); 781590Srgrimes else 791590Srgrimes dev_dbg(dev, "%s: module %s got owner reference\n", 801590Srgrimes __func__, module_name); 811590Srgrimes return &mdi->mdev; 821590Srgrimes } 831590Srgrimes 841590Srgrimes mdi = kzalloc(sizeof(*mdi), GFP_KERNEL); 851590Srgrimes if (!mdi) 861590Srgrimes return NULL; 871590Srgrimes 881590Srgrimes mdi->owner = owner; 891590Srgrimes kref_init(&mdi->refcount); 901590Srgrimes list_add_tail(&mdi->list, &media_device_list); 911590Srgrimes 921590Srgrimes dev_dbg(dev, "%s: Allocated media device for owner %s\n", 931590Srgrimes __func__, module_name); 941590Srgrimes return &mdi->mdev; 951590Srgrimes} 961590Srgrimes 971590Srgrimesstruct media_device *media_device_usb_allocate(struct usb_device *udev, 9858309Sgreen const char *module_name, 991590Srgrimes struct module *owner) 1001590Srgrimes{ 1011590Srgrimes struct media_device *mdev; 1021590Srgrimes 1031590Srgrimes mutex_lock(&media_device_lock); 1041590Srgrimes mdev = __media_device_get(&udev->dev, module_name, owner); 1051590Srgrimes if (!mdev) { 1061590Srgrimes mutex_unlock(&media_device_lock); 1071590Srgrimes return ERR_PTR(-ENOMEM); 1081590Srgrimes } 1091590Srgrimes 11028066Scharnier /* check if media device is already initialized */ 1111590Srgrimes if (!mdev->dev) 1121590Srgrimes __media_device_usb_init(mdev, udev, udev->product, 1131590Srgrimes module_name); 1141590Srgrimes mutex_unlock(&media_device_lock); 1151590Srgrimes return mdev; 1161590Srgrimes} 1171590SrgrimesEXPORT_SYMBOL_GPL(media_device_usb_allocate); 11860394Snsayer 1191590Srgrimesvoid media_device_delete(struct media_device *mdev, const char *module_name, 12017522Sache struct module *owner) 12117522Sache{ 1221590Srgrimes struct media_device_instance *mdi = to_media_device_instance(mdev); 12358309Sgreen 1241590Srgrimes mutex_lock(&media_device_lock); 12558309Sgreen /* put module reference for the media_device owner */ 12658309Sgreen if (mdi->owner != owner) { 12758309Sgreen module_put(mdi->owner); 1281590Srgrimes dev_dbg(mdi->mdev.dev, 1291590Srgrimes "%s: module %s put owner module reference\n", 1301590Srgrimes __func__, module_name); 1311590Srgrimes } 1321590Srgrimes mutex_unlock(&media_device_lock); 13360394Snsayer kref_put(&mdi->refcount, media_device_instance_release); 13460394Snsayer} 13560394SnsayerEXPORT_SYMBOL_GPL(media_device_delete); 13660394Snsayer